]> git.basschouten.com Git - openhab-addons.git/blob
fb49bf5a7a1caf468a457147c278cf49f9c70bcf
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.jeelink.internal.pca301;
14
15 import static org.openhab.binding.jeelink.internal.JeeLinkBindingConstants.*;
16
17 import java.math.BigDecimal;
18 import java.math.RoundingMode;
19 import java.util.concurrent.ScheduledFuture;
20 import java.util.concurrent.TimeUnit;
21 import java.util.concurrent.atomic.AtomicInteger;
22
23 import org.openhab.binding.jeelink.internal.JeeLinkHandler;
24 import org.openhab.binding.jeelink.internal.JeeLinkSensorHandler;
25 import org.openhab.binding.jeelink.internal.ReadingPublisher;
26 import org.openhab.binding.jeelink.internal.config.Pca301SensorConfig;
27 import org.openhab.core.library.types.OnOffType;
28 import org.openhab.core.library.types.QuantityType;
29 import org.openhab.core.library.unit.Units;
30 import org.openhab.core.thing.ChannelUID;
31 import org.openhab.core.thing.Thing;
32 import org.openhab.core.types.Command;
33 import org.openhab.core.types.RefreshType;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 /**
38  * Handler for an EC3000 sensor thing.
39  *
40  * @author Volker Bier - Initial contribution
41  */
42 public class Pca301SensorHandler extends JeeLinkSensorHandler<Pca301Reading> {
43     private final Logger logger = LoggerFactory.getLogger(Pca301SensorHandler.class);
44
45     private JeeLinkHandler bridge;
46     private OnOffType state;
47     private final AtomicInteger channel = new AtomicInteger(-1);
48
49     private ScheduledFuture<?> retry;
50     private int sendCount;
51
52     public Pca301SensorHandler(Thing thing, String sensorType) {
53         super(thing, sensorType);
54     }
55
56     @Override
57     public Class<Pca301Reading> getReadingClass() {
58         return Pca301Reading.class;
59     }
60
61     @Override
62     public void initialize() {
63         super.initialize();
64
65         bridge = (JeeLinkHandler) getBridge().getHandler();
66
67         Pca301SensorConfig cfg = getConfigAs(Pca301SensorConfig.class);
68         sendCount = cfg.sendCount;
69
70         logger.debug("initilized handler for thing {} ({}): sendCount = {}", getThing().getLabel(),
71                 getThing().getUID().getId(), sendCount);
72     }
73
74     @Override
75     public void dispose() {
76         super.dispose();
77         cancelRetry();
78     }
79
80     @Override
81     public synchronized void handleCommand(ChannelUID channelUid, Command command) {
82         logger.debug("received command for thing {} ({}): {}", getThing().getLabel(), getThing().getUID().getId(),
83                 command);
84
85         if (channelUid.getIdWithoutGroup().equals(SWITCHING_STATE_CHANNEL)) {
86             if (command instanceof OnOffType) {
87                 sendCommandRetry((OnOffType) command);
88             } else {
89                 sendCommand(command);
90             }
91         } else if (command != RefreshType.REFRESH) {
92             logger.warn("Unsupported command {} for channel {} of sensor with id {}.", command,
93                     channelUid.getIdWithoutGroup(), this.id);
94         }
95     }
96
97     @Override
98     public ReadingPublisher<Pca301Reading> createPublisher() {
99         return new ReadingPublisher<Pca301Reading>() {
100             @Override
101             public void publish(Pca301Reading reading) {
102                 if (reading != null) {
103                     channel.set(reading.getChannel());
104
105                     BigDecimal current = new BigDecimal(reading.getCurrent()).setScale(1, RoundingMode.HALF_UP);
106                     state = reading.isOn() ? OnOffType.ON : OnOffType.OFF;
107
108                     updateState(CURRENT_POWER_CHANNEL, new QuantityType<>(current, Units.WATT));
109                     updateState(CONSUMPTION_CHANNEL, new QuantityType<>(reading.getTotal(), Units.WATT_HOUR));
110                     updateState(SWITCHING_STATE_CHANNEL, state);
111
112                     logger.debug("updated states for thing {} ({}): state={}, current={}, total={}",
113                             getThing().getLabel(), getThing().getUID().getId(), state, current, reading.getTotal());
114                 }
115             }
116
117             @Override
118             public void dispose() {
119             }
120         };
121     }
122
123     private void sendCommand(Command command) {
124         int chan = channel.get();
125
126         if (chan != -1) {
127             if (command == RefreshType.REFRESH) {
128                 bridge.getConnection().sendCommands(chan + ",4," + id.replaceAll("-", ",") + ",0,255,255,255,255s");
129             } else if (command instanceof OnOffType) {
130                 bridge.getConnection().sendCommands(chan + ",5," + id.replaceAll("-", ",") + ","
131                         + (command == OnOffType.ON ? "1" : "2") + ",255,255,255,255s");
132             } else {
133                 logger.warn("Unsupported command {} for sensor with id {}.", command, this.id);
134             }
135         } else if (command != RefreshType.REFRESH && !(command instanceof OnOffType)) {
136             logger.warn("Could not send command {} for sensor with id {}. Ignoring command.", command, this.id);
137         }
138     }
139
140     private synchronized void sendCommandRetry(OnOffType command) {
141         cancelRetry();
142
143         retry = scheduler.scheduleWithFixedDelay(new Runnable() {
144             int remainingRetries = sendCount;
145
146             @Override
147             public void run() {
148                 if (state == null) {
149                     logger.debug("skip sending of command (current state not yet known) for thing {} ({}): {}",
150                             getThing().getLabel(), getThing().getUID().getId(), command);
151                 } else if ((state != command && remainingRetries > 0)) {
152                     logger.debug("sending command for thing {} ({}) attempt {}/{}: {}", getThing().getLabel(),
153                             getThing().getUID().getId(), (sendCount - remainingRetries + 1), sendCount, command);
154
155                     sendCommand(command);
156                     remainingRetries--;
157                 } else {
158                     // we get here when the state is as expected or when the state is still not as expected after
159                     // the configured number of retries. we should cancel the retry for both cases
160                     if (state != command) {
161                         logger.debug("giving up command for thing {} ({}): {}", getThing().getLabel(),
162                                 getThing().getUID().getId(), command);
163                     }
164
165                     cancelRetry();
166                 }
167             }
168         }, 0, 2, TimeUnit.SECONDS);
169     }
170
171     private synchronized void cancelRetry() {
172         if (retry != null) {
173             retry.cancel(true);
174             retry = null;
175         }
176     }
177 }