2 * Copyright (c) 2010-2024 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.mikrotik.internal.handler;
15 import static org.openhab.binding.mikrotik.internal.MikrotikBindingConstants.*;
17 import java.math.BigDecimal;
18 import java.time.LocalDateTime;
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.openhab.binding.mikrotik.internal.MikrotikBindingConstants;
23 import org.openhab.binding.mikrotik.internal.config.WirelessClientThingConfig;
24 import org.openhab.binding.mikrotik.internal.model.RouterosCapsmanRegistration;
25 import org.openhab.binding.mikrotik.internal.model.RouterosDevice;
26 import org.openhab.binding.mikrotik.internal.model.RouterosRegistrationBase;
27 import org.openhab.binding.mikrotik.internal.model.RouterosWirelessRegistration;
28 import org.openhab.binding.mikrotik.internal.util.RateCalculator;
29 import org.openhab.binding.mikrotik.internal.util.StateUtil;
30 import org.openhab.core.thing.ChannelUID;
31 import org.openhab.core.thing.Thing;
32 import org.openhab.core.thing.ThingTypeUID;
33 import org.openhab.core.types.Command;
34 import org.openhab.core.types.State;
35 import org.openhab.core.types.UnDefType;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
40 * The {@link MikrotikWirelessClientThingHandler} is a {@link MikrotikBaseThingHandler} subclass that wraps shared
41 * functionality for all wireless clients listed either in CAPsMAN or Wireless RouterOS sections.
42 * It is responsible for handling commands, which are sent to one of the channels and emit channel updates whenever
45 * @author Oleg Vivtash - Initial contribution
48 public class MikrotikWirelessClientThingHandler extends MikrotikBaseThingHandler<WirelessClientThingConfig> {
49 private final Logger logger = LoggerFactory.getLogger(MikrotikWirelessClientThingHandler.class);
51 private @Nullable RouterosRegistrationBase wifiReg;
53 private boolean online = false;
54 private boolean continuousConnection = false;
55 private @Nullable LocalDateTime lastSeen;
57 private final RateCalculator txByteRate = new RateCalculator(BigDecimal.ZERO);
58 private final RateCalculator rxByteRate = new RateCalculator(BigDecimal.ZERO);
59 private final RateCalculator txPacketRate = new RateCalculator(BigDecimal.ZERO);
60 private final RateCalculator rxPacketRate = new RateCalculator(BigDecimal.ZERO);
62 public static boolean supportsThingType(ThingTypeUID thingTypeUID) {
63 return MikrotikBindingConstants.THING_TYPE_WIRELESS_CLIENT.equals(thingTypeUID);
66 public MikrotikWirelessClientThingHandler(Thing thing) {
70 private void fetchModels() {
71 var cfg = this.config;
73 RouterosDevice routeros = getRouterOs();
75 RouterosWirelessRegistration wifiRegistration = null;
76 if (routeros != null) {
77 wifiRegistration = routeros.findWirelessRegistration(cfg.mac);
79 this.wifiReg = wifiRegistration;
80 if (wifiRegistration != null && !cfg.ssid.isBlank()
81 && !cfg.ssid.equalsIgnoreCase(wifiRegistration.getSSID())) {
85 if (this.wifiReg == null && routeros != null) {
86 // try looking in capsman when there is no wirelessRegistration
87 RouterosCapsmanRegistration capsmanReg = routeros.findCapsmanRegistration(cfg.mac);
88 this.wifiReg = capsmanReg;
89 if (capsmanReg != null && !cfg.ssid.isBlank() && !cfg.ssid.equalsIgnoreCase(capsmanReg.getSSID())) {
97 protected void refreshModels() {
99 var wifiReg = this.wifiReg;
100 if (wifiReg != null) {
101 this.lastSeen = LocalDateTime.now();
103 var cfg = this.config;
104 int considerContinuous = 180;
106 considerContinuous = cfg.considerContinuous;
108 txByteRate.update(wifiReg.getTxBytes());
109 rxByteRate.update(wifiReg.getRxBytes());
110 txPacketRate.update(wifiReg.getTxPackets());
111 rxPacketRate.update(wifiReg.getRxPackets());
112 LocalDateTime uptimeStart = wifiReg.getUptimeStart();
113 continuousConnection = (uptimeStart != null)
114 && LocalDateTime.now().isAfter(uptimeStart.plusSeconds(considerContinuous));
117 this.continuousConnection = false;
122 protected void refreshChannel(ChannelUID channelUID) {
123 var wifiReg = this.wifiReg;
125 String channelID = channelUID.getIdWithoutGroup();
126 State oldState = currentState.getOrDefault(channelID, UnDefType.NULL);
127 State newState = oldState;
129 if (channelID.equals(CHANNEL_CONNECTED)) {
130 newState = StateUtil.boolContactOrNull(this.online);
131 } else if (channelID.equals(CHANNEL_LAST_SEEN)) {
132 newState = StateUtil.timeOrNull(lastSeen);
133 } else if (channelID.equals(CHANNEL_CONTINUOUS)) {
134 newState = StateUtil.boolContactOrNull(this.continuousConnection);
135 } else if (!this.online || wifiReg == null) {
136 newState = UnDefType.NULL;
140 newState = StateUtil.stringOrNull(wifiReg.getName());
142 case CHANNEL_COMMENT:
143 newState = StateUtil.stringOrNull(wifiReg.getComment());
146 newState = StateUtil.stringOrNull(wifiReg.getMacAddress());
148 case CHANNEL_INTERFACE:
149 newState = StateUtil.stringOrNull(wifiReg.getInterfaceName());
152 newState = StateUtil.stringOrNull(wifiReg.getSSID());
154 case CHANNEL_UP_SINCE:
155 newState = StateUtil.timeOrNull(wifiReg.getUptimeStart());
157 case CHANNEL_TX_DATA_RATE:
158 newState = StateUtil.qtyMegabitPerSecOrNull(txByteRate.getMegabitRate());
160 case CHANNEL_RX_DATA_RATE:
161 newState = StateUtil.qtyMegabitPerSecOrNull(rxByteRate.getMegabitRate());
163 case CHANNEL_TX_PACKET_RATE:
164 newState = StateUtil.floatOrNull(txPacketRate.getRate());
166 case CHANNEL_RX_PACKET_RATE:
167 newState = StateUtil.floatOrNull(rxPacketRate.getRate());
169 case CHANNEL_TX_BYTES:
170 newState = StateUtil.bigIntOrNull(wifiReg.getTxBytes());
172 case CHANNEL_RX_BYTES:
173 newState = StateUtil.bigIntOrNull(wifiReg.getRxBytes());
175 case CHANNEL_TX_PACKETS:
176 newState = StateUtil.bigIntOrNull(wifiReg.getTxPackets());
178 case CHANNEL_RX_PACKETS:
179 newState = StateUtil.bigIntOrNull(wifiReg.getRxPackets());
182 newState = UnDefType.NULL;
183 if (wifiReg instanceof RouterosWirelessRegistration) {
184 newState = getWirelessRegistrationChannelState(channelID);
185 } else if (wifiReg instanceof RouterosCapsmanRegistration) {
186 newState = getCapsmanRegistrationChannelState(channelID);
191 if (!newState.equals(oldState)) {
192 updateState(channelID, newState);
193 currentState.put(channelID, newState);
197 @SuppressWarnings("null")
198 protected State getCapsmanRegistrationChannelState(String channelID) {
199 if (this.wifiReg == null) {
200 return UnDefType.UNDEF;
203 RouterosCapsmanRegistration capsmanReg = (RouterosCapsmanRegistration) this.wifiReg;
206 return StateUtil.intOrNull(capsmanReg.getRxSignal());
208 return UnDefType.UNDEF;
212 @SuppressWarnings("null")
213 protected State getWirelessRegistrationChannelState(String channelID) {
214 if (this.wifiReg == null) {
215 return UnDefType.UNDEF;
218 RouterosWirelessRegistration wirelessReg = (RouterosWirelessRegistration) this.wifiReg;
221 return StateUtil.intOrNull(wirelessReg.getRxSignal());
223 return UnDefType.UNDEF;
228 protected void executeCommand(ChannelUID channelUID, Command command) {
232 logger.warn("Ignoring unsupported command = {} for channel = {}", command, channelUID);