2 * Copyright (c) 2010-2022 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.*;
17 import java.util.List;
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;
43 * The {@link JablotronJa100FHandler} is responsible for handling commands, which are
44 * sent to one of the channels.
46 * @author Ondrej Pecta - Initial contribution
49 public class JablotronJa100FHandler extends JablotronAlarmHandler {
51 private final Logger logger = LoggerFactory.getLogger(JablotronJa100FHandler.class);
53 private ExpiringCache<JablotronGetSectionsResponse> sectionCache;
54 private ExpiringCache<JablotronGetPGResponse> pgCache;
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);
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());
68 if (channelUID.getId().startsWith("sec-") && command instanceof StringType) {
69 if ("PARTIAL_ARM".equals(command.toString())) {
70 controlComponent(channelUID.getId(), "CONTROL-SECTION", "DISARM");
72 scheduler.execute(() -> controlComponent(channelUID.getId().toUpperCase(), "CONTROL-SECTION",
76 if (channelUID.getId().startsWith("pg-") && command instanceof OnOffType) {
78 () -> controlComponent(channelUID.getId().toUpperCase(), "CONTROL-PG", command.toString()));
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());
89 } else if (channel.startsWith("pg-")) {
90 JablotronGetPGResponse pgs = pgCache.getValue();
92 updateSectionState(channel, pgs.getData().getStates());
94 } else if (CHANNEL_LAST_CHECK_TIME.equals(channel)) {
97 updateEventChannel(channel);
102 protected void updateSegmentStatus(JablotronServiceDetailSegment segment) {
106 private void controlComponent(String componentId, String action, String value) {
107 logger.debug("Controlling component: {} with action: {} and value: {}", componentId, action, value);
109 JablotronBridgeHandler handler = getBridgeHandler();
110 if (handler != null) {
111 JablotronGetSectionsResponse response;
113 response = handler.controlComponent(getThing(), thingConfig.getCode(), action, value, componentId);
114 } catch (SecurityException se) {
115 response = handler.controlComponent(getThing(), thingConfig.getCode(), action, value, componentId);
117 if (response != null) {
118 updateSectionState(response.getData().getStates());
120 logger.debug("null response/status received during the control of component: {}", componentId);
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());
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());
144 private @Nullable JablotronGetSectionsResponse sendGetSections() {
145 JablotronBridgeHandler handler = getBridgeHandler();
146 if (handler != null) {
147 return handler.sendGetSections(getThing(), alarmName);
152 protected @Nullable JablotronGetPGResponse sendGetProgrammableGates() {
153 JablotronBridgeHandler handler = getBridgeHandler();
154 if (handler != null) {
155 return handler.sendGetProgrammableGates(getThing(), alarmName);
161 protected synchronized boolean updateAlarmStatus() {
162 JablotronBridgeHandler handler = getBridgeHandler();
163 if (handler != null) {
164 updateState(CHANNEL_LAST_CHECK_TIME, getCheckTime());
167 JablotronGetSectionsResponse response = handler.sendGetSections(getThing(), alarmName);
168 if (response != null) {
169 createSectionChannels(response.getData().getSections());
170 updateSectionState(response.getData().getStates());
174 JablotronGetPGResponse resp = handler.sendGetProgrammableGates(getThing(), alarmName);
176 createPGChannels(resp.getData().getProgrammableGates());
177 updateSectionState(resp.getData().getStates());
181 List<JablotronHistoryDataEvent> events = sendGetEventHistory();
182 if (events != null && !events.isEmpty()) {
183 JablotronHistoryDataEvent event = events.get(0);
184 updateLastEvent(event);
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());
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());
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);
226 private void updateSectionState(List<JablotronState> states) {
227 for (JablotronState state : states) {
228 String id = state.getCloudComponentId();
229 updateSection(id, state);
233 private void updateSection(String id, JablotronState state) {
234 logger.debug("component id: {} with state: {}", id, state.getState());
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;
242 logger.debug("unknown component id: {}", id);
245 Channel channel = getThing().getChannel(id.toLowerCase());
246 if (channel != null) {
247 updateState(channel.getUID(), newState);
249 logger.debug("The channel: {} still doesn't exist!", id);