[asuswrt] Initial contribution (#13815)

Signed-off-by: Christian Wild <christian@wildclan.de>
This commit is contained in:
Christian Wild 2023-07-15 14:07:51 +02:00 committed by GitHub
parent ee687aa1cd
commit d2f4e05295
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 4470 additions and 0 deletions

View File

@ -131,6 +131,11 @@
<artifactId>org.openhab.binding.astro</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.asuswrt</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.atlona</artifactId>

View File

@ -0,0 +1,13 @@
This content is produced and maintained by the openHAB project.
* Project home: https://www.openhab.org
== Declared Project Licenses
This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.
== Source Code
https://github.com/openhab/openhab-addons

View File

@ -0,0 +1,91 @@
# Asuswrt Binding
This binding adds support to read information from ASUS-Routers (Copyright © ASUS).
## Supported Things
This binding supports ASUS routers with Asuswrt or [Asuswrt-Merlin](https://www.asuswrt-merlin.net/) firmware.
Firmware 5.x.x (some DSL models) is NOT supported (not Asuswrt).
| ThingType | Name | Descripion |
|---------------|------------|--------------------------------------|
| bridge | router | Router to which the binding connects |
| - | interface | Network interface of the router |
| - | client | Client is connected to the bridge |
### `router` Thing Configuration
| Name | Type | Description | Default | Required | Advanced |
|-----------------|---------|---------------------------------------|---------------------|----------|----------|
| hostname | text | Hostname or IP address of the device | router.asus.com | yes | no |
| username | text | Username to access the device | N/A | yes | no |
| password | text | Password to access the device | N/A | yes | no |
| useSSL | boolean | Connect over SSL or use http:// | false | no | no |
| refreshInterval | integer | Interval the device is polled in sec. | 20 | no | yes |
| httpPort | integer | HTTP-Port | 80 | no | yes |
| httpsPort | integer | HTTPS-Port | 443 | no | yes |
### `interface` Thing Configuration
| Name | Type | Description | Default | Required | Advanced |
|-----------------|---------|---------------------------------------|---------------------|----------|----------|
| interfaceName | text | options name of interface (wan/lan) | N/A | yes | no |
### `client` Thing Configuration
| Name | Type | Description | Default | Required | Advanced |
|-----------------|---------|---------------------------------------|---------------------|----------|----------|
| macAddress | text | Unique MAC address of the device | N/A | yes | no |
| clientNick | text | Nickname used by OH | N/A | no | no |
## Properties
All devices support some of the following properties:
| property | description | things supporting this channel |
|------------------|------------------------------|---------------------------------------|
| vendor | Vendor of device | router, client |
| dnsName | DNS name of device | router, client |
## Channels
All devices support some of the following channels:
| group | channel |type | description | things supporting this channel |
|------------------|----------------------|------------------------|--------------------------------------------|-----------------------------------|
| network-info | mac-address | text (RO) | HW address | interface, client |
| | ip-address | text (RO) | IP address | interface |
| | ip-method | text (RO) | IP method (static/dhcp) | interface, client |
| | subnet | text (RO) | Subnetmask | interface |
| | gateway | text (RO) | Default gateway | interface |
| | dns-servers | text (RO) | DNS servers | interface |
| | network-state | Switch (RO) | Client is online | interface, client |
| | internet-state | Switch (RO) | Client connected to Internet | client |
| sys-info | mem-total | Number:DataAmountype | Total memory in MB | router |
| | mem-used | Number:DataAmountype | Used memory in MB | router |
| | mem-free | Number:DataAmountype | Free memory in MB | router |
| | mem-used-percent | Number:Dimensionles | Used memory in % | router |
| | cpu-used-percent | Number:Dimensionles | Total CPU usage in percent over all cores | router |
| client-list | known-clients | text (RO) | Known clients with name and MAC addresses | router |
| | online-clients | text (RO) | Online clients with name and MAC addresses | router |
| | online-macs | text (RO) | List with MAC addresses of online clients | router |
| | online-clients-count | Number:Dimensionless | Count of online clients | router |
| traffic | current-rx | Number:DataTransferRate| Current DataTransferRate MBits/s (receive) | interface, client |
| | current-tx | Number:DataTransferRate| Current DataTransferRate MBits/s (send) | interface, client |
| | today-rx | Number:DataAmount | Data received since 0:00 a clock in MB | interface, client |
| | today-tx | Number:DataAmount | Data sent since 0:00 a clock in MB | interface, client |
| | total-rx | Number:DataAmount | Data received since reboot in MB | interface, client |
| | total-tx | Number:DataAmount | Data sent since reboot in MB | interface, client |
## Events
All devices support some of the following Events:
| group | event |kind | description | things supporting this event |
|------------------|---------------------|------------|------------------------------------------------------------------------|---------------------------------|
| network-info | connection-event | Trigger | Fired if connection is established ('connected') or ('disconnected') | interface |
| | client-online-event | Trigger | Fired if client leaves ('gone') or enters ('connected') the network | client |
| client-list | client-online-event | Trigger | Fired if client leaves ('gone') or enters ('connected') the network | router |

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
<version>4.0.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.binding.asuswrt</artifactId>
<name>openHAB Add-ons :: Bundles :: Asuswrt Binding</name>
</project>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.asuswrt-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
<feature name="openhab-binding-asuswrt" description="Asuswrt Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.asuswrt/${project.version}</bundle>
</feature>
</features>

View File

@ -0,0 +1,212 @@
/**
* Copyright (c) 2010-2023 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.asuswrt.internal;
import static org.openhab.binding.asuswrt.internal.constants.AsuswrtBindingConstants.*;
import static org.openhab.binding.asuswrt.internal.constants.AsuswrtBindingSettings.*;
import static org.openhab.binding.asuswrt.internal.helpers.AsuswrtUtils.*;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.asuswrt.internal.structures.AsuswrtClientInfo;
import org.openhab.binding.asuswrt.internal.structures.AsuswrtClientList;
import org.openhab.binding.asuswrt.internal.structures.AsuswrtInterfaceList;
import org.openhab.binding.asuswrt.internal.structures.AsuswrtIpInfo;
import org.openhab.binding.asuswrt.internal.things.AsuswrtRouter;
import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link AsuswrtDiscoveryService} is responsible for discovering clients.
*
* @author Christian Wild - Initial contribution
*/
@NonNullByDefault
public class AsuswrtDiscoveryService extends AbstractDiscoveryService implements ThingHandlerService {
private final Logger logger = LoggerFactory.getLogger(AsuswrtDiscoveryService.class);
private String uid = "";
protected @NonNullByDefault({}) AsuswrtRouter router;
public AsuswrtDiscoveryService() {
super(SUPPORTED_THING_TYPES_UIDS, DISCOVERY_TIMEOUT_S, false);
}
@Override
public void activate() {
}
@Override
public void deactivate() {
super.deactivate();
removeAllResults();
}
@Override
public void setThingHandler(@Nullable ThingHandler handler) {
if (handler instanceof AsuswrtRouter router) {
router.setDiscoveryService(this);
this.router = router;
this.uid = router.getUID().getAsString();
}
}
@Override
public @Nullable ThingHandler getThingHandler() {
return this.router;
}
/*
* Scan handling
*/
/**
* Starts a manual scan.
*/
@Override
public void startScan() {
logger.trace("{} starting scan", uid);
if (router != null) {
/* query Data */
router.queryDeviceData(false);
/* discover interfaces */
AsuswrtInterfaceList ifList = router.getInterfaces();
handleInterfaceScan(ifList);
/* discover clients */
AsuswrtClientList clientList = router.getClients();
handleClientScan(clientList);
}
}
@Override
public void stopScan() {
super.stopScan();
removeOlderResults(getTimestampOfLastScan());
}
/**
* Removes all scan results.
*/
private void removeAllResults() {
removeOlderResults(new Date().getTime());
}
/**
* Creates {@link DiscoveryResult}s from the provided {@link AsuswrtInterfaceList}.
*/
private void handleInterfaceScan(AsuswrtInterfaceList ifList) {
try {
for (AsuswrtIpInfo ifInfo : ifList) {
DiscoveryResult discoveryResult = createInterfaceResult(ifInfo);
thingDiscovered(discoveryResult);
}
} catch (Exception e) {
logger.debug("Error while handling interface scan reults", e);
}
}
/**
* Creates {@link DiscoveryResult}s from the provided {@link AsuswrtClientList}.
*/
public void handleClientScan(AsuswrtClientList clientList) {
try {
for (AsuswrtClientInfo client : clientList) {
DiscoveryResult discoveryResult = createClientResult(client);
thingDiscovered(discoveryResult);
}
} catch (Exception e) {
logger.debug("Error while handling client scan results", e);
}
}
/*
* Discovery result creation
*/
/**
* Creates a {@link DiscoveryResult} from the provided {@link AsuswrtIpInfo}.
*/
private DiscoveryResult createInterfaceResult(AsuswrtIpInfo interfaceInfo) {
String ifName = interfaceInfo.getName();
String macAddress = interfaceInfo.getMAC();
String label = "AwrtInterface_" + ifName;
Map<String, Object> properties = new HashMap<>();
properties.put(NETWORK_REPRESENTATION_PROPERTY, ifName);
properties.put(Thing.PROPERTY_MAC_ADDRESS, macAddress);
logger.debug("{} thing discovered: '{}", uid, label);
if (this.router != null) {
ThingUID bridgeUID = router.getUID();
ThingUID thingUID = new ThingUID(THING_TYPE_INTERFACE, bridgeUID, ifName);
return DiscoveryResultBuilder.create(thingUID).withProperties(properties)
.withRepresentationProperty(NETWORK_REPRESENTATION_PROPERTY).withBridge(bridgeUID).withLabel(label)
.build();
} else {
ThingUID thingUID = new ThingUID(BINDING_ID, ifName);
return DiscoveryResultBuilder.create(thingUID).withProperties(properties)
.withRepresentationProperty(NETWORK_REPRESENTATION_PROPERTY).withLabel(label).build();
}
}
/**
* Creates a {@link DiscoveryResult} from the provided {@link AsuswrtClientInfo}.
*/
private DiscoveryResult createClientResult(AsuswrtClientInfo clientInfo) {
String macAddress = clientInfo.getMac();
String unformatedMac = unformatMac(macAddress);
String clientName;
String nickName;
String label = "AwrtClient_";
// Create label and thing names
clientName = stringOrDefault(clientInfo.getName(), "client_" + unformatedMac);
nickName = stringOrDefault(clientInfo.getNickName(), clientName);
if (nickName.equals(clientName)) {
label += nickName;
} else {
label += nickName + " (" + clientName + ")";
}
// Create properties
Map<String, Object> properties = new HashMap<>();
properties.put(Thing.PROPERTY_MAC_ADDRESS, macAddress);
properties.put(Thing.PROPERTY_VENDOR, clientInfo.getVendor());
properties.put(PROPERTY_CLIENT_NAME, clientName);
properties.put(CHANNEL_CLIENT_NICKNAME, nickName);
logger.debug("{} thing discovered: '{}", uid, label);
if (this.router != null) {
ThingUID bridgeUID = router.getUID();
ThingUID thingUID = new ThingUID(THING_TYPE_CLIENT, bridgeUID, unformatedMac);
return DiscoveryResultBuilder.create(thingUID).withProperties(properties)
.withRepresentationProperty(CLIENT_REPRESENTATION_PROPERTY).withTTL(DISCOVERY_AUTOREMOVE_S)
.withBridge(bridgeUID).withLabel(label).build();
} else {
ThingUID thingUID = new ThingUID(BINDING_ID, unformatedMac);
return DiscoveryResultBuilder.create(thingUID).withProperties(properties)
.withRepresentationProperty(CLIENT_REPRESENTATION_PROPERTY).withTTL(DISCOVERY_AUTOREMOVE_S)
.withLabel(label).build();
}
}
}

View File

@ -0,0 +1,126 @@
/**
* Copyright (c) 2010-2023 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.asuswrt.internal;
import static org.openhab.binding.asuswrt.internal.constants.AsuswrtBindingConstants.*;
import static org.openhab.binding.asuswrt.internal.constants.AsuswrtBindingSettings.*;
import static org.openhab.binding.asuswrt.internal.constants.AsuswrtErrorConstants.*;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.openhab.binding.asuswrt.internal.things.AsuswrtClient;
import org.openhab.binding.asuswrt.internal.things.AsuswrtInterface;
import org.openhab.binding.asuswrt.internal.things.AsuswrtRouter;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link AsuswrtHandlerFactory} is responsible for creating things and thing handlers.
*
* @author Christian Wild - Initial contribution
*/
@NonNullByDefault
@Component(configurationPid = "binding.asuswrt", service = ThingHandlerFactory.class)
public class AsuswrtHandlerFactory extends BaseThingHandlerFactory {
private final Logger logger = LoggerFactory.getLogger(AsuswrtHandlerFactory.class);
private final Set<AsuswrtRouter> routerHandlers = new HashSet<>();
private final HttpClient httpClient;
public AsuswrtHandlerFactory() {
// Set SslContextfactory
SslContextFactory sslContextFactory = new SslContextFactory.Client();
if (HTTP_SSL_TRUST_ALL) {
sslContextFactory.setTrustAll(true);
sslContextFactory.setEndpointIdentificationAlgorithm(null);
}
// Create new httpClient
httpClient = new HttpClient(sslContextFactory);
httpClient.setFollowRedirects(false);
httpClient.setMaxConnectionsPerDestination(HTTP_MAX_CONNECTIONS);
httpClient.setMaxRequestsQueuedPerDestination(HTTP_MAX_QUEUED_REQUESTS);
try {
httpClient.start();
} catch (Exception e) {
logger.error(ERR_HTTP_CLIENT_FAILED);
}
}
@Deactivate
@Override
protected void deactivate(ComponentContext componentContext) {
super.deactivate(componentContext);
try {
httpClient.stop();
} catch (Exception e) {
logger.debug("Unable to stop httpClient");
}
}
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (THING_TYPE_ROUTER.equals(thingTypeUID)) {
AsuswrtRouter router = new AsuswrtRouter((Bridge) thing, this.httpClient);
routerHandlers.add(router);
return router;
} else if (THING_TYPE_CLIENT.equals(thingTypeUID)) {
AsuswrtRouter router = getRouter(thing);
if (router != null) {
return new AsuswrtClient(thing, router);
}
} else if (THING_TYPE_INTERFACE.equals(thingTypeUID)) {
AsuswrtRouter router = getRouter(thing);
if (router != null) {
return new AsuswrtInterface(thing, router);
}
}
return null;
}
/**
* Gets the {@link AsuswrtRouter} handler (Bridge) from a Thing.
*/
protected @Nullable AsuswrtRouter getRouter(Thing thing) {
ThingUID bridgeUID = thing.getBridgeUID();
if (bridgeUID != null) {
for (AsuswrtRouter router : routerHandlers) {
if (bridgeUID.equals(router.getUID())) {
return router;
}
}
}
logger.warn(ERR_BRIDGE_NOT_DECLARED);
return null;
}
}

View File

@ -0,0 +1,199 @@
/**
* Copyright (c) 2010-2023 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.asuswrt.internal.api;
import static org.openhab.binding.asuswrt.internal.constants.AsuswrtBindingSettings.*;
import static org.openhab.binding.asuswrt.internal.constants.AsuswrtErrorConstants.*;
import static org.openhab.binding.asuswrt.internal.helpers.AsuswrtUtils.getValueOrDefault;
import java.net.NoRouteToHostException;
import java.util.concurrent.TimeoutException;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLKeyException;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jetty.client.api.ContentResponse;
import org.openhab.binding.asuswrt.internal.structures.AsuswrtConfiguration;
import org.openhab.binding.asuswrt.internal.structures.AsuswrtCredentials;
import org.openhab.binding.asuswrt.internal.things.AsuswrtRouter;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonObject;
/**
* The {@link AsuswrtConnector} is a {@link AsuswrtHttpClient} that also keeps track of router configuration and
* credentials.
*
* @author Christian Wild - Initial contribution
*/
@NonNullByDefault
public class AsuswrtConnector extends AsuswrtHttpClient {
private final Logger logger = LoggerFactory.getLogger(AsuswrtConnector.class);
private AsuswrtCredentials credentials;
private AsuswrtConfiguration routerConfig;
protected Long lastQuery = 0L;
public AsuswrtConnector(AsuswrtRouter router) {
super(router);
routerConfig = router.getConfiguration();
this.credentials = new AsuswrtCredentials(routerConfig);
}
/*
* Connector commands
*/
/**
* Login to the router.
*/
public Boolean login() {
String url = getURL("login.cgi");
String encodedCredentials = credentials.getEncodedCredentials();
String payload = "";
logout(); // logout (unset cookie) first
router.errorHandler.reset();
logger.trace("({}) perform login to '{}' with '{}'", uid, url, encodedCredentials);
payload = "login_authorization=" + encodedCredentials + "}";
ContentResponse response = getSyncRequest(url, payload);
if (response != null) {
setCookieFromResponse(response);
}
if (cookieStore.isValid()) {
router.setState(ThingStatus.ONLINE);
return true;
}
return false;
}
/**
* Logout and unsets the cookie.
*/
public void logout() {
this.cookieStore.resetCookie();
}
/**
* Gets system information from the device.
*/
public void querySysInfo(boolean asyncRequest) {
queryDeviceData(CMD_GET_SYSINFO, asyncRequest);
}
/**
* Queries data from the device.
*
* @param command command constant to sent
* @param asyncRequest <code>true</code> if request should be sent asynchronous, <code>false</code> if synchronous
*/
public void queryDeviceData(String command, boolean asyncRequest) {
logger.trace("({}) queryDeviceData", uid);
Long now = System.currentTimeMillis();
router.errorHandler.reset();
if (cookieStore.cookieIsExpired()) {
login();
}
if (now > this.lastQuery + HTTP_QUERY_MIN_GAP_MS) {
String url = getURL("appGet.cgi");
String payload = "hook=" + command;
this.lastQuery = now;
// Send payload as url parameter
url = url + "?" + payload;
url = url.replace(";", "%3B");
// Send asynchronous or synchronous HTTP request
if (asyncRequest) {
sendAsyncRequest(url, payload, command);
} else {
sendSyncRequest(url, payload, command);
}
} else {
logger.trace("({}) query skipped cause of min_gap: {} <- {}", uid, now, lastQuery);
}
}
/*
* Response handling
*/
/**
* Handle successful HTTP response by delegating to the connector class.
*
* @param responseBody response body as string
* @param command command constant which was sent
*/
@Override
protected void handleHttpSuccessResponse(String responseBody, String command) {
JsonObject jsonObject = getJsonFromString(responseBody);
router.dataReceived(jsonObject, command);
}
/**
* Handles HTTP result failures.
*
* @param e Throwable exception
* @param payload full payload for debugging
*/
@Override
protected void handleHttpResultError(Throwable e, String payload) {
super.handleHttpResultError(e, payload);
String errorMessage = getValueOrDefault(e.getMessage(), "");
if (e instanceof TimeoutException || e instanceof NoRouteToHostException) {
router.errorHandler.raiseError(ERR_CONN_TIMEOUT, errorMessage);
router.setState(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, errorMessage);
} else if (e instanceof SSLException || e instanceof SSLKeyException || e instanceof SSLHandshakeException) {
router.errorHandler.raiseError(ERR_SSL_EXCEPTION, payload);
router.setState(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, errorMessage);
} else if (e instanceof InterruptedException) {
router.errorHandler.raiseError(new Exception(e), payload);
router.setState(ThingStatus.UNKNOWN, ThingStatusDetail.COMMUNICATION_ERROR, errorMessage);
} else {
router.errorHandler.raiseError(new Exception(e), errorMessage);
router.setState(ThingStatus.UNKNOWN, ThingStatusDetail.COMMUNICATION_ERROR, errorMessage);
}
}
/*
* Other
*/
/**
* Gets the target URL.
*/
protected String getURL(String site) {
String url = routerConfig.hostname;
if (routerConfig.useSSL) {
url = HTTPS_PROTOCOL + url;
if (routerConfig.httpsPort != 443) {
url = url + ":" + routerConfig.httpsPort;
}
} else {
url = HTTP_PROTOCOL + url;
if (routerConfig.httpPort != 80) {
url = url + ":" + routerConfig.httpPort;
}
}
return url + "/" + site;
}
}

View File

@ -0,0 +1,84 @@
/**
* Copyright (c) 2010-2023 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.asuswrt.internal.api;
import static org.openhab.binding.asuswrt.internal.constants.AsuswrtBindingSettings.COOKIE_LIFETIME_S;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link AsuswrtCookie} is used for storing cookie details.
*
* @author Christian Wild - Initial contribution
*/
@NonNullByDefault
public class AsuswrtCookie {
protected String cookie = "";
protected String token = "";
protected Long cookieTimeStamp = 0L;
/*
* Set and reset functions
*/
/**
* Sets a new cookie.
*/
public void setCookie(String cookie) {
this.cookie = cookie;
cookieTimeStamp = System.currentTimeMillis();
}
/**
* Resets a cookie.
*/
public void resetCookie() {
cookie = "";
token = "";
cookieTimeStamp = 0L;
}
/*
* Cookie checks
*/
/**
* Checks if a cookie is set.
*/
public boolean cookieIsSet() {
return !cookie.isBlank();
}
/**
* Checks if a cookie is expired.
*
* @return <code>true</code> if cookie is set and expired
*/
public boolean cookieIsExpired() {
return cookieTimeStamp > 0L && System.currentTimeMillis() > cookieTimeStamp + (COOKIE_LIFETIME_S * 1000);
}
/**
* Checks if a cookie is set and not expired.
*/
public boolean isValid() {
return !cookieIsExpired() && cookieIsSet();
}
/**
* Gets the cookie.
*/
public String getCookie() {
return cookie;
}
}

View File

@ -0,0 +1,249 @@
/**
* Copyright (c) 2010-2023 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.asuswrt.internal.api;
import static org.openhab.binding.asuswrt.internal.constants.AsuswrtBindingConstants.JSON_MEMBER_TOKEN;
import static org.openhab.binding.asuswrt.internal.constants.AsuswrtBindingSettings.*;
import static org.openhab.binding.asuswrt.internal.constants.AsuswrtErrorConstants.*;
import static org.openhab.binding.asuswrt.internal.helpers.AsuswrtUtils.getValueOrDefault;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpResponse;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Result;
import org.eclipse.jetty.client.util.BufferingResponseListener;
import org.eclipse.jetty.client.util.StringContentProvider;
import org.eclipse.jetty.http.HttpMethod;
import org.openhab.binding.asuswrt.internal.helpers.AsuswrtUtils;
import org.openhab.binding.asuswrt.internal.things.AsuswrtRouter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
/**
* The {@link AsuswrtHttpClient} is used for (a)synchronous HTTP requests.
*
* @author Christian Wild - Initial contribution
*/
@NonNullByDefault
public class AsuswrtHttpClient {
private final Logger logger = LoggerFactory.getLogger(AsuswrtHttpClient.class);
private Gson gson = new Gson();
protected AsuswrtRouter router;
protected final String uid;
public AsuswrtCookie cookieStore = new AsuswrtCookie();
public AsuswrtHttpClient(AsuswrtRouter router) {
this.router = router;
uid = router.getUID().toString();
}
/*
* HTTP actions
*/
/**
* Sends a synchronous HTTP request.
*
* The result will be handled in {@link #handleHttpSuccessResponse(String, String) or
* {@link #handleHttpResultError(Throwable)}.
*
* If the response should be returned use {@link #getSyncRequest(String, String)} instead.
*
* @param url the URL the request is sent to
* @param payload the payload to send
* @param command the command to perform
*/
protected void sendSyncRequest(String url, String payload, String command) {
ContentResponse response = getSyncRequest(url, payload);
if (response != null) {
handleHttpSuccessResponse(response.getContentAsString(), command);
}
}
/**
* Sends a synchronous HTTP request.
*
* @param url the URL the request is sent to
* @param payload the payload to send
* @return {@link ContentResponse} of the request
*/
protected @Nullable ContentResponse getSyncRequest(String url, String payload) {
logger.trace("({}) sendRequest '{}' to '{}' with cookie '{}'", uid, payload, url, cookieStore.getCookie());
Request httpRequest = this.router.getHttpClient().newRequest(url).method(HttpMethod.POST.toString());
// Set header
httpRequest = setHeaders(httpRequest);
httpRequest.timeout(HTTP_TIMEOUT_MS, TimeUnit.MILLISECONDS);
// Add request body
httpRequest.content(new StringContentProvider(payload, HTTP_CONTENT_CHARSET), HTTP_CONTENT_TYPE);
try {
return httpRequest.send();
} catch (Exception e) {
handleHttpResultError(e);
}
return null;
}
/**
* Sends an asynchronous HTTP request so it does not wait for an answer.
*
* The result will be handled in {@link #handleHttpSuccessResponse(String, String) or
* {@link #handleHttpResultError(Throwable)}.
*
* @param url the URL to which the request is sent to
* @param payload the payload data
* @param command command to execute, this will handle ResponseType
*/
protected void sendAsyncRequest(String url, String payload, String command) {
logger.trace("({}) sendAsyncRequest to '{}' with cookie '{}'", uid, url, cookieStore.getCookie());
try {
Request httpRequest = router.getHttpClient().newRequest(url).method(HttpMethod.POST.toString());
// Set header
httpRequest = setHeaders(httpRequest);
// Add request body
httpRequest.content(new StringContentProvider(payload, HTTP_CONTENT_CHARSET), HTTP_CONTENT_TYPE);
httpRequest.timeout(HTTP_TIMEOUT_MS, TimeUnit.MILLISECONDS).send(new BufferingResponseListener() {
@NonNullByDefault({})
@Override
public void onComplete(Result result) {
final HttpResponse response = (HttpResponse) result.getResponse();
if (result.getFailure() != null) {
// Handle result errors
handleHttpResultError(result.getFailure());
} else if (response.getStatus() != 200) {
logger.debug("({}) sendAsyncRequest response error '{}'", uid, response.getStatus());
router.errorHandler.raiseError(ERR_RESPONSE, getContentAsString());
} else {
// Request successful
String rBody = getContentAsString();
logger.trace("({}) requestCompleted '{}'", uid, rBody);
// Handle result
handleHttpSuccessResponse(rBody, command);
}
}
});
} catch (Exception e) {
router.errorHandler.raiseError(e);
}
}
/**
* Sets HTTP headers.
*/
private Request setHeaders(Request httpRequest) {
// Set header
httpRequest.header("content-type", HTTP_CONTENT_TYPE);
httpRequest.header("user-agent", HTTP_USER_AGENT);
if (cookieStore.isValid()) {
httpRequest.header("cookie", cookieStore.getCookie());
}
return httpRequest;
}
/*
* Response handling
*/
/**
* Handles HTTP result failures.
*
* @param e the exception
* @param payload full payload for debugging
*/
protected void handleHttpResultError(Throwable e, String payload) {
String errorMessage = getValueOrDefault(e.getMessage(), "");
if (e instanceof TimeoutException) {
logger.debug("({}) sendAsyncRequest timeout'{}'", uid, errorMessage);
} else if (e instanceof InterruptedException) {
logger.debug("({}) sending request interrupted: {}", uid, e.toString());
} else {
logger.debug("({}) sendAsyncRequest failed'{}'", uid, errorMessage);
}
}
protected void handleHttpResultError(Throwable e) {
handleHttpResultError(e, "");
}
/**
* Handles a successful HTTP response.
*
* @param responseBody response body as string
* @param command command constant which was sent
*/
protected void handleHttpSuccessResponse(String responseBody, String command) {
}
/**
* Sets a cookie from a response.
*/
protected void setCookieFromResponse(ContentResponse response) {
cookieStore.resetCookie();
if (response.getStatus() == 200) {
String rBody = response.getContentAsString();
logger.trace("({}) received response '{}'", uid, rBody);
try {
/* get json object 'asus_token' */
JsonObject jsonObject = gson.fromJson(rBody, JsonObject.class);
if (jsonObject != null && jsonObject.has(JSON_MEMBER_TOKEN)) {
String token = jsonObject.get(JSON_MEMBER_TOKEN).getAsString();
this.cookieStore.setCookie("asus_token=" + token);
}
} catch (Exception e) {
logger.debug("({}) {} on login request '{}'", uid, ERR_RESPONSE, e.getMessage());
router.errorHandler.raiseError(ERR_RESPONSE, e.getMessage());
}
} else {
String reason = AsuswrtUtils.getValueOrDefault(response.getReason(), "");
router.errorHandler.raiseError(ERR_RESPONSE, reason);
}
}
/**
* Gets JSON from a response.
*/
protected JsonObject getJsonFromResponse(ContentResponse response) {
return getJsonFromString(response.getContentAsString());
}
/**
* Gets JSON from a response.
*/
protected JsonObject getJsonFromString(String responseBody) {
try {
JsonObject jsonObject = gson.fromJson(responseBody, JsonObject.class);
logger.trace("({}) received result: {}", uid, responseBody);
/* get error code (0=success) */
if (jsonObject != null) {
return jsonObject;
}
} catch (Exception e) {
logger.debug("({}) {} {}", uid, ERR_JSON_FORMAT, responseBody);
router.getErrorHandler().raiseError(e);
}
return new JsonObject();
}
}

View File

@ -0,0 +1,194 @@
/**
* Copyright (c) 2010-2023 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.asuswrt.internal.constants;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link AsuswrtBindingConstants} class defines common constants, which are used across the whole binding.
*
* @author Christian Wild - Initial contribution
*/
@NonNullByDefault
public class AsuswrtBindingConstants {
public static final String BINDING_ID = "asuswrt";
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_ROUTER = new ThingTypeUID(BINDING_ID, "router");
public static final ThingTypeUID THING_TYPE_CLIENT = new ThingTypeUID(BINDING_ID, "client");
public static final ThingTypeUID THING_TYPE_INTERFACE = new ThingTypeUID(BINDING_ID, "interface");
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_ROUTER, THING_TYPE_CLIENT,
THING_TYPE_INTERFACE);
// Things with channel groups
public static final Set<ThingTypeUID> CHANNEL_GROUP_THING_SET = Collections
.unmodifiableSet(Stream.of(SUPPORTED_THING_TYPES_UIDS).flatMap(Set::stream).collect(Collectors.toSet()));
/*
* Channel lists
* Item channel names
*/
// General event constants
public static final String EVENT_STATE_CONNECTED = "connected";
public static final String EVENT_STATE_GONE = "gone";
public static final String EVENT_STATE_DISCONNECTED = "disconnected";
// Global channels
public static final String CHANNELS_ALL = "any-channel";
// Channel group system info
public static final String CHANNEL_GROUP_SYSINFO = "sys-info";
public static final String CHANNEL_MEM_FREE = "mem-free";
public static final String CHANNEL_MEM_FREE_PERCENT = "mem-free-percent";
public static final String CHANNEL_MEM_TOTAL = "mem-total";
public static final String CHANNEL_MEM_USED = "mem-used";
public static final String CHANNEL_MEM_USED_PERCENT = "mem-used-percent";
public static final String CHANNEL_CPU_USED_PERCENT = "cpu-used-percent";
// Channel group interface information
public static final String CHANNEL_GROUP_NETWORK = "network-info";
public static final String CHANNEL_NETWORK_IP = "ip-address";
public static final String CHANNEL_NETWORK_MAC = "mac-address";
public static final String CHANNEL_NETWORK_MASK = "subnet";
public static final String CHANNEL_NETWORK_GATEWAY = "gateway";
public static final String CHANNEL_NETWORK_METHOD = "ip-method";
public static final String CHANNEL_NETWORK_DNS = "dns-servers";
public static final String CHANNEL_NETWORK_STATE = "network-state";
public static final String CHANNEL_NETWORK_INTERNET = "internet-state";
public static final String EVENT_CONNECTION = "connection-event";
// Channel group clientList information
public static final String CHANNEL_GROUP_CLIENTS = "client-list";
public static final String CHANNEL_CLIENTS_KNOWN = "known-clients";
public static final String CHANNEL_CLIENTS_ONLINE = "online-clients";
public static final String CHANNEL_CLIENTS_COUNT = "online-clients-count";
public static final String CHANNEL_CLIENTS_ONLINE_MAC = "online-macs";
public static final String EVENT_CLIENT_CONNECTION = "client-online-event";
// Channel group client information
public static final String CHANNEL_GROUP_CLIENT = "client";
public static final String CHANNEL_CLIENT_NICKNAME = "client-name";
// Channel group traffic
public static final String CHANNEL_GROUP_TRAFFIC = "traffic";
public static final String CHANNEL_TRAFFIC_TOTAL_RX = "total-rx";
public static final String CHANNEL_TRAFFIC_TOTAL_TX = "total-tx";
public static final String CHANNEL_TRAFFIC_TODAY_RX = "today-rx";
public static final String CHANNEL_TRAFFIC_TODAY_TX = "today-tx";
public static final String CHANNEL_TRAFFIC_CURRENT_RX = "current-rx";
public static final String CHANNEL_TRAFFIC_CURRENT_TX = "current-tx";
/*
* Properties
*/
// Interface
public static final String PROPERTY_INTERFACE_NAME = "interfaceName";
public static final String NETWORK_REPRESENTATION_PROPERTY = "interfaceName";
// client
public static final String PROPERTY_CLIENT_NAME = "dnsName";
public static final String CLIENT_REPRESENTATION_PROPERTY = "macAddress";
/*
* JSON request member names
* Member names of JSON response
*/
public static final String JSON_MEMBER_TOKEN = "asus_token";
// sysInfo
public static final String JSON_MEMBER_PRODUCTID = "productid";
public static final String JSON_MEMBER_FIRMWARE = "firmver";
public static final String JSON_MEMBER_BUILD = "buildno";
public static final String JSON_MEMBER_EXTENDNO = "extendo";
public static final String JSON_MEMBER_MAC = "lan_hwaddr";
// lanInfo
public static final String JSON_MEMBER_LAN_IP = "lan_ipaddr";
public static final String JSON_MEMBER_LAN_GATEWAY = "lan_gateway";
public static final String JSON_MEMBER_LAN_NETMASK = "lan_netmask";
public static final String JSON_MEMBER_LAN_PROTO = "lan_proto";
// wanInfo
public static final String JSON_MEMBER_WAN_IP = "wanlink-ipaddr";
public static final String JSON_MEMBER_WAN_GATEWAY = "wanlink-gateway";
public static final String JSON_MEMBER_WAN_NETMASK = "wanlink-netmask";
public static final String JSON_MEMBER_WAN_PROTO = "wanlink-type";
public static final String JSON_MEMBER_WAN_DNS_SERVER = "wanlink-dns";
public static final String JSON_MEMBER_WAN_CONNECTED = "wanlink-status";
// clientInfo
public static final String JSON_MEMBER_CLIENTS = "get_clientlist";
public static final String JSON_MEMBER_MACLIST = "maclist";
public static final String JSON_MEMBER_API_LEVEL = "ClientAPILevel";
public static final String JSON_MEMBER_CLIENT_RXCUR = "curRx";
public static final String JSON_MEMBER_CLIENT_TXCUR = "curTx";
public static final String JSON_MEMBER_CLIENT_DEFTYPE = "defaultType";
public static final String JSON_MEMBER_CLIENT_DPIDEVICE = "dpiDevice";
public static final String JSON_MEMBER_CLIENT_DPITYPE = "dpiType";
public static final String JSON_MEMBER_CLIENT_IPFROM = "from";
public static final String JSON_MEMBER_CLIENT_GROUP = "group";
public static final String JSON_MEMBER_CLIENT_INETMODE = "internetMode";
public static final String JSON_MEMBER_CLIENT_INETSTATE = "internet-state";
public static final String JSON_MEMBER_CLIENT_IP = "ip";
public static final String JSON_MEMBER_CLIENT_IPMETHOD = "ip-method";
public static final String JSON_MEMBER_CLIENT_IPGATEWAY = "isGateway";
public static final String JSON_MEMBER_CLIENT_GN = "isGN";
public static final String JSON_MEMBER_CLIENT_ITUNES = "isITunes";
public static final String JSON_MEMBER_CLIENT_LOGIN = "isLogin";
public static final String JSON_MEMBER_CLIENT_ONLINE = "isOnline";
public static final String JSON_MEMBER_CLIENT_PRINTER = "isPrinter";
public static final String JSON_MEMBER_CLIENT_WEBSRV = "isWebServer";
public static final String JSON_MEMBER_CLIENT_WIFI = "isWL";
public static final String JSON_MEMBER_CLIENT_KEEPARP = "keeparp";
public static final String JSON_MEMBER_CLIENT_MAC = "mac";
public static final String JSON_MEMBER_CLIENT_MACREPEAT = "macRepeat";
public static final String JSON_MEMBER_CLIENT_NAME = "name";
public static final String JSON_MEMBER_CLIENT_NICK = "nickName";
public static final String JSON_MEMBER_CLIENT_MODE = "opMode";
public static final String JSON_MEMBER_CLIENT_QOSLVL = "qosLevel";
public static final String JSON_MEMBER_CLIENT_ROG = "ROG";
public static final String JSON_MEMBER_CLIENT_RSSI = "rssi";
public static final String JSON_MEMBER_CLIENT_SSID = "ssid";
public static final String JSON_MEMBER_CLIENT_RXTOTAL = "totalRx";
public static final String JSON_MEMBER_CLIENT_TXTOTAL = "totalTx";
public static final String JSON_MEMBER_CLIENT_VENDOR = "vendor";
public static final String JSON_MEMBER_CLIENT_CONNECTTIME = "wlConnectTime";
public static final String JSON_MEMBER_CLIENT_WTFAST = "wtfast";
// usage
public static final String JSON_MEMBER_CPU_USAGE = "cpu_usage";
public static final String JSON_MEMBER_CPU_TOTAL = "cpu{x}_total";
public static final String JSON_MEMBER_CPU_USED = "cpu{x}_usage";
public static final String JSON_MEMBER_MEM_USAGE = "memory_usage";
public static final String JSON_MEMBER_MEM_TOTAL = "mem_total";
public static final String JSON_MEMBER_MEM_USED = "mem_used";
public static final String JSON_MEMBER_MEM_FREE = "mem_free";
public static final Integer USAGE_CPU_COUNT = 4; // max count of CPU cores
// traffic
public static final String JSON_MEMBER_TRAFFIC = "netdev";
public static final String JSON_MEMBER_INET_RX = "INTERNET_rx";
public static final String JSON_MEMBER_INET_TX = "INTERNET_tx";
public static final String JSON_MEMBER_LAN_RX = "WIRED_rx";
public static final String JSON_MEMBER_LAN_TX = "WIRED_tx";
public static final String JSON_MEMBER_WLAN_RX = "WIRELESS{}_rx";
public static final String JSON_MEMBER_WLAN_TX = "WIRELESS{}_tx";
}

