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.orbitbhyve.internal.handler;
15 import static org.openhab.binding.orbitbhyve.internal.OrbitBhyveBindingConstants.*;
17 import java.util.HashMap;
18 import java.util.List;
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.openhab.binding.orbitbhyve.internal.model.OrbitBhyveDevice;
23 import org.openhab.binding.orbitbhyve.internal.model.OrbitBhyveDeviceStatus;
24 import org.openhab.binding.orbitbhyve.internal.model.OrbitBhyveProgram;
25 import org.openhab.binding.orbitbhyve.internal.model.OrbitBhyveZone;
26 import org.openhab.core.library.types.DateTimeType;
27 import org.openhab.core.library.types.DecimalType;
28 import org.openhab.core.library.types.OnOffType;
29 import org.openhab.core.library.types.QuantityType;
30 import org.openhab.core.library.types.StringType;
31 import org.openhab.core.library.unit.Units;
32 import org.openhab.core.thing.Bridge;
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.ThingStatusInfo;
39 import org.openhab.core.thing.binding.BaseThingHandler;
40 import org.openhab.core.thing.binding.builder.ChannelBuilder;
41 import org.openhab.core.thing.binding.builder.ThingBuilder;
42 import org.openhab.core.thing.type.ChannelTypeUID;
43 import org.openhab.core.types.Command;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
48 * The {@link OrbitBhyveSprinklerHandler} is responsible for handling commands, which are
49 * sent to one of the channels.
51 * @author Ondrej Pecta - Initial contribution
54 public class OrbitBhyveSprinklerHandler extends BaseThingHandler {
56 private final Logger logger = LoggerFactory.getLogger(OrbitBhyveSprinklerHandler.class);
58 public OrbitBhyveSprinklerHandler(Thing thing) {
62 private int wateringTime = 5;
63 private HashMap<String, OrbitBhyveProgram> programs = new HashMap<>();
64 private String deviceId = "";
67 public void handleCommand(ChannelUID channelUID, Command command) {
68 OrbitBhyveBridgeHandler handler = getBridgeHandler();
69 if (handler != null) {
70 if (CHANNEL_CONTROL.equals(channelUID.getId()) && command instanceof OnOffType) {
71 String mode = OnOffType.ON.equals(command) ? "auto" : "off";
72 handler.changeRunMode(deviceId, mode);
75 if (CHANNEL_SMART_WATERING.equals(channelUID.getId()) && command instanceof OnOffType) {
76 boolean enable = OnOffType.ON.equals(command);
77 handler.setSmartWatering(deviceId, enable);
80 if (!channelUID.getId().startsWith("enable_program") && OnOffType.OFF.equals(command)) {
81 handler.stopWatering(deviceId);
84 if (CHANNEL_WATERING_TIME.equals(channelUID.getId()) && command instanceof QuantityType quantityCommand) {
85 final QuantityType<?> value = quantityCommand.toUnit(Units.MINUTE);
87 wateringTime = value.intValue();
91 if (channelUID.getId().startsWith("zone")) {
92 if (OnOffType.ON.equals(command)) {
93 handler.runZone(deviceId, channelUID.getId().replace("zone_", ""), wateringTime);
97 if (channelUID.getId().startsWith("program")) {
98 if (OnOffType.ON.equals(command)) {
99 handler.runProgram(deviceId, channelUID.getId().replace("program_", ""));
103 if (channelUID.getId().startsWith("enable_program") && command instanceof OnOffType) {
104 String id = channelUID.getId().replace("enable_program_", "");
105 OrbitBhyveProgram prog = programs.get(id);
107 handler.enableProgram(prog, OnOffType.ON.equals(command));
109 logger.debug("Cannot get program id: {}", id);
113 if (CHANNEL_RAIN_DELAY.equals(channelUID.getId()) && command instanceof DecimalType) {
114 final QuantityType<?> value = ((QuantityType<?>) command).toUnit(Units.HOUR);
116 handler.setRainDelay(deviceId, value.intValue());
123 private String getSprinklerId() {
124 return getThing().getConfiguration().get("id") != null ? getThing().getConfiguration().get("id").toString()
128 private @Nullable OrbitBhyveBridgeHandler getBridgeHandler() {
129 Bridge bridge = getBridge();
130 if (bridge != null) {
131 return (OrbitBhyveBridgeHandler) bridge.getHandler();
137 public void initialize() {
138 Bridge bridge = getBridge();
139 if (bridge != null) {
140 logger.debug("Initializing, bridge is {}", bridge.getStatus());
141 if (ThingStatus.ONLINE == bridge.getStatus()) {
144 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
149 private synchronized void doInit() {
150 OrbitBhyveBridgeHandler handler = getBridgeHandler();
151 if (handler != null) {
152 deviceId = getSprinklerId();
153 if ("".equals(deviceId)) {
154 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Sprinkler id is missing!");
156 OrbitBhyveDevice device = handler.getDevice(deviceId);
157 if (device != null) {
158 setDeviceOnline(device.isConnected());
159 createChannels(device.getZones());
160 updateDeviceStatus(device.getStatus());
162 List<OrbitBhyveProgram> programs = handler.getPrograms();
163 for (OrbitBhyveProgram program : programs) {
164 if (deviceId.equals(program.getDeviceId())) {
165 cacheProgram(program);
166 createProgram(program);
170 updateState(CHANNEL_WATERING_TIME, new QuantityType<>(wateringTime, Units.MINUTE));
171 logger.debug("Finished initializing of sprinkler!");
177 public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
178 super.bridgeStatusChanged(bridgeStatusInfo);
179 if (bridgeStatusInfo.getStatus() == ThingStatus.ONLINE) {
184 private synchronized void cacheProgram(OrbitBhyveProgram program) {
185 if (!programs.containsKey(program.getProgram())) {
186 programs.put(program.getProgram(), program);
190 public void updateDeviceStatus(OrbitBhyveDeviceStatus status) {
191 if (!status.getMode().isEmpty()) {
192 updateState(CHANNEL_MODE, new StringType(status.getMode()));
193 updateState(CHANNEL_CONTROL, OnOffType.from(!"off".equals(status.getMode())));
195 if (!status.getNextStartTime().isEmpty()) {
196 DateTimeType dt = new DateTimeType(status.getNextStartTime());
197 updateState(CHANNEL_NEXT_START, dt);
198 logger.debug("Next start time: {}", status.getNextStartTime());
200 updateState(CHANNEL_RAIN_DELAY, new DecimalType(status.getDelay()));
203 private void createProgram(OrbitBhyveProgram program) {
204 String channelName = "program_" + program.getProgram();
205 if (thing.getChannel(channelName) == null) {
206 logger.debug("Creating channel for program: {} with name: {}", program.getProgram(), program.getName());
207 createProgramChannel(channelName, "Switch", "Program " + program.getName());
209 String enableChannelName = "enable_" + channelName;
210 if (thing.getChannel(enableChannelName) == null) {
211 logger.debug("Creating enable channel for program: {} with name: {}", program.getProgram(),
213 createProgramChannel(enableChannelName, "Switch", "Enable program " + program.getName());
215 Channel ch = thing.getChannel(enableChannelName);
217 updateState(ch.getUID(), OnOffType.from(program.isEnabled()));
221 private void createProgramChannel(String name, String type, String label) {
222 ChannelTypeUID program = new ChannelTypeUID(BINDING_ID, "program");
223 createChannel(name, type, label, program);
226 private void createChannels(List<OrbitBhyveZone> zones) {
227 for (OrbitBhyveZone zone : zones) {
228 String channelName = "zone_" + zone.getStation();
229 if (thing.getChannel(channelName) == null) {
230 logger.debug("Creating channel for zone: {} with name: {}", zone.getStation(), zone.getName());
231 createZoneChannel(channelName, "Switch", "Zone " + zone.getName());
236 private void createZoneChannel(String name, String type, String label) {
237 ChannelTypeUID zone = new ChannelTypeUID(BINDING_ID, "zone");
238 createChannel(name, type, label, zone);
241 private void createChannel(String name, String type, String label, ChannelTypeUID typeUID) {
242 ThingBuilder thingBuilder = editThing();
243 Channel channel = ChannelBuilder.create(new ChannelUID(thing.getUID(), name), type).withLabel(label)
244 .withType(typeUID).build();
245 thingBuilder.withChannel(channel);
246 updateThing(thingBuilder.build());
249 public void setDeviceOnline(boolean connected) {
251 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
252 "Not connected to Orbit BHyve Cloud");
254 updateStatus(ThingStatus.ONLINE);
258 public void updateProgram(OrbitBhyveProgram program) {
259 String enableChannelName = "enable_program_" + program.getProgram();
260 Channel ch = thing.getChannel(enableChannelName);
262 updateState(ch.getUID(), OnOffType.from(program.isEnabled()));
266 public void updateSmartWatering(String senseMode) {
267 updateState(CHANNEL_SMART_WATERING, OnOffType.from("auto".equals(senseMode)));