2 * Copyright (c) 2010-2021 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 boolean 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())) {
94 return this.wifiReg != null;
98 protected void refreshModels() {
99 this.online = fetchModels();
101 lastSeen = LocalDateTime.now();
103 continuousConnection = false;
105 var wifiReg = this.wifiReg;
106 if (wifiReg != null) {
107 var cfg = this.config;
108 int considerContinuous = 180;
110 considerContinuous = cfg.considerContinuous;
112 txByteRate.update(wifiReg.getTxBytes());
113 rxByteRate.update(wifiReg.getRxBytes());
114 txPacketRate.update(wifiReg.getTxPackets());
115 rxPacketRate.update(wifiReg.getRxPackets());
116 LocalDateTime uptimeStart = wifiReg.getUptimeStart();
117 continuousConnection = (uptimeStart != null)
118 && LocalDateTime.now().isAfter(uptimeStart.plusSeconds(considerContinuous));
123 protected void refreshChannel(ChannelUID channelUID) {
124 var wifiReg = this.wifiReg;
125 if (wifiReg == null) {
126 logger.warn("wifiReg is null in refreshChannel({})", channelUID);
130 String channelID = channelUID.getIdWithoutGroup();
131 State oldState = currentState.getOrDefault(channelID, UnDefType.NULL);
132 State newState = oldState;
134 if (channelID.equals(CHANNEL_CONNECTED)) {
135 newState = StateUtil.boolOrNull(online);
136 } else if (channelID.equals(CHANNEL_LAST_SEEN)) {
137 newState = StateUtil.timeOrNull(lastSeen);
138 } else if (channelID.equals(CHANNEL_CONTINUOUS)) {
139 newState = StateUtil.boolOrNull(continuousConnection);
140 } else if (!online) {
141 newState = UnDefType.NULL;
145 newState = StateUtil.stringOrNull(wifiReg.getName());
147 case CHANNEL_COMMENT:
148 newState = StateUtil.stringOrNull(wifiReg.getComment());
151 newState = StateUtil.stringOrNull(wifiReg.getMacAddress());
153 case CHANNEL_INTERFACE:
154 newState = StateUtil.stringOrNull(wifiReg.getInterfaceName());
157 newState = StateUtil.stringOrNull(wifiReg.getSSID());
159 case CHANNEL_UP_SINCE:
160 newState = StateUtil.timeOrNull(wifiReg.getUptimeStart());
162 case CHANNEL_TX_DATA_RATE:
163 newState = StateUtil.qtyMegabitPerSecOrNull(txByteRate.getMegabitRate());
165 case CHANNEL_RX_DATA_RATE:
166 newState = StateUtil.qtyMegabitPerSecOrNull(rxByteRate.getMegabitRate());
168 case CHANNEL_TX_PACKET_RATE:
169 newState = StateUtil.floatOrNull(txPacketRate.getRate());
171 case CHANNEL_RX_PACKET_RATE:
172 newState = StateUtil.floatOrNull(rxPacketRate.getRate());
174 case CHANNEL_TX_BYTES:
175 newState = StateUtil.bigIntOrNull(wifiReg.getTxBytes());
177 case CHANNEL_RX_BYTES:
178 newState = StateUtil.bigIntOrNull(wifiReg.getRxBytes());
180 case CHANNEL_TX_PACKETS:
181 newState = StateUtil.bigIntOrNull(wifiReg.getTxPackets());
183 case CHANNEL_RX_PACKETS:
184 newState = StateUtil.bigIntOrNull(wifiReg.getRxPackets());
187 newState = UnDefType.NULL;
188 if (wifiReg instanceof RouterosWirelessRegistration) {
189 newState = getWirelessRegistrationChannelState(channelID);
190 } else if (wifiReg instanceof RouterosCapsmanRegistration) {
191 newState = getCapsmanRegistrationChannelState(channelID);
196 if (!newState.equals(oldState)) {
197 updateState(channelID, newState);
198 currentState.put(channelID, newState);
202 @SuppressWarnings("null")
203 protected State getCapsmanRegistrationChannelState(String channelID) {
204 if (this.wifiReg == null) {
205 return UnDefType.UNDEF;
208 RouterosCapsmanRegistration capsmanReg = (RouterosCapsmanRegistration) this.wifiReg;
211 return StateUtil.intOrNull(capsmanReg.getRxSignal());
213 return UnDefType.UNDEF;
217 @SuppressWarnings("null")
218 protected State getWirelessRegistrationChannelState(String channelID) {
219 if (this.wifiReg == null) {
220 return UnDefType.UNDEF;
223 RouterosWirelessRegistration wirelessReg = (RouterosWirelessRegistration) this.wifiReg;
226 return StateUtil.intOrNull(wirelessReg.getRxSignal());
228 return UnDefType.UNDEF;
233 protected void executeCommand(ChannelUID channelUID, Command command) {
237 logger.warn("Ignoring unsupported command = {} for channel = {}", command, channelUID);