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.unifi.internal.handler;
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;
28 import javax.measure.quantity.ElectricCurrent;
29 import javax.measure.quantity.ElectricPotential;
30 import javax.measure.quantity.Power;
32 import org.eclipse.jdt.annotation.NonNullByDefault;
33 import org.eclipse.jdt.annotation.Nullable;
34 import org.openhab.binding.unifi.internal.UniFiPoePortThingConfig;
35 import org.openhab.binding.unifi.internal.api.UniFiController;
36 import org.openhab.binding.unifi.internal.api.UniFiException;
37 import org.openhab.binding.unifi.internal.api.cache.UniFiControllerCache;
38 import org.openhab.binding.unifi.internal.api.dto.UniFiDevice;
39 import org.openhab.binding.unifi.internal.api.dto.UniFiPortTable;
40 import org.openhab.binding.unifi.internal.api.dto.UniFiPortTuple;
41 import org.openhab.binding.unifi.internal.api.dto.UniFiSwitchPorts;
42 import org.openhab.core.library.types.OnOffType;
43 import org.openhab.core.library.types.QuantityType;
44 import org.openhab.core.library.types.StringType;
45 import org.openhab.core.library.unit.Units;
46 import org.openhab.core.thing.Channel;
47 import org.openhab.core.thing.ChannelUID;
48 import org.openhab.core.thing.Thing;
49 import org.openhab.core.thing.ThingStatus;
50 import org.openhab.core.thing.ThingStatusDetail;
51 import org.openhab.core.types.Command;
52 import org.openhab.core.types.State;
53 import org.openhab.core.types.UnDefType;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
58 * A Power Over Ethernet (PoE) port on a UniFi switch.
60 * @author Hilbrand Bouwkamp - Initial contribution
63 public class UniFiPoePortThingHandler extends UniFiBaseThingHandler<UniFiSwitchPorts, UniFiPoePortThingConfig> {
65 private final Logger logger = LoggerFactory.getLogger(UniFiPoePortThingHandler.class);
67 private UniFiPoePortThingConfig config = new UniFiPoePortThingConfig();
68 private String poeEnableMode = "";
70 public UniFiPoePortThingHandler(final Thing thing) {
75 protected boolean initialize(final UniFiPoePortThingConfig config) {
77 if (!config.isValid()) {
78 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
79 "@text/error.thing.poe.offline.configuration_error");
82 return initPoeEnableMode();
85 private boolean initPoeEnableMode() {
86 final Channel channel = getThing().getChannel(CHANNEL_PORT_POE_ENABLE);
88 if (channel == null) {
91 final String channelConfigPoeEnableMode = (String) channel.getConfiguration()
92 .get(CHANNEL_ENABLE_PARAMETER_MODE);
93 poeEnableMode = channelConfigPoeEnableMode.isBlank() ? CHANNEL_ENABLE_PARAMETER_MODE_AUTO
94 : channelConfigPoeEnableMode;
100 protected @Nullable UniFiSwitchPorts getEntity(final UniFiControllerCache cache) {
101 return cache.getSwitchPorts(config.getMacAddress());
105 protected State getChannelState(final UniFiSwitchPorts ports, final String channelId) {
106 final UniFiPortTuple portTuple = getPort(ports);
108 if (portTuple == null) {
109 return setOfflineOnNoPoEPortData();
111 final UniFiPortTable port = portTuple.getTable();
114 return setOfflineOnNoPoEPortData();
120 state = OnOffType.from(port.isUp());
122 case CHANNEL_PORT_POE_ENABLE:
123 state = OnOffType.from(port.isPoeEnabled());
125 case CHANNEL_PORT_POE_MODE:
126 state = StringType.valueOf(port.getPoeMode());
128 case CHANNEL_PORT_POE_POWER:
129 state = new QuantityType<Power>(Double.valueOf(port.getPoePower()), Units.WATT);
131 case CHANNEL_PORT_POE_VOLTAGE:
132 state = new QuantityType<ElectricPotential>(Double.valueOf(port.getPoeVoltage()), Units.VOLT);
134 case CHANNEL_PORT_POE_CURRENT:
135 state = new QuantityType<ElectricCurrent>(Double.valueOf(port.getPoeCurrent()), MILLI(Units.AMPERE));
138 state = UnDefType.UNDEF;
143 private State setOfflineOnNoPoEPortData() {
144 if (getThing().getStatus() != ThingStatus.OFFLINE) {
145 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
146 "@text/error.thing.poe.offline.nodata_error");
148 return UnDefType.NULL;
151 private @Nullable UniFiPortTuple getPort(final UniFiSwitchPorts ports) {
152 return ports.getPort(config.getPortNumber());
156 protected boolean handleCommand(final UniFiController controller, final UniFiSwitchPorts ports,
157 final ChannelUID channelUID, final Command command) throws UniFiException {
158 final String channelID = channelUID.getIdWithoutGroup();
161 case CHANNEL_PORT_POE_ENABLE:
162 if (command instanceof OnOffType) {
163 return handleModeCommand(controller, ports,
164 OnOffType.ON == command ? poeEnableMode : CHANNEL_ENABLE_PARAMETER_MODE_OFF);
167 case CHANNEL_PORT_POE_MODE:
168 if (command instanceof StringType) {
169 return handleModeCommand(controller, ports, command.toFullString());
172 case CHANNEL_PORT_POE_CMD:
173 if (command instanceof StringType) {
174 return handleCmd(controller, ports, command.toFullString());
182 private boolean handleModeCommand(final UniFiController controller, final UniFiSwitchPorts ports,
183 final String poeMode) throws UniFiException {
184 final @Nullable UniFiDevice device = controller.getCache().getDevice(config.getMacAddress());
186 if (canUpdate(device, ports) && device != null) {
187 controller.poeMode(device, ports.updatedList(config.getPortNumber(), p -> p.setPoeMode(poeMode)));
188 // No refresh because UniFi device takes some time to update. Therefore a refresh would only show the
194 private boolean handleCmd(final UniFiController controller, final UniFiSwitchPorts ports, final String command)
195 throws UniFiException {
196 final @Nullable UniFiDevice device = controller.getCache().getDevice(config.getMacAddress());
198 if (canUpdate(device, ports) && device != null) {
199 if (CHANNEL_PORT_POE_CMD_POWER_CYCLE.equalsIgnoreCase(command.replaceAll("[- ]", ""))) {
200 controller.poePowerCycle(device, config.getPortNumber());
202 logger.info("Unknown command '{}' given to PoE port for thing '{}': device {} or portToUpdate {} null",
203 command, getThing().getUID(), device, ports);
210 private boolean canUpdate(final @Nullable UniFiDevice device, final UniFiSwitchPorts ports) {
211 if (device == null || getPort(ports) == null) {
212 logger.info("Could not change the PoE port state for thing '{}': device {} or portToUpdate {} null",
213 getThing().getUID(), device, config.getPortNumber());