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.openhab.binding.jablotron.internal.model.JablotronControlResponse;
23 import org.openhab.binding.jablotron.internal.model.JablotronDataUpdateResponse;
24 import org.openhab.binding.jablotron.internal.model.JablotronServiceDetailSegment;
25 import org.openhab.binding.jablotron.internal.model.JablotronServiceDetailSegmentInfo;
26 import org.openhab.core.cache.ExpiringCache;
27 import org.openhab.core.library.types.OnOffType;
28 import org.openhab.core.library.types.QuantityType;
29 import org.openhab.core.library.types.StringType;
30 import org.openhab.core.library.unit.SIUnits;
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;
44 * The {@link JablotronJa100Handler} is responsible for handling commands, which are
45 * sent to one of the channels.
47 * @author Ondrej Pecta - Initial contribution
50 public class JablotronJa100Handler extends JablotronAlarmHandler {
52 private final Logger logger = LoggerFactory.getLogger(JablotronJa100Handler.class);
54 public JablotronJa100Handler(Thing thing, String alarmName) {
55 super(thing, alarmName);
56 dataCache = new ExpiringCache<>(CACHE_TIMEOUT_MS, this::sendGetStatusRequest);
60 public void handleCommand(ChannelUID channelUID, Command command) {
61 if (RefreshType.REFRESH.equals(command)) {
62 logger.debug("refreshing channel: {}", channelUID.getId());
63 updateChannel(channelUID.getId());
65 if (channelUID.getId().startsWith("state_") && command instanceof StringType) {
66 scheduler.execute(() -> {
67 controlSTATESection(channelUID.getId().toUpperCase(), command.toString());
71 if (channelUID.getId().startsWith("pgm_") && command instanceof OnOffType) {
72 scheduler.execute(() -> {
73 controlPGMSection(channelUID.getId().toUpperCase(), command.equals(OnOffType.ON) ? "set" : "unset");
79 private void updateChannel(String channel) {
80 ExpiringCache<JablotronDataUpdateResponse> localDataCache = dataCache;
81 if (localDataCache != null) {
82 if (channel.startsWith("state_") || channel.startsWith("pgm_") || channel.startsWith("thermometer_")
83 || channel.startsWith("thermostat_")) {
84 updateSegmentStatus(channel, localDataCache.getValue());
85 } else if (CHANNEL_LAST_CHECK_TIME.equals(channel)) {
88 updateEventChannel(channel);
93 private void createChannel(JablotronServiceDetailSegment section) {
94 if (section.getSegmentId().startsWith("PGM_")) {
95 createPGMChannel(section.getSegmentId().toLowerCase(), section.getSegmentName());
97 createStateChannel(section.getSegmentId().toLowerCase(), section.getSegmentName());
101 private void createTempChannel(String name, String label) {
102 ChannelTypeUID temperature = new ChannelTypeUID(BINDING_ID, "temperature");
103 ThingBuilder thingBuilder = editThing();
104 Channel channel = ChannelBuilder.create(new ChannelUID(thing.getUID(), name), "Number:Temperature")
105 .withLabel(label).withType(temperature).build();
106 thingBuilder.withChannel(channel);
107 updateThing(thingBuilder.build());
110 private void createThermostatChannel(String name, String label) {
111 ChannelTypeUID temperature = new ChannelTypeUID(BINDING_ID, "thermostat");
112 ThingBuilder thingBuilder = editThing();
113 Channel channel = ChannelBuilder.create(new ChannelUID(thing.getUID(), name), "Number:Temperature")
114 .withLabel(label).withType(temperature).build();
115 thingBuilder.withChannel(channel);
116 updateThing(thingBuilder.build());
119 private void createPGMChannel(String name, String label) {
120 ChannelTypeUID pgmStatus = new ChannelTypeUID(BINDING_ID, "pgm_state");
121 ThingBuilder thingBuilder = editThing();
122 Channel channel = ChannelBuilder.create(new ChannelUID(thing.getUID(), name), "Switch").withLabel(label)
123 .withType(pgmStatus).build();
124 thingBuilder.withChannel(channel);
125 updateThing(thingBuilder.build());
128 private void createStateChannel(String name, String label) {
129 ChannelTypeUID alarmStatus = new ChannelTypeUID(BINDING_ID, "alarm_state");
130 ThingBuilder thingBuilder = editThing();
131 Channel channel = ChannelBuilder.create(new ChannelUID(thing.getUID(), name), "String").withLabel(label)
132 .withType(alarmStatus).build();
133 thingBuilder.withChannel(channel);
134 updateThing(thingBuilder.build());
138 protected void updateSegmentStatus(JablotronServiceDetailSegment segment) {
139 logger.debug("Segment id: {} and status: {}", segment.getSegmentId(), segment.getSegmentState());
140 String segmentId = segment.getSegmentId();
142 if (segmentId.startsWith("STATE_") || segmentId.startsWith("PGM_")) {
143 processSection(segment);
144 } else if (segmentId.startsWith("THERMOMETER_")) {
145 processThermometer(segment);
146 } else if (segmentId.startsWith("THERMOSTAT_")) {
147 processThermostat(segment);
149 logger.debug("Unknown segment received: {} with state: {}", segment.getSegmentId(),
150 segment.getSegmentState());
154 private void processSection(JablotronServiceDetailSegment segment) {
155 String segmentId = segment.getSegmentId().toLowerCase();
156 Channel channel = getThing().getChannel(segmentId);
157 if (channel == null) {
158 logger.debug("Creating a new channel: {}", segmentId);
159 createChannel(segment);
161 channel = getThing().getChannel(segmentId);
162 if (channel != null) {
163 logger.debug("Updating channel: {} to value: {}", channel.getUID(), segment.getSegmentState());
165 if (segmentId.startsWith("pgm_")) {
166 newState = "unset".equals(segment.getSegmentState()) ? OnOffType.OFF : OnOffType.ON;
168 newState = new StringType(segment.getSegmentState());
170 updateState(channel.getUID(), newState);
172 logger.debug("The channel: {} still doesn't exist!", segmentId);
176 private void processThermometer(JablotronServiceDetailSegment segment) {
177 String segmentId = segment.getSegmentId().toLowerCase();
178 Channel channel = getThing().getChannel(segmentId);
179 if (channel == null) {
180 logger.debug("Creating a new temperature channel: {}", segmentId);
181 createTempChannel(segmentId, segment.getSegmentName());
182 processThermometer(segment);
185 updateTemperatureChannel(channel, segment);
188 private void processThermostat(JablotronServiceDetailSegment segment) {
189 String segmentId = segment.getSegmentId().toLowerCase();
190 Channel channel = getThing().getChannel(segmentId);
191 if (channel == null) {
192 logger.debug("Creating a new thermostat channel: {}", segmentId);
193 createThermostatChannel(segmentId, segment.getSegmentName());
194 processThermostat(segment);
197 updateTemperatureChannel(channel, segment);
200 private void updateTemperatureChannel(Channel channel, JablotronServiceDetailSegment segment) {
201 List<JablotronServiceDetailSegmentInfo> infos = segment.getSegmentInfos();
202 if (infos.size() > 0) {
203 logger.debug("Found value: {} and type: {}", infos.get(0).getValue(), infos.get(0).getType());
204 updateState(channel.getUID(), QuantityType.valueOf(infos.get(0).getValue(), SIUnits.CELSIUS));
206 logger.debug("No segment information received");
210 public synchronized void controlPGMSection(String section, String status) {
211 logger.debug("Controlling section: {} with status: {}", section, status);
212 JablotronControlResponse response = sendUserCode(section, section.toLowerCase(), status, thingConfig.getCode());
215 if (response == null) {
216 logger.debug("null response/status received during the control of PGM section: {}", section);
220 public synchronized void controlSTATESection(String section, String status) {
221 logger.debug("Controlling section: {} with status: {}", section, status);
222 JablotronControlResponse response = sendUserCode(section, section.toLowerCase().replace("state", "section"),
223 status, thingConfig.getCode());
226 if (response == null) {
227 logger.debug("null response/status received during the control of STATE section: {}", section);