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;
23 import java.util.Objects;
25 import org.openhab.binding.jeelink.internal.JeeLinkSensorHandler;
26 import org.openhab.binding.jeelink.internal.ReadingPublisher;
27 import org.openhab.binding.jeelink.internal.RollingAveragePublisher;
28 import org.openhab.binding.jeelink.internal.RollingReadingAverage;
29 import org.openhab.binding.jeelink.internal.config.LaCrosseTemperatureSensorConfig;
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.openhab.core.util.StringUtils;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
46 * Handler for a LaCrosse Temperature Sensor thing.
48 * @author Volker Bier - Initial contribution
50 public class LaCrosseTemperatureSensorHandler extends JeeLinkSensorHandler<LaCrosseTemperatureReading> {
51 private final Logger logger = LoggerFactory.getLogger(LaCrosseTemperatureSensorHandler.class);
53 public LaCrosseTemperatureSensorHandler(Thing thing, String sensorType) {
54 super(thing, sensorType);
58 public Class<LaCrosseTemperatureReading> getReadingClass() {
59 return LaCrosseTemperatureReading.class;
63 public ReadingPublisher<LaCrosseTemperatureReading> createPublisher() {
64 return new ReadingPublisher<LaCrosseTemperatureReading>() {
65 private final Map<Integer, ReadingPublisher<LaCrosseTemperatureReading>> channelPublishers = new HashMap<>();
68 public void publish(LaCrosseTemperatureReading reading) {
69 if (reading != null) {
70 int channelNo = reading.getChannel();
72 ReadingPublisher<LaCrosseTemperatureReading> publisher;
73 synchronized (channelPublishers) {
74 publisher = channelPublishers.get(channelNo);
75 if (publisher == null) {
76 publisher = createPublisherForChannel(channelNo);
77 channelPublishers.put(channelNo, publisher);
79 createMissingChannels(reading.getChannel());
83 publisher.publish(reading);
87 private void createMissingChannels(int channelNo) {
88 List<Channel> missingChannels = new ArrayList<>();
90 String idSuffix = channelNo > 1 ? String.valueOf(channelNo) : "";
91 String labelSuffix = channelNo > 1 ? " " + channelNo : "";
92 for (String channelName : new String[] { TEMPERATURE_CHANNEL, HUMIDITY_CHANNEL }) {
93 if (getThing().getChannel(channelName + idSuffix) == null) {
94 missingChannels.add(ChannelBuilder
95 .create(new ChannelUID(getThing().getUID(), channelName + idSuffix), "Number")
96 .withType(new ChannelTypeUID(getThing().getThingTypeUID().getBindingId(), channelName))
97 .withLabel(Objects.requireNonNull(StringUtils.capitalize(channelName + labelSuffix)))
101 missingChannels.addAll(getThing().getChannels());
103 if (!missingChannels.isEmpty()) {
104 ThingBuilder thingBuilder = editThing();
105 thingBuilder.withChannels(missingChannels);
106 updateThing(thingBuilder.build());
111 public void dispose() {
112 synchronized (channelPublishers) {
113 for (ReadingPublisher<LaCrosseTemperatureReading> p : channelPublishers.values()) {
116 channelPublishers.clear();
122 public ReadingPublisher<LaCrosseTemperatureReading> createPublisherForChannel(int channelNo) {
123 ReadingPublisher<LaCrosseTemperatureReading> publisher = new ReadingPublisher<LaCrosseTemperatureReading>() {
125 public void publish(LaCrosseTemperatureReading reading) {
126 if (reading != null && getThing().getStatus() == ThingStatus.ONLINE) {
127 BigDecimal temp = new BigDecimal(reading.getTemperature()).setScale(1, RoundingMode.HALF_UP);
129 if (channelNo == 1) {
131 "updating states for thing {} ({}): temp={} ({}), humidity={}, batteryNew={}, batteryLow={}",
132 getThing().getLabel(), getThing().getUID().getId(), temp, reading.getTemperature(),
133 reading.getHumidity(), reading.isBatteryNew(), reading.isBatteryLow());
134 updateState(TEMPERATURE_CHANNEL, new QuantityType<>(temp, SIUnits.CELSIUS));
135 updateState(HUMIDITY_CHANNEL, new QuantityType<>(reading.getHumidity(), Units.PERCENT));
136 updateState(BATTERY_NEW_CHANNEL, OnOffType.from(reading.isBatteryNew()));
137 updateState(BATTERY_LOW_CHANNEL, OnOffType.from(reading.isBatteryLow()));
139 logger.debug("updating states for channel {} of thing {} ({}): temp={} ({}), humidity={}",
140 reading.getChannel(), getThing().getLabel(), getThing().getUID().getId(), temp,
141 reading.getTemperature(), reading.getHumidity());
142 updateState(TEMPERATURE_CHANNEL + reading.getChannel(),
143 new QuantityType<>(temp, SIUnits.CELSIUS));
144 updateState(HUMIDITY_CHANNEL + reading.getChannel(),
145 new QuantityType<>(reading.getHumidity(), Units.PERCENT));
151 public void dispose() {
155 LaCrosseTemperatureSensorConfig cfg = getConfigAs(LaCrosseTemperatureSensorConfig.class);
156 if (cfg.bufferSize > 1 && cfg.updateInterval > 0) {
157 publisher = new RollingAveragePublisher<LaCrosseTemperatureReading>(cfg.bufferSize, cfg.updateInterval,
158 publisher, scheduler) {
160 public RollingReadingAverage<LaCrosseTemperatureReading> createRollingReadingAverage(int bufferSize) {
161 return new LaCrosseRollingReadingAverage(bufferSize);
166 if (cfg.maxDiff > 0) {
167 publisher = new DifferenceCheckingPublisher(cfg.maxDiff, publisher);
170 publisher = new BoundsCheckingPublisher(cfg.minTemp, cfg.maxTemp, publisher);