View File

@ -0,0 +1,63 @@
/**
* Copyright (c) 2010-2023 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.asuswrt.internal.constants;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link AsuswrtBindingSettings} class defines common settings constants, which are used across the whole binding.
*
* @author Christian Wild - Initial contribution
*/
@NonNullByDefault
public class AsuswrtBindingSettings {
// Binding settings
public static final Integer HTTP_MAX_CONNECTIONS = 10; // setMaxConnectionsPerDestination for HTTP-Client
public static final Integer HTTP_MAX_QUEUED_REQUESTS = 10; // setMaxRequestsQueuedPerDestination for HTTP-Client
public static final Integer HTTP_TIMEOUT_MS = 5000; // http request timeout
public static final Integer HTTP_QUERY_MIN_GAP_MS = 5000; // http minimun gap between query data requests
public static final String HTTP_CONTENT_TYPE = "application/x-www-form-urlencoded";
public static final String HTTP_USER_AGENT = "asusrouter-Android-DUTUtil-1.0.0.3.58-163";
public static final String HTTP_CONTENT_CHARSET = "utf-8";
public static final String HTTP_PROTOCOL = "http://";
public static final String HTTPS_PROTOCOL = "https://";
public static final Boolean HTTP_SSL_TRUST_ALL = true; // trust all ssl-certs
public static final Integer COOKIE_LIFETIME_S = 3600; // lifetime of login-cookie
public static final Integer POLLING_INTERVAL_S_MIN = 5; // minimum polling interval
public static final Integer POLLING_INTERVAL_S_DEFAULT = 20; // default polling interval
public static final Integer RECONNECT_INTERVAL_S = 30; // interval trying try to reconnect to router
public static final Integer DISCOVERY_TIMEOUT_S = 10; // discovery service timeout in s
public static final Integer DISCOVERY_AUTOREMOVE_S = 1800; // discovery service remove things after x seconds
// List of device commands
public static final String CMD_GET_SYSINFO = "nvram_get(productid);nvram_get(firmver);nvram_get(buildno);nvram_get(extendno);nvram_get(lan_hwaddr);";
public static final String CMD_GET_LANINFO = "nvram_get(lan_hwaddr);nvram_get(lan_ipaddr);nvram_get(lan_proto);nvram_get(lan_netmask);nvram_get(lan_gateway);";
public static final String CMD_GET_WANINFO = "wanlink(status);wanlink(type);wanlink(ipaddr);wanlink(netmask);wanlink(gateway);wanlink(dns);wanlink(lease);wanlink(expires);";
public static final String CMD_GET_CLIENTLIST = "get_clientlist();";
public static final String CMD_GET_TRAFFIC = "netdev(appobj);";
public static final String CMD_GET_UPTIME = "uptime();";
public static final String CMD_GET_USAGE = "cpu_usage(appobj);memory_usage(appobj);";
public static final String CMD_GET_MEMUSAGE = "memory_usage(appobj);";
public static final String CMD_GET_CPUUSAGE = "cpu_usage(appobj);";
// List of interfaces
public static final String INTERFACE_WAN = "wan";
public static final String INTERFACE_LAN = "lan";
public static final String INTERFACE_WLAN = "wlan";
public static final String INTERFACE_CLIENT = "client";
public static final Set<String> INTERFACE_LIST = Set.of(INTERFACE_WAN, INTERFACE_LAN);
}

