]> git.basschouten.com Git - openhab-addons.git/blob
2ba986ddd44aec98973efa6fe0e9b0d86539b776
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.jablotron.internal.handler;
14
15 import static org.openhab.binding.jablotron.JablotronBindingConstants.*;
16
17 import java.util.List;
18
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.openhab.binding.jablotron.internal.model.JablotronHistoryDataEvent;
22 import org.openhab.binding.jablotron.internal.model.JablotronServiceDetailSegment;
23 import org.openhab.binding.jablotron.internal.model.ja100f.JablotronGetPGResponse;
24 import org.openhab.binding.jablotron.internal.model.ja100f.JablotronGetSectionsResponse;
25 import org.openhab.binding.jablotron.internal.model.ja100f.JablotronGetThermoDevicesResponse;
26 import org.openhab.binding.jablotron.internal.model.ja100f.JablotronSection;
27 import org.openhab.binding.jablotron.internal.model.ja100f.JablotronState;
28 import org.openhab.binding.jablotron.internal.model.ja100f.JablotronThermoDevice;
29 import org.openhab.core.cache.ExpiringCache;
30 import org.openhab.core.library.types.OnOffType;
31 import org.openhab.core.library.types.QuantityType;
32 import org.openhab.core.library.types.StringType;
33 import org.openhab.core.library.unit.SIUnits;
34 import org.openhab.core.thing.Channel;
35 import org.openhab.core.thing.ChannelUID;
36 import org.openhab.core.thing.Thing;
37 import org.openhab.core.thing.binding.builder.ChannelBuilder;
38 import org.openhab.core.thing.binding.builder.ThingBuilder;
39 import org.openhab.core.thing.type.ChannelTypeUID;
40 import org.openhab.core.types.Command;
41 import org.openhab.core.types.RefreshType;
42 import org.openhab.core.types.State;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46 /**
47  * The {@link JablotronJa100FHandler} is responsible for handling commands, which are
48  * sent to one of the channels.
49  *
50  * @author Ondrej Pecta - Initial contribution
51  */
52 @NonNullByDefault
53 public class JablotronJa100FHandler extends JablotronAlarmHandler {
54
55     private final Logger logger = LoggerFactory.getLogger(JablotronJa100FHandler.class);
56
57     private ExpiringCache<JablotronGetSectionsResponse> sectionCache;
58     private ExpiringCache<JablotronGetPGResponse> pgCache;
59
60     public JablotronJa100FHandler(Thing thing, String alarmName) {
61         super(thing, alarmName);
62         sectionCache = new ExpiringCache<>(CACHE_TIMEOUT_MS, this::sendGetSections);
63         pgCache = new ExpiringCache<>(CACHE_TIMEOUT_MS, this::sendGetProgrammableGates);
64     }
65
66     @Override
67     public void handleCommand(ChannelUID channelUID, Command command) {
68         if (RefreshType.REFRESH.equals(command)) {
69             logger.debug("refreshing channel: {}", channelUID.getId());
70             updateChannel(channelUID.getId());
71         } else {
72             if (channelUID.getId().startsWith("sec-") && command instanceof StringType) {
73                 if ("PARTIAL_ARM".equals(command.toString())) {
74                     controlComponent(channelUID.getId(), "CONTROL-SECTION", "DISARM");
75                 }
76                 scheduler.execute(() -> controlComponent(channelUID.getId().toUpperCase(), "CONTROL-SECTION",
77                         command.toString()));
78             }
79
80             if (channelUID.getId().startsWith("pg-") && command instanceof OnOffType) {
81                 scheduler.execute(
82                         () -> controlComponent(channelUID.getId().toUpperCase(), "CONTROL-PG", command.toString()));
83             }
84         }
85     }
86
87     private void updateChannel(String channel) {
88         if (channel.startsWith("sec-")) {
89             JablotronGetSectionsResponse sections = sectionCache.getValue();
90             if (sections != null) {
91                 updateSectionState(channel, sections.getData().getStates());
92             }
93         } else if (channel.startsWith("pg-")) {
94             JablotronGetPGResponse pgs = pgCache.getValue();
95             if (pgs != null) {
96                 updateSectionState(channel, pgs.getData().getStates());
97             }
98         } else if (CHANNEL_LAST_CHECK_TIME.equals(channel)) {
99             // not updating
100         } else {
101             updateEventChannel(channel);
102         }
103     }
104
105     @Override
106     protected void updateSegmentStatus(JablotronServiceDetailSegment segment) {
107         // nothing
108     }
109
110     private void controlComponent(String componentId, String action, String value) {
111         logger.debug("Controlling component: {} with action: {} and value: {}", componentId, action, value);
112
113         JablotronBridgeHandler handler = getBridgeHandler();
114         if (handler != null) {
115             JablotronGetSectionsResponse response;
116             try {
117                 response = handler.controlComponent(getThing(), thingConfig.getCode(), action, value, componentId);
118             } catch (SecurityException se) {
119                 response = handler.controlComponent(getThing(), thingConfig.getCode(), action, value, componentId);
120             }
121             if (response != null) {
122                 updateSectionState(response.getData().getStates());
123             } else {
124                 logger.debug("null response/status received during the control of component: {}", componentId);
125                 updateAlarmStatus();
126             }
127         }
128     }
129
130     private void createPGChannel(String name, String label) {
131         ChannelTypeUID pgmStatus = new ChannelTypeUID(BINDING_ID, "pgm_state");
132         ThingBuilder thingBuilder = editThing();
133         Channel channel = ChannelBuilder.create(new ChannelUID(thing.getUID(), name), "Switch").withLabel(label)
134                 .withType(pgmStatus).build();
135         thingBuilder.withChannel(channel);
136         updateThing(thingBuilder.build());
137     }
138
139     private void createStateChannel(String name, String label) {
140         ChannelTypeUID alarmStatus = new ChannelTypeUID(BINDING_ID, "ja100f_alarm_state");
141         ThingBuilder thingBuilder = editThing();
142         Channel channel = ChannelBuilder.create(new ChannelUID(thing.getUID(), name), "String").withLabel(label)
143                 .withType(alarmStatus).build();
144         thingBuilder.withChannel(channel);
145         updateThing(thingBuilder.build());
146     }
147
148     private void createThermoChannel(String name, String label) {
149         ChannelTypeUID alarmStatus = new ChannelTypeUID(BINDING_ID, "temperature");
150         ThingBuilder thingBuilder = editThing();
151         Channel channel = ChannelBuilder.create(new ChannelUID(thing.getUID(), name), "Number").withLabel(label)
152                 .withType(alarmStatus).build();
153         thingBuilder.withChannel(channel);
154         updateThing(thingBuilder.build());
155     }
156
157     private @Nullable JablotronGetSectionsResponse sendGetSections() {
158         JablotronBridgeHandler handler = getBridgeHandler();
159         if (handler != null) {
160             return handler.sendGetSections(getThing(), alarmName);
161         }
162         return null;
163     }
164
165     protected @Nullable JablotronGetPGResponse sendGetProgrammableGates() {
166         JablotronBridgeHandler handler = getBridgeHandler();
167         if (handler != null) {
168             return handler.sendGetProgrammableGates(getThing(), alarmName);
169         }
170         return null;
171     }
172
173     @Override
174     protected synchronized boolean updateAlarmStatus() {
175         JablotronBridgeHandler handler = getBridgeHandler();
176         if (handler != null) {
177             updateState(CHANNEL_LAST_CHECK_TIME, getCheckTime());
178
179             // sections
180             JablotronGetSectionsResponse response = handler.sendGetSections(getThing(), alarmName);
181             if (response != null) {
182                 createSectionChannels(response.getData().getSections());
183                 updateSectionState(response.getData().getStates());
184             }
185
186             // PGs
187             JablotronGetPGResponse resp = handler.sendGetProgrammableGates(getThing(), alarmName);
188             if (resp != null) {
189                 createPGChannels(resp.getData().getProgrammableGates());
190                 updateSectionState(resp.getData().getStates());
191             }
192
193             // thermo devices
194             JablotronGetThermoDevicesResponse respThermo = handler.sendGetThermometers(getThing(), alarmName);
195             if (respThermo != null) {
196                 createThermoDeviceChannels(respThermo.getData().getThermoDevices());
197                 updateThermoState(respThermo.getData().getStates());
198             }
199
200             // update events
201             List<JablotronHistoryDataEvent> events = sendGetEventHistory();
202             if (events != null && !events.isEmpty()) {
203                 JablotronHistoryDataEvent event = events.get(0);
204                 updateLastEvent(event);
205             }
206             return true;
207         } else {
208             return false;
209         }
210     }
211
212     private void createPGChannels(List<JablotronSection> programmableGates) {
213         for (JablotronSection gate : programmableGates) {
214             String id = gate.getCloudComponentId().toLowerCase();
215             logger.trace("component id: {} with name: {}", id, gate.getName());
216             Channel channel = getThing().getChannel(id);
217             if (channel == null) {
218                 logger.debug("Creating a new channel: {}", id);
219                 createPGChannel(id, gate.getName());
220             }
221         }
222     }
223
224     private void createSectionChannels(List<JablotronSection> sections) {
225         for (JablotronSection section : sections) {
226             String id = section.getCloudComponentId().toLowerCase();
227             logger.trace("component id: {} with name: {}", id, section.getName());
228             Channel channel = getThing().getChannel(id);
229             if (channel == null) {
230                 logger.debug("Creating a new channel: {}", id);
231                 createStateChannel(id, section.getName());
232             }
233         }
234     }
235
236     private void createThermoDeviceChannels(List<JablotronThermoDevice> thermoDevices) {
237         for (JablotronThermoDevice device : thermoDevices) {
238             String id = device.getObjectDeviceId().toLowerCase();
239             logger.trace("object device id: {} with name: {}", id, device.getName());
240             Channel channel = getThing().getChannel(id);
241             if (channel == null) {
242                 logger.debug("Creating a new channel: {}", id);
243                 createThermoChannel(id, device.getName());
244             }
245         }
246     }
247
248     private void updateSectionState(String section, List<JablotronState> states) {
249         for (JablotronState state : states) {
250             String id = state.getCloudComponentId();
251             if (id.equals(section.toUpperCase())) {
252                 updateSection(id, state);
253                 break;
254             }
255         }
256     }
257
258     private void updateSectionState(List<JablotronState> states) {
259         for (JablotronState state : states) {
260             String id = state.getCloudComponentId();
261             updateSection(id, state);
262         }
263     }
264
265     private void updateThermoState(List<JablotronState> states) {
266         for (JablotronState state : states) {
267             logger.debug("updating thermo state: {}", state.getObjectDeviceId());
268             String id = state.getObjectDeviceId();
269             updateSection(id, state);
270         }
271     }
272
273     private void updateSection(String id, JablotronState state) {
274         logger.debug("component id: {} with state: {}", id, state.getState());
275         State newState;
276
277         if (id.startsWith("SEC-")) {
278             newState = new StringType(state.getState());
279         } else if (id.startsWith("PG-")) {
280             newState = OnOffType.from("ON".equals(state.getState()));
281         } else if (id.startsWith("THM-")) {
282             newState = new QuantityType<>(state.getTemperature(), SIUnits.CELSIUS);
283         } else {
284             logger.debug("unknown component id: {}", id);
285             return;
286         }
287         Channel channel = getThing().getChannel(id.toLowerCase());
288         if (channel != null) {
289             updateState(channel.getUID(), newState);
290         } else {
291             logger.debug("The channel: {} still doesn't exist!", id);
292         }
293     }
294 }