- dry Contact or IR Interface `99`: add `3` before --> `where="399"`
- energy meter F520/F521 numbered `1`: add `5` before --> `where="51"`
- energy meter F522/F523 numbered `4`: add `7` before and `#0` after --> `where="74#0"`
+ - energy meter F520/F521 the `energyRefreshPeriod` configuration parameter sets the number of minutes (the minimum value is 30, the maximum value is 1440) between refreshes for energy totalizers (default: 30 minutes) --> `energyRefreshPeriod` = 35
- alarm zone `2` --> `where="2"`
- example for Zigbee devices: `where=765432101#9`. The ID of the device (ADDR part) is usually written in hexadecimal on the device itself, for example `ID 0074CBB1`: convert to decimal (`7654321`) and add `01#9` at the end to obtain `where=765432101#9`. For 2-unit switch devices (`zb_on_off_switch2u`), last part should be `00#9`.
### Lighting, Automation, Basic/CEN/CEN+ Scenario Events, Dry Contact / IR Interfaces, Power and Aux channels
-| Channel Type ID (channel ID) | Applies to Thing Type IDs | Item Type | Description | Read/Write |
+| Channel Type ID (channel ID) | Applies to Thing Type IDs | Item Type | Description | Read/Write |
|-----------------------------------------|---------------------------------------------------------------|---------------|-----------------------------------------------------------------------------------------------------------------------|:-----------:|
-| `switch` or `switch_01`/`02` for Zigbee | `bus_on_off_switch`, `zb_on_off_switch`, `zb_on_off_switch2u` | Switch | To switch the device `ON` and `OFF` | R/W |
-| `brightness` | `bus_dimmer`, `zb_dimmer` | Dimmer | To adjust the brightness value (Percent, `ON`, `OFF`) | R/W |
-| `shutter` | `bus_automation` | Rollershutter | To activate roller shutters (`UP`, `DOWN`, `STOP`, Percent - [see Shutter position](#shutter-position)) | R/W |
-| `scenario` | `bus_scenario_control` | String | Trigger channel for Basic scenario events [see possible values](#scenario-channels) | R (TRIGGER) |
-| `button#X` | `bus_cen_scenario_control`, `bus_cenplus_scenario_control` | String | Trigger channel for CEN/CEN+ scenario events [see possible values](#scenario-channels) | R (TRIGGER) |
-| `sensor` | `bus_dry_contact_ir` | Switch | Indicates if a Dry Contact Interface is `ON`/`OFF`, or if an IR Sensor is detecting movement (`ON`), or not (`OFF`) | R |
-| `power` | `bus_energy_meter` | Number:Power | The current active power usage from Energy Meter | R |
+| `switch` or `switch_01`/`02` for Zigbee | `bus_on_off_switch`, `zb_on_off_switch`, `zb_on_off_switch2u` | Switch | To switch the device `ON` and `OFF` | R/W |
+| `brightness` | `bus_dimmer`, `zb_dimmer` | Dimmer | To adjust the brightness value (Percent, `ON`, `OFF`) | R/W |
+| `shutter` | `bus_automation` | Rollershutter | To activate roller shutters (`UP`, `DOWN`, `STOP`, Percent - [see Shutter position](#shutter-position)) | R/W |
+| `scenario` | `bus_scenario_control` | String | Trigger channel for Basic scenario events [see possible values](#scenario-channels) | R (TRIGGER) |
+| `button#X` | `bus_cen_scenario_control`, `bus_cenplus_scenario_control` | String | Trigger channel for CEN/CEN+ scenario events [see possible values](#scenario-channels) | R (TRIGGER) |
+| `sensor` | `bus_dry_contact_ir` | Switch | Indicates if a Dry Contact Interface is `ON`/`OFF`, or if an IR Sensor is detecting movement (`ON`), or not (`OFF`) | R |
+| `power` | `bus_energy_meter` | Number:Power | The current active power usage from Energy Meter | R |
+| `energyToday` | `bus_energy_meter` | Number:Energy | Current day energy totalizer | R |
+| `energyThisMonth` | `bus_energy_meter` | Number:Energy | Current month energy totalizer | R |
| `aux` | `bus_aux` | String | Possible commands: `ON`, `OFF`, `TOGGLE`, `STOP`, `UP`, `DOWN`, `ENABLED`, `DISABLED`, `RESET_GEN`, `RESET_BI`, `RESET_TRI`. Only `ON` and `OFF` are supported for now | R/W |
### Alarm channels
Number:Power iCENTRAL_Ta "Power [%.0f %unit%]" { channel="openwebnet:bus_energy_meter:mybridge:CENTRAL_Ta:power" }
Number:Power iCENTRAL_Tb "Power [%.0f %unit%]" { channel="openwebnet:bus_energy_meter:mybridge:CENTRAL_Tb:power" }
+Number:Energy iCENTRAL_Ta_day "Energy Day [%.1f]" { channel="openwebnet:bus_energy_meter:mybridge:CENTRAL_Ta:energyToday"}
+Number:Energy iCENTRAL_Tb_day "Energy Day [%.1f]" { channel="openwebnet:bus_energy_meter:mybridge:CENTRAL_Tb:energyToday"}
+Number:Energy iCENTRAL_Ta_month "Energy Month [%.1f]" { channel="openwebnet:bus_energy_meter:mybridge:CENTRAL_Ta:energyThisMonth"}
+Number:Energy iCENTRAL_Tb_month "Energy Month [%.1f]" { channel="openwebnet:bus_energy_meter:mybridge:CENTRAL_Tb:energyThisMonth"}
// 99 zones thermo central unit
Group gCentralUnit "Thermo Central Unit"
Frame label="Energy Meters" icon="energy"
{
- Default item=iCENTRAL_Ta label="General" icon="energy" valuecolor=[>3000="red"]
- Default item=iCENTRAL_Tb label="Ground Floor" icon="energy" valuecolor=[>3000="red"]
+ Default item=iCENTRAL_Ta label="General" icon="energy" valuecolor=[>3000="red"]
+ Default item=iCENTRAL_Tb label="Ground Floor" icon="energy" valuecolor=[>3000="red"]
+ Default item=CENTRAL_Ta_day label="General Energy Today" icon="energy" valuecolor=[>3000="blue"]
+ Default item=CENTRAL_Tb_day label="Ground Floor Energy Today" icon="energy" valuecolor=[>3000="blue"]
+ Default item=CENTRAL_Ta_month label="General Energy This Month" icon="energy" valuecolor=[>3000="yellow"]
+ Default item=CENTRAL_Tb_month label="Ground Floor Energy This Month" icon="energy" valuecolor=[>3000="yellow"]
}
Frame label="Living Room Thermo"
*/
package org.openhab.binding.openwebnet.internal.handler;
+import static org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants.CHANNEL_ENERGY_TOTALIZER_DAY;
+import static org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants.CHANNEL_ENERGY_TOTALIZER_MONTH;
import static org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants.CHANNEL_POWER;
import java.util.Set;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
+import javax.measure.quantity.Energy;
import javax.measure.quantity.Power;
import org.eclipse.jdt.annotation.NonNullByDefault;
* device. It extends the abstract {@link OpenWebNetThingHandler}.
*
* @author Massimo Valla - Initial contribution
- * @author Andrea Conte - Energy management
+ * @author Andrea Conte, Giovanni Fabiani - Energy management
*/
@NonNullByDefault
public class OpenWebNetEnergyHandler extends OpenWebNetThingHandler {
private final Logger logger = LoggerFactory.getLogger(OpenWebNetEnergyHandler.class);
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = OpenWebNetBindingConstants.ENERGY_MANAGEMENT_SUPPORTED_THING_TYPES;
- public static final int ENERGY_SUBSCRIPTION_PERIOD = 10; // minutes
- private @Nullable ScheduledFuture<?> notificationSchedule;
+ private static final int POWER_SUBSCRIPTION_PERIOD = 10; // MINUTES
+ private int energyRefreshPeriod; // MINUTES
+
+ private @Nullable ScheduledFuture<?> powerSchedule;
+ private @Nullable ScheduledFuture<?> energySchedule;
public OpenWebNetEnergyHandler(Thing thing) {
super(thing);
@Override
public void initialize() {
super.initialize();
+ try {
+ Object refreshPeriodConfig = getConfig().get(OpenWebNetBindingConstants.CONFIG_PROPERTY_REFRESH_PERIOD);
+ energyRefreshPeriod = Integer.parseInt(refreshPeriodConfig.toString());
+ } catch (NumberFormatException e) {
+ logger.debug("NumberFormatException caught while parsing OpenWebNetEnergyHandler configuration: {}",
+ e.getMessage());
+ energyRefreshPeriod = 30;
+ }
// In order to get data from the probe we must send a command over the bus, this could be done only when the
// bridge is online.
if (gw != null && gw.isConnected()) {
// bridge is online
subscribeToActivePowerChanges();
+ subscribeToEnergyTotalizer();
}
}
}
// subscribe the scheduler only after the bridge is online
if (bridgeStatusInfo.getStatus().equals(ThingStatus.ONLINE)) {
subscribeToActivePowerChanges();
+ subscribeToEnergyTotalizer();
}
}
private void subscribeToActivePowerChanges() {
- notificationSchedule = scheduler.scheduleWithFixedDelay(() -> {
+ powerSchedule = scheduler.scheduleWithFixedDelay(() -> {
if (isFirstSchedulerLaunch) {
logger.debug(
"subscribeToActivePowerChanges() For WHERE={} subscribing to active power changes notification for the next {}min",
- deviceWhere, ENERGY_SUBSCRIPTION_PERIOD);
+ deviceWhere, POWER_SUBSCRIPTION_PERIOD);
} else {
logger.debug(
"subscribeToActivePowerChanges() Refreshing subscription for the next {}min for WHERE={} to active power changes notification",
- ENERGY_SUBSCRIPTION_PERIOD, deviceWhere);
+ POWER_SUBSCRIPTION_PERIOD, deviceWhere);
}
Where w = deviceWhere;
if (w == null) {
logger.warn("subscribeToActivePowerChanges() WHERE=null. Skipping");
} else {
try {
- send(EnergyManagement.setActivePowerNotificationsTime(w.value(), ENERGY_SUBSCRIPTION_PERIOD));
+ send(EnergyManagement.setActivePowerNotificationsTime(w.value(), POWER_SUBSCRIPTION_PERIOD));
isFirstSchedulerLaunch = false;
} catch (Exception e) {
if (isFirstSchedulerLaunch) {
}
}
}
- }, 0, ENERGY_SUBSCRIPTION_PERIOD - 1, TimeUnit.MINUTES);
+ }, 0, POWER_SUBSCRIPTION_PERIOD - 1, TimeUnit.MINUTES);
+ }
+
+ private void subscribeToEnergyTotalizer() {
+ Where w = deviceWhere;
+ if (w == null) {
+ logger.warn("subscribeToEnergyTotalizer() WHERE=null. Skipping");
+ return;
+ }
+ energySchedule = scheduler.scheduleWithFixedDelay(() -> {
+ try {
+ send(EnergyManagement.requestCurrentDayTotalizer(w.value()));
+ send(EnergyManagement.requestCurrentMonthTotalizer(w.value()));
+ } catch (Exception e) {
+ logger.warn(
+ "subscribeToEnergyTotalizer() Could not subscribe to totalizers scheduler for WHERE={}. Exception={}",
+ w, e.getMessage());
+ }
+ }, 0, energyRefreshPeriod, TimeUnit.MINUTES);
}
@Override
public void dispose() {
- if (notificationSchedule != null) {
- ScheduledFuture<?> ns = notificationSchedule;
- ns.cancel(false);
- logger.debug("dispose() scheduler stopped.");
+ ScheduledFuture<?> sfp = powerSchedule;
+ if (sfp != null) {
+ sfp.cancel(false);
+ powerSchedule = null;
+ logger.debug("dispose() power scheduler stopped.");
+ }
+ ScheduledFuture<?> sfe = energySchedule;
+ if (sfe != null) {
+ sfe.cancel(false);
+ energySchedule = null;
+ logger.debug("dispose() energy scheduler stopped.");
}
super.dispose();
}
if (w != null) {
try {
send(EnergyManagement.requestActivePower(w.value()));
+ send(EnergyManagement.requestCurrentDayTotalizer(w.value()));
+ send(EnergyManagement.requestCurrentMonthTotalizer(w.value()));
} catch (OWNException e) {
logger.debug("Exception while requesting state for channel {}: {} ", channel, e.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
protected void refreshDevice(boolean refreshAll) {
logger.debug("--- refreshDevice() : refreshing SINGLE... ({})", thing.getUID());
requestChannelState(new ChannelUID(thing.getUID(), CHANNEL_POWER));
+ requestChannelState(new ChannelUID(thing.getUID(), CHANNEL_ENERGY_TOTALIZER_DAY));
+ requestChannelState(new ChannelUID(thing.getUID(), CHANNEL_ENERGY_TOTALIZER_MONTH));
}
@Override
// fix: check for correct DIM (ActivePower / 113)
if (msg.getDim().equals(EnergyManagement.DimEnergyMgmt.ACTIVE_POWER)) {
updateActivePower(msg);
+ } else if (msg.getDim().equals(EnergyManagement.DimEnergyMgmt.PARTIAL_TOTALIZER_CURRENT_DAY)) {
+ updateCurrentDayTotalizer(msg);
+ } else if (msg.getDim().equals(EnergyManagement.DimEnergyMgmt.PARTIAL_TOTALIZER_CURRENT_MONTH)) {
+ updateCurrentMonthTotalizer(msg);
} else {
logger.debug("handleMessage() Ignoring message {} because it's not related to active power value.",
msg);
* Updates energy power state based on an EnergyManagement message received from the OWN network
*
* @param msg the EnergyManagement message received
- * @throws FrameException
*/
private void updateActivePower(BaseOpenMessage msg) {
Integer activePower;
} catch (FrameException e) {
logger.warn("FrameException on frame {}: {}", msg, e.getMessage());
updateState(CHANNEL_POWER, UnDefType.UNDEF);
+ } catch (NumberFormatException e) {
+ logger.warn("NumberFormatException on frame {}: {}", msg, e.getMessage());
+ updateState(CHANNEL_POWER, UnDefType.UNDEF);
+ }
+ }
+
+ /**
+ * Updates current day totalizer
+ *
+ * @param msg the EnergyManagement message received
+ */
+ private void updateCurrentDayTotalizer(BaseOpenMessage msg) {
+ Double currentDayEnergy;
+ try {
+ currentDayEnergy = Double.parseDouble(msg.getDimValues()[0]) / 1000d;
+ updateState(CHANNEL_ENERGY_TOTALIZER_DAY, new QuantityType<Energy>(currentDayEnergy, Units.KILOWATT_HOUR));
+ } catch (FrameException e) {
+ logger.warn("FrameException on frame {}: {}", msg, e.getMessage());
+ updateState(CHANNEL_ENERGY_TOTALIZER_DAY, UnDefType.UNDEF);
+ } catch (NumberFormatException e) {
+ logger.warn("NumberFormatException on frame {}: {}", msg, e.getMessage());
+ updateState(CHANNEL_ENERGY_TOTALIZER_DAY, UnDefType.UNDEF);
+ }
+ }
+
+ /**
+ * Updates current month totalizer
+ *
+ * @param msg the EnergyManagement message received
+ */
+ private void updateCurrentMonthTotalizer(BaseOpenMessage msg) {
+ Double currentMonthEnergy;
+ try {
+ currentMonthEnergy = Double.parseDouble(msg.getDimValues()[0]) / 1000d;
+ updateState(CHANNEL_ENERGY_TOTALIZER_MONTH,
+ new QuantityType<Energy>(currentMonthEnergy, Units.KILOWATT_HOUR));
+ } catch (FrameException e) {
+ logger.warn("FrameException on frame {}: {}", msg, e.getMessage());
+ updateState(CHANNEL_ENERGY_TOTALIZER_MONTH, UnDefType.UNDEF);
+ } catch (NumberFormatException e) {
+ logger.warn("NumberFormatException on frame {}: {}", msg, e.getMessage());
+ updateState(CHANNEL_ENERGY_TOTALIZER_MONTH, UnDefType.UNDEF);
}
}
}