View File

@ -0,0 +1,34 @@
/**
* Copyright (c) 2010-2023 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.asuswrt.internal.constants;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link AsuswrtErrorConstants} class defines error constants, which are used across the whole binding.
*
* @author Christian Wild - Initial contribution
*/
@NonNullByDefault
public class AsuswrtErrorConstants {
public static final String ERR_HTTP_CLIENT_FAILED = "Starting 'httpClient' failed";
public static final String ERR_CONN_TIMEOUT = "Connection timeout";
public static final String ERR_RESPONSE = "Response not okay";
public static final String ERR_JSON_FORMAT = "Unexpected or malfomrated JSON response";
public static final String ERR_JSON_UNKNOWN_MEMBER = "JSON member not found";
public static final String ERR_SSL_EXCEPTION = "SSL Exception";
public static final String ERR_INVALID_MAC_ADDRESS = "Invalid MAC address";
public static final String ERR_BRIDGE_OFFLINE = "Bridge is offline";
public static final String ERR_BRIDGE_NOT_DECLARED = "Bridge not found or not declared";
}

View File

@ -0,0 +1,95 @@
/**
* Copyright (c) 2010-2023 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.asuswrt.internal.helpers;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* This class is used for handling errors.
*
* @author Christian Wild - Initial contribution
*/
@NonNullByDefault
public class AsuswrtErrorHandler {
private String errorMessage = "";
private String infoMessage = "";
public AsuswrtErrorHandler() {
}
public AsuswrtErrorHandler(Exception ex) {
raiseError(ex);
}
/*
* Public functions
*/
/**
* Raises a new error.
*
* @param exception the exception
*/
public void raiseError(Exception ex) {
raiseError(ex, "");
}
/**
* Raises a new error.
*
* @param exception the exception
* @param infoMessage optional info message
*/
public void raiseError(Exception ex, @Nullable String infoMessage) {
this.errorMessage = AsuswrtUtils.getValueOrDefault(ex.getMessage(), "");
this.infoMessage = AsuswrtUtils.getValueOrDefault(infoMessage, "");
}
/**
* Raises a new error.
*
* @param errorMessage the error message
* @param infoMessage optional info message
*/
public void raiseError(String errorMessage, @Nullable String infoMessage) {
this.errorMessage = errorMessage;
this.infoMessage = AsuswrtUtils.getValueOrDefault(infoMessage, "");
}
/**
* Resets the error.
*/
public void reset() {
errorMessage = "";
infoMessage = "";
}
/*
* Getters
*/
/**
* Get the error message.
*/
public String getErrorMessage() {
return errorMessage;
}
/**
* Get the info message.
*/
public String getInfoMessage() {
return infoMessage;
}
}

View File

@ -0,0 +1,414 @@
/**
* Copyright (c) 2010-2023 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.asuswrt.internal.helpers;
import java.util.regex.Pattern;
import javax.measure.Unit;
import javax.measure.quantity.Energy;
import javax.measure.quantity.Power;
import javax.measure.quantity.Time;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.HSBType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.types.State;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
/**
* The {@link AsuswrtUtils} contains utility helper functions.
*
* @author Christian Wild - Initial Initial contribution
*/
@NonNullByDefault
public class AsuswrtUtils {
private static final Pattern PATTERN_MAC_PAIRS = Pattern.compile("^([a-fA-F0-9]{2}[:\\.-]?){5}[a-fA-F0-9]{2}$");
private static final Pattern PATTERN_MAC_TRIPLES = Pattern.compile("^([a-fA-F0-9]{3}[:\\.-]?){3}[a-fA-F0-9]{3}$");
/*
* Calculation utility methods
*/
/**
* Limits a value between limits.
*
* @param value the value that should be limited
* @param lowerLimit will be returned if value is below
* @param upperLimit will be returned if value is higher
*/
public static int limitVal(@Nullable Integer value, int lowerLimit, int upperLimit) {
if (value == null || value < lowerLimit) {
return lowerLimit;
} else if (value > upperLimit) {
return upperLimit;
}
return value;
}
/*
* Formatting utility methods
*/
/**
* Returns a value or default value when the value is <code>null</code>.
*
* @param <T> Type of value
* @param value the value which should be checked
* @param defaultValue the default value that will be returned when <code>value</code> is <code>null</code>
*/
public static <T> T getValueOrDefault(@Nullable T value, T defaultValue) {
return value == null ? defaultValue : value;
}
/**
* Formats a MAC address by replacing old separator characters and adding new ones.
*
* @param mac unformatted MAC address
* @param newSeparatorChar new separator characters (e.g. ":","-" )
*/
public static String formatMac(String mac, char newSeparatorChar) {
String unformatedMac = unformatMac(mac);
String formatedMac = "";
try {
formatedMac = unformatedMac.replaceAll("(.{2})", "$1" + newSeparatorChar).substring(0, 17);
return formatedMac;
} catch (Exception e) {
return mac;
}
}
/**
* Unformats a MAC address. Removes all separator characters.
*/
public static String unformatMac(String rawMac) {
String mac = rawMac;
mac = mac.replace("-", "");
mac = mac.replace(":", "");
mac = mac.replace(".", "");
mac = mac.replace(" ", "");
return mac;
}
/**
* Checks if a MAC address is valid.
*/
public static boolean isValidMacAddress(String mac) {
// MAC-Addresses usually are 6 * 2 hex nibbles separated by colons,
// but apparently it is legal to have 4 * 3 hex nibbles as well,
// and the separators can be any of : or - or . or nothing.
return (PATTERN_MAC_PAIRS.matcher(mac).find() || PATTERN_MAC_TRIPLES.matcher(mac).find());
}
/**
* Converts a hexadecimal String to a byte array.
*/
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
try {
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16));
}
} catch (Exception e) {
}
return data;
}
/**
* Converts a {@link String} to a <code>boolean</code>.
*
* @param s the string to be converted ('0', '1', '-1', 'true', 'false')
* @param defVal default value if no match was found
*/
public static boolean stringToBool(@Nullable String s, boolean defVal) {
if (s == null) {
return defVal;
} else if ("1".equals(s) || "-1".equals(s)) {
return true;
} else if ("0".equals(s)) {
return false;
} else {
try {
return Boolean.parseBoolean(s);
} catch (Exception e) {
return defVal;
}
}
}
/**
* Converts a {@link String} to an <code>int</code>.
*
* @param s the string to be converted
* @param defVal the default value if the string is not a number
*/
public static int stringToInteger(@Nullable String s, int defVal) {
if (s == null) {
return defVal;
}
try {
return Integer.parseInt(s);
} catch (Exception e) {
return defVal;
}
}
/**
* Returns the provided string if it is not <code>null</code>, empty or blank. Otherwise the default value is
* returned.
*
* @param s the string to check
* @param defVal the default value
* @return the string or the default value
*/
public static String stringOrDefault(@Nullable String s, String defVal) {
if (s == null || s.isEmpty() || s.isBlank()) {
return defVal;
}
return s;
}
/*
* JSON formatting
*/
/**
* Checks if a String is valid JSON.
*/
public static boolean isValidJson(String json) {
try {
Gson gson = new Gson();
JsonObject jsnObject = gson.fromJson(json, JsonObject.class);
return jsnObject != null;
} catch (Exception e) {
return false;
}
}
/**
* Gets a {@link String} value from a {@link JsonObject}.
*
* @param jsonObject the object that will be searched for the key
* @param name the name of the key containing the value
* @param defVal the default value if the key does not exist
*/
public static String jsonObjectToString(@Nullable JsonObject jsonObject, String name, String defVal) {
if (jsonObject != null && jsonObject.has(name)) {
return jsonObject.get(name).getAsString();
} else {
return defVal;
}
}
/**
* Gets a {@link String} value from a {@link JsonObject} using an empty String as default value.
*
* @param jsonObject the object that will be searched for the key
* @param name the name of the key containing the value
*/
public static String jsonObjectToString(@Nullable JsonObject jsonObject, String name) {
return jsonObjectToString(jsonObject, name, "");
}
/**
* Gets a <code>boolean</code> value from a {@link JsonObject}.
*
* @param jsonObject the object that will be searched for the key
* @param name the name of the key containing the value
* @param defVal the default value if the key does not exist
*/
public static boolean jsonObjectToBool(@Nullable JsonObject jsonObject, String name, boolean defVal) {
if (jsonObject != null && jsonObject.has(name)) {
JsonPrimitive o = jsonObject.getAsJsonPrimitive(name);
if (o.isBoolean()) {
return jsonObject.get(name).getAsBoolean();
} else if (o.isNumber()) {
Integer iVal = jsonObject.get(name).getAsInt();
return (iVal.equals(1) || iVal.equals(-1));
} else if (o.isString()) {
String val = jsonObject.get(name).getAsString();
return stringToBool(val, defVal);
}
}
return defVal;
}
/**
* Gets a <code>boolean</code> value from a {@link JsonObject} using <code>false</code> as default value.
*
* @param jsonObject the object that will be searched for the key
* @param name the name of the key containing the value
*/
public static boolean jsonObjectToBool(@Nullable JsonObject jsonObject, String name) {
return jsonObjectToBool(jsonObject, name, false);
}
/**
* Gets an <code>int</code> value from a {@link JsonObject}.
*
* @param jsonObject the object that will be searched for the key
* @param name the name of the key containing the value
* @param defVal the default value if the key does not exist
*/
public static int jsonObjectToInt(@Nullable JsonObject jsonObject, String name, int defVal) {
if (jsonObject != null && jsonObject.has(name)) {
JsonPrimitive o = jsonObject.getAsJsonPrimitive(name);
if (o.isNumber()) {
return jsonObject.get(name).getAsInt();
} else if (o.isString()) {
String val = jsonObject.get(name).getAsString();
return stringToInteger(val, defVal);
}
}
return defVal;
}
/**
* Gets an <code>int</code> value from a {@link JsonObject} using <code>0</code> as default value.
*
* @param jsonObject the object that will be searched for the key
* @param name the name of the key containing the value
*/
public static int jsonObjectToInt(@Nullable JsonObject jsonObject, String name) {
return jsonObjectToInt(jsonObject, name, 0);
}
/**
* Gets a {@link Number} value from a {@link JsonObject}.
*
* @param jsonObject the object that will be searched for the key
* @param name the name of the key containing the value
* @param defVal the default value if the key does not exist
*/
public static Number jsonObjectToNumber(@Nullable JsonObject jsonObject, String name, Number defVal) {
if (jsonObject != null && jsonObject.has(name)) {
return jsonObject.get(name).getAsNumber();
} else {
return defVal;
}
}
/**
* Gets a {@link Number} value from a {@link JsonObject} using <code>0</code> as default value.
*
* @param jsonObject the object that will be searched for the key
* @param name the name of the key containing the value
*/
public static Number jsonObjectToNumber(@Nullable JsonObject jsonObject, String name) {
return jsonObjectToNumber(jsonObject, name, 0);
}
/*
* Type utility methods
*/
/**
* Returns an {@link OnOffType} from a {@link Boolean}.
*/
public static OnOffType getOnOffType(@Nullable Boolean boolVal) {
return (boolVal != null ? boolVal ? OnOffType.ON : OnOffType.OFF : OnOffType.OFF);
}
/**
* Returns an {@link OnOffType} from an {@link Integer}.
*/
public static OnOffType getOnOffType(Integer intVal) {
return intVal == 0 ? OnOffType.OFF : OnOffType.ON;
}
/**
* Returns a {@link StringType} from a {@link String}.
*/
public static StringType getStringType(@Nullable String strVal) {
return new StringType(strVal != null ? strVal : "");
}
/**
* Returns a {@link DecimalType} from a {@link Double}.
*/
public static DecimalType getDecimalType(@Nullable Double numVal) {
return new DecimalType((numVal != null ? numVal : 0));
}
/**
* Returns a {@link DecimalType} from an {@link Integer}.
*/
public static DecimalType getDecimalType(@Nullable Integer numVal) {
return new DecimalType((numVal != null ? numVal : 0));
}
/**
* Returns a {@link DecimalType} from a {@link Long}.
*/
public static DecimalType getDecimalType(@Nullable Long numVal) {
return new DecimalType((numVal != null ? numVal : 0));
}
/**
* Returns a {@link PercentType} from an {@link Integer}.
*/
public static PercentType getPercentType(@Nullable Integer numVal) {
Integer val = limitVal(numVal, 0, 100);
return new PercentType(val);
}
/**
* Returns a {@link HSBType} from {@link Integer}s.
*
* @param hue the hue color
* @param saturation the saturation (0-100)
* @param brightness the brightness (0-100)
*/
public static HSBType getHSBType(Integer hue, Integer saturation, Integer brightness) {
DecimalType h = new DecimalType(hue);
PercentType s = new PercentType(saturation);
PercentType b = new PercentType(brightness);
return new HSBType(h, s, b);
}
/**
* Returns a {@link QuantityType} with the {@link Time} unit.
*/
public static QuantityType<Time> getTimeType(@Nullable Number numVal, Unit<Time> unit) {
return new QuantityType<>((numVal != null ? numVal : 0), unit);
}
/**
* Returns a {@link QuantityType} with the {@link Power} unit.
*/
public static QuantityType<Power> getPowerType(@Nullable Number numVal, Unit<Power> unit) {
return new QuantityType<>((numVal != null ? numVal : 0), unit);
}
/**
* Returns a {@link QuantityType} with the {@link Energy} unit.
*/
public static QuantityType<Energy> getEnergyType(@Nullable Number numVal, Unit<Energy> unit) {
return new QuantityType<>((numVal != null ? numVal : 0), unit);
}
/**
* Returns a {@link QuantityType} with the provided unit.
*/
public static State getQuantityType(@Nullable Number numVal, Unit<?> unit) {
return new QuantityType<>((numVal != null ? numVal : 0), unit);
}
}

