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.neato.internal.handler;
15 import static org.openhab.binding.neato.internal.NeatoBindingConstants.*;
17 import java.util.concurrent.ScheduledFuture;
18 import java.util.concurrent.TimeUnit;
20 import org.apache.commons.lang3.ObjectUtils;
21 import org.eclipse.jdt.annotation.NonNull;
22 import org.openhab.binding.neato.internal.CouldNotFindRobotException;
23 import org.openhab.binding.neato.internal.NeatoBindingConstants;
24 import org.openhab.binding.neato.internal.NeatoCommunicationException;
25 import org.openhab.binding.neato.internal.NeatoRobot;
26 import org.openhab.binding.neato.internal.classes.Cleaning;
27 import org.openhab.binding.neato.internal.classes.Details;
28 import org.openhab.binding.neato.internal.classes.NeatoState;
29 import org.openhab.binding.neato.internal.config.NeatoRobotConfig;
30 import org.openhab.core.library.types.DecimalType;
31 import org.openhab.core.library.types.OnOffType;
32 import org.openhab.core.library.types.StringType;
33 import org.openhab.core.thing.ChannelUID;
34 import org.openhab.core.thing.Thing;
35 import org.openhab.core.thing.ThingStatus;
36 import org.openhab.core.thing.ThingStatusDetail;
37 import org.openhab.core.thing.binding.BaseThingHandler;
38 import org.openhab.core.types.Command;
39 import org.openhab.core.types.RefreshType;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
44 * The {@link NeatoHandler} is responsible for handling commands, which are
45 * sent to one of the channels.
47 * @author Patrik Wimnell - Initial contribution
48 * @author Jeff Lauterbach - Code Cleanup and Refactor
50 public class NeatoHandler extends BaseThingHandler {
52 private Logger logger = LoggerFactory.getLogger(NeatoHandler.class);
54 private NeatoRobot mrRobot;
56 private int refreshTime;
57 private ScheduledFuture<?> refreshTask;
59 public NeatoHandler(Thing thing) {
64 public void handleCommand(@NonNull ChannelUID channelUID, Command command) {
65 if (command instanceof RefreshType) {
66 refreshStateAndUpdate();
67 } else if (channelUID.getId().equals(NeatoBindingConstants.COMMAND)) {
68 sendCommandToRobot(command);
72 private void sendCommandToRobot(Command command) {
73 logger.debug("Ok - will handle command for CHANNEL_COMMAND");
76 mrRobot.sendCommand(command.toString());
77 } catch (NeatoCommunicationException e) {
78 logger.debug("Error while processing command from openHAB.", e);
79 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
81 this.refreshStateAndUpdate();
85 public void dispose() {
86 logger.debug("Running dispose()");
87 if (this.refreshTask != null) {
88 this.refreshTask.cancel(true);
89 this.refreshTask = null;
94 public void initialize() {
95 updateStatus(ThingStatus.UNKNOWN);
96 logger.debug("Will boot up Neato Vacuum Cleaner binding!");
98 NeatoRobotConfig config = getThing().getConfiguration().as(NeatoRobotConfig.class);
100 logger.debug("Neato Robot Config: {}", config);
102 refreshTime = config.getRefresh();
103 if (refreshTime < 30) {
105 "Refresh time [{}] is not valid. Refresh time must be at least 30 seconds. Setting to minimum of 30 sec",
107 config.setRefresh(30);
110 mrRobot = new NeatoRobot(config);
111 startAutomaticRefresh();
114 public void refreshStateAndUpdate() {
115 if (mrRobot != null) {
117 mrRobot.sendGetState();
118 updateStatus(ThingStatus.ONLINE);
120 mrRobot.sendGetGeneralInfo();
123 } catch (NeatoCommunicationException | CouldNotFindRobotException e) {
124 logger.debug("Error when refreshing state.", e);
125 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
130 private void startAutomaticRefresh() {
131 Runnable refresher = () -> refreshStateAndUpdate();
133 this.refreshTask = scheduler.scheduleWithFixedDelay(refresher, 0, refreshTime, TimeUnit.SECONDS);
134 logger.debug("Start automatic refresh at {} seconds", refreshTime);
137 private void publishChannels() {
138 logger.debug("Updating Channels");
140 NeatoState neatoState = mrRobot.getState();
141 if (neatoState == null) {
145 updateProperty(Thing.PROPERTY_FIRMWARE_VERSION, neatoState.getMeta().getFirmware());
146 updateProperty(Thing.PROPERTY_MODEL_ID, neatoState.getMeta().getModelName());
148 updateState(CHANNEL_STATE, new StringType(neatoState.getRobotState().name()));
149 updateState(CHANNEL_ERROR, new StringType((String) ObjectUtils.defaultIfNull(neatoState.getError(), "")));
150 updateState(CHANNEL_ACTION, new StringType(neatoState.getRobotAction().name()));
152 Details details = neatoState.getDetails();
153 if (details != null) {
154 updateState(CHANNEL_BATTERY, new DecimalType(details.getCharge()));
155 updateState(CHANNEL_DOCKHASBEENSEEN, details.getDockHasBeenSeen() ? OnOffType.ON : OnOffType.OFF);
156 updateState(CHANNEL_ISCHARGING, details.getIsCharging() ? OnOffType.ON : OnOffType.OFF);
157 updateState(CHANNEL_ISSCHEDULED, details.getIsScheduleEnabled() ? OnOffType.ON : OnOffType.OFF);
158 updateState(CHANNEL_ISDOCKED, details.getIsDocked() ? OnOffType.ON : OnOffType.OFF);
161 Cleaning cleaning = neatoState.getCleaning();
162 if (cleaning != null) {
163 updateState(CHANNEL_CLEANINGCATEGORY, new StringType(cleaning.getCategory().name()));
164 updateState(CHANNEL_CLEANINGMODE, new StringType(cleaning.getMode().name()));
165 updateState(CHANNEL_CLEANINGMODIFIER, new StringType(cleaning.getModifier().name()));
166 updateState(CHANNEL_CLEANINGSPOTWIDTH, new DecimalType(cleaning.getSpotWidth()));
167 updateState(CHANNEL_CLEANINGSPOTHEIGHT, new DecimalType(cleaning.getSpotHeight()));