From 3bfeddd226f13709b3cf0470cc4f9c2a9e229977 Mon Sep 17 00:00:00 2001 From: Christian Wild Date: Fri, 25 Nov 2022 18:33:00 +0100 Subject: [PATCH] [asuswrt] added interface thing * revised complete code Signed-off-by: Christian Wild --- bundles/org.openhab.binding.asuswrt/README.md | 121 ++++++---- .../org.openhab.binding.asuswrt/README.md.bak | 98 ++++++++ .../internal/AsuswrtDiscoveryService.java | 118 +++++++-- .../internal/AsuswrtHandlerFactory.java | 20 +- .../internal/api/AsuswrtConnector.java | 61 +++-- .../asuswrt/internal/api/AsuswrtCookie.java | 101 ++++++++ .../internal/api/AsuswrtHttpClient.java | 31 +-- .../constants/AsuswrtBindingConstants.java | 53 ++-- .../constants/AsuswrtBindingSettings.java | 13 +- .../constants/AsuswrtErrorConstants.java | 3 + .../internal/helpers/AsuswrtUtils.java | 2 +- .../structures/AsuswrtClientList.java | 9 + .../structures/AsuswrtConfiguration.java | 16 +- .../structures/AsuswrtInterfaceList.java | 143 +++++++++++ .../internal/structures/AsuswrtIpInfo.java | 45 ++-- .../structures/AsuswrtRouterInfo.java | 41 +--- .../internal/things/AsuswrtClient.java | 31 ++- .../internal/things/AsuswrtInterface.java | 193 +++++++++++++++ .../internal/things/AsuswrtRouter.java | 227 +++++++++--------- .../main/resources/OH-INF/thing/channels.xml | 6 + .../main/resources/OH-INF/thing/client.xml | 10 +- .../main/resources/OH-INF/thing/interface.xml | 50 ++++ .../main/resources/OH-INF/thing/router.xml | 48 ++-- .../internal/TapoControlHandlerFactory.java | 3 +- 24 files changed, 1073 insertions(+), 370 deletions(-) create mode 100644 bundles/org.openhab.binding.asuswrt/README.md.bak create mode 100644 bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/api/AsuswrtCookie.java create mode 100644 bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/structures/AsuswrtInterfaceList.java create mode 100644 bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/things/AsuswrtInterface.java create mode 100644 bundles/org.openhab.binding.asuswrt/src/main/resources/OH-INF/thing/interface.xml diff --git a/bundles/org.openhab.binding.asuswrt/README.md b/bundles/org.openhab.binding.asuswrt/README.md index 40745032bd2af..8e6103b109568 100644 --- a/bundles/org.openhab.binding.asuswrt/README.md +++ b/bundles/org.openhab.binding.asuswrt/README.md @@ -1,76 +1,99 @@ -# asuswrt Binding +# Asuswrt Binding -_Give some details about what this binding is meant for - a protocol, system, specific device._ +This binding adds support to control get informations from ASUS-Router (Copyright © ASUS). -_If possible, provide some resources like pictures (only PNG is supported currently), a video, etc. to give an impression of what can be done with this binding._ -_You can place such resources into a `doc` folder next to this README.md._ +# !! EARLY BETA !! -_Put each sentence in a separate line to improve readability of diffs._ +# BINDING AND REDME NOT FULLY WORKING/COMPLETED ## Supported Things -_Please describe the different supported things / devices including their ThingTypeUID within this section._ -_Which different types are supported, which models were tested etc.?_ -_Note that it is planned to generate some part of this based on the XML files within ```src/main/resources/OH-INF/thing``` of your binding._ +Binding supports ASUS-Router with AsusWRT or -AsusWRT-Merlin Firmware. +Firmware 5.x.x (some DSL models) is NOT supported (not AsusWRT). -- `bridge`: Short description of the Bridge, if any -- `sample`: Short description of the Thing with the ThingTypeUID `sample` +| ThingType | Name | Descripion | +|---------------|------------|-----------------------------------------| +| bridge | router | router binding is connecting | +| - | interface | network interface of router | +| - | client | client is connected to the bridge | -## Discovery +### `router` Thing Configuration -_Describe the available auto-discovery features here._ -_Mention for what it works and what needs to be kept in mind when using it._ +| 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 | -## Binding Configuration +### `interface` Thing Configuration -_If your binding requires or supports general configuration settings, please create a folder ```cfg``` and place the configuration file ```.cfg``` inside it._ -_In this section, you should link to this file and provide some information about the options._ -_The file could e.g. look like:_ +| Name | Type | Description | Default | Required | Advanced | +|-----------------|---------|---------------------------------------|---------------------|----------|----------| +| interfaceName | text | options name of interface (wan/lan) | N/A | yes | no | -``` -# Configuration for the asuswrt Binding -# -# Default secret key for the pairing of the asuswrt Thing. -# It has to be between 10-40 (alphanumeric) characters. -# This may be changed by the user for security reasons. -secret=openHABSecret -``` +### `client` Thing Configuration -_Note that it is planned to generate some part of this based on the information that is available within ```src/main/resources/OH-INF/binding``` of your binding._ +| 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 | -_If your binding does not offer any generic configurations, you can remove this section completely._ -## Thing Configuration +## Properties -_Describe what is needed to manually configure a thing, either through the UI or via a thing-file._ -_This should be mainly about its mandatory and optional configuration parameters._ +All devices support some of the following properties: -_Note that it is planned to generate some part of this based on the XML files within ```src/main/resources/OH-INF/thing``` of your binding._ +| property | description | things supporting this channel | +|------------------|------------------------------|---------------------------------------| +| vendor | Vendor of device | router, client | +| dnsName | DNS-Name of device | router, client | -### `sample` Thing Configuration - -| Name | Type | Description | Default | Required | Advanced | -|-----------------|---------|---------------------------------------|---------|----------|----------| -| hostname | text | Hostname or IP address of the device | N/A | yes | no | -| password | text | Password to access the device | N/A | yes | no | -| refreshInterval | integer | Interval the device is polled in sec. | 600 | no | yes | ## Channels -_Here you should provide information about available channel types, what their meaning is and how they can be used._ +All devices support some of the following channels: + +| group | channel |type | description | things supporting this channel | +|------------------|--------------------|------------------------|--------------------------------------------|-----------------------------------| +| networkInfo | macAddress | text (RO) | HW-Address | interface, client | +| | ipAddress | text (RO) | IP-Address | interface | +| | ipMethod | text (RO) | Ip-Method (static/dhcp) | interface, client | +| | subnet | text (RO) | Subnetmask | interface | +| | gateway | text (RO) | Default-Gateway | interface | +| | dnsServers | text (RO) | DNS-Servers | interface | +| | networkState | Switch (RO) | Client is online | interface, client | +| | internetState | Switch (RO) | Client connected to Internet | client | +| sysInfoGroup | memTotal | Number:DataAmountype | Total memory in MB | router | +| | memUsed | Number:DataAmountype | Used memory in MB | router | +| | memFree | Number:DataAmountype | Free memory in MB | router | +| | memUsedPercent | Number:Dimensionles | Used memory in % | router | +| | cpuUsedPercent | Number:Dimensionles | Total CPU usage in percent over all cores | router | +| clientListGroup | knownClients | text (RO) | Known clients with name and MAC-Addresses | router | +| | onlineClients | text (RO) | Online clients with name and MAC-Addresses | router | +| | onlineMACs | text (RO) | List with mac-addresses of online clients | router | +| | onlineClientsCount | Number:Dimensionless | Count of online clients | router | + + +## Events + +All devices support some of the following Events: +| group | event |kind | description | things supporting this event | +|------------------|-----------------|------------|------------------------------------------------------------------------|---------------------------------| +| networkInfo | connectionEvent | Trigger | Fired if Client leaves ('gone') or enters ('connected') the network | interface, client | + + -_Note that it is planned to generate some part of this based on the XML files within ```src/main/resources/OH-INF/thing``` of your binding._ +## Debugging and Tracing -| Channel | Type | Read/Write | Description | -|---------|--------|------------|-----------------------------| -| control | Switch | RW | This is the control channel | +If you want to see what's going on in the binding, switch the loglevel to TRACE in the Karaf console -## Full Example +`log:set TRACE org.openhab.binding.asuswrt` -_Provide a full usage example based on textual configuration files._ -_*.things, *.items examples are mandatory as textual configuration is well used by many users._ -_*.sitemap examples are optional._ +Set the logging back to normal -## Any custom content here! +`log:set INFO org.openhab.binding.asuswrt`+ -_Feel free to add additional sections for whatever you think should also be mentioned about your binding!_ diff --git a/bundles/org.openhab.binding.asuswrt/README.md.bak b/bundles/org.openhab.binding.asuswrt/README.md.bak new file mode 100644 index 0000000000000..fbd6610ea30d1 --- /dev/null +++ b/bundles/org.openhab.binding.asuswrt/README.md.bak @@ -0,0 +1,98 @@ +# Asuswrt Binding + +This binding adds support to control get informations from ASUS-Router (Copyright © ASUS). + +# !! EARLY BETA !! +# BINDING AND REDME NOT FULLY WORKING/COMPLETED + +## Supported Things + +Binding supports ASUS-Router with AsusWRT or -AsusWRT-Merlin Firmware. +Firmware 5.x.x (some DSL models) is NOT supported (not AsusWRT). + +| ThingType | Name | Descripion | +|---------------|------------|-----------------------------------------| +| bridge | router | router binding is connecting | +| - | interface | network interface of 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 | +|------------------|--------------------|------------------------|--------------------------------------------|-----------------------------------| +| networkInfo | macAddress | text (RO) | HW-Address | interface, client | +| | ipAddress | text (RO) | IP-Address | interface | +| | ipMethod | text (RO) | Ip-Method (static/dhcp) | interface, client | +| | subnet | text (RO) | Subnetmask | interface | +| | gateway | text (RO) | Default-Gateway | interface | +| | dnsServers | text (RO) | DNS-Servers | interface | +| | networkState | Switch (RO) | Client is online | interface, client | +| | internetState | Switch (RO) | Client connected to Internet | client | +| sysInfoGroup | memTotal | Number:DataAmountype | Total memory in MB | router | +| | memUsed | Number:DataAmountype | Used memory in MB | router | +| | memFree | Number:DataAmountype | Free memory in MB | router | +| | memUsedPercent | Number:Dimensionles | Used memory in % | router | +| | cpuUsedPercent | Number:Dimensionles | Total CPU usage in percent over all cores | router | +| clientListGroup | knownClients | text (RO) | Known clients with name and MAC-Addresses | router | +| | onlineClients | text (RO) | Online clients with name and MAC-Addresses | router | +| | onlineMACs | text (RO) | List with mac-addresses of online clients | router | +| | onlineClientsCount | Number:Dimensionless | Count of online clients | router | + + + +## Events + +All devices support some of the following Events: +| group | event |kind | description | things supporting this event | +|------------------|-----------------|------------|------------------------------------------------------------------------|---------------------------------| +| networkInfo | connectionEvent | Trigger | Fired if Client leaves ('gone') or enters ('connected') the network | interface, client | + + + +## Debugging and Tracing + +If you want to see what's going on in the binding, switch the loglevel to TRACE in the Karaf console + +`log:set TRACE org.openhab.binding.asuswrt` + +Set the logging back to normal + +`log:set INFO org.openhab.binding.asuswrt` \ No newline at end of file diff --git a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/AsuswrtDiscoveryService.java b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/AsuswrtDiscoveryService.java index 1b77a63579f9e..e109d659fc142 100644 --- a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/AsuswrtDiscoveryService.java +++ b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/AsuswrtDiscoveryService.java @@ -16,6 +16,7 @@ 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; @@ -23,6 +24,8 @@ 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; @@ -42,6 +45,7 @@ @NonNullByDefault public class AsuswrtDiscoveryService extends AbstractDiscoveryService implements ThingHandlerService { private final Logger logger = LoggerFactory.getLogger(AsuswrtDiscoveryService.class); + private String uid = ""; protected @NonNullByDefault({}) AsuswrtRouter router; /*********************************** @@ -60,6 +64,7 @@ public void activate() { @Override public void deactivate() { super.deactivate(); + removeAllResults(); } @Override @@ -68,6 +73,7 @@ public void setThingHandler(@Nullable ThingHandler handler) { AsuswrtRouter router = (AsuswrtRouter) handler; router.setDiscoveryService(this); this.router = router; + this.uid = router.getUID().getAsString(); } } @@ -87,23 +93,59 @@ public void setThingHandler(@Nullable ThingHandler handler) { */ @Override public void startScan() { - removeOlderResults(getTimestampOfLastScan()); + logger.trace("{} starting scan", uid); if (router != null) { + /* query Data */ router.queryDeviceData(false); - AsuswrtClientList clientList = router.getDeviceInfo().getClients(); - handleScanResults(clientList); + /* discover interfaces */ + AsuswrtInterfaceList ifList = router.getInterfaces(); + handleInterfaceScan(ifList); + /* discover clients */ + AsuswrtClientList clientList = router.getClients(); + handleClientScan(clientList); + } + } + + @Override + public void stopScan() { + super.stopScan(); + removeOlderResults(getTimestampOfLastScan()); + } + + /** + * Remove all scan results + */ + public void removeAllResults() { + removeOlderResults(new Date().getTime()); + } + + /** + * Work with result from get interfaces from router + * Create DiscoveryResult from interfaceList + * + * @param ifList + */ + public void handleInterfaceScan(AsuswrtInterfaceList ifList) { + try { + for (AsuswrtIpInfo ifInfo : ifList) { + DiscoveryResult discoveryResult = createInterfaceResult(ifInfo); + thingDiscovered(discoveryResult); + } + } catch (Exception e) { + logger.debug("error handling scan results", e); } } /** - * work with result from get clients from router + * Work with result from get clients from router + * Create DiscoveryResult from clientList * * @param deviceList */ - public void handleScanResults(AsuswrtClientList clientList) { + public void handleClientScan(AsuswrtClientList clientList) { try { for (AsuswrtClientInfo client : clientList) { - DiscoveryResult discoveryResult = createDiscoveryResult(client); + DiscoveryResult discoveryResult = createClientResult(client); thingDiscovered(discoveryResult); } } catch (Exception e) { @@ -111,40 +153,82 @@ public void handleScanResults(AsuswrtClientList clientList) { } } - public DiscoveryResult createDiscoveryResult(AsuswrtClientInfo clientInfo) { - String clientMac = clientInfo.getMac(); - String unformatedMac = unformatMac(clientMac); + /*********************************** + * + * CREATE DISCOVERY RESULTS + * + ************************************/ + /** + * Create DiscoveryResult from single interfaceInfo + * + * @param interfaceInfo + * @return + */ + public DiscoveryResult createInterfaceResult(AsuswrtIpInfo interfaceInfo) { + String ifName = interfaceInfo.getName(); + String macAddress = interfaceInfo.getMAC(); + String unformatedMac = unformatMac(macAddress); + String label = "AwrtInterface_" + ifName; + + Map properties = new HashMap<>(); + properties.put(NETWORK_REPRASENTATION_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_REPRASENTATION_PROPERTY).withBridge(bridgeUID).withLabel(label) + .build(); + } else { + ThingUID thingUID = new ThingUID(BINDING_ID, ifName); + return DiscoveryResultBuilder.create(thingUID).withProperties(properties) + .withRepresentationProperty(NETWORK_REPRASENTATION_PROPERTY).withLabel(label).build(); + } + } + + /** + * Create DiscoveryResult from single clientInfo + * + * @param clientInfo + * @return + */ + public DiscoveryResult createClientResult(AsuswrtClientInfo clientInfo) { + String macAddress = clientInfo.getMac(); + String unformatedMac = unformatMac(macAddress); String clientName; String nickName; - String label; + 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; + label += nickName; } else { - label = nickName + " (" + clientName + ")"; + label += nickName + " (" + clientName + ")"; } /* create properties */ Map properties = new HashMap<>(); - properties.put(Thing.PROPERTY_MAC_ADDRESS, clientInfo.getMac()); + 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("client '{}'' discovered", clientMac); + 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_REPRASENTATION_PROPERTY).withBridge(bridgeUID).withLabel(label) - .build(); + .withRepresentationProperty(CLIENT_REPRASENTATION_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_REPRASENTATION_PROPERTY).withLabel(label).build(); + .withRepresentationProperty(CLIENT_REPRASENTATION_PROPERTY).withTTL(DISCOVERY_AUTOREMOVE_S) + .withLabel(label).build(); } } } diff --git a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/AsuswrtHandlerFactory.java b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/AsuswrtHandlerFactory.java index 5c73476e15186..261adf1ab6e4a 100644 --- a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/AsuswrtHandlerFactory.java +++ b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/AsuswrtHandlerFactory.java @@ -14,6 +14,7 @@ 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; @@ -21,7 +22,9 @@ 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; @@ -50,15 +53,21 @@ public class AsuswrtHandlerFactory extends BaseThingHandlerFactory { 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(); + 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("cannot start httpClient"); + logger.error(ERR_HTTP_CLIENT_FAILED); } } @@ -91,6 +100,11 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { 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; } @@ -111,7 +125,7 @@ protected AsuswrtRouter getRouter(Thing thing) { } } } - logger.debug("bridge router not found"); + logger.warn(ERR_BRIDGE_NOT_DECLARED); return null; } } diff --git a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/api/AsuswrtConnector.java b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/api/AsuswrtConnector.java index 98202af2269fe..13172dbd13bed 100644 --- a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/api/AsuswrtConnector.java +++ b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/api/AsuswrtConnector.java @@ -19,6 +19,10 @@ 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; @@ -66,7 +70,7 @@ public AsuswrtConnector(AsuswrtRouter router) { * @return */ public Boolean login() { - String url = routerConfig.url + "/login.cgi"; + String url = getURL("login.cgi"); String encodedCredentials = credentials.getEncodedCredentials(); String payload = ""; @@ -80,7 +84,7 @@ public Boolean login() { if (response != null) { setCookieFromResponse(response); } - if (isValidLogin()) { + if (cookieStore.isValid()) { router.setState(ThingStatus.ONLINE); return true; } @@ -92,9 +96,7 @@ public Boolean login() { * unset cookie */ public void logout() { - this.cookie = ""; - this.token = ""; - this.cookieTimeStamp = 0L; + this.cookieStore.resetCookie(); } /** @@ -116,10 +118,12 @@ public void queryDeviceData(String command, Boolean asyncRequest) { Long now = System.currentTimeMillis(); router.errorHandler.reset(); - checkAuth(); + if (cookieStore.cookieIsExpired()) { + login(); + } if (now > this.lastQuery + HTTP_QUERY_MIN_GAP_MS) { - String url = routerConfig.url + "/appGet.cgi"; + String url = getURL("appGet.cgi"); String payload = "hook=" + command; this.lastQuery = now; @@ -171,6 +175,9 @@ protected void handleHttpResultError(Throwable e, String payload) { 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); @@ -182,32 +189,34 @@ protected void handleHttpResultError(Throwable e, String payload) { /*********************************** * - * PUBLIC STUFF + * PRIVATE STUFF * ************************************/ - /** - * check if cookie is set and not expired + * Get Target URL * + * @param site * @return */ - public Boolean isValidLogin() { - Boolean cookieExpired = System.currentTimeMillis() > this.cookieTimeStamp + (COOKIE_LIFETIME_S * 1000); - if (cookieExpired.equals(true)) { - logger.trace("({}) cookie is expired ", uid); + 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 cookieExpired.equals(false) && !this.cookie.isBlank(); + return url + "/" + site; } - /** - * check authentication (login) and relogin if not - * - * @return - */ - public Boolean checkAuth() { - if (isValidLogin().equals(false)) { - return login(); - } - return true; - } + /*********************************** + * + * PUBLIC STUFF + * + ************************************/ } diff --git a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/api/AsuswrtCookie.java b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/api/AsuswrtCookie.java new file mode 100644 index 0000000000000..114d3d03f9833 --- /dev/null +++ b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/api/AsuswrtCookie.java @@ -0,0 +1,101 @@ +/** + * Copyright (c) 2010-2022 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 org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * CLASS FOR COOKIE HANDLING + * + * @author Christian Wild - Initial contribution + */ +@NonNullByDefault +public class AsuswrtCookie { + protected String cookie = ""; + protected String token = ""; + protected Long cookieTimeStamp = 0L; + + /*********************************** + * + * SET AND RESET FUNCTIONS + * + ************************************/ + + /** + * Set new cookie + * + * @param cookie + */ + public void setCookie(String cookie) { + this.cookie = cookie; + this.cookieTimeStamp = System.currentTimeMillis(); + } + + /** + * reset cookie + */ + public void resetCookie() { + this.cookie = ""; + this.token = ""; + this.cookieTimeStamp = 0L; + } + + /*********************************** + * + * CHECK COOKIE + * + ************************************/ + + /** + * check if cookie is set + * + * @return + */ + public Boolean cookieIsSet() { + return !this.cookie.isBlank(); + } + + /** + * check if cookie is expired + * + * @return true if cookie is set and expired + */ + public Boolean cookieIsExpired() { + if (this.cookieTimeStamp > 0L + && System.currentTimeMillis() > this.cookieTimeStamp + (COOKIE_LIFETIME_S * 1000)) { + return true; + } + return false; + } + + /** + * Check if cookie is set and not expired + * + * @return + */ + public Boolean isValid() { + return !cookieIsExpired() && cookieIsSet(); + } + + /*********************************** + * + * GET VALUES + * + ************************************/ + + public String getCookie() { + return this.cookie; + } +} diff --git a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/api/AsuswrtHttpClient.java b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/api/AsuswrtHttpClient.java index bd67e53f38308..5026971c9b92f 100644 --- a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/api/AsuswrtHttpClient.java +++ b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/api/AsuswrtHttpClient.java @@ -45,13 +45,10 @@ @NonNullByDefault public class AsuswrtHttpClient { private final Logger logger = LoggerFactory.getLogger(AsuswrtHttpClient.class); - private Gson gson = new Gson(); - protected String cookie = ""; - protected String token = ""; - protected Long cookieTimeStamp = 0L; protected AsuswrtRouter router; protected final String uid; + public AsuswrtCookie cookieStore = new AsuswrtCookie(); /** * INIT CLASS @@ -94,7 +91,7 @@ protected void sendSyncRequest(String url, String payload, String command) { */ @Nullable protected ContentResponse getSyncRequest(String url, String payload) { - logger.trace("({}) sendRequest '{}' to '{}' with cookie '{}'", uid, payload, url, this.cookie); + logger.trace("({}) sendRequest '{}' to '{}' with cookie '{}'", uid, payload, url, cookieStore.getCookie()); Request httpRequest = this.router.getHttpClient().newRequest(url).method(HttpMethod.POST.toString()); /* set header */ @@ -121,7 +118,7 @@ protected ContentResponse getSyncRequest(String url, String payload) { * @param command command executed - this will handle RepsonseType */ protected void sendAsyncRequest(String url, String payload, String command) { - logger.trace("({}) sendAsncRequest to '{}' with cookie '{}'", uid, url, this.cookie); + logger.trace("({}) sendAsncRequest to '{}' with cookie '{}'", uid, url, cookieStore.getCookie()); try { Request httpRequest = router.getHttpClient().newRequest(url).method(HttpMethod.POST.toString()); @@ -163,8 +160,8 @@ private Request setHeaders(Request httpRequest) { /* set header */ httpRequest.header("content-type", HTTP_CONTENT_TYPE); httpRequest.header("user-agent", HTTP_USER_AGENT); - if (!this.cookie.isBlank()) { - httpRequest.header("cookie", this.cookie); + if (cookieStore.isValid()) { + httpRequest.header("cookie", cookieStore.getCookie()); } return httpRequest; } @@ -186,13 +183,10 @@ protected void handleHttpResultError(Throwable e, String payload) { if (e instanceof TimeoutException) { logger.debug("({}) sendAsyncRequest timeout'{}'", uid, errorMessage); - router.errorHandler.raiseError(ERR_CONN_TIMEOUT, errorMessage); } else if (e instanceof InterruptedException) { logger.debug("({}) sending request interrupted: {}", uid, e.toString()); - router.errorHandler.raiseError(new Exception(e), payload); } else { logger.debug("({}) sendAsyncRequest failed'{}'", uid, errorMessage); - router.errorHandler.raiseError(new Exception(e), errorMessage); } } @@ -216,7 +210,7 @@ protected void handleHttpSuccessResponse(String responseBody, String command) { * @param response */ protected void setCookieFromResponse(ContentResponse response) { - resetToken(); + cookieStore.resetCookie(); if (response.getStatus() == 200) { String rBody = response.getContentAsString(); logger.trace("({}) received response '{}'", uid, rBody); @@ -224,9 +218,8 @@ protected void setCookieFromResponse(ContentResponse response) { /* get json object 'asus_token' */ JsonObject jsonObject = gson.fromJson(rBody, JsonObject.class); if (jsonObject != null && jsonObject.has(JSON_MEMBER_TOKEN)) { - this.token = jsonObject.get(JSON_MEMBER_TOKEN).getAsString(); - this.cookie = "asus_token=" + token; - this.cookieTimeStamp = System.currentTimeMillis(); + 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()); @@ -238,14 +231,6 @@ protected void setCookieFromResponse(ContentResponse response) { } } - /** - * reset Token (Logout) - */ - protected void resetToken() { - this.token = ""; - this.cookie = ""; - } - /** * get Json from response * diff --git a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/constants/AsuswrtBindingConstants.java b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/constants/AsuswrtBindingConstants.java index 041369c8fa1c1..9a8bf45fbd142 100644 --- a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/constants/AsuswrtBindingConstants.java +++ b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/constants/AsuswrtBindingConstants.java @@ -34,8 +34,10 @@ public class AsuswrtBindingConstants { // 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 SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_ROUTER, THING_TYPE_CLIENT); + public static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_ROUTER, THING_TYPE_CLIENT, + THING_TYPE_INTERFACE); /*** THINGS WITH CHANNEL GROUPS ***/ public static final Set CHANNEL_GROUP_THING_SET = Collections @@ -46,19 +48,14 @@ public class AsuswrtBindingConstants { * item channel names ***/ - // general channels - public static final String CHANNEL_IP_ADDRESS = "ipAddress"; - public static final String CHANNEL_MAC_ADDRESS = "macAddress"; - public static final String CHANNEL_SUBNET = "subnet"; - public static final String CHANNEL_GATEWAY = "gateway"; - public static final String CHANNEL_IP_METHOD = "ipMethod"; - public static final String EVENT_CONNECTION = "connectionEvent"; - // general event constats 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 = "anyChannel"; + // channel group system info public static final String CHANNEL_GROUP_SYSINFO = "sysInfo"; public static final String CHANNEL_MEM_FREE = "memFree"; @@ -68,29 +65,39 @@ public class AsuswrtBindingConstants { public static final String CHANNEL_MEM_USED_PERCENT = "memUsedPercent"; public static final String CHANNEL_CPU_USED_PERCENT = "cpuUsedPercent"; - // channel group lan information - public static final String CHANNEL_GROUP_LANINFO = "lanInfo"; - - // channel group wan information - public static final String CHANNEL_GROUP_WANINFO = "wanInfo"; - public static final String CHANNEL_WAN_DNS_SERVER = "wanDNS"; - public static final String CHANNEL_WAN_STATUS = "wanStatus"; + // channel group interface information + public static final String CHANNEL_GROUP_NETWORK = "networkInfo"; + public static final String CHANNEL_NETWORK_IP = "ipAddress"; + public static final String CHANNEL_NETWORK_MAC = "macAddress"; + public static final String CHANNEL_NETWORK_MASK = "subnet"; + public static final String CHANNEL_NETWORK_GATEWAY = "gateway"; + public static final String CHANNEL_NETWORK_METHOD = "ipMethod"; + public static final String CHANNEL_NETWORK_DNS = "dnsServers"; + public static final String CHANNEL_NETWORK_STATE = "networkState"; + public static final String CHANNEL_NETWORK_INTERNET = "internetState"; + public static final String EVENT_CONNECTION = "connectionEvent"; // channel group clientList information public static final String CHANNEL_GROUP_CLIENTS = "clientList"; public static final String CHANNEL_CLIENTS_KNOWN = "knownClients"; public static final String CHANNEL_CLIENTS_ONLINE = "onlineClients"; + public static final String CHANNEL_CLIENTS_COUNT = "onlineClientsCount"; public static final String CHANNEL_CLIENTS_ONLINE_MAC = "onlineMACs"; // channel group client information - public static final String CLIENT_REPRASENTATION_PROPERTY = "macAddress"; - public static final String PROPERTY_CLIENT_MAC = "macAddress"; - public static final String PROPERTY_CLIENT_NAME = "clientName"; public static final String CHANNEL_GROUP_CLIENT = "client"; - public static final String CHANNEL_CLIENT_NICKNAME = "clientNick"; - public static final String CHANNEL_CLIENT_ONLINE = "isOnline"; - public static final String CHANNEL_CLIENT_INETSTATE = "internetState"; - public static final String EVENT_CLIENT_ONLINE = "onlineEvent"; + public static final String CHANNEL_CLIENT_NICKNAME = "clientName"; + + /** + * PROPERTIES + */ + + // interface + public static final String PROPERTY_INTERFACE_NAME = "interfaceName"; + public static final String NETWORK_REPRASENTATION_PROPERTY = "interfaceName"; + // client + public static final String PROPERTY_CLIENT_NAME = "dnsName"; + public static final String CLIENT_REPRASENTATION_PROPERTY = "macAddress"; /*** * JSON REQUEST MEMBERNAMES diff --git a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/constants/AsuswrtBindingSettings.java b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/constants/AsuswrtBindingSettings.java index 5f26fcb2adf0e..ad159d67bd81b 100644 --- a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/constants/AsuswrtBindingSettings.java +++ b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/constants/AsuswrtBindingSettings.java @@ -12,6 +12,8 @@ */ package org.openhab.binding.asuswrt.internal.constants; +import java.util.Set; + import org.eclipse.jdt.annotation.NonNullByDefault; /** @@ -32,12 +34,15 @@ public class AsuswrtBindingSettings { 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 = 10; // minimum polling interval public static final Integer POLLING_INTERVAL_S_DEFAULT = 30; // 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 + 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);"; @@ -49,4 +54,10 @@ public class AsuswrtBindingSettings { 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 Set INTERFACE_LIST = Set.of(INTERFACE_WAN, INTERFACE_LAN); } diff --git a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/constants/AsuswrtErrorConstants.java b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/constants/AsuswrtErrorConstants.java index 062baf8949dca..af8eec3703aee 100644 --- a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/constants/AsuswrtErrorConstants.java +++ b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/constants/AsuswrtErrorConstants.java @@ -26,10 +26,13 @@ public class AsuswrtErrorConstants { /**************************************** * LIST OF ERROR MESSAGES ****************************************/ + 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_FOMRAT = "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"; } diff --git a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/helpers/AsuswrtUtils.java b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/helpers/AsuswrtUtils.java index a8fe1b3b2df85..ce105a177f814 100644 --- a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/helpers/AsuswrtUtils.java +++ b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/helpers/AsuswrtUtils.java @@ -369,7 +369,7 @@ public static DecimalType getDecimalType(@Nullable Integer numVal) { * * @param numVal */ - public static DecimalType getDecimalTypel(@Nullable Long numVal) { + public static DecimalType getDecimalType(@Nullable Long numVal) { return new DecimalType((numVal != null ? numVal : 0)); } diff --git a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/structures/AsuswrtClientList.java b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/structures/AsuswrtClientList.java index c696195127840..19942a198f5b8 100644 --- a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/structures/AsuswrtClientList.java +++ b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/structures/AsuswrtClientList.java @@ -169,6 +169,15 @@ public String getClientNames() { return clients.toString(); } + /** + * Return count of clients in list + * + * @return + */ + public Integer getCount() { + return this.clientList.size(); + } + /* * Return ; seperated list with macAddresses */ diff --git a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/structures/AsuswrtConfiguration.java b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/structures/AsuswrtConfiguration.java index 240608ecfa119..3228dd1b80ef7 100644 --- a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/structures/AsuswrtConfiguration.java +++ b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/structures/AsuswrtConfiguration.java @@ -12,13 +12,7 @@ */ package org.openhab.binding.asuswrt.internal.structures; -import static org.openhab.binding.asuswrt.internal.constants.AsuswrtBindingSettings.*; - import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.core.config.core.Configuration; -import org.openhab.core.thing.Thing; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * The {@link AsuswrtConfiguration} class contains fields mapping thing configuration parameters. @@ -27,23 +21,25 @@ */ @NonNullByDefault public class AsuswrtConfiguration { - private final Logger logger = LoggerFactory.getLogger(AsuswrtConfiguration.class); /* THING CONFIGUTATION PROPERTYS */ 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 CONFIGUTATION PARAMETERS */ public String hostname = ""; public String username = ""; public String password = ""; - public String url = ""; public int pollingInterval = 20; public int reconnectInterval = 60; public int discoveryInterval = 3600; + public int httpPort = 80; + public int httpsPort = 443; public boolean autoDiscoveryEnabled = false; - - private Thing router; + public boolean useSSL = false; } diff --git a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/structures/AsuswrtInterfaceList.java b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/structures/AsuswrtInterfaceList.java new file mode 100644 index 0000000000000..77f26d52ed1b1 --- /dev/null +++ b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/structures/AsuswrtInterfaceList.java @@ -0,0 +1,143 @@ +/** + * Copyright (c) 2010-2022 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 ipInfo list + * + * @author Christian Wild - Initial contribution + */ +@NonNullByDefault +public class AsuswrtInterfaceList implements Iterable { + private List ipInfoList = new ArrayList(); + + /** + * INIT CLASS + */ + public AsuswrtInterfaceList() { + } + + /** + * ITERATOR + * + * @return ipInfoInfo + */ + @Override + public Iterator iterator() { + return ipInfoList.iterator(); + } + + /*********************************** + * + * SET VALUES + * + ************************************/ + + /** + * ADD INTERFACE TO LIST + * + * @param ipInfoInfo AsuswrtIpInfo + */ + private void addInterface(AsuswrtIpInfo ipInfo) { + + this.ipInfoList.add(ipInfo); + } + + /** + * Set InterfaceData from jsonObject / create new if not exists + * + * @param ifName name of interface + * @param jsonObject with interface data + */ + public void setData(String ifName, JsonObject jsonObject) { + if (hasInterface(ifName).equals(true)) { + getByName(ifName).setData(jsonObject); + } else { + addInterface(new AsuswrtIpInfo(ifName, jsonObject)); + } + } + + /*********************************** + * + * GET VALUES + * + ************************************/ + + /** + * GET INTERFACE BY NAME + * + * @param ipInfoName String interface + * @return AsuswrtIpInfo + */ + public AsuswrtIpInfo getByName(String ifName) { + for (AsuswrtIpInfo ipInfo : this.ipInfoList) { + if (ipInfo.getName().equals(ifName)) { + return ipInfo; + } + } + return new AsuswrtIpInfo(); + } + + /** + * GET INTERFACE BY MAC + * + * @param ipInfoMAC String ipInfo MAC Address + * @return AsuswrtIpInfo + */ + public AsuswrtIpInfo getByMAC(String ipInfoMAC) { + for (AsuswrtIpInfo ipInfo : this.ipInfoList) { + if (ipInfo.getMAC().equals(ipInfoMAC)) { + return ipInfo; + } + } + return new AsuswrtIpInfo(); + } + + /** + * GET INTERFACE BY IP + * + * @param ipAddress String IP-Address + * @return AsuswrtIpInfo + */ + public AsuswrtIpInfo getByIP(String ipAddress) { + for (AsuswrtIpInfo ipInfo : this.ipInfoList) { + if (ipInfo.getIpAddress().equals(ipAddress)) { + return ipInfo; + } + } + return new AsuswrtIpInfo(); + } + + /** + * Check if interface is in list + * + * @param ifName InterfaceName + * @return true if data was set + */ + public Boolean hasInterface(String ifName) { + for (AsuswrtIpInfo ipInfo : this.ipInfoList) { + if (ipInfo.getName().equals(ifName)) { + return true; + } + } + return false; + } +} diff --git a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/structures/AsuswrtIpInfo.java b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/structures/AsuswrtIpInfo.java index e2fec42926b1e..75e0dd27d7ec8 100644 --- a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/structures/AsuswrtIpInfo.java +++ b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/structures/AsuswrtIpInfo.java @@ -13,6 +13,7 @@ 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; @@ -26,12 +27,12 @@ */ @NonNullByDefault public class AsuswrtIpInfo { + private String ifName = ""; private String hwAddress = ""; private String ipAddress = ""; private String ipProto = ""; private String subnet = ""; private String gateway = ""; - private String name = ""; private String dnsServer = ""; private Boolean connected = false; @@ -45,10 +46,12 @@ public AsuswrtIpInfo() { * * INIT CLASS * + * @param interfaceName name of interface * @param jsonObject with ipInfo */ - public AsuswrtIpInfo(JsonObject jsonObject) { - setData(jsonObject, CHANNEL_GROUP_SYSINFO); + public AsuswrtIpInfo(String ifName, JsonObject jsonObject) { + this.ifName = ifName; + setData(jsonObject); } /*********************************** @@ -63,23 +66,23 @@ public AsuswrtIpInfo(JsonObject jsonObject) { * @param jsonObject jsonObject data is stored * @param channelGroup channelGroup data belongs to */ - public void setData(JsonObject jsonObject, String channelGroup) { - this.hwAddress = jsonObjectToString(jsonObject, JSON_MEMBER_MAC, this.hwAddress); - switch (channelGroup) { - case CHANNEL_GROUP_LANINFO: - this.ipAddress = jsonObjectToString(jsonObject, JSON_MEMBER_LAN_IP, this.ipAddress); - this.subnet = jsonObjectToString(jsonObject, JSON_MEMBER_LAN_NETMASK, this.subnet); - this.gateway = jsonObjectToString(jsonObject, JSON_MEMBER_LAN_GATEWAY, this.gateway); - this.ipProto = jsonObjectToString(jsonObject, JSON_MEMBER_LAN_PROTO, this.ipProto); - break; - case CHANNEL_GROUP_WANINFO: - this.ipAddress = jsonObjectToString(jsonObject, JSON_MEMBER_WAN_IP, this.ipAddress); - this.subnet = jsonObjectToString(jsonObject, JSON_MEMBER_WAN_NETMASK, this.subnet); - this.gateway = jsonObjectToString(jsonObject, JSON_MEMBER_WAN_GATEWAY, this.gateway); - this.ipProto = jsonObjectToString(jsonObject, JSON_MEMBER_WAN_PROTO, this.ipProto); - this.dnsServer = jsonObjectToString(jsonObject, JSON_MEMBER_WAN_DNS_SERVER, this.dnsServer); - this.connected = (jsonObjectToInt(jsonObject, JSON_MEMBER_WAN_CONNECTED).equals(1)); - break; + public void setData(JsonObject jsonObject) { + if (ifName.startsWith(INTERFACE_LAN)) { + this.hwAddress = jsonObjectToString(jsonObject, JSON_MEMBER_MAC, this.hwAddress); + this.ipAddress = jsonObjectToString(jsonObject, JSON_MEMBER_LAN_IP, this.ipAddress); + this.subnet = jsonObjectToString(jsonObject, JSON_MEMBER_LAN_NETMASK, this.subnet); + this.gateway = jsonObjectToString(jsonObject, JSON_MEMBER_LAN_GATEWAY, this.gateway); + this.ipProto = jsonObjectToString(jsonObject, JSON_MEMBER_LAN_PROTO, this.ipProto); + } else if (ifName.startsWith(INTERFACE_WAN)) { + this.hwAddress = jsonObjectToString(jsonObject, JSON_MEMBER_MAC, this.hwAddress); + this.ipAddress = jsonObjectToString(jsonObject, JSON_MEMBER_WAN_IP, this.ipAddress); + this.subnet = jsonObjectToString(jsonObject, JSON_MEMBER_WAN_NETMASK, this.subnet); + this.gateway = jsonObjectToString(jsonObject, JSON_MEMBER_WAN_GATEWAY, this.gateway); + this.ipProto = jsonObjectToString(jsonObject, JSON_MEMBER_WAN_PROTO, this.ipProto); + this.dnsServer = jsonObjectToString(jsonObject, JSON_MEMBER_WAN_DNS_SERVER, this.dnsServer); + this.connected = (jsonObjectToInt(jsonObject, JSON_MEMBER_WAN_CONNECTED).equals(1)); + } else if (ifName.startsWith(INTERFACE_WLAN)) { + // ToDo } } @@ -114,7 +117,7 @@ public String getDNSNServer() { } public String getName() { - return this.name; + return this.ifName; } public Boolean isConnected() { diff --git a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/structures/AsuswrtRouterInfo.java b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/structures/AsuswrtRouterInfo.java index eb0cf7bb3b54c..41ed4b5d7cc96 100644 --- a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/structures/AsuswrtRouterInfo.java +++ b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/structures/AsuswrtRouterInfo.java @@ -35,9 +35,7 @@ public class AsuswrtRouterInfo { private String productId = ""; private String fwVersion = ""; private String fwBuild = ""; - private AsuswrtIpInfo lanInfo = new AsuswrtIpInfo(); - private AsuswrtIpInfo wanInfo = new AsuswrtIpInfo(); - private AsuswrtClientList clientList = new AsuswrtClientList(); + private String macAddress = ""; private Map usageStats = new HashMap<>(); /** @@ -69,8 +67,6 @@ public AsuswrtRouterInfo(JsonObject jsonObject) { */ public void setAllData(JsonObject jsonObject) { setSysInfo(jsonObject); - setNetworkData(jsonObject); - setClientData(jsonObject); setUsageStats(jsonObject); } @@ -84,31 +80,12 @@ public void setSysInfo(JsonObject jsonObject) { this.productId = jsonObject.get(JSON_MEMBER_PRODUCTID).toString(); this.fwVersion = jsonObject.get(JSON_MEMBER_FIRMWARE).toString(); this.fwBuild = jsonObject.get(JSON_MEMBER_BUILD).toString(); - this.lanInfo.setData(jsonObject, CHANNEL_GROUP_SYSINFO); + this.macAddress = jsonObject.get(JSON_MEMBER_MAC).toString(); } catch (Exception e) { logger.trace("incomplete SysInfo"); } } - /** - * Set Network from jsonObject - * - * @param jsonObject with network data - */ - public void setNetworkData(JsonObject jsonObject) { - this.lanInfo.setData(jsonObject, CHANNEL_GROUP_LANINFO); - this.wanInfo.setData(jsonObject, CHANNEL_GROUP_WANINFO); - } - - /** - * Set ClientList from jsonObject - * - * @param jsonObject - */ - public void setClientData(JsonObject jsonObject) { - this.clientList.setData(jsonObject); - } - /** * Set UsageStats from jsonObject * @@ -150,19 +127,7 @@ public String getFirmwareVersion() { } public String getMAC() { - return this.lanInfo.getMAC(); - } - - public AsuswrtIpInfo getLanInfo() { - return this.lanInfo; - } - - public AsuswrtIpInfo getWanInfo() { - return this.wanInfo; - } - - public AsuswrtClientList getClients() { - return this.clientList; + return this.macAddress; } public AsuswrtUsage getMemUsage() { diff --git a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/things/AsuswrtClient.java b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/things/AsuswrtClient.java index 4680f392da279..231d788d484b6 100644 --- a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/things/AsuswrtClient.java +++ b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/things/AsuswrtClient.java @@ -89,23 +89,31 @@ public void handleCommand(ChannelUID channelUID, Command command) { } /** - * update clientpropedrties and channels + * update clientpropedrties * * @param clientInfo */ - public void clientPropertiesChanged(AsuswrtClientInfo clientInfo) { + public void updateClientProperties(AsuswrtClientInfo clientInfo) { logger.trace("({}) clientPropertiesChanged ", uid); Map 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); + } - updateState(getChannelID(CHANNEL_GROUP_CLIENT, CHANNEL_CLIENT_ONLINE), getOnOffType(clientInfo.isOnline())); - updateState(getChannelID(CHANNEL_GROUP_CLIENT, CHANNEL_CLIENT_INETSTATE), + /** + * Update Thing-Channels + * + * @param clientInfo + */ + public void updateChannels(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_CLIENT, CHANNEL_IP_ADDRESS), getStringType(clientInfo.getIP())); - updateState(getChannelID(CHANNEL_GROUP_CLIENT, CHANNEL_IP_METHOD), getStringType(clientInfo.getIpMethod())); + updateState(getChannelID(CHANNEL_GROUP_NETWORK, CHANNEL_NETWORK_IP), getStringType(clientInfo.getIP())); + updateState(getChannelID(CHANNEL_GROUP_NETWORK, CHANNEL_NETWORK_METHOD), + getStringType(clientInfo.getIpMethod())); } /** @@ -114,11 +122,11 @@ public void clientPropertiesChanged(AsuswrtClientInfo clientInfo) { * @param clientInfo */ private void fireEvents(AsuswrtClientInfo clientInfo) { - if (checkForStateChange(CHANNEL_CLIENT_ONLINE, clientInfo.isOnline())) { + if (checkForStateChange(CHANNEL_GROUP_NETWORK, clientInfo.isOnline())) { if (clientInfo.isOnline()) { - triggerChannel(getChannelID(CHANNEL_GROUP_CLIENT, EVENT_CLIENT_ONLINE), EVENT_STATE_CONNECTED); + triggerChannel(getChannelID(CHANNEL_GROUP_NETWORK, EVENT_CONNECTION), EVENT_STATE_CONNECTED); } else { - triggerChannel(getChannelID(CHANNEL_GROUP_CLIENT, EVENT_CLIENT_ONLINE), EVENT_STATE_GONE); + triggerChannel(getChannelID(CHANNEL_GROUP_NETWORK, EVENT_CONNECTION), EVENT_STATE_GONE); } } } @@ -128,9 +136,10 @@ private void fireEvents(AsuswrtClientInfo clientInfo) { */ private void refreshData() { String mac = getMac(); - AsuswrtClientInfo clientInfo = router.deviceInfo.getClients().getClientByMAC(mac); + AsuswrtClientInfo clientInfo = router.getClients().getClientByMAC(mac); fireEvents(clientInfo); - clientPropertiesChanged(clientInfo); + updateClientProperties(clientInfo); + updateChannels(clientInfo); } /*********************************** diff --git a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/things/AsuswrtInterface.java b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/things/AsuswrtInterface.java new file mode 100644 index 0000000000000..6859e9c4bbbcd --- /dev/null +++ b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/things/AsuswrtInterface.java @@ -0,0 +1,193 @@ +/** + * Copyright (c) 2010-2022 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.core.config.core.Configuration; +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; + +/** + * CLASS HANDLING ROUTER CLIENTS + * + * @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 oldStates = new HashMap<>(); + protected final String uid; + + /** + * Constructor + * + * @param thing Thing object representing client + * @param router Router (Bridge) Thing + */ + public AsuswrtInterface(Thing thing, AsuswrtRouter router) { + super(thing); + this.router = router; + this.uid = getThing().getUID().getAsString(); + } + + /*********************************** + * + * INIT AND SETTINGS + * + ************************************/ + + /** + * INITIALIZE DEVICE + */ + @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_REPRASENTATION_PROPERTY, ifName); + updateChannels(); + updateStatus(ThingStatus.ONLINE); + } else { + logger.debug("({}) configurtation error", uid); + } + } + + /*********************************** + * + * COMMAND AND EVENTS + * + ************************************/ + /** + * handle Commands + */ + @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); + updateInterfaceData(interfaceInfo); + } catch (Exception e) { + logger.debug("({}) unable to refresh data - property interfaceName not found ", uid); + } + } + + /** + * Update Network Channels + * + * @param deviceInfo + */ + private void updateInterfaceData(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())); + } + + /** + * fire events when new informations changed + * + * @param clientInfo + */ + 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 + * + ************************************/ + + /** + * 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_NETWORK + "#", ""); + return channel; + } + + /** + * Check if state changed since last channel update + * + * @param stateName name of state (channel) + * @param comparator comparation value + * @return true if changed, false if not or no old value existds + */ + 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; + } +} diff --git a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/things/AsuswrtRouter.java b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/things/AsuswrtRouter.java index 539e31e3747ee..a32dbfc09fd52 100644 --- a/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/things/AsuswrtRouter.java +++ b/bundles/org.openhab.binding.asuswrt/src/main/java/org/openhab/binding/asuswrt/internal/things/AsuswrtRouter.java @@ -18,7 +18,6 @@ import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ScheduledFuture; @@ -33,6 +32,7 @@ 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; @@ -69,13 +69,15 @@ public class AsuswrtRouter extends BaseBridgeHandler { private @Nullable ScheduledFuture reconnectJob; private @Nullable ScheduledFuture discoveryJob; private @NonNullByDefault({}) AsuswrtDiscoveryService discoveryService; - private Map oldStates = new HashMap<>(); + 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; - private AsuswrtConfiguration config; - private AsuswrtConnector connector; + public AsuswrtErrorHandler errorHandler; - public AsuswrtRouterInfo deviceInfo; /** * INIT CLASS @@ -87,10 +89,9 @@ public AsuswrtRouter(Bridge bridge, HttpClient httpClient) { Thing thing = getThing(); this.uid = thing.getUID().toString(); this.errorHandler = new AsuswrtErrorHandler(); - this.config = new AsuswrtConfiguration(); this.httpClient = httpClient; - this.connector = new AsuswrtConnector(this); this.deviceInfo = new AsuswrtRouterInfo(); + this.config = new AsuswrtConfiguration(); } /*********************************** @@ -101,6 +102,7 @@ public AsuswrtRouter(Bridge bridge, HttpClient httpClient) { @Override public void initialize() { this.config = getConfigAs(AsuswrtConfiguration.class); + this.connector = new AsuswrtConnector(this); // Initialize the handler. setState(ThingStatus.UNKNOWN); @@ -152,13 +154,14 @@ private void delayedStartUp() { */ 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 : {}", this.getUID(), pollingInterval); + logger.trace("({}) start polling scheduler with interval {} {}", this.getUID(), pollingInterval, timeUnit); this.pollingJob = scheduler.scheduleWithFixedDelay(this::pollingJobAction, pollingInterval, pollingInterval, - TimeUnit.SECONDS); + timeUnit); } else { stopScheduler(this.pollingJob); } @@ -178,12 +181,12 @@ protected void pollingJobAction() { */ 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 with interval : {}", this.getUID(), pollingInterval); - this.reconnectJob = scheduler.scheduleWithFixedDelay(this::reconnectJobAction, pollingInterval, pollingInterval, - TimeUnit.SECONDS); + logger.trace("({}) start reconnect scheduler in {} {}", this.getUID(), pollingInterval, timeUnit); + this.reconnectJob = scheduler.schedule(this::reconnectJobAction, pollingInterval, timeUnit); } /** @@ -198,11 +201,12 @@ protected void reconnectJobAction() { */ protected void startDiscoveryScheduler() { int pollingInterval = config.discoveryInterval; + TimeUnit timeUnit = TimeUnit.SECONDS; if (config.autoDiscoveryEnabled && pollingInterval > 0) { - logger.trace("{} starting bridge discovery sheduler", this.uid); - + logger.trace("{} starting bridge discovery sheduler with interval {} {}", this.getUID(), pollingInterval, + timeUnit); this.discoveryJob = scheduler.scheduleWithFixedDelay(discoveryService::startScan, 0, pollingInterval, - TimeUnit.MINUTES); + timeUnit); } else { stopScheduler(this.discoveryJob); } @@ -230,9 +234,10 @@ protected void stopScheduler(@Nullable ScheduledFuture scheduler) { /** * Connect to router and set states */ + @SuppressWarnings("null") protected void connect() { connector.login(); - if (connector.isValidLogin()) { + if (connector.cookieStore.cookieIsSet()) { stopScheduler(reconnectJob); queryDeviceData(false); devicePropertiesChanged(this.deviceInfo); @@ -248,6 +253,7 @@ protected void connect() { * * @param asyncRequest */ + @SuppressWarnings("null") public void queryDeviceData(Boolean asyncRequest) { connector.queryDeviceData( CMD_GET_SYSINFO + CMD_GET_USAGE + CMD_GET_LANINFO + CMD_GET_WANINFO + CMD_GET_CLIENTLIST, asyncRequest); @@ -268,17 +274,21 @@ public void queryDeviceData() { * @param command */ public void dataReceived(JsonObject jsonObject, String command) { - fireEvents(deviceInfo); if (command.contains(CMD_GET_SYSINFO)) { deviceInfo.setSysInfo(jsonObject); devicePropertiesChanged(deviceInfo); } if (command.contains(CMD_GET_CLIENTLIST)) { - deviceInfo.setClientData(jsonObject); - updateClientThings(deviceInfo.getClients()); + clientList.setData(jsonObject); + updateClients(); } - if (command.contains(CMD_GET_LANINFO) || command.contains(CMD_GET_WANINFO)) { - this.deviceInfo.setNetworkData(jsonObject); + if (command.contains(CMD_GET_LANINFO)) { + interfaceList.setData(INTERFACE_LAN, jsonObject); + updateChild(THING_TYPE_INTERFACE, NETWORK_REPRASENTATION_PROPERTY, INTERFACE_LAN); + } + if (command.contains(CMD_GET_WANINFO)) { + interfaceList.setData(INTERFACE_WAN, jsonObject); + updateChild(THING_TYPE_INTERFACE, NETWORK_REPRASENTATION_PROPERTY, INTERFACE_WAN); } if (command.contains(CMD_GET_USAGE) || command.contains(CMD_GET_MEMUSAGE) || command.contains(CMD_GET_CPUUSAGE)) { @@ -297,11 +307,11 @@ public void dataReceived(JsonObject jsonObject, String command) { public void setState(ThingStatus thingStatus, ThingStatusDetail statusDetail, String text) { if (!thingStatus.equals(getThing().getStatus())) { updateStatus(thingStatus, statusDetail, text); - updateClientStates(thingStatus); + updateChildStates(thingStatus); if (thingStatus.equals(ThingStatus.OFFLINE)) { + stopScheduler(this.pollingJob); /* set channels to undef */ getThing().getChannels().forEach(c -> updateState(c.getUID(), UnDefType.UNDEF)); - stopScheduler(this.pollingJob); startReconnectScheduler(); } } @@ -342,6 +352,14 @@ public AsuswrtRouterInfo getDeviceInfo() { return this.deviceInfo; } + public AsuswrtClientList getClients() { + return this.clientList; + } + + public AsuswrtInterfaceList getInterfaces() { + return this.interfaceList; + } + public ThingStatus getState() { return getThing().getStatus(); } @@ -375,7 +393,7 @@ public void handleCommand(ChannelUID channelUID, Command command) { public void devicePropertiesChanged(AsuswrtRouterInfo deviceInfo) { /* device properties */ Map properties = editProperties(); - properties.put(Thing.PROPERTY_MAC_ADDRESS, deviceInfo.getMAC()); + 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); @@ -383,7 +401,7 @@ public void devicePropertiesChanged(AsuswrtRouterInfo deviceInfo) { /*********************************** * - * CHANNELS / CLIENTS + * CHANNELS * ************************************/ @@ -393,7 +411,6 @@ public void devicePropertiesChanged(AsuswrtRouterInfo deviceInfo) { * @param deviceInfo */ public void updateChannels(AsuswrtRouterInfo deviceInfo) { - updateNetworkChannels(deviceInfo); updateClientChannels(deviceInfo); updateUsageChannels(deviceInfo); } @@ -418,39 +435,6 @@ public void updateUsageChannels(AsuswrtRouterInfo deviceInfo) { getQuantityType(deviceInfo.getCpuAverage().getUsedPercent(), Units.PERCENT)); } - /** - * Update Network Channels - * - * @param deviceInfo - */ - public void updateNetworkChannels(AsuswrtRouterInfo deviceInfo) { - /* lanInfo */ - updateState(getChannelID(CHANNEL_GROUP_LANINFO, CHANNEL_IP_ADDRESS), - getStringType(deviceInfo.getLanInfo().getIpAddress())); - updateState(getChannelID(CHANNEL_GROUP_LANINFO, CHANNEL_SUBNET), - getStringType(deviceInfo.getLanInfo().getSubnet())); - updateState(getChannelID(CHANNEL_GROUP_LANINFO, CHANNEL_GATEWAY), - getStringType(deviceInfo.getLanInfo().getGateway())); - updateState(getChannelID(CHANNEL_GROUP_LANINFO, CHANNEL_MAC_ADDRESS), - getStringType(deviceInfo.getLanInfo().getMAC())); - updateState(getChannelID(CHANNEL_GROUP_LANINFO, CHANNEL_IP_METHOD), - getStringType(deviceInfo.getLanInfo().getIpProto())); - - /* wanInfo */ - updateState(getChannelID(CHANNEL_GROUP_WANINFO, CHANNEL_IP_ADDRESS), - getStringType(deviceInfo.getWanInfo().getIpAddress())); - updateState(getChannelID(CHANNEL_GROUP_WANINFO, CHANNEL_SUBNET), - getStringType(deviceInfo.getWanInfo().getSubnet())); - updateState(getChannelID(CHANNEL_GROUP_WANINFO, CHANNEL_GATEWAY), - getStringType(deviceInfo.getWanInfo().getGateway())); - updateState(getChannelID(CHANNEL_GROUP_WANINFO, CHANNEL_IP_METHOD), - getStringType(deviceInfo.getWanInfo().getIpProto())); - updateState(getChannelID(CHANNEL_GROUP_WANINFO, CHANNEL_WAN_DNS_SERVER), - getStringType(deviceInfo.getWanInfo().getDNSNServer())); - updateState(getChannelID(CHANNEL_GROUP_WANINFO, CHANNEL_WAN_STATUS), - getOnOffType(deviceInfo.getWanInfo().isConnected())); - } - /** * Update Client Channel * @@ -458,74 +442,112 @@ public void updateNetworkChannels(AsuswrtRouterInfo deviceInfo) { */ public void updateClientChannels(AsuswrtRouterInfo deviceInfo) { updateState(getChannelID(CHANNEL_GROUP_CLIENTS, CHANNEL_CLIENTS_KNOWN), - getStringType(deviceInfo.getClients().getClientList())); + getStringType(clientList.getClientList())); updateState(getChannelID(CHANNEL_GROUP_CLIENTS, CHANNEL_CLIENTS_ONLINE), - getStringType(deviceInfo.getClients().getOnlineClients().getClientList())); + 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(deviceInfo.getClients().getOnlineClients().getMacAddresses())); + getStringType(clientList.getOnlineClients().getMacAddresses())); } + /*********************************** + * + * CHILD THINGS + * + ************************************/ /** - * fire events when new clientInformations changed + * Update all Child-Things with type Client * - * @param clientInfo + * @param AsuswrtRouterInfo */ - public void fireEvents(AsuswrtRouterInfo deviceInfo) { - Boolean isConnected = deviceInfo.getWanInfo().isConnected(); - if (checkForStateChange(CHANNEL_WAN_STATUS, isConnected)) { - if (isConnected) { - triggerChannel(getChannelID(CHANNEL_GROUP_WANINFO, EVENT_CONNECTION), EVENT_STATE_CONNECTED); - } else { - triggerChannel(getChannelID(CHANNEL_GROUP_WANINFO, EVENT_CONNECTION), EVENT_STATE_DISCONNECTED); - } - } + public void updateClients() { + updateChildThings(THING_TYPE_CLIENT); } /** - * UPDATE ALL CLIENT THINGS + * Update all Child-Things with type Interface * - * @param AsuswrtRouterInfo + * @param routerInfo */ - public void updateClients(AsuswrtRouterInfo routerInfo) { - updateClientThings(routerInfo.getClients()); + public void updateInterfaces() { + updateChildThings(THING_TYPE_INTERFACE); } /** - * UPDATE ALL CLIENT THINGS + * Update all Child-Things belonging to ThingTypeUID * * @param clientList AsuswrtClientList */ - public void updateClientThings(AsuswrtClientList clientList) { + public void updateChildThings(ThingTypeUID thingTypeToUpdate) { ThingTypeUID thingTypeUID; List things = getThing().getThings(); for (Thing thing : things) { thingTypeUID = thing.getThingTypeUID(); - ThingUID thingUID = thing.getUID(); - if (THING_TYPE_CLIENT.equals(thingTypeUID)) { - ChannelUID cuid = new ChannelUID(thingUID, CHANNEL_GROUP_CLIENT); - ThingHandler handler = thing.getHandler(); - if (handler != null) { - handler.handleCommand(cuid, RefreshType.REFRESH); + 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 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 updateClientStates(ThingStatus thingStatus) { + public void updateChildStates(ThingStatus thingStatus) { List things = getThing().getThings(); for (Thing thing : things) { - 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, "")); - } + 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, "")); } } } @@ -560,24 +582,7 @@ protected String getChannelID(String group, String channel) { protected String getChannelFromID(ChannelUID channelID) { String channel = channelID.getIdWithoutGroup(); channel = channel.replace(CHANNEL_GROUP_SYSINFO + "#", ""); - channel = channel.replace(CHANNEL_GROUP_LANINFO + "#", ""); + channel = channel.replace(CHANNEL_GROUP_CLIENTS + "#", ""); return channel; } - - /** - * Check if state changed since last channel update - * - * @param stateName name of state (channel) - * @param comparator comparation value - * @return true if changed, false if not or no old value existds - */ - 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; - } } diff --git a/bundles/org.openhab.binding.asuswrt/src/main/resources/OH-INF/thing/channels.xml b/bundles/org.openhab.binding.asuswrt/src/main/resources/OH-INF/thing/channels.xml index ae85283eaffa6..b4172b45774e1 100644 --- a/bundles/org.openhab.binding.asuswrt/src/main/resources/OH-INF/thing/channels.xml +++ b/bundles/org.openhab.binding.asuswrt/src/main/resources/OH-INF/thing/channels.xml @@ -95,6 +95,12 @@ List with mac-addresses of online clients + + Number:Dimensionless + + number online clients + + String diff --git a/bundles/org.openhab.binding.asuswrt/src/main/resources/OH-INF/thing/client.xml b/bundles/org.openhab.binding.asuswrt/src/main/resources/OH-INF/thing/client.xml index 22659651fb4c8..18b30da242a71 100644 --- a/bundles/org.openhab.binding.asuswrt/src/main/resources/OH-INF/thing/client.xml +++ b/bundles/org.openhab.binding.asuswrt/src/main/resources/OH-INF/thing/client.xml @@ -13,11 +13,11 @@ Client connected to Asuswrt-Rotuer - + Vendor - DNS Name + DNS Name macAddress @@ -36,17 +36,17 @@ - + Clients connected to router - + Client IP-Address - + diff --git a/bundles/org.openhab.binding.asuswrt/src/main/resources/OH-INF/thing/interface.xml b/bundles/org.openhab.binding.asuswrt/src/main/resources/OH-INF/thing/interface.xml new file mode 100644 index 0000000000000..5a0712f6c1150 --- /dev/null +++ b/bundles/org.openhab.binding.asuswrt/src/main/resources/OH-INF/thing/interface.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + Interface of Router + + + + interfaceName + + + + + Name of selected interface. *Maybe not all are supported by your device* + + + + + + + + + + + + + + + LAN connection state + + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.asuswrt/src/main/resources/OH-INF/thing/router.xml b/bundles/org.openhab.binding.asuswrt/src/main/resources/OH-INF/thing/router.xml index d9e741355cc1d..b76da54d86f4a 100644 --- a/bundles/org.openhab.binding.asuswrt/src/main/resources/OH-INF/thing/router.xml +++ b/bundles/org.openhab.binding.asuswrt/src/main/resources/OH-INF/thing/router.xml @@ -10,8 +10,6 @@ Router with asuswrt or asuswrt-merlin OS - - @@ -31,6 +29,23 @@ Password to access the device + + + Use SSL to authenticate. If not use http + false + + + + Port used for HTTP-connection + 80 + true + + + + Port used for HTTPS-connection + 443 + true + Interval the device is polled in sec. @@ -73,34 +88,6 @@ - - - - LAN connection state - - - - - - - - - - - - - WAN connection state - - - - - - - - - - - @@ -114,6 +101,7 @@ Online Clients with Name and MAC-Addresses + diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/TapoControlHandlerFactory.java b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/TapoControlHandlerFactory.java index f24fda61759ae..da38ba61b841c 100644 --- a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/TapoControlHandlerFactory.java +++ b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/TapoControlHandlerFactory.java @@ -56,7 +56,8 @@ public class TapoControlHandlerFactory extends BaseThingHandlerFactory { @Activate public TapoControlHandlerFactory() { // create new httpClient - httpClient = new HttpClient(new SslContextFactory.Client()); + SslContextFactory.Client sslContextFactory = new SslContextFactory.Client(); + httpClient = new HttpClient(sslContextFactory); httpClient.setFollowRedirects(false); httpClient.setMaxConnectionsPerDestination(HTTP_MAX_CONNECTIONS); httpClient.setMaxRequestsQueuedPerDestination(HTTP_MAX_QUEUED_REQUESTS);