View File

@ -0,0 +1,235 @@
/**
* Copyright (c) 2010-2023 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.asuswrt.internal.structures;
import static org.openhab.binding.asuswrt.internal.constants.AsuswrtBindingConstants.*;
import static org.openhab.binding.asuswrt.internal.constants.AsuswrtBindingSettings.INTERFACE_CLIENT;
import static org.openhab.binding.asuswrt.internal.helpers.AsuswrtUtils.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import com.google.gson.JsonObject;
/**
* The {@link AsuswrtClientInfo} class stores client data.
*
* @author Christian Wild - Initial contribution
*/
@NonNullByDefault
public class AsuswrtClientInfo {
private AsuswrtTraffic traffic = new AsuswrtTraffic();
private Integer defaultType = 0;
private String dpiDevice = "";
private String dpiType = "";
private String from = "";
private String group = "";
private String internetMode = "";
private Boolean internetState = false;
private String ip = "";
private String ipMethod = "";
private Boolean isGateway = false;
private Boolean isGN = false;
private Boolean isITunes = false;
private Boolean isLogin = false;
private Boolean isOnline = false;
private Boolean isPrinter = false;
private Boolean isWebServer = false;
private Integer isWL = 0;
private String keeparp = "";
private String mac = "";
private Boolean macRepeat = false;
private String name = "";
private String nickName = "";
private Integer opMode = 0;
private String qosLevel = "";
private Integer rog = 0;
private Integer rssi = 0;
private String ssid = "";
private String vendor = "";
private String wlConnectTime = "";
private Integer wtfast = 0;
public AsuswrtClientInfo() {
}
public AsuswrtClientInfo(JsonObject jsonObject) {
traffic = new AsuswrtTraffic(INTERFACE_CLIENT);
setData(jsonObject);
}
public void setData(JsonObject jsonObject) {
traffic.setData(jsonObject);
defaultType = jsonObjectToInt(jsonObject, JSON_MEMBER_CLIENT_DEFTYPE, defaultType);
dpiDevice = jsonObjectToString(jsonObject, JSON_MEMBER_CLIENT_DPIDEVICE, dpiDevice);
dpiType = jsonObjectToString(jsonObject, JSON_MEMBER_CLIENT_DPITYPE, dpiType);
from = jsonObjectToString(jsonObject, JSON_MEMBER_CLIENT_IPFROM, from);
group = jsonObjectToString(jsonObject, JSON_MEMBER_CLIENT_GROUP, group);
internetMode = jsonObjectToString(jsonObject, JSON_MEMBER_CLIENT_INETMODE, internetMode);
internetState = jsonObjectToBool(jsonObject, JSON_MEMBER_CLIENT_INETSTATE, internetState);
ip = jsonObjectToString(jsonObject, JSON_MEMBER_CLIENT_IP, ip);
ipMethod = jsonObjectToString(jsonObject, JSON_MEMBER_CLIENT_IPMETHOD, ipMethod);
isGateway = jsonObjectToBool(jsonObject, JSON_MEMBER_CLIENT_IPGATEWAY, isGateway);
isGN = jsonObjectToBool(jsonObject, JSON_MEMBER_CLIENT_GN, isGN);
isITunes = jsonObjectToBool(jsonObject, JSON_MEMBER_CLIENT_ITUNES, isITunes);
isLogin = jsonObjectToBool(jsonObject, JSON_MEMBER_CLIENT_LOGIN, isLogin);
isOnline = jsonObjectToBool(jsonObject, JSON_MEMBER_CLIENT_ONLINE, isOnline);
isPrinter = jsonObjectToBool(jsonObject, JSON_MEMBER_CLIENT_PRINTER, isPrinter);
isWebServer = jsonObjectToBool(jsonObject, JSON_MEMBER_CLIENT_WEBSRV, isWebServer);
isWL = jsonObjectToInt(jsonObject, JSON_MEMBER_CLIENT_WIFI, isWL);
keeparp = jsonObjectToString(jsonObject, JSON_MEMBER_CLIENT_KEEPARP, keeparp);
mac = jsonObjectToString(jsonObject, JSON_MEMBER_CLIENT_MAC, mac);
macRepeat = jsonObjectToBool(jsonObject, JSON_MEMBER_CLIENT_MACREPEAT, macRepeat);
name = jsonObjectToString(jsonObject, JSON_MEMBER_CLIENT_NAME, name);
nickName = jsonObjectToString(jsonObject, JSON_MEMBER_CLIENT_NICK, nickName);
opMode = jsonObjectToInt(jsonObject, JSON_MEMBER_CLIENT_MODE, opMode);
qosLevel = jsonObjectToString(jsonObject, JSON_MEMBER_CLIENT_QOSLVL, qosLevel);
rog = jsonObjectToInt(jsonObject, JSON_MEMBER_CLIENT_ROG, rog);
rssi = jsonObjectToInt(jsonObject, JSON_MEMBER_CLIENT_RSSI, rssi);
ssid = jsonObjectToString(jsonObject, JSON_MEMBER_CLIENT_SSID, ssid);
vendor = jsonObjectToString(jsonObject, JSON_MEMBER_CLIENT_VENDOR, vendor);
wlConnectTime = jsonObjectToString(jsonObject, JSON_MEMBER_CLIENT_CONNECTTIME, wlConnectTime);
wtfast = jsonObjectToInt(jsonObject, JSON_MEMBER_CLIENT_WTFAST, wtfast);
}
/*
* Getters
*/
public AsuswrtTraffic getTraffic() {
return traffic;
}
public Integer getDefaultType() {
return defaultType;
}
public String getDpiDevice() {
return dpiDevice;
}
public String getDpiType() {
return dpiType;
}
public String getIpFrom() {
return from;
}
public String getGroup() {
return group;
}
public String getInternetMode() {
return internetMode;
}
public Boolean getInternetState() {
return internetState;
}
public String getIP() {
return ip;
}
public String getIpMethod() {
return ipMethod;
}
public Boolean isGateway() {
return isGateway;
}
public Boolean isGN() {
return isGN;
}
public Boolean isITunes() {
return isITunes;
}
public Boolean isLogin() {
return isLogin;
}
public Boolean isOnline() {
return isOnline;
}
public Boolean isPrinter() {
return isPrinter;
}
public Boolean isWebServer() {
return isWebServer;
}
public Integer isWL() {
return isWL;
}
public Boolean isWiFiConnected() {
return isWL > 0;
}
public String getKeepArp() {
return keeparp;
}
public String getMac() {
return mac;
}
public Boolean getMacRepeat() {
return macRepeat;
}
public String getName() {
return name;
}
public String getNickName() {
return nickName;
}
public Integer getOpMode() {
return opMode;
}
public String getQosLevel() {
return qosLevel;
}
public Integer getROG() {
return rog;
}
public Integer getRSSI() {
return rssi;
}
public String getSSID() {
return ssid;
}
public String getVendor() {
return vendor;
}
public String getWlanConnectTime() {
return wlConnectTime;
}
public Integer getWtFast() {
return wtfast;
}
}

View File

@ -0,0 +1,177 @@
/**
* Copyright (c) 2010-2023 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.asuswrt.internal.structures;
import static org.openhab.binding.asuswrt.internal.constants.AsuswrtBindingConstants.*;
import static org.openhab.binding.asuswrt.internal.constants.AsuswrtErrorConstants.*;
import static org.openhab.binding.asuswrt.internal.helpers.AsuswrtUtils.isValidMacAddress;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonObject;
/**
* The {@link AsuswrtClientList} class stores a list of {@link AsuswrtClientInfo}.
*
* @author Christian Wild - Initial contribution
*/
@NonNullByDefault
public class AsuswrtClientList implements Iterable<AsuswrtClientInfo> {
private final Logger logger = LoggerFactory.getLogger(AsuswrtClientList.class);
private List<AsuswrtClientInfo> clientList = new ArrayList<>();
public AsuswrtClientList() {
}
public AsuswrtClientList(JsonObject jsonObject) {
setData(jsonObject);
}
@Override
public Iterator<AsuswrtClientInfo> iterator() {
return clientList.iterator();
}
/**
* Sets the {@link AsuswrtClientList} using a {@link JsonObject}.
*/
public void setData(JsonObject jsonObject) {
clientList.clear();
try {
JsonObject jsonList = jsonObject.getAsJsonObject(JSON_MEMBER_CLIENTS);
// Remove the member MAC list, it contains only online clients
jsonList.remove(JSON_MEMBER_MACLIST);
jsonList.remove(JSON_MEMBER_API_LEVEL);
// Iterate over the MAC addresses
jsonList.keySet().forEach(macAddress -> {
if (isValidMacAddress(macAddress)) {
AsuswrtClientInfo clientInfo = new AsuswrtClientInfo(jsonList.getAsJsonObject(macAddress));
addClient(clientInfo);
} else {
logger.trace("getClientlist: {} '{}'", ERR_INVALID_MAC_ADDRESS, macAddress);
}
});
} catch (Exception e) {
logger.debug("getClientlist: {} - {}'", ERR_JSON_FORMAT, e.getMessage());
}
}
/**
* Adds {@link AsuswrtClientInfo} to the list.
*/
private void addClient(AsuswrtClientInfo clientInfo) {
clientList.add(clientInfo);
}
/*
* Getters
*/
/**
* Gets {@link AsuswrtClientInfo} from the list for a client based on its name.
*
* @param clientName the name of the client for which the info is returned
*/
public AsuswrtClientInfo getClientByName(String clientName) {
for (AsuswrtClientInfo client : this.clientList) {
if (client.getName().equals(clientName)) {
return client;
}
}
return new AsuswrtClientInfo();
}
/**
* Gets {@link AsuswrtClientInfo} from the list for a client based on its MAC address.
*
* @param clientMAC the MAC address of the client for which the info is returned
*/
public AsuswrtClientInfo getClientByMAC(String clientMAC) {
for (AsuswrtClientInfo client : this.clientList) {
if (client.getMac().equals(clientMAC)) {
return client;
}
}
return new AsuswrtClientInfo();
}
/**
* Gets {@link AsuswrtClientInfo} from the list for a client based on its IP address.
*
* @param clientIP the IP address of the client for which the info is returned
*/
public AsuswrtClientInfo getClientByIP(String clientIP) {
for (AsuswrtClientInfo client : this.clientList) {
if (client.getIP().equals(clientIP)) {
return client;
}
}
return new AsuswrtClientInfo();
}
/*
* Returns a <code>;</code> separated list with client names and MAC addresses.
*/
public String getClientList() {
StringBuilder clients = new StringBuilder();
for (AsuswrtClientInfo client : this.clientList) {
clients.append(client.getName() + " [" + client.getMac() + "]; ");
}
return clients.toString();
}
/*
* Returns a <code>;</code> separated list with client names.
*/
public String getClientNames() {
return clientList.stream().map(AsuswrtClientInfo::getName).collect(Collectors.joining("; "));
}
/**
* Returns the number of clients in the list.
*/
public Integer getCount() {
return clientList.size();
}
/*
* Returns a <code>;</code> separated list with MAC addresses.
*/
public String getMacAddresses() {
StringBuilder clients = new StringBuilder();
for (AsuswrtClientInfo client : this.clientList) {
clients.append(client.getMac() + "; ");
}
return clients.toString();
}
/**
* Returns a {@link AsuswrtClientList} of online clients.
*/
public AsuswrtClientList getOnlineClients() {
AsuswrtClientList clients = new AsuswrtClientList();
for (AsuswrtClientInfo client : this.clientList) {
if (client.isOnline()) {
clients.addClient(client);
}
}
return clients;
}
}

View File

@ -0,0 +1,45 @@
/**
* Copyright (c) 2010-2023 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.asuswrt.internal.structures;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link AsuswrtConfiguration} class contains fields mapping thing configuration parameters.
*
* @author Christian Wild - Initial contribution
*/
@NonNullByDefault
public class AsuswrtConfiguration {
// Thing configuration properties
public static final String CONFIG_USER = "username";
public static final String CONFIG_PASS = "password";
public static final String CONFIG_HOSTNAME = "hostname";
public static final String CONFIG_UPDATE_INTERVAL = "refreshInterval";
public static final String CONFIG_SSL_AUTH = "useSSL";
public static final String CONFIG_PORT_HTTP = "httpPort";
public static final String CONFIG_PORT_HTTPS = "httpsPort";
// Thing configuration parameters
public String hostname = "";
public String username = "";
public String password = "";
public int pollingInterval = 20;
public int reconnectInterval = 60;
public int discoveryInterval = 3600;
public int httpPort = 80;
public int httpsPort = 443;
public boolean autoDiscoveryEnabled = false;
public boolean useSSL = false;
}

View File

@ -0,0 +1,81 @@
/**
* Copyright (c) 2010-2023 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.asuswrt.internal.structures;
import java.util.Base64;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* This class is used for storing Asuswrt credentials.
*
* @author Christian Wild - Initial contribution
*/
@NonNullByDefault
public class AsuswrtCredentials {
private String username = "";
private String password = "";
private String encodedCredentials = "";
public AsuswrtCredentials() {
}
public AsuswrtCredentials(AsuswrtConfiguration routerConfig) {
setCredentials(routerConfig.username, routerConfig.password);
}
public AsuswrtCredentials(String username, String password) {
setCredentials(username, password);
}
/*
* Private methods
*/
/**
* Stores the given credentials.
*/
private void setCredentials(String username, String password) {
this.username = username;
this.password = password;
encodedCredentials = b64encode(username + ":" + password);
}
/**
* Encodes a String using Base64.
*/
private String b64encode(String string) {
return Base64.getEncoder().encodeToString((string).getBytes());
}
/*
* Public methods
*/
/**
* Returns Base64 encoded credentials.
*
* @return 'username:password' as Base64 encoded string
*/
public String getEncodedCredentials() {
return encodedCredentials;
}
public String getPassword() {
return password;
}
public String getUsername() {
return username;
}
}

