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.onewiregpio.internal.handler;
15 import static org.openhab.binding.onewiregpio.internal.OneWireGPIOBindingConstants.*;
17 import java.io.IOException;
18 import java.math.BigDecimal;
19 import java.math.RoundingMode;
20 import java.nio.file.Files;
21 import java.nio.file.InvalidPathException;
22 import java.nio.file.Paths;
23 import java.util.List;
24 import java.util.Optional;
25 import java.util.concurrent.ScheduledFuture;
26 import java.util.concurrent.TimeUnit;
27 import java.util.stream.Stream;
29 import org.openhab.binding.onewiregpio.internal.OneWireGPIOBindingConstants;
30 import org.openhab.binding.onewiregpio.internal.OneWireGpioConfiguration;
31 import org.openhab.core.library.types.QuantityType;
32 import org.openhab.core.library.unit.SIUnits;
33 import org.openhab.core.thing.Channel;
34 import org.openhab.core.thing.ChannelUID;
35 import org.openhab.core.thing.Thing;
36 import org.openhab.core.thing.ThingStatus;
37 import org.openhab.core.thing.ThingStatusDetail;
38 import org.openhab.core.thing.binding.BaseThingHandler;
39 import org.openhab.core.types.Command;
40 import org.openhab.core.types.RefreshType;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
45 * The {@link OneWireGPIOHandler} is responsible for handling commands, which are
46 * sent to one of the channels.
48 * @author Anatol Ogorek - Initial contribution
49 * @author Konstantin Polihronov - Changed configuration handling and added new parameter - precision
51 public class OneWireGPIOHandler extends BaseThingHandler {
53 private final Logger logger = LoggerFactory.getLogger(OneWireGPIOHandler.class);
55 private String gpioBusFile;
56 private Integer refreshTime;
57 private Integer precision;
59 private ScheduledFuture<?> sensorRefreshJob;
61 public OneWireGPIOHandler(Thing thing) {
66 public void handleCommand(ChannelUID channelUID, Command command) {
67 if (channelUID.getId().equals(TEMPERATURE)) {
68 if (command instanceof RefreshType) {
69 publishSensorValue(channelUID);
71 logger.debug("Command {} is not supported for channel: {}. Supported command: REFRESH", command,
78 public void initialize() {
79 OneWireGpioConfiguration configuration = getConfigAs(OneWireGpioConfiguration.class);
80 gpioBusFile = configuration.gpio_bus_file;
81 refreshTime = configuration.refresh_time;
82 precision = configuration.precision.intValue();
83 logger.debug("GPIO Busfile={}, RefreshTime={}, precision={}", gpioBusFile, refreshTime, precision);
85 if (checkConfiguration()) {
86 startAutomaticRefresh();
87 updateStatus(ThingStatus.ONLINE);
92 * This method checks if the provided configuration is valid.
93 * When invalid parameter is found, default value is assigned.
95 private boolean checkConfiguration() {
96 if (gpioBusFile == null || gpioBusFile.isEmpty()) {
97 logger.debug("GPIO_BUS_FILE not set. Please check configuration, and set proper path to w1_slave file.");
98 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
99 "The path to the w1_slave sensor data file is missing.");
103 if (refreshTime <= 0) {
104 logger.debug("Refresh time [{}] is not valid. Falling back to default value: {}.", refreshTime,
105 DEFAULT_REFRESH_TIME);
106 refreshTime = DEFAULT_REFRESH_TIME;
109 if (precision < 0 || precision > MAX_PRECISION_VALUE) {
111 "Precision value {} is outside allowed values [0 - {}]. Falling back to maximum precision value.",
112 precision, MAX_PRECISION_VALUE);
113 precision = MAX_PRECISION_VALUE;
119 private void startAutomaticRefresh() {
120 Runnable refresher = () -> {
121 List<Channel> channels = getThing().getChannels();
122 for (Channel channel : channels) {
123 if (isLinked(channel.getUID().getId())) {
124 publishSensorValue(channel.getUID());
129 sensorRefreshJob = scheduler.scheduleWithFixedDelay(refresher, 0, refreshTime.intValue(), TimeUnit.SECONDS);
130 logger.debug("Start automatic refresh every {} seconds", refreshTime.intValue());
133 private void publishSensorValue(ChannelUID channelUID) {
134 String channelID = channelUID.getId();
137 publishTemperatureSensorState(channelUID);
140 logger.debug("Can not update channel with ID : {} - channel name might be wrong!", channelID);
145 private void publishTemperatureSensorState(ChannelUID channelUID) {
146 BigDecimal temp = readSensorTemperature(gpioBusFile);
148 updateState(channelUID, new QuantityType<>(temp, SIUnits.CELSIUS));
152 private BigDecimal readSensorTemperature(String gpioFile) {
153 try (Stream<String> stream = Files.lines(Paths.get(gpioFile))) {
154 Optional<String> temperatureLine = stream
155 .filter(s -> s.contains(OneWireGPIOBindingConstants.FILE_TEMP_MARKER)).findFirst();
156 if (temperatureLine.isPresent()) {
157 String line = temperatureLine.get();
158 String tempString = line.substring(line.indexOf(OneWireGPIOBindingConstants.FILE_TEMP_MARKER)
159 + OneWireGPIOBindingConstants.FILE_TEMP_MARKER.length());
160 Integer intTemp = Integer.parseInt(tempString);
161 if (getThing().getStatus() != ThingStatus.ONLINE) {
162 updateStatus(ThingStatus.ONLINE);
164 return calculateValue(intTemp);
167 "GPIO file didn't contain line with 't=' where temperature value should be available. Check if configuration points to the proper file");
170 } catch (IOException | InvalidPathException e) {
171 logger.debug("error reading GPIO bus file. File path is: {}. Check if path is proper.", gpioFile, e);
172 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Error reading GPIO bus file.");
177 private BigDecimal calculateValue(Integer intTemp) {
178 BigDecimal result = BigDecimal.valueOf(intTemp).movePointLeft(3);
179 if (precision != MAX_PRECISION_VALUE) {
180 result = result.setScale(precision, RoundingMode.HALF_UP);
182 logger.debug("Thing = {}, temperature value = {}.", getThing().getUID(), result);
187 public void dispose() {
188 if (sensorRefreshJob != null) {
189 sensorRefreshJob.cancel(true);