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