View File

@ -0,0 +1,121 @@
/**
* Copyright (c) 2010-2023 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.asuswrt.internal.structures;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import com.google.gson.JsonObject;
/**
* The {@link AsuswrtInterfaceList} class stores a list of {@link AsuswrtIpInfo}.
*
* @author Christian Wild - Initial contribution
*/
@NonNullByDefault
public class AsuswrtInterfaceList implements Iterable<AsuswrtIpInfo> {
private List<AsuswrtIpInfo> ipInfoList = new ArrayList<>();
public AsuswrtInterfaceList() {
}
@Override
public Iterator<AsuswrtIpInfo> iterator() {
return ipInfoList.iterator();
}
/*
* Setters
*/
/**
* Adds an {@link AsuswrtIpInfo} to the list.
*/
private void addInterface(AsuswrtIpInfo ipInfo) {
ipInfoList.add(ipInfo);
}
/**
* Sets the {@link AsuswrtInterfaceList} using a {@link JsonObject}.
*/
public void setData(String ifName, JsonObject jsonObject) {
if (hasInterface(ifName)) {
getByName(ifName).setData(jsonObject);
} else {
addInterface(new AsuswrtIpInfo(ifName, jsonObject));
}
}
/*
* Getters
*/
/**
* Gets {@link AsuswrtIpInfo} from the list for an interface based on its name.
*
* @param ifName the name of the interface for which the info is returned
*/
public AsuswrtIpInfo getByName(String ifName) {
for (AsuswrtIpInfo ipInfo : ipInfoList) {
if (ipInfo.getName().equals(ifName)) {
return ipInfo;
}
}
return new AsuswrtIpInfo();
}
/**
* Gets {@link AsuswrtIpInfo} from the list for an interface based on its MAC address.
*
* @param ipInfoMAC the MAC address of the interface for which the info is returned
*/
public AsuswrtIpInfo getByMAC(String ipInfoMAC) {
for (AsuswrtIpInfo ipInfo : ipInfoList) {
if (ipInfo.getMAC().equals(ipInfoMAC)) {
return ipInfo;
}
}
return new AsuswrtIpInfo();
}
/**
* Gets {@link AsuswrtIpInfo} from the list for an interface based on its IP address.
*
* @param ipAddress the IP address of the interface for which the info is returned
*/
public AsuswrtIpInfo getByIP(String ipAddress) {
for (AsuswrtIpInfo ipInfo : ipInfoList) {
if (ipInfo.getIpAddress().equals(ipAddress)) {
return ipInfo;
}
}
return new AsuswrtIpInfo();
}
/**
* Checks if an interface with the given name is in the list.
*
* @param ifName the name of the interface
*/
public boolean hasInterface(String ifName) {
for (AsuswrtIpInfo ipInfo : ipInfoList) {
if (ipInfo.getName().equals(ifName)) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,124 @@
/**
* Copyright (c) 2010-2023 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.asuswrt.internal.structures;
import static org.openhab.binding.asuswrt.internal.constants.AsuswrtBindingConstants.*;
import static org.openhab.binding.asuswrt.internal.constants.AsuswrtBindingSettings.*;
import static org.openhab.binding.asuswrt.internal.helpers.AsuswrtUtils.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonObject;
/**
* The {@link AsuswrtIpInfo} class stores IP data.
*
* @author Christian Wild - Initial contribution
*/
@NonNullByDefault
public class AsuswrtIpInfo {
private final Logger logger = LoggerFactory.getLogger(AsuswrtIpInfo.class);
private AsuswrtTraffic traffic = new AsuswrtTraffic();
private String ifName = "";
private String hwAddress = "";
private String ipAddress = "";
private String ipProto = "";
private String subnet = "";
private String gateway = "";
private String dnsServer = "";
private Boolean connected = false;
public AsuswrtIpInfo() {
}
/**
* Constructor.
*
* @param interfaceName name of interface
* @param jsonObject with ipInfo
*/
public AsuswrtIpInfo(String ifName, JsonObject jsonObject) {
this.ifName = ifName;
traffic = new AsuswrtTraffic(ifName);
setData(jsonObject);
}
/*
* Setters
*/
public void setData(JsonObject jsonObject) {
if (ifName.startsWith(INTERFACE_LAN)) {
logger.trace("(AsuswrtIpInfo) setData for interface {}", INTERFACE_LAN);
hwAddress = jsonObjectToString(jsonObject, JSON_MEMBER_MAC, hwAddress);
ipAddress = jsonObjectToString(jsonObject, JSON_MEMBER_LAN_IP, ipAddress);
subnet = jsonObjectToString(jsonObject, JSON_MEMBER_LAN_NETMASK, subnet);
gateway = jsonObjectToString(jsonObject, JSON_MEMBER_LAN_GATEWAY, gateway);
ipProto = jsonObjectToString(jsonObject, JSON_MEMBER_LAN_PROTO, ipProto);
} else if (ifName.startsWith(INTERFACE_WAN)) {
logger.trace("(AsuswrtIpInfo) setData for interface {}", INTERFACE_WAN);
hwAddress = jsonObjectToString(jsonObject, JSON_MEMBER_MAC, hwAddress);
ipAddress = jsonObjectToString(jsonObject, JSON_MEMBER_WAN_IP, ipAddress);
subnet = jsonObjectToString(jsonObject, JSON_MEMBER_WAN_NETMASK, subnet);
gateway = jsonObjectToString(jsonObject, JSON_MEMBER_WAN_GATEWAY, gateway);
ipProto = jsonObjectToString(jsonObject, JSON_MEMBER_WAN_PROTO, ipProto);
dnsServer = jsonObjectToString(jsonObject, JSON_MEMBER_WAN_DNS_SERVER, dnsServer);
connected = (jsonObjectToInt(jsonObject, JSON_MEMBER_WAN_CONNECTED) == 1);
}
if (jsonObject.has(JSON_MEMBER_TRAFFIC)) {
traffic.setData(jsonObject.getAsJsonObject(JSON_MEMBER_TRAFFIC));
}
}
/*
* Getters
*/
public AsuswrtTraffic getTraffic() {
return traffic;
}
public String getMAC() {
return hwAddress;
}
public String getIpAddress() {
return ipAddress;
}
public String getSubnet() {
return subnet;
}
public String getGateway() {
return gateway;
}
public String getIpProto() {
return ipProto;
}
public String getDNSNServer() {
return dnsServer;
}
public String getName() {
return ifName;
}
public Boolean isConnected() {
return connected;
}
}

View File

@ -0,0 +1,154 @@
/**
* Copyright (c) 2010-2023 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.asuswrt.internal.structures;
import static org.openhab.binding.asuswrt.internal.constants.AsuswrtBindingConstants.*;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonObject;
/**
* The {@link AsuswrtRouterInfo} class stores the router data
*
* @author Christian Wild - Initial contribution
*/
@NonNullByDefault
public class AsuswrtRouterInfo {
private final Logger logger = LoggerFactory.getLogger(AsuswrtRouterInfo.class);
private String productId = "";
private String fwVersion = "";
private String fwBuild = "";
private String macAddress = "";
private Map<String, AsuswrtUsage> usageStats = new HashMap<>();
public AsuswrtRouterInfo() {
}
public AsuswrtRouterInfo(JsonObject jsonObject) {
setSysInfo(jsonObject);
}
/*
* Setters
*/
public void setAllData(JsonObject jsonObject) {
setSysInfo(jsonObject);
setUsageStats(jsonObject);
}
public void setSysInfo(JsonObject jsonObject) {
try {
productId = jsonObject.get(JSON_MEMBER_PRODUCTID).toString();
fwVersion = jsonObject.get(JSON_MEMBER_FIRMWARE).toString();
fwBuild = jsonObject.get(JSON_MEMBER_BUILD).toString();
macAddress = jsonObject.get(JSON_MEMBER_MAC).toString();
} catch (Exception e) {
logger.trace("incomplete SysInfo");
}
}
public void setUsageStats(JsonObject jsonObject) {
JsonObject jsnMemUsage = jsonObject.getAsJsonObject(JSON_MEMBER_MEM_USAGE);
JsonObject jsnCpuUsage = jsonObject.getAsJsonObject(JSON_MEMBER_CPU_USAGE);
// Get memory usage
if (jsnMemUsage != null) {
usageStats.put(JSON_MEMBER_MEM_USAGE,
new AsuswrtUsage(jsnMemUsage, JSON_MEMBER_MEM_TOTAL, JSON_MEMBER_MEM_USED));
}
// Loop cpu usages
if (jsnCpuUsage != null) {
for (Integer i = 1; i <= USAGE_CPU_COUNT; i++) {
String member = JSON_MEMBER_CPU_USAGE + "_" + i;
String total = JSON_MEMBER_CPU_TOTAL.replace("{x}", "" + i);
String used = JSON_MEMBER_CPU_USED.replace("{x}", "" + i);
if (jsnCpuUsage.has(total) && jsnCpuUsage.has(used)) {
usageStats.put(member, new AsuswrtUsage(jsnCpuUsage, total, used));
}
}
}
}
/*
* Getters
*/
public String getProductId() {
return productId;
}
public String getFirmwareVersion() {
return fwVersion + " (" + fwBuild + ")";
}
public String getMAC() {
return macAddress;
}
public AsuswrtUsage getMemUsage() {
if (usageStats.containsKey(JSON_MEMBER_MEM_USAGE)) {
AsuswrtUsage usage = usageStats.get(JSON_MEMBER_MEM_USAGE);
if (usage != null) {
return usage;
}
}
return new AsuswrtUsage();
}
/**
* Gets the CPU usage for a core.
*
* @param coreNum the core number
* @return the {@link AsuswrtUsage} for the given core
*/
public AsuswrtUsage getCpuUsage(Integer coreNum) {
String coreKey = JSON_MEMBER_CPU_USAGE + "_" + coreNum;
if (usageStats.containsKey(coreKey)) {
AsuswrtUsage usage = usageStats.get(coreKey);
if (usage != null) {
return usage;
}
}
return new AsuswrtUsage();
}
/**
* Get CPU usage average over all cores.
*
* @return the {@link AsuswrtUsage} with CPU usage average over all cores
*/
public AsuswrtUsage getCpuAverage() {
String coreKey;
AsuswrtUsage coreStatsX;
Integer total = 0, used = 0, coreNum;
for (coreNum = 1; coreNum <= USAGE_CPU_COUNT; coreNum++) {
coreKey = JSON_MEMBER_CPU_USAGE + "_" + coreNum;
coreStatsX = usageStats.get(coreKey);
if (coreStatsX != null) {
total += coreStatsX.getTotal();
used += coreStatsX.getUsed();
}
}
if (coreNum > 1) {
total = total / coreNum - 1;
used = used / coreNum - 1;
}
return new AsuswrtUsage(total, used);
}
}

View File

@ -0,0 +1,191 @@
/**
* Copyright (c) 2010-2023 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.asuswrt.internal.structures;
import static org.openhab.binding.asuswrt.internal.constants.AsuswrtBindingConstants.*;
import static org.openhab.binding.asuswrt.internal.constants.AsuswrtBindingSettings.*;
import static org.openhab.binding.asuswrt.internal.helpers.AsuswrtUtils.*;
import java.time.LocalDate;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonObject;
/**
* The {@link AsuswrtTraffic} class handles traffic statistics
*
* @author Christian Wild - Initial contribution
*/
@NonNullByDefault
public class AsuswrtTraffic {
private final Logger logger = LoggerFactory.getLogger(AsuswrtTraffic.class);
private Double curTX = 0.0;
private Double curRX = 0.0;
private Integer totalTX = 0;
private Integer totalRX = 0;
private Integer zeroHourTX = 0;
private Integer zeroHourRX = 0;
private LocalDate zeroHourDate = LocalDate.now();
private Long lastUpdate = 0L;
private String representationProperty = "";
public AsuswrtTraffic() {
}
/**
* Constructor.
*
* @param representationProperty representationProperty of the device (i.e. interfaceName)
*/
public AsuswrtTraffic(String representationProperty) {
this.representationProperty = representationProperty.toLowerCase();
}
/**
* Constructor.
*
* @param jsonObject stores the data
* @param representationProperty representationProperty of the device (i.e. interfaceName)
*/
public AsuswrtTraffic(JsonObject jsonObject, String representationProperty) {
this.representationProperty = representationProperty;
setData(jsonObject);
}
public void setData(JsonObject jsonObject) {
Integer intRX;
Integer intTX;
if (representationProperty.startsWith(INTERFACE_LAN)) {
intRX = getTrafficFromHex(jsonObject, JSON_MEMBER_LAN_RX);
intTX = getTrafficFromHex(jsonObject, JSON_MEMBER_LAN_TX);
curRX = calculateCurrentTraffic(intRX, totalRX);
curTX = calculateCurrentTraffic(intTX, totalTX);
totalRX = getTrafficFromHex(jsonObject, JSON_MEMBER_LAN_RX);
totalTX = getTrafficFromHex(jsonObject, JSON_MEMBER_LAN_TX);
} else if (representationProperty.startsWith(INTERFACE_WAN)) {
intRX = getTrafficFromHex(jsonObject, JSON_MEMBER_INET_RX);
intTX = getTrafficFromHex(jsonObject, JSON_MEMBER_INET_TX);
curRX = calculateCurrentTraffic(intRX, totalRX);
curTX = calculateCurrentTraffic(intTX, totalTX);
totalRX = getTrafficFromHex(jsonObject, JSON_MEMBER_INET_RX);
totalTX = getTrafficFromHex(jsonObject, JSON_MEMBER_INET_TX);
} else if (representationProperty.startsWith(INTERFACE_WLAN)) {
for (int i = 0; i < 1; i++) {
intRX = getTrafficFromHex(jsonObject, JSON_MEMBER_WLAN_RX.replace("{}", Integer.toString(i)));
intTX = getTrafficFromHex(jsonObject, JSON_MEMBER_WLAN_TX.replace("{}", Integer.toString(i)));
curRX = calculateCurrentTraffic(intRX, totalRX);
curTX = calculateCurrentTraffic(intTX, totalTX);
totalRX = getTrafficFromHex(jsonObject, JSON_MEMBER_INET_RX);
totalTX = getTrafficFromHex(jsonObject, JSON_MEMBER_INET_TX);
}
} else if (INTERFACE_CLIENT.equals(representationProperty)) {
curRX = Double.valueOf(jsonObjectToInt(jsonObject, JSON_MEMBER_CLIENT_RXCUR, -1));
curTX = Double.valueOf(jsonObjectToInt(jsonObject, JSON_MEMBER_CLIENT_TXCUR, -1));
totalRX = jsonObjectToInt(jsonObject, JSON_MEMBER_CLIENT_RXTOTAL, -1);
totalTX = jsonObjectToInt(jsonObject, JSON_MEMBER_CLIENT_TXTOTAL, -1);
} else {
logger.trace("({}) can't set Trafficdata", representationProperty);
}
lastUpdate = System.currentTimeMillis();
setZeroHourTraffic(totalRX, totalTX);
}
/**
* Saves the traffic values at the start of a new day.
*/
private void setZeroHourTraffic(Integer totalRX, Integer totalTX) {
LocalDate today = LocalDate.now();
if (today.isAfter(zeroHourDate) || zeroHourRX > totalRX) {
zeroHourRX = totalRX;
zeroHourTX = totalTX;
zeroHourDate = today;
}
}
/**
* Gets the traffic as {@link Integer} value from a hexadecimal value in a {@link JsonObject}.
*
* @param jsonObject the object containing the values
* @param jsonMember the name of the key that stores the value
* @return the traffic value
*/
private Integer getTrafficFromHex(JsonObject jsonObject, String jsonMember) {
Long lngVal;
if (jsonObject.has(jsonMember)) {
String hex = jsonObjectToString(jsonObject, jsonMember);
try {
lngVal = Long.decode(hex);
lngVal = lngVal * 8 / 1024 / 1024 / 2;
return lngVal.intValue();
} catch (Exception e) {
logger.debug("({}) error calculating traffic from hex '{}'", representationProperty, hex);
}
}
return -1;
}
/**
* Calculates the traffic from the actual and old total traffic using the time span.
*
* @param actVal the actual value
* @param oldVal the old value
* @return the current traffic value
*/
private Double calculateCurrentTraffic(Integer actVal, Integer oldVal) {
if (lastUpdate > 0) {
Long timeSpan = (System.currentTimeMillis() - lastUpdate) / 1000;
Integer div = 0;
try {
if (actVal >= 0) {
div = actVal - oldVal;
return Double.valueOf(div / timeSpan.intValue());
}
} catch (Exception e) {
logger.debug("({}) error calculating traffic from timeSpan '{}/{}'", representationProperty, div,
timeSpan);
}
}
return -1.0;
}
/*
* Getters
*/
public Double getCurrentRX() {
return curRX;
}
public Double getCurrentTX() {
return curTX;
}
public Integer getTotalRX() {
return totalRX;
}
public Integer getTotalTX() {
return totalTX;
}
public Integer getTodayRX() {
return totalRX - zeroHourRX;
}
public Integer getTodayTX() {
return totalTX - zeroHourTX;
}
}

View File

@ -0,0 +1,114 @@
/**
* Copyright (c) 2010-2023 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.asuswrt.internal.structures;
import static org.openhab.binding.asuswrt.internal.helpers.AsuswrtUtils.jsonObjectToInt;
import org.eclipse.jdt.annotation.NonNullByDefault;
import com.google.gson.JsonObject;
/**
* The {@link AsuswrtUsage} class handles usage statistics
*
* @author Christian Wild - Initial contribution
*/
@NonNullByDefault
public class AsuswrtUsage {
private Integer free = 0;
private Integer used = 0;
private Integer total = 0;
public AsuswrtUsage() {
}
/**
* Constructor.
*
* @param jsonObject jsonObject data is stored
* @param totalKey name of key total available is stored
* @param usedKey name of key used is stored
*/
public AsuswrtUsage(JsonObject jsonObject, String totalKey, String usedKey) {
setData(jsonObject, totalKey, usedKey);
}
/**
* Constructor.
*
* @param totalUsage the total usage
* @param used the usage
*/
public AsuswrtUsage(Integer totalUsage, Integer used) {
setData(totalUsage, used);
}
/*
* Setters
*/
/**
* Sets the usage data from a JSON object.
*
* @param jsonObject the JSON object containing the data
* @param totalKey the key name with the 'total available' value
* @param usedKey the key name with the 'used' value
*/
public void setData(JsonObject jsonObject, String totalKey, String usedKey) {
total = jsonObjectToInt(jsonObject, totalKey, 0);
used = jsonObjectToInt(jsonObject, usedKey, 0);
free = total - used;
}
/**
* Sets usage data from integer values.
*
* @param totalUsage the total available value
* @param used the used value
*/
public void setData(Integer totalUsage, Integer used) {
total = totalUsage;
this.used = used;
free = total - used;
}
/*
* Getters
*/
public Integer getTotal() {
return total;
}
public Integer getUsed() {
return used;
}
public Integer getFree() {
return free;
}
public Integer getUsedPercent() {
if (total > 0) {
return ((used * 100) / total);
}
return 0;
}
public Integer getFreePercent() {
if (total > 0) {
return ((free * 100) / total);
}
return 0;
}
}

View File

@ -0,0 +1,196 @@
/**
* Copyright (c) 2010-2023 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.asuswrt.internal.things;
import static org.openhab.binding.asuswrt.internal.constants.AsuswrtBindingConstants.*;
import static org.openhab.binding.asuswrt.internal.helpers.AsuswrtUtils.*;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.asuswrt.internal.helpers.AsuswrtUtils;
import org.openhab.binding.asuswrt.internal.structures.AsuswrtClientInfo;
import org.openhab.binding.asuswrt.internal.structures.AsuswrtTraffic;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link AsuswrtClient} is used as {@link org.openhab.core.thing.binding.ThingHandler ThingHandler} for router
* clients.
*
* @author Christian Wild - Initial contribution
*/
@NonNullByDefault
public class AsuswrtClient extends BaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(AsuswrtClient.class);
private final AsuswrtRouter router;
private Map<String, Object> oldStates = new HashMap<>();
protected final String uid;
public AsuswrtClient(Thing thing, AsuswrtRouter router) {
super(thing);
this.router = router;
this.uid = getThing().getUID().getAsString();
}
@Override
public void initialize() {
logger.trace("({}) Initializing thing ", uid);
router.queryDeviceData(false);
refreshData();
updateStatus(ThingStatus.ONLINE);
}
/*
* Commands and events
*/
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
refreshData();
}
}
public void updateClientProperties(AsuswrtClientInfo clientInfo) {
logger.trace("({}) clientPropertiesChanged ", uid);
Map<String, String> properties = editProperties();
properties.put(Thing.PROPERTY_MAC_ADDRESS, clientInfo.getMac());
properties.put(Thing.PROPERTY_VENDOR, clientInfo.getVendor());
properties.put(PROPERTY_CLIENT_NAME, clientInfo.getName());
updateProperties(properties);
}
public void updateClientChannels(AsuswrtClientInfo clientInfo) {
updateState(getChannelID(CHANNEL_GROUP_NETWORK, CHANNEL_NETWORK_STATE), getOnOffType(clientInfo.isOnline()));
updateState(getChannelID(CHANNEL_GROUP_NETWORK, CHANNEL_NETWORK_INTERNET),
getOnOffType(clientInfo.getInternetState()));
updateState(getChannelID(CHANNEL_GROUP_NETWORK, CHANNEL_NETWORK_IP), getStringType(clientInfo.getIP()));
updateState(getChannelID(CHANNEL_GROUP_NETWORK, CHANNEL_NETWORK_METHOD),
getStringType(clientInfo.getIpMethod()));
}
private void updateTrafficChannels(AsuswrtTraffic traffic) {
updateState(getChannelID(CHANNEL_GROUP_TRAFFIC, CHANNEL_TRAFFIC_CURRENT_RX),
getQuantityType(traffic.getCurrentRX(), Units.MEGABIT_PER_SECOND));
updateState(getChannelID(CHANNEL_GROUP_TRAFFIC, CHANNEL_TRAFFIC_CURRENT_TX),
getQuantityType(traffic.getCurrentTX(), Units.MEGABIT_PER_SECOND));
updateState(getChannelID(CHANNEL_GROUP_TRAFFIC, CHANNEL_TRAFFIC_TODAY_RX),
getQuantityType(traffic.getTodayRX(), Units.MEGABYTE));
updateState(getChannelID(CHANNEL_GROUP_TRAFFIC, CHANNEL_TRAFFIC_TODAY_TX),
getQuantityType(traffic.getTodayTX(), Units.MEGABYTE));
updateState(getChannelID(CHANNEL_GROUP_TRAFFIC, CHANNEL_TRAFFIC_TOTAL_RX),
getQuantityType(traffic.getTotalRX(), Units.MEGABYTE));
updateState(getChannelID(CHANNEL_GROUP_TRAFFIC, CHANNEL_TRAFFIC_TOTAL_TX),
getQuantityType(traffic.getTotalTX(), Units.MEGABYTE));
}
/**
* Fires events on {@link AsuswrtClientInfo} changes.
*/
private void fireEvents(AsuswrtClientInfo clientInfo) {
if (checkForStateChange(CHANNEL_GROUP_NETWORK, clientInfo.isOnline())) {
if (clientInfo.isOnline()) {
triggerChannel(getChannelID(CHANNEL_GROUP_NETWORK, EVENT_CLIENT_CONNECTION), EVENT_STATE_CONNECTED);
router.fireEvent(getChannelID(CHANNEL_GROUP_CLIENTS, EVENT_CLIENT_CONNECTION), EVENT_STATE_CONNECTED);
} else {
triggerChannel(getChannelID(CHANNEL_GROUP_NETWORK, EVENT_CLIENT_CONNECTION), EVENT_STATE_GONE);
router.fireEvent(getChannelID(CHANNEL_GROUP_CLIENTS, EVENT_CLIENT_CONNECTION), EVENT_STATE_GONE);
}
}
}
private void refreshData() {
String mac = getMac();
AsuswrtClientInfo clientInfo = router.getClients().getClientByMAC(mac);
fireEvents(clientInfo);
updateClientProperties(clientInfo);
updateClientChannels(clientInfo);
updateTrafficChannels(clientInfo.getTraffic());
}
/*
* Functions
*/
/**
* Gets the MAC address of a client from properties or settings.
*/
public String getMac() {
String mac = "";
Map<String, String> properties = getThing().getProperties();
Configuration config = getThing().getConfiguration();
/* get mac from properties */
if (properties.containsKey(Thing.PROPERTY_MAC_ADDRESS)) {
mac = config.get(Thing.PROPERTY_MAC_ADDRESS).toString();
}
/* get mac from config */
if (mac.isBlank() && config.containsKey(Thing.PROPERTY_MAC_ADDRESS)) {
mac = config.get(Thing.PROPERTY_MAC_ADDRESS).toString();
}
if (mac.isBlank()) {
logger.debug("({}) cant find macAddress in properties and config", uid);
}
return AsuswrtUtils.formatMac(mac, ':');
}
/**
* Gets the channel ID including the group.
*/
protected String getChannelID(String group, String channel) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (CHANNEL_GROUP_THING_SET.contains(thingTypeUID) && group.length() > 0) {
return group + "#" + channel;
}
return channel;
}
/**
* Gets a channel name from a channel ID.
*/
protected String getChannelFromID(ChannelUID channelID) {
String channel = channelID.getIdWithoutGroup();
channel = channel.replace(CHANNEL_GROUP_CLIENT + "#", "");
return channel;
}
/**
* Checks if the state changed since the last channel update.
*
* @param stateName the name of the state (channel)
* @param comparator comparison value
* @return <code>true</code> if changed, <code>false</code> if not or no old value exists
*/
private Boolean checkForStateChange(String stateName, Object comparator) {
if (oldStates.get(stateName) == null) {
oldStates.put(stateName, comparator);
} else if (!comparator.equals(oldStates.get(stateName))) {
oldStates.put(stateName, comparator);
return true;
}
return false;
}
}

