]> git.basschouten.com Git - openhab-addons.git/blob
6aee1157f7ccfe043310bc2995512daa627c5a9b
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 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.nikohomecontrol.internal.handler;
14
15 import static org.openhab.binding.nikohomecontrol.internal.NikoHomeControlBindingConstants.*;
16 import static org.openhab.core.types.RefreshType.REFRESH;
17
18 import java.util.HashMap;
19 import java.util.Map;
20
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.openhab.binding.nikohomecontrol.internal.protocol.NhcEnergyMeter;
24 import org.openhab.binding.nikohomecontrol.internal.protocol.NhcEnergyMeterEvent;
25 import org.openhab.binding.nikohomecontrol.internal.protocol.NikoHomeControlCommunication;
26 import org.openhab.binding.nikohomecontrol.internal.protocol.nhc2.NhcEnergyMeter2;
27 import org.openhab.core.library.types.QuantityType;
28 import org.openhab.core.library.unit.Units;
29 import org.openhab.core.thing.Bridge;
30 import org.openhab.core.thing.ChannelUID;
31 import org.openhab.core.thing.Thing;
32 import org.openhab.core.thing.ThingStatus;
33 import org.openhab.core.thing.ThingStatusDetail;
34 import org.openhab.core.thing.binding.BaseThingHandler;
35 import org.openhab.core.types.Command;
36 import org.openhab.core.types.UnDefType;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 /**
41  * The {@link NikoHomeControlEnergyMeterHandler} is responsible for handling commands, which are
42  * sent to one of the channels.
43  *
44  * @author Mark Herwege - Initial Contribution
45  */
46 @NonNullByDefault
47 public class NikoHomeControlEnergyMeterHandler extends BaseThingHandler implements NhcEnergyMeterEvent {
48
49     private final Logger logger = LoggerFactory.getLogger(NikoHomeControlEnergyMeterHandler.class);
50
51     private volatile @Nullable NhcEnergyMeter nhcEnergyMeter;
52
53     private String energyMeterId = "";
54
55     public NikoHomeControlEnergyMeterHandler(Thing thing) {
56         super(thing);
57     }
58
59     @Override
60     public void handleCommand(ChannelUID channelUID, Command command) {
61         NhcEnergyMeter nhcEnergyMeter = this.nhcEnergyMeter;
62         if (nhcEnergyMeter == null) {
63             logger.debug("energy meter with ID {} not initialized", energyMeterId);
64             return;
65         }
66
67         if (REFRESH.equals(command)) {
68             energyMeterEvent(nhcEnergyMeter.getPower());
69         }
70     }
71
72     @Override
73     public void initialize() {
74         NikoHomeControlEnergyMeterConfig config = getConfig().as(NikoHomeControlEnergyMeterConfig.class);
75
76         energyMeterId = config.energyMeterId;
77
78         NikoHomeControlCommunication nhcComm = getCommunication();
79         if (nhcComm == null) {
80             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED,
81                     "@text/offline.bridge-unitialized");
82             return;
83         } else {
84             updateStatus(ThingStatus.UNKNOWN);
85         }
86
87         // We need to do this in a separate thread because we may have to wait for the
88         // communication to become active
89         scheduler.submit(() -> {
90             if (!nhcComm.communicationActive()) {
91                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
92                         "@text/offline.communication-error");
93                 return;
94             }
95
96             NhcEnergyMeter nhcEnergyMeter = nhcComm.getEnergyMeters().get(energyMeterId);
97             if (nhcEnergyMeter == null) {
98                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
99                         "@text/offline.configuration-error.energyMeterId");
100                 return;
101             }
102
103             nhcEnergyMeter.setEventHandler(this);
104
105             updateProperties(nhcEnergyMeter);
106
107             String location = nhcEnergyMeter.getLocation();
108             if (thing.getLocation() == null) {
109                 thing.setLocation(location);
110             }
111
112             // Subscribing to power readings starts an intensive data flow, therefore only do it when there is an item
113             // linked to the channel
114             if (isLinked(CHANNEL_POWER)) {
115                 nhcComm.startEnergyMeter(energyMeterId);
116             }
117
118             this.nhcEnergyMeter = nhcEnergyMeter;
119
120             logger.debug("energy meter intialized {}", energyMeterId);
121
122             Bridge bridge = getBridge();
123             if ((bridge != null) && (bridge.getStatus() == ThingStatus.ONLINE)) {
124                 updateStatus(ThingStatus.ONLINE);
125             } else {
126                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
127             }
128         });
129     }
130
131     @Override
132     public void dispose() {
133         NikoHomeControlCommunication nhcComm = getCommunication();
134
135         if (nhcComm != null) {
136             nhcComm.stopEnergyMeter(energyMeterId);
137         }
138     }
139
140     private void updateProperties(NhcEnergyMeter nhcEnergyMeter) {
141         Map<String, String> properties = new HashMap<>();
142
143         if (nhcEnergyMeter instanceof NhcEnergyMeter2) {
144             NhcEnergyMeter2 energyMeter = (NhcEnergyMeter2) nhcEnergyMeter;
145             properties.put(PROPERTY_DEVICE_TYPE, energyMeter.getDeviceType());
146             properties.put(PROPERTY_DEVICE_TECHNOLOGY, energyMeter.getDeviceTechnology());
147             properties.put(PROPERTY_DEVICE_MODEL, energyMeter.getDeviceModel());
148         }
149
150         thing.setProperties(properties);
151     }
152
153     @Override
154     public void energyMeterEvent(@Nullable Integer power) {
155         if (power == null) {
156             updateState(CHANNEL_POWER, UnDefType.UNDEF);
157         } else {
158             updateState(CHANNEL_POWER, new QuantityType<>(power, Units.WATT));
159         }
160         updateStatus(ThingStatus.ONLINE);
161     }
162
163     @Override
164     public void energyMeterInitialized() {
165         Bridge bridge = getBridge();
166         if ((bridge != null) && (bridge.getStatus() == ThingStatus.ONLINE)) {
167             updateStatus(ThingStatus.ONLINE);
168         }
169     }
170
171     @Override
172     public void energyMeterRemoved() {
173         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
174                 "@text/offline.configuration-error.energyMeterRemoved");
175     }
176
177     @Override
178     // Subscribing to power readings starts an intensive data flow, therefore only do it when there is an item linked to
179     // the channel
180     public void channelLinked(ChannelUID channelUID) {
181         NikoHomeControlCommunication nhcComm = getCommunication();
182         if (nhcComm != null) {
183             // This can be expensive, therefore do it in a job.
184             scheduler.submit(() -> {
185                 if (!nhcComm.communicationActive()) {
186                     restartCommunication(nhcComm);
187                 }
188
189                 if (nhcComm.communicationActive()) {
190                     nhcComm.startEnergyMeter(energyMeterId);
191                     updateStatus(ThingStatus.ONLINE);
192                 }
193             });
194         }
195     }
196
197     @Override
198     public void channelUnlinked(ChannelUID channelUID) {
199         NikoHomeControlCommunication nhcComm = getCommunication();
200         if (nhcComm != null) {
201             // This can be expensive, therefore do it in a job.
202             scheduler.submit(() -> {
203                 if (!nhcComm.communicationActive()) {
204                     restartCommunication(nhcComm);
205                 }
206
207                 if (nhcComm.communicationActive()) {
208                     nhcComm.stopEnergyMeter(energyMeterId);
209                     // as this is momentary power production/consumption, we set it UNDEF as we do not get readings
210                     // anymore
211                     updateState(CHANNEL_POWER, UnDefType.UNDEF);
212                     updateStatus(ThingStatus.ONLINE);
213                 }
214             });
215         }
216     }
217
218     private void restartCommunication(NikoHomeControlCommunication nhcComm) {
219         // We lost connection but the connection object is there, so was correctly started.
220         // Try to restart communication.
221         nhcComm.restartCommunication();
222         // If still not active, take thing offline and return.
223         if (!nhcComm.communicationActive()) {
224             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
225                     "@text/offline.communication-error");
226             return;
227         }
228         // Also put the bridge back online
229         NikoHomeControlBridgeHandler nhcBridgeHandler = getBridgeHandler();
230         if (nhcBridgeHandler != null) {
231             nhcBridgeHandler.bridgeOnline();
232         } else {
233             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED,
234                     "@text/offline.bridge-unitialized");
235         }
236     }
237
238     private @Nullable NikoHomeControlCommunication getCommunication() {
239         NikoHomeControlBridgeHandler nhcBridgeHandler = getBridgeHandler();
240         return nhcBridgeHandler != null ? nhcBridgeHandler.getCommunication() : null;
241     }
242
243     private @Nullable NikoHomeControlBridgeHandler getBridgeHandler() {
244         Bridge nhcBridge = getBridge();
245         return nhcBridge != null ? (NikoHomeControlBridgeHandler) nhcBridge.getHandler() : null;
246     }
247 }