]> git.basschouten.com Git - openhab-addons.git/blob
e315acddcbef96ea73cf2b019decc7d140f9020d
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.digitalstrom.internal.handler;
14
15 import java.util.HashSet;
16 import java.util.Map;
17 import java.util.Set;
18
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.GeneralDeviceInformation;
24 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.CachedMeteringValue;
25 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceStateUpdate;
26 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.ChangeableDeviceConfigEnum;
27 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.MeteringTypeEnum;
28 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.MeteringUnitsEnum;
29 import org.openhab.binding.digitalstrom.internal.providers.DsChannelTypeProvider;
30 import org.openhab.core.library.types.DecimalType;
31 import org.openhab.core.thing.Bridge;
32 import org.openhab.core.thing.ChannelUID;
33 import org.openhab.core.thing.Thing;
34 import org.openhab.core.thing.ThingStatus;
35 import org.openhab.core.thing.ThingStatusDetail;
36 import org.openhab.core.thing.ThingStatusInfo;
37 import org.openhab.core.thing.ThingTypeUID;
38 import org.openhab.core.thing.binding.BaseThingHandler;
39 import org.openhab.core.thing.binding.ThingHandler;
40 import org.openhab.core.types.Command;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 /**
45  * The {@link CircuitHandler} is responsible for handling the configuration and updating the metering channels of a
46  * digitalStrom circuit. <br>
47  * <br>
48  * For that it uses the {@link BridgeHandler} to register this class as a {@link DeviceStatusListener} to get informed
49  * about changes from the accompanying {@link Circuit}.
50  *
51  * @author Michael Ochel
52  * @author Matthias Siegele
53  */
54 public class CircuitHandler extends BaseThingHandler implements DeviceStatusListener {
55
56     private final Logger logger = LoggerFactory.getLogger(CircuitHandler.class);
57
58     /**
59      * Contains all supported thing types of this handler, will be filled by DsDeviceThingTypeProvider.
60      */
61     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>();
62
63     private String dSID;
64     private Circuit circuit;
65
66     private BridgeHandler dssBridgeHandler;
67
68     /**
69      * Creates a new {@link CircuitHandler}.
70      *
71      * @param thing must not be null
72      */
73     public CircuitHandler(Thing thing) {
74         super(thing);
75     }
76
77     @Override
78     public void initialize() {
79         logger.debug("Initializing CircuitHandler.");
80         if (StringUtils.isNotBlank((String) getConfig().get(DigitalSTROMBindingConstants.DEVICE_DSID))) {
81             dSID = getConfig().get(DigitalSTROMBindingConstants.DEVICE_DSID).toString();
82             final Bridge bridge = getBridge();
83             if (bridge != null) {
84                 bridgeStatusChanged(bridge.getStatusInfo());
85             } else {
86                 // Set status to OFFLINE if no bridge is available e.g. because the bridge has been removed and the
87                 // Thing was reinitialized.
88                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Bridge is missing!");
89             }
90         } else {
91             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "dSID is missing");
92         }
93     }
94
95     @Override
96     public void dispose() {
97         logger.debug("Handler disposed... unregister DeviceStatusListener");
98         if (dSID != null) {
99             if (dssBridgeHandler != null) {
100                 dssBridgeHandler.unregisterDeviceStatusListener(this);
101             }
102         }
103         circuit = null;
104     }
105
106     private synchronized BridgeHandler getDssBridgeHandler() {
107         if (this.dssBridgeHandler == null) {
108             Bridge bridge = getBridge();
109             if (bridge == null) {
110                 logger.debug("Bride cannot be found");
111                 return null;
112             }
113             ThingHandler handler = bridge.getHandler();
114
115             if (handler instanceof BridgeHandler) {
116                 dssBridgeHandler = (BridgeHandler) handler;
117             } else {
118                 return null;
119             }
120         }
121         return dssBridgeHandler;
122     }
123
124     @Override
125     public void thingUpdated(Thing thing) {
126         this.thing = thing;
127         if (circuit == null) {
128             initialize();
129         }
130     }
131
132     @Override
133     public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
134         if (bridgeStatusInfo.getStatus().equals(ThingStatus.ONLINE)) {
135             if (dSID != null) {
136                 if (getDssBridgeHandler() != null) {
137                     if (circuit == null) {
138                         updateStatus(ThingStatus.ONLINE, ThingStatusDetail.CONFIGURATION_PENDING,
139                                 "waiting for listener registration");
140                         dssBridgeHandler.registerDeviceStatusListener(this);
141                     } else {
142                         updateStatus(ThingStatus.ONLINE);
143                     }
144                 } else {
145                     updateStatus(ThingStatus.OFFLINE);
146                 }
147             } else {
148                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "No dSID is set!");
149             }
150         }
151         if (bridgeStatusInfo.getStatus().equals(ThingStatus.OFFLINE)) {
152             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
153         }
154         if (bridgeStatusInfo.getStatus().equals(ThingStatus.REMOVED)) {
155             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Bridge has been removed.");
156         }
157         logger.debug("Set status to {}", getThing().getStatusInfo());
158     }
159
160     @Override
161     public void handleCommand(ChannelUID channelUID, Command command) {
162         // the same handling like total metering values
163         if (dssBridgeHandler != null) {
164             dssBridgeHandler.handleCommand(channelUID, command);
165         }
166     }
167
168     @Override
169     public void onDeviceStateChanged(DeviceStateUpdate deviceStateUpdate) {
170         if (deviceStateUpdate != null && DeviceStateUpdate.UPDATE_CIRCUIT_METER.equals(deviceStateUpdate.getType())) {
171             if (deviceStateUpdate.getValue() instanceof CachedMeteringValue) {
172                 CachedMeteringValue cachedVal = (CachedMeteringValue) deviceStateUpdate.getValue();
173                 if (MeteringUnitsEnum.WH.equals(cachedVal.getMeteringUnit())) {
174                     if (cachedVal.getMeteringType().equals(MeteringTypeEnum.ENERGY)) {
175                         updateState(getChannelID(cachedVal), new DecimalType(cachedVal.getValue() * 0.001));
176                     } else {
177                         updateState(getChannelID(cachedVal), new DecimalType(cachedVal.getValue()));
178                     }
179                 }
180             }
181         }
182     }
183
184     @Override
185     public void onDeviceRemoved(GeneralDeviceInformation device) {
186         if (device instanceof Circuit) {
187             this.circuit = (Circuit) device;
188             if (getThing().getStatus().equals(ThingStatus.ONLINE)) {
189                 if (!circuit.isPresent()) {
190                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE,
191                             "Circuit is not present in the digitalSTROM-System.");
192                 } else {
193                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE,
194                             "Circuit is not available in the digitalSTROM-System.");
195                 }
196
197             }
198             logger.debug("Set status to {}", getThing().getStatus());
199         }
200     }
201
202     @Override
203     public void onDeviceAdded(GeneralDeviceInformation device) {
204         if (device instanceof Circuit) {
205             this.circuit = (Circuit) device;
206             if (this.circuit.isPresent()) {
207                 ThingStatusInfo statusInfo = this.dssBridgeHandler.getThing().getStatusInfo();
208                 updateStatus(statusInfo.getStatus(), statusInfo.getStatusDetail(), statusInfo.getDescription());
209                 logger.debug("Set status to {}", getThing().getStatus());
210
211                 checkCircuitInfoProperties(this.circuit);
212
213                 // load first channel values
214                 onCircuitStateInitial(this.circuit);
215                 return;
216             }
217         }
218         onDeviceRemoved(device);
219     }
220
221     private void checkCircuitInfoProperties(Circuit device) {
222         boolean propertiesChanged = false;
223         Map<String, String> properties = editProperties();
224         // check device info
225         if (device.getName() != null) {
226             properties.put(DigitalSTROMBindingConstants.DEVICE_NAME, device.getName());
227             propertiesChanged = true;
228         }
229         if (device.getDSUID() != null) {
230             properties.put(DigitalSTROMBindingConstants.DEVICE_UID, device.getDSUID());
231             propertiesChanged = true;
232         }
233         if (device.getHwName() != null) {
234             properties.put(DigitalSTROMBindingConstants.HW_NAME, device.getHwName());
235             propertiesChanged = true;
236         }
237         if (device.getHwVersionString() != null) {
238             properties.put(DigitalSTROMBindingConstants.HW_VERSION, device.getHwVersionString());
239             propertiesChanged = true;
240         }
241         if (device.getSwVersion() != null) {
242             properties.put(DigitalSTROMBindingConstants.SW_VERSION, device.getSwVersion());
243             propertiesChanged = true;
244         }
245         if (device.getApiVersion() != null) {
246             properties.put(DigitalSTROMBindingConstants.API_VERSION, device.getApiVersion().toString());
247             propertiesChanged = true;
248         }
249         if (device.getDspSwVersion() != null) {
250             properties.put(DigitalSTROMBindingConstants.DSP_SW_VERSION, device.getDspSwVersion().toString());
251             propertiesChanged = true;
252         }
253         if (device.getArmSwVersion() != null) {
254             properties.put(DigitalSTROMBindingConstants.ARM_SW_VERSION, device.getArmSwVersion().toString());
255             propertiesChanged = true;
256         }
257         if (propertiesChanged) {
258             super.updateProperties(properties);
259             propertiesChanged = false;
260         }
261     }
262
263     private void onCircuitStateInitial(Circuit circuit) {
264         if (circuit != null) {
265             for (CachedMeteringValue cachedMeterValue : circuit.getAllCachedMeteringValues()) {
266                 if (cachedMeterValue != null && MeteringUnitsEnum.WH.equals(cachedMeterValue.getMeteringUnit())) {
267                     String channelID = getChannelID(cachedMeterValue);
268                     if (isLinked(channelID)) {
269                         channelLinked(new ChannelUID(getThing().getUID(), channelID));
270                     }
271                 }
272             }
273         }
274     }
275
276     private String getChannelID(CachedMeteringValue cachedMeterValue) {
277         return DsChannelTypeProvider.getMeteringChannelID(cachedMeterValue.getMeteringType(),
278                 cachedMeterValue.getMeteringUnit(), false);
279     }
280
281     @Override
282     public void channelLinked(ChannelUID channelUID) {
283         if (circuit != null) {
284             MeteringTypeEnum meteringType = DsChannelTypeProvider.getMeteringType(channelUID.getId());
285             double val = circuit.getMeteringValue(meteringType, MeteringUnitsEnum.WH);
286             if (val > -1) {
287                 if (meteringType.equals(MeteringTypeEnum.ENERGY)) {
288                     updateState(channelUID, new DecimalType(val * 0.001));
289                 } else {
290                     updateState(channelUID, new DecimalType(val));
291                 }
292             }
293         }
294     }
295
296     @Override
297     public void onDeviceConfigChanged(ChangeableDeviceConfigEnum whatConfig) {
298         // nothing to do, will be registered again
299     }
300
301     @Override
302     public void onSceneConfigAdded(short sceneID) {
303         // nothing to do
304     }
305
306     @Override
307     public String getDeviceStatusListenerID() {
308         return this.dSID;
309     }
310 }