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