2 * Copyright (c) 2010-2023 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.openhab.binding.jablotron.internal.model.JablotronControlResponse;
21 import org.openhab.binding.jablotron.internal.model.JablotronDataUpdateResponse;
22 import org.openhab.binding.jablotron.internal.model.JablotronServiceDetailSegment;
23 import org.openhab.binding.jablotron.internal.model.JablotronServiceDetailSegmentInfo;
24 import org.openhab.core.cache.ExpiringCache;
25 import org.openhab.core.library.types.OnOffType;
26 import org.openhab.core.library.types.QuantityType;
27 import org.openhab.core.library.types.StringType;
28 import org.openhab.core.library.unit.SIUnits;
29 import org.openhab.core.thing.Channel;
30 import org.openhab.core.thing.ChannelUID;
31 import org.openhab.core.thing.Thing;
32 import org.openhab.core.thing.binding.builder.ChannelBuilder;
33 import org.openhab.core.thing.binding.builder.ThingBuilder;
34 import org.openhab.core.thing.type.ChannelTypeUID;
35 import org.openhab.core.types.Command;
36 import org.openhab.core.types.RefreshType;
37 import org.openhab.core.types.State;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
42 * The {@link JablotronJa100Handler} is responsible for handling commands, which are
43 * sent to one of the channels.
45 * @author Ondrej Pecta - Initial contribution
48 public class JablotronJa100Handler extends JablotronAlarmHandler {
50 private final Logger logger = LoggerFactory.getLogger(JablotronJa100Handler.class);
52 public JablotronJa100Handler(Thing thing, String alarmName) {
53 super(thing, alarmName);
54 dataCache = new ExpiringCache<>(CACHE_TIMEOUT_MS, this::sendGetStatusRequest);
58 public void handleCommand(ChannelUID channelUID, Command command) {
59 if (RefreshType.REFRESH.equals(command)) {
60 logger.debug("refreshing channel: {}", channelUID.getId());
61 updateChannel(channelUID.getId());
63 if (channelUID.getId().startsWith("state_") && command instanceof StringType) {
64 scheduler.execute(() -> {
65 controlSTATESection(channelUID.getId().toUpperCase(), command.toString());
69 if (channelUID.getId().startsWith("pgm_") && command instanceof OnOffType) {
70 scheduler.execute(() -> {
71 controlPGMSection(channelUID.getId().toUpperCase(), command.equals(OnOffType.ON) ? "set" : "unset");
77 private void updateChannel(String channel) {
78 ExpiringCache<JablotronDataUpdateResponse> localDataCache = dataCache;
79 if (localDataCache != null) {
80 if (channel.startsWith("state_") || channel.startsWith("pgm_") || channel.startsWith("thermometer_")
81 || channel.startsWith("thermostat_")) {
82 updateSegmentStatus(channel, localDataCache.getValue());
83 } else if (CHANNEL_LAST_CHECK_TIME.equals(channel)) {
86 updateEventChannel(channel);
91 private void createChannel(JablotronServiceDetailSegment section) {
92 if (section.getSegmentId().startsWith("PGM_")) {
93 createPGMChannel(section.getSegmentId().toLowerCase(), section.getSegmentName());
95 createStateChannel(section.getSegmentId().toLowerCase(), section.getSegmentName());
99 private void createTempChannel(String name, String label) {
100 ChannelTypeUID temperature = new ChannelTypeUID(BINDING_ID, "temperature");
101 ThingBuilder thingBuilder = editThing();
102 Channel channel = ChannelBuilder.create(new ChannelUID(thing.getUID(), name), "Number:Temperature")
103 .withLabel(label).withType(temperature).build();
104 thingBuilder.withChannel(channel);
105 updateThing(thingBuilder.build());
108 private void createThermostatChannel(String name, String label) {
109 ChannelTypeUID temperature = new ChannelTypeUID(BINDING_ID, "thermostat");
110 ThingBuilder thingBuilder = editThing();
111 Channel channel = ChannelBuilder.create(new ChannelUID(thing.getUID(), name), "Number:Temperature")
112 .withLabel(label).withType(temperature).build();
113 thingBuilder.withChannel(channel);
114 updateThing(thingBuilder.build());
117 private void createPGMChannel(String name, String label) {
118 ChannelTypeUID pgmStatus = new ChannelTypeUID(BINDING_ID, "pgm_state");
119 ThingBuilder thingBuilder = editThing();
120 Channel channel = ChannelBuilder.create(new ChannelUID(thing.getUID(), name), "Switch").withLabel(label)
121 .withType(pgmStatus).build();
122 thingBuilder.withChannel(channel);
123 updateThing(thingBuilder.build());
126 private void createStateChannel(String name, String label) {
127 ChannelTypeUID alarmStatus = new ChannelTypeUID(BINDING_ID, "alarm_state");
128 ThingBuilder thingBuilder = editThing();
129 Channel channel = ChannelBuilder.create(new ChannelUID(thing.getUID(), name), "String").withLabel(label)
130 .withType(alarmStatus).build();
131 thingBuilder.withChannel(channel);
132 updateThing(thingBuilder.build());
136 protected void updateSegmentStatus(JablotronServiceDetailSegment segment) {
137 logger.debug("Segment id: {} and status: {}", segment.getSegmentId(), segment.getSegmentState());
138 String segmentId = segment.getSegmentId();
140 if (segmentId.startsWith("STATE_") || segmentId.startsWith("PGM_")) {
141 processSection(segment);
142 } else if (segmentId.startsWith("THERMOMETER_")) {
143 processThermometer(segment);
144 } else if (segmentId.startsWith("THERMOSTAT_")) {
145 processThermostat(segment);
147 logger.debug("Unknown segment received: {} with state: {}", segment.getSegmentId(),
148 segment.getSegmentState());
152 private void processSection(JablotronServiceDetailSegment segment) {
153 String segmentId = segment.getSegmentId().toLowerCase();
154 Channel channel = getThing().getChannel(segmentId);
155 if (channel == null) {
156 logger.debug("Creating a new channel: {}", segmentId);
157 createChannel(segment);
159 channel = getThing().getChannel(segmentId);
160 if (channel != null) {
161 logger.debug("Updating channel: {} to value: {}", channel.getUID(), segment.getSegmentState());
163 if (segmentId.startsWith("pgm_")) {
164 newState = OnOffType.from(!"unset".equals(segment.getSegmentState()));
166 newState = new StringType(segment.getSegmentState());
168 updateState(channel.getUID(), newState);
170 logger.debug("The channel: {} still doesn't exist!", segmentId);
174 private void processThermometer(JablotronServiceDetailSegment segment) {
175 String segmentId = segment.getSegmentId().toLowerCase();
176 Channel channel = getThing().getChannel(segmentId);
177 if (channel == null) {
178 logger.debug("Creating a new temperature channel: {}", segmentId);
179 createTempChannel(segmentId, segment.getSegmentName());
180 processThermometer(segment);
183 updateTemperatureChannel(channel, segment);
186 private void processThermostat(JablotronServiceDetailSegment segment) {
187 String segmentId = segment.getSegmentId().toLowerCase();
188 Channel channel = getThing().getChannel(segmentId);
189 if (channel == null) {
190 logger.debug("Creating a new thermostat channel: {}", segmentId);
191 createThermostatChannel(segmentId, segment.getSegmentName());
192 processThermostat(segment);
195 updateTemperatureChannel(channel, segment);
198 private void updateTemperatureChannel(Channel channel, JablotronServiceDetailSegment segment) {
199 List<JablotronServiceDetailSegmentInfo> infos = segment.getSegmentInfos();
200 if (!infos.isEmpty()) {
201 logger.debug("Found value: {} and type: {}", infos.get(0).getValue(), infos.get(0).getType());
202 updateState(channel.getUID(), QuantityType.valueOf(infos.get(0).getValue(), SIUnits.CELSIUS));
204 logger.debug("No segment information received");
208 public synchronized void controlPGMSection(String section, String status) {
209 logger.debug("Controlling section: {} with status: {}", section, status);
210 JablotronControlResponse response = sendUserCode(section, section.toLowerCase(), status, thingConfig.getCode());
213 if (response == null) {
214 logger.debug("null response/status received during the control of PGM section: {}", section);
218 public synchronized void controlSTATESection(String section, String status) {
219 logger.debug("Controlling section: {} with status: {}", section, status);
220 JablotronControlResponse response = sendUserCode(section, section.toLowerCase().replace("state", "section"),
221 status, thingConfig.getCode());
224 if (response == null) {
225 logger.debug("null response/status received during the control of STATE section: {}", section);