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.digitalstrom.internal.handler;
15 import java.util.HashSet;
19 import org.apache.commons.lang.StringUtils;
20 import org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants;
21 import org.openhab.binding.digitalstrom.internal.lib.listener.DeviceStatusListener;
22 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Circuit;
23 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
24 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.GeneralDeviceInformation;
25 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.CachedMeteringValue;
26 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceStateUpdate;
27 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.ChangeableDeviceConfigEnum;
28 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.MeteringTypeEnum;
29 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.MeteringUnitsEnum;
30 import org.openhab.binding.digitalstrom.internal.providers.DsChannelTypeProvider;
31 import org.openhab.core.library.types.DecimalType;
32 import org.openhab.core.thing.Bridge;
33 import org.openhab.core.thing.ChannelUID;
34 import org.openhab.core.thing.Thing;
35 import org.openhab.core.thing.ThingStatus;
36 import org.openhab.core.thing.ThingStatusDetail;
37 import org.openhab.core.thing.ThingStatusInfo;
38 import org.openhab.core.thing.ThingTypeUID;
39 import org.openhab.core.thing.binding.BaseThingHandler;
40 import org.openhab.core.thing.binding.ThingHandler;
41 import org.openhab.core.types.Command;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
46 * The {@link CircuitHandler} is responsible for handling the configuration and updating the metering channels of a
47 * digitalStrom circuit. <br>
49 * For that it uses the {@link BridgeHandler} to register this class as a {@link DeviceStatusListener} to get informed
50 * about changes from the accompanying {@link Circuit}.
52 * @author Michael Ochel
53 * @author Matthias Siegele
55 public class CircuitHandler extends BaseThingHandler implements DeviceStatusListener {
57 private final Logger logger = LoggerFactory.getLogger(CircuitHandler.class);
60 * Contains all supported thing types of this handler, will be filled by DsDeviceThingTypeProvider.
62 public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>();
65 private Circuit circuit;
67 private BridgeHandler dssBridgeHandler;
70 * Creates a new {@link CircuitHandler}.
72 * @param thing must not be null
74 public CircuitHandler(Thing thing) {
79 public void initialize() {
80 logger.debug("Initializing CircuitHandler.");
81 if (StringUtils.isNotBlank((String) getConfig().get(DigitalSTROMBindingConstants.DEVICE_DSID))) {
82 dSID = getConfig().get(DigitalSTROMBindingConstants.DEVICE_DSID).toString();
83 final Bridge bridge = getBridge();
85 bridgeStatusChanged(bridge.getStatusInfo());
87 // Set status to OFFLINE if no bridge is available e.g. because the bridge has been removed and the
88 // Thing was reinitialized.
89 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Bridge is missing!");
92 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "dSID is missing");
97 public void dispose() {
98 logger.debug("Handler disposed... unregister DeviceStatusListener");
100 if (dssBridgeHandler != null) {
101 dssBridgeHandler.unregisterDeviceStatusListener(this);
107 private synchronized BridgeHandler getDssBridgeHandler() {
108 if (this.dssBridgeHandler == null) {
109 Bridge bridge = getBridge();
110 if (bridge == null) {
111 logger.debug("Bride cannot be found");
114 ThingHandler handler = bridge.getHandler();
116 if (handler instanceof BridgeHandler) {
117 dssBridgeHandler = (BridgeHandler) handler;
122 return dssBridgeHandler;
126 public void thingUpdated(Thing thing) {
128 if (circuit == null) {
134 public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
135 if (bridgeStatusInfo.getStatus().equals(ThingStatus.ONLINE)) {
137 if (getDssBridgeHandler() != null) {
138 if (circuit == null) {
139 updateStatus(ThingStatus.ONLINE, ThingStatusDetail.CONFIGURATION_PENDING,
140 "waiting for listener registration");
141 dssBridgeHandler.registerDeviceStatusListener(this);
143 updateStatus(ThingStatus.ONLINE);
146 updateStatus(ThingStatus.OFFLINE);
149 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "No dSID is set!");
152 if (bridgeStatusInfo.getStatus().equals(ThingStatus.OFFLINE)) {
153 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
155 if (bridgeStatusInfo.getStatus().equals(ThingStatus.REMOVED)) {
156 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Bridge has been removed.");
158 logger.debug("Set status to {}", getThing().getStatusInfo());
162 public void handleCommand(ChannelUID channelUID, Command command) {
163 // the same handling like total metering values
164 if (dssBridgeHandler != null) {
165 dssBridgeHandler.handleCommand(channelUID, command);
170 public void onDeviceStateChanged(DeviceStateUpdate deviceStateUpdate) {
171 if (deviceStateUpdate != null && DeviceStateUpdate.UPDATE_CIRCUIT_METER.equals(deviceStateUpdate.getType())) {
172 if (deviceStateUpdate.getValue() instanceof CachedMeteringValue) {
173 CachedMeteringValue cachedVal = (CachedMeteringValue) deviceStateUpdate.getValue();
174 if (MeteringUnitsEnum.WH.equals(cachedVal.getMeteringUnit())) {
175 if (cachedVal.getMeteringType().equals(MeteringTypeEnum.ENERGY)) {
176 updateState(getChannelID(cachedVal), new DecimalType(cachedVal.getValue() * 0.001));
178 updateState(getChannelID(cachedVal), new DecimalType(cachedVal.getValue()));
186 public void onDeviceRemoved(GeneralDeviceInformation device) {
187 if (device instanceof Circuit) {
188 this.circuit = (Circuit) device;
189 if (this.getThing().getStatus().equals(ThingStatus.ONLINE)) {
190 if (!((Device) circuit).isPresent()) {
191 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE,
192 "Circuit is not present in the digitalSTROM-System.");
194 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE,
195 "Circuit is not avaible in the digitalSTROM-System.");
199 logger.debug("Set status to {}", getThing().getStatus());
204 public void onDeviceAdded(GeneralDeviceInformation device) {
205 if (device instanceof Circuit) {
206 this.circuit = (Circuit) device;
207 if (this.circuit.isPresent()) {
208 ThingStatusInfo statusInfo = this.dssBridgeHandler.getThing().getStatusInfo();
209 updateStatus(statusInfo.getStatus(), statusInfo.getStatusDetail(), statusInfo.getDescription());
210 logger.debug("Set status to {}", getThing().getStatus());
212 checkCircuitInfoProperties(this.circuit);
214 // load first channel values
215 onCircuitStateInitial(this.circuit);
219 onDeviceRemoved(device);
222 private void checkCircuitInfoProperties(Circuit device) {
223 boolean propertiesChanged = false;
224 Map<String, String> properties = editProperties();
226 if (device.getName() != null) {
227 properties.put(DigitalSTROMBindingConstants.DEVICE_NAME, device.getName());
228 propertiesChanged = true;
230 if (device.getDSUID() != null) {
231 properties.put(DigitalSTROMBindingConstants.DEVICE_UID, device.getDSUID());
232 propertiesChanged = true;
234 if (device.getHwName() != null) {
235 properties.put(DigitalSTROMBindingConstants.HW_NAME, device.getHwName());
236 propertiesChanged = true;
238 if (device.getHwVersionString() != null) {
239 properties.put(DigitalSTROMBindingConstants.HW_VERSION, device.getHwVersionString());
240 propertiesChanged = true;
242 if (device.getSwVersion() != null) {
243 properties.put(DigitalSTROMBindingConstants.SW_VERSION, device.getSwVersion());
244 propertiesChanged = true;
246 if (device.getApiVersion() != null) {
247 properties.put(DigitalSTROMBindingConstants.API_VERSION, device.getApiVersion().toString());
248 propertiesChanged = true;
250 if (device.getDspSwVersion() != null) {
251 properties.put(DigitalSTROMBindingConstants.DSP_SW_VERSION, device.getDspSwVersion().toString());
252 propertiesChanged = true;
254 if (device.getArmSwVersion() != null) {
255 properties.put(DigitalSTROMBindingConstants.ARM_SW_VERSION, device.getArmSwVersion().toString());
256 propertiesChanged = true;
258 if (propertiesChanged) {
259 super.updateProperties(properties);
260 propertiesChanged = false;
264 private void onCircuitStateInitial(Circuit circuit) {
265 if (circuit != null) {
266 for (CachedMeteringValue cachedMeterValue : circuit.getAllCachedMeteringValues()) {
267 if (cachedMeterValue != null && MeteringUnitsEnum.WH.equals(cachedMeterValue.getMeteringUnit())) {
268 String channelID = getChannelID(cachedMeterValue);
269 if (isLinked(channelID)) {
270 channelLinked(new ChannelUID(getThing().getUID(), channelID));
277 private String getChannelID(CachedMeteringValue cachedMeterValue) {
278 return DsChannelTypeProvider.getMeteringChannelID(cachedMeterValue.getMeteringType(),
279 cachedMeterValue.getMeteringUnit(), false);
283 public void channelLinked(ChannelUID channelUID) {
284 if (circuit != null) {
285 MeteringTypeEnum meteringType = DsChannelTypeProvider.getMeteringType(channelUID.getId());
286 double val = circuit.getMeteringValue(meteringType, MeteringUnitsEnum.WH);
288 if (meteringType.equals(MeteringTypeEnum.ENERGY)) {
289 updateState(channelUID, new DecimalType(val * 0.001));
291 updateState(channelUID, new DecimalType(val));
298 public void onDeviceConfigChanged(ChangeableDeviceConfigEnum whatConfig) {
299 // nothing to do, will be registered again
303 public void onSceneConfigAdded(short sceneID) {
308 public String getDeviceStatusListenerID() {