2 * Copyright (c) 2010-2020 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.innogysmarthome.internal.handler;
15 import static org.openhab.binding.innogysmarthome.internal.InnogyBindingConstants.*;
17 import java.time.format.DateTimeFormatter;
18 import java.time.format.FormatStyle;
19 import java.util.HashMap;
21 import java.util.Map.Entry;
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.openhab.binding.innogysmarthome.internal.client.entity.action.ShutterAction;
27 import org.openhab.binding.innogysmarthome.internal.client.entity.capability.Capability;
28 import org.openhab.binding.innogysmarthome.internal.client.entity.capability.CapabilityState;
29 import org.openhab.binding.innogysmarthome.internal.client.entity.device.Device;
30 import org.openhab.binding.innogysmarthome.internal.client.entity.event.Event;
31 import org.openhab.binding.innogysmarthome.internal.listener.DeviceStatusListener;
32 import org.openhab.core.library.types.*;
33 import org.openhab.core.thing.Bridge;
34 import org.openhab.core.thing.Channel;
35 import org.openhab.core.thing.ChannelUID;
36 import org.openhab.core.thing.CommonTriggerEvents;
37 import org.openhab.core.thing.Thing;
38 import org.openhab.core.thing.ThingStatus;
39 import org.openhab.core.thing.ThingStatusDetail;
40 import org.openhab.core.thing.ThingStatusInfo;
41 import org.openhab.core.thing.ThingTypeUID;
42 import org.openhab.core.thing.binding.BaseThingHandler;
43 import org.openhab.core.thing.binding.ThingHandler;
44 import org.openhab.core.types.Command;
45 import org.openhab.core.types.RefreshType;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
50 * The {@link InnogyDeviceHandler} is responsible for handling the {@link Device}s and their commands, which are
51 * sent to one of the channels.
53 * @author Oliver Kuhl - Initial contribution
56 public class InnogyDeviceHandler extends BaseThingHandler implements DeviceStatusListener {
58 public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = SUPPORTED_DEVICE_THING_TYPES;
60 private static final String DEBUG = "DEBUG";
61 private static final String LONG_PRESS = "LongPress";
62 private static final String SHORT_PRESS = "ShortPress";
64 private final Logger logger = LoggerFactory.getLogger(InnogyDeviceHandler.class);
65 private final Object lock = new Object();
67 private String deviceId = "";
68 private @Nullable InnogyBridgeHandler bridgeHandler;
71 * Constructs a new {@link InnogyDeviceHandler} for the given {@link Thing}.
75 public InnogyDeviceHandler(final Thing thing) {
80 public void handleCommand(final ChannelUID channelUID, final Command command) {
81 logger.debug("handleCommand called for channel '{}' of type '{}' with command '{}'", channelUID,
82 getThing().getThingTypeUID().getId(), command);
84 final InnogyBridgeHandler innogyBridgeHandler = getInnogyBridgeHandler();
85 if (innogyBridgeHandler == null) {
86 logger.warn("BridgeHandler not found. Cannot handle command without bridge.");
89 if (!ThingStatus.ONLINE.equals(innogyBridgeHandler.getThing().getStatus())) {
90 logger.debug("Cannot handle command - bridge is not online. Command ignored.");
94 if (command instanceof RefreshType) {
96 final Device device = innogyBridgeHandler.getDeviceById(deviceId);
98 onDeviceStateChanged(device);
104 if (CHANNEL_SWITCH.equals(channelUID.getId())) {
108 final Device device = innogyBridgeHandler.getDeviceById(deviceId);
109 if (device != null && DEBUG.equals(device.getConfig().getName())) {
110 logger.debug("DEBUG SWITCH ACTIVATED!");
111 if (OnOffType.ON.equals(command)) {
112 innogyBridgeHandler.onEvent(
113 "{\"sequenceNumber\": -1,\"type\": \"MessageCreated\",\"desc\": \"/desc/event/MessageCreated\",\"namespace\": \"core.RWE\",\"timestamp\": \"2019-07-07T18:41:47.2970000Z\",\"source\": \"/desc/device/SHC.RWE/1.0\",\"data\": {\"id\": \"6e5ce2290cd247208f95a5b53736958b\",\"type\": \"DeviceLowBattery\",\"read\": false,\"class\": \"Alert\",\"timestamp\": \"2019-07-07T18:41:47.232Z\",\"devices\": [\"/device/fe51785319854f36a621d0b4f8ea0e25\"],\"properties\": {\"deviceName\": \"Heizkörperthermostat\",\"serialNumber\": \"914110165056\",\"locationName\": \"Bad\"},\"namespace\": \"core.RWE\"}}");
115 innogyBridgeHandler.onEvent(
116 "{\"sequenceNumber\": -1,\"type\": \"MessageDeleted\",\"desc\": \"/desc/event/MessageDeleted\",\"namespace\": \"core.RWE\",\"timestamp\": \"2019-07-07T19:15:39.2100000Z\",\"data\": { \"id\": \"6e5ce2290cd247208f95a5b53736958b\" }}");
121 if (command instanceof OnOffType) {
122 innogyBridgeHandler.commandSwitchDevice(deviceId, OnOffType.ON.equals(command));
126 } else if (CHANNEL_DIMMER.equals(channelUID.getId())) {
127 if (command instanceof DecimalType) {
128 final DecimalType dimLevel = (DecimalType) command;
129 innogyBridgeHandler.commandSetDimmLevel(deviceId, dimLevel.intValue());
130 } else if (command instanceof OnOffType) {
131 if (OnOffType.ON.equals(command)) {
132 innogyBridgeHandler.commandSetDimmLevel(deviceId, 100);
134 innogyBridgeHandler.commandSetDimmLevel(deviceId, 0);
139 } else if (CHANNEL_ROLLERSHUTTER.equals(channelUID.getId())) {
140 if (command instanceof DecimalType) {
141 final DecimalType rollerShutterLevel = (DecimalType) command;
142 innogyBridgeHandler.commandSetRollerShutterLevel(deviceId,
143 invertValueIfConfigured(CHANNEL_ROLLERSHUTTER, rollerShutterLevel.intValue()));
144 } else if (command instanceof OnOffType) {
145 if (OnOffType.ON.equals(command)) {
146 innogyBridgeHandler.commandSetRollerShutterStop(deviceId, ShutterAction.ShutterActions.DOWN);
148 innogyBridgeHandler.commandSetRollerShutterStop(deviceId, ShutterAction.ShutterActions.UP);
150 } else if (command instanceof UpDownType) {
151 if (UpDownType.DOWN.equals(command)) {
152 innogyBridgeHandler.commandSetRollerShutterStop(deviceId, ShutterAction.ShutterActions.DOWN);
154 innogyBridgeHandler.commandSetRollerShutterStop(deviceId, ShutterAction.ShutterActions.UP);
156 } else if (command instanceof StopMoveType) {
157 if (StopMoveType.STOP.equals(command)) {
158 innogyBridgeHandler.commandSetRollerShutterStop(deviceId, ShutterAction.ShutterActions.STOP);
163 } else if (CHANNEL_SET_TEMPERATURE.equals(channelUID.getId())) {
164 if (command instanceof DecimalType) {
165 final DecimalType pointTemperature = (DecimalType) command;
166 innogyBridgeHandler.commandUpdatePointTemperature(deviceId, pointTemperature.doubleValue());
170 } else if (CHANNEL_OPERATION_MODE.equals(channelUID.getId())) {
171 if (command instanceof StringType) {
172 final String autoModeCommand = command.toString();
174 if (CapabilityState.STATE_VALUE_OPERATION_MODE_AUTO.equals(autoModeCommand)) {
175 innogyBridgeHandler.commandSetOperationMode(deviceId, true);
176 } else if (CapabilityState.STATE_VALUE_OPERATION_MODE_MANUAL.equals(autoModeCommand)) {
177 innogyBridgeHandler.commandSetOperationMode(deviceId, false);
179 logger.warn("Could not set operationmode. Invalid value '{}'! Only '{}' or '{}' allowed.",
180 autoModeCommand, CapabilityState.STATE_VALUE_OPERATION_MODE_AUTO,
181 CapabilityState.STATE_VALUE_OPERATION_MODE_MANUAL);
186 } else if (CHANNEL_ALARM.equals(channelUID.getId())) {
187 if (command instanceof OnOffType) {
188 innogyBridgeHandler.commandSwitchAlarm(deviceId, OnOffType.ON.equals(command));
191 logger.debug("UNSUPPORTED channel {} for device {}.", channelUID.getId(), deviceId);
196 public void initialize() {
197 logger.debug("Initializing innogy SmartHome device handler.");
198 initializeThing(getBridge() == null ? null : getBridge().getStatus());
202 public void dispose() {
203 if (bridgeHandler != null) {
204 bridgeHandler.unregisterDeviceStatusListener(this);
209 public void bridgeStatusChanged(final ThingStatusInfo bridgeStatusInfo) {
210 logger.debug("bridgeStatusChanged {}", bridgeStatusInfo);
211 initializeThing(bridgeStatusInfo.getStatus());
215 * Initializes the {@link Thing} corresponding to the given status of the bridge.
217 * @param bridgeStatus
219 private void initializeThing(@Nullable final ThingStatus bridgeStatus) {
220 logger.debug("initializeThing thing {} bridge status {}", getThing().getUID(), bridgeStatus);
221 final String configDeviceId = (String) getConfig().get(PROPERTY_ID);
222 if (configDeviceId != null) {
223 deviceId = configDeviceId;
224 // note: this call implicitly registers our handler as a listener on
226 if (getInnogyBridgeHandler() != null) {
227 if (bridgeStatus == ThingStatus.ONLINE) {
228 if (initializeProperties()) {
229 updateStatus(ThingStatus.ONLINE);
231 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.GONE,
232 "Device not found in innogy config. Was it removed?");
235 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
238 updateStatus(ThingStatus.OFFLINE);
241 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "device id unknown");
246 * Initializes all properties of the {@link Device}, like vendor, serialnumber etc.
248 private boolean initializeProperties() {
249 synchronized (this.lock) {
251 final Device device = getDevice();
252 if (device != null) {
253 final Map<String, String> properties = editProperties();
254 properties.put(PROPERTY_ID, device.getId());
255 properties.put(PROPERTY_PROTOCOL_ID, device.getConfig().getProtocolId());
256 if (device.hasSerialNumber()) {
257 properties.put(Thing.PROPERTY_SERIAL_NUMBER, device.getSerialnumber());
259 properties.put(Thing.PROPERTY_VENDOR, device.getManufacturer());
260 properties.put(PROPERTY_VERSION, device.getVersion());
261 if (device.hasLocation()) {
262 properties.put(PROPERTY_LOCATION, device.getLocation().getName());
264 if (device.isBatteryPowered()) {
265 properties.put(PROPERTY_BATTERY_POWERED, "yes");
267 properties.put(PROPERTY_BATTERY_POWERED, "no");
269 if (device.isController()) {
270 properties.put(PROPERTY_DEVICE_TYPE, "Controller");
271 } else if (device.isVirtualDevice()) {
272 properties.put(PROPERTY_DEVICE_TYPE, "Virtual");
273 } else if (device.isRadioDevice()) {
274 properties.put(PROPERTY_DEVICE_TYPE, "Radio");
278 if (DEVICE_RST.equals(device.getType()) || DEVICE_RST2.equals(device.getType())
279 || DEVICE_WRT.equals(device.getType())) {
280 properties.put(PROPERTY_DISPLAY_CURRENT_TEMPERATURE,
281 device.getConfig().getDisplayCurrentTemperature());
285 if (DEVICE_ANALOG_METER.equals(device.getType()) || DEVICE_GENERATION_METER.equals(device.getType())
286 || DEVICE_SMART_METER.equals(device.getType())
287 || DEVICE_TWO_WAY_METER.equals(device.getType())) {
288 properties.put(PROPERTY_METER_ID, device.getConfig().getMeterId());
289 properties.put(PROPERTY_METER_FIRMWARE_VERSION, device.getConfig().getMeterFirmwareVersion());
292 if (device.getConfig().getTimeOfAcceptance() != null) {
293 properties.put(PROPERTY_TIME_OF_ACCEPTANCE, device.getConfig().getTimeOfAcceptance()
294 .format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)));
296 if (device.getConfig().getTimeOfDiscovery() != null) {
297 properties.put(PROPERTY_TIME_OF_DISCOVERY, device.getConfig().getTimeOfDiscovery()
298 .format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)));
301 updateProperties(properties);
303 onDeviceStateChanged(device);
306 logger.warn("initializeProperties: The device with id {} isn't found", deviceId);
313 * Returns the {@link Device} associated with this {@link InnogyDeviceHandler} (referenced by the
314 * {@link InnogyDeviceHandler#deviceId}).
316 * @return the {@link Device} or null, if not found or no {@link InnogyBridgeHandler} is available
318 private @Nullable Device getDevice() {
319 if (getInnogyBridgeHandler() != null) {
320 return getInnogyBridgeHandler().getDeviceById(deviceId);
326 * Returns the innogy bridge handler.
328 * @return the {@link InnogyBridgeHandler} or null
330 private @Nullable InnogyBridgeHandler getInnogyBridgeHandler() {
331 synchronized (this.lock) {
332 if (this.bridgeHandler == null) {
334 final Bridge bridge = getBridge();
335 if (bridge == null) {
339 final ThingHandler handler = bridge.getHandler();
340 if (handler instanceof InnogyBridgeHandler) {
341 this.bridgeHandler = (InnogyBridgeHandler) handler;
342 this.bridgeHandler.registerDeviceStatusListener(this);
347 return this.bridgeHandler;
352 public void onDeviceStateChanged(final Device device) {
353 synchronized (this.lock) {
354 if (!deviceId.equals(device.getId())) {
355 logger.trace("DeviceId {} not relevant for this handler (responsible for id {})", device.getId(),
360 logger.debug("onDeviceStateChanged called with device {}/{}", device.getConfig().getName(), device.getId());
363 if (device.hasDeviceState()) {
365 Boolean reachable = null;
366 if (device.getDeviceState().hasIsReachableState()) {
367 reachable = device.getDeviceState().isReachable();
370 if (reachable != null && !reachable) {
371 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Device not reachable.");
373 } else if ((reachable != null && reachable) || DEVICE_VARIABLE_ACTUATOR.equals(device.getType())) {
374 if (device.getDeviceState().deviceIsIncluded()) {
375 updateStatus(ThingStatus.ONLINE);
377 updateStatus(ThingStatus.ONLINE, ThingStatusDetail.CONFIGURATION_PENDING,
378 "State is " + device.getDeviceState().getDeviceInclusionState());
383 if (device.isBatteryPowered()) {
384 if (device.hasLowBattery()) {
385 updateState(CHANNEL_BATTERY_LOW, OnOffType.ON);
387 updateState(CHANNEL_BATTERY_LOW, OnOffType.OFF);
392 for (final Entry<String, Capability> entry : device.getCapabilityMap().entrySet()) {
393 final Capability c = entry.getValue();
395 logger.debug("->capability:{} ({}/{})", c.getId(), c.getType(), c.getName());
397 if (c.getCapabilityState() == null) {
398 logger.debug("Capability not available for device {} ({})", device.getConfig().getName(),
402 switch (c.getType()) {
403 case Capability.TYPE_VARIABLEACTUATOR:
404 final Boolean variableActuatorState = c.getCapabilityState().getVariableActuatorState();
405 if (variableActuatorState != null) {
406 updateState(CHANNEL_SWITCH, variableActuatorState ? OnOffType.ON : OnOffType.OFF);
408 logger.debug("State for {} is STILL NULL!! cstate-id: {}, c-id: {}", c.getType(),
409 c.getCapabilityState().getId(), c.getId());
412 case Capability.TYPE_SWITCHACTUATOR:
413 final Boolean switchActuatorState = c.getCapabilityState().getSwitchActuatorState();
414 if (switchActuatorState != null) {
415 updateState(CHANNEL_SWITCH, switchActuatorState ? OnOffType.ON : OnOffType.OFF);
417 logger.debug("State for {} is STILL NULL!! cstate-id: {}, c-id: {}", c.getType(),
418 c.getCapabilityState().getId(), c.getId());
421 case Capability.TYPE_DIMMERACTUATOR:
422 final Integer dimLevel = c.getCapabilityState().getDimmerActuatorState();
423 if (dimLevel != null) {
424 logger.debug("Dimlevel state {}", dimLevel);
425 updateState(CHANNEL_DIMMER, new PercentType(dimLevel));
427 logger.debug("State for {} is STILL NULL!! cstate-id: {}, c-id: {}", c.getType(),
428 c.getCapabilityState().getId(), c.getId());
431 case Capability.TYPE_ROLLERSHUTTERACTUATOR:
432 Integer rollerShutterLevel = c.getCapabilityState().getRollerShutterActuatorState();
433 if (rollerShutterLevel != null) {
434 rollerShutterLevel = invertValueIfConfigured(CHANNEL_ROLLERSHUTTER, rollerShutterLevel);
435 logger.debug("RollerShutterlevel state {}", rollerShutterLevel);
436 updateState(CHANNEL_ROLLERSHUTTER, new PercentType(rollerShutterLevel));
438 logger.debug("State for {} is STILL NULL!! cstate-id: {}, c-id: {}", c.getType(),
439 c.getCapabilityState().getId(), c.getId());
442 case Capability.TYPE_TEMPERATURESENSOR:
444 final Double temperatureSensorState = c.getCapabilityState()
445 .getTemperatureSensorTemperatureState();
446 if (temperatureSensorState != null) {
447 logger.debug("-> Temperature sensor state: {}", temperatureSensorState);
448 updateState(CHANNEL_TEMPERATURE, new DecimalType(temperatureSensorState));
450 logger.debug("State for {} is STILL NULL!! cstate-id: {}, c-id: {}", c.getType(),
451 c.getCapabilityState().getId(), c.getId());
455 final Boolean temperatureSensorFrostWarningState = c.getCapabilityState()
456 .getTemperatureSensorFrostWarningState();
457 if (temperatureSensorFrostWarningState != null) {
458 updateState(CHANNEL_FROST_WARNING,
459 temperatureSensorFrostWarningState ? OnOffType.ON : OnOffType.OFF);
461 logger.debug("State for {} is STILL NULL!! cstate-id: {}, c-id: {}", c.getType(),
462 c.getCapabilityState().getId(), c.getId());
466 case Capability.TYPE_THERMOSTATACTUATOR:
468 final Double thermostatActuatorPointTemperatureState = c.getCapabilityState()
469 .getThermostatActuatorPointTemperatureState();
470 if (thermostatActuatorPointTemperatureState != null) {
471 final DecimalType pointTemp = new DecimalType(thermostatActuatorPointTemperatureState);
473 "Update CHANNEL_SET_TEMPERATURE: state:{}->decType:{} (DeviceName {}, Capab-ID:{})",
474 thermostatActuatorPointTemperatureState, pointTemp, device.getConfig().getName(),
476 updateState(CHANNEL_SET_TEMPERATURE, pointTemp);
478 logger.debug("State for {} is STILL NULL!! cstate-id: {}, c-id: {}", c.getType(),
479 c.getCapabilityState().getId(), c.getId());
483 final String thermostatActuatorOperationModeState = c.getCapabilityState()
484 .getThermostatActuatorOperationModeState();
485 if (thermostatActuatorOperationModeState != null) {
486 final StringType operationMode = new StringType(thermostatActuatorOperationModeState);
487 updateState(CHANNEL_OPERATION_MODE, operationMode);
489 logger.debug("State for {} is STILL NULL!! cstate-id: {}, c-id: {}", c.getType(),
490 c.getCapabilityState().getId(), c.getId());
493 // window reduction active
494 final Boolean thermostatActuatorWindowReductionActiveState = c.getCapabilityState()
495 .getThermostatActuatorWindowReductionActiveState();
496 if (thermostatActuatorWindowReductionActiveState != null) {
497 updateState(CHANNEL_WINDOW_REDUCTION_ACTIVE,
498 thermostatActuatorWindowReductionActiveState ? OnOffType.ON : OnOffType.OFF);
500 logger.debug("State for {} is STILL NULL!! cstate-id: {}, c-id: {}", c.getType(),
501 c.getCapabilityState().getId(), c.getId());
504 case Capability.TYPE_HUMIDITYSENSOR:
506 final Double humidityState = c.getCapabilityState().getHumiditySensorHumidityState();
507 if (humidityState != null) {
508 final DecimalType humidity = new DecimalType(humidityState);
509 updateState(CHANNEL_HUMIDITY, humidity);
511 logger.debug("State for {} is STILL NULL!! cstate-id: {}, c-id: {}", c.getType(),
512 c.getCapabilityState().getId(), c.getId());
516 final Boolean humiditySensorMoldWarningState = c.getCapabilityState()
517 .getHumiditySensorMoldWarningState();
518 if (humiditySensorMoldWarningState != null) {
519 updateState(CHANNEL_MOLD_WARNING,
520 humiditySensorMoldWarningState ? OnOffType.ON : OnOffType.OFF);
522 logger.debug("State for {} is STILL NULL!! cstate-id: {}, c-id: {}", c.getType(),
523 c.getCapabilityState().getId(), c.getId());
526 case Capability.TYPE_WINDOWDOORSENSOR:
527 final Boolean contactState = c.getCapabilityState().getWindowDoorSensorState();
528 if (contactState != null) {
529 updateState(CHANNEL_CONTACT, contactState ? OpenClosedType.OPEN : OpenClosedType.CLOSED);
531 logger.debug("State for {} is STILL NULL!! cstate-id: {}, c-id: {}", c.getType(),
532 c.getCapabilityState().getId(), c.getId());
535 case Capability.TYPE_SMOKEDETECTORSENSOR:
536 final Boolean smokeState = c.getCapabilityState().getSmokeDetectorSensorState();
537 if (smokeState != null) {
538 updateState(CHANNEL_SMOKE, smokeState ? OnOffType.ON : OnOffType.OFF);
540 logger.debug("State for {} is STILL NULL!! cstate-id: {}, c-id: {}", c.getType(),
541 c.getCapabilityState().getId(), c.getId());
544 case Capability.TYPE_ALARMACTUATOR:
545 final Boolean alarmState = c.getCapabilityState().getAlarmActuatorState();
546 if (alarmState != null) {
547 updateState(CHANNEL_ALARM, alarmState ? OnOffType.ON : OnOffType.OFF);
549 logger.debug("State for {} is STILL NULL!! cstate-id: {}, c-id: {}", c.getType(),
550 c.getCapabilityState().getId(), c.getId());
553 case Capability.TYPE_MOTIONDETECTIONSENSOR:
554 final Integer motionState = c.getCapabilityState().getMotionDetectionSensorState();
555 if (motionState != null) {
556 final DecimalType motionCount = new DecimalType(motionState);
557 logger.debug("Motion state {} -> count {}", motionState, motionCount);
558 updateState(CHANNEL_MOTION_COUNT, motionCount);
560 logger.debug("State for {} is STILL NULL!! cstate-id: {}, c-id: {}", c.getType(),
561 c.getCapabilityState().getId(), c.getId());
564 case Capability.TYPE_LUMINANCESENSOR:
565 final Double luminanceState = c.getCapabilityState().getLuminanceSensorState();
566 if (luminanceState != null) {
567 final DecimalType luminance = new DecimalType(luminanceState);
568 updateState(CHANNEL_LUMINANCE, luminance);
570 logger.debug("State for {} is STILL NULL!! cstate-id: {}, c-id: {}", c.getType(),
571 c.getCapabilityState().getId(), c.getId());
574 case Capability.TYPE_PUSHBUTTONSENSOR:
575 final Integer pushCountState = c.getCapabilityState().getPushButtonSensorCounterState();
576 final Integer buttonIndexState = c.getCapabilityState().getPushButtonSensorButtonIndexState();
577 logger.debug("Pushbutton index {} count {}", buttonIndexState, pushCountState);
578 if (pushCountState != null) {
579 final DecimalType pushCount = new DecimalType(pushCountState);
580 // prevent error when buttonIndexState is null
581 if (buttonIndexState != null) {
582 if (buttonIndexState >= 0 && buttonIndexState <= 7) {
583 final int channelIndex = buttonIndexState + 1;
584 final String type = c.getCapabilityState().getPushButtonSensorButtonIndexType();
585 final String triggerEvent = SHORT_PRESS.equals(type)
586 ? CommonTriggerEvents.SHORT_PRESSED
587 : (LONG_PRESS.equals(type) ? CommonTriggerEvents.LONG_PRESSED
588 : CommonTriggerEvents.PRESSED);
590 triggerChannel(CHANNEL_BUTTON + channelIndex, triggerEvent);
591 updateState(String.format(CHANNEL_BUTTON_COUNT, channelIndex), pushCount);
593 logger.debug("Button index {} not supported.", buttonIndexState);
595 // Button handled so remove state to avoid re-trigger.
596 c.getCapabilityState().setPushButtonSensorButtonIndexState(null);
597 c.getCapabilityState().setPushButtonSensorButtonIndexType(null);
599 logger.debug("State for {} is STILL NULL!! cstate-id: {}, c-id: {}", c.getType(),
600 c.getCapabilityState().getId(), c.getId());
603 logger.debug("State for {} is STILL NULL!! cstate-id: {}, c-id: {}", c.getType(),
604 c.getCapabilityState().getId(), c.getId());
607 case Capability.TYPE_ENERGYCONSUMPTIONSENSOR:
608 updateStateForEnergyChannel(CHANNEL_ENERGY_CONSUMPTION_MONTH_KWH,
609 c.getCapabilityState().getEnergyConsumptionSensorEnergyConsumptionMonthKWhState(), c);
610 updateStateForEnergyChannel(CHANNEL_ABOLUTE_ENERGY_CONSUMPTION,
611 c.getCapabilityState().getEnergyConsumptionSensorAbsoluteEnergyConsumptionState(), c);
612 updateStateForEnergyChannel(CHANNEL_ENERGY_CONSUMPTION_MONTH_EURO,
613 c.getCapabilityState().getEnergyConsumptionSensorEnergyConsumptionMonthEuroState(), c);
614 updateStateForEnergyChannel(CHANNEL_ENERGY_CONSUMPTION_DAY_EURO,
615 c.getCapabilityState().getEnergyConsumptionSensorEnergyConsumptionDayEuroState(), c);
616 updateStateForEnergyChannel(CHANNEL_ENERGY_CONSUMPTION_DAY_KWH,
617 c.getCapabilityState().getEnergyConsumptionSensorEnergyConsumptionDayKWhState(), c);
619 case Capability.TYPE_POWERCONSUMPTIONSENSOR:
620 updateStateForEnergyChannel(CHANNEL_POWER_CONSUMPTION_WATT,
621 c.getCapabilityState().getPowerConsumptionSensorPowerConsumptionWattState(), c);
623 case Capability.TYPE_GENERATIONMETERENERGYSENSOR:
624 updateStateForEnergyChannel(CHANNEL_ENERGY_GENERATION_MONTH_KWH,
625 c.getCapabilityState().getGenerationMeterEnergySensorEnergyPerMonthInKWhState(), c);
626 updateStateForEnergyChannel(CHANNEL_TOTAL_ENERGY_GENERATION,
627 c.getCapabilityState().getGenerationMeterEnergySensorTotalEnergyState(), c);
628 updateStateForEnergyChannel(CHANNEL_ENERGY_GENERATION_MONTH_EURO,
629 c.getCapabilityState().getGenerationMeterEnergySensorEnergyPerMonthInEuroState(), c);
630 updateStateForEnergyChannel(CHANNEL_ENERGY_GENERATION_DAY_EURO,
631 c.getCapabilityState().getGenerationMeterEnergySensorEnergyPerDayInEuroState(), c);
632 updateStateForEnergyChannel(CHANNEL_ENERGY_GENERATION_DAY_KWH,
633 c.getCapabilityState().getGenerationMeterEnergySensorEnergyPerDayInKWhState(), c);
635 case Capability.TYPE_GENERATIONMETERPOWERCONSUMPTIONSENSOR:
636 updateStateForEnergyChannel(CHANNEL_POWER_GENERATION_WATT,
637 c.getCapabilityState().getGenerationMeterPowerConsumptionSensorPowerInWattState(), c);
639 case Capability.TYPE_TWOWAYMETERENERGYCONSUMPTIONSENSOR:
640 updateStateForEnergyChannel(CHANNEL_ENERGY_MONTH_KWH,
641 c.getCapabilityState().getTwoWayMeterEnergyConsumptionSensorEnergyPerMonthInKWhState(),
643 updateStateForEnergyChannel(CHANNEL_TOTAL_ENERGY,
644 c.getCapabilityState().getTwoWayMeterEnergyConsumptionSensorTotalEnergyState(), c);
645 updateStateForEnergyChannel(CHANNEL_ENERGY_MONTH_EURO,
646 c.getCapabilityState().getTwoWayMeterEnergyConsumptionSensorEnergyPerMonthInEuroState(),
648 updateStateForEnergyChannel(CHANNEL_ENERGY_DAY_EURO,
649 c.getCapabilityState().getTwoWayMeterEnergyConsumptionSensorEnergyPerDayInEuroState(),
651 updateStateForEnergyChannel(CHANNEL_ENERGY_DAY_KWH,
652 c.getCapabilityState().getTwoWayMeterEnergyConsumptionSensorEnergyPerDayInKWhState(),
655 case Capability.TYPE_TWOWAYMETERENERGYFEEDSENSOR:
656 updateStateForEnergyChannel(CHANNEL_ENERGY_FEED_MONTH_KWH,
657 c.getCapabilityState().getTwoWayMeterEnergyFeedSensorEnergyPerMonthInKWhState(), c);
658 updateStateForEnergyChannel(CHANNEL_TOTAL_ENERGY_FED,
659 c.getCapabilityState().getTwoWayMeterEnergyFeedSensorTotalEnergyState(), c);
660 updateStateForEnergyChannel(CHANNEL_ENERGY_FEED_MONTH_EURO,
661 c.getCapabilityState().getTwoWayMeterEnergyFeedSensorEnergyPerMonthInEuroState(), c);
662 updateStateForEnergyChannel(CHANNEL_ENERGY_FEED_DAY_EURO,
663 c.getCapabilityState().getTwoWayMeterEnergyFeedSensorEnergyPerDayInEuroState(), c);
664 updateStateForEnergyChannel(CHANNEL_ENERGY_FEED_DAY_KWH,
665 c.getCapabilityState().getTwoWayMeterEnergyFeedSensorEnergyPerDayInKWhState(), c);
667 case Capability.TYPE_TWOWAYMETERPOWERCONSUMPTIONSENSOR:
668 updateStateForEnergyChannel(CHANNEL_POWER_WATT,
669 c.getCapabilityState().getTwoWayMeterPowerConsumptionSensorPowerInWattState(), c);
672 logger.debug("Unsupported capability type {}.", c.getType());
680 * Updates the state for the {@link Channel} of an energy {@link Device}.
686 private void updateStateForEnergyChannel(final String channelId, @Nullable final Double state,
687 final Capability capability) {
689 final DecimalType newValue = new DecimalType(state);
690 updateState(channelId, newValue);
692 logger.debug("State for {} is STILL NULL!! cstate-id: {}, c-id: {}", capability.getType(),
693 capability.getCapabilityState().getId(), capability.getId());
698 public void onDeviceStateChanged(final Device changedDevice, final Event event) {
699 synchronized (this.lock) {
700 Device device = changedDevice;
701 if (!deviceId.equals(device.getId())) {
705 logger.trace("DeviceId {} relevant for this handler.", device.getId());
707 if (event.isLinkedtoCapability()) {
708 boolean deviceChanged = false;
709 final String linkedCapabilityId = event.getSourceId();
711 HashMap<String, Capability> capabilityMap = device.getCapabilityMap();
712 Capability capability = capabilityMap.get(linkedCapabilityId);
713 logger.trace("Loaded Capability {}, {} with id {}, device {} from device id {}", capability.getType(),
714 capability.getName(), capability.getId(), capability.getDeviceLink(), device.getId());
716 CapabilityState capabilityState;
717 if (capability.hasState()) {
718 capabilityState = capability.getCapabilityState();
721 if (capability.isTypeVariableActuator()) {
722 capabilityState.setVariableActuatorState(event.getProperties().getValue());
723 deviceChanged = true;
726 } else if (capability.isTypeSwitchActuator()) {
727 capabilityState.setSwitchActuatorState(event.getProperties().getOnState());
728 deviceChanged = true;
731 } else if (capability.isTypeDimmerActuator()) {
732 capabilityState.setDimmerActuatorState(event.getProperties().getDimLevel());
733 deviceChanged = true;
735 // RollerShutterActuator
736 } else if (capability.isTypeRollerShutterActuator()) {
737 capabilityState.setRollerShutterActuatorState(event.getProperties().getShutterLevel());
738 deviceChanged = true;
741 } else if (capability.isTypeTemperatureSensor()) {
742 // when values are changed, they come with separate events
743 // values should only updated when they are not null
744 final Double tmpTemperatureState = event.getProperties().getTemperature();
745 final Boolean tmpFrostWarningState = event.getProperties().getFrostWarning();
746 if (tmpTemperatureState != null) {
747 capabilityState.setTemperatureSensorTemperatureState(tmpTemperatureState);
749 if (tmpFrostWarningState != null) {
750 capabilityState.setTemperatureSensorFrostWarningState(tmpFrostWarningState);
752 deviceChanged = true;
754 // ThermostatActuator
755 } else if (capability.isTypeThermostatActuator()) {
756 // when values are changed, they come with separate events
757 // values should only updated when they are not null
759 final Double tmpPointTemperatureState = event.getProperties().getPointTemperature();
760 final String tmpOperationModeState = event.getProperties().getOperationMode();
761 final Boolean tmpWindowReductionActiveState = event.getProperties().getWindowReductionActive();
763 if (tmpPointTemperatureState != null) {
764 capabilityState.setThermostatActuatorPointTemperatureState(tmpPointTemperatureState);
766 if (tmpOperationModeState != null) {
767 capabilityState.setThermostatActuatorOperationModeState(tmpOperationModeState);
769 if (tmpWindowReductionActiveState != null) {
771 .setThermostatActuatorWindowReductionActiveState(tmpWindowReductionActiveState);
773 deviceChanged = true;
776 } else if (capability.isTypeHumiditySensor()) {
777 // when values are changed, they come with separate events
778 // values should only updated when they are not null
779 final Double tmpHumidityState = event.getProperties().getHumidity();
780 final Boolean tmpMoldWarningState = event.getProperties().getMoldWarning();
781 if (tmpHumidityState != null) {
782 capabilityState.setHumiditySensorHumidityState(tmpHumidityState);
784 if (tmpMoldWarningState != null) {
785 capabilityState.setHumiditySensorMoldWarningState(tmpMoldWarningState);
787 deviceChanged = true;
790 } else if (capability.isTypeWindowDoorSensor()) {
791 capabilityState.setWindowDoorSensorState(event.getProperties().getIsOpen());
792 deviceChanged = true;
794 // SmokeDetectorSensor
795 } else if (capability.isTypeSmokeDetectorSensor()) {
796 capabilityState.setSmokeDetectorSensorState(event.getProperties().getIsSmokeAlarm());
797 deviceChanged = true;
800 } else if (capability.isTypeAlarmActuator()) {
801 capabilityState.setAlarmActuatorState(event.getProperties().getOnState());
802 deviceChanged = true;
804 // MotionDetectionSensor
805 } else if (capability.isTypeMotionDetectionSensor()) {
806 capabilityState.setMotionDetectionSensorState(event.getProperties().getMotionDetectedCount());
807 deviceChanged = true;
810 } else if (capability.isTypeLuminanceSensor()) {
811 capabilityState.setLuminanceSensorState(event.getProperties().getLuminance());
812 deviceChanged = true;
815 } else if (capability.isTypePushButtonSensor()) {
816 // Some devices send both StateChanged and ButtonPressed. But only one should be handled.
817 // If ButtonPressed is send lastPressedButtonIndex is not set in StateChanged so ignore
819 // type is also not always present if null will be interpreted as a normal key press.
820 final Integer tmpButtonIndex = event.getProperties().getLastPressedButtonIndex();
822 if (tmpButtonIndex != null) {
823 capabilityState.setPushButtonSensorButtonIndexState(tmpButtonIndex);
825 .setPushButtonSensorButtonIndexType(event.getProperties().getLastKeyPressType());
827 final Integer tmpLastKeyPressCounter = event.getProperties().getLastKeyPressCounter();
829 if (tmpLastKeyPressCounter != null) {
830 capabilityState.setPushButtonSensorCounterState(tmpLastKeyPressCounter);
832 deviceChanged = true;
835 // EnergyConsumptionSensor
836 } else if (capability.isTypeEnergyConsumptionSensor()) {
837 capabilityState.setEnergyConsumptionSensorEnergyConsumptionMonthKWhState(
838 event.getProperties().getEnergyConsumptionMonthKWh());
839 capabilityState.setEnergyConsumptionSensorAbsoluteEnergyConsumptionState(
840 event.getProperties().getAbsoluteEnergyConsumption());
841 capabilityState.setEnergyConsumptionSensorEnergyConsumptionMonthEuroState(
842 event.getProperties().getEnergyConsumptionMonthEuro());
843 capabilityState.setEnergyConsumptionSensorEnergyConsumptionDayEuroState(
844 event.getProperties().getEnergyConsumptionDayEuro());
845 capabilityState.setEnergyConsumptionSensorEnergyConsumptionDayKWhState(
846 event.getProperties().getEnergyConsumptionDayKWh());
847 deviceChanged = true;
849 // PowerConsumptionSensor
850 } else if (capability.isTypePowerConsumptionSensor()) {
851 capabilityState.setPowerConsumptionSensorPowerConsumptionWattState(
852 event.getProperties().getPowerConsumptionWatt());
853 deviceChanged = true;
855 // GenerationMeterEnergySensor
856 } else if (capability.isTypeGenerationMeterEnergySensor()) {
857 capabilityState.setGenerationMeterEnergySensorEnergyPerMonthInKWhState(
858 event.getProperties().getEnergyPerMonthInKWh());
860 .setGenerationMeterEnergySensorTotalEnergyState(event.getProperties().getTotalEnergy());
861 capabilityState.setGenerationMeterEnergySensorEnergyPerMonthInEuroState(
862 event.getProperties().getEnergyPerMonthInEuro());
863 capabilityState.setGenerationMeterEnergySensorEnergyPerDayInEuroState(
864 event.getProperties().getEnergyPerDayInEuro());
865 capabilityState.setGenerationMeterEnergySensorEnergyPerDayInKWhState(
866 event.getProperties().getEnergyPerDayInKWh());
867 deviceChanged = true;
869 // GenerationMeterPowerConsumptionSensor
870 } else if (capability.isTypeGenerationMeterPowerConsumptionSensor()) {
871 capabilityState.setGenerationMeterPowerConsumptionSensorPowerInWattState(
872 event.getProperties().getPowerInWatt());
873 deviceChanged = true;
875 // TwoWayMeterEnergyConsumptionSensor
876 } else if (capability.isTypeTwoWayMeterEnergyConsumptionSensor()) {
877 capabilityState.setTwoWayMeterEnergyConsumptionSensorEnergyPerMonthInKWhState(
878 event.getProperties().getEnergyPerMonthInKWh());
879 capabilityState.setTwoWayMeterEnergyConsumptionSensorTotalEnergyState(
880 event.getProperties().getTotalEnergy());
881 capabilityState.setTwoWayMeterEnergyConsumptionSensorEnergyPerMonthInEuroState(
882 event.getProperties().getEnergyPerMonthInEuro());
883 capabilityState.setTwoWayMeterEnergyConsumptionSensorEnergyPerDayInEuroState(
884 event.getProperties().getEnergyPerDayInEuro());
885 capabilityState.setTwoWayMeterEnergyConsumptionSensorEnergyPerDayInKWhState(
886 event.getProperties().getEnergyPerDayInKWh());
887 deviceChanged = true;
889 // TwoWayMeterEnergyFeedSensor
890 } else if (capability.isTypeTwoWayMeterEnergyFeedSensor()) {
891 capabilityState.setTwoWayMeterEnergyFeedSensorEnergyPerMonthInKWhState(
892 event.getProperties().getEnergyPerMonthInKWh());
894 .setTwoWayMeterEnergyFeedSensorTotalEnergyState(event.getProperties().getTotalEnergy());
895 capabilityState.setTwoWayMeterEnergyFeedSensorEnergyPerMonthInEuroState(
896 event.getProperties().getEnergyPerMonthInEuro());
897 capabilityState.setTwoWayMeterEnergyFeedSensorEnergyPerDayInEuroState(
898 event.getProperties().getEnergyPerDayInEuro());
899 capabilityState.setTwoWayMeterEnergyFeedSensorEnergyPerDayInKWhState(
900 event.getProperties().getEnergyPerDayInKWh());
901 deviceChanged = true;
903 // TwoWayMeterPowerConsumptionSensor
904 } else if (capability.isTypeTwoWayMeterPowerConsumptionSensor()) {
905 capabilityState.setTwoWayMeterPowerConsumptionSensorPowerInWattState(
906 event.getProperties().getPowerInWatt());
907 deviceChanged = true;
910 logger.debug("Unsupported capability type {}.", capability.getType());
913 logger.debug("Capability {} has no state (yet?) - refreshing device.", capability.getName());
916 final InnogyBridgeHandler innogyBridgeHandler = getInnogyBridgeHandler();
917 if (innogyBridgeHandler != null) {
918 device = innogyBridgeHandler.refreshDevice(deviceId);
920 if (device != null) {
921 capabilityMap = device.getCapabilityMap();
922 capability = capabilityMap.get(linkedCapabilityId);
923 if (capability.hasState()) {
924 deviceChanged = true;
928 if (deviceChanged && device != null) {
929 onDeviceStateChanged(device);
932 } else if (event.isLinkedtoDevice()) {
933 if (device.hasDeviceState()) {
934 onDeviceStateChanged(device);
936 logger.debug("Device {}/{} has no state.", device.getConfig().getName(), device.getId());
943 * Returns the inverted value. Currently only rollershutter channels are supported.
946 * @return the value or the inverted value
948 private int invertValueIfConfigured(final String channelId, final int value) {
949 if (!CHANNEL_ROLLERSHUTTER.equals(channelId)) {
950 logger.debug("Channel {} cannot be inverted.", channelId);
955 final Channel channel = getThing().getChannel(channelId);
956 if (channel == null) {
957 logger.debug("Channel {} was null! Value not inverted.", channelId);
960 final Boolean invert = (Boolean) channel.getConfiguration().get("invert");
961 return invert != null && invert ? value : (100 - value);