View File

@ -0,0 +1,177 @@
/**
* Copyright (c) 2010-2023 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.asuswrt.internal.things;
import static org.openhab.binding.asuswrt.internal.constants.AsuswrtBindingConstants.*;
import static org.openhab.binding.asuswrt.internal.helpers.AsuswrtUtils.*;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.asuswrt.internal.structures.AsuswrtIpInfo;
import org.openhab.binding.asuswrt.internal.structures.AsuswrtTraffic;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link AsuswrtInterface} is used as {@link org.openhab.core.thing.binding.ThingHandler ThingHandler} for router
* interfaces.
*
* @author Christian Wild - Initial contribution
*/
@NonNullByDefault
public class AsuswrtInterface extends BaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(AsuswrtInterface.class);
private final AsuswrtRouter router;
private String ifName = "";
private Map<String, Object> oldStates = new HashMap<>();
protected final String uid;
public AsuswrtInterface(Thing thing, AsuswrtRouter router) {
super(thing);
this.router = router;
this.uid = getThing().getUID().getAsString();
}
@Override
public void initialize() {
logger.trace("({}) Initializing thing ", uid);
Configuration config = getThing().getConfiguration();
if (config.containsKey(PROPERTY_INTERFACE_NAME)) {
this.ifName = config.get(PROPERTY_INTERFACE_NAME).toString();
updateProperty(NETWORK_REPRESENTATION_PROPERTY, ifName);
updateChannels();
updateStatus(ThingStatus.ONLINE);
} else {
logger.debug("({}) configurtation error", uid);
}
}
/*
* Commands and events
*/
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
updateChannels();
}
}
public void updateChannels() {
try {
AsuswrtIpInfo interfaceInfo = router.getInterfaces().getByName(ifName);
fireEvents(interfaceInfo);
updateInterfaceChannels(interfaceInfo);
updateTrafficChannels(interfaceInfo.getTraffic());
} catch (Exception e) {
logger.debug("({}) unable to refresh data - property interfaceName not found ", uid);
}
}
private void updateInterfaceChannels(AsuswrtIpInfo interfaceInfo) {
updateState(getChannelID(CHANNEL_GROUP_NETWORK, CHANNEL_NETWORK_MAC), getStringType(interfaceInfo.getMAC()));
updateState(getChannelID(CHANNEL_GROUP_NETWORK, CHANNEL_NETWORK_IP),
getStringType(interfaceInfo.getIpAddress()));
updateState(getChannelID(CHANNEL_GROUP_NETWORK, CHANNEL_NETWORK_MASK),
getStringType(interfaceInfo.getSubnet()));
updateState(getChannelID(CHANNEL_GROUP_NETWORK, CHANNEL_NETWORK_GATEWAY),
getStringType(interfaceInfo.getGateway()));
updateState(getChannelID(CHANNEL_GROUP_NETWORK, CHANNEL_NETWORK_METHOD),
getStringType(interfaceInfo.getIpProto()));
updateState(getChannelID(CHANNEL_GROUP_NETWORK, CHANNEL_NETWORK_DNS),
getStringType(interfaceInfo.getDNSNServer()));
updateState(getChannelID(CHANNEL_GROUP_NETWORK, CHANNEL_NETWORK_STATE),
getOnOffType(interfaceInfo.isConnected()));
}
private void updateTrafficChannels(AsuswrtTraffic traffic) {
updateState(getChannelID(CHANNEL_GROUP_TRAFFIC, CHANNEL_TRAFFIC_CURRENT_RX),
getQuantityType(traffic.getCurrentRX(), Units.MEGABIT_PER_SECOND));
updateState(getChannelID(CHANNEL_GROUP_TRAFFIC, CHANNEL_TRAFFIC_CURRENT_TX),
getQuantityType(traffic.getCurrentTX(), Units.MEGABIT_PER_SECOND));
updateState(getChannelID(CHANNEL_GROUP_TRAFFIC, CHANNEL_TRAFFIC_TODAY_RX),
getQuantityType(traffic.getTodayRX(), Units.MEGABYTE));
updateState(getChannelID(CHANNEL_GROUP_TRAFFIC, CHANNEL_TRAFFIC_TODAY_TX),
getQuantityType(traffic.getTodayTX(), Units.MEGABYTE));
updateState(getChannelID(CHANNEL_GROUP_TRAFFIC, CHANNEL_TRAFFIC_TOTAL_RX),
getQuantityType(traffic.getTotalRX(), Units.MEGABYTE));
updateState(getChannelID(CHANNEL_GROUP_TRAFFIC, CHANNEL_TRAFFIC_TOTAL_TX),
getQuantityType(traffic.getTotalTX(), Units.MEGABYTE));
}
/**
* Fires events on {@link AsuswrtIpInfo} changes.
*/
public void fireEvents(AsuswrtIpInfo interfaceInfo) {
Boolean isConnected = interfaceInfo.isConnected();
if (checkForStateChange(CHANNEL_NETWORK_STATE, isConnected)) {
if (isConnected) {
triggerChannel(getChannelID(CHANNEL_GROUP_NETWORK, EVENT_CONNECTION), EVENT_STATE_CONNECTED);
} else {
triggerChannel(getChannelID(CHANNEL_GROUP_NETWORK, EVENT_CONNECTION), EVENT_STATE_DISCONNECTED);
}
}
}
/*
* Functions
*/
/**
* Gets the channel ID including the group.
*/
protected String getChannelID(String group, String channel) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (CHANNEL_GROUP_THING_SET.contains(thingTypeUID) && group.length() > 0) {
return group + "#" + channel;
}
return channel;
}
/**
* Gets a channel name from a channel ID.
*/
protected String getChannelFromID(ChannelUID channelID) {
String channel = channelID.getIdWithoutGroup();
channel = channel.replace(CHANNEL_GROUP_NETWORK + "#", "");
return channel;
}
/**
* Checks if the state changed since the last channel update.
*
* @param stateName the name of the state (channel)
* @param comparator comparison value
* @return <code>true</code> if changed, <code>false</code> if not or no old value exists
*/
private Boolean checkForStateChange(String stateName, Object comparator) {
if (oldStates.get(stateName) == null) {
oldStates.put(stateName, comparator);
} else if (!comparator.equals(oldStates.get(stateName))) {
oldStates.put(stateName, comparator);
return true;
}
return false;
}
}

View File

