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.liquidcheck.internal;
15 import static org.openhab.binding.liquidcheck.internal.LiquidCheckBindingConstants.CONTENT_CHANNEL;
16 import static org.openhab.binding.liquidcheck.internal.LiquidCheckBindingConstants.FILL_INDICATOR_CHANNEL;
17 import static org.openhab.binding.liquidcheck.internal.LiquidCheckBindingConstants.LEVEL_CHANNEL;
18 import static org.openhab.binding.liquidcheck.internal.LiquidCheckBindingConstants.MEASURE_CHANNEL;
19 import static org.openhab.binding.liquidcheck.internal.LiquidCheckBindingConstants.PUMP_TOTAL_RUNS_CHANNEL;
20 import static org.openhab.binding.liquidcheck.internal.LiquidCheckBindingConstants.PUMP_TOTAL_RUNTIME_CHANNEL;
21 import static org.openhab.binding.liquidcheck.internal.LiquidCheckBindingConstants.RAW_CONTENT_CHANNEL;
22 import static org.openhab.binding.liquidcheck.internal.LiquidCheckBindingConstants.RAW_LEVEL_CHANNEL;
24 import java.util.HashMap;
26 import java.util.concurrent.ExecutionException;
27 import java.util.concurrent.ScheduledFuture;
28 import java.util.concurrent.TimeUnit;
29 import java.util.concurrent.TimeoutException;
31 import org.eclipse.jdt.annotation.NonNullByDefault;
32 import org.eclipse.jdt.annotation.Nullable;
33 import org.eclipse.jetty.client.HttpClient;
34 import org.openhab.binding.liquidcheck.internal.httpclient.LiquidCheckHttpClient;
35 import org.openhab.binding.liquidcheck.internal.json.CommData;
36 import org.openhab.core.library.types.DecimalType;
37 import org.openhab.core.library.types.OnOffType;
38 import org.openhab.core.library.types.QuantityType;
39 import org.openhab.core.library.unit.SIUnits;
40 import org.openhab.core.library.unit.Units;
41 import org.openhab.core.thing.ChannelUID;
42 import org.openhab.core.thing.Thing;
43 import org.openhab.core.thing.ThingStatus;
44 import org.openhab.core.thing.ThingStatusDetail;
45 import org.openhab.core.thing.binding.BaseThingHandler;
46 import org.openhab.core.types.Command;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
50 import com.google.gson.Gson;
51 import com.google.gson.JsonSyntaxException;
54 * The {@link LiquidCheckHandler} is responsible for handling commands, which are
55 * sent to one of the channels.
57 * @author Marcel Goerentz - Initial contribution
60 public class LiquidCheckHandler extends BaseThingHandler {
62 private final Logger logger = LoggerFactory.getLogger(LiquidCheckHandler.class);
63 private final HttpClient httpClient;
65 private Map<String, String> oldProps = new HashMap<>();
67 private LiquidCheckConfiguration config = new LiquidCheckConfiguration();
68 private @Nullable LiquidCheckHttpClient client;
70 private @Nullable ScheduledFuture<?> polling;
72 public LiquidCheckHandler(Thing thing, HttpClient httpClient) {
74 this.httpClient = httpClient;
78 @SuppressWarnings("null")
79 public void handleCommand(ChannelUID channelUID, Command command) {
80 if (channelUID.getId().equals(MEASURE_CHANNEL)) {
81 if (command instanceof OnOffType) {
83 LiquidCheckHttpClient client = this.client;
84 if (client != null && client.isConnected()) {
85 String response = client.measureCommand();
86 CommData commandResponse = new Gson().fromJson(response, CommData.class);
87 if (commandResponse != null && !commandResponse.header.name.equals("")) {
88 if (!"success".equals(commandResponse.context.status)) {
89 logger.warn("Starting the measurement was not successful!");
92 logger.debug("The object commandResponse is null!");
95 } catch (TimeoutException | ExecutionException | JsonSyntaxException e) {
96 logger.warn("This went wrong in handleCommand: {}", e.getMessage());
97 } catch (InterruptedException e) {
98 Thread.currentThread().interrupt();
100 updateState(channelUID, OnOffType.OFF);
106 public void initialize() {
107 config = getConfigAs(LiquidCheckConfiguration.class);
108 oldProps = thing.getProperties();
110 updateStatus(ThingStatus.UNKNOWN);
111 var client = new LiquidCheckHttpClient(config, httpClient);
112 this.client = client;
113 PollingForData pollingRunnable = new PollingForData(client);
114 polling = scheduler.scheduleWithFixedDelay(pollingRunnable, 0, config.refreshInterval, TimeUnit.SECONDS);
118 public void dispose() {
119 ScheduledFuture<?> polling = this.polling;
120 if (null != polling) {
121 polling.cancel(true);
126 private class PollingForData implements Runnable {
128 private final LiquidCheckHttpClient client;
130 public PollingForData(LiquidCheckHttpClient client) {
131 this.client = client;
137 String jsonString = client.pollData();
138 CommData response = new Gson().fromJson(jsonString, CommData.class);
139 if (response != null && !response.header.messageId.equals("")) {
140 Map<String, String> properties = response.createPropertyMap();
141 if (!oldProps.equals(properties)) {
142 oldProps = properties;
143 updateProperties(properties);
145 updateState(CONTENT_CHANNEL, new QuantityType<>(response.payload.measure.content, Units.LITRE));
146 updateState(LEVEL_CHANNEL, new QuantityType<>(response.payload.measure.level, SIUnits.METRE));
147 updateState(RAW_CONTENT_CHANNEL,
148 new QuantityType<>(response.payload.measure.raw.content, Units.LITRE));
150 updateState(RAW_LEVEL_CHANNEL,
151 new QuantityType<>(response.payload.measure.raw.level, SIUnits.METRE));
153 updateState(PUMP_TOTAL_RUNS_CHANNEL, new DecimalType(response.payload.system.pump.totalRuns));
154 updateState(PUMP_TOTAL_RUNTIME_CHANNEL,
155 new QuantityType<>(response.payload.system.pump.totalRuntime, Units.SECOND));
156 if (config.maxContent > 1) {
157 double fillIndicator = response.payload.measure.content / config.maxContent * 100;
158 updateState(FILL_INDICATOR_CHANNEL, new QuantityType<>(fillIndicator, Units.PERCENT));
160 if (!thing.getStatus().equals(ThingStatus.ONLINE)) {
161 updateStatus(ThingStatus.ONLINE);
164 logger.debug("Json is null");
166 } catch (TimeoutException | ExecutionException | JsonSyntaxException e) {
167 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
168 } catch (InterruptedException e) {
169 Thread.currentThread().interrupt();