2 * Copyright (c) 2010-2021 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.jablotron.internal.handler;
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;
19 import java.util.List;
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;
45 * The {@link JablotronJa100FHandler} is responsible for handling commands, which are
46 * sent to one of the channels.
48 * @author Ondrej Pecta - Initial contribution
51 public class JablotronJa100FHandler extends JablotronAlarmHandler {
53 private final Logger logger = LoggerFactory.getLogger(JablotronJa100FHandler.class);
55 private ExpiringCache<JablotronGetSectionsResponse> sectionCache;
56 private ExpiringCache<JablotronGetPGResponse> pgCache;
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);
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());
70 if (channelUID.getId().startsWith("sec-") && command instanceof StringType) {
71 if ("PARTIAL_ARM".equals(command.toString())) {
72 controlComponent(channelUID.getId(), "CONTROL-SECTION", "DISARM");
74 scheduler.execute(() -> controlComponent(channelUID.getId().toUpperCase(), "CONTROL-SECTION",
78 if (channelUID.getId().startsWith("pg-") && command instanceof OnOffType) {
80 () -> controlComponent(channelUID.getId().toUpperCase(), "CONTROL-PG", command.toString()));
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());
91 } else if (channel.startsWith("pg-")) {
92 JablotronGetPGResponse pgs = pgCache.getValue();
94 updateSectionState(channel, pgs.getData().getStates());
96 } else if (CHANNEL_LAST_CHECK_TIME.equals(channel)) {
99 updateEventChannel(channel);
104 protected void updateSegmentStatus(JablotronServiceDetailSegment segment) {
108 private void controlComponent(String componentId, String action, String value) {
109 logger.debug("Controlling component: {} with action: {} and value: {}", componentId, action, value);
111 JablotronBridgeHandler handler = getBridgeHandler();
112 if (handler != null) {
113 JablotronGetSectionsResponse response;
115 response = handler.controlComponent(getThing(), thingConfig.getCode(), action, value, componentId);
116 } catch (SecurityException se) {
117 response = handler.controlComponent(getThing(), thingConfig.getCode(), action, value, componentId);
119 if (response != null) {
120 updateSectionState(response.getData().getStates());
122 logger.debug("null response/status received during the control of component: {}", componentId);
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());
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());
146 private @Nullable JablotronGetSectionsResponse sendGetSections() {
147 JablotronBridgeHandler handler = getBridgeHandler();
148 if (handler != null) {
149 return handler.sendGetSections(getThing(), alarmName);
154 protected @Nullable JablotronGetPGResponse sendGetProgrammableGates() {
155 JablotronBridgeHandler handler = getBridgeHandler();
156 if (handler != null) {
157 return handler.sendGetProgrammableGates(getThing(), alarmName);
163 protected synchronized boolean updateAlarmStatus() {
164 JablotronBridgeHandler handler = getBridgeHandler();
165 if (handler != null) {
166 updateState(CHANNEL_LAST_CHECK_TIME, getCheckTime());
169 JablotronGetSectionsResponse response = handler.sendGetSections(getThing(), alarmName);
170 if (response != null) {
171 createSectionChannels(response.getData().getSections());
172 updateSectionState(response.getData().getStates());
176 JablotronGetPGResponse resp = handler.sendGetProgrammableGates(getThing(), alarmName);
178 createPGChannels(resp.getData().getProgrammableGates());
179 updateSectionState(resp.getData().getStates());
183 List<JablotronHistoryDataEvent> events = sendGetEventHistory();
184 if (events != null && events.size() > 0) {
185 JablotronHistoryDataEvent event = events.get(0);
186 updateLastEvent(event);
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());
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());
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);
228 private void updateSectionState(List<JablotronState> states) {
229 for (JablotronState state : states) {
230 String id = state.getCloudComponentId();
231 updateSection(id, state);
235 private void updateSection(String id, JablotronState state) {
236 logger.debug("component id: {} with state: {}", id, state.getState());
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;
244 logger.debug("unknown component id: {}", id);
247 Channel channel = getThing().getChannel(id.toLowerCase());
248 if (channel != null) {
249 updateState(channel.getUID(), newState);
251 logger.debug("The channel: {} still doesn't exist!", id);