@ -0,0 +1,531 @@
/**
* Copyright (c) 2010-2023 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.asuswrt.internal.things;
import static org.openhab.binding.asuswrt.internal.constants.AsuswrtBindingConstants.*;
import static org.openhab.binding.asuswrt.internal.constants.AsuswrtBindingSettings.*;
import static org.openhab.binding.asuswrt.internal.helpers.AsuswrtUtils.*;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.asuswrt.internal.AsuswrtDiscoveryService;
import org.openhab.binding.asuswrt.internal.api.AsuswrtConnector;
import org.openhab.binding.asuswrt.internal.helpers.AsuswrtErrorHandler;
import org.openhab.binding.asuswrt.internal.helpers.AsuswrtUtils;
import org.openhab.binding.asuswrt.internal.structures.AsuswrtClientList;
import org.openhab.binding.asuswrt.internal.structures.AsuswrtConfiguration;
import org.openhab.binding.asuswrt.internal.structures.AsuswrtInterfaceList;
import org.openhab.binding.asuswrt.internal.structures.AsuswrtRouterInfo;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingStatusInfo;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.BaseBridgeHandler;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonObject;
/**
* The {@link AsuswrtRouter} is responsible for handling commands, which are sent to one of the channels.
*
* @author Christian Wild - Initial contribution
*/
@NonNullByDefault
public class AsuswrtRouter extends BaseBridgeHandler {
private final Logger logger = LoggerFactory.getLogger(AsuswrtRouter.class);
private @Nullable ScheduledFuture<?> startupJob;
private @Nullable ScheduledFuture<?> pollingJob;
private @Nullable ScheduledFuture<?> reconnectJob;
private @Nullable ScheduledFuture<?> discoveryJob;
private @NonNullByDefault({}) AsuswrtDiscoveryService discoveryService;
private @Nullable AsuswrtConnector connector;
private AsuswrtConfiguration config;
private AsuswrtRouterInfo deviceInfo;
private AsuswrtInterfaceList interfaceList = new AsuswrtInterfaceList();
private AsuswrtClientList clientList = new AsuswrtClientList();
private final HttpClient httpClient;
private final String uid;
public AsuswrtErrorHandler errorHandler;
public AsuswrtRouter(Bridge bridge, HttpClient httpClient) {
super(bridge);
Thing thing = getThing();
uid = thing.getUID().toString();
errorHandler = new AsuswrtErrorHandler();
this.httpClient = httpClient;
deviceInfo = new AsuswrtRouterInfo();
config = new AsuswrtConfiguration();
}
@Override
public void initialize() {
config = getConfigAs(AsuswrtConfiguration.class);
connector = new AsuswrtConnector(this);
// Initialize the handler.
setState(ThingStatus.UNKNOWN);
// background initialization (delay it a little bit):
startupJob = scheduler.schedule(this::delayedStartUp, 1000, TimeUnit.MILLISECONDS);
}
@Override
public void dispose() {
stopScheduler(startupJob);
stopScheduler(pollingJob);
stopScheduler(discoveryJob);
stopScheduler(reconnectJob);
}
@Override
public Collection<Class<? extends ThingHandlerService>> getServices() {
return List.of(AsuswrtDiscoveryService.class);
}
public void setDiscoveryService(AsuswrtDiscoveryService discoveryService) {
this.discoveryService = discoveryService;
}
/*
* Scheduler
*/
/**
* Delayed one-time startup job.
*/
private void delayedStartUp() {
connect();
}
public void startPollingJob() {
int pollingInterval = AsuswrtUtils.getValueOrDefault(config.pollingInterval, POLLING_INTERVAL_S_DEFAULT);
TimeUnit timeUnit = TimeUnit.SECONDS;
if (pollingInterval > 0) {
if (pollingInterval < POLLING_INTERVAL_S_MIN) {
pollingInterval = POLLING_INTERVAL_S_MIN;
}
logger.trace("({}) start polling scheduler with interval {} {}", getUID(), pollingInterval, timeUnit);
pollingJob = scheduler.scheduleWithFixedDelay(this::pollingJobAction, pollingInterval, pollingInterval,
timeUnit);
} else {
stopScheduler(pollingJob);
}
}
protected void pollingJobAction() {
if (ThingStatus.ONLINE.equals(getState())) {
queryDeviceData();
}
}
protected void startReconnectScheduler() {
int pollingInterval = config.reconnectInterval;
TimeUnit timeUnit = TimeUnit.SECONDS;
if (pollingInterval < RECONNECT_INTERVAL_S) {
pollingInterval = RECONNECT_INTERVAL_S;
}
logger.trace("({}) start reconnect scheduler in {} {}", getUID(), pollingInterval, timeUnit);
reconnectJob = scheduler.schedule(this::reconnectJobAction, pollingInterval, timeUnit);
}
protected void reconnectJobAction() {
connect();
}
protected void startDiscoveryScheduler() {
int pollingInterval = config.discoveryInterval;
TimeUnit timeUnit = TimeUnit.SECONDS;
if (config.autoDiscoveryEnabled && pollingInterval > 0) {
logger.trace("{} starting bridge discovery sheduler with interval {} {}", getUID(), pollingInterval,
timeUnit);
discoveryJob = scheduler.scheduleWithFixedDelay(discoveryService::startScan, 0, pollingInterval, timeUnit);
} else {
stopScheduler(discoveryJob);
}
}
/**
* Stops a scheduler.
*
* @param scheduler ScheduledFeature<?> which should be stopped
*/
protected void stopScheduler(@Nullable ScheduledFuture<?> scheduler) {
if (scheduler != null) {
logger.trace("{} stopping scheduler {}", uid, scheduler);
scheduler.cancel(true);
}
}
/*
* Functions
*/
/**
* Connects to the router and sets the states.
*/
@SuppressWarnings("null")
protected void connect() {
connector.login();
if (connector.cookieStore.cookieIsSet()) {
stopScheduler(reconnectJob);
queryDeviceData(false);
devicePropertiesChanged(deviceInfo);
setState(ThingStatus.ONLINE);
startPollingJob();
} else {
setState(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, errorHandler.getErrorMessage());
}
}
@SuppressWarnings("null")
public void queryDeviceData(Boolean asyncRequest) {
connector.queryDeviceData(CMD_GET_SYSINFO + CMD_GET_USAGE + CMD_GET_LANINFO + CMD_GET_WANINFO
+ CMD_GET_CLIENTLIST + CMD_GET_TRAFFIC, asyncRequest);
}
/**
* Queries device data asynchronously.
*/
public void queryDeviceData() {
queryDeviceData(true);
}
/**
* Sets routerInfo data and updates channels on receiving new data with the associated command.
*
* @param jsonObject contains the received data
* @param command the command that was sent
*/
public void dataReceived(JsonObject jsonObject, String command) {
if (command.contains(CMD_GET_SYSINFO)) {
deviceInfo.setSysInfo(jsonObject);
devicePropertiesChanged(deviceInfo);
}
if (command.contains(CMD_GET_CLIENTLIST)) {
clientList.setData(jsonObject);
updateClients();
}
if (command.contains(CMD_GET_LANINFO)) {
interfaceList.setData(INTERFACE_LAN, jsonObject);
updateChild(THING_TYPE_INTERFACE, NETWORK_REPRESENTATION_PROPERTY, INTERFACE_LAN);
}
if (command.contains(CMD_GET_WANINFO)) {
interfaceList.setData(INTERFACE_WAN, jsonObject);
updateChild(THING_TYPE_INTERFACE, NETWORK_REPRESENTATION_PROPERTY, INTERFACE_WAN);
}
if (command.contains(CMD_GET_USAGE) || command.contains(CMD_GET_MEMUSAGE)
|| command.contains(CMD_GET_CPUUSAGE)) {
deviceInfo.setUsageStats(jsonObject);
}
updateChannels(deviceInfo, clientList);
}
/**
* Updates the router status.
*/
public void setState(ThingStatus thingStatus, ThingStatusDetail statusDetail, String text) {
if (!thingStatus.equals(getThing().getStatus())) {
updateStatus(thingStatus, statusDetail, text);
updateChildStates(thingStatus);
if (ThingStatus.OFFLINE.equals(thingStatus)) {
stopScheduler(pollingJob);
// Set channels to undef
getThing().getChannels().forEach(c -> updateState(c.getUID(), UnDefType.UNDEF));
startReconnectScheduler();
}
}
}
/**
* Upate RouterStatus
*/
public void setState(ThingStatus thingStatus) {
setState(thingStatus, ThingStatusDetail.NONE, "");
}
/***********************************
*
* PUBLIC GETs
*
************************************/
public HttpClient getHttpClient() {
return httpClient;
}
public AsuswrtConfiguration getConfiguration() {
return config;
}
public AsuswrtErrorHandler getErrorHandler() {
return errorHandler;
}
public ThingUID getUID() {
return thing.getUID();
}
public AsuswrtRouterInfo getDeviceInfo() {
return deviceInfo;
}
public AsuswrtClientList getClients() {
return clientList;
}
public AsuswrtInterfaceList getInterfaces() {
return interfaceList;
}
public ThingStatus getState() {
return getThing().getStatus();
}
/***********************************
*
* COMMAND HANDLER
*
************************************/
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
queryDeviceData();
}
}
/***********************************
*
* PROPERTIES
*
************************************/
/**
* UPDATE PROPERTIES
*
* If only one property must be changed, there is also a convenient method
* updateProperty(String name, String value).
*/
public void devicePropertiesChanged(AsuswrtRouterInfo deviceInfo) {
/* device properties */
Map<String, String> properties = editProperties();
properties.put(Thing.PROPERTY_MAC_ADDRESS, interfaceList.getByName(INTERFACE_WAN).getMAC());
properties.put(Thing.PROPERTY_MODEL_ID, deviceInfo.getProductId());
properties.put(Thing.PROPERTY_FIRMWARE_VERSION, deviceInfo.getFirmwareVersion());
updateProperties(properties);
}
/***********************************
*
* CHANNELS
*
************************************/
/**
* Update all Channels
*/
public void updateChannels(AsuswrtRouterInfo deviceInfo, AsuswrtClientList clientList) {
updateClientChannels(clientList);
updateUsageChannels(deviceInfo);
}
/**
* Update Channel Usage
*/
public void updateUsageChannels(AsuswrtRouterInfo deviceInfo) {
updateState(getChannelID(CHANNEL_GROUP_SYSINFO, CHANNEL_MEM_TOTAL),
getQuantityType(deviceInfo.getMemUsage().getTotal(), Units.MEGABYTE));
updateState(getChannelID(CHANNEL_GROUP_SYSINFO, CHANNEL_MEM_FREE),
getQuantityType(deviceInfo.getMemUsage().getFree(), Units.MEGABYTE));
updateState(getChannelID(CHANNEL_GROUP_SYSINFO, CHANNEL_MEM_USED),
getQuantityType(deviceInfo.getMemUsage().getUsed(), Units.MEGABYTE));
updateState(getChannelID(CHANNEL_GROUP_SYSINFO, CHANNEL_MEM_FREE_PERCENT),
getQuantityType(deviceInfo.getMemUsage().getFreePercent(), Units.PERCENT));
updateState(getChannelID(CHANNEL_GROUP_SYSINFO, CHANNEL_MEM_USED_PERCENT),
getQuantityType(deviceInfo.getMemUsage().getUsedPercent(), Units.PERCENT));
updateState(getChannelID(CHANNEL_GROUP_SYSINFO, CHANNEL_CPU_USED_PERCENT),
getQuantityType(deviceInfo.getCpuAverage().getUsedPercent(), Units.PERCENT));
}
/**
* Update Client Channel
*/
public void updateClientChannels(AsuswrtClientList clientList) {
updateState(getChannelID(CHANNEL_GROUP_CLIENTS, CHANNEL_CLIENTS_KNOWN),
getStringType(clientList.getClientList()));
updateState(getChannelID(CHANNEL_GROUP_CLIENTS, CHANNEL_CLIENTS_ONLINE),
getStringType(clientList.getOnlineClients().getClientList()));
updateState(getChannelID(CHANNEL_GROUP_CLIENTS, CHANNEL_CLIENTS_COUNT),
getDecimalType(clientList.getOnlineClients().getCount()));
updateState(getChannelID(CHANNEL_GROUP_CLIENTS, CHANNEL_CLIENTS_ONLINE_MAC),
getStringType(clientList.getOnlineClients().getMacAddresses()));
}
/**
* Fire Event
*
* @param channelUID chanelUID event belongs to
* @param event event-name is fired
*/
protected void fireEvent(String channel, String event) {
triggerChannel(channel, event);
}
/***********************************
*
* CHILD THINGS
*
************************************/
/**
* Update all Child-Things with type Client
*/
public void updateClients() {
updateChildThings(THING_TYPE_CLIENT);
}
/**
* Update all Child-Things with type Interface
*/
public void updateInterfaces() {
updateChildThings(THING_TYPE_INTERFACE);
}
/**
* Update all Child-Things belonging to ThingTypeUID
*/
public void updateChildThings(ThingTypeUID thingTypeToUpdate) {
ThingTypeUID thingTypeUID;
List<Thing> things = getThing().getThings();
for (Thing thing : things) {
thingTypeUID = thing.getThingTypeUID();
if (thingTypeToUpdate.equals(thingTypeUID)) {
updateChild(thing);
}
}
}
/**
* Update Child single child with special representationProperty
*
* @param thingTypeToUpdate ThingTypeUID of Thing to update
* @param representationProperty Name of representationProperty
* @param propertyValue Value of representationProperty
*/
public void updateChild(ThingTypeUID thingTypeToUpdate, String representationProperty, String propertyValue) {
List<Thing> things = getThing().getThings();
for (Thing thing : things) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (thingTypeToUpdate.equals(thingTypeUID)) {
String thingProperty = thing.getProperties().get(representationProperty);
if (propertyValue.equals(thingProperty)) {
updateChild(thing);
}
}
}
}
/**
* Update Child-Thing (send refreshCommand)
*
* @param thing - Thing to update
*/
public void updateChild(Thing thing) {
ThingHandler handler = thing.getHandler();
if (handler != null) {
ChannelUID cUid = new ChannelUID(thing.getUID(), CHANNELS_ALL);
handler.handleCommand(cUid, RefreshType.REFRESH);
}
}
/**
* Set State of all clients
*
* @param thingStatus new ThingStatus
*/
public void updateChildStates(ThingStatus thingStatus) {
List<Thing> things = getThing().getThings();
for (Thing thing : things) {
updateChildState(thing, thingStatus);
}
}
/**
* Set State of a Thing
*
* @param thing Thing to update
* @param thingStatus new ThingStatus
*/
public void updateChildState(Thing thing, ThingStatus thingStatus) {
ThingHandler handler = thing.getHandler();
if (handler != null) {
if (ThingStatus.OFFLINE.equals(thingStatus)) {
handler.bridgeStatusChanged(new ThingStatusInfo(thingStatus, ThingStatusDetail.BRIDGE_OFFLINE, ""));
} else {
handler.bridgeStatusChanged(new ThingStatusInfo(thingStatus, ThingStatusDetail.NONE, ""));
}
}
}
/***********************************
*
* FUNCTIONS
*
************************************/
/**
* Get ChannelID including group
*
* @param group String channel-group
* @param channel String channel-name
* @return String channelID
*/
protected String getChannelID(String group, String channel) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (CHANNEL_GROUP_THING_SET.contains(thingTypeUID) && group.length() > 0) {
return group + "#" + channel;
}
return channel;
}
/**
* Get Channel from ChannelID
*
* @param channelID String channelID
* @return String channel-name
*/
protected String getChannelFromID(ChannelUID channelID) {
String channel = channelID.getIdWithoutGroup();
channel = channel.replace(CHANNEL_GROUP_SYSINFO + "#", "");
channel = channel.replace(CHANNEL_GROUP_CLIENTS + "#", "");
return channel;
}
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<addon:addon id="asuswrt" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:addon="https://openhab.org/schemas/addon/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/addon/v1.0.0 https://openhab.org/schemas/addon-1.0.0.xsd">
<type>binding</type>
<name>Asuswrt Binding</name>
<description>Binding for ASUS routers (Asuswrt / Asuswrt-Merlin only)</description>
<connection>local</connection>
</addon:addon>

View File

