mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[Mikrotik] Add support for RouterOS 7 devices and support internal radios with capsman disabled (#17547)
* Add support for API version 7 and AX wifi6 range of devices. Signed-off-by: Matthew Skinner <matt@pcmus.com> Signed-off-by: Ciprian Pascu <contact@ciprianpascu.ro>
This commit is contained in:
parent
756ad0232a
commit
6f283a47d4
@ -12,8 +12,7 @@
|
||||
*/
|
||||
package org.openhab.binding.mikrotik.internal.handler;
|
||||
|
||||
import static org.openhab.core.thing.ThingStatus.OFFLINE;
|
||||
import static org.openhab.core.thing.ThingStatus.ONLINE;
|
||||
import static org.openhab.core.thing.ThingStatus.*;
|
||||
import static org.openhab.core.thing.ThingStatusDetail.CONFIGURATION_ERROR;
|
||||
import static org.openhab.core.types.RefreshType.REFRESH;
|
||||
|
||||
@ -63,8 +62,6 @@ public abstract class MikrotikBaseThingHandler<C extends ConfigValidation> exten
|
||||
protected ExpiringCache<Boolean> refreshCache = new ExpiringCache<>(Duration.ofDays(1), () -> false);
|
||||
protected Map<String, State> currentState = new HashMap<>();
|
||||
|
||||
// public static boolean supportsThingType(ThingTypeUID thingTypeUID) <- in subclasses
|
||||
|
||||
public MikrotikBaseThingHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
@ -12,8 +12,7 @@
|
||||
*/
|
||||
package org.openhab.binding.mikrotik.internal.handler;
|
||||
|
||||
import static org.openhab.core.thing.ThingStatus.OFFLINE;
|
||||
import static org.openhab.core.thing.ThingStatus.ONLINE;
|
||||
import static org.openhab.core.thing.ThingStatus.*;
|
||||
import static org.openhab.core.thing.ThingStatusDetail.GONE;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
@ -31,6 +30,7 @@ import org.openhab.binding.mikrotik.internal.model.RouterosL2TPSrvInterface;
|
||||
import org.openhab.binding.mikrotik.internal.model.RouterosLTEInterface;
|
||||
import org.openhab.binding.mikrotik.internal.model.RouterosPPPCliInterface;
|
||||
import org.openhab.binding.mikrotik.internal.model.RouterosPPPoECliInterface;
|
||||
import org.openhab.binding.mikrotik.internal.model.RouterosWifiInterface;
|
||||
import org.openhab.binding.mikrotik.internal.model.RouterosWlanInterface;
|
||||
import org.openhab.binding.mikrotik.internal.util.RateCalculator;
|
||||
import org.openhab.binding.mikrotik.internal.util.StateUtil;
|
||||
@ -184,6 +184,8 @@ public class MikrotikInterfaceThingHandler extends MikrotikBaseThingHandler<Inte
|
||||
newState = getEtherIterfaceChannelState(channelID);
|
||||
} else if (iface instanceof RouterosCapInterface) {
|
||||
newState = getCapIterfaceChannelState(channelID);
|
||||
} else if (iface instanceof RouterosWifiInterface) {
|
||||
newState = getWifiIterfaceChannelState(channelID);
|
||||
} else if (iface instanceof RouterosWlanInterface) {
|
||||
newState = getWlanIterfaceChannelState(channelID);
|
||||
} else if (iface instanceof RouterosPPPCliInterface) {
|
||||
@ -264,6 +266,26 @@ public class MikrotikInterfaceThingHandler extends MikrotikBaseThingHandler<Inte
|
||||
}
|
||||
}
|
||||
|
||||
protected State getWifiIterfaceChannelState(String channelID) {
|
||||
RouterosWifiInterface wlIface = (RouterosWifiInterface) this.iface;
|
||||
if (wlIface == null) {
|
||||
return UnDefType.UNDEF;
|
||||
}
|
||||
|
||||
switch (channelID) {
|
||||
case MikrotikBindingConstants.CHANNEL_STATE:
|
||||
return StateUtil.stringOrNull(wlIface.getCurrentState());
|
||||
case MikrotikBindingConstants.CHANNEL_RATE:
|
||||
return StateUtil.stringOrNull(wlIface.getRate());
|
||||
case MikrotikBindingConstants.CHANNEL_REGISTERED_CLIENTS:
|
||||
return StateUtil.intOrNull(wlIface.getRegisteredClients());
|
||||
case MikrotikBindingConstants.CHANNEL_AUTHORIZED_CLIENTS:
|
||||
return StateUtil.intOrNull(wlIface.getAuthorizedClients());
|
||||
default:
|
||||
return UnDefType.UNDEF;
|
||||
}
|
||||
}
|
||||
|
||||
protected State getPPPoECliChannelState(String channelID) {
|
||||
RouterosPPPoECliInterface pppCli = (RouterosPPPoECliInterface) this.iface;
|
||||
if (pppCli == null) {
|
||||
|
@ -281,6 +281,8 @@ public class MikrotikRouterosBridgeHandler extends BaseBridgeHandler {
|
||||
case MikrotikBindingConstants.CHANNEL_CPU_LOAD:
|
||||
newState = StateUtil.qtyPercentOrNull(rbRes.getCpuLoad());
|
||||
break;
|
||||
default:
|
||||
logger.warn("Unimplemented channel:{}", channelID);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ import org.openhab.binding.mikrotik.internal.model.RouterosRegistrationBase;
|
||||
import org.openhab.binding.mikrotik.internal.model.RouterosWirelessRegistration;
|
||||
import org.openhab.binding.mikrotik.internal.util.RateCalculator;
|
||||
import org.openhab.binding.mikrotik.internal.util.StateUtil;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
@ -214,11 +215,10 @@ public class MikrotikWirelessClientThingHandler extends MikrotikBaseThingHandler
|
||||
if (this.wifiReg == null) {
|
||||
return UnDefType.UNDEF;
|
||||
}
|
||||
|
||||
RouterosWirelessRegistration wirelessReg = (RouterosWirelessRegistration) this.wifiReg;
|
||||
switch (channelID) {
|
||||
case CHANNEL_SIGNAL:
|
||||
return StateUtil.intOrNull(wirelessReg.getRxSignal());
|
||||
return new DecimalType(wirelessReg.getRxSignal());
|
||||
default:
|
||||
return UnDefType.UNDEF;
|
||||
}
|
||||
|
@ -52,12 +52,13 @@ public class RouterosDevice {
|
||||
public static final String PROP_TYPE_KEY = "type";
|
||||
public static final String PROP_NAME_KEY = "name";
|
||||
public static final String PROP_SSID_KEY = "ssid";
|
||||
|
||||
public static final String PROP_CONFIG_SSID_KEY = "configuration.ssid";
|
||||
private static final String CMD_PRINT_IFACES = "/interface/print";
|
||||
private static final String CMD_PRINT_IFACE_TYPE_TPL = "/interface/%s/print";
|
||||
private static final String CMD_MONTOR_IFACE_MONITOR_TPL = "/interface/%s/monitor numbers=%s once";
|
||||
private static final String CMD_PRINT_CAPS_IFACES = "/caps-man/interface/print";
|
||||
private static final String CMD_PRINT_CAPSMAN_REGS = "/caps-man/registration-table/print";
|
||||
private static final String CMD_PRINT_WIFI_REGS = "/interface/wifi/registration-table/print";
|
||||
private static final String CMD_PRINT_WIRELESS_REGS = "/interface/wireless/registration-table/print";
|
||||
private static final String CMD_PRINT_RESOURCE = "/system/resource/print";
|
||||
private static final String CMD_PRINT_RB_INFO = "/system/routerboard/print";
|
||||
@ -85,6 +86,8 @@ public class RouterosDevice {
|
||||
return Optional.of(new RouterosCapInterface(interfaceProps));
|
||||
case WLAN:
|
||||
return Optional.of(new RouterosWlanInterface(interfaceProps));
|
||||
case WIFI:
|
||||
return Optional.of(new RouterosWifiInterface(interfaceProps));
|
||||
case PPPOE_CLIENT:
|
||||
return Optional.of(new RouterosPPPoECliInterface(interfaceProps));
|
||||
case PPP_CLIENT:
|
||||
@ -116,6 +119,9 @@ public class RouterosDevice {
|
||||
public void start() throws MikrotikApiException {
|
||||
login();
|
||||
updateRouterboardInfo();
|
||||
if (rbInfo != null) {
|
||||
logger.debug("RouterOS Version = {}", rbInfo.getFirmwareVersion());
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
@ -160,8 +166,25 @@ public class RouterosDevice {
|
||||
synchronized (this) {
|
||||
updateResources();
|
||||
updateInterfaceData();
|
||||
updateCapsmanRegistrations();
|
||||
updateWirelessRegistrations();
|
||||
try {
|
||||
updateCapsmanRegistrations();
|
||||
} catch (MikrotikApiException e) {
|
||||
logger.debug(
|
||||
"MikrotikApiException: Device may have the CAPsMAN feature for wireless management disabled.");
|
||||
}
|
||||
wirelessRegistrationCache.clear();
|
||||
try {
|
||||
updateWirelessRegistrations();
|
||||
} catch (MikrotikApiException e) {
|
||||
logger.debug(
|
||||
"MikrotikApiException: Device does not appear to have any built in CAPsMAN wireless devices.");
|
||||
}
|
||||
try {
|
||||
updateWifiRegistrations();
|
||||
} catch (MikrotikApiException e) {
|
||||
logger.debug("MikrotikApiException: Device does not appear to have any built in wifi.");
|
||||
}
|
||||
logger.trace("There are {} wirelessRegistration's registered in cache.", wirelessRegistrationCache.size());
|
||||
}
|
||||
}
|
||||
|
||||
@ -205,6 +228,7 @@ public class RouterosDevice {
|
||||
this.wlanSsid.clear();
|
||||
this.interfaceCache.clear();
|
||||
ifaceResponse.forEach(props -> {
|
||||
logger.trace("Interface Details:{}", props.toString());
|
||||
Optional<RouterosInterfaceBase> ifaceOpt = createTypedInterface(props);
|
||||
if (ifaceOpt.isPresent()) {
|
||||
RouterosInterfaceBase iface = ifaceOpt.get();
|
||||
@ -215,12 +239,14 @@ public class RouterosDevice {
|
||||
}
|
||||
});
|
||||
|
||||
// Checks if any new interfaces have been setup since last check
|
||||
Map<String, Map<String, String>> typedIfaceResponse = new HashMap<>();
|
||||
for (String ifaceApiType : interfaceTypesToPoll) {
|
||||
String cmd = String.format(CMD_PRINT_IFACE_TYPE_TPL, ifaceApiType);
|
||||
if (ifaceApiType.compareTo("cap") == 0) {
|
||||
cmd = CMD_PRINT_CAPS_IFACES;
|
||||
}
|
||||
logger.debug("Command used for updating the interfaces is:{}", cmd);
|
||||
connection.execute(cmd).forEach(propMap -> {
|
||||
String ifaceName = propMap.get(PROP_NAME_KEY);
|
||||
if (ifaceName != null) {
|
||||
@ -235,24 +261,36 @@ public class RouterosDevice {
|
||||
|
||||
for (RouterosInterfaceBase ifaceModel : interfaceCache) {
|
||||
// Enrich with detailed data
|
||||
|
||||
Map<String, String> additionalIfaceProps = typedIfaceResponse.get(ifaceModel.getName());
|
||||
if (additionalIfaceProps != null) {
|
||||
ifaceModel.mergeProps(additionalIfaceProps);
|
||||
}
|
||||
// Get monitor data
|
||||
// Get monitor data, runs if you have added an interface thing.
|
||||
if (ifaceModel.hasMonitor() && monitoredInterfaces.contains(ifaceModel.getName())) {
|
||||
String cmd = String.format(CMD_MONTOR_IFACE_MONITOR_TPL, ifaceModel.getApiType(), ifaceModel.getName());
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Getting detailed data for Interface:{}, with command:{}", ifaceModel.getName(), cmd);
|
||||
}
|
||||
List<Map<String, String>> monitorProps = connection.execute(cmd);
|
||||
ifaceModel.mergeProps(monitorProps.get(0));
|
||||
}
|
||||
// Note SSIDs for non-CAPsMAN wireless clients
|
||||
String ifaceName = ifaceModel.getName();
|
||||
String ifaceSsid = ifaceModel.getProperty(PROP_SSID_KEY);
|
||||
String ifaceSsid;
|
||||
switch (ifaceModel.getApiType()) {
|
||||
case "wifi":
|
||||
ifaceSsid = ifaceModel.getProperty(PROP_CONFIG_SSID_KEY);
|
||||
break;
|
||||
case "caps":
|
||||
case "wireless":
|
||||
default:
|
||||
ifaceSsid = ifaceModel.getProperty(PROP_SSID_KEY);
|
||||
}
|
||||
if (ifaceName != null && ifaceSsid != null && !ifaceName.isBlank() && !ifaceSsid.isBlank()) {
|
||||
this.wlanSsid.put(ifaceName, ifaceSsid);
|
||||
}
|
||||
}
|
||||
logger.debug("Found the following SSID's:{}", wlanSsid.toString());
|
||||
}
|
||||
|
||||
private void updateCapsmanRegistrations() throws MikrotikApiException {
|
||||
@ -273,7 +311,6 @@ public class RouterosDevice {
|
||||
return;
|
||||
}
|
||||
List<Map<String, String>> response = conn.execute(CMD_PRINT_WIRELESS_REGS);
|
||||
wirelessRegistrationCache.clear();
|
||||
response.forEach(props -> {
|
||||
String wlanIfaceName = props.get("interface");
|
||||
String wlanSsidName = wlanSsid.get(wlanIfaceName);
|
||||
@ -285,6 +322,23 @@ public class RouterosDevice {
|
||||
});
|
||||
}
|
||||
|
||||
private void updateWifiRegistrations() throws MikrotikApiException {
|
||||
ApiConnection conn = this.connection;
|
||||
if (conn == null) {
|
||||
return;
|
||||
}
|
||||
List<Map<String, String>> response = conn.execute(CMD_PRINT_WIFI_REGS);
|
||||
response.forEach(props -> {
|
||||
String wlanIfaceName = props.get("interface");
|
||||
String wlanSsidName = wlanSsid.get(wlanIfaceName);
|
||||
|
||||
if (wlanSsidName != null && wlanIfaceName != null && !wlanIfaceName.isBlank() && !wlanSsidName.isBlank()) {
|
||||
props.put("configuration.ssid", wlanSsidName);
|
||||
}
|
||||
wirelessRegistrationCache.add(new RouterosWirelessRegistration(props));
|
||||
});
|
||||
}
|
||||
|
||||
private void updateResources() throws MikrotikApiException {
|
||||
ApiConnection conn = this.connection;
|
||||
if (conn == null) {
|
||||
|
@ -26,9 +26,12 @@ public enum RouterosInterfaceType {
|
||||
ETHERNET("ether"),
|
||||
BRIDGE("bridge"),
|
||||
WLAN("wlan"),
|
||||
WIFI("wifi"),
|
||||
CAP("cap"),
|
||||
PPP_CLIENT("ppp-out"),
|
||||
PPPOE_CLIENT("pppoe-out"),
|
||||
VLAN("vlan"),
|
||||
VETH("veth"), // docker containers create virtual ether ports
|
||||
L2TP_SERVER("l2tp-in"),
|
||||
L2TP_CLIENT("l2tp-out"),
|
||||
LTE("lte");
|
||||
|
@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.mikrotik.internal.model;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link RouterosWifiInterface} is a model class for `wifi` interface models having casting accessors for
|
||||
* data that is specific to this network interface kind. Is a subclass of {@link RouterosInterfaceBase}.
|
||||
*
|
||||
* @author Matthew Skinner - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class RouterosWifiInterface extends RouterosWlanInterface {
|
||||
|
||||
public RouterosWifiInterface(Map<String, String> props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RouterosInterfaceType getDesignedType() {
|
||||
return RouterosInterfaceType.WIFI;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getApiType() {
|
||||
return "wifi";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRegisteredClients() {
|
||||
Integer registeredClients = getIntProp("registered-peers");
|
||||
return registeredClients == null ? 0 : registeredClients;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAuthorizedClients() {
|
||||
Integer authedClients = getIntProp("authorized-peers");
|
||||
return authedClients == null ? 0 : authedClients;
|
||||
}
|
||||
}
|
@ -27,12 +27,29 @@ import org.openhab.binding.mikrotik.internal.util.Converter;
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class RouterosWirelessRegistration extends RouterosRegistrationBase {
|
||||
|
||||
public RouterosWirelessRegistration(Map<String, String> props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
public int getRxSignal() {
|
||||
String signalValue = getProp("signal-strength", "0@hz").split("@")[0];
|
||||
String signalValue = getProp("signal", "0");
|
||||
if (signalValue.isEmpty()) {
|
||||
signalValue = getProp("signal-strength", "0@hz").split("@")[0];
|
||||
} else {
|
||||
int value = Integer.parseInt(signalValue);
|
||||
if (value < -80) {
|
||||
return 0;
|
||||
} else if (value < -75) {
|
||||
return 1;
|
||||
} else if (value < -68) {
|
||||
return 2;
|
||||
} else if (value < -55) {
|
||||
return 3;
|
||||
} else {
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
return Integer.parseInt(signalValue);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user