]> git.basschouten.com Git - openhab-addons.git/blob
f3e34f054cb5a93951bcb8f6890ed3ca5f97d48e
[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.unifi.internal.handler;
14
15 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_ENABLE_PARAMETER_MODE;
16 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_ENABLE_PARAMETER_MODE_AUTO;
17 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_ENABLE_PARAMETER_MODE_OFF;
18 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_ONLINE;
19 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_PORT_POE_CMD;
20 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_PORT_POE_CMD_POWER_CYCLE;
21 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_PORT_POE_CURRENT;
22 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_PORT_POE_ENABLE;
23 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_PORT_POE_MODE;
24 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_PORT_POE_POWER;
25 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_PORT_POE_VOLTAGE;
26 import static org.openhab.core.library.unit.MetricPrefix.MILLI;
27
28 import javax.measure.Quantity;
29 import javax.measure.Unit;
30
31 import org.eclipse.jdt.annotation.NonNullByDefault;
32 import org.eclipse.jdt.annotation.Nullable;
33 import org.openhab.binding.unifi.internal.UniFiPoePortThingConfig;
34 import org.openhab.binding.unifi.internal.api.UniFiController;
35 import org.openhab.binding.unifi.internal.api.UniFiException;
36 import org.openhab.binding.unifi.internal.api.cache.UniFiControllerCache;
37 import org.openhab.binding.unifi.internal.api.dto.UniFiDevice;
38 import org.openhab.binding.unifi.internal.api.dto.UniFiPortTable;
39 import org.openhab.binding.unifi.internal.api.dto.UniFiPortTuple;
40 import org.openhab.binding.unifi.internal.api.dto.UniFiSwitchPorts;
41 import org.openhab.core.library.types.OnOffType;
42 import org.openhab.core.library.types.QuantityType;
43 import org.openhab.core.library.types.StringType;
44 import org.openhab.core.library.unit.Units;
45 import org.openhab.core.thing.Channel;
46 import org.openhab.core.thing.ChannelUID;
47 import org.openhab.core.thing.Thing;
48 import org.openhab.core.thing.ThingStatus;
49 import org.openhab.core.thing.ThingStatusDetail;
50 import org.openhab.core.types.Command;
51 import org.openhab.core.types.State;
52 import org.openhab.core.types.UnDefType;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 /**
57  * A Power Over Ethernet (PoE) port on a UniFi switch.
58  *
59  * @author Hilbrand Bouwkamp - Initial contribution
60  */
61 @NonNullByDefault
62 public class UniFiPoePortThingHandler extends UniFiBaseThingHandler<UniFiSwitchPorts, UniFiPoePortThingConfig> {
63
64     private final Logger logger = LoggerFactory.getLogger(UniFiPoePortThingHandler.class);
65
66     private UniFiPoePortThingConfig config = new UniFiPoePortThingConfig();
67     private String poeEnableMode = "";
68
69     public UniFiPoePortThingHandler(final Thing thing) {
70         super(thing);
71     }
72
73     @Override
74     protected boolean initialize(final UniFiPoePortThingConfig config) {
75         this.config = config;
76         if (!config.isValid()) {
77             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
78                     "@text/error.thing.poe.offline.configuration_error");
79             return false;
80         }
81         return initPoeEnableMode();
82     }
83
84     private boolean initPoeEnableMode() {
85         final Channel channel = getThing().getChannel(CHANNEL_PORT_POE_ENABLE);
86
87         if (channel == null) {
88             return false;
89         } else {
90             final String channelConfigPoeEnableMode = (String) channel.getConfiguration()
91                     .get(CHANNEL_ENABLE_PARAMETER_MODE);
92             poeEnableMode = channelConfigPoeEnableMode.isBlank() ? CHANNEL_ENABLE_PARAMETER_MODE_AUTO
93                     : channelConfigPoeEnableMode;
94             return true;
95         }
96     }
97
98     @Override
99     protected @Nullable UniFiSwitchPorts getEntity(final UniFiControllerCache cache) {
100         return cache.getSwitchPorts(config.getMacAddress());
101     }
102
103     @Override
104     protected State getChannelState(final UniFiSwitchPorts ports, final String channelId) {
105         final UniFiPortTuple portTuple = getPort(ports);
106
107         if (portTuple == null) {
108             return setOfflineOnNoPoEPortData();
109         }
110         final UniFiPortTable port = portTuple.getTable();
111
112         if (port == null) {
113             return setOfflineOnNoPoEPortData();
114         }
115         final State state;
116
117         switch (channelId) {
118             case CHANNEL_ONLINE:
119                 state = OnOffType.from(port.isUp());
120                 break;
121             case CHANNEL_PORT_POE_ENABLE:
122                 state = OnOffType.from(port.isPoeEnabled());
123                 break;
124             case CHANNEL_PORT_POE_MODE:
125                 state = StringType.valueOf(port.getPoeMode());
126                 break;
127             case CHANNEL_PORT_POE_POWER:
128                 state = safeDouble(port.getPoePower(), Units.WATT);
129                 break;
130             case CHANNEL_PORT_POE_VOLTAGE:
131                 state = safeDouble(port.getPoeVoltage(), Units.VOLT);
132                 break;
133             case CHANNEL_PORT_POE_CURRENT:
134                 state = safeDouble(port.getPoeCurrent(), MILLI(Units.AMPERE));
135                 break;
136             default:
137                 state = UnDefType.UNDEF;
138         }
139         return state;
140     }
141
142     private <Q extends Quantity<Q>> State safeDouble(final String value, final Unit<Q> unit) {
143         try {
144             return value == null ? UnDefType.UNDEF : QuantityType.valueOf(Double.parseDouble(value), unit);
145         } catch (final NumberFormatException e) {
146             logger.debug("Could not parse value '{}' for unit {}", value, unit);
147             return UnDefType.UNDEF;
148         }
149     }
150
151     private State setOfflineOnNoPoEPortData() {
152         if (getThing().getStatus() != ThingStatus.OFFLINE) {
153             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
154                     "@text/error.thing.poe.offline.nodata_error");
155         }
156         return UnDefType.NULL;
157     }
158
159     private @Nullable UniFiPortTuple getPort(final UniFiSwitchPorts ports) {
160         return ports.getPort(config.getPortNumber());
161     }
162
163     @Override
164     protected boolean handleCommand(final UniFiController controller, final UniFiSwitchPorts ports,
165             final ChannelUID channelUID, final Command command) throws UniFiException {
166         final String channelID = channelUID.getIdWithoutGroup();
167
168         switch (channelID) {
169             case CHANNEL_PORT_POE_ENABLE:
170                 if (command instanceof OnOffType) {
171                     return handleModeCommand(controller, ports,
172                             OnOffType.ON == command ? poeEnableMode : CHANNEL_ENABLE_PARAMETER_MODE_OFF);
173                 }
174                 break;
175             case CHANNEL_PORT_POE_MODE:
176                 if (command instanceof StringType) {
177                     return handleModeCommand(controller, ports, command.toFullString());
178                 }
179                 break;
180             case CHANNEL_PORT_POE_CMD:
181                 if (command instanceof StringType) {
182                     return handleCmd(controller, ports, command.toFullString());
183                 }
184             default:
185                 return false;
186         }
187         return false;
188     }
189
190     private boolean handleModeCommand(final UniFiController controller, final UniFiSwitchPorts ports,
191             final String poeMode) throws UniFiException {
192         final @Nullable UniFiDevice device = controller.getCache().getDevice(config.getMacAddress());
193
194         if (canUpdate(device, ports) && device != null) {
195             controller.poeMode(device, ports.updatedList(config.getPortNumber(), p -> p.setPoeMode(poeMode)));
196             // No refresh because UniFi device takes some time to update. Therefore a refresh would only show the
197             // old state.
198         }
199         return true;
200     }
201
202     private boolean handleCmd(final UniFiController controller, final UniFiSwitchPorts ports, final String command)
203             throws UniFiException {
204         final @Nullable UniFiDevice device = controller.getCache().getDevice(config.getMacAddress());
205
206         if (canUpdate(device, ports) && device != null) {
207             if (CHANNEL_PORT_POE_CMD_POWER_CYCLE.equalsIgnoreCase(command.replaceAll("[- ]", ""))) {
208                 controller.poePowerCycle(device, config.getPortNumber());
209             } else {
210                 logger.info("Unknown command '{}' given to PoE port for thing '{}': device {} or portToUpdate {} null",
211                         command, getThing().getUID(), device, ports);
212             }
213
214         }
215         return true;
216     }
217
218     private boolean canUpdate(final @Nullable UniFiDevice device, final UniFiSwitchPorts ports) {
219         if (device == null || getPort(ports) == null) {
220             logger.info("Could not change the PoE port state for thing '{}': device {} or portToUpdate {} null",
221                     getThing().getUID(), device, config.getPortNumber());
222             return false;
223         }
224         return true;
225     }
226 }