@ -0,0 +1,118 @@
# add-on
addon.asuswrt.name = Asuswrt Binding
addon.asuswrt.description = Binding for ASUS routers (Asuswrt / Asuswrt-Merlin only)
# thing types
thing-type.asuswrt.client.label = Asuswrt Client
thing-type.asuswrt.client.description = Client connected to Asuswrt-Router
thing-type.asuswrt.interface.label = Router Interface
thing-type.asuswrt.interface.description = Interface of router
thing-type.asuswrt.router.label = Asuswrt Router
thing-type.asuswrt.router.description = Router with Asuswrt or Asuswrt-Merlin OS
# thing types config
thing-type.config.asuswrt.client.clientNick.label = Nickname
thing-type.config.asuswrt.client.clientNick.description = Nickname of the device
thing-type.config.asuswrt.client.macAddress.label = MAC Address
thing-type.config.asuswrt.client.macAddress.description = MAC address of the device
thing-type.config.asuswrt.interface.interfaceName.label = Interface Name
thing-type.config.asuswrt.interface.interfaceName.description = Name of selected interface. *Maybe not all are supported by your device*
thing-type.config.asuswrt.interface.interfaceName.option.wan = WAN
thing-type.config.asuswrt.interface.interfaceName.option.lan = LAN
thing-type.config.asuswrt.router.hostname.label = Hostname
thing-type.config.asuswrt.router.hostname.description = Hostname or IP address of the device
thing-type.config.asuswrt.router.httpPort.label = HTTP Port
thing-type.config.asuswrt.router.httpPort.description = Port used for HTTP connection
thing-type.config.asuswrt.router.httpsPort.label = HTTPS Port
thing-type.config.asuswrt.router.httpsPort.description = Port used for HTTPS connection
thing-type.config.asuswrt.router.password.label = Password
thing-type.config.asuswrt.router.password.description = Password to access the device
thing-type.config.asuswrt.router.pollingInterval.label = Polling Interval
thing-type.config.asuswrt.router.pollingInterval.description = Interval the device is polled in sec.
thing-type.config.asuswrt.router.useSSL.label = Use SSL
thing-type.config.asuswrt.router.useSSL.description = Use SSL to authenticate. If not use HTTP
thing-type.config.asuswrt.router.username.label = Username
thing-type.config.asuswrt.router.username.description = Username to access the device
# channel group types
channel-group-type.asuswrt.client-list-group.label = Clients
channel-group-type.asuswrt.client-list-group.description = Clients connected to router
channel-group-type.asuswrt.client-list-group.channel.known-clients.label = Known Clients
channel-group-type.asuswrt.client-list-group.channel.known-clients.description = Known clients with name and MAC addresses
channel-group-type.asuswrt.client-list-group.channel.online-clients.description = Online clients with name and MAC addresses
channel-group-type.asuswrt.clientNetworkGroup.label = Clients
channel-group-type.asuswrt.clientNetworkGroup.description = Clients connected to router
channel-group-type.asuswrt.clientNetworkGroup.channel.ip-address.description = Client IP address
channel-group-type.asuswrt.if-info-group.label = LAN Status
channel-group-type.asuswrt.if-info-group.description = LAN connection state
channel-group-type.asuswrt.sys-info-group.label = System Info
channel-group-type.asuswrt.sys-info-group.description = System information about the device
channel-group-type.asuswrt.sys-info-group.channel.cpu-used-percent.label = Total CPU Usage
channel-group-type.asuswrt.sys-info-group.channel.cpu-used-percent.description = Total CPU usage in percent over all cores
channel-group-type.asuswrt.sys-info-group.channel.mem-free.label = Free Memory
channel-group-type.asuswrt.sys-info-group.channel.mem-free.description = Free memory in MB
channel-group-type.asuswrt.sys-info-group.channel.mem-free-percent.label = Free Memory
channel-group-type.asuswrt.sys-info-group.channel.mem-free-percent.description = Free memory in %
channel-group-type.asuswrt.sys-info-group.channel.mem-total.label = Total Memory
channel-group-type.asuswrt.sys-info-group.channel.mem-total.description = Total memory in MB
channel-group-type.asuswrt.sys-info-group.channel.mem-used.label = Used Memory
channel-group-type.asuswrt.sys-info-group.channel.mem-used.description = Used memory in MB
channel-group-type.asuswrt.sys-info-group.channel.mem-used-percent.label = Used Memory
channel-group-type.asuswrt.sys-info-group.channel.mem-used-percent.description = Used memory in %
channel-group-type.asuswrt.traffic-group.label = Traffic
channel-group-type.asuswrt.traffic-group.description = Traffic Monitoring
channel-group-type.asuswrt.traffic-group.channel.cur-rx.label = Current Traffic Received
channel-group-type.asuswrt.traffic-group.channel.cur-tx.label = Current Traffic Sent
channel-group-type.asuswrt.traffic-group.channel.today-rx.label = Today Traffic Received
channel-group-type.asuswrt.traffic-group.channel.today-tx.label = Today Traffic Sent
channel-group-type.asuswrt.traffic-group.channel.total-rx.label = Total Traffic Received
channel-group-type.asuswrt.traffic-group.channel.total-tx.label = Total Traffic Sent
# channel types
channel-type.asuswrt.client-nick-name.label = Nickname
channel-type.asuswrt.client-nick-name.description = Nickname of client
channel-type.asuswrt.client-online-event-type.label = Online State Changed Trigger
channel-type.asuswrt.client-online-event-type.description = Event is fired if client leaves ('gone') or enters ('connected') the network
channel-type.asuswrt.clients-online-count-type.label = Online Clients Count
channel-type.asuswrt.clients-online-count-type.description = number online clients
channel-type.asuswrt.clients-online-mac-type.label = Online MAC Addresses
channel-type.asuswrt.clients-online-mac-type.description = List with MAC addresses of online clients
channel-type.asuswrt.clients-online-type.label = Online Clients
channel-type.asuswrt.clients-online-type.description = List of online clients
channel-type.asuswrt.connection-event-type.label = ConnectionState Changed Event
channel-type.asuswrt.connection-event-type.description = Event is fired connection state changes ('connected'/'disconnected')
channel-type.asuswrt.current-traffic-type.label = Current Traffic
channel-type.asuswrt.current-traffic-type.description = Current traffic in MBit/s
channel-type.asuswrt.dns-name-type.label = DNS Name
channel-type.asuswrt.dns-name-type.description = DNS name
channel-type.asuswrt.dns-server-type.label = DNS Server
channel-type.asuswrt.dns-server-type.description = Used DNS Servers
channel-type.asuswrt.interne-state-type.label = Internet Connected
channel-type.asuswrt.interne-state-type.description = Client is connected to Internet
channel-type.asuswrt.ip-address-type.label = IP Address
channel-type.asuswrt.ip-address-type.description = IP address of interface
channel-type.asuswrt.ip-connection-state.label = Connected
channel-type.asuswrt.ip-connection-state.description = Connection state of interface
channel-type.asuswrt.ip-gateway-type.label = Gateway
channel-type.asuswrt.ip-gateway-type.description = Gateway of interface
channel-type.asuswrt.ip-netmask-type.label = Subnet
channel-type.asuswrt.ip-netmask-type.description = Subnet mask of interface
channel-type.asuswrt.ip-proto-type.label = IP Protocol
channel-type.asuswrt.ip-proto-type.description = IP address protocol (DHCP/Static)
channel-type.asuswrt.is-online-type.label = Online
channel-type.asuswrt.is-online-type.description = Client is online
channel-type.asuswrt.mac-address-type.label = MAC Address
channel-type.asuswrt.mac-address-type.description = MAC address of device (LAN)
channel-type.asuswrt.productid.label = Router Model
channel-type.asuswrt.productid.description = Model/ProductID of your Router
channel-type.asuswrt.today-taffic-type.label = Today Traffic
channel-type.asuswrt.today-taffic-type.description = Total traffic in MB since 0:00 a clock
channel-type.asuswrt.total-traffic-type.label = Total Traffic
channel-type.asuswrt.total-traffic-type.description = Total traffic in MB since reboot
channel-type.asuswrt.usage-data-type.label = Usage in MB
channel-type.asuswrt.usage-type-percent.label = Percentage

View File

@ -0,0 +1,179 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="asuswrt"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<!-- ####################### GLOBAL CHANNEL GROUPS ########################## -->
<!-- Traffic -->
<channel-group-type id="traffic-group">
<label>Traffic</label>
<description>Traffic Monitoring</description>
<channels>
<channel id="cur-rx" typeId="current-traffic-type">
<label>Current Traffic Received</label>
</channel>
<channel id="cur-tx" typeId="current-traffic-type">
<label>Current Traffic Sent</label>
</channel>
<channel id="today-rx" typeId="today-taffic-type">
<label>Today Traffic Received</label>
</channel>
<channel id="today-tx" typeId="today-taffic-type">
<label>Today Traffic Sent</label>
</channel>
<channel id="total-rx" typeId="total-traffic-type">
<label>Total Traffic Received</label>
</channel>
<channel id="total-tx" typeId="total-traffic-type">
<label>Total Traffic Sent</label>
</channel>
</channels>
</channel-group-type>
<!-- ############################### CHANNELS ############################### -->
<!-- Product Id -->
<channel-type id="productid">
<item-type>String</item-type>
<label>Router Model</label>
<description>Model/ProductID of your Router</description>
</channel-type>
<!-- Usage -->
<channel-type id="usage-data-type">
<item-type>Number:DataAmount</item-type>
<label>Usage in MB</label>
<state pattern="%.0f %unit%" readOnly="true"></state>
</channel-type>
<channel-type id="usage-type-percent">
<item-type>Number:Dimensionless</item-type>
<label>Percentage</label>
<state pattern="%.1f %unit%" readOnly="true"></state>
</channel-type>
<!-- LAN/WAN INFO -->
<channel-type id="dns-name-type">
<item-type>String</item-type>
<label>DNS Name</label>
<description>DNS name</description>
<state readOnly="true"></state>
</channel-type>
<channel-type id="dns-server-type">
<item-type>String</item-type>
<label>DNS Server</label>
<description>Used DNS Servers</description>
<state readOnly="true"></state>
</channel-type>
<channel-type id="ip-address-type">
<item-type>String</item-type>
<label>IP Address</label>
<description>IP address of interface</description>
<state readOnly="true"></state>
</channel-type>
<channel-type id="ip-proto-type">
<item-type>String</item-type>
<label>IP Protocol</label>
<description>IP address protocol (DHCP/Static)</description>
<state readOnly="true"></state>
</channel-type>
<channel-type id="mac-address-type">
<item-type>String</item-type>
<label>MAC Address</label>
<description>MAC address of device (LAN)</description>
<state readOnly="true"></state>
</channel-type>
<channel-type id="ip-netmask-type">
<item-type>String</item-type>
<label>Subnet</label>
<description>Subnet mask of interface</description>
<state readOnly="true"></state>
</channel-type>
<channel-type id="ip-gateway-type">
<item-type>String</item-type>
<label>Gateway</label>
<description>Gateway of interface</description>
<state readOnly="true"></state>
</channel-type>
<channel-type id="ip-connection-state">
<item-type>Switch</item-type>
<label>Connected</label>
<description>Connection state of interface</description>
<state readOnly="true"></state>
</channel-type>
<channel-type id="connection-event-type">
<kind>Trigger</kind>
<label>ConnectionState Changed Event</label>
<description>Event is fired connection state changes ('connected'/'disconnected')</description>
</channel-type>
<!-- CLIENTS -->
<channel-type id="clients-online-type">
<item-type>String</item-type>
<label>Online Clients</label>
<description>List of online clients</description>
<state readOnly="true"></state>
</channel-type>
<channel-type id="clients-online-mac-type">
<item-type>String</item-type>
<label>Online MAC Addresses</label>
<description>List with MAC addresses of online clients</description>
<state readOnly="true"></state>
</channel-type>
<channel-type id="clients-online-count-type">
<item-type>Number:Dimensionless</item-type>
<label>Online Clients Count</label>
<description>number online clients</description>
<state pattern="%.0f" readOnly="true"></state>
</channel-type>
<channel-type id="client-nick-name">
<item-type>String</item-type>
<label>Nickname</label>
<description>Nickname of client</description>
<state readOnly="true"></state>
</channel-type>
<channel-type id="is-online-type">
<item-type>Switch</item-type>
<label>Online</label>
<description>Client is online</description>
<state readOnly="true"></state>
</channel-type>
<channel-type id="interne-state-type">
<item-type>Switch</item-type>
<label>Internet Connected</label>
<description>Client is connected to Internet</description>
<state readOnly="true"></state>
</channel-type>
<channel-type id="client-online-event-type">
<kind>Trigger</kind>
<label>Online State Changed Trigger</label>
<description>Event is fired if client leaves ('gone') or enters ('connected') the network</description>
</channel-type>
<!-- Traffic -->
<channel-type id="current-traffic-type">
<item-type>Number:DataTransferRate</item-type>
<label>Current Traffic</label>
<description>Current traffic in MBit/s</description>
<state pattern="%.2f %unit%" readOnly="true"></state>
</channel-type>
<channel-type id="today-taffic-type">
<item-type>Number:DataAmount</item-type>
<label>Today Traffic</label>
<description>Total traffic in MB since 0:00 a clock</description>
<state pattern="%.0f %unit%" readOnly="true"></state>
</channel-type>
<channel-type id="total-traffic-type">
<item-type>Number:DataAmount</item-type>
<label>Total Traffic</label>
<description>Total traffic in MB since reboot</description>
<state pattern="%.0f %unit%" readOnly="true"></state>
</channel-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="asuswrt"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<!-- Router Thing Type -->
<thing-type id="client">
<supported-bridge-type-refs>
<bridge-type-ref id="router"/>
</supported-bridge-type-refs>
<label>Asuswrt Client</label>
<description>Client connected to Asuswrt-Router</description>
<channel-groups>
<channel-group id="network-info" typeId="clientNetworkGroup"></channel-group>
<channel-group id="traffic" typeId="traffic-group"></channel-group>
</channel-groups>
<properties>
<property name="vendor">Vendor</property>
<property name="dnsName">DNS Name</property>
</properties>
<representation-property>macAddress</representation-property>
<config-description>
<parameter name="macAddress" type="text" required="true">
<label>MAC Address</label>
<description>MAC address of the device</description>
<default>00:00:00:00:00:00</default>
</parameter>
<parameter name="clientNick" type="text" required="false">
<label>Nickname</label>
<description>Nickname of the device</description>
</parameter>
</config-description>
</thing-type>
<!-- ############################### CHANNEL-GROUPS ############################### -->
<channel-group-type id="clientNetworkGroup">
<label>Clients</label>
<description>Clients connected to router</description>
<channels>
<channel id="network-state" typeId="is-online-type"></channel>
<channel id="ip-address" typeId="ip-address-type">
<description>Client IP address</description>
</channel>
<channel id="ip-method" typeId="ip-proto-type"></channel>
<channel id="internet-state" typeId="interne-state-type"></channel>
<channel id="client-online-event" typeId="client-online-event-type"></channel>
</channels>
</channel-group-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="asuswrt"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<!-- Router Thing Type -->
<thing-type id="interface">
<supported-bridge-type-refs>
<bridge-type-ref id="router"/>
</supported-bridge-type-refs>
<label>Router Interface</label>
<description>Interface of router</description>
<channel-groups>
<channel-group id="network-info" typeId="if-info-group"></channel-group>
<channel-group id="traffic" typeId="traffic-group"></channel-group>
</channel-groups>
<representation-property>interfaceName</representation-property>
<config-description>
<parameter name="interfaceName" type="text" required="true">
<label>Interface Name</label>
<description>Name of selected interface. *Maybe not all are supported by your device*</description>
<options>
<option value="wan">WAN</option>
<option value="lan">LAN</option>
</options>
</parameter>
</config-description>
</thing-type>
<!-- ############################### CHANNEL-GROUPS ############################### -->
<!-- Interface Information -->
<channel-group-type id="if-info-group">
<label>LAN Status</label>
<description>LAN connection state</description>
<channels>
<channel id="mac-address" typeId="mac-address-type"></channel>
<channel id="ip-address" typeId="ip-address-type"></channel>
<channel id="ip-method" typeId="ip-proto-type"></channel>
<channel id="subnet" typeId="ip-netmask-type"></channel>
<channel id="gateway" typeId="ip-gateway-type"></channel>
<channel id="dns-servers" typeId="dns-server-type"></channel>
<channel id="network-state" typeId="ip-connection-state"></channel>
<channel id="connection-event" typeId="connection-event-type"></channel>
</channels>
</channel-group-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,108 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="asuswrt"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<!-- Router Thing Type -->
<bridge-type id="router">
<label>Asuswrt Router</label>
<description>Router with Asuswrt or Asuswrt-Merlin OS</description>
<channel-groups>
<channel-group id="sys-info" typeId="sys-info-group"></channel-group>
<channel-group id="client-list" typeId="client-list-group"></channel-group>
</channel-groups>
<config-description>
<parameter name="hostname" type="text" required="true">
<context>network-address</context>
<label>Hostname</label>
<description>Hostname or IP address of the device</description>
<default>router.asus.com</default>
</parameter>
<parameter name="username" type="text" required="true">
<label>Username</label>
<description>Username to access the device</description>
</parameter>
<parameter name="password" type="text" required="true">
<context>password</context>
<label>Password</label>
<description>Password to access the device</description>
</parameter>
<parameter name="useSSL" type="boolean">
<label>Use SSL</label>
<description>Use SSL to authenticate. If not use HTTP</description>
<default>false</default>
</parameter>
<parameter name="httpPort" type="integer">
<label>HTTP Port</label>
<description>Port used for HTTP connection</description>
<default>80</default>
<advanced>true</advanced>
</parameter>
<parameter name="httpsPort" type="integer">
<label>HTTPS Port</label>
<description>Port used for HTTPS connection</description>
<default>443</default>
<advanced>true</advanced>
</parameter>
<parameter name="pollingInterval" type="integer" unit="s" min="3">
<label>Polling Interval</label>
<description>Interval the device is polled in sec.</description>
<default>20</default>
<advanced>true</advanced>
</parameter>
</config-description>
</bridge-type>
<!-- ############################### CHANNEL-GROUPS ############################### -->
<!-- System Information -->
<channel-group-type id="sys-info-group">
<label>System Info</label>
<description>System information about the device</description>
<channels>
<channel id="mem-total" typeId="usage-data-type">
<label>Total Memory</label>
<description>Total memory in MB</description>
</channel>
<channel id="mem-used" typeId="usage-data-type">
<label>Used Memory</label>
<description>Used memory in MB</description>
</channel>
<channel id="mem-free" typeId="usage-data-type">
<label>Free Memory</label>
<description>Free memory in MB</description>
</channel>
<channel id="mem-free-percent" typeId="usage-type-percent">
<label>Free Memory</label>
<description>Free memory in %</description>
</channel>
<channel id="mem-used-percent" typeId="usage-type-percent">
<label>Used Memory</label>
<description>Used memory in %</description>
</channel>
<channel id="cpu-used-percent" typeId="usage-type-percent">
<label>Total CPU Usage</label>
<description>Total CPU usage in percent over all cores</description>
</channel>
</channels>
</channel-group-type>
<!-- Clients -->
<channel-group-type id="client-list-group">
<label>Clients</label>
<description>Clients connected to router</description>
<channels>
<channel id="known-clients" typeId="clients-online-type">
<label>Known Clients</label>
<description>Known clients with name and MAC addresses</description>
</channel>
<channel id="online-clients" typeId="clients-online-type">
<description>Online clients with name and MAC addresses</description>
</channel>
<channel id="online-macs" typeId="clients-online-mac-type"></channel>
<channel id="online-clients-count" typeId="clients-online-count-type"></channel>
<channel id="client-online-event" typeId="client-online-event-type"></channel>
</channels>
</channel-group-type>
</thing:thing-descriptions>

View File

@ -60,6 +60,7 @@
<module>org.openhab.binding.anel</module>
<module>org.openhab.binding.anthem</module>
<module>org.openhab.binding.astro</module>
<module>org.openhab.binding.asuswrt</module>
<module>org.openhab.binding.atlona</module>
<module>org.openhab.binding.autelis</module>
<module>org.openhab.binding.automower</module>