]> git.basschouten.com Git - openhab-addons.git/blob
150423bffe16e0045cf8089f36cde8437525b288
[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.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;
44
45 /**
46  * The {@link CircuitHandler} is responsible for handling the configuration and updating the metering channels of a
47  * digitalStrom circuit. <br>
48  * <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}.
51  *
52  * @author Michael Ochel
53  * @author Matthias Siegele
54  */
55 public class CircuitHandler extends BaseThingHandler implements DeviceStatusListener {
56
57     private final Logger logger = LoggerFactory.getLogger(CircuitHandler.class);
58
59     /**
60      * Contains all supported thing types of this handler, will be filled by DsDeviceThingTypeProvider.
61      */
62     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>();
63
64     private String dSID;
65     private Circuit circuit;
66
67     private BridgeHandler dssBridgeHandler;
68
69     /**
70      * Creates a new {@link CircuitHandler}.
71      *
72      * @param thing must not be null
73      */
74     public CircuitHandler(Thing thing) {
75         super(thing);
76     }
77
78     @Override
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();
84             if (bridge != null) {
85                 bridgeStatusChanged(bridge.getStatusInfo());
86             } else {
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!");
90             }
91         } else {
92             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "dSID is missing");
93         }
94     }
95
96     @Override
97     public void dispose() {
98         logger.debug("Handler disposed... unregister DeviceStatusListener");
99         if (dSID != null) {
100             if (dssBridgeHandler != null) {
101                 dssBridgeHandler.unregisterDeviceStatusListener(this);
102             }
103         }
104         circuit = null;
105     }
106
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");
112                 return null;
113             }
114             ThingHandler handler = bridge.getHandler();
115
116             if (handler instanceof BridgeHandler) {
117                 dssBridgeHandler = (BridgeHandler) handler;
118             } else {
119                 return null;
120             }
121         }
122         return dssBridgeHandler;
123     }
124
125     @Override
126     public void thingUpdated(Thing thing) {
127         this.thing = thing;
128         if (circuit == null) {
129             initialize();
130         }
131     }
132
133     @Override
134     public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
135         if (bridgeStatusInfo.getStatus().equals(ThingStatus.ONLINE)) {
136             if (dSID != null) {
137                 if (getDssBridgeHandler() != null) {
138                     if (circuit == null) {
139                         updateStatus(ThingStatus.ONLINE, ThingStatusDetail.CONFIGURATION_PENDING,
140                                 "waiting for listener registration");
141                         dssBridgeHandler.registerDeviceStatusListener(this);
142                     } else {
143                         updateStatus(ThingStatus.ONLINE);
144                     }
145                 } else {
146                     updateStatus(ThingStatus.OFFLINE);
147                 }
148             } else {
149                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "No dSID is set!");
150             }
151         }
152         if (bridgeStatusInfo.getStatus().equals(ThingStatus.OFFLINE)) {
153             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
154         }
155         if (bridgeStatusInfo.getStatus().equals(ThingStatus.REMOVED)) {
156             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Bridge has been removed.");
157         }
158         logger.debug("Set status to {}", getThing().getStatusInfo());
159     }
160
161     @Override
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);
166         }
167     }
168
169     @Override
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));
177                     } else {
178                         updateState(getChannelID(cachedVal), new DecimalType(cachedVal.getValue()));
179                     }
180                 }
181             }
182         }
183     }
184
185     @Override
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.");
193                 } else {
194                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE,
195                             "Circuit is not avaible in the digitalSTROM-System.");
196                 }
197
198             }
199             logger.debug("Set status to {}", getThing().getStatus());
200         }
201     }
202
203     @Override
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());
211
212                 checkCircuitInfoProperties(this.circuit);
213
214                 // load first channel values
215                 onCircuitStateInitial(this.circuit);
216                 return;
217             }
218         }
219         onDeviceRemoved(device);
220     }
221
222     private void checkCircuitInfoProperties(Circuit device) {
223         boolean propertiesChanged = false;
224         Map<String, String> properties = editProperties();
225         // check device info
226         if (device.getName() != null) {
227             properties.put(DigitalSTROMBindingConstants.DEVICE_NAME, device.getName());
228             propertiesChanged = true;
229         }
230         if (device.getDSUID() != null) {
231             properties.put(DigitalSTROMBindingConstants.DEVICE_UID, device.getDSUID());
232             propertiesChanged = true;
233         }
234         if (device.getHwName() != null) {
235             properties.put(DigitalSTROMBindingConstants.HW_NAME, device.getHwName());
236             propertiesChanged = true;
237         }
238         if (device.getHwVersionString() != null) {
239             properties.put(DigitalSTROMBindingConstants.HW_VERSION, device.getHwVersionString());
240             propertiesChanged = true;
241         }
242         if (device.getSwVersion() != null) {
243             properties.put(DigitalSTROMBindingConstants.SW_VERSION, device.getSwVersion());
244             propertiesChanged = true;
245         }
246         if (device.getApiVersion() != null) {
247             properties.put(DigitalSTROMBindingConstants.API_VERSION, device.getApiVersion().toString());
248             propertiesChanged = true;
249         }
250         if (device.getDspSwVersion() != null) {
251             properties.put(DigitalSTROMBindingConstants.DSP_SW_VERSION, device.getDspSwVersion().toString());
252             propertiesChanged = true;
253         }
254         if (device.getArmSwVersion() != null) {
255             properties.put(DigitalSTROMBindingConstants.ARM_SW_VERSION, device.getArmSwVersion().toString());
256             propertiesChanged = true;
257         }
258         if (propertiesChanged) {
259             super.updateProperties(properties);
260             propertiesChanged = false;
261         }
262     }
263
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));
271                     }
272                 }
273             }
274         }
275     }
276
277     private String getChannelID(CachedMeteringValue cachedMeterValue) {
278         return DsChannelTypeProvider.getMeteringChannelID(cachedMeterValue.getMeteringType(),
279                 cachedMeterValue.getMeteringUnit(), false);
280     }
281
282     @Override
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);
287             if (val > -1) {
288                 if (meteringType.equals(MeteringTypeEnum.ENERGY)) {
289                     updateState(channelUID, new DecimalType(val * 0.001));
290                 } else {
291                     updateState(channelUID, new DecimalType(val));
292                 }
293             }
294         }
295     }
296
297     @Override
298     public void onDeviceConfigChanged(ChangeableDeviceConfigEnum whatConfig) {
299         // nothing to do, will be registered again
300     }
301
302     @Override
303     public void onSceneConfigAdded(short sceneID) {
304         // nothing to do
305     }
306
307     @Override
308     public String getDeviceStatusListenerID() {
309         return this.dSID;
310     }
311 }