]> git.basschouten.com Git - openhab-addons.git/blob
ede88d34826e0776b20e9c62677816a392d0778f
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 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         logger.debug("Set status to {}", getThing().getStatusInfo());
155     }
156
157     @Override
158     public void handleCommand(ChannelUID channelUID, Command command) {
159         // the same handling like total metering values
160         if (dssBridgeHandler != null) {
161             dssBridgeHandler.handleCommand(channelUID, command);
162         }
163     }
164
165     @Override
166     public void onDeviceStateChanged(DeviceStateUpdate deviceStateUpdate) {
167         if (deviceStateUpdate != null && DeviceStateUpdate.UPDATE_CIRCUIT_METER.equals(deviceStateUpdate.getType())) {
168             if (deviceStateUpdate.getValue() instanceof CachedMeteringValue) {
169                 CachedMeteringValue cachedVal = (CachedMeteringValue) deviceStateUpdate.getValue();
170                 if (MeteringUnitsEnum.WH.equals(cachedVal.getMeteringUnit())) {
171                     if (cachedVal.getMeteringType().equals(MeteringTypeEnum.ENERGY)) {
172                         updateState(getChannelID(cachedVal), new DecimalType(cachedVal.getValue() * 0.001));
173                     } else {
174                         updateState(getChannelID(cachedVal), new DecimalType(cachedVal.getValue()));
175                     }
176                 }
177             }
178         }
179     }
180
181     @Override
182     public void onDeviceRemoved(GeneralDeviceInformation device) {
183         if (device instanceof Circuit) {
184             this.circuit = (Circuit) device;
185             if (getThing().getStatus().equals(ThingStatus.ONLINE)) {
186                 if (!circuit.isPresent()) {
187                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE,
188                             "Circuit is not present in the digitalSTROM-System.");
189                 } else {
190                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE,
191                             "Circuit is not available in the digitalSTROM-System.");
192                 }
193
194             }
195             logger.debug("Set status to {}", getThing().getStatus());
196         }
197     }
198
199     @Override
200     public void onDeviceAdded(GeneralDeviceInformation device) {
201         if (device instanceof Circuit) {
202             this.circuit = (Circuit) device;
203             if (this.circuit.isPresent()) {
204                 ThingStatusInfo statusInfo = this.dssBridgeHandler.getThing().getStatusInfo();
205                 updateStatus(statusInfo.getStatus(), statusInfo.getStatusDetail(), statusInfo.getDescription());
206                 logger.debug("Set status to {}", getThing().getStatus());
207
208                 checkCircuitInfoProperties(this.circuit);
209
210                 // load first channel values
211                 onCircuitStateInitial(this.circuit);
212                 return;
213             }
214         }
215         onDeviceRemoved(device);
216     }
217
218     private void checkCircuitInfoProperties(Circuit device) {
219         boolean propertiesChanged = false;
220         Map<String, String> properties = editProperties();
221         // check device info
222         if (device.getName() != null) {
223             properties.put(DigitalSTROMBindingConstants.DEVICE_NAME, device.getName());
224             propertiesChanged = true;
225         }
226         if (device.getDSUID() != null) {
227             properties.put(DigitalSTROMBindingConstants.DEVICE_UID, device.getDSUID());
228             propertiesChanged = true;
229         }
230         if (device.getHwName() != null) {
231             properties.put(DigitalSTROMBindingConstants.HW_NAME, device.getHwName());
232             propertiesChanged = true;
233         }
234         if (device.getHwVersionString() != null) {
235             properties.put(DigitalSTROMBindingConstants.HW_VERSION, device.getHwVersionString());
236             propertiesChanged = true;
237         }
238         if (device.getSwVersion() != null) {
239             properties.put(DigitalSTROMBindingConstants.SW_VERSION, device.getSwVersion());
240             propertiesChanged = true;
241         }
242         if (device.getApiVersion() != null) {
243             properties.put(DigitalSTROMBindingConstants.API_VERSION, device.getApiVersion().toString());
244             propertiesChanged = true;
245         }
246         if (device.getDspSwVersion() != null) {
247             properties.put(DigitalSTROMBindingConstants.DSP_SW_VERSION, device.getDspSwVersion().toString());
248             propertiesChanged = true;
249         }
250         if (device.getArmSwVersion() != null) {
251             properties.put(DigitalSTROMBindingConstants.ARM_SW_VERSION, device.getArmSwVersion().toString());
252             propertiesChanged = true;
253         }
254         if (propertiesChanged) {
255             super.updateProperties(properties);
256             propertiesChanged = false;
257         }
258     }
259
260     private void onCircuitStateInitial(Circuit circuit) {
261         if (circuit != null) {
262             for (CachedMeteringValue cachedMeterValue : circuit.getAllCachedMeteringValues()) {
263                 if (cachedMeterValue != null && MeteringUnitsEnum.WH.equals(cachedMeterValue.getMeteringUnit())) {
264                     String channelID = getChannelID(cachedMeterValue);
265                     if (isLinked(channelID)) {
266                         channelLinked(new ChannelUID(getThing().getUID(), channelID));
267                     }
268                 }
269             }
270         }
271     }
272
273     private String getChannelID(CachedMeteringValue cachedMeterValue) {
274         return DsChannelTypeProvider.getMeteringChannelID(cachedMeterValue.getMeteringType(),
275                 cachedMeterValue.getMeteringUnit(), false);
276     }
277
278     @Override
279     public void channelLinked(ChannelUID channelUID) {
280         if (circuit != null) {
281             MeteringTypeEnum meteringType = DsChannelTypeProvider.getMeteringType(channelUID.getId());
282             double val = circuit.getMeteringValue(meteringType, MeteringUnitsEnum.WH);
283             if (val > -1) {
284                 if (meteringType.equals(MeteringTypeEnum.ENERGY)) {
285                     updateState(channelUID, new DecimalType(val * 0.001));
286                 } else {
287                     updateState(channelUID, new DecimalType(val));
288                 }
289             }
290         }
291     }
292
293     @Override
294     public void onDeviceConfigChanged(ChangeableDeviceConfigEnum whatConfig) {
295         // nothing to do, will be registered again
296     }
297
298     @Override
299     public void onSceneConfigAdded(short sceneID) {
300         // nothing to do
301     }
302
303     @Override
304     public String getDeviceStatusListenerID() {
305         return this.dSID;
306     }
307 }