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.jeelink.internal.lacrosse;
15 import static org.openhab.binding.jeelink.internal.JeeLinkBindingConstants.*;
17 import java.math.BigDecimal;
18 import java.math.RoundingMode;
19 import java.util.ArrayList;
20 import java.util.HashMap;
21 import java.util.List;
24 import org.openhab.binding.jeelink.internal.JeeLinkSensorHandler;
25 import org.openhab.binding.jeelink.internal.ReadingPublisher;
26 import org.openhab.binding.jeelink.internal.RollingAveragePublisher;
27 import org.openhab.binding.jeelink.internal.RollingReadingAverage;
28 import org.openhab.binding.jeelink.internal.config.LaCrosseTemperatureSensorConfig;
29 import org.openhab.binding.jeelink.internal.util.StringUtils;
30 import org.openhab.core.library.types.OnOffType;
31 import org.openhab.core.library.types.QuantityType;
32 import org.openhab.core.library.unit.SIUnits;
33 import org.openhab.core.library.unit.Units;
34 import org.openhab.core.thing.Channel;
35 import org.openhab.core.thing.ChannelUID;
36 import org.openhab.core.thing.Thing;
37 import org.openhab.core.thing.ThingStatus;
38 import org.openhab.core.thing.binding.builder.ChannelBuilder;
39 import org.openhab.core.thing.binding.builder.ThingBuilder;
40 import org.openhab.core.thing.type.ChannelTypeUID;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
45 * Handler for a LaCrosse Temperature Sensor thing.
47 * @author Volker Bier - Initial contribution
49 public class LaCrosseTemperatureSensorHandler extends JeeLinkSensorHandler<LaCrosseTemperatureReading> {
50 private final Logger logger = LoggerFactory.getLogger(LaCrosseTemperatureSensorHandler.class);
52 public LaCrosseTemperatureSensorHandler(Thing thing, String sensorType) {
53 super(thing, sensorType);
57 public Class<LaCrosseTemperatureReading> getReadingClass() {
58 return LaCrosseTemperatureReading.class;
62 public ReadingPublisher<LaCrosseTemperatureReading> createPublisher() {
63 return new ReadingPublisher<LaCrosseTemperatureReading>() {
64 private final Map<Integer, ReadingPublisher<LaCrosseTemperatureReading>> channelPublishers = new HashMap<>();
67 public void publish(LaCrosseTemperatureReading reading) {
68 if (reading != null) {
69 int channelNo = reading.getChannel();
71 ReadingPublisher<LaCrosseTemperatureReading> publisher;
72 synchronized (channelPublishers) {
73 publisher = channelPublishers.get(channelNo);
74 if (publisher == null) {
75 publisher = createPublisherForChannel(channelNo);
76 channelPublishers.put(channelNo, publisher);
78 createMissingChannels(reading.getChannel());
82 publisher.publish(reading);
86 private void createMissingChannels(int channelNo) {
87 List<Channel> missingChannels = new ArrayList<>();
89 String idSuffix = channelNo > 1 ? String.valueOf(channelNo) : "";
90 String labelSuffix = channelNo > 1 ? " " + channelNo : "";
91 for (String channelName : new String[] { TEMPERATURE_CHANNEL, HUMIDITY_CHANNEL }) {
92 if (getThing().getChannel(channelName + idSuffix) == null) {
93 missingChannels.add(ChannelBuilder
94 .create(new ChannelUID(getThing().getUID(), channelName + idSuffix), "Number")
95 .withType(new ChannelTypeUID(getThing().getThingTypeUID().getBindingId(), channelName))
96 .withLabel(StringUtils.capitalize(channelName + labelSuffix)).build());
99 missingChannels.addAll(getThing().getChannels());
101 if (!missingChannels.isEmpty()) {
102 ThingBuilder thingBuilder = editThing();
103 thingBuilder.withChannels(missingChannels);
104 updateThing(thingBuilder.build());
109 public void dispose() {
110 synchronized (channelPublishers) {
111 for (ReadingPublisher<LaCrosseTemperatureReading> p : channelPublishers.values()) {
114 channelPublishers.clear();
120 public ReadingPublisher<LaCrosseTemperatureReading> createPublisherForChannel(int channelNo) {
121 ReadingPublisher<LaCrosseTemperatureReading> publisher = new ReadingPublisher<LaCrosseTemperatureReading>() {
123 public void publish(LaCrosseTemperatureReading reading) {
124 if (reading != null && getThing().getStatus() == ThingStatus.ONLINE) {
125 BigDecimal temp = new BigDecimal(reading.getTemperature()).setScale(1, RoundingMode.HALF_UP);
127 if (channelNo == 1) {
129 "updating states for thing {} ({}): temp={} ({}), humidity={}, batteryNew={}, batteryLow={}",
130 getThing().getLabel(), getThing().getUID().getId(), temp, reading.getTemperature(),
131 reading.getHumidity(), reading.isBatteryNew(), reading.isBatteryLow());
132 updateState(TEMPERATURE_CHANNEL, new QuantityType<>(temp, SIUnits.CELSIUS));
133 updateState(HUMIDITY_CHANNEL, new QuantityType<>(reading.getHumidity(), Units.PERCENT));
134 updateState(BATTERY_NEW_CHANNEL, reading.isBatteryNew() ? OnOffType.ON : OnOffType.OFF);
135 updateState(BATTERY_LOW_CHANNEL, reading.isBatteryLow() ? OnOffType.ON : OnOffType.OFF);
137 logger.debug("updating states for channel {} of thing {} ({}): temp={} ({}), humidity={}",
138 reading.getChannel(), getThing().getLabel(), getThing().getUID().getId(), temp,
139 reading.getTemperature(), reading.getHumidity());
140 updateState(TEMPERATURE_CHANNEL + reading.getChannel(),
141 new QuantityType<>(temp, SIUnits.CELSIUS));
142 updateState(HUMIDITY_CHANNEL + reading.getChannel(),
143 new QuantityType<>(reading.getHumidity(), Units.PERCENT));
149 public void dispose() {
153 LaCrosseTemperatureSensorConfig cfg = getConfigAs(LaCrosseTemperatureSensorConfig.class);
154 if (cfg.bufferSize > 1 && cfg.updateInterval > 0) {
155 publisher = new RollingAveragePublisher<LaCrosseTemperatureReading>(cfg.bufferSize, cfg.updateInterval,
156 publisher, scheduler) {
158 public RollingReadingAverage<LaCrosseTemperatureReading> createRollingReadingAverage(int bufferSize) {
159 return new LaCrosseRollingReadingAverage(bufferSize);
164 if (cfg.maxDiff > 0) {
165 publisher = new DifferenceCheckingPublisher(cfg.maxDiff, publisher);
168 publisher = new BoundsCheckingPublisher(cfg.minTemp, cfg.maxTemp, publisher);