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.mynice.internal.handler;
15 import static org.openhab.binding.mynice.internal.MyNiceBindingConstants.*;
16 import static org.openhab.core.thing.Thing.*;
18 import java.util.List;
20 import java.util.Optional;
21 import java.util.concurrent.TimeUnit;
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.openhab.binding.mynice.internal.config.CourtesyConfiguration;
25 import org.openhab.binding.mynice.internal.xml.dto.CommandType;
26 import org.openhab.binding.mynice.internal.xml.dto.Device;
27 import org.openhab.binding.mynice.internal.xml.dto.Properties.DoorStatus;
28 import org.openhab.binding.mynice.internal.xml.dto.Property;
29 import org.openhab.binding.mynice.internal.xml.dto.T4Command;
30 import org.openhab.core.library.types.OnOffType;
31 import org.openhab.core.library.types.StopMoveType;
32 import org.openhab.core.library.types.StringType;
33 import org.openhab.core.thing.Bridge;
34 import org.openhab.core.thing.Channel;
35 import org.openhab.core.thing.ChannelUID;
36 import org.openhab.core.thing.Thing;
37 import org.openhab.core.thing.ThingStatus;
38 import org.openhab.core.thing.binding.BaseThingHandler;
39 import org.openhab.core.thing.binding.BridgeHandler;
40 import org.openhab.core.types.Command;
41 import org.openhab.core.types.RefreshType;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
47 * @author Gaƫl L'hopital - Initial contribution
50 public class GateHandler extends BaseThingHandler implements MyNiceDataListener {
52 private final Logger logger = LoggerFactory.getLogger(GateHandler.class);
54 private String id = "";
55 private Optional<DoorStatus> gateStatus = Optional.empty();
56 private List<T4Command> t4Allowed = List.of();
58 public GateHandler(Thing thing) {
63 public void initialize() {
64 id = (String) getConfig().get(DEVICE_ID);
65 getBridgeHandler().ifPresent(h -> h.registerDataListener(this));
69 public void dispose() {
71 gateStatus = Optional.empty();
72 t4Allowed = List.of();
73 getBridgeHandler().ifPresent(h -> h.unregisterDataListener(this));
76 private Optional<It4WifiHandler> getBridgeHandler() {
77 Bridge bridge = getBridge();
79 BridgeHandler handler = bridge.getHandler();
80 if (handler instanceof It4WifiHandler it4Handler) {
81 return Optional.of(it4Handler);
84 return Optional.empty();
88 public void handleCommand(ChannelUID channelUID, Command command) {
89 String channelId = channelUID.getId();
91 if (command instanceof RefreshType) {
92 getBridgeHandler().ifPresent(handler -> handler.sendCommand(CommandType.INFO));
93 } else if (CHANNEL_COURTESY.equals(channelId) && command instanceof OnOffType) {
94 handleT4Command(T4Command.MDEy);
95 } else if (CHANNEL_STATUS.equals(channelId)) {
96 gateStatus.ifPresentOrElse(status -> {
97 if (command instanceof StopMoveType stopMoveCommand) {
98 handleStopMove(status, stopMoveCommand);
101 handleStopMove(status, StopMoveType.valueOf(command.toString()));
102 } catch (IllegalArgumentException e) {
103 logger.warn("Invalid StopMoveType command received : {}", command);
106 }, () -> logger.info("Current status of the gate unknown, can not send {} command", command));
107 } else if (CHANNEL_COMMAND.equals(channelId)) {
108 getBridgeHandler().ifPresent(handler -> handler.sendCommand(id, command.toString()));
109 } else if (CHANNEL_T4_COMMAND.equals(channelId)) {
111 T4Command t4 = T4Command.fromCode(command.toString());
113 } catch (IllegalArgumentException e) {
114 logger.warn("{} is not a valid T4 command", command);
117 logger.warn("Unable to handle command {} on channel {}", command, channelId);
121 private void handleStopMove(DoorStatus status, StopMoveType stopMoveCommand) {
122 if (stopMoveCommand == StopMoveType.STOP) {
123 if (status == DoorStatus.STOPPED) {
124 logger.info("The gate is already stopped.");
126 handleT4Command(T4Command.MDAy);
131 // It's a move Command
132 if (status == DoorStatus.OPEN) {
133 handleT4Command(T4Command.MDA0);
134 } else if (status == DoorStatus.CLOSED) {
135 handleT4Command(T4Command.MDAz);
136 } else if (status.moving) {
137 logger.info("The gate is already currently moving.");
138 } else { // it is closed
139 handleT4Command(T4Command.MDAx);
143 private void handleT4Command(T4Command t4Command) {
144 if (t4Allowed.contains(t4Command)) {
145 getBridgeHandler().ifPresent(handler -> handler.sendCommand(id, t4Command));
147 logger.warn("This gate does not accept the T4 command '{}'", t4Command);
152 public void onDataFetched(List<Device> devices) {
153 devices.stream().filter(d -> id.equals(d.id)).findFirst().map(device -> {
154 updateStatus(ThingStatus.ONLINE);
155 Property t4list = device.properties.t4allowed;
156 if (t4Allowed.isEmpty() && t4list != null) {
157 int value = Integer.parseInt(t4list.values, 16);
158 t4Allowed = T4Command.fromBitmask(value).stream().toList();
159 if (thing.getProperties().isEmpty()) {
160 updateProperties(Map.of(PROPERTY_VENDOR, device.manuf, PROPERTY_MODEL_ID, device.prod,
161 PROPERTY_SERIAL_NUMBER, device.serialNr, PROPERTY_HARDWARE_VERSION, device.versionHW,
162 PROPERTY_FIRMWARE_VERSION, device.versionFW, ALLOWED_T4,
163 String.join(",", t4Allowed.stream().map(Enum::name).toList())));
166 if (device.prod != null) {
167 getBridgeHandler().ifPresent(h -> h.sendCommand(CommandType.STATUS));
169 DoorStatus status = device.properties.status();
171 updateState(CHANNEL_STATUS, new StringType(status.name()));
172 updateState(CHANNEL_OBSTRUCTED, OnOffType.from(device.properties.obstructed()));
173 updateState(CHANNEL_MOVING, OnOffType.from(status.moving));
174 if (status.moving && isLinked(CHANNEL_COURTESY)) {
175 Channel courtesy = getThing().getChannel(CHANNEL_COURTESY);
176 if (courtesy != null) {
177 updateState(CHANNEL_COURTESY, OnOffType.ON);
178 CourtesyConfiguration config = courtesy.getConfiguration().as(CourtesyConfiguration.class);
179 scheduler.schedule(() -> updateState(CHANNEL_COURTESY, OnOffType.OFF), config.duration,
183 gateStatus = Optional.of(status);