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