]> git.basschouten.com Git - openhab-addons.git/blob
855c93821d10d967410405ed7b6df459909ba110
[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.CACHE_TIMEOUT_MS;
16 import static org.openhab.binding.jablotron.JablotronBindingConstants.CHANNEL_LAST_CHECK_TIME;
17
18 import java.util.List;
19
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.openhab.binding.jablotron.internal.model.JablotronHistoryDataEvent;
23 import org.openhab.binding.jablotron.internal.model.JablotronServiceDetailSegment;
24 import org.openhab.binding.jablotron.internal.model.ja100f.JablotronGetPGResponse;
25 import org.openhab.binding.jablotron.internal.model.ja100f.JablotronGetSectionsResponse;
26 import org.openhab.binding.jablotron.internal.model.ja100f.JablotronSection;
27 import org.openhab.binding.jablotron.internal.model.ja100f.JablotronState;
28 import org.openhab.core.cache.ExpiringCache;
29 import org.openhab.core.library.types.OnOffType;
30 import org.openhab.core.library.types.StringType;
31 import org.openhab.core.thing.Channel;
32 import org.openhab.core.thing.ChannelUID;
33 import org.openhab.core.thing.Thing;
34 import org.openhab.core.thing.binding.builder.ChannelBuilder;
35 import org.openhab.core.thing.binding.builder.ThingBuilder;
36 import org.openhab.core.thing.type.ChannelTypeUID;
37 import org.openhab.core.types.Command;
38 import org.openhab.core.types.RefreshType;
39 import org.openhab.core.types.State;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 /**
44  * The {@link JablotronJa100FHandler} is responsible for handling commands, which are
45  * sent to one of the channels.
46  *
47  * @author Ondrej Pecta - Initial contribution
48  */
49 @NonNullByDefault
50 public class JablotronJa100FHandler extends JablotronAlarmHandler {
51
52     private final Logger logger = LoggerFactory.getLogger(JablotronJa100FHandler.class);
53
54     private ExpiringCache<JablotronGetSectionsResponse> sectionCache;
55     private ExpiringCache<JablotronGetPGResponse> pgCache;
56
57     public JablotronJa100FHandler(Thing thing, String alarmName) {
58         super(thing, alarmName);
59         sectionCache = new ExpiringCache<>(CACHE_TIMEOUT_MS, this::sendGetSections);
60         pgCache = new ExpiringCache<>(CACHE_TIMEOUT_MS, this::sendGetProgrammableGates);
61     }
62
63     @Override
64     public void handleCommand(ChannelUID channelUID, Command command) {
65         if (RefreshType.REFRESH.equals(command)) {
66             logger.debug("refreshing channel: {}", channelUID.getId());
67             updateChannel(channelUID.getId());
68         } else {
69             if (channelUID.getId().startsWith("sec-") && command instanceof StringType) {
70                 if ("PARTIAL_ARM".equals(command.toString())) {
71                     controlComponent(channelUID.getId(), "CONTROL-SECTION", "DISARM");
72                 }
73                 scheduler.execute(() -> controlComponent(channelUID.getId().toUpperCase(), "CONTROL-SECTION",
74                         command.toString()));
75             }
76
77             if (channelUID.getId().startsWith("pg-") && command instanceof OnOffType) {
78                 scheduler.execute(
79                         () -> controlComponent(channelUID.getId().toUpperCase(), "CONTROL-PG", command.toString()));
80             }
81         }
82     }
83
84     private void updateChannel(String channel) {
85         if (channel.startsWith("sec-")) {
86             JablotronGetSectionsResponse sections = sectionCache.getValue();
87             if (sections != null) {
88                 updateSectionState(channel, sections.getData().getStates());
89             }
90         } else if (channel.startsWith("pg-")) {
91             JablotronGetPGResponse pgs = pgCache.getValue();
92             if (pgs != null) {
93                 updateSectionState(channel, pgs.getData().getStates());
94             }
95         } else if (CHANNEL_LAST_CHECK_TIME.equals(channel)) {
96             // not updating
97         } else {
98             updateEventChannel(channel);
99         }
100     }
101
102     @Override
103     protected void updateSegmentStatus(JablotronServiceDetailSegment segment) {
104         // nothing
105     }
106
107     private void controlComponent(String componentId, String action, String value) {
108         logger.debug("Controlling component: {} with action: {} and value: {}", componentId, action, value);
109
110         JablotronBridgeHandler handler = getBridgeHandler();
111         if (handler != null) {
112             JablotronGetSectionsResponse response;
113             try {
114                 response = handler.controlComponent(getThing(), thingConfig.getCode(), action, value, componentId);
115             } catch (SecurityException se) {
116                 response = handler.controlComponent(getThing(), thingConfig.getCode(), action, value, componentId);
117             }
118             if (response != null) {
119                 updateSectionState(response.getData().getStates());
120             } else {
121                 logger.debug("null response/status received during the control of component: {}", componentId);
122                 updateAlarmStatus();
123             }
124         }
125     }
126
127     private void createPGChannel(String name, String label) {
128         ThingBuilder thingBuilder = editThing();
129         Channel channel = ChannelBuilder.create(new ChannelUID(thing.getUID(), name), "Switch").withLabel(label)
130                 .build();
131         thingBuilder.withChannel(channel);
132         updateThing(thingBuilder.build());
133     }
134
135     private void createStateChannel(String name, String label) {
136         ChannelTypeUID alarmStatus = new ChannelTypeUID("jablotron", "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.size() > 0) {
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 }