]> git.basschouten.com Git - openhab-addons.git/blob
59d1521a54fc94f72d604068b58abd14b39250db
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 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.opensprinkler.internal.handler;
14
15 import static org.openhab.binding.opensprinkler.internal.OpenSprinklerBindingConstants.*;
16 import static org.openhab.core.library.unit.MetricPrefix.MILLI;
17 import static org.openhab.core.library.unit.Units.PERCENT;
18
19 import java.math.BigDecimal;
20 import java.util.ArrayList;
21
22 import javax.measure.quantity.Dimensionless;
23 import javax.measure.quantity.ElectricCurrent;
24
25 import org.eclipse.jdt.annotation.NonNullByDefault;
26 import org.openhab.binding.opensprinkler.internal.OpenSprinklerStateDescriptionProvider;
27 import org.openhab.binding.opensprinkler.internal.api.OpenSprinklerApi;
28 import org.openhab.binding.opensprinkler.internal.api.exception.CommunicationApiException;
29 import org.openhab.binding.opensprinkler.internal.api.exception.UnauthorizedApiException;
30 import org.openhab.core.library.types.DecimalType;
31 import org.openhab.core.library.types.OnOffType;
32 import org.openhab.core.library.types.QuantityType;
33 import org.openhab.core.library.types.StringType;
34 import org.openhab.core.library.unit.Units;
35 import org.openhab.core.thing.Channel;
36 import org.openhab.core.thing.ChannelUID;
37 import org.openhab.core.thing.Thing;
38 import org.openhab.core.thing.ThingStatus;
39 import org.openhab.core.thing.ThingStatusDetail;
40 import org.openhab.core.thing.binding.builder.ThingBuilder;
41 import org.openhab.core.types.Command;
42 import org.openhab.core.types.RefreshType;
43
44 /**
45  * @author Chris Graham - Initial contribution
46  * @author Florian Schmidt - Refactoring
47  */
48 @NonNullByDefault
49 public class OpenSprinklerDeviceHandler extends OpenSprinklerBaseHandler {
50     public final OpenSprinklerStateDescriptionProvider stateDescriptionProvider;
51
52     public OpenSprinklerDeviceHandler(Thing thing, OpenSprinklerStateDescriptionProvider stateDescriptionProvider) {
53         super(thing);
54         this.stateDescriptionProvider = stateDescriptionProvider;
55     }
56
57     @Override
58     protected void updateChannel(ChannelUID channel) {
59         OpenSprinklerApi localAPI = getApi();
60         if (localAPI == null) {
61             return;
62         }
63         switch (channel.getIdWithoutGroup()) {
64             case SENSOR_RAIN:
65                 if (localAPI.isRainDetected()) {
66                     updateState(channel, OnOffType.ON);
67                 } else {
68                     updateState(channel, OnOffType.OFF);
69                 }
70                 break;
71             case CHANNEL_RAIN_DELAY:
72                 updateState(channel, localAPI.getRainDelay());
73                 break;
74             case SENSOR_2:
75                 if (localAPI.getSensor2State() == 1) {
76                     updateState(channel, OnOffType.ON);
77                 } else {
78                     updateState(channel, OnOffType.OFF);
79                 }
80                 break;
81             case SENSOR_WATERLEVEL:
82                 updateState(channel, QuantityType.valueOf(localAPI.waterLevel(), PERCENT));
83                 break;
84             case SENSOR_CURRENT_DRAW:
85                 updateState(channel, new QuantityType<ElectricCurrent>(localAPI.currentDraw(), MILLI(Units.AMPERE)));
86                 break;
87             case SENSOR_SIGNAL_STRENGTH:
88                 int rssiValue = localAPI.signalStrength();
89                 if (rssiValue < -80) {
90                     updateState(channel, DecimalType.ZERO);
91                 } else if (rssiValue < -70) {
92                     updateState(channel, new DecimalType(1));
93                 } else if (rssiValue < -60) {
94                     updateState(channel, new DecimalType(2));
95                 } else if (rssiValue < -40) {
96                     updateState(channel, new DecimalType(3));
97                 } else if (rssiValue >= -40) {
98                     updateState(channel, new DecimalType(4));
99                 }
100                 break;
101             case SENSOR_FLOW_COUNT:
102                 updateState(channel, new QuantityType<Dimensionless>(localAPI.flowSensorCount(), Units.ONE));
103                 break;
104             case CHANNEL_PROGRAMS:
105                 break;
106             case CHANNEL_ENABLE_PROGRAMS:
107                 if (localAPI.getIsEnabled()) {
108                     updateState(channel, OnOffType.ON);
109                 } else {
110                     updateState(channel, OnOffType.OFF);
111                 }
112                 break;
113             case CHANNEL_STATIONS:
114                 break;
115             case NEXT_DURATION:
116                 break;
117             case CHANNEL_RESET_STATIONS:
118                 break;
119             case CHANNEL_QUEUED_ZONES:
120                 updateState(channel, new DecimalType(localAPI.getQueuedZones()));
121                 break;
122             case CHANNEL_CLOUD_CONNECTED:
123                 updateState(channel, OnOffType.from(localAPI.getCloudConnected() == 3));
124                 break;
125             case CHANNEL_PAUSE_PROGRAMS:
126                 updateState(channel, new QuantityType<>(localAPI.getPausedState(), Units.SECOND));
127                 break;
128             default:
129                 logger.debug("Can not update the unknown channel {}", channel);
130         }
131     }
132
133     @Override
134     public void initialize() {
135         super.initialize();
136         OpenSprinklerApi localAPI = getApi();
137         // Remove channels due to missing sensors or old firmware
138         if (localAPI != null) {
139             ArrayList<Channel> removeChannels = new ArrayList<>();
140             Channel channel = thing.getChannel(SENSOR_CURRENT_DRAW);
141             if (localAPI.currentDraw() == -1 && channel != null) {
142                 logger.debug("No current sensor detected, removing channel.");
143                 removeChannels.add(channel);
144             }
145             channel = thing.getChannel(SENSOR_SIGNAL_STRENGTH);
146             if (localAPI.signalStrength() == 1 && channel != null) {
147                 removeChannels.add(channel);
148             }
149             channel = thing.getChannel(SENSOR_FLOW_COUNT);
150             if (localAPI.flowSensorCount() == -1 && channel != null) {
151                 removeChannels.add(channel);
152             }
153             channel = thing.getChannel(SENSOR_2);
154             if (localAPI.getSensor2State() == -1 && channel != null) {
155                 removeChannels.add(channel);
156             }
157             channel = thing.getChannel(CHANNEL_QUEUED_ZONES);
158             if (localAPI.getQueuedZones() == -1 && channel != null) {
159                 removeChannels.add(channel);
160             }
161             channel = thing.getChannel(CHANNEL_CLOUD_CONNECTED);
162             if (localAPI.getCloudConnected() == -1 && channel != null) {
163                 removeChannels.add(channel);
164             }
165             channel = thing.getChannel(CHANNEL_PAUSE_PROGRAMS);
166             if (localAPI.getPausedState() == -1 && channel != null) {
167                 removeChannels.add(channel);
168             }
169             if (!removeChannels.isEmpty()) {
170                 ThingBuilder thingBuilder = editThing();
171                 thingBuilder.withoutChannels(removeChannels);
172                 updateThing(thingBuilder.build());
173             }
174             updateProgramsChanOptions(localAPI);
175             updateStationsChanOptions(localAPI);
176             nextDurationTime = new BigDecimal(1800);
177             updateState(NEXT_DURATION, new QuantityType<>(nextDurationTime, Units.SECOND));
178         }
179     }
180
181     /**
182      * Fetch the stored Program list and update the StateOptions on the channel so they match.
183      *
184      * @param api
185      */
186     private void updateProgramsChanOptions(OpenSprinklerApi api) {
187         stateDescriptionProvider.setStateOptions(new ChannelUID(this.getThing().getUID(), CHANNEL_PROGRAMS),
188                 api.getPrograms());
189     }
190
191     private void updateStationsChanOptions(OpenSprinklerApi api) {
192         stateDescriptionProvider.setStateOptions(new ChannelUID(this.getThing().getUID(), CHANNEL_STATIONS),
193                 api.getStations());
194     }
195
196     protected void handleRainDelayCommand(ChannelUID channelUID, Command command, OpenSprinklerApi api)
197             throws UnauthorizedApiException, CommunicationApiException {
198         if (!(command instanceof QuantityType<?>)) {
199             logger.warn("Ignoring implausible non-QuantityType command for rainDelay.");
200             return;
201         }
202         QuantityType<?> quantity = (QuantityType<?>) command;
203         quantity = quantity.toUnit(Units.HOUR);
204         if (quantity != null) {
205             api.setRainDelay(quantity.intValue());
206         }
207     }
208
209     @Override
210     public void handleCommand(ChannelUID channelUID, Command command) {
211         OpenSprinklerApi api = getApi();
212         if (api == null) {
213             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "OpenSprinkler bridge returned no API.");
214             return;
215         }
216         OpenSprinklerHttpBridgeHandler localBridge = bridgeHandler;
217         if (localBridge == null) {
218             return;
219         }
220         try {
221             if (command instanceof RefreshType) {
222                 switch (channelUID.getIdWithoutGroup()) {
223                     case CHANNEL_PROGRAMS:
224                         api.getProgramData();
225                         updateProgramsChanOptions(api);
226                         break;
227                     case CHANNEL_STATIONS:
228                         api.getStationNames();
229                         updateStationsChanOptions(api);
230                         break;
231                 }
232             } else {
233                 switch (channelUID.getIdWithoutGroup()) {
234                     case CHANNEL_PROGRAMS:
235                         api.runProgram(command);
236                         break;
237                     case CHANNEL_ENABLE_PROGRAMS:
238                         api.enablePrograms(command);
239                         break;
240                     case NEXT_DURATION:
241                         handleNextDurationCommand(channelUID, command);
242                         break;
243                     case CHANNEL_RESET_STATIONS:
244                         if (command == OnOffType.ON) {
245                             api.resetStations();
246                         }
247                         break;
248                     case CHANNEL_STATIONS:
249                         if (command instanceof StringType) {
250                             BigDecimal temp = new BigDecimal(command.toString());
251                             api.openStation(temp.intValue(), nextDurationValue());
252                         }
253                         break;
254                     case CHANNEL_RAIN_DELAY:
255                         handleRainDelayCommand(channelUID, command, api);
256                         break;
257                     case CHANNEL_PAUSE_PROGRAMS:
258                         if (command == OnOffType.OFF) {
259                             api.setPausePrograms(0);
260                         } else if (command instanceof DecimalType) {
261                             api.setPausePrograms(((BigDecimal) command).intValue());
262                         } else if (command instanceof QuantityType<?>) {
263                             QuantityType<?> quantity = (QuantityType<?>) command;
264                             quantity = quantity.toUnit(Units.SECOND);
265                             if (quantity != null) {
266                                 api.setPausePrograms(quantity.toBigDecimal().intValue());
267                             }
268                         } else {
269                             logger.warn(
270                                     "The CHANNEL_PAUSE_PROGRAMS only supports QuanityType in seconds, DecimalType and OFF");
271                             return;
272                         }
273                         break;
274                 }
275                 localBridge.delayedRefresh();// update sensors and controls after command is sent
276             }
277         } catch (Exception e) {
278             localBridge.communicationError(e);
279         }
280     }
281 }