From 6411ce8c1962656017bfd2b09279999606e92210 Mon Sep 17 00:00:00 2001 From: Ricardo Larranaga Date: Fri, 3 Mar 2023 14:32:40 -0400 Subject: [PATCH 1/9] Initial Contribution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ricardo Larrañaga Signed-off-by: Ricardo Larranaga --- CODEOWNERS | 1 + bom/openhab-addons/pom.xml | 5 + bundles/org.openhab.binding.broadlink/NOTICE | 13 + .../org.openhab.binding.broadlink/README.md | 126 ++++++++ bundles/org.openhab.binding.broadlink/pom.xml | 26 ++ .../src/main/feature/feature.xml | 9 + .../broadlink/BroadlinkBindingConstants.java | 107 +++++++ .../config/BroadlinkDeviceConfiguration.java | 127 ++++++++ .../broadlink/handler/BroadlinkA1Handler.java | 64 ++++ .../handler/BroadlinkBaseThingHandler.java | 292 ++++++++++++++++++ .../handler/BroadlinkRemoteHandler.java | 192 ++++++++++++ .../handler/BroadlinkRemoteModel2Handler.java | 55 ++++ .../handler/BroadlinkRemoteModel3Handler.java | 31 ++ .../BroadlinkRemoteModel3V44057Handler.java | 35 +++ .../handler/BroadlinkRemoteModel4Handler.java | 101 ++++++ .../handler/BroadlinkSocketHandler.java | 50 +++ .../handler/BroadlinkSocketModel1Handler.java | 38 +++ .../handler/BroadlinkSocketModel2Handler.java | 124 ++++++++ .../handler/BroadlinkSocketModel3Handler.java | 80 +++++ .../BroadlinkSocketModel3SHandler.java | 74 +++++ .../BroadlinkStripModel11K3S2UHandler.java | 133 ++++++++ .../handler/BroadlinkStripModel1Handler.java | 132 ++++++++ .../handler/BroadlinkStripModel2Handler.java | 29 ++ .../internal/BroadlinkBindingConstants.java | 34 ++ .../internal/BroadlinkHandlerFactory.java | 116 +++++++ .../internal/BroadlinkMappingService.java | 154 +++++++++ .../broadlink/internal/BroadlinkProtocol.java | 211 +++++++++++++ ...moteDynamicCommandDescriptionProvider.java | 39 +++ .../broadlink/internal/ModelMapper.java | 158 ++++++++++ .../broadlink/internal/NetworkUtils.java | 114 +++++++ .../binding/broadlink/internal/Utils.java | 101 ++++++ .../discovery/BroadlinkDiscoveryService.java | 108 +++++++ .../discovery/DeviceRediscoveryAgent.java | 72 +++++ .../discovery/DeviceRediscoveryListener.java | 27 ++ .../discovery/DiscoveryFinishedListener.java | 25 ++ .../internal/discovery/DiscoveryProtocol.java | 85 +++++ .../internal/socket/BroadlinkSocket.java | 157 ++++++++++ .../socket/BroadlinkSocketListener.java | 28 ++ .../socket/NetworkTrafficObserver.java | 28 ++ .../internal/socket/RetryableSocket.java | 119 +++++++ .../main/resources/OH-INF/binding/binding.xml | 8 + .../main/resources/OH-INF/config/config.xml | 53 ++++ .../resources/OH-INF/config/rm-config.xml | 59 ++++ .../OH-INF/i18n/broadlink_xx.properties | 21 ++ .../main/resources/OH-INF/thing/a-types.xml | 21 ++ .../main/resources/OH-INF/thing/channels.xml | 69 +++++ .../main/resources/OH-INF/thing/mp-types.xml | 58 ++++ .../main/resources/OH-INF/thing/rm-types.xml | 50 +++ .../main/resources/OH-INF/thing/sp-types.xml | 57 ++++ .../resources/OH-INF/thing/thing-types.xml | 46 +++ .../broadlink/AbstractBroadlinkTest.java | 43 +++ .../AbstractBroadlinkThingHandlerTest.java | 83 +++++ .../BroadlinkRemoteModel2HandlerTest.java | 147 +++++++++ .../BroadlinkRemoteModel3HandlerTest.java | 88 ++++++ .../BroadlinkRemoteModel4HandlerTest.java | 233 ++++++++++++++ .../BroadlinkSocketModel2HandlerTest.java | 172 +++++++++++ .../BroadlinkSocketModel3HandlerTest.java | 142 +++++++++ .../BroadlinkSocketModel3SHandlerTest.java | 119 +++++++ .../internal/BroadlinkMappingServiceTest.java | 58 ++++ .../internal/BroadlinkProtocolTest.java | 59 ++++ .../broadlink/internal/ModelMapperTest.java | 85 +++++ .../binding/broadlink/internal/UtilsTest.java | 95 ++++++ .../resources/conf/transform/broadlink.map | 3 + bundles/pom.xml | 1 + 64 files changed, 5190 insertions(+) create mode 100644 bundles/org.openhab.binding.broadlink/NOTICE create mode 100644 bundles/org.openhab.binding.broadlink/README.md create mode 100644 bundles/org.openhab.binding.broadlink/pom.xml create mode 100644 bundles/org.openhab.binding.broadlink/src/main/feature/feature.xml create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/BroadlinkBindingConstants.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/config/BroadlinkDeviceConfiguration.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkA1Handler.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkBaseThingHandler.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteHandler.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel2Handler.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3Handler.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3V44057Handler.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4Handler.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketHandler.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel1Handler.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel2Handler.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3Handler.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandler.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkStripModel11K3S2UHandler.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkStripModel1Handler.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkStripModel2Handler.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkBindingConstants.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkHandlerFactory.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkMappingService.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkProtocol.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkRemoteDynamicCommandDescriptionProvider.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/ModelMapper.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/NetworkUtils.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/Utils.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/BroadlinkDiscoveryService.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DeviceRediscoveryAgent.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DeviceRediscoveryListener.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DiscoveryFinishedListener.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DiscoveryProtocol.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/BroadlinkSocket.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/BroadlinkSocketListener.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/NetworkTrafficObserver.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/RetryableSocket.java create mode 100644 bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/binding/binding.xml create mode 100644 bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/config/config.xml create mode 100644 bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/config/rm-config.xml create mode 100644 bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/i18n/broadlink_xx.properties create mode 100644 bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/thing/a-types.xml create mode 100644 bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/thing/channels.xml create mode 100644 bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/thing/mp-types.xml create mode 100644 bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/thing/rm-types.xml create mode 100644 bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/thing/sp-types.xml create mode 100644 bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/thing/thing-types.xml create mode 100644 bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/AbstractBroadlinkTest.java create mode 100644 bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/AbstractBroadlinkThingHandlerTest.java create mode 100644 bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel2HandlerTest.java create mode 100644 bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3HandlerTest.java create mode 100644 bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4HandlerTest.java create mode 100644 bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel2HandlerTest.java create mode 100644 bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3HandlerTest.java create mode 100644 bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandlerTest.java create mode 100644 bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/BroadlinkMappingServiceTest.java create mode 100644 bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/BroadlinkProtocolTest.java create mode 100644 bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/ModelMapperTest.java create mode 100644 bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/UtilsTest.java create mode 100644 bundles/org.openhab.binding.broadlink/src/test/resources/conf/transform/broadlink.map diff --git a/CODEOWNERS b/CODEOWNERS index 69fc52c11ce4e..a8220146263a5 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -49,6 +49,7 @@ /bundles/org.openhab.binding.boschindego/ @jofleck @jlaur /bundles/org.openhab.binding.boschshc/ @stefan-kaestle @coeing @GerdZanker /bundles/org.openhab.binding.bosesoundtouch/ @marvkis @tratho +/bundles/org.openhab.binding.broadlink/ @themillhousegorup @rlarranaga /bundles/org.openhab.binding.broadlinkthermostat/ @flo-02-mu /bundles/org.openhab.binding.bsblan/ @hypetsch /bundles/org.openhab.binding.bticinosmarther/ @MrRonfo diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml index 28893eca65d64..cd0f0902cab2f 100644 --- a/bom/openhab-addons/pom.xml +++ b/bom/openhab-addons/pom.xml @@ -241,6 +241,11 @@ org.openhab.binding.bosesoundtouch ${project.version} + + org.openhab.addons.bundles + org.openhab.binding.broadlink + ${project.version} + org.openhab.addons.bundles org.openhab.binding.broadlinkthermostat diff --git a/bundles/org.openhab.binding.broadlink/NOTICE b/bundles/org.openhab.binding.broadlink/NOTICE new file mode 100644 index 0000000000000..38d625e349232 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/NOTICE @@ -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 diff --git a/bundles/org.openhab.binding.broadlink/README.md b/bundles/org.openhab.binding.broadlink/README.md new file mode 100644 index 0000000000000..6928d4613587e --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/README.md @@ -0,0 +1,126 @@ +# Broadlink Binding + +This binding supports a range of home networking devices made by (and occasionally OEM licensed from) [Broadlink](https://www.ibroadlink.com/). + +## Supported Things + +| Thing ID | Description | +|------------|-------------------------------------------------------------------------| +| a1 | Broadlink A1 multi sensor | +| mp1 | Broadlink MP1 WiFi Smart Power Strip (4 sockets) | +| mp1_1k3s2u | Broadlink MP1 1K3S2U WiFi Smart Power Strip (3 sockets, 2 USB) | +| mp2 | Broadlink MP2 WiFi Smart Power Strip (3 sockets, 3 USB) | +| sp1 | Broadlink SP1 WiFi Smart Socket | +| sp2 | Broadlink SP2 WiFi Smart Socket with night light | +| sp3 | Broadlink SP3/Mini WiFi Smart Socket with night light | +| sp3s | Broadlink SP3s WiFi Smart Socket with Power Meter | +| rm2 | Broadline RM2/Pro WiFi IR/RF Transmitter with temperature sensor | +| rm3 | Broadlink RM3/Mini WiFi IR Transmitter | +| rm3q | Broadlink RM3 WiFi IR Transmitter with Firmware v44057 | +| rm4 | Broadlink RM4 WiFi IR Transmitter with temperature and humidity sensors | + +## Discovery + +Devices in the above list that are set up and working in the Broadlink mobile app should be discoverable by initiating a discovery from the openHAB UI. + +> The `Lock Device` setting must be switched off for your device via the Broadlink app to be discoverable in openHAB. + +## Thing Configuration + +| Name | Type | Default | description | +|---------------------|---------|---------------|-----------------------------------------------------------------------------------| +| ipAddress | String | | Sets the IP address of the Broadlink device | +| staticIp | Boolean | true | Enabled if your broadlink device has a Static IP set | +| port | Integer | 80 | The network port for the device | +| macAddress | String | | The device's MAC Address | +| pollingInterval | Integer | 30 | The interval in seconds for polling the status of the device | +| ignoreFailedUpdates | Boolean | false | If enabled, failed status requests won't put the device `OFFLINE` | +| mapFilename | String | broadlink.map | The map file that contains remote codes to send via IR | + +> The `mapFilename` setting is applicable to the RM series of devices only. + +## Channels + +| Channel | Supported Devices | Type | Description | +|------------------|--------------------------|----------------------|-------------------------------------------------| +| powerOn | MP2, all SPx | Switch | Power on/off for switches/strips | +| nightLight | SP3 | Switch | Night light on/off | +| temperature | A1, RM2, RM4 | Number:Temperature | Temperature | +| humidity | A1, RM4 | Number:Dimensionless | Air humidity percentage | +| noise | A1 | String | Noise level: `QUIET`/`NORMAL`/`NOISY`/`EXTREME` | +| light | A1 | String | Light level: `DARK`/`DIM`/`NORMAL`/`BRIGHT` | +| air | A1 | String | Air quality: `PERFECT`/`GOOD`/`NORMAL`/`BAD` | +| s1powerOn | MP1, MP1_1k3s2u | Switch | Socket 1 power | +| s2powerOn | MP1, MP1_1k3s2u | Switch | Socket 2 power | +| s3powerOn | MP1, v_1k3s2u | Switch | Socket 3 power | +| s4powerOn | MP1 | Switch | Socket 4 power | +| usbPowerOn | MP1_1k3s2u | Switch | USB power | +| powerConsumption | MP2, SP2s,SP3s | Number:Power | Power consumption | +| command | all RMx | String | IR Command code to transmit | +| learningControl | all RMx | String | Learn mode command channel (see below) | + +## Map File + +The Broadlink RM family of devices can transmit IR codes. +The map file contains a list of IR command codes to send via the device. +The file uses the [Java Properties File format](https://en.wikipedia.org/wiki/.properties) and is stored in the `/transform` folder. +By default, the file name is `broadlink.map` but can be changed using the `mapFile` setting. + +Here is a map file example: + +``` +TV_POWER=26008c0092961039103a1039101510151014101510151039103a10391015101411141015101510141139101510141114101510151014103a10141139103911391037123a10391000060092961039103911391014111410151015101411391039103a101411141015101510141015103911141015101510141015101510391015103911391039103a1039103911000d05000000000000000000000000 +heatpump_off=2600760069380D0C0D0C0D290D0C0D290D0C0D0C0D0C0D290D290D0C0D0C0D0C0D290D290D0C0D0C0D0C0D0C0D0C0D0C0D0C0D0C0D0C0D0C0D0C0D0C0D0C0D290D0C0D0C0D0C0D0C0D0C0D0C0D0C0D290D0C0D0C0D0C0D0C0D290D0C0D0C0D0C0D0C0D0C0D0C0D290D0C0D290D290D290D290D290D290E0002900000 + +``` + +The above codes are power on/off for Samsung TVs and Power Off for a Fujitsu heat pump. +To send either code, the string `TV_POWER` or `heatpump_off` must be sent to the `command` channel for the device. + +## Learning new remote codes + +To obtain the command codes, you can get this binding to put your Broadlink RMx device into +"learn mode" and then ask it for the code it learnt. Here are the steps: + +1. In the openHAB web UI, navigate to your RMx Thing, and click on its *Channels* tab +2. Find the *Remote Learning Control* channel and create an Item for it +3. Click the item, and click the rectangular area that is marked NULL +4. In the pop-up menu that appears, select "Enter infrared learn mode" +5. *The LED on your RM device will illuminate solidly* +6. Point your IR remote control at your RM device and press the button you'd like to learn +7. *The LED on your RM device will extinguish once it has learnt the command* +8. Now click the rectangular area again (which will now show "Enter infrared learn mode") +9. Select the "Check last captured IR code" menu option in the pop-up menu +10. Inspect the `openhab.log` file on your openHAB server - you should see the following: + +``` +[BroadlinkRemoteHandler] - BEGIN LAST LEARNT CODE (976 bytes) +[BroadlinkRemoteHandler] - 2600bc017239100d0e2b0e0f100c107f55747be51a3e1d4ff4......f5be8b3d4ff4b +4d77c44d105fa530546becaa2bcfbd348b30145447f55747be51a3747be51a3e1d4ff4b3f4f4f......a3e1d4ff4b348 +0145447f55747be51a3e1d4ff4b +[BroadlinkRemoteHandler] - END LAST LEARNT CODE (1944 characters) +``` + +11. If you carefully copy the log line between the `BEGIN` and `END` messages, + it should have exactly the number of characters as advised in the `END` message. + +12. You can now paste a new entry into your `map` file, with the name of your choice; for example: + +``` +BLURAY_ON=2600bc017239100d0e2b0e0f100c107f55747be51a3e1d4ff4...0145447f55747be51a3e1d4ff4b +``` + + +## Full Example + +Items file example; `sockets.items`: + +``` +Switch BroadlinkSP3 "Christmas Lights" [ "Lighting" ] { channel="broadlink:sp3:34-ea-34-22-44-66:powerOn" } +``` + +## Credits + +- [Cato Sognen](https://community.openhab.org/u/cato_sognen) +- [JAD](http://www.javadecompilers.com/jad) (Java Decompiler) + diff --git a/bundles/org.openhab.binding.broadlink/pom.xml b/bundles/org.openhab.binding.broadlink/pom.xml new file mode 100644 index 0000000000000..af5691ff44b1a --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/pom.xml @@ -0,0 +1,26 @@ + + + + 4.0.0 + + + org.openhab.addons.bundles + org.openhab.addons.reactor.bundles + 3.4.3-SNAPSHOT + + + org.openhab.binding.broadlink + + openHAB Add-ons :: Bundles :: Broadlink Binding + + + + junit + junit + 4.13 + test + + + + diff --git a/bundles/org.openhab.binding.broadlink/src/main/feature/feature.xml b/bundles/org.openhab.binding.broadlink/src/main/feature/feature.xml new file mode 100644 index 0000000000000..397452eb63161 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/feature/feature.xml @@ -0,0 +1,9 @@ + + + mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features + + + openhab-runtime-base + mvn:org.openhab.addons.bundles/org.openhab.binding.broadlink/${project.version} + + diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/BroadlinkBindingConstants.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/BroadlinkBindingConstants.java new file mode 100644 index 0000000000000..5a6d3ed362830 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/BroadlinkBindingConstants.java @@ -0,0 +1,107 @@ +/** + * 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.broadlink; + +import java.util.HashMap; +import java.util.Map; + +import javax.measure.Unit; +import javax.measure.quantity.Dimensionless; +import javax.measure.quantity.Power; +import javax.measure.quantity.Temperature; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.library.unit.SIUnits; +import org.openhab.core.library.unit.Units; +import org.openhab.core.thing.ThingTypeUID; + +/** + * The {@link BroadlinkBindingConstants} class defines common constants, which are + * used across the whole binding. + * + * @author John Marshall/Cato Sognen - Initial contribution + */ +@NonNullByDefault +public class BroadlinkBindingConstants { + + public static final ThingTypeUID THING_TYPE_RM2 = new ThingTypeUID("broadlink", "rm2"); + public static final ThingTypeUID THING_TYPE_RM3 = new ThingTypeUID("broadlink", "rm3"); + public static final ThingTypeUID THING_TYPE_RM3Q = new ThingTypeUID("broadlink", "rm3q"); + public static final ThingTypeUID THING_TYPE_RM4 = new ThingTypeUID("broadlink", "rm4"); + public static final ThingTypeUID THING_TYPE_A1 = new ThingTypeUID("broadlink", "a1"); + public static final ThingTypeUID THING_TYPE_MP1 = new ThingTypeUID("broadlink", "mp1"); + public static final ThingTypeUID THING_TYPE_MP1_1K3S2U = new ThingTypeUID("broadlink", "mp1_1k3s2u"); + public static final ThingTypeUID THING_TYPE_MP2 = new ThingTypeUID("broadlink", "mp2"); + public static final ThingTypeUID THING_TYPE_SP1 = new ThingTypeUID("broadlink", "sp1"); + public static final ThingTypeUID THING_TYPE_SP2 = new ThingTypeUID("broadlink", "sp2"); + public static final ThingTypeUID THING_TYPE_SP2S = new ThingTypeUID("broadlink", "sp2s"); + public static final ThingTypeUID THING_TYPE_SP3 = new ThingTypeUID("broadlink", "sp3"); + public static final ThingTypeUID THING_TYPE_SP3S = new ThingTypeUID("broadlink", "sp3s"); + public static final ThingTypeUID THING_TYPE_PIR = new ThingTypeUID("broadlink", "s1p"); + public static final ThingTypeUID THING_TYPE_MAGNET = new ThingTypeUID("broadlink", "s1m"); + + public static final String RM2 = "Broadlink RM2"; + public static final String RM3 = "Broadlink RM3"; + public static final String RM3Q = "Broadlink RM3 v11057"; + public static final String RM4 = "Broadlink RM4 / RM4 Mini / RM4 Pro"; + public static final String A1 = "Broadlink A1"; + public static final String MP1 = "Broadlink MP1"; + public static final String MP1_1K3S2U = "Broadlink MP1 1K3S2U"; + public static final String MP2 = "Broadlink MP2"; + + public static final String SP1 = "Broadlink SP1"; + public static final String SP2 = "Broadlink SP2"; + public static final String SP2S = "Broadlink SP2s"; + public static final String SP3 = "Broadlink SP3"; + public static final String SP3S = "Broadlink SP3s"; + public static final String S1P = "Smart One PIR Sensor"; + public static final String S1M = "Smart One Magnet Sensor"; + + public static final String BROADLINK_AUTH_KEY = "097628343fe99e23765c1513accf8b02"; + public static final String BROADLINK_IV = "562e17996d093d28ddb3ba695a2e6f58"; + + public static final String COMMAND_CHANNEL = "command"; + public static final String LEARNING_CONTROL_CHANNEL = "learningControl"; + public static final String LEARNING_CONTROL_COMMAND_LEARN = "LEARN"; + public static final String LEARNING_CONTROL_COMMAND_CHECK = "CHECK"; + public static final String CHANNEL_TEMPERATURE = "temperature"; + public static final String CHANNEL_HUMIDITY = "humidity"; + public static final String CHANNEL_POWER_CONSUMPTION = "powerConsumption"; + + public static final String COMMAND_POWER_ON = "powerOn"; + public static final String COMMAND_NIGHTLIGHT = "nightLight"; + + public static final Unit BROADLINK_TEMPERATURE_UNIT = SIUnits.CELSIUS; + public static final Unit BROADLINK_HUMIDITY_UNIT = Units.PERCENT; + public static final Unit BROADLINK_POWER_CONSUMPTION_UNIT = Units.WATT; + + public static final Map SUPPORTED_THING_TYPES_UIDS_TO_NAME_MAP = new HashMap<>(); + + static { + SUPPORTED_THING_TYPES_UIDS_TO_NAME_MAP.put(THING_TYPE_RM2, RM2); + SUPPORTED_THING_TYPES_UIDS_TO_NAME_MAP.put(THING_TYPE_RM3, RM3); + SUPPORTED_THING_TYPES_UIDS_TO_NAME_MAP.put(THING_TYPE_RM3Q, RM3Q); + SUPPORTED_THING_TYPES_UIDS_TO_NAME_MAP.put(THING_TYPE_RM4, RM4); + SUPPORTED_THING_TYPES_UIDS_TO_NAME_MAP.put(THING_TYPE_A1, A1); + SUPPORTED_THING_TYPES_UIDS_TO_NAME_MAP.put(THING_TYPE_MP1, MP1); + SUPPORTED_THING_TYPES_UIDS_TO_NAME_MAP.put(THING_TYPE_MP1_1K3S2U, MP1_1K3S2U); + SUPPORTED_THING_TYPES_UIDS_TO_NAME_MAP.put(THING_TYPE_MP2, MP2); + SUPPORTED_THING_TYPES_UIDS_TO_NAME_MAP.put(THING_TYPE_SP1, SP1); + SUPPORTED_THING_TYPES_UIDS_TO_NAME_MAP.put(THING_TYPE_SP2, SP2); + SUPPORTED_THING_TYPES_UIDS_TO_NAME_MAP.put(THING_TYPE_SP2S, SP2S); + SUPPORTED_THING_TYPES_UIDS_TO_NAME_MAP.put(THING_TYPE_SP3, SP3); + SUPPORTED_THING_TYPES_UIDS_TO_NAME_MAP.put(THING_TYPE_SP3S, SP3S); + SUPPORTED_THING_TYPES_UIDS_TO_NAME_MAP.put(THING_TYPE_PIR, S1P); + SUPPORTED_THING_TYPES_UIDS_TO_NAME_MAP.put(THING_TYPE_MAGNET, S1M); + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/config/BroadlinkDeviceConfiguration.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/config/BroadlinkDeviceConfiguration.java new file mode 100644 index 0000000000000..e81c6dfb89456 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/config/BroadlinkDeviceConfiguration.java @@ -0,0 +1,127 @@ +/** + * 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.broadlink.config; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Device configuration for the supported Broadlink devices. + * + * @author John Marshall/Cato Sognen - Initial contribution + */ +@NonNullByDefault +public class BroadlinkDeviceConfiguration { + private String ipAddress; + private boolean staticIp; + private int port; + private String macAddress; + private byte[] macAddressBytes; + private int pollingInterval; + private String mapFilename; + private boolean ignoreFailedUpdates; + private int deviceType; + + public BroadlinkDeviceConfiguration() { + ipAddress = ""; + staticIp = true; + macAddress = ""; + macAddressBytes = new byte[0]; + pollingInterval = 30; + mapFilename = "broadlink.map"; + ignoreFailedUpdates = false; + } + + public String getIpAddress() { + return ipAddress; + } + + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + } + + public boolean isStaticIp() { + return staticIp; + } + + public void setStaticIp(boolean staticIp) { + this.staticIp = staticIp; + } + + public void setPort(int port) { + this.port = port; + } + + public int getPort() { + return port; + } + + public void setMacAddress(String macAddress) { + this.macAddressBytes = new byte[0]; + this.macAddress = macAddress; + } + + public byte[] getMacAddress() { + if (macAddressBytes.length != 6) { + macAddressBytes = new byte[6]; + String elements[] = macAddress.split(":"); + for (int i = 0; i < 6; i++) { + String element = elements[i]; + macAddressBytes[i] = (byte) Integer.parseInt(element, 16); + } + } + return macAddressBytes; + } + + public String getMacAddressAsString() { + return macAddress; + } + + public int getPollingInterval() { + return pollingInterval; + } + + public void setPollingInterval(int pollingInterval) { + this.pollingInterval = pollingInterval; + } + + public String getMapFilename() { + return mapFilename; + } + + public void setMapFilename(String mapFilename) { + this.mapFilename = mapFilename; + } + + public int getDeviceType() { + return deviceType; + } + + public void setDeviceType(int newDeviceType) { + this.deviceType = newDeviceType; + } + + public void setIgnoreFailedUpdates(boolean ignore) { + this.ignoreFailedUpdates = ignore; + } + + public boolean isIgnoreFailedUpdates() { + return this.ignoreFailedUpdates; + } + + public String toString() { + return (new StringBuilder("BroadlinkDeviceConfiguration [ipAddress=")).append(ipAddress).append(" (static: ") + .append(staticIp).append("), port=").append(port).append(", macAddress=").append(macAddress) + .append(", pollingInterval=").append(pollingInterval).append(", mapFilename=").append(mapFilename) + .append("]").toString(); + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkA1Handler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkA1Handler.java new file mode 100644 index 0000000000000..02519fda51e0d --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkA1Handler.java @@ -0,0 +1,64 @@ +/** + * 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.broadlink.handler; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.broadlink.internal.ModelMapper; +import org.openhab.core.thing.Thing; + +/** + * Handles the A1 environmental sensor. + * + * @author John Marshall/Cato Sognen - Initial contribution + */ +@NonNullByDefault +public class BroadlinkA1Handler extends BroadlinkBaseThingHandler { + + public BroadlinkA1Handler(Thing thing) { + super(thing); + } + + protected boolean getStatusFromDevice() { + logger.trace("A1 getStatusFromDevice"); + byte payload[]; + payload = new byte[16]; + payload[0] = 1; + + try { + byte message[] = buildMessage((byte) 0x6a, payload); + + byte[] response = sendAndReceiveDatagram(message, "A1 device status"); + if (response == null) { + logger.warn("Got nothing back while getting device status"); + return false; + } + byte decryptResponse[] = decodeDevicePacket(response); + double temperature = ((double) (decryptResponse[4] * 10 + decryptResponse[5]) / 10D); + logger.trace("A1 getStatusFromDevice got temperature {}", temperature); + + updateTemperature(temperature); + updateHumidity((double) (decryptResponse[6] * 10 + decryptResponse[7]) / 10D); + updateState("light", ModelMapper.getLightValue(decryptResponse[8])); + updateState("air", ModelMapper.getAirValue(decryptResponse[10])); + updateState("noise", ModelMapper.getNoiseValue(decryptResponse[12])); + return true; + } catch (Exception ex) { + logger.warn("Failed while getting device status", ex); + return false; + } + } + + protected boolean onBroadlinkDeviceBecomingReachable() { + return getStatusFromDevice(); + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkBaseThingHandler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkBaseThingHandler.java new file mode 100644 index 0000000000000..cee90194ca1ca --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkBaseThingHandler.java @@ -0,0 +1,292 @@ +/** + * 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.broadlink.handler; + +import static org.openhab.binding.broadlink.BroadlinkBindingConstants.*; +import static org.openhab.binding.broadlink.BroadlinkBindingConstants.BROADLINK_HUMIDITY_UNIT; + +import java.io.IOException; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.broadlink.BroadlinkBindingConstants; +import org.openhab.binding.broadlink.config.BroadlinkDeviceConfiguration; +import org.openhab.binding.broadlink.internal.BroadlinkProtocol; +import org.openhab.binding.broadlink.internal.NetworkUtils; +import org.openhab.binding.broadlink.internal.Utils; +import org.openhab.binding.broadlink.internal.discovery.DeviceRediscoveryAgent; +import org.openhab.binding.broadlink.internal.discovery.DeviceRediscoveryListener; +import org.openhab.binding.broadlink.internal.socket.NetworkTrafficObserver; +import org.openhab.binding.broadlink.internal.socket.RetryableSocket; +import org.openhab.core.library.types.QuantityType; +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.binding.BaseThingHandler; +import org.openhab.core.types.Command; +import org.openhab.core.types.RefreshType; +import org.openhab.core.util.HexUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Abstract superclass of all supported Broadlink devices. + * + * @author John Marshall/Cato Sognen - Initial contribution + */ +@NonNullByDefault +public abstract class BroadlinkBaseThingHandler extends BaseThingHandler implements DeviceRediscoveryListener { + + public final Logger logger = LoggerFactory.getLogger(getClass()); + private static final String INITIAL_DEVICE_ID = "00000000"; + + protected BroadlinkDeviceConfiguration thingConfig = new BroadlinkDeviceConfiguration(); + + private @Nullable RetryableSocket socket; + + // Can be injected for test purposes + private @Nullable NetworkTrafficObserver networkTrafficObserver; + + private int count; + private @Nullable ScheduledFuture refreshHandle; + private boolean authenticated = false; + // These get handed to us by the device after successful authentication: + private byte[] deviceId; + private byte[] deviceKey; + + public BroadlinkBaseThingHandler(Thing thing) { + super(thing); + logger.debug("constructed: resetting deviceKey to '{}', length {}", + BroadlinkBindingConstants.BROADLINK_AUTH_KEY, BroadlinkBindingConstants.BROADLINK_AUTH_KEY.length()); + this.deviceId = HexUtils.hexToBytes(INITIAL_DEVICE_ID); + this.deviceKey = HexUtils.hexToBytes(BroadlinkBindingConstants.BROADLINK_AUTH_KEY); + } + + // For test purposes + void setSocket(RetryableSocket socket) { + this.socket = socket; + } + + void setNetworkTrafficObserver(NetworkTrafficObserver networkTrafficObserver) { + this.networkTrafficObserver = networkTrafficObserver; + } + + private boolean hasAuthenticated() { + return authenticated; + } + + public void initialize() { + logger.debug("initializing handler"); + + this.thingConfig = getConfigAs(BroadlinkDeviceConfiguration.class); + count = (new Random()).nextInt(65535); + + if (this.socket == null) { + this.socket = new RetryableSocket(thingConfig, logger); + } + + updateItemStatus(); + + if (thingConfig.getPollingInterval() != 0) { + refreshHandle = scheduler.scheduleWithFixedDelay(new Runnable() { + + public void run() { + updateItemStatus(); + } + }, 1L, thingConfig.getPollingInterval(), TimeUnit.SECONDS); + } + } + + public void dispose() { + logger.debug("Disposing of {}", getThing().getLabel()); + if (refreshHandle != null && !refreshHandle.isDone()) { + logger.debug("Cancelling refresh task"); + boolean cancelled = refreshHandle.cancel(true); + logger.debug("Cancellation successful: {}", cancelled); + } + if (socket != null) { + socket.close(); + socket = null; + } + super.dispose(); + } + + private boolean authenticate() { + logger.trace("Authenticating"); + authenticated = false; + // When authenticating, we must ALWAYS use the initial values + this.deviceId = HexUtils.hexToBytes(INITIAL_DEVICE_ID); + this.deviceKey = HexUtils.hexToBytes(BroadlinkBindingConstants.BROADLINK_AUTH_KEY); + + try { + byte authRequest[] = buildMessage((byte) 0x65, BroadlinkProtocol.buildAuthenticationPayload(), -1); + byte response[] = sendAndReceiveDatagram(authRequest, "authentication"); + if (response == null) { + logger.warn("response from device during authentication was null"); + return false; + } + byte decryptResponse[] = decodeDevicePacket(response); + this.deviceId = BroadlinkProtocol.getDeviceId(decryptResponse); + this.deviceKey = BroadlinkProtocol.getDeviceKey(decryptResponse); + + // Update the properties, so that these values can be seen in the UI: + Map properties = editProperties(); + properties.put("id", HexUtils.bytesToHex(deviceId)); + properties.put("key", HexUtils.bytesToHex(deviceKey)); + updateProperties(properties); + logger.debug("Authenticated with id '{}' and key '{}'", HexUtils.bytesToHex(deviceId), + HexUtils.bytesToHex(deviceKey)); + authenticated = true; + return true; + } catch (Exception e) { + logger.warn("Authentication failed: ", e); + return false; + } + } + + protected byte @Nullable [] sendAndReceiveDatagram(byte message[], String purpose) { + return socket.sendAndReceive(message, purpose); + } + + protected byte[] buildMessage(byte command, byte payload[]) throws IOException { + return buildMessage(command, payload, thingConfig.getDeviceType()); + } + + private byte[] buildMessage(byte command, byte payload[], int deviceType) throws IOException { + count = count + 1 & 0xffff; + + if (networkTrafficObserver != null) { + networkTrafficObserver.onCommandSent(command); + networkTrafficObserver.onBytesSent(payload); + } + + return BroadlinkProtocol.buildMessage(command, payload, count, thingConfig.getMacAddress(), deviceId, + HexUtils.hexToBytes(BroadlinkBindingConstants.BROADLINK_IV), deviceKey, deviceType, logger); + } + + protected byte[] decodeDevicePacket(byte[] responseBytes) throws IOException { + byte[] rxBytes = BroadlinkProtocol.decodePacket(responseBytes, this.deviceKey, + BroadlinkBindingConstants.BROADLINK_IV); + + if (networkTrafficObserver != null) { + networkTrafficObserver.onBytesReceived(rxBytes); + } + return rxBytes; + } + + public void handleCommand(ChannelUID channelUID, Command command) { + if (command instanceof RefreshType) { + logger.trace("Refresh requested, updating item status ..."); + + updateItemStatus(); + } + } + + // Can be implemented by devices that should do something on being found; e.g. perform a first status query + protected boolean onBroadlinkDeviceBecomingReachable() { + return true; + } + + // Implemented by devices that can update the openHAB state + // model. Return false if something went wrong that requires + // a change in the device's online state + protected boolean getStatusFromDevice() { + return true; + } + + public void updateItemStatus() { + logger.trace("updateItemStatus; checking host availability at {}", thingConfig.getIpAddress()); + if (NetworkUtils.hostAvailabilityCheck(thingConfig.getIpAddress(), 3000, logger)) { + logger.trace("updateItemStatus; host found at {}", thingConfig.getIpAddress()); + if (!Utils.isOnline(getThing())) { + logger.trace("updateItemStatus; device not currently online, resolving"); + transitionToOnline(); + } else { + // Normal operation ... + boolean gotStatusOk = getStatusFromDevice(); + if (!gotStatusOk) { + if (thingConfig.isIgnoreFailedUpdates()) { + logger.warn( + "Problem getting status. Not marking offline because configured to ignore failed updates ..."); + } else { + forceOffline(ThingStatusDetail.GONE, "Problem getting status"); + } + } + } + } else { + if (thingConfig.isStaticIp()) { + if (!Utils.isOffline(getThing())) { + forceOffline(ThingStatusDetail.NONE, "Couldn't find statically-IP-addressed device"); + } + } else { + logger.debug("Dynamic IP device not found at {}, will search...", thingConfig.getIpAddress()); + DeviceRediscoveryAgent dra = new DeviceRediscoveryAgent(thingConfig, this); + dra.attemptRediscovery(); + logger.debug("Asynchronous dynamic IP device search initiated..."); + } + } + } + + public void onDeviceRediscovered(String newIpAddress) { + logger.info("Rediscovered this device at IP {}", newIpAddress); + thingConfig.setIpAddress(newIpAddress); + transitionToOnline(); + } + + public void onDeviceRediscoveryFailure() { + if (!Utils.isOffline(getThing())) { + forceOffline(ThingStatusDetail.NONE, + "Couldn't rediscover dynamically-IP-addressedv device after network scan"); + } + } + + private void transitionToOnline() { + if (!hasAuthenticated()) { + logger.debug( + "We've never actually successfully authenticated with this device in this session. Doing so now"); + if (authenticate()) { + logger.debug("Authenticated with newly-detected device, will now get its status"); + } else { + forceOffline(ThingStatusDetail.COMMUNICATION_ERROR, "Couldn't authenticate"); + return; + } + } + if (onBroadlinkDeviceBecomingReachable()) { + updateStatus(ThingStatus.ONLINE); + } else { + forceOffline(ThingStatusDetail.COMMUNICATION_ERROR, "Trouble getting status"); + } + } + + private void forceOffline(ThingStatusDetail detail, String reason) { + logger.warn("Online -> Offline due to: {}", reason); + authenticated = false; // This session is dead; we'll need to re-authenticate next time + updateStatus(ThingStatus.OFFLINE, detail, reason); + if (socket != null) { + socket.close(); + } + } + + protected void updateTemperature(double temperature) { + updateState(CHANNEL_TEMPERATURE, new QuantityType<>(temperature, BROADLINK_TEMPERATURE_UNIT)); + } + + protected void updateHumidity(double humidity) { + updateState(CHANNEL_HUMIDITY, new QuantityType<>(humidity, BROADLINK_HUMIDITY_UNIT)); + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteHandler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteHandler.java new file mode 100644 index 0000000000000..7a2d0c452223b --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteHandler.java @@ -0,0 +1,192 @@ +/** + * 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.broadlink.handler; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.broadlink.BroadlinkBindingConstants; +import org.openhab.binding.broadlink.internal.BroadlinkMappingService; +import org.openhab.binding.broadlink.internal.BroadlinkRemoteDynamicCommandDescriptionProvider; +import org.openhab.binding.broadlink.internal.Utils; +import org.openhab.core.thing.Channel; +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.type.ChannelTypeUID; +import org.openhab.core.types.Command; +import org.openhab.core.types.RefreshType; +import org.openhab.core.util.HexUtils; + +/** + * Remote blaster handler superclass + * + * @author Cato Sognen - Initial contribution + * @author John Marshall - V3 rewrite with dynamic command description provider + */ +@NonNullByDefault +public abstract class BroadlinkRemoteHandler extends BroadlinkBaseThingHandler { + + public static final byte COMMAND_BYTE_SEND_CODE = 0x02; + public static final byte COMMAND_BYTE_ENTER_LEARNING = 0x03; + public static final byte COMMAND_BYTE_CHECK_LEARNT_DATA = 0x04; + + private final BroadlinkRemoteDynamicCommandDescriptionProvider commandDescriptionProvider; + private @Nullable BroadlinkMappingService mappingService; + + public BroadlinkRemoteHandler(Thing thing, + BroadlinkRemoteDynamicCommandDescriptionProvider commandDescriptionProvider) { + super(thing); + this.commandDescriptionProvider = commandDescriptionProvider; + } + + public void initialize() { + super.initialize(); + this.mappingService = new BroadlinkMappingService(thingConfig.getMapFilename(), commandDescriptionProvider, + new ChannelUID(thing.getUID(), BroadlinkBindingConstants.COMMAND_CHANNEL)); + } + + public void dispose() { + if (this.mappingService != null) { + this.mappingService.dispose(); + } + super.dispose(); + } + + protected byte @Nullable [] sendCommand(byte commandByte, String purpose) { + return sendCommand(commandByte, new byte[0], purpose); + } + + private byte @Nullable [] sendCommand(byte commandByte, byte[] codeBytes, String purpose) { + try { + ByteArrayOutputStream outputStream = buildCommandMessage(commandByte, codeBytes); + byte[] padded = Utils.padTo(outputStream.toByteArray(), 16); + byte[] message = buildMessage((byte) 0x6a, padded); + return sendAndReceiveDatagram(message, purpose); + } catch (IOException e) { + logger.warn("Exception while sending command", e); + } + + return null; + } + + protected void sendCode(byte[] code) { + sendCommand(COMMAND_BYTE_SEND_CODE, code, "send remote code"); + } + + protected ByteArrayOutputStream buildCommandMessage(byte commandByte, byte[] codeBytes) throws IOException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + byte[] preamble = new byte[4]; + preamble[0] = commandByte; + outputStream.write(preamble); + if (codeBytes.length > 0) { + outputStream.write(codeBytes); + } + + return outputStream; + } + + protected byte[] extractResponsePayload(byte[] responseBytes) throws IOException { + byte decryptedResponse[] = decodeDevicePacket(responseBytes); + // Interesting stuff begins at the fourth byte + return Utils.slice(decryptedResponse, 4, decryptedResponse.length); + } + + private void sendCheckDataCommandAndLog() { + try { + byte[] response = sendCommand(COMMAND_BYTE_CHECK_LEARNT_DATA, "send learnt code check command"); + if (response == null) { + logger.warn("Got nothing back while getting learnt code"); + } else { + String hexString = Utils.toHexString(extractResponsePayload(response)); + logger.info("BEGIN LAST LEARNT CODE"); + logger.info("{}", hexString); + logger.info("END LAST LEARNT CODE ({} characters)", hexString.length()); + } + } catch (IOException e) { + logger.warn("Exception while attempting to check learnt code", e); + } + } + + void handleLearningCommand(String learningCommand) { + logger.trace("Sending learning-channel command {}", learningCommand); + switch (learningCommand) { + case BroadlinkBindingConstants.LEARNING_CONTROL_COMMAND_LEARN: + sendCommand(COMMAND_BYTE_ENTER_LEARNING, "enter remote code learning mode"); + break; + case BroadlinkBindingConstants.LEARNING_CONTROL_COMMAND_CHECK: + sendCheckDataCommandAndLog(); + break; + default: + logger.warn("Unrecognised learning channel command: {}", learningCommand); + } + } + + public void handleCommand(ChannelUID channelUID, Command command) { + if (!Utils.isOnline(getThing())) { + logger.debug("Can't handle command {} because handler for thing {} is not ONLINE", command, + getThing().getLabel()); + return; + } + if (command instanceof RefreshType) { + updateItemStatus(); + return; + } + + Channel channel = thing.getChannel(channelUID.getId()); + if (channel == null) { + logger.warn("Unexpected null channel while handling command {}", command.toFullString()); + return; + } + ChannelTypeUID channelTypeUID = channel.getChannelTypeUID(); + if (channelTypeUID == null) { + logger.warn("Unexpected null channelTypeUID while handling command {}", command.toFullString()); + return; + } + switch (channelTypeUID.getId()) { + case BroadlinkBindingConstants.COMMAND_CHANNEL: { + logger.debug("Handling ir/rf command '{}' on channel {} of thing {}", command, channelUID.getId(), + getThing().getLabel()); + byte code[] = lookupCode(command, channelUID); + if (code != null) { + sendCode(code); + } + break; + } + case BroadlinkBindingConstants.LEARNING_CONTROL_CHANNEL: + handleLearningCommand(command.toString()); + break; + default: + logger.debug("Thing {} has unknown channel type '{}'", getThing().getLabel(), channelTypeUID.getId()); + } + } + + private byte @Nullable [] lookupCode(Command command, ChannelUID channelUID) { + byte code[] = null; + String value = this.mappingService.lookup(command.toString()); + + if (value == null || value.isEmpty()) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, + "No entries found for command in map file, or the file is missing."); + return null; + } + + code = HexUtils.hexToBytes(value); + + logger.debug("Transformed command '{}' for thing {}", command, getThing().getLabel()); + return code; + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel2Handler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel2Handler.java new file mode 100644 index 0000000000000..3a6622f69a1cd --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel2Handler.java @@ -0,0 +1,55 @@ +/** + * 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.broadlink.handler; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.broadlink.internal.BroadlinkRemoteDynamicCommandDescriptionProvider; +import org.openhab.core.thing.Thing; + +/** + * Remote blaster handler + * + * @author John Marshall/Cato Sognen - Initial contribution + */ +@NonNullByDefault +public class BroadlinkRemoteModel2Handler extends BroadlinkRemoteHandler { + + public BroadlinkRemoteModel2Handler(Thing thing, + BroadlinkRemoteDynamicCommandDescriptionProvider commandDescriptionProvider) { + super(thing, commandDescriptionProvider); + } + + protected boolean onBroadlinkDeviceBecomingReachable() { + return getStatusFromDevice(); + } + + protected boolean getStatusFromDevice() { + try { + byte payload[] = new byte[16]; + payload[0] = 1; + byte message[] = buildMessage((byte) 0x6a, payload); + byte response[] = sendAndReceiveDatagram(message, "RM2 device status"); + if (response == null) { + logger.warn("response from RM2 device was null"); + return false; + } + byte decodedPayload[] = decodeDevicePacket(response); + double temperature = ((double) (decodedPayload[4] * 10 + decodedPayload[5]) / 10D); + updateTemperature(temperature); + return true; + } catch (Exception e) { + logger.warn("Could not get status: ", e); + return false; + } + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3Handler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3Handler.java new file mode 100644 index 0000000000000..55210f7c3a6eb --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3Handler.java @@ -0,0 +1,31 @@ +/** + * 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.broadlink.handler; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.broadlink.internal.BroadlinkRemoteDynamicCommandDescriptionProvider; +import org.openhab.core.thing.Thing; + +/** + * Remote blaster handler for RM mini 3 devices + * + * @author John Marshall - Initial contribution + */ +@NonNullByDefault +public class BroadlinkRemoteModel3Handler extends BroadlinkRemoteHandler { + + public BroadlinkRemoteModel3Handler(Thing thing, + BroadlinkRemoteDynamicCommandDescriptionProvider commandDescriptionProvider) { + super(thing, commandDescriptionProvider); + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3V44057Handler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3V44057Handler.java new file mode 100644 index 0000000000000..84904cc07275c --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3V44057Handler.java @@ -0,0 +1,35 @@ +/** + * 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.broadlink.handler; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.broadlink.internal.BroadlinkRemoteDynamicCommandDescriptionProvider; +import org.openhab.core.thing.Thing; + +/** + * Supports quirks in V44057 firmware. + * + * @author Stewart Cossey - Initial contribution + */ +@NonNullByDefault +public class BroadlinkRemoteModel3V44057Handler extends BroadlinkRemoteModel4Handler { + + public BroadlinkRemoteModel3V44057Handler(Thing thing, + BroadlinkRemoteDynamicCommandDescriptionProvider commandDescriptionProvider) { + super(thing, commandDescriptionProvider); + } + + protected boolean getStatusFromDevice() { + return true; + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4Handler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4Handler.java new file mode 100644 index 0000000000000..30ce697a03701 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4Handler.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.broadlink.handler; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.broadlink.internal.BroadlinkRemoteDynamicCommandDescriptionProvider; +import org.openhab.binding.broadlink.internal.Utils; +import org.openhab.core.thing.Thing; + +/** + * Remote blaster handler, "generation" 4 + * + * These devices place a 6-byte preamble before their payload. + * The format is: + * Byte 00 01 02 03 04 05 + * PLl PLh CMD 00 00 00 + * + * Where PL is the 16-bit unsigned length of the payload PLUS 4 BYTES + * so PLl is the lower byte and PLh is the high byte + * + * @author John Marshall/Cato Sognen - Initial contribution + */ +@NonNullByDefault +public class BroadlinkRemoteModel4Handler extends BroadlinkRemoteHandler { + + public BroadlinkRemoteModel4Handler(Thing thing, + BroadlinkRemoteDynamicCommandDescriptionProvider commandDescriptionProvider) { + super(thing, commandDescriptionProvider); + } + + protected boolean onBroadlinkDeviceBecomingReachable() { + return getStatusFromDevice(); + } + + protected boolean getStatusFromDevice() { + try { + // These devices use a 2-byte preamble to the normal protocol; + // https://github.com/mjg59/python-broadlink/blob/0bd58c6f598fe7239246ad9d61508febea625423/broadlink/__init__.py#L666 + byte[] response = sendCommand((byte) 0x24, "RM4 device status"); // Status check is now Ox24, not 0x01 as in + // earlier devices + if (response == null) { + logger.warn("response from RM4 device was null"); + return false; + } + byte decodedPayload[] = extractResponsePayload(response); + + // Temps and humidity get divided by 100 now, not 10 + double temperature = ((double) (decodedPayload[0] * 100 + decodedPayload[1]) / 100D); + updateTemperature(temperature); + double humidity = ((double) (decodedPayload[2] * 100 + decodedPayload[3]) / 100D); + updateHumidity(humidity); + return true; + } catch (Exception e) { + logger.warn("Could not get status: ", e); + return false; + } + } + + // These devices use a 6-byte sendCode preamble instead of the previous 4: + // https://github.com/mjg59/python-broadlink/blob/822b3c326631c1902b5892a83db126291acbf0b6/broadlink/remote.py#L78 + @Override + protected ByteArrayOutputStream buildCommandMessage(byte commandByte, byte[] codeBytes) throws IOException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + byte[] preamble = new byte[6]; + int length = codeBytes.length + 4; + preamble[0] = (byte) (length & 0xFF); + preamble[1] = (byte) ((length >> 8) & 0xFF); + preamble[2] = commandByte; + outputStream.write(preamble); + if (codeBytes.length > 0) { + outputStream.write(codeBytes); + } + + return outputStream; + } + + // Interesting stuff begins at the 6th byte, and runs for the length indicated + // in the first two bytes of the response (little-endian) + 2, as opposed to + // whatever the "natural" decrypted length is + @Override + protected byte[] extractResponsePayload(byte[] responseBytes) throws IOException { + byte decryptedResponse[] = decodeDevicePacket(responseBytes); + int lsb = decryptedResponse[0] & 0xFF; + int msb = decryptedResponse[1] & 0xFF; + int payloadLength = (msb << 8) + lsb; + return Utils.slice(decryptedResponse, 6, payloadLength + 2); + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketHandler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketHandler.java new file mode 100644 index 0000000000000..b0cf04e6b4828 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketHandler.java @@ -0,0 +1,50 @@ +/** + * 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.broadlink.handler; + +import java.io.IOException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.types.Command; + +/** + * Abstract superclass for power socket devices + * + * @author John Marshall/Cato Sognen - Initial contribution + */ +@NonNullByDefault +public abstract class BroadlinkSocketHandler extends BroadlinkBaseThingHandler { + + public BroadlinkSocketHandler(Thing thing) { + super(thing); + } + + protected abstract void setStatusOnDevice(int state) throws IOException; + + public void handleCommand(ChannelUID channelUID, Command command) { + try { + if (channelUID.getId().equals("powerOn")) { + if (command == OnOffType.ON) { + setStatusOnDevice(1); + } else if (command == OnOffType.OFF) { + setStatusOnDevice(0); + } + } + } catch (IOException e) { + logger.warn("Could not send command to socket device", e); + } + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel1Handler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel1Handler.java new file mode 100644 index 0000000000000..0f16f88fb4773 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel1Handler.java @@ -0,0 +1,38 @@ +/** + * 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.broadlink.handler; + +import java.io.IOException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.thing.Thing; + +/** + * Smart power socket handler + * + * @author John Marshall/Cato Sognen - Initial contribution + */ +@NonNullByDefault +public class BroadlinkSocketModel1Handler extends BroadlinkSocketHandler { + + public BroadlinkSocketModel1Handler(Thing thing) { + super(thing); + } + + public void setStatusOnDevice(int state) throws IOException { + byte payload[] = new byte[16]; + payload[0] = (byte) state; + byte message[] = buildMessage((byte) 102, payload); + sendAndReceiveDatagram(message, "Setting SP1 status"); + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel2Handler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel2Handler.java new file mode 100644 index 0000000000000..01e3722d1a36c --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel2Handler.java @@ -0,0 +1,124 @@ +/** + * 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.broadlink.handler; + +import static org.openhab.binding.broadlink.BroadlinkBindingConstants.*; + +import java.io.IOException; + +import javax.measure.quantity.Power; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.types.Command; + +/** + * Smart power socket handler with optional power consumption (SP2s) + * + * @author Cato Sognen - Initial contribution + * @author John Marshall - rework for correct SP2s handling + */ +@NonNullByDefault +public class BroadlinkSocketModel2Handler extends BroadlinkSocketHandler { + protected boolean supportsPowerConsumptionMeasurement; + + public BroadlinkSocketModel2Handler(Thing thing, boolean supportsPowerConsumptionMeasurement) { + super(thing); + this.supportsPowerConsumptionMeasurement = supportsPowerConsumptionMeasurement; + } + + protected void setStatusOnDevice(int status) throws IOException { + byte payload[] = new byte[16]; + payload[0] = 2; + payload[4] = (byte) status; + byte message[] = buildMessage((byte) 0x6a, payload); + sendAndReceiveDatagram(message, "Setting switch device status to " + status); + } + + protected OnOffType deriveOnOffBitFromStatusPayload(byte[] statusPayload, byte mask) { + byte statusByte = statusPayload[4]; + if ((statusByte & mask) == mask) { + return OnOffType.ON; + } + return OnOffType.OFF; + } + + OnOffType derivePowerStateFromStatusBytes(byte[] statusPayload) { + return deriveOnOffBitFromStatusPayload(statusPayload, (byte) 0x01); + } + + // https://github.com/mjg59/python-broadlink/blob/822b3c326631c1902b5892a83db126291acbf0b6/broadlink/switch.py#L186 + double derivePowerConsumption(byte[] statusPayload) throws IOException { + if (statusPayload.length > 6) { + // Bytes are little-endian, at positions 4,5 and 6 + int highByte = statusPayload[6] & 0xFF; + int midByte = statusPayload[5] & 0xFF; + int lowByte = statusPayload[4] & 0xFF; + int intValue = (highByte << 16) + (midByte << 8) + lowByte; + return (double) intValue / 1000; + } + return 0D; + } + + protected int toPowerOnOffBits(Command powerOnOff) { + return powerOnOff == OnOffType.ON ? 0x01 : 0x00; + } + + public void handleCommand(ChannelUID channelUID, Command command) { + try { + if (channelUID.getId().equals(COMMAND_POWER_ON)) { + setStatusOnDevice(toPowerOnOffBits(command)); + } + } catch (IOException e) { + logger.warn("Could not send command to socket device", e); + } + } + + protected void updatePowerConsumption(double consumptionWatts) { + updateState(CHANNEL_POWER_CONSUMPTION, + new QuantityType(consumptionWatts, BROADLINK_POWER_CONSUMPTION_UNIT)); + } + + protected boolean getStatusFromDevice() { + try { + logger.trace("SP2/SP2s getting status..."); + byte[] statusBytes = getStatusBytesFromDevice(); + updateState(COMMAND_POWER_ON, derivePowerStateFromStatusBytes(statusBytes)); + if (supportsPowerConsumptionMeasurement) { + updatePowerConsumption(derivePowerConsumption(statusBytes)); + } + return true; + } catch (Exception ex) { + logger.warn("Exception while getting status from device", ex); + return false; + } + } + + protected byte[] getStatusBytesFromDevice() throws IOException { + byte payload[] = new byte[16]; + payload[0] = 1; + byte message[] = buildMessage((byte) 0x6a, payload); + byte response[] = sendAndReceiveDatagram(message, "SP2/SP2s status byte"); + if (response == null) { + throw new IOException("No response while fetching status byte from SP2/SP2s device"); + } + return decodeDevicePacket(response); + } + + protected boolean onBroadlinkDeviceBecomingReachable() { + return getStatusFromDevice(); + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3Handler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3Handler.java new file mode 100644 index 0000000000000..855be00b58877 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3Handler.java @@ -0,0 +1,80 @@ +/** + * 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.broadlink.handler; + +import static org.openhab.binding.broadlink.BroadlinkBindingConstants.COMMAND_NIGHTLIGHT; +import static org.openhab.binding.broadlink.BroadlinkBindingConstants.COMMAND_POWER_ON; + +import java.io.IOException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.types.Command; + +/** + * Smart power socket handler with nightlight + * + * @author Cato Sognen - Initial contribution + * @author John Marshall - Nightlight support + */ +@NonNullByDefault +public class BroadlinkSocketModel3Handler extends BroadlinkSocketModel2Handler { + + public BroadlinkSocketModel3Handler(Thing thing) { + super(thing, false); + } + + OnOffType deriveNightLightStateFromStatusBytes(byte[] statusPayload) { + return deriveOnOffBitFromStatusPayload(statusPayload, (byte) 0x02); + } + + static int mergeOnOffBits(Command powerOnOff, Command nightLightOnOff) { + int powerBit = powerOnOff == OnOffType.ON ? 0x01 : 0x00; + int nightLightBit = nightLightOnOff == OnOffType.ON ? 0x02 : 0x00; + return powerBit | nightLightBit; + } + + protected boolean getStatusFromDevice() { + try { + logger.debug("SP3 getting status..."); + byte[] statusBytes = getStatusBytesFromDevice(); + updateState(COMMAND_POWER_ON, derivePowerStateFromStatusBytes(statusBytes)); + updateState(COMMAND_NIGHTLIGHT, deriveNightLightStateFromStatusBytes(statusBytes)); + return true; + } catch (Exception ex) { + logger.warn("Exception while getting status from device", ex); + return false; + } + } + + public void handleCommand(ChannelUID channelUID, Command command) { + try { + // Always pull back the latest device status and merge it: + byte[] statusBytes = getStatusBytesFromDevice(); + OnOffType powerStatus = derivePowerStateFromStatusBytes(statusBytes); + OnOffType nightLightStatus = deriveNightLightStateFromStatusBytes(statusBytes); + + if (channelUID.getId().equals(COMMAND_POWER_ON)) { + setStatusOnDevice(mergeOnOffBits(command, nightLightStatus)); + } + + if (channelUID.getId().equals(COMMAND_NIGHTLIGHT)) { + setStatusOnDevice(mergeOnOffBits(powerStatus, command)); + } + } catch (IOException e) { + logger.warn("Could not send command to SP3 device", e); + } + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandler.java new file mode 100644 index 0000000000000..e47bf2791ef59 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandler.java @@ -0,0 +1,74 @@ +/** + * 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.broadlink.handler; + +import java.io.IOException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.thing.Thing; + +/** + * Smart power socket handler with power consumption measurement. + * Despite its name, it is more closely related to the SP2 than the SP3, + * as it doesn't have a nightlight. + * + * @author John Marshall - Initial contribution + */ +@NonNullByDefault +public class BroadlinkSocketModel3SHandler extends BroadlinkSocketModel2Handler { + + public BroadlinkSocketModel3SHandler(Thing thing) { + super(thing, true); + } + + // The SP3S device needs to be explicitly + // asked to obtain the power consumption (as opposed to the SP2S) + // and it has other quirks too + // @see + // https://github.com/mjg59/python-broadlink/blob/822b3c326631c1902b5892a83db126291acbf0b6/broadlink/switch.py#L247 + @Override + double derivePowerConsumption(byte[] unusedPayload) throws IOException { + byte payload[] = { 8, 0, (byte) 254, 1, 5, 1, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0 }; + byte message[] = buildMessage((byte) 0x6a, payload); + byte response[] = sendAndReceiveDatagram(message, "SP3s power consumption byte"); + if (response != null) { + byte consumptionResponsePayload[] = decodeDevicePacket(response); + return deriveSP3sPowerConsumption(consumptionResponsePayload); + } + return 0D; + } + + // Reading between the lines at: + // https://github.com/mjg59/python-broadlink/issues/492 + // It appears that this is basically BCD with the major part + // of the wattage as LSB in payload[7] and payload[6] and the decimal part in payload[5] + // so for example, with a payload: 0 0 0 0 0x33 0x75 0x00 + // this actually should be interpreted as 75.33W! + // For a larger example: + // 0 0 0 0 0x44 0x66 0x02 + // Would be 266.44W + double deriveSP3sPowerConsumption(byte[] consumptionResponsePayload) { + if (consumptionResponsePayload.length > 7) { + return (fromBCD(consumptionResponsePayload[7]) * 100) + fromBCD(consumptionResponsePayload[6]) + + (fromBCD(consumptionResponsePayload[5]) / 100); + + } + return 0D; + } + + private double fromBCD(byte bcdDigit) { + int highNibble = ((int) bcdDigit & 0xF0) >> 4; + int lowNibble = bcdDigit & 0x0F; + return highNibble * 10 + lowNibble; + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkStripModel11K3S2UHandler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkStripModel11K3S2UHandler.java new file mode 100644 index 0000000000000..79588ea773d00 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkStripModel11K3S2UHandler.java @@ -0,0 +1,133 @@ +/** + * 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.broadlink.handler; + +import java.io.IOException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.types.Command; +import org.openhab.core.types.RefreshType; + +/** + * Multiple power socket plus USB strip device - 3 AC outlets and 2 USB outlets + * + * @author John Marshall/Cato Sognen - Initial contribution + */ +@NonNullByDefault +public class BroadlinkStripModel11K3S2UHandler extends BroadlinkBaseThingHandler { + + public BroadlinkStripModel11K3S2UHandler(Thing thing) { + super(thing); + } + + public void handleCommand(ChannelUID channelUID, Command command) { + if (command instanceof RefreshType) { + updateItemStatus(); + return; + } + + switch (channelUID.getId()) { + case "s1powerOn": + interpretCommandForSocket(1, command); + break; + case "s2powerOn": + interpretCommandForSocket(2, command); + break; + case "s3powerOn": + interpretCommandForSocket(3, command); + break; + case "usbPowerOn": + interpretCommandForSocket(4, command); + break; + default: + break; + + } + } + + private void interpretCommandForSocket(int sid, Command command) { + try { + if (command == OnOffType.ON) { + setStatusOnDevice((byte) sid, (byte) 1); + } else if (command == OnOffType.OFF) { + setStatusOnDevice((byte) sid, (byte) 0); + } + } catch (IOException e) { + logger.warn("Couldn't interpret command for strip device MP13K2U", e); + } + } + + private void setStatusOnDevice(byte sid, byte state) throws IOException { + int sidMask = 1 << sid - 1; + byte payload[] = new byte[16]; + payload[0] = 13; + payload[2] = -91; + payload[3] = -91; + payload[4] = 90; + payload[5] = 90; + if (state == 1) { + payload[6] = (byte) (178 + (sidMask << 1)); + } else { + payload[6] = (byte) (byte) (178 + sidMask); + } + payload[7] = -64; + payload[8] = 2; + payload[10] = 3; + payload[13] = (byte) sidMask; + if (state == 1) { + payload[14] = (byte) sidMask; + } else { + payload[14] = 0; + } + byte message[] = buildMessage((byte) 106, payload); + sendAndReceiveDatagram(message, "Setting MP13K2U status"); + } + + protected boolean getStatusFromDevice() { + byte payload[] = new byte[16]; + payload[0] = 10; + payload[2] = -91; + payload[3] = -91; + payload[4] = 90; + payload[5] = 90; + payload[6] = -82; + payload[7] = -64; + payload[8] = 1; + try { + byte message[] = buildMessage((byte) 106, payload); + byte response[] = sendAndReceiveDatagram(message, "status for MP13K2U strip"); + if (response == null) { + logger.warn("response from MP13K2U strip device was null"); + return false; + } + byte decodedPayload[] = decodeDevicePacket(response); + final int status = decodedPayload[14]; + + this.updateState("s1powerOn", (status & 0x01) == 0x01 ? OnOffType.ON : OnOffType.OFF); + this.updateState("s2powerOn", (status & 0x02) == 0x02 ? OnOffType.ON : OnOffType.OFF); + this.updateState("s3powerOn", (status & 0x04) == 0x04 ? OnOffType.ON : OnOffType.OFF); + this.updateState("usbPowerOn", (status & 0x08) == 0x08 ? OnOffType.ON : OnOffType.OFF); + } catch (Exception ex) { + logger.warn("Exception while getting status from device", ex); + return false; + } + return true; + } + + protected boolean onBroadlinkDeviceBecomingReachable() { + return getStatusFromDevice(); + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkStripModel1Handler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkStripModel1Handler.java new file mode 100644 index 0000000000000..946e4331e3103 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkStripModel1Handler.java @@ -0,0 +1,132 @@ +/** + * 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.broadlink.handler; + +import java.io.IOException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.types.Command; +import org.openhab.core.types.RefreshType; + +/** + * Multiple power socket strip device + * + * @author John Marshall/Cato Sognen - Initial contribution + */ +@NonNullByDefault +public class BroadlinkStripModel1Handler extends BroadlinkBaseThingHandler { + + public BroadlinkStripModel1Handler(Thing thing) { + super(thing); + } + + public void handleCommand(ChannelUID channelUID, Command command) { + if (command instanceof RefreshType) { + updateItemStatus(); + return; + } + + switch (channelUID.getId()) { + case "s1powerOn": + interpretCommandForSocket(1, command); + break; + case "s2powerOn": + interpretCommandForSocket(2, command); + break; + case "s3powerOn": + interpretCommandForSocket(3, command); + break; + case "s4powerOn": + interpretCommandForSocket(4, command); + break; + default: + break; + } + } + + private void interpretCommandForSocket(int sid, Command command) { + try { + if (command == OnOffType.ON) { + setStatusOnDevice((byte) sid, (byte) 1); + } else if (command == OnOffType.OFF) { + setStatusOnDevice((byte) sid, (byte) 0); + } + } catch (IOException e) { + logger.warn("Couldn't interpret command for strip device", e); + } + } + + private void setStatusOnDevice(byte sid, byte state) throws IOException { + int sidMask = 1 << sid - 1; + byte payload[] = new byte[16]; + payload[0] = 13; + payload[2] = -91; + payload[3] = -91; + payload[4] = 90; + payload[5] = 90; + if (state == 1) { + payload[6] = (byte) (178 + (sidMask << 1)); + } else { + payload[6] = (byte) (byte) (178 + sidMask); + } + payload[7] = -64; + payload[8] = 2; + payload[10] = 3; + payload[13] = (byte) sidMask; + if (state == 1) { + payload[14] = (byte) sidMask; + } else { + payload[14] = 0; + } + byte message[] = buildMessage((byte) 106, payload); + sendAndReceiveDatagram(message, "Setting MPx status"); + } + + protected boolean getStatusFromDevice() { + byte payload[] = new byte[16]; + payload[0] = 10; + payload[2] = -91; + payload[3] = -91; + payload[4] = 90; + payload[5] = 90; + payload[6] = -82; + payload[7] = -64; + payload[8] = 1; + try { + byte message[] = buildMessage((byte) 106, payload); + byte response[] = sendAndReceiveDatagram(message, "status for strip"); + if (response == null) { + logger.warn("response from strip device was null"); + return false; + } + byte decodedPayload[] = decodeDevicePacket(response); + final int status = decodedPayload[14]; + + this.updateState("s1powerOn", (status & 1) == 1 ? OnOffType.ON : OnOffType.OFF); + this.updateState("s2powerOn", (status & 2) == 2 ? OnOffType.ON : OnOffType.OFF); + this.updateState("s3powerOn", (status & 4) == 4 ? OnOffType.ON : OnOffType.OFF); + this.updateState("s4powerOn", (status & 8) == 8 ? OnOffType.ON : OnOffType.OFF); + } catch (Exception ex) { + logger.warn("Exception while getting status from device", ex); + return false; + } + return true; + } + + protected boolean onBroadlinkDeviceBecomingReachable() { + return getStatusFromDevice(); + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkStripModel2Handler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkStripModel2Handler.java new file mode 100644 index 0000000000000..e136293f17b7e --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkStripModel2Handler.java @@ -0,0 +1,29 @@ +/** + * 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.broadlink.handler; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.thing.Thing; + +/** + * Multiple power socket strip device + * + * @author John Marshall/Cato Sognen - Initial contribution + */ +@NonNullByDefault +public class BroadlinkStripModel2Handler extends BroadlinkSocketModel2Handler { + + public BroadlinkStripModel2Handler(Thing thing) { + super(thing, false); + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkBindingConstants.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkBindingConstants.java new file mode 100644 index 0000000000000..bae11ef5d30be --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkBindingConstants.java @@ -0,0 +1,34 @@ +/** + * 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.broadlink.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.thing.ThingTypeUID; + +/** + * The {@link BroadlinkBindingConstants} class defines common constants, which are + * used across the whole binding. + * + * @author John Marshall - Initial contribution + */ +@NonNullByDefault +public class BroadlinkBindingConstants { + + private static final String BINDING_ID = "broadlink"; + + // List of all Thing Type UIDs + public static final ThingTypeUID THING_TYPE_SAMPLE = new ThingTypeUID(BINDING_ID, "sample"); + + // List of all Channel ids + public static final String CHANNEL_1 = "channel1"; +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkHandlerFactory.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkHandlerFactory.java new file mode 100644 index 0000000000000..2b0e8f91d2625 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkHandlerFactory.java @@ -0,0 +1,116 @@ +/** + * 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.broadlink.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.broadlink.BroadlinkBindingConstants; +import org.openhab.binding.broadlink.handler.BroadlinkA1Handler; +import org.openhab.binding.broadlink.handler.BroadlinkRemoteModel2Handler; +import org.openhab.binding.broadlink.handler.BroadlinkRemoteModel3Handler; +import org.openhab.binding.broadlink.handler.BroadlinkRemoteModel3V44057Handler; +import org.openhab.binding.broadlink.handler.BroadlinkRemoteModel4Handler; +import org.openhab.binding.broadlink.handler.BroadlinkSocketModel1Handler; +import org.openhab.binding.broadlink.handler.BroadlinkSocketModel2Handler; +import org.openhab.binding.broadlink.handler.BroadlinkSocketModel3Handler; +import org.openhab.binding.broadlink.handler.BroadlinkSocketModel3SHandler; +import org.openhab.binding.broadlink.handler.BroadlinkStripModel11K3S2UHandler; +import org.openhab.binding.broadlink.handler.BroadlinkStripModel1Handler; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingTypeUID; +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.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link BroadlinkHandlerFactory} is responsible for creating things and thing + * handlers. + * + * @author John Marshall/Cato Sognen - Initial contribution + */ +@NonNullByDefault +@Component(service = ThingHandlerFactory.class, configurationPid = "binding.broadlink") +public class BroadlinkHandlerFactory extends BaseThingHandlerFactory { + + private final Logger logger = LoggerFactory.getLogger(BroadlinkHandlerFactory.class); + private final BroadlinkRemoteDynamicCommandDescriptionProvider commandDescriptionProvider; + + @Activate + public BroadlinkHandlerFactory( + final @Reference BroadlinkRemoteDynamicCommandDescriptionProvider commandDescriptionProvider) { + this.commandDescriptionProvider = commandDescriptionProvider; + } + + public boolean supportsThingType(ThingTypeUID thingTypeUID) { + return BroadlinkBindingConstants.SUPPORTED_THING_TYPES_UIDS_TO_NAME_MAP.keySet().contains(thingTypeUID); + } + + protected @Nullable ThingHandler createHandler(Thing thing) { + ThingTypeUID thingTypeUID = thing.getThingTypeUID(); + if (logger.isDebugEnabled()) { + logger.debug("Creating Thing handler for '{}'", thingTypeUID.getAsString()); + } + if (thingTypeUID.equals(BroadlinkBindingConstants.THING_TYPE_RM2)) { + logger.debug("RM 2 handler requested created"); + return new BroadlinkRemoteModel2Handler(thing, commandDescriptionProvider); + } + if (thingTypeUID.equals(BroadlinkBindingConstants.THING_TYPE_RM3)) { + logger.debug("RM 3 handler requested created"); + return new BroadlinkRemoteModel3Handler(thing, commandDescriptionProvider); + } + if (thingTypeUID.equals(BroadlinkBindingConstants.THING_TYPE_RM3Q)) { + logger.debug("RM 3 v11057 handler requested created"); + return new BroadlinkRemoteModel3V44057Handler(thing, commandDescriptionProvider); + } + if (thingTypeUID.equals(BroadlinkBindingConstants.THING_TYPE_RM4)) { + logger.debug("RM 4 handler requested created"); + return new BroadlinkRemoteModel4Handler(thing, commandDescriptionProvider); + } + if (thingTypeUID.equals(BroadlinkBindingConstants.THING_TYPE_A1)) { + logger.debug("A1 handler requested created"); + return new BroadlinkA1Handler(thing); + } + if (thingTypeUID.equals(BroadlinkBindingConstants.THING_TYPE_MP1)) { + return new BroadlinkStripModel1Handler(thing); + } + if (thingTypeUID.equals(BroadlinkBindingConstants.THING_TYPE_MP1_1K3S2U)) { + return new BroadlinkStripModel11K3S2UHandler(thing); + } + if (thingTypeUID.equals(BroadlinkBindingConstants.THING_TYPE_SP1)) { + return new BroadlinkSocketModel1Handler(thing); + } + if (thingTypeUID.equals(BroadlinkBindingConstants.THING_TYPE_SP2)) { + return new BroadlinkSocketModel2Handler(thing, false); + } + if (thingTypeUID.equals(BroadlinkBindingConstants.THING_TYPE_SP2S)) { + return new BroadlinkSocketModel2Handler(thing, true); + } + if (thingTypeUID.equals(BroadlinkBindingConstants.THING_TYPE_SP3)) { + return new BroadlinkSocketModel3Handler(thing); + } + if (thingTypeUID.equals(BroadlinkBindingConstants.THING_TYPE_SP3S)) { + return new BroadlinkSocketModel3SHandler(thing); + } + if (thingTypeUID.equals(BroadlinkBindingConstants.THING_TYPE_MP2)) { + return new BroadlinkStripModel1Handler(thing); + } else { + logger.warn("Can't create handler for thing type UID: {}", thingTypeUID.getAsString()); + return null; + } + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkMappingService.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkMappingService.java new file mode 100644 index 0000000000000..175c054c42068 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkMappingService.java @@ -0,0 +1,154 @@ +/** + * 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.broadlink.internal; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardWatchEventKinds; +import java.nio.file.WatchEvent; +import java.nio.file.WatchKey; +import java.nio.file.WatchService; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.stream.Stream; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.OpenHAB; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.types.CommandOption; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This Broadlink-specific mapper watches the given map file and loads the contents + * into a Map in order to offer keys that it then dynamically supplies to the provided + * BroadlinkRemoteDynamicCommandDescriptionProvider. + * + * @author John Marshall - Initial contribution + */ +@NonNullByDefault +public class BroadlinkMappingService { + private static final String TRANSFORM_DIR = OpenHAB.getConfigFolder() + File.separator + "transform" + + File.separator; + private final Logger logger = LoggerFactory.getLogger(BroadlinkMappingService.class); + private final String mapFileName; + private final BroadlinkRemoteDynamicCommandDescriptionProvider commandDescriptionProvider; + private final ChannelUID targetChannelUID; + private final Map commandMap = new HashMap<>(); + + private @Nullable WatchService watchService = null; + private @Nullable WatchKey transformDirWatchKey = null; + private @Nullable Thread watchThread = null; + + public BroadlinkMappingService(String mapFileName, + BroadlinkRemoteDynamicCommandDescriptionProvider commandDescriptionProvider, ChannelUID targetChannelUID) { + this.mapFileName = mapFileName; + this.commandDescriptionProvider = commandDescriptionProvider; + this.targetChannelUID = targetChannelUID; + reloadFromFile(); + startWatching(); + logger.debug("BroadlinkMappingService constructed on behalf of {}", this.targetChannelUID); + } + + public void dispose() { + try { + if (watchThread != null && !watchThread.isInterrupted()) { + watchThread.interrupt(); + watchThread = null; + } + if (this.transformDirWatchKey != null) { + this.transformDirWatchKey.cancel(); + this.transformDirWatchKey = null; + } + if (this.watchService != null) { + this.watchService.close(); + this.watchService = null; + } + } catch (IOException ioe) { + logger.warn("Cannot deactivate watcher", ioe); + } + } + + public @Nullable String lookup(String command) { + return commandMap.get(command); + } + + private Runnable watchingRunnable = new Runnable() { + @Override + public void run() { + while (!Thread.currentThread().isInterrupted()) { + try { + WatchKey key = watchService.take(); // Blocks + List> events = key.pollEvents(); + + Stream> modificationEvents = events.stream() + .filter(e -> e.kind() == StandardWatchEventKinds.ENTRY_MODIFY); + + if (modificationEvents + .anyMatch(e -> ((WatchEvent) e).context().toString().equals(mapFileName))) { + logger.debug("File {} has changed - reloading", mapFileName); + reloadFromFile(); + } + key.reset(); + } catch (InterruptedException x) { + return; + } + } + } + }; + + private void startWatching() { + try { + this.watchService = FileSystems.getDefault().newWatchService(); + this.transformDirWatchKey = Paths.get(TRANSFORM_DIR).register(watchService, + StandardWatchEventKinds.ENTRY_MODIFY); + this.watchThread = new Thread(watchingRunnable, "BroadlinkMappingService-mapfile-watcher"); + this.watchThread.setDaemon(true); + this.watchThread.start(); + } catch (IOException ioe) { + logger.warn("Couldn't setup automatic watch:", ioe); + } + } + + private void reloadFromFile() { + Properties props = new Properties(); + Path mapFilePath = Paths.get(TRANSFORM_DIR + mapFileName); + try (FileReader reader = new FileReader(mapFilePath.toFile())) { + props.load(reader); + commandMap.clear(); + props.stringPropertyNames().forEach(k -> { + commandMap.put(k, props.getProperty(k)); + }); + logger.info("Read {} commands from {}", commandMap.size(), mapFilePath); + notifyAvailableCommands(commandMap.keySet()); + } catch (IOException e) { + logger.warn("Couldn't read {}: {}", mapFilePath, e.getMessage()); + } + } + + private void notifyAvailableCommands(Set commandNames) { + List commandOptions = new ArrayList<>(); + commandNames.forEach((c) -> commandOptions.add(new CommandOption(c, null))); + logger.debug("notifying framework about {} commands from {}", commandOptions.size(), mapFileName); + this.commandDescriptionProvider.setCommandOptions(targetChannelUID, commandOptions); + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkProtocol.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkProtocol.java new file mode 100644 index 0000000000000..e2965ebf98e83 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkProtocol.java @@ -0,0 +1,211 @@ +/** + * 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.broadlink.internal; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.ProtocolException; +import java.util.Calendar; +import java.util.TimeZone; + +import javax.crypto.spec.IvParameterSpec; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.util.HexUtils; +import org.slf4j.Logger; + +/** + * Static methods for working with the Broadlink network prototcol. + * + * @author John Marshall/Cato Sognen - Initial contribution + */ +@NonNullByDefault +public class BroadlinkProtocol { + + public static byte[] buildMessage(byte command, byte[] payload, int count, byte[] mac, byte[] deviceId, byte[] iv, + byte[] key, int deviceType, Logger logger) { + byte packet[] = new byte[0x38]; + packet[0x00] = 0x5a; + packet[0x01] = (byte) 0xa5; // https://stackoverflow.com/questions/20026942/type-mismatch-cannot-convert-int-to-byte + /* + * int 0b10000000 is 128 byte 0b10000000 is -128 + */ + packet[0x02] = (byte) 0xaa; + packet[0x03] = 0x55; + packet[0x04] = 0x5a; + packet[0x05] = (byte) 0xa5; + packet[0x06] = (byte) 0xaa; + packet[0x07] = 0x55; + packet[0x24] = (byte) (deviceType & 0xff); + packet[0x25] = (byte) (deviceType >> 8); + packet[0x26] = command; + packet[0x28] = (byte) (count & 0xff); + packet[0x29] = (byte) (count >> 8); + packet[0x2a] = mac[0]; + packet[0x2b] = mac[1]; + packet[0x2c] = mac[2]; + packet[0x2d] = mac[3]; + packet[0x2e] = mac[4]; + packet[0x2f] = mac[5]; + packet[0x30] = deviceId[0]; + packet[0x31] = deviceId[1]; + packet[0x32] = deviceId[2]; + packet[0x33] = deviceId[3]; + int checksum = 0xBEAF; + int i = 0; + byte abyte0[]; + int k = (abyte0 = payload).length; + for (int j = 0; j < k; j++) { + byte b = abyte0[j]; + i = Byte.toUnsignedInt(b); + checksum += i; + checksum &= 0xffff; + } + packet[0x34] = (byte) (checksum & 0xff); + packet[0x35] = (byte) (checksum >> 8); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try { + outputStream.write(packet); + outputStream.write(Utils.encrypt(key, new IvParameterSpec(iv), payload)); + } catch (IOException e) { + logger.warn("IOException while building message", e); + return packet; + } + byte data[] = outputStream.toByteArray(); + checksum = 0xBEAF; + byte abyte1[]; + int i1 = (abyte1 = data).length; + for (int l = 0; l < i1; l++) { + byte b = abyte1[l]; + i = Byte.toUnsignedInt(b); + checksum += i; + checksum &= 0xffff; + } + data[0x20] = (byte) (checksum & 0xff); + data[0x21] = (byte) (checksum >> 8); + return data; + } + + public static byte[] buildAuthenticationPayload() { + // https://github.com/mjg59/python-broadlink/blob/master/protocol.md + byte payload[] = new byte[0x50]; + payload[0x04] = 0x31; + payload[0x05] = 0x31; + payload[0x06] = 0x31; + payload[0x07] = 0x31; + payload[0x08] = 0x31; + payload[0x09] = 0x31; + payload[0x0a] = 0x31; + payload[0x0b] = 0x31; + payload[0x0c] = 0x31; + payload[0x0d] = 0x31; + payload[0x0e] = 0x31; + payload[0x0f] = 0x31; + payload[0x10] = 0x31; + payload[0x11] = 0x31; + payload[0x12] = 0x31; + payload[0x1e] = 0x01; + payload[0x2d] = 0x01; + payload[0x30] = (byte) 'T'; + payload[0x31] = (byte) 'e'; + payload[0x32] = (byte) 's'; + payload[0x33] = (byte) 't'; + payload[0x34] = (byte) ' '; + payload[0x35] = (byte) ' '; + payload[0x36] = (byte) '1'; + + return payload; + } + + public static byte[] buildDiscoveryPacket(String host, int port) { + String localAddress[] = null; + localAddress = host.toString().split("\\."); + int ipAddress[] = new int[4]; + for (int i = 0; i < 4; i++) { + ipAddress[i] = Integer.parseInt(localAddress[i]); + } + Calendar calendar = Calendar.getInstance(); + calendar.setFirstDayOfWeek(2); + TimeZone timeZone = TimeZone.getDefault(); + int timezone = timeZone.getRawOffset() / 0x36ee80; + byte packet[] = new byte[48]; + if (timezone < 0) { + packet[8] = (byte) ((255 + timezone) - 1); + packet[9] = -1; + packet[10] = -1; + packet[11] = -1; + } else { + packet[8] = 8; + packet[9] = 0; + packet[10] = 0; + packet[11] = 0; + } + packet[12] = (byte) (calendar.get(1) & 0xff); + packet[13] = (byte) (calendar.get(1) >> 8); + packet[14] = (byte) calendar.get(12); + packet[15] = (byte) calendar.get(11); + packet[16] = (byte) (calendar.get(1) - 2000); + packet[17] = (byte) (calendar.get(7) + 1); + packet[18] = (byte) calendar.get(5); + packet[19] = (byte) (calendar.get(2) + 1); + packet[24] = (byte) ipAddress[0]; + packet[25] = (byte) ipAddress[1]; + packet[26] = (byte) ipAddress[2]; + packet[27] = (byte) ipAddress[3]; + packet[28] = (byte) (port & 0xff); + packet[29] = (byte) (port >> 8); + packet[38] = 6; + int checksum = 0xBEAF; + byte abyte0[]; + int k = (abyte0 = packet).length; + for (int j = 0; j < k; j++) { + byte b = abyte0[j]; + checksum += Byte.toUnsignedInt(b); + } + + checksum &= 0xffff; + packet[32] = (byte) (checksum & 0xff); + packet[33] = (byte) (checksum >> 8); + return packet; + } + + public static final int MIN_RESPONSE_PACKET_LENGTH = 0x24; + + public static byte[] decodePacket(byte[] packet, byte[] authorizationKey, String initializationVector) + throws IOException { + if (packet.length < MIN_RESPONSE_PACKET_LENGTH) { + throw new ProtocolException("Unexpectedly short packet; length " + packet.length + + " is shorter than protocol minimum " + MIN_RESPONSE_PACKET_LENGTH); + } + boolean error = (int) packet[0x22] != 0 || (int) packet[0x23] != 0; + if (error) { + throw new ProtocolException(String.format("Response from device is not valid. (0x22=0x%02X,0x23=0x%02X)", + packet[0x22], packet[0x23])); + } + + try { + IvParameterSpec ivSpec = new IvParameterSpec(HexUtils.hexToBytes(initializationVector)); + return Utils.decrypt(authorizationKey, ivSpec, Utils.padTo(Utils.slice(packet, 56, packet.length), 16)); + } catch (Exception ex) { + throw new IOException("Failed while getting device status", ex); + } + } + + public static byte[] getDeviceId(byte response[]) { + return Utils.slice(response, 0, 4); + } + + public static byte[] getDeviceKey(byte response[]) { + return Utils.slice(response, 4, 20); + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkRemoteDynamicCommandDescriptionProvider.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkRemoteDynamicCommandDescriptionProvider.java new file mode 100644 index 0000000000000..6a677f14ab069 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkRemoteDynamicCommandDescriptionProvider.java @@ -0,0 +1,39 @@ +/** + * 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.broadlink.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.thing.binding.BaseDynamicCommandDescriptionProvider; +import org.openhab.core.thing.i18n.ChannelTypeI18nLocalizationService; +import org.openhab.core.thing.type.DynamicCommandDescriptionProvider; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +/** + * The {@link BroadlinkRemoteDynamicCommandDescriptionProvider} allows learnt remote codes + * (from the mapping file) to be selected from the openHAB UI without needing to be + * triggered from a rule etc. + * + * @author John Marshall - Initial contribution + */ +@Component(service = { DynamicCommandDescriptionProvider.class, + BroadlinkRemoteDynamicCommandDescriptionProvider.class }) +@NonNullByDefault +public class BroadlinkRemoteDynamicCommandDescriptionProvider extends BaseDynamicCommandDescriptionProvider { + @Activate + public BroadlinkRemoteDynamicCommandDescriptionProvider( + final @Reference ChannelTypeI18nLocalizationService channelTypeI18nLocalizationService) { + this.channelTypeI18nLocalizationService = channelTypeI18nLocalizationService; + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/ModelMapper.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/ModelMapper.java new file mode 100644 index 0000000000000..b654f9b4d9ea7 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/ModelMapper.java @@ -0,0 +1,158 @@ +/** + * 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.broadlink.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.broadlink.BroadlinkBindingConstants; +import org.openhab.core.library.types.StringType; +import org.openhab.core.thing.ThingTypeUID; +import org.slf4j.Logger; + +/** + * Mappings of internal values to user-visible ones. + * + * @author Cato Sognen - Initial contribution + * @author John Marshall - V2 and V3 updates + */ +@NonNullByDefault +public class ModelMapper { + private static final StringType UNKNOWN = new StringType("UNKNOWN"); + + public static ThingTypeUID getThingType(int model, Logger logger) { + logger.debug("Looking for thing type corresponding to model {}", model); + + switch (model) { + case 0x0000: + return BroadlinkBindingConstants.THING_TYPE_SP1; + case 0x2717: + case 0x2719: + case 0x271A: + case 0x2720: + case 0x2728: + case 0x273E: + case 0x7530: + case 0x7539: + case 0x753E: + case 0x7540: + case 0x7544: + case 0x7546: + case 0x7547: + case 0x7918: + case 0x7919: + case 0x791A: + case 0x7D0D: + return BroadlinkBindingConstants.THING_TYPE_SP2; + case 0x2711: + case 0x2716: + case 0x271D: + case 0x2736: + return BroadlinkBindingConstants.THING_TYPE_SP2S; + case 0x2733: + case 0x7D00: + return BroadlinkBindingConstants.THING_TYPE_SP3; + case 0x9479: + case 0x947A: + return BroadlinkBindingConstants.THING_TYPE_SP3S; + case 0x2737: + case 0x278F: + case 0x27C2: + case 0x27C7: + case 0x27CC: + case 0x27CD: + case 0x27D0: + case 0x27D1: + case 0x27D3: + case 0x27DE: + return BroadlinkBindingConstants.THING_TYPE_RM3; + case 0x2712: + case 0x272A: + case 0x273D: + case 0x277C: + case 0x2783: + case 0x2787: + case 0x278B: + case 0x2797: + case 0x279D: + case 0x27A1: + case 0x27A6: + case 0x27A9: + case 0x27C3: + return BroadlinkBindingConstants.THING_TYPE_RM2; + case 0x5F36: + case 0x6508: + return BroadlinkBindingConstants.THING_TYPE_RM3Q; + case 0x51DA: + case 0x6070: + case 0x610E: + case 0x610F: + case 0x62BC: + case 0x62BE: + case 0x6364: + case 0x648D: + case 0x6539: + case 0x653A: + case 0x6026: + case 0x61A2: + case 0x649B: + case 0x653C: + return BroadlinkBindingConstants.THING_TYPE_RM4; + case 0x2714: + return BroadlinkBindingConstants.THING_TYPE_A1; + case 0x4EB5: + case 0x4EF7: + case 0x4F1B: + case 0x4F65: + return BroadlinkBindingConstants.THING_TYPE_MP1; + default: { + String modelAsHexString = Integer.toHexString(model); + logger.warn( + "Device identifying itself as '{}' (0x{}) is not currently supported. Please report this to the developer!", + model, modelAsHexString); + logger.warn( + "Join the discussion at https://community.openhab.org/t/broadlink-binding-for-rmx-a1-spx-and-mp-any-interest/22768/616"); + throw new UnsupportedOperationException("Device identifying itself as '" + model + "' (hex 0x" + + modelAsHexString + ") is not currently supported. Please report this to the developer!"); + } + } + } + + private static StringType lookup(StringType[] values, byte b) { + int index = Byte.toUnsignedInt(b); + if (index < values.length) { + return values[index]; + } else { + return UNKNOWN; + } + } + + private static final StringType[] AIR_VALUES = { new StringType("PERFECT"), new StringType("GOOD"), + new StringType("NORMAL"), new StringType("BAD") }; + + public static StringType getAirValue(byte b) { + return lookup(AIR_VALUES, b); + } + + private static final StringType[] LIGHT_VALUES = { new StringType("DARK"), new StringType("DIM"), + new StringType("NORMAL"), new StringType("BRIGHT") }; + + public static StringType getLightValue(byte b) { + return lookup(LIGHT_VALUES, b); + } + + private static final StringType[] NOISE_VALUES = { new StringType("QUIET"), new StringType("NORMAL"), + new StringType("NOISY"), new StringType("EXTREME") }; + + public static StringType getNoiseValue(byte b) { + return lookup(NOISE_VALUES, b); + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/NetworkUtils.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/NetworkUtils.java new file mode 100644 index 0000000000000..7fd6e766ee84f --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/NetworkUtils.java @@ -0,0 +1,114 @@ +/** + * 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.broadlink.internal; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.ServerSocket; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.Enumeration; +import java.util.concurrent.ThreadLocalRandom; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.slf4j.Logger; + +/** + * Utilities for working with the local network. + * + * @author John Marshall/Cato Sognen - Initial contribution + */ +@NonNullByDefault +public class NetworkUtils { + + public static boolean hostAvailabilityCheck(@Nullable String host, int timeout, Logger logger) { + if (host == null) { + logger.warn("Can't check availability of a null host"); + return false; + } + try { + InetAddress address = InetAddress.getByName(host); + return address.isReachable(timeout); + } catch (Exception e) { + logger.warn("Exception while trying to determine reachability of {}", host, e); + } + return false; + } + + public static @Nullable InetAddress findNonLoopbackAddress() throws SocketException { + Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); + while (ifaces.hasMoreElements()) { + NetworkInterface iface = ifaces.nextElement(); + Enumeration inetAddrs = iface.getInetAddresses(); + while (inetAddrs.hasMoreElements()) { + InetAddress inetAddr = inetAddrs.nextElement(); + if (inetAddr.isLoopbackAddress()) { + continue; /* Loop/switch isn't completed */ + } + + if (inetAddr.isSiteLocalAddress()) { + return inetAddr; + } + } + } + + return null; + } + + public static InetAddress getLocalHostLANAddress() throws UnknownHostException { + try { + InetAddress candidateAddress = findNonLoopbackAddress(); + + if (candidateAddress != null) { + return candidateAddress; + } + InetAddress jdkSuppliedAddress = InetAddress.getLocalHost(); + if (jdkSuppliedAddress == null) { + throw new UnknownHostException("The JDK InetAddress.getLocalHost() method unexpectedly returned null."); + } else { + return jdkSuppliedAddress; + } + } catch (Exception e) { + UnknownHostException unknownHostException = new UnknownHostException( + (new StringBuilder("Failed to determine LAN address: ")).append(e).toString()); + unknownHostException.initCause(e); + throw unknownHostException; + } + } + + public static int nextFreePort(InetAddress host, int from, int to) { + int port = randInt(from, to); + do { + if (isLocalPortFree(host, port)) { + return port; + } + port = ThreadLocalRandom.current().nextInt(from, to); + } while (true); + } + + public static boolean isLocalPortFree(InetAddress host, int port) { + try { + (new ServerSocket(port, 50, host)).close(); + } catch (IOException e) { + return false; + } + return true; + } + + public static int randInt(int min, int max) { + int randomNum = ThreadLocalRandom.current().nextInt((max - min) + 1) + min; + return randomNum; + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/Utils.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/Utils.java new file mode 100644 index 0000000000000..a4b9b6ea34630 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/Utils.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.broadlink.internal; + +import java.io.IOException; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingStatus; + +/** + * Utilities for working with the Broadlink devices. + * + * @author John Marshall/Cato Sognen - Initial contribution + */ +@NonNullByDefault +public class Utils { + public static boolean isOnline(Thing thing) { + return thing.getStatus().equals(ThingStatus.ONLINE); + } + + public static boolean isOffline(Thing thing) { + return thing.getStatus().equals(ThingStatus.OFFLINE); + } + + public static byte[] slice(byte source[], int from, int to) throws IllegalArgumentException { + if (from > to) { + throw new IllegalArgumentException("Can't slice; from: " + from + " is larger than to: " + to); + } + if (to - from > source.length) { + throw new IllegalArgumentException( + "Can't slice; from: " + from + " - to: " + to + " is longer than source length: " + source.length); + } + if (to == from) { + byte sliced[] = new byte[1]; + sliced[0] = source[from]; + return sliced; + } else { + byte sliced[] = new byte[to - from]; + System.arraycopy(source, from, sliced, 0, to - from); + return sliced; + } + } + + public static byte[] padTo(byte[] source, int quotient) { + int modulo = source.length % quotient; + if (modulo == 0) { + return source; + } + + int requiredNewSize = source.length + (quotient - modulo); + byte[] padded = new byte[requiredNewSize]; + System.arraycopy(source, 0, padded, 0, source.length); + + return padded; + } + + public static String toHexString(byte[] source) { + StringBuilder stringBuilder = new StringBuilder(source.length * 2); + for (byte b : source) { + stringBuilder.append(String.format("%02x", b)); + } + return stringBuilder.toString(); + } + + public static byte[] encrypt(byte key[], IvParameterSpec ivSpec, byte data[]) throws IOException { + SecretKeySpec secretKey = new SecretKeySpec(key, "AES"); + try { + Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); + cipher.init(1, secretKey, ivSpec); + return cipher.doFinal(data); + } catch (Exception e) { + throw new IOException(e); + } + } + + public static byte[] decrypt(byte key[], IvParameterSpec ivSpec, byte data[]) throws IOException { + SecretKeySpec secretKey = new SecretKeySpec(key, "AES"); + try { + Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); + cipher.init(2, secretKey, ivSpec); + return cipher.doFinal(data); + } catch (Exception e) { + throw new IOException(e); + } + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/BroadlinkDiscoveryService.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/BroadlinkDiscoveryService.java new file mode 100644 index 0000000000000..5c1d2b38e0489 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/BroadlinkDiscoveryService.java @@ -0,0 +1,108 @@ +/** + * 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.broadlink.internal.discovery; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.broadlink.BroadlinkBindingConstants; +import org.openhab.binding.broadlink.internal.socket.BroadlinkSocketListener; +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.config.discovery.DiscoveryService; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.ThingUID; +import org.osgi.service.component.annotations.Component; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Broadlink discovery implementation. + * + * @author Cato Sognen - Initial contribution + * @author John Marshall - Rewrite for V2 and V3 + */ +@NonNullByDefault +@Component(service = DiscoveryService.class, configurationPid = "discovery.broadlink") +public class BroadlinkDiscoveryService extends AbstractDiscoveryService + implements BroadlinkSocketListener, DiscoveryFinishedListener { + + private final Logger logger = LoggerFactory.getLogger(BroadlinkDiscoveryService.class); + private int foundCount = 0; + + public BroadlinkDiscoveryService() { + super(BroadlinkBindingConstants.SUPPORTED_THING_TYPES_UIDS_TO_NAME_MAP.keySet(), 10, true); + logger.info("BroadlinkDiscoveryService - Constructed"); + } + + public void startScan() { + foundCount = 0; + logger.warn("BroadlinkDiscoveryService - Beginning Broadlink device scan..."); + DiscoveryProtocol.beginAsync(this, 10000L, this, logger); + } + + public void onDiscoveryFinished() { + logger.info("Discovery complete. Found {} Broadlink devices", foundCount); + } + + protected synchronized void stopScan() { + super.stopScan(); + removeOlderResults(getTimestampOfLastScan()); + } + + public void onDataReceived(String remoteAddress, int remotePort, String remoteMAC, ThingTypeUID thingTypeUID, + int model) { + logger.trace("Data received during Broadlink device discovery: from {}:{} [{}]", remoteAddress, remotePort, + remoteMAC); + foundCount++; + discoveryResultSubmission(remoteAddress, remotePort, remoteMAC, thingTypeUID, model); + } + + private void discoveryResultSubmission(String remoteAddress, int remotePort, String remoteMAC, + ThingTypeUID thingTypeUID, int model) { + String modelAsHexString = String.format("%x", model); + if (logger.isDebugEnabled()) { + logger.debug("Adding new Broadlink device ({} => {}) at {} with mac '{}' to Smarthome inbox", + modelAsHexString, thingTypeUID, remoteAddress, remoteMAC); + } + Map properties = new HashMap(6); + properties.put("ipAddress", remoteAddress); + properties.put("port", Integer.valueOf(remotePort)); + properties.put(Thing.PROPERTY_MAC_ADDRESS, remoteMAC); + properties.put("deviceType", modelAsHexString); + ThingUID thingUID = new ThingUID(thingTypeUID, remoteMAC.replace(":", "-")); + if (logger.isDebugEnabled()) { + logger.debug("Device '{}' discovered at '{}'.", thingUID, remoteAddress); + } + + if (BroadlinkBindingConstants.SUPPORTED_THING_TYPES_UIDS_TO_NAME_MAP.containsKey(thingTypeUID)) { + notifyThingDiscovered(thingTypeUID, thingUID, remoteAddress, properties); + } else { + logger.info("Discovered a {} but do not know how to support it at this time :-(", thingTypeUID); + } + } + + private void notifyThingDiscovered(ThingTypeUID thingTypeUID, ThingUID thingUID, String remoteAddress, + Map properties) { + String deviceHumanName = BroadlinkBindingConstants.SUPPORTED_THING_TYPES_UIDS_TO_NAME_MAP.get(thingTypeUID); + String label = deviceHumanName + " [" + remoteAddress + "]"; + DiscoveryResult result = DiscoveryResultBuilder.create(thingUID).withThingType(thingTypeUID) + .withProperties(properties).withLabel(label).withRepresentationProperty(Thing.PROPERTY_MAC_ADDRESS) + .build(); + + thingDiscovered(result); + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DeviceRediscoveryAgent.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DeviceRediscoveryAgent.java new file mode 100644 index 0000000000000..60d20891aea63 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DeviceRediscoveryAgent.java @@ -0,0 +1,72 @@ +/** + * 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.broadlink.internal.discovery; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.broadlink.config.BroadlinkDeviceConfiguration; +import org.openhab.binding.broadlink.internal.socket.BroadlinkSocketListener; +import org.openhab.core.thing.ThingTypeUID; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This agent exploits the well-known Broadlink device discovery process + * to attempt to "rediscover" a previously-discovered dynamically-addressed + * Broadlink device that may have recently changed IP address. + * + * This agent has NOTHING TO DO WITH the initial device discovery process. + * It is explicitly initiated when a dynamically-addressed Broadlink device + * appears to have dropped off the network. + * + * @author John Marshall - Initial contribution + */ +@NonNullByDefault +public class DeviceRediscoveryAgent implements BroadlinkSocketListener, DiscoveryFinishedListener { + + private final Logger logger = LoggerFactory.getLogger(DeviceRediscoveryAgent.class); + private final BroadlinkDeviceConfiguration missingThingConfig; + private final DeviceRediscoveryListener drl; + private boolean foundDevice = false; + + public DeviceRediscoveryAgent(BroadlinkDeviceConfiguration missingThingConfig, DeviceRediscoveryListener drl) { + this.missingThingConfig = missingThingConfig; + this.drl = drl; + } + + public void attemptRediscovery() { + logger.warn("DeviceRediscoveryAgent - Beginning Broadlink device scan for missing {}", + missingThingConfig.toString()); + DiscoveryProtocol.beginAsync(this, 5000L, this, logger); + } + + public void onDataReceived(String remoteAddress, int remotePort, String remoteMAC, ThingTypeUID thingTypeUID, + int model) { + logger.trace("Data received during Broadlink device rediscovery: from {}:{} [{}]", remoteAddress, remotePort, + remoteMAC); + + // if this thing matches the missingThingConfig, we've found it! + logger.trace("Comparing with desired mac: {}", missingThingConfig.getMacAddressAsString()); + + if (missingThingConfig.getMacAddressAsString().equals(remoteMAC)) { + logger.info("We have a match for target MAC {} at {} - reassociate!", remoteMAC, remoteAddress); + foundDevice = true; + this.drl.onDeviceRediscovered(remoteAddress); + } + } + + public void onDiscoveryFinished() { + if (!foundDevice) { + this.drl.onDeviceRediscoveryFailure(); + } + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DeviceRediscoveryListener.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DeviceRediscoveryListener.java new file mode 100644 index 0000000000000..c45fbf903a579 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DeviceRediscoveryListener.java @@ -0,0 +1,27 @@ +/** + * 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.broadlink.internal.discovery; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Broadlink discovery implementation. + * + * @author John Marshall - Initial contribution + */ +@NonNullByDefault +public interface DeviceRediscoveryListener { + void onDeviceRediscovered(String newIpAddress); + + void onDeviceRediscoveryFailure(); +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DiscoveryFinishedListener.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DiscoveryFinishedListener.java new file mode 100644 index 0000000000000..2bda9265cf472 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DiscoveryFinishedListener.java @@ -0,0 +1,25 @@ +/** + * 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.broadlink.internal.discovery; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Broadlink discovery implementation. + * + * @author John Marshall - Initial contribution + */ +@NonNullByDefault +public interface DiscoveryFinishedListener { + void onDiscoveryFinished(); +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DiscoveryProtocol.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DiscoveryProtocol.java new file mode 100644 index 0000000000000..51c8d1b3309eb --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DiscoveryProtocol.java @@ -0,0 +1,85 @@ +/** + * 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.broadlink.internal.discovery; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.broadlink.internal.BroadlinkProtocol; +import org.openhab.binding.broadlink.internal.NetworkUtils; +import org.openhab.binding.broadlink.internal.socket.BroadlinkSocket; +import org.openhab.binding.broadlink.internal.socket.BroadlinkSocketListener; +import org.slf4j.Logger; + +/** + * @author John Marshall - Initial contribution + */ +@NonNullByDefault +public class DiscoveryProtocol { + + @NonNullByDefault + private static class AsyncDiscoveryThread extends Thread { + private final BroadlinkSocketListener listener; + private final long timeoutMillis; + private final DiscoveryFinishedListener finishedListener; + private final Logger logger; + + AsyncDiscoveryThread(BroadlinkSocketListener listener, long timeoutMillis, + DiscoveryFinishedListener finishedListener, Logger logger) { + this.listener = listener; + this.timeoutMillis = timeoutMillis; + this.finishedListener = finishedListener; + this.logger = logger; + } + + public void run() { + BroadlinkSocket.registerListener(listener, logger); + DiscoveryProtocol.discoverDevices(logger); + DiscoveryProtocol.waitUntilEnded(timeoutMillis, logger); + logger.warn("Ended Broadlink device scan..."); + BroadlinkSocket.unregisterListener(listener, logger); + finishedListener.onDiscoveryFinished(); + } + } + + public static void beginAsync(BroadlinkSocketListener listener, long discoveryTimeoutMillis, + DiscoveryFinishedListener discoveryFinishedListener, Logger logger) { + logger.warn("Beginning async Broadlink device scan; will wait {} ms for responses", discoveryTimeoutMillis); + AsyncDiscoveryThread adt = new AsyncDiscoveryThread(listener, discoveryTimeoutMillis, discoveryFinishedListener, + logger); + adt.start(); + } + + public static void discoverDevices(Logger logger) { + try { + InetAddress localAddress = NetworkUtils.getLocalHostLANAddress(); + int localPort = NetworkUtils.nextFreePort(localAddress, 1024, 3000); + byte message[] = BroadlinkProtocol.buildDiscoveryPacket(localAddress.getHostAddress(), localPort); + BroadlinkSocket.sendMessage(message, "255.255.255.255", 80, logger); + } catch (UnknownHostException e) { + logger.warn("Failed to initiate discovery", e); + } + } + + private static void waitUntilEnded(long discoveryTimeoutMillis, Logger logger) { + try { + logger.warn("Broadlink device scan waiting for {} ms to complete ...", discoveryTimeoutMillis); + Thread.sleep(discoveryTimeoutMillis); + logger.warn("Device scan: wait complete ..."); + + } catch (InterruptedException e) { + logger.warn("problem {}", e.getMessage()); + } + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/BroadlinkSocket.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/BroadlinkSocket.java new file mode 100644 index 0000000000000..50364d008f669 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/BroadlinkSocket.java @@ -0,0 +1,157 @@ +/** + * 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.broadlink.internal.socket; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.InetAddress; +import java.net.MulticastSocket; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.broadlink.internal.ModelMapper; +import org.slf4j.Logger; + +/** + * Threaded socket implementation + * + * @author John Marshall/Cato Sognen - Initial contribution + */ + +@NonNullByDefault +public class BroadlinkSocket { + private static byte buffer[]; + private static DatagramPacket datagramPacket; + @Nullable + private static MulticastSocket socket = null; + @Nullable + private static Thread socketReceiveThread; + private static List listeners = new ArrayList(); + + static { + buffer = new byte[1024]; + datagramPacket = new DatagramPacket(buffer, buffer.length); + } + + public static String decodeMAC(byte mac[]) { + if (mac.length < 6) { + throw new IllegalArgumentException("Insufficient MAC bytes provided, cannot decode it"); + } + + StringBuilder sb = new StringBuilder(18); + for (int i = 5; i >= 0; i--) { + if (sb.length() > 0) { + sb.append(':'); + } + sb.append(String.format("%02x", new Object[] { Byte.valueOf(mac[i]) })); + } + + return sb.toString(); + } + + @NonNullByDefault + private static class ReceiverThread extends Thread { + private Logger logger; + + public void run() { + receiveData(BroadlinkSocket.socket, BroadlinkSocket.datagramPacket); + } + + private void receiveData(@Nullable MulticastSocket socket, DatagramPacket dgram) { + try { + while (true) { + socket.receive(dgram); + BroadlinkSocketListener listener; + byte remoteMAC[]; + org.openhab.core.thing.ThingTypeUID deviceType; + int model; + for (Iterator iterator = (new ArrayList( + BroadlinkSocket.listeners)).iterator(); iterator.hasNext(); listener.onDataReceived( + dgram.getAddress().getHostAddress(), dgram.getPort(), decodeMAC(remoteMAC), + deviceType, model)) { + listener = iterator.next(); + byte receivedPacket[] = dgram.getData(); + remoteMAC = Arrays.copyOfRange(receivedPacket, 58, 64); + model = Byte.toUnsignedInt(receivedPacket[52]) | Byte.toUnsignedInt(receivedPacket[53]) << 8; + deviceType = ModelMapper.getThingType(model, logger); + } + } + } catch (IOException e) { + if (!isInterrupted()) { + logger.warn("Error while receiving", e); + } + } + logger.info("Receiver thread ended"); + } + + private ReceiverThread(Logger logger) { + this.logger = logger; + } + } + + public static void registerListener(BroadlinkSocketListener listener, Logger logger) { + listeners.add(listener); + if (socket == null) { + setupSocket(logger); + } + } + + public static void unregisterListener(BroadlinkSocketListener listener, Logger logger) { + listeners.remove(listener); + if (listeners.isEmpty() && socket != null) { + closeSocket(logger); + } + } + + private static void setupSocket(Logger logger) { + synchronized (BroadlinkSocket.class) { + try { + socket = new MulticastSocket(); + } catch (IOException e) { + logger.warn("Setup socket error '{}'.", e.getMessage()); + } + socketReceiveThread = new ReceiverThread(logger); + socketReceiveThread.start(); + } + } + + private static void closeSocket(Logger logger) { + synchronized (BroadlinkSocket.class) { + if (socketReceiveThread != null) { + socketReceiveThread.interrupt(); + } + if (socket != null) { + logger.info("Socket closed"); + socket.close(); + socket = null; + } + } + } + + public static void sendMessage(byte message[], Logger logger) { + sendMessage(message, "255.255.255.255", 80, logger); + } + + public static void sendMessage(byte message[], String host, int port, Logger logger) { + try { + DatagramPacket sendPacket = new DatagramPacket(message, message.length, InetAddress.getByName(host), port); + socket.send(sendPacket); + } catch (IOException e) { + logger.warn("IO Error sending message: '{}'", e.getMessage()); + } + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/BroadlinkSocketListener.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/BroadlinkSocketListener.java new file mode 100644 index 0000000000000..9fe835fa427cf --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/BroadlinkSocketListener.java @@ -0,0 +1,28 @@ +/** + * 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.broadlink.internal.socket; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.thing.ThingTypeUID; + +/** + * Interface for something that is interested in being informed when data arrives on a socket + * + * @author John Marshall/Cato Sognen - Initial contribution + */ +@NonNullByDefault +public interface BroadlinkSocketListener { + + public abstract void onDataReceived(String remoteAddress, int remotePort, String remoteMAC, + ThingTypeUID thingTypeUID, int model); +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/NetworkTrafficObserver.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/NetworkTrafficObserver.java new file mode 100644 index 0000000000000..679376e6d424f --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/NetworkTrafficObserver.java @@ -0,0 +1,28 @@ +/** + * 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.broadlink.internal.socket; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * @author John Marshall - Initial contribution + */ +@NonNullByDefault +public interface NetworkTrafficObserver { + + public void onCommandSent(byte command); + + public void onBytesSent(byte[] sentBytes); + + public void onBytesReceived(byte[] receivedBytes); +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/RetryableSocket.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/RetryableSocket.java new file mode 100644 index 0000000000000..17d345868903e --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/RetryableSocket.java @@ -0,0 +1,119 @@ +/** + * 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.broadlink.internal.socket; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketTimeoutException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.broadlink.config.BroadlinkDeviceConfiguration; +import org.slf4j.Logger; + +/** + * @author John Marshall - Initial contribution + */ +@NonNullByDefault +public class RetryableSocket { + private final BroadlinkDeviceConfiguration thingConfig; + private final Logger logger; + + private @Nullable DatagramSocket socket = null; + + public RetryableSocket(BroadlinkDeviceConfiguration thingConfig, Logger logger) { + this.thingConfig = thingConfig; + this.logger = logger; + } + + /** + * Send a packet to the device, and expect a response. + * We'll try again if we fail to get any response. + */ + public byte @Nullable [] sendAndReceive(byte message[], String purpose) { + byte[] firstAttempt = sendAndReceiveOneTime(message, purpose); + + if (firstAttempt != null) { + return firstAttempt; + } else { + return sendAndReceiveOneTime(message, purpose); + } + } + + private byte @Nullable [] sendAndReceiveOneTime(byte message[], String purpose) { + // To avoid the possibility of a very fast response not being heard, + // we set up as much as possible for the response ahead of time: + byte response[] = new byte[1024]; + DatagramPacket receivePacket = new DatagramPacket(response, response.length); + if (sendDatagram(message, purpose)) { + receivePacket = receiveDatagram(purpose, receivePacket); + if (receivePacket != null) { + return receivePacket.getData(); + } + } + + return null; + } + + private boolean sendDatagram(byte message[], String purpose) { + try { + logger.trace("Sending {} to {}:{}", purpose, thingConfig.getIpAddress(), thingConfig.getPort()); + if (socket == null || socket.isClosed()) { + logger.trace("No existing socket ... creating"); + socket = new DatagramSocket(); + socket.setBroadcast(true); + socket.setReuseAddress(true); + socket.setSoTimeout(5000); + } + InetAddress host = InetAddress.getByName(thingConfig.getIpAddress()); + int port = thingConfig.getPort(); + DatagramPacket sendPacket = new DatagramPacket(message, message.length, new InetSocketAddress(host, port)); + socket.send(sendPacket); + logger.trace("Sending {} complete", purpose); + return true; + } catch (IOException e) { + logger.warn("IO error during UDP command sending {}:", purpose, e); + return false; + } + } + + private @Nullable DatagramPacket receiveDatagram(String purpose, DatagramPacket receivePacket) { + logger.trace("Awaiting {} response", purpose); + + try { + if (socket == null) { + logger.warn("receiveDatagram {} for socket was unexpectedly null", purpose); + } else { + socket.receive(receivePacket); + logger.trace("Received {} ({} bytes)", purpose, receivePacket.getLength()); + return receivePacket; + } + } catch (SocketTimeoutException ste) { + logger.debug("No further {} response received for device", purpose); + } catch (Exception e) { + logger.warn("While {}", purpose, e); + } + + return null; + } + + public void close() { + if (socket != null) { + socket.close(); + socket = null; + } + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/binding/binding.xml b/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/binding/binding.xml new file mode 100644 index 0000000000000..235788007bd1a --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/binding/binding.xml @@ -0,0 +1,8 @@ + + + + Broadlink Binding + This is the binding for Broadlink devices. + diff --git a/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/config/config.xml b/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/config/config.xml new file mode 100644 index 0000000000000..63b7ebbad1a28 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/config/config.xml @@ -0,0 +1,53 @@ + + + + + + network-address + + Network address of the device. + true + + + static-ip + + Will the device always be given this network address? + true + true + true + + + 80 + network-port + + Network port of the device. + true + true + + + mac-address + + MAC address of the device. + true + + + + The interval in seconds for polling the status of the device. + true + 30 + true + + + ignore-failed-updates + + Should failed status requests force the device offline? + true + true + false + + + diff --git a/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/config/rm-config.xml b/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/config/rm-config.xml new file mode 100644 index 0000000000000..5be431f406ee3 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/config/rm-config.xml @@ -0,0 +1,59 @@ + + + + + + network-address + + Network address of the device. + true + + + static-ip + + Will the device always be given this network address? + true + true + true + + + 80 + network-port + + Network port of the device. + true + true + + + mac-address + + MAC address of the device. + true + + + + The interval in seconds for polling the status of the device. + true + 30 + true + + + + Enter name of file containing mapping of commands to IR codes + broadlink.map + true + + + ignore-failed-updates + + Should failed status requests force the device offline? + true + true + false + + + diff --git a/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/i18n/broadlink_xx.properties b/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/i18n/broadlink_xx.properties new file mode 100644 index 0000000000000..96fcc218eba0d --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/i18n/broadlink_xx.properties @@ -0,0 +1,21 @@ +# FIXME: please substitute the xx with a proper locale, ie. de +# FIXME: please do not add the file to the repo if you add or change no content +# binding +binding.broadlink.name = +binding.broadlink.description = + +# thing types +thing-type.broadlink.sample.label = +thing-type.broadlink.sample.description = + +# thing type config description +thing-type.config.broadlink.sample.hostname.label = +thing-type.config.broadlink.sample.hostname.description = +thing-type.config.broadlink.sample.password.label = +thing-type.config.broadlink.sample.password.description = +thing-type.config.broadlink.sample.refreshInterval.label = +thing-type.config.broadlink.sample.refreshInterval.description = + +# channel types +channel-type.broadlink.sample-channel.label = +channel-type.broadlink.sample-channel.description = diff --git a/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/thing/a-types.xml b/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/thing/a-types.xml new file mode 100644 index 0000000000000..b85e5a4ba5a9d --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/thing/a-types.xml @@ -0,0 +1,21 @@ + + + + + + The Broadlink A1 is a multi sensor that can can detect temperature, humidity, illumination, background + noise and air quality. + + + + + + + + macAddress + + + diff --git a/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/thing/channels.xml b/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/thing/channels.xml new file mode 100644 index 0000000000000..851632593eab1 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/thing/channels.xml @@ -0,0 +1,69 @@ + + + + + String + + The IR/RF command sent to the device + Text + + + String + + Instructs the Broadlink device to perform tasks related to code learning + + + + + + + + + Number:Temperature + + Temperature + + + + Number:Dimensionless + + Humidity + + + + Switch + + PowerOutlet + + + Switch + + Lightbulb + + + Number:Power + + + + + String + + Light conditions + + + + String + + Noise conditions + + + + String + + Air quality conditions + + + diff --git a/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/thing/mp-types.xml b/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/thing/mp-types.xml new file mode 100644 index 0000000000000..b8ad500ff9631 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/thing/mp-types.xml @@ -0,0 +1,58 @@ + + + + + + The Broadlink MP1 Smart Home Wifi Plug Power Strip 4 Ports Individual Wireless Remote Control. + + + + + + + + + + + + + + + macAddress + + + + + The Broadlink MP1 1K3S2U Smart Home Wifi Plug Power Strip 3 AC, 2 USB Individual Wireless Remote Control. + + + + + + + + + + + + + + + macAddress + + + + + The Broadlink MP2 is a smart socket with Wi-Fi connectivity. It does not support switching by individual + ports. + + + + + macAddress + + + diff --git a/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/thing/rm-types.xml b/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/thing/rm-types.xml new file mode 100644 index 0000000000000..876a529391eb2 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/thing/rm-types.xml @@ -0,0 +1,50 @@ + + + + + + The Broadlink RM 2/Pro is a Wi-Fi IR/RF transmitter with a temperature sensor. + + + + + + macAddress + + + + + The Broadlink RM 3/Mini is a Wi-Fi IR transmitter. + + + + + macAddress + + + + + The Broadlink RM 3/Mini is a Wi-Fi IR transmitter running v44057 firmware. + + + + + macAddress + + + + + The Broadlink RM 4 is a Wi-Fi IR transmitter with temperature and humidity sensors. + + + + + + + macAddress + + + diff --git a/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/thing/sp-types.xml b/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/thing/sp-types.xml new file mode 100644 index 0000000000000..2fb827d91a5ca --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/thing/sp-types.xml @@ -0,0 +1,57 @@ + + + + + + The Broadlink SP1 is a Wi-Fi smart socket. + + + + macAddress + + + + + The Broadlink SP2 is a Wi-Fi smart socket. + + + + macAddress + + + + + The Broadlink SP2s is a Wi-Fi smart socket with power consumption measurement. + + + + + macAddress + + + + + The Broadlink SP3 is a Wi-Fi smart socket with night light. The SP mini 3 omits the night light. + + + + + + + macAddress + + + + + The Broadlink SP3s is a Wi-Fi smart socket with power consumption measurement + + + + + macAddress + + + diff --git a/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/thing/thing-types.xml new file mode 100644 index 0000000000000..7dd2d6f7d2eb9 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/main/resources/OH-INF/thing/thing-types.xml @@ -0,0 +1,46 @@ + + + + + + + + + Sample thing for Broadlink Binding + + + + + + + + network-address + + Hostname or IP address of the device + + + password + + Passwort to access the device + + + + Interval the device is polled in sec. + + + + + + + Number:Temperature + + Sample channel for Broadlink Binding + + diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/AbstractBroadlinkTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/AbstractBroadlinkTest.java new file mode 100644 index 0000000000000..3970ce768c4d2 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/AbstractBroadlinkTest.java @@ -0,0 +1,43 @@ +/** + * 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.broadlink; + +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.openhab.core.OpenHAB; + +/** + * Abstract superclass for all Broadlink unit tests; + * ensures that the mapping file will be found + * in a testing context + * + * @author John Marshall - Initial contribution + */ +@NonNullByDefault +public abstract class AbstractBroadlinkTest { + protected static final Path TEST_CONF_DIRECTORY = Paths.get("src", "test", "resources", "conf"); + + @BeforeClass + public static void beforeClass() { + System.setProperty(OpenHAB.CONFIG_DIR_PROG_ARGUMENT, TEST_CONF_DIRECTORY.toFile().getAbsolutePath()); + } + + @AfterClass + public static void afterClass() { + System.clearProperty(OpenHAB.CONFIG_DIR_PROG_ARGUMENT); + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/AbstractBroadlinkThingHandlerTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/AbstractBroadlinkThingHandlerTest.java new file mode 100644 index 0000000000000..1e933f82f0756 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/AbstractBroadlinkThingHandlerTest.java @@ -0,0 +1,83 @@ +/** + * 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.broadlink.handler; + +import static org.openhab.binding.broadlink.BroadlinkBindingConstants.BROADLINK_AUTH_KEY; +import static org.openhab.binding.broadlink.BroadlinkBindingConstants.BROADLINK_IV; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.mockito.Mockito; +import org.openhab.binding.broadlink.AbstractBroadlinkTest; +import org.openhab.binding.broadlink.BroadlinkBindingConstants; +import org.openhab.binding.broadlink.internal.BroadlinkProtocol; +import org.openhab.binding.broadlink.internal.BroadlinkRemoteDynamicCommandDescriptionProvider; +import org.openhab.binding.broadlink.internal.socket.NetworkTrafficObserver; +import org.openhab.binding.broadlink.internal.socket.RetryableSocket; +import org.openhab.core.config.core.Configuration; +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.binding.ThingHandlerCallback; +import org.openhab.core.thing.internal.ThingImpl; +import org.openhab.core.util.HexUtils; +import org.slf4j.LoggerFactory; + +/** + * Abstract thing handler test. + * + * @author John Marshall/Cato Sognen - Initial contribution + */ +@NonNullByDefault +public abstract class AbstractBroadlinkThingHandlerTest extends AbstractBroadlinkTest { + + protected Map properties = new HashMap<>(); + protected Configuration config = new Configuration(); + protected ThingImpl thing = new ThingImpl(BroadlinkBindingConstants.THING_TYPE_A1, "a1"); + + protected RetryableSocket mockSocket = Mockito.mock(RetryableSocket.class); + protected NetworkTrafficObserver trafficObserver = Mockito.mock(NetworkTrafficObserver.class); + protected ThingHandlerCallback mockCallback = Mockito.mock(ThingHandlerCallback.class); + protected BroadlinkRemoteDynamicCommandDescriptionProvider commandDescriptionProvider = Mockito + .mock(BroadlinkRemoteDynamicCommandDescriptionProvider.class); + + protected void configureUnderlyingThing(ThingTypeUID thingTypeUID, String thingId) { + properties = new HashMap<>(); + properties.put("authorizationKey", "097628343fe99e23765c1513accf8b02"); + properties.put(Thing.PROPERTY_MAC_ADDRESS, "AB:CD:AB:CD:AB:CD"); + properties.put("iv", "562e17996d093d28ddb3ba695a2e6f58"); + config = new Configuration(properties); + + thing = new ThingImpl(thingTypeUID, thingId); + thing.setConfiguration(config); + thing.setStatusInfo(new ThingStatusInfo(ThingStatus.ONLINE, ThingStatusDetail.NONE, null)); + } + + protected void setMocksForTesting(BroadlinkBaseThingHandler handler) { + handler.setSocket(mockSocket); + handler.setNetworkTrafficObserver(trafficObserver); + handler.setCallback(mockCallback); + handler.initialize(); + } + + protected byte[] generateReceivedBroadlinkMessage(byte[] payload) { + byte[] mac = { 0x11, 0x22, 0x11, 0x22, 0x11, 0x22 }; + byte[] devId = { 0x11, 0x22, 0x11, 0x22 }; + return BroadlinkProtocol.buildMessage((byte) 0x6a, payload, 99, mac, devId, HexUtils.hexToBytes(BROADLINK_IV), + HexUtils.hexToBytes(BROADLINK_AUTH_KEY), 0x2714, LoggerFactory.getLogger(getClass())); + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel2HandlerTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel2HandlerTest.java new file mode 100644 index 0000000000000..5e18195a675c1 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel2HandlerTest.java @@ -0,0 +1,147 @@ +/** + * 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.broadlink.handler; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; + +import java.io.IOException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.openhab.binding.broadlink.BroadlinkBindingConstants; + +/** + * Tests the Remote Model 2 handler. + * + * @author John Marshall - Initial contribution + */ +@NonNullByDefault +public class BroadlinkRemoteModel2HandlerTest extends AbstractBroadlinkThingHandlerTest { + + @Before + public void setUp() { + configureUnderlyingThing(BroadlinkBindingConstants.THING_TYPE_RM2, "rm2-test"); + MockitoAnnotations.initMocks(this); + Mockito.when(mockSocket.sendAndReceive(Mockito.any(byte[].class), Mockito.anyString())).thenReturn(response); + } + + private byte[] response = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; + + @Test + public void sendsExpectedBytesWhenGettingDeviceStatus() { + ArgumentCaptor commandCaptor = ArgumentCaptor.forClass(Byte.class); + ArgumentCaptor byteArrayCaptor = ArgumentCaptor.forClass(byte[].class); + BroadlinkRemoteHandler model2 = new BroadlinkRemoteModel2Handler(thing, commandDescriptionProvider); + setMocksForTesting(model2); + reset(trafficObserver); + model2.getStatusFromDevice(); + + verify(trafficObserver).onCommandSent(commandCaptor.capture()); + assertEquals(0x6a, commandCaptor.getValue().byteValue()); + + verify(trafficObserver).onBytesSent(byteArrayCaptor.capture()); + + byte[] sentBytes = byteArrayCaptor.getValue(); + assertEquals(16, sentBytes.length); + assertEquals(0x01, sentBytes[0]); + } + + @Test + public void sendsExpectedBytesWhenSendingCode() throws IOException { + ArgumentCaptor commandCaptor = ArgumentCaptor.forClass(Byte.class); + ArgumentCaptor byteCaptor = ArgumentCaptor.forClass(byte[].class); + BroadlinkRemoteHandler model2 = new BroadlinkRemoteModel2Handler(thing, commandDescriptionProvider); + setMocksForTesting(model2); + // Note the length is 12 so as to not require padding + byte[] code = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a }; + + reset(trafficObserver); + model2.sendCode(code); + + verify(trafficObserver).onCommandSent(commandCaptor.capture()); + assertEquals(0x6a, commandCaptor.getValue().byteValue()); + + verify(trafficObserver).onBytesSent(byteCaptor.capture()); + + byte[] sentBytes = byteCaptor.getValue(); + assertEquals(16, sentBytes.length); + + assertEquals(0x02, sentBytes[0]); // 0x00, 0x00, 0x00 + + assertEquals(0x01, sentBytes[4]); + assertEquals(0x02, sentBytes[5]); + assertEquals(0x03, sentBytes[6]); + assertEquals(0x04, sentBytes[7]); + assertEquals(0x05, sentBytes[8]); + assertEquals(0x06, sentBytes[9]); + assertEquals(0x07, sentBytes[10]); + assertEquals(0x08, sentBytes[11]); + assertEquals(0x09, sentBytes[12]); + assertEquals(0x0a, sentBytes[13]); + } + + @Test + public void sendsExpectedBytesWhenSendingCodeIncludingPadding() throws IOException { + ArgumentCaptor commandCaptor = ArgumentCaptor.forClass(Byte.class); + ArgumentCaptor byteCaptor = ArgumentCaptor.forClass(byte[].class); + BroadlinkRemoteHandler model2 = new BroadlinkRemoteModel2Handler(thing, commandDescriptionProvider); + setMocksForTesting(model2); + // Note the length is such that padding up to the next multiple of 16 will be needed + byte[] code = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11 }; + reset(trafficObserver); + model2.sendCode(code); + + verify(trafficObserver).onCommandSent(commandCaptor.capture()); + assertEquals(0x6a, commandCaptor.getValue().byteValue()); + + verify(trafficObserver).onBytesSent(byteCaptor.capture()); + + byte[] sentBytes = byteCaptor.getValue(); + assertEquals(32, sentBytes.length); + + assertEquals(0x02, sentBytes[0]); // 0x00, 0x00, 0x00 + + assertEquals(0x01, sentBytes[4]); + assertEquals(0x02, sentBytes[5]); + assertEquals(0x03, sentBytes[6]); + assertEquals(0x04, sentBytes[7]); + assertEquals(0x05, sentBytes[8]); + assertEquals(0x06, sentBytes[9]); + assertEquals(0x07, sentBytes[10]); + assertEquals(0x08, sentBytes[11]); + assertEquals(0x09, sentBytes[12]); + assertEquals(0x0a, sentBytes[13]); + assertEquals(0x0b, sentBytes[14]); + assertEquals(0x0c, sentBytes[15]); + assertEquals(0x0d, sentBytes[16]); + assertEquals(0x0e, sentBytes[17]); + assertEquals(0x0f, sentBytes[18]); + assertEquals(0x10, sentBytes[19]); + assertEquals(0x11, sentBytes[20]); + assertEquals(0x00, sentBytes[21]); + assertEquals(0x00, sentBytes[31]); + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3HandlerTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3HandlerTest.java new file mode 100644 index 0000000000000..dd76dad3f775e --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3HandlerTest.java @@ -0,0 +1,88 @@ +/** + * 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.broadlink.handler; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.openhab.binding.broadlink.BroadlinkBindingConstants.LEARNING_CONTROL_COMMAND_LEARN; + +import java.io.IOException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.openhab.binding.broadlink.BroadlinkBindingConstants; + +/** + * Tests the Remote Model 3 handler. + * + * @author John Marshall - Initial contribution + */ +@NonNullByDefault +public class BroadlinkRemoteModel3HandlerTest extends AbstractBroadlinkThingHandlerTest { + + @Before + public void setUp() { + configureUnderlyingThing(BroadlinkBindingConstants.THING_TYPE_RM3, "rm3-test"); + MockitoAnnotations.initMocks(this); + Mockito.when(mockSocket.sendAndReceive(Mockito.any(byte[].class), Mockito.anyString())).thenReturn(response); + } + + private byte[] response = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; + + @Test + public void sendsExpectedBytesWhenEnteringLearnMode() throws IOException { + ArgumentCaptor commandCaptor = ArgumentCaptor.forClass(Byte.class); + ArgumentCaptor byteCaptor = ArgumentCaptor.forClass(byte[].class); + BroadlinkRemoteHandler model3 = new BroadlinkRemoteModel3Handler(thing, commandDescriptionProvider); + setMocksForTesting(model3); + + reset(trafficObserver); + model3.handleLearningCommand(LEARNING_CONTROL_COMMAND_LEARN); + + verify(trafficObserver).onCommandSent(commandCaptor.capture()); + assertEquals(0x6a, commandCaptor.getValue().byteValue()); + + verify(trafficObserver).onBytesSent(byteCaptor.capture()); + + byte[] sentBytes = byteCaptor.getValue(); + assertEquals(16, sentBytes.length); + + assertEquals(0x03, sentBytes[0]); // 0x03, then fifteen zeroes + assertEquals(0x00, sentBytes[1]); + assertEquals(0x00, sentBytes[2]); + assertEquals(0x00, sentBytes[3]); + assertEquals(0x00, sentBytes[4]); + assertEquals(0x00, sentBytes[5]); + assertEquals(0x00, sentBytes[6]); + assertEquals(0x00, sentBytes[7]); + assertEquals(0x00, sentBytes[8]); + assertEquals(0x00, sentBytes[9]); + assertEquals(0x00, sentBytes[10]); + assertEquals(0x00, sentBytes[11]); + assertEquals(0x00, sentBytes[12]); + assertEquals(0x00, sentBytes[13]); + assertEquals(0x00, sentBytes[14]); + assertEquals(0x00, sentBytes[15]); + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4HandlerTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4HandlerTest.java new file mode 100644 index 0000000000000..344e6e84f447d --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4HandlerTest.java @@ -0,0 +1,233 @@ +/** + * 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.broadlink.handler; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.*; +import static org.openhab.binding.broadlink.BroadlinkBindingConstants.*; + +import java.io.IOException; +import java.util.List; + +import javax.measure.quantity.Dimensionless; +import javax.measure.quantity.Temperature; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.openhab.binding.broadlink.BroadlinkBindingConstants; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.types.State; + +/** + * Tests the Remote Model 4 handler. + * + * @author John Marshall - Initial contribution + */ +@NonNullByDefault +public class BroadlinkRemoteModel4HandlerTest extends AbstractBroadlinkThingHandlerTest { + + private byte[] response = { (byte) 0x5a, (byte) 0xa5, (byte) 0xaa, (byte) 0x55, (byte) 0x5a, (byte) 0xa5, + (byte) 0xaa, (byte) 0x55, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0xf6, (byte) 0xcd, (byte) 0x00, (byte) 0x00, (byte) 0x14, (byte) 0x27, + (byte) 0x6a, (byte) 0x00, (byte) 0x63, (byte) 0x00, (byte) 0x11, (byte) 0x22, (byte) 0x11, (byte) 0x22, + (byte) 0x11, (byte) 0x22, (byte) 0x11, (byte) 0x22, (byte) 0x11, (byte) 0x22, (byte) 0x00, (byte) 0xc0, + (byte) 0x00, (byte) 0x00, (byte) 0x09, (byte) 0x9a, (byte) 0x60, (byte) 0xfb, (byte) 0x72, (byte) 0x07, + (byte) 0x4f, (byte) 0x89, (byte) 0xf8, (byte) 0xb4, (byte) 0xdb, (byte) 0xb0, (byte) 0x72, (byte) 0xe7, + (byte) 0x1f, (byte) 0x86, }; + + @Before + public void setUp() { + configureUnderlyingThing(BroadlinkBindingConstants.THING_TYPE_RM4, "rm4-test"); + MockitoAnnotations.initMocks(this); + Mockito.when(mockSocket.sendAndReceive(Mockito.any(byte[].class), Mockito.anyString())).thenReturn(response); + } + + @Test + public void sendsExpectedBytesWhenGettingDeviceStatus() { + ArgumentCaptor commandCaptor = ArgumentCaptor.forClass(Byte.class); + + ArgumentCaptor byteCaptor = ArgumentCaptor.forClass(byte[].class); + BroadlinkRemoteHandler model4 = new BroadlinkRemoteModel4Handler(thing, commandDescriptionProvider); + setMocksForTesting(model4); + reset(trafficObserver); + model4.getStatusFromDevice(); + + verify(trafficObserver).onCommandSent(commandCaptor.capture()); + assertEquals(0x6a, commandCaptor.getValue().byteValue()); + + verify(trafficObserver).onBytesSent(byteCaptor.capture()); + + byte[] sentBytes = byteCaptor.getValue(); + assertEquals(16, sentBytes.length); + + assertEquals(0x04, sentBytes[0]); + assertEquals(0x00, sentBytes[1]); + assertEquals(0x24, sentBytes[2]); + } + + @Test + public void sendsExpectedBytesWhenSendingCode() throws IOException { + ArgumentCaptor commandCaptor = ArgumentCaptor.forClass(Byte.class); + ArgumentCaptor byteCaptor = ArgumentCaptor.forClass(byte[].class); + BroadlinkRemoteHandler model4 = new BroadlinkRemoteModel4Handler(thing, commandDescriptionProvider); + setMocksForTesting(model4); + // Note the length is 10 so as to not require padding (6 byte preamble) + byte[] code = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a }; + + reset(trafficObserver); + model4.sendCode(code); + + verify(trafficObserver).onCommandSent(commandCaptor.capture()); + assertEquals(0x6a, commandCaptor.getValue().byteValue()); + + verify(trafficObserver).onBytesSent(byteCaptor.capture()); + + byte[] sentBytes = byteCaptor.getValue(); + assertEquals(16, sentBytes.length); + + assertEquals((byte) 0x0e, (byte) sentBytes[0]); + assertEquals(0x00, sentBytes[1]); + + assertEquals(0x02, sentBytes[2]); + assertEquals(0x00, sentBytes[3]); + assertEquals(0x00, sentBytes[4]); + assertEquals(0x00, sentBytes[5]); + + assertEquals(0x01, sentBytes[6]); + assertEquals(0x02, sentBytes[7]); + assertEquals(0x03, sentBytes[8]); + assertEquals(0x04, sentBytes[9]); + assertEquals(0x05, sentBytes[10]); + assertEquals(0x06, sentBytes[11]); + assertEquals(0x07, sentBytes[12]); + assertEquals(0x08, sentBytes[13]); + assertEquals(0x09, sentBytes[14]); + assertEquals(0x0a, sentBytes[15]); + } + + @Test + public void sendsExpectedBytesWhenSendingCodeIncludingPadding() throws IOException { + ArgumentCaptor commandCaptor = ArgumentCaptor.forClass(Byte.class); + ArgumentCaptor byteCaptor = ArgumentCaptor.forClass(byte[].class); + BroadlinkRemoteHandler model4 = new BroadlinkRemoteModel4Handler(thing, commandDescriptionProvider); + setMocksForTesting(model4); + // Note the length is such that padding up to the next multiple of 16 will be needed + byte[] code = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b }; + reset(trafficObserver); + model4.sendCode(code); + + verify(trafficObserver).onCommandSent(commandCaptor.capture()); + assertEquals(0x6a, commandCaptor.getValue().byteValue()); + + verify(trafficObserver).onBytesSent(byteCaptor.capture()); + + byte[] sentBytes = byteCaptor.getValue(); + assertEquals(32, sentBytes.length); + + // Calculated length field is len(data) + 4 ===> 11 + 4 = 15 = 0x0f + + assertEquals((byte) 0x0f, (byte) sentBytes[0]); + assertEquals(0x00, sentBytes[1]); + + assertEquals(0x02, sentBytes[2]); // The "send code" command + + assertEquals(0x01, sentBytes[6]); // The payload + assertEquals(0x02, sentBytes[7]); + assertEquals(0x03, sentBytes[8]); + assertEquals(0x04, sentBytes[9]); + assertEquals(0x05, sentBytes[10]); + assertEquals(0x06, sentBytes[11]); + assertEquals(0x07, sentBytes[12]); + assertEquals(0x08, sentBytes[13]); + assertEquals(0x09, sentBytes[14]); + assertEquals(0x0a, sentBytes[15]); + assertEquals(0x0b, sentBytes[16]); + assertEquals(0x00, sentBytes[17]); + } + + @Test + public void setsTheTemperatureAndHumidityChannelsAfterGettingStatus() { + BroadlinkRemoteHandler model4 = new BroadlinkRemoteModel4Handler(thing, commandDescriptionProvider); + setMocksForTesting(model4); + reset(mockCallback); + + model4.getStatusFromDevice(); + + ArgumentCaptor channelCaptor = ArgumentCaptor.forClass(ChannelUID.class); + ArgumentCaptor stateCaptor = ArgumentCaptor.forClass(State.class); + verify(mockCallback, times(2)).stateUpdated(channelCaptor.capture(), stateCaptor.capture()); + + List channelCaptures = channelCaptor.getAllValues(); + List stateCaptures = stateCaptor.getAllValues(); + + ChannelUID expectedTemperatureChannel = new ChannelUID(thing.getUID(), CHANNEL_TEMPERATURE); + assertEquals(expectedTemperatureChannel, channelCaptures.get(0)); + + QuantityType expectedTemperature = new QuantityType<>(21.22, + BroadlinkBindingConstants.BROADLINK_TEMPERATURE_UNIT); + assertEquals(expectedTemperature, stateCaptures.get(0)); + + ChannelUID expectedHumidityChannel = new ChannelUID(thing.getUID(), CHANNEL_HUMIDITY); + assertEquals(expectedHumidityChannel, channelCaptures.get(1)); + + QuantityType expectedHumidity = new QuantityType(39.4, + BroadlinkBindingConstants.BROADLINK_HUMIDITY_UNIT); + assertEquals(expectedHumidity, stateCaptures.get(1)); + } + + @Test + public void sendsExpectedBytesWhenEnteringLearnMode() throws IOException { + ArgumentCaptor commandCaptor = ArgumentCaptor.forClass(Byte.class); + ArgumentCaptor byteCaptor = ArgumentCaptor.forClass(byte[].class); + BroadlinkRemoteHandler model4 = new BroadlinkRemoteModel4Handler(thing, commandDescriptionProvider); + setMocksForTesting(model4); + + reset(trafficObserver); + model4.handleLearningCommand(LEARNING_CONTROL_COMMAND_LEARN); + + verify(trafficObserver).onCommandSent(commandCaptor.capture()); + assertEquals(0x6a, commandCaptor.getValue().byteValue()); + + verify(trafficObserver).onBytesSent(byteCaptor.capture()); + + byte[] sentBytes = byteCaptor.getValue(); + assertEquals(16, sentBytes.length); + + // Expecting: + // PLl, PLh, 0 0 0 then padding for the rest up to 16 + // Where PL = length(data) + 4 - so in this case, 4 + assertEquals(0x04, sentBytes[0]); // Low length byte + assertEquals(0x00, sentBytes[1]); // High length byte + assertEquals(0x03, sentBytes[2]); + assertEquals(0x00, sentBytes[3]); + assertEquals(0x00, sentBytes[4]); + assertEquals(0x00, sentBytes[5]); + assertEquals(0x00, sentBytes[6]); + assertEquals(0x00, sentBytes[7]); + assertEquals(0x00, sentBytes[8]); + assertEquals(0x00, sentBytes[9]); + assertEquals(0x00, sentBytes[10]); + assertEquals(0x00, sentBytes[11]); + assertEquals(0x00, sentBytes[12]); + assertEquals(0x00, sentBytes[13]); + assertEquals(0x00, sentBytes[14]); + assertEquals(0x00, sentBytes[15]); + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel2HandlerTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel2HandlerTest.java new file mode 100644 index 0000000000000..757c762d57162 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel2HandlerTest.java @@ -0,0 +1,172 @@ +/** + * 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.broadlink.handler; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.openhab.binding.broadlink.BroadlinkBindingConstants.CHANNEL_POWER_CONSUMPTION; +import static org.openhab.binding.broadlink.BroadlinkBindingConstants.COMMAND_POWER_ON; + +import java.io.IOException; +import java.util.List; + +import javax.measure.quantity.Power; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.openhab.binding.broadlink.BroadlinkBindingConstants; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.types.State; + +/** + * Tests the Socket Model 2 handler. + * + * @author John Marshall - Initial contribution + */ +@NonNullByDefault +public class BroadlinkSocketModel2HandlerTest extends AbstractBroadlinkThingHandlerTest { + + private final byte[] response = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; + + @Before + public void setUp() { + configureUnderlyingThing(BroadlinkBindingConstants.THING_TYPE_SP2, "sp2-test"); + MockitoAnnotations.initMocks(this); + Mockito.when(mockSocket.sendAndReceive(Mockito.any(byte[].class), Mockito.anyString())).thenReturn(response); + } + + @Test + public void derivePowerStateBitsOff() { + BroadlinkSocketModel2Handler model2 = new BroadlinkSocketModel2Handler(thing, false); + byte[] payload = { 0x00, 0x00, 0x00, 0x00, 0x00 }; + OnOffType result = model2.derivePowerStateFromStatusBytes(payload); + assertEquals(OnOffType.OFF, result); + } + + @Test + public void derivePowerStateBitsOn1() { + BroadlinkSocketModel2Handler model2 = new BroadlinkSocketModel2Handler(thing, false); + byte[] payload = { 0x00, 0x00, 0x00, 0x00, 0x01 }; + OnOffType result = model2.derivePowerStateFromStatusBytes(payload); + assertEquals(OnOffType.ON, result); + } + + @Test + public void derivePowerStateBitsOn3() { + BroadlinkSocketModel2Handler model2 = new BroadlinkSocketModel2Handler(thing, false); + byte[] payload = { 0x00, 0x00, 0x00, 0x00, 0x03 }; + OnOffType result = model2.derivePowerStateFromStatusBytes(payload); + assertEquals(OnOffType.ON, result); + } + + @Test + public void derivePowerStateBitsOnFD() { + BroadlinkSocketModel2Handler model2 = new BroadlinkSocketModel2Handler(thing, false); + byte[] payload = { 0x00, 0x00, 0x00, 0x00, (byte) 0xFD }; + OnOffType result = model2.derivePowerStateFromStatusBytes(payload); + assertEquals(OnOffType.ON, result); + } + + @Test + public void derivePowerConsumptionFromStatusBytesTooShort() throws IOException { + BroadlinkSocketModel2Handler model2 = new BroadlinkSocketModel2Handler(thing, false); + byte[] payload = { 0x00, 0x00, 0x00, 0x00, 0x33 }; + double result = model2.derivePowerConsumption(payload); + assertEquals(0D, result, 0.1D); + } + + @Test + public void derivePowerConsumptionFromStatusBytesCorrect() throws IOException { + BroadlinkSocketModel2Handler model2 = new BroadlinkSocketModel2Handler(thing, false); + byte[] payload = { 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00 }; + double result = model2.derivePowerConsumption(payload); + assertEquals(66.051D, result, 0.1D); + } + + @Test + public void setsThePowerChannelOnlyAfterGettingStatusOnSP2() { + byte[] response = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, }; + Mockito.when(mockSocket.sendAndReceive(Mockito.any(byte[].class), Mockito.anyString())).thenReturn(response); + BroadlinkSocketHandler model2 = new BroadlinkSocketModel2Handler(thing, false); + setMocksForTesting(model2); + + reset(mockCallback); + + model2.getStatusFromDevice(); + + ArgumentCaptor channelCaptor = ArgumentCaptor.forClass(ChannelUID.class); + ArgumentCaptor stateCaptor = ArgumentCaptor.forClass(State.class); + verify(mockCallback).stateUpdated(channelCaptor.capture(), stateCaptor.capture()); + + ChannelUID expectedPowerChannel = new ChannelUID(thing.getUID(), COMMAND_POWER_ON); + assertEquals(expectedPowerChannel, channelCaptor.getValue()); + + assertEquals(OnOffType.ON, stateCaptor.getValue()); + } + + @Test + public void setsThePowerAndPowerConsumptionAfterGettingStatusOnSP2S() { + // Power bytes are 4, 5, 6 (little-endian) + // So here it's 0x38291 => 230033, divided by 1000 ==> 230.033W + byte[] payload = { 0x08, 0x00, 0x11, 0x22, (byte) 0x91, (byte) 0x82, 0x3, 0x16, 0x27, 0x28, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x16 }; + byte[] responseMessage = generateReceivedBroadlinkMessage(payload); + Mockito.when(mockSocket.sendAndReceive(Mockito.any(byte[].class), Mockito.anyString())) + .thenReturn(responseMessage); + BroadlinkSocketHandler model2s = new BroadlinkSocketModel2Handler(thing, true); + setMocksForTesting(model2s); + + reset(mockCallback); + + model2s.getStatusFromDevice(); + + ArgumentCaptor channelCaptor = ArgumentCaptor.forClass(ChannelUID.class); + ArgumentCaptor stateCaptor = ArgumentCaptor.forClass(State.class); + verify(mockCallback, Mockito.times(2)).stateUpdated(channelCaptor.capture(), stateCaptor.capture()); + + List channels = channelCaptor.getAllValues(); + List states = stateCaptor.getAllValues(); + + ChannelUID expectedPowerChannel = new ChannelUID(thing.getUID(), COMMAND_POWER_ON); + assertEquals(expectedPowerChannel, channels.get(0)); + + assertEquals(OnOffType.ON, states.get(0)); + + ChannelUID expectedConsumptionChannel = new ChannelUID(thing.getUID(), CHANNEL_POWER_CONSUMPTION); + assertEquals(expectedConsumptionChannel, channels.get(1)); + + QuantityType expectedPower = new QuantityType<>(230.033, + BroadlinkBindingConstants.BROADLINK_POWER_CONSUMPTION_UNIT); + assertEquals(expectedPower, states.get(1)); + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3HandlerTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3HandlerTest.java new file mode 100644 index 0000000000000..43368d8117ab7 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3HandlerTest.java @@ -0,0 +1,142 @@ +/** + * 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.broadlink.handler; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.openhab.binding.broadlink.BroadlinkBindingConstants.*; +import static org.openhab.binding.broadlink.handler.BroadlinkSocketModel3Handler.mergeOnOffBits; + +import java.util.List; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.openhab.binding.broadlink.BroadlinkBindingConstants; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.types.State; + +/** + * Tests the Socket Model 3 handler. + * + * @author John Marshall - Initial contribution + */ +@NonNullByDefault +public class BroadlinkSocketModel3HandlerTest extends AbstractBroadlinkThingHandlerTest { + + private final byte[] response = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; + + private final BroadlinkSocketModel3Handler model3; + + public BroadlinkSocketModel3HandlerTest() { + super(); + configureUnderlyingThing(BroadlinkBindingConstants.THING_TYPE_SP3, "sp3-test"); + model3 = new BroadlinkSocketModel3Handler(thing); + } + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + Mockito.when(mockSocket.sendAndReceive(Mockito.any(byte[].class), Mockito.anyString())).thenReturn(response); + } + + @Test + public void mergeOnOffBitsAllZero() { + int result = mergeOnOffBits(OnOffType.OFF, OnOffType.OFF); + assertEquals(0x00, result); + } + + @Test + public void mergeOnOffBitsPowerOn() { + int result = mergeOnOffBits(OnOffType.ON, OnOffType.OFF); + assertEquals(0x01, result); + } + + @Test + public void mergeOnOffBitsNightlightOn() { + int result = mergeOnOffBits(OnOffType.OFF, OnOffType.ON); + assertEquals(0x02, result); + } + + @Test + public void mergeOnOffBitsAllOn() { + int result = mergeOnOffBits(OnOffType.ON, OnOffType.ON); + assertEquals(0x03, result); + } + + @Test + public void deriveNightLightStateBitsOff() { + byte[] payload = { 0x00, 0x00, 0x00, 0x00, 0x00 }; + OnOffType result = model3.deriveNightLightStateFromStatusBytes(payload); + assertEquals(OnOffType.OFF, result); + } + + @Test + public void deriveNightLightStateBitsOn2() { + byte[] payload = { 0x00, 0x00, 0x00, 0x00, 0x02 }; + OnOffType result = model3.deriveNightLightStateFromStatusBytes(payload); + assertEquals(OnOffType.ON, result); + } + + @Test + public void deriveNightLightStateBitsOn3() { + byte[] payload = { 0x00, 0x00, 0x00, 0x00, 0x03 }; + OnOffType result = model3.deriveNightLightStateFromStatusBytes(payload); + assertEquals(OnOffType.ON, result); + } + + @Test + public void deriveNightLightStateBitsOnFF() { + byte[] payload = { 0x00, 0x00, 0x00, 0x00, (byte) 0xFF }; + OnOffType result = model3.deriveNightLightStateFromStatusBytes(payload); + assertEquals(OnOffType.ON, result); + } + + @Test + public void setsThePowerChannelAndNightlightAfterGettingStatusOnSP3() { + Mockito.when(mockSocket.sendAndReceive(Mockito.any(byte[].class), Mockito.anyString())).thenReturn(response); + setMocksForTesting(model3); + + reset(mockCallback); + + model3.getStatusFromDevice(); + + ArgumentCaptor channelCaptor = ArgumentCaptor.forClass(ChannelUID.class); + ArgumentCaptor stateCaptor = ArgumentCaptor.forClass(State.class); + verify(mockCallback, Mockito.times(2)).stateUpdated(channelCaptor.capture(), stateCaptor.capture()); + + List channels = channelCaptor.getAllValues(); + List states = stateCaptor.getAllValues(); + + ChannelUID expectedPowerChannel = new ChannelUID(thing.getUID(), COMMAND_POWER_ON); + assertEquals(expectedPowerChannel, channels.get(0)); + + assertEquals(OnOffType.ON, states.get(0)); + + ChannelUID expectedNightlightChannel = new ChannelUID(thing.getUID(), COMMAND_NIGHTLIGHT); + assertEquals(expectedNightlightChannel, channels.get(1)); + + assertEquals(OnOffType.OFF, states.get(1)); + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandlerTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandlerTest.java new file mode 100644 index 0000000000000..989a4b0fc447a --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandlerTest.java @@ -0,0 +1,119 @@ +/** + * 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.broadlink.handler; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.openhab.binding.broadlink.BroadlinkBindingConstants.*; + +import java.util.List; + +import javax.measure.quantity.Power; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.openhab.binding.broadlink.BroadlinkBindingConstants; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.types.State; + +/** + * Tests the Socket Model 3S (SP3S) handler. + * + * @author John Marshall - Initial contribution + */ +@NonNullByDefault +public class BroadlinkSocketModel3SHandlerTest extends AbstractBroadlinkThingHandlerTest { + + private final BroadlinkSocketModel3SHandler model3s; + + public BroadlinkSocketModel3SHandlerTest() { + super(); + configureUnderlyingThing(BroadlinkBindingConstants.THING_TYPE_SP3S, "sp3s-test"); + model3s = new BroadlinkSocketModel3SHandler(thing); + } + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void deriveSp3sPowerConsumptionTooShort() { + byte[] payload = { 0x00, 0x00, 0x00, 0x00, 0x33 }; + double result = model3s.deriveSP3sPowerConsumption(payload); + assertEquals(0D, result, 0.1D); + } + + @Test + public void deriveSp3sPowerConsumptionCorrectSmallValue() { + byte[] payload = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x02, 0x00 }; + double result = model3s.deriveSP3sPowerConsumption(payload); + assertEquals(2.19D, result, 0.1D); + } + + @Test + public void deriveSp3sPowerConsumptionCorrectMediumValue() { + byte[] payload = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x75, 0x00 }; + double result = model3s.deriveSP3sPowerConsumption(payload); + assertEquals(75.33D, result, 0.1D); + } + + @Test + public void deriveSp3sPowerConsumptionCorrectLargeValue() { + byte[] payload = { 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0x99, (byte) 0x88, 0x07 }; + double result = model3s.deriveSP3sPowerConsumption(payload); + assertEquals(788.99D, result, 0.1D); + } + + @Test + public void setsThePowerChannelAndConsumptionAfterGettingStatusOnSP3S() { + // Power bytes are 5, 6, 7 (little-endian) in BCD + // So here it's 0x38291 => 38291, divided by 100 ==> 382.91W + byte[] payload = { 0x08, 0x00, 0x11, 0x22, 0x01, (byte) 0x91, (byte) 0x82, 0x3, 0x16, 0x27, 0x28, 0x01, 0x02, + 0x04, 0x05, 0x16 }; + byte[] responseMessage = generateReceivedBroadlinkMessage(payload); + Mockito.when(mockSocket.sendAndReceive(Mockito.any(byte[].class), Mockito.anyString())) + .thenReturn(responseMessage); + setMocksForTesting(model3s); + + reset(mockCallback); + + model3s.getStatusFromDevice(); + + ArgumentCaptor channelCaptor = ArgumentCaptor.forClass(ChannelUID.class); + ArgumentCaptor stateCaptor = ArgumentCaptor.forClass(State.class); + verify(mockCallback, Mockito.times(2)).stateUpdated(channelCaptor.capture(), stateCaptor.capture()); + + List channels = channelCaptor.getAllValues(); + List states = stateCaptor.getAllValues(); + + ChannelUID expectedPowerChannel = new ChannelUID(thing.getUID(), COMMAND_POWER_ON); + assertEquals(expectedPowerChannel, channels.get(0)); + + assertEquals(OnOffType.ON, states.get(0)); + + ChannelUID expectedConsumptionChannel = new ChannelUID(thing.getUID(), CHANNEL_POWER_CONSUMPTION); + assertEquals(expectedConsumptionChannel, channels.get(1)); + + QuantityType expectedPower = new QuantityType<>(382.91, + BroadlinkBindingConstants.BROADLINK_POWER_CONSUMPTION_UNIT); + assertEquals(expectedPower, states.get(1)); + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/BroadlinkMappingServiceTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/BroadlinkMappingServiceTest.java new file mode 100644 index 0000000000000..a58df1f6c243e --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/BroadlinkMappingServiceTest.java @@ -0,0 +1,58 @@ +/** + * 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.broadlink.internal; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.verify; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.Test; +import org.mockito.Mockito; +import org.openhab.binding.broadlink.AbstractBroadlinkTest; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.types.CommandOption; + +/** + * Tests the Broadlink mapping service. + * + * @author John Marshall - Initial contribution + */ +@NonNullByDefault +public class BroadlinkMappingServiceTest extends AbstractBroadlinkTest { + private static final String TEST_MAP_FILE = "broadlink.map"; + private static final ChannelUID TEST_CHANNEL_UID = new ChannelUID("bsm:test:channel:uid"); + + private BroadlinkRemoteDynamicCommandDescriptionProvider mockProvider = Mockito + .mock(BroadlinkRemoteDynamicCommandDescriptionProvider.class); + + @Test + public void canReadFromAMapFile() { + BroadlinkMappingService bms = new BroadlinkMappingService(TEST_MAP_FILE, mockProvider, TEST_CHANNEL_UID); + + assertEquals("00112233", bms.lookup("TEST_COMMAND_ON")); + assertEquals("33221100", bms.lookup("TEST_COMMAND_OFF")); + } + + @Test + public void notifiesTheFrameworkOfTheAvailableCommands() { + new BroadlinkMappingService(TEST_MAP_FILE, mockProvider, TEST_CHANNEL_UID); + + List expected = new ArrayList<>(); + expected.add(new CommandOption("TEST_COMMAND_ON", null)); + expected.add(new CommandOption("TEST_COMMAND_OFF", null)); + verify(mockProvider).setCommandOptions(TEST_CHANNEL_UID, expected); + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/BroadlinkProtocolTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/BroadlinkProtocolTest.java new file mode 100644 index 0000000000000..47497ae0f266a --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/BroadlinkProtocolTest.java @@ -0,0 +1,59 @@ +/** + * 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.broadlink.internal; + +import static org.junit.Assert.assertEquals; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.Test; +import org.mockito.Mockito; +import org.openhab.core.util.HexUtils; +import org.slf4j.Logger; + +/** + * Tests the Broadlink protocol. + * + * @author John Marshall/Cato Sognen - Initial contribution + */ +@NonNullByDefault +public class BroadlinkProtocolTest { + + private final Logger mockLogger = Mockito.mock(Logger.class); + + byte[] mac = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, }; + + byte[] deviceId = { 0x10, 0x11, 0x12, 0x13 }; + + byte[] iv = HexUtils.hexToBytes("562e17996d093d28ddb3ba695a2e6f58"); + + byte[] deviceKey = HexUtils.hexToBytes("097628343fe99e23765c1513accf8b02"); + + @Test + public void canBuildMessageWithCorrectChecksums() { + byte[] payload = {}; + byte[] result = BroadlinkProtocol.buildMessage((byte) 0x0, payload, 0, mac, deviceId, iv, deviceKey, 1234, + mockLogger); + + assertEquals(56, result.length); + + // bytes 0x34 and 0x35 contain the payload checksum, + // which given we have an empty payload, should be the initial + // 0xBEAF + int payloadChecksum = ((result[0x35] & 0xff) << 8) + (result[0x34] & 0xff); + assertEquals(0xbeaf, payloadChecksum); + + // bytes 0x20 and 0x21 contain the overall checksum + int overallChecksum = ((result[0x21] & 0xff) << 8) + (result[0x20] & 0xff); + assertEquals(0xc549, overallChecksum); + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/ModelMapperTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/ModelMapperTest.java new file mode 100644 index 0000000000000..5cf3076c5bb89 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/ModelMapperTest.java @@ -0,0 +1,85 @@ +/** + * 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.broadlink.internal; + +import static org.junit.Assert.assertEquals; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; +import org.openhab.binding.broadlink.BroadlinkBindingConstants; +import org.slf4j.Logger; + +/** + * Tests that each Thing Type maps to the right model number. + * + * @author John Marshall/Cato Sognen - Initial contribution + */ +@NonNullByDefault +public class ModelMapperTest { + + private Logger mockLogger = Mockito.mock(Logger.class); + + @Test + public void mapsSpMini2ASp2() { + assertEquals(BroadlinkBindingConstants.THING_TYPE_SP2, ModelMapper.getThingType(0x7539, mockLogger)); + } + + @Test + public void mapsRmMini3AsRm3() { + assertEquals(BroadlinkBindingConstants.THING_TYPE_RM3, ModelMapper.getThingType(0x27c2, mockLogger)); + } + + @Test + public void mapsRm35f36AsRm3Q() { + assertEquals(BroadlinkBindingConstants.THING_TYPE_RM3Q, ModelMapper.getThingType(0x5f36, mockLogger)); + } + + @Test + public void mapsRm4bAsRm4() { + assertEquals(BroadlinkBindingConstants.THING_TYPE_RM4, ModelMapper.getThingType(0x51da, mockLogger)); + } + + @Test + public void mapsRm4ProAsRm4() { + assertEquals(BroadlinkBindingConstants.THING_TYPE_RM4, ModelMapper.getThingType(0x61a2, mockLogger)); + } + + @Test + public void mapsRm462bcAsRm4() { + assertEquals(BroadlinkBindingConstants.THING_TYPE_RM4, ModelMapper.getThingType(0x62bc, mockLogger)); + } + + @Test + public void mapsRm4Model6026AsRm4() { + assertEquals(BroadlinkBindingConstants.THING_TYPE_RM4, ModelMapper.getThingType(0x6026, mockLogger)); + } + + @Test + public void mapsRm4Model24846AsRm4() { + assertEquals(BroadlinkBindingConstants.THING_TYPE_RM4, ModelMapper.getThingType(24846, mockLogger)); + } + + @Test + public void throwsOnUnrecognisedDeviceModel() { + try { + ModelMapper.getThingType(0x6666, mockLogger); + Assert.fail("Should have thrown on unmapped device model"); + } catch (Exception e) { + assertEquals( + "Device identifying itself as '26214' (hex 0x6666) is not currently supported. Please report this to the developer!", + e.getMessage()); + } + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/UtilsTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/UtilsTest.java new file mode 100644 index 0000000000000..a87da6f05d2fc --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/UtilsTest.java @@ -0,0 +1,95 @@ +/** + * 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.broadlink.internal; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.Test; + +/** + * Tests the generic utility functions. + * + * @author John Marshall/Cato Sognen - Initial contribution + */ +@NonNullByDefault +public class UtilsTest { + @Test + public void padToDoesNothingOnQuotientSizedBuffer() { + byte[] source = { 0x01, 0x02, 0x03, 0x04 }; + + byte[] result = Utils.padTo(source, 4); + assertEquals(source, result); + } + + @Test + public void padToExtendsOversizedBuffer() { + byte[] source = { 0x01, 0x02, 0x03, 0x04 }; + + byte[] result = Utils.padTo(source, 3); + assertEquals(6, result.length); + byte[] expected = { 0x01, 0x02, 0x03, 0x04, 0x0, 0x0, }; + + assertArrayEquals(expected, result); + } + + @Test + public void padToExtendsUndersizedBuffer() { + byte[] source = { 0x01, 0x02, 0x03, 0x04 }; + + byte[] result = Utils.padTo(source, 8); + assertEquals(8, result.length); + byte[] expected = { 0x01, 0x02, 0x03, 0x04, 0x0, 0x0, 0x0, 0x0, }; + + assertArrayEquals(expected, result); + } + + @Test + public void padToExtendsUndersizedBufferMultiple() { + byte[] source = { 0x01, 0x02, 0x03, 0x04 }; + + byte[] result = Utils.padTo(source, 16); + assertEquals(16, result.length); + byte[] expected = { 0x01, 0x02, 0x03, 0x04, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, }; + + assertArrayEquals(expected, result); + } + + @Test + public void toHexStringWorksOnSingleByte() { + byte[] source = { (byte) 0x81 }; + + String result = Utils.toHexString(source); + + assertEquals("81", result); + } + + @Test + public void toHexStringWorksOnMultipleBytesLowValues() { + byte[] source = { 0x01, 0x02, 0x03, 0x04 }; + + String result = Utils.toHexString(source); + + assertEquals("01020304", result); + } + + @Test + public void toHexStringWorksOnMultipleBytesMixedValues() { + byte[] source = { (byte) 0x81, (byte) 0xC2, 0x03, (byte) 0xA3, (byte) 0xF4 }; + + String result = Utils.toHexString(source); + + assertEquals("81c203a3f4", result); + } +} diff --git a/bundles/org.openhab.binding.broadlink/src/test/resources/conf/transform/broadlink.map b/bundles/org.openhab.binding.broadlink/src/test/resources/conf/transform/broadlink.map new file mode 100644 index 0000000000000..5d178b84e5377 --- /dev/null +++ b/bundles/org.openhab.binding.broadlink/src/test/resources/conf/transform/broadlink.map @@ -0,0 +1,3 @@ +TEST_COMMAND_ON=00112233 + +TEST_COMMAND_OFF=33221100 \ No newline at end of file diff --git a/bundles/pom.xml b/bundles/pom.xml index 23bf367cd0e9e..d0fe3c6814b1e 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -82,6 +82,7 @@ org.openhab.binding.boschindego org.openhab.binding.boschshc org.openhab.binding.bosesoundtouch + org.openhab.binding.broadlink org.openhab.binding.broadlinkthermostat org.openhab.binding.bsblan org.openhab.binding.bticinosmarther From 3b634fc25f0ab3fd66eda973a08d13833b8e9055 Mon Sep 17 00:00:00 2001 From: Ricardo Larranaga Date: Fri, 3 Mar 2023 14:44:06 -0400 Subject: [PATCH 2/9] Upgrade JUnit 4 to 5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ricardo Larrañaga Signed-off-by: Ricardo Larranaga --- bundles/org.openhab.binding.broadlink/pom.xml | 9 --------- .../openhab/binding/broadlink/AbstractBroadlinkTest.java | 8 ++++---- .../handler/BroadlinkRemoteModel2HandlerTest.java | 8 ++++---- .../handler/BroadlinkRemoteModel3HandlerTest.java | 8 ++++---- .../handler/BroadlinkRemoteModel4HandlerTest.java | 8 ++++---- .../handler/BroadlinkSocketModel2HandlerTest.java | 8 ++++---- .../handler/BroadlinkSocketModel3HandlerTest.java | 8 ++++---- .../handler/BroadlinkSocketModel3SHandlerTest.java | 8 ++++---- .../broadlink/internal/BroadlinkMappingServiceTest.java | 4 ++-- .../broadlink/internal/BroadlinkProtocolTest.java | 4 ++-- .../binding/broadlink/internal/ModelMapperTest.java | 8 ++++---- .../openhab/binding/broadlink/internal/UtilsTest.java | 6 +++--- 12 files changed, 39 insertions(+), 48 deletions(-) diff --git a/bundles/org.openhab.binding.broadlink/pom.xml b/bundles/org.openhab.binding.broadlink/pom.xml index af5691ff44b1a..dcd8dad2f197a 100644 --- a/bundles/org.openhab.binding.broadlink/pom.xml +++ b/bundles/org.openhab.binding.broadlink/pom.xml @@ -14,13 +14,4 @@ openHAB Add-ons :: Bundles :: Broadlink Binding - - - junit - junit - 4.13 - test - - - diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/AbstractBroadlinkTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/AbstractBroadlinkTest.java index 3970ce768c4d2..50e6978e4f2cb 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/AbstractBroadlinkTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/AbstractBroadlinkTest.java @@ -16,8 +16,8 @@ import java.nio.file.Paths; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.junit.AfterClass; -import org.junit.BeforeClass; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; import org.openhab.core.OpenHAB; /** @@ -31,12 +31,12 @@ public abstract class AbstractBroadlinkTest { protected static final Path TEST_CONF_DIRECTORY = Paths.get("src", "test", "resources", "conf"); - @BeforeClass + @BeforeAll public static void beforeClass() { System.setProperty(OpenHAB.CONFIG_DIR_PROG_ARGUMENT, TEST_CONF_DIRECTORY.toFile().getAbsolutePath()); } - @AfterClass + @AfterAll public static void afterClass() { System.clearProperty(OpenHAB.CONFIG_DIR_PROG_ARGUMENT); } diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel2HandlerTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel2HandlerTest.java index 5e18195a675c1..c3786a2c3bf80 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel2HandlerTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel2HandlerTest.java @@ -12,15 +12,15 @@ */ package org.openhab.binding.broadlink.handler; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import java.io.IOException; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; @@ -34,7 +34,7 @@ @NonNullByDefault public class BroadlinkRemoteModel2HandlerTest extends AbstractBroadlinkThingHandlerTest { - @Before + @BeforeEach public void setUp() { configureUnderlyingThing(BroadlinkBindingConstants.THING_TYPE_RM2, "rm2-test"); MockitoAnnotations.initMocks(this); diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3HandlerTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3HandlerTest.java index dd76dad3f775e..acb47742845e0 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3HandlerTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3HandlerTest.java @@ -12,7 +12,7 @@ */ package org.openhab.binding.broadlink.handler; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.openhab.binding.broadlink.BroadlinkBindingConstants.LEARNING_CONTROL_COMMAND_LEARN; @@ -20,8 +20,8 @@ import java.io.IOException; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; @@ -35,7 +35,7 @@ @NonNullByDefault public class BroadlinkRemoteModel3HandlerTest extends AbstractBroadlinkThingHandlerTest { - @Before + @BeforeEach public void setUp() { configureUnderlyingThing(BroadlinkBindingConstants.THING_TYPE_RM3, "rm3-test"); MockitoAnnotations.initMocks(this); diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4HandlerTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4HandlerTest.java index 344e6e84f447d..fab78aa380ec1 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4HandlerTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4HandlerTest.java @@ -12,7 +12,7 @@ */ package org.openhab.binding.broadlink.handler; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.*; import static org.openhab.binding.broadlink.BroadlinkBindingConstants.*; @@ -23,8 +23,8 @@ import javax.measure.quantity.Temperature; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; @@ -52,7 +52,7 @@ public class BroadlinkRemoteModel4HandlerTest extends AbstractBroadlinkThingHand (byte) 0x4f, (byte) 0x89, (byte) 0xf8, (byte) 0xb4, (byte) 0xdb, (byte) 0xb0, (byte) 0x72, (byte) 0xe7, (byte) 0x1f, (byte) 0x86, }; - @Before + @BeforeEach public void setUp() { configureUnderlyingThing(BroadlinkBindingConstants.THING_TYPE_RM4, "rm4-test"); MockitoAnnotations.initMocks(this); diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel2HandlerTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel2HandlerTest.java index 757c762d57162..d77a2c89d35f0 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel2HandlerTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel2HandlerTest.java @@ -12,7 +12,7 @@ */ package org.openhab.binding.broadlink.handler; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.openhab.binding.broadlink.BroadlinkBindingConstants.CHANNEL_POWER_CONSUMPTION; @@ -24,8 +24,8 @@ import javax.measure.quantity.Power; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; @@ -51,7 +51,7 @@ public class BroadlinkSocketModel2HandlerTest extends AbstractBroadlinkThingHand 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; - @Before + @BeforeEach public void setUp() { configureUnderlyingThing(BroadlinkBindingConstants.THING_TYPE_SP2, "sp2-test"); MockitoAnnotations.initMocks(this); diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3HandlerTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3HandlerTest.java index 43368d8117ab7..74ff3a6406d9e 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3HandlerTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3HandlerTest.java @@ -12,7 +12,7 @@ */ package org.openhab.binding.broadlink.handler; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.openhab.binding.broadlink.BroadlinkBindingConstants.*; @@ -21,8 +21,8 @@ import java.util.List; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; @@ -55,7 +55,7 @@ public BroadlinkSocketModel3HandlerTest() { model3 = new BroadlinkSocketModel3Handler(thing); } - @Before + @BeforeEach public void setUp() { MockitoAnnotations.initMocks(this); Mockito.when(mockSocket.sendAndReceive(Mockito.any(byte[].class), Mockito.anyString())).thenReturn(response); diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandlerTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandlerTest.java index 989a4b0fc447a..0782dffbf7187 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandlerTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandlerTest.java @@ -12,7 +12,7 @@ */ package org.openhab.binding.broadlink.handler; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.openhab.binding.broadlink.BroadlinkBindingConstants.*; @@ -22,8 +22,8 @@ import javax.measure.quantity.Power; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; @@ -49,7 +49,7 @@ public BroadlinkSocketModel3SHandlerTest() { model3s = new BroadlinkSocketModel3SHandler(thing); } - @Before + @BeforeEach public void setUp() { MockitoAnnotations.initMocks(this); } diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/BroadlinkMappingServiceTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/BroadlinkMappingServiceTest.java index a58df1f6c243e..523d3c34ce5f6 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/BroadlinkMappingServiceTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/BroadlinkMappingServiceTest.java @@ -12,14 +12,14 @@ */ package org.openhab.binding.broadlink.internal; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.verify; import java.util.ArrayList; import java.util.List; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; import org.openhab.binding.broadlink.AbstractBroadlinkTest; import org.openhab.core.thing.ChannelUID; diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/BroadlinkProtocolTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/BroadlinkProtocolTest.java index 47497ae0f266a..ce3daab10c333 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/BroadlinkProtocolTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/BroadlinkProtocolTest.java @@ -12,10 +12,10 @@ */ package org.openhab.binding.broadlink.internal; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; import org.openhab.core.util.HexUtils; import org.slf4j.Logger; diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/ModelMapperTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/ModelMapperTest.java index 5cf3076c5bb89..3f3d6a1e82b1d 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/ModelMapperTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/ModelMapperTest.java @@ -12,11 +12,11 @@ */ package org.openhab.binding.broadlink.internal; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; import org.openhab.binding.broadlink.BroadlinkBindingConstants; import org.slf4j.Logger; @@ -75,7 +75,7 @@ public void mapsRm4Model24846AsRm4() { public void throwsOnUnrecognisedDeviceModel() { try { ModelMapper.getThingType(0x6666, mockLogger); - Assert.fail("Should have thrown on unmapped device model"); + Assertions.fail("Should have thrown on unmapped device model"); } catch (Exception e) { assertEquals( "Device identifying itself as '26214' (hex 0x6666) is not currently supported. Please report this to the developer!", diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/UtilsTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/UtilsTest.java index a87da6f05d2fc..5be1e8517aae4 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/UtilsTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/UtilsTest.java @@ -12,11 +12,11 @@ */ package org.openhab.binding.broadlink.internal; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** * Tests the generic utility functions. From 33d048ffafae30194d50171b346983971c2f035f Mon Sep 17 00:00:00 2001 From: Ricardo Larranaga Date: Fri, 3 Mar 2023 14:55:51 -0400 Subject: [PATCH 3/9] Removed deprecatad initMocks call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ricardo Larrañaga Signed-off-by: Ricardo Larranaga --- .../broadlink/handler/BroadlinkRemoteModel2HandlerTest.java | 4 ++-- .../broadlink/handler/BroadlinkRemoteModel3HandlerTest.java | 4 ++-- .../broadlink/handler/BroadlinkRemoteModel4HandlerTest.java | 4 ++-- .../broadlink/handler/BroadlinkSocketModel2HandlerTest.java | 4 ++-- .../broadlink/handler/BroadlinkSocketModel3HandlerTest.java | 4 ++-- .../broadlink/handler/BroadlinkSocketModel3SHandlerTest.java | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel2HandlerTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel2HandlerTest.java index c3786a2c3bf80..e8f7d6fd97933 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel2HandlerTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel2HandlerTest.java @@ -35,9 +35,9 @@ public class BroadlinkRemoteModel2HandlerTest extends AbstractBroadlinkThingHandlerTest { @BeforeEach - public void setUp() { + public void setUp() throws Exception { configureUnderlyingThing(BroadlinkBindingConstants.THING_TYPE_RM2, "rm2-test"); - MockitoAnnotations.initMocks(this); + MockitoAnnotations.openMocks(this).close(); Mockito.when(mockSocket.sendAndReceive(Mockito.any(byte[].class), Mockito.anyString())).thenReturn(response); } diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3HandlerTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3HandlerTest.java index acb47742845e0..c45be66f6c46b 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3HandlerTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3HandlerTest.java @@ -36,9 +36,9 @@ public class BroadlinkRemoteModel3HandlerTest extends AbstractBroadlinkThingHandlerTest { @BeforeEach - public void setUp() { + public void setUp() throws Exception { configureUnderlyingThing(BroadlinkBindingConstants.THING_TYPE_RM3, "rm3-test"); - MockitoAnnotations.initMocks(this); + MockitoAnnotations.openMocks(this).close(); Mockito.when(mockSocket.sendAndReceive(Mockito.any(byte[].class), Mockito.anyString())).thenReturn(response); } diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4HandlerTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4HandlerTest.java index fab78aa380ec1..60665e5b0d756 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4HandlerTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4HandlerTest.java @@ -53,9 +53,9 @@ public class BroadlinkRemoteModel4HandlerTest extends AbstractBroadlinkThingHand (byte) 0x1f, (byte) 0x86, }; @BeforeEach - public void setUp() { + public void setUp() throws Exception { configureUnderlyingThing(BroadlinkBindingConstants.THING_TYPE_RM4, "rm4-test"); - MockitoAnnotations.initMocks(this); + MockitoAnnotations.openMocks(this).close(); Mockito.when(mockSocket.sendAndReceive(Mockito.any(byte[].class), Mockito.anyString())).thenReturn(response); } diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel2HandlerTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel2HandlerTest.java index d77a2c89d35f0..a7777c202919f 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel2HandlerTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel2HandlerTest.java @@ -52,9 +52,9 @@ public class BroadlinkSocketModel2HandlerTest extends AbstractBroadlinkThingHand 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; @BeforeEach - public void setUp() { + public void setUp() throws Exception { configureUnderlyingThing(BroadlinkBindingConstants.THING_TYPE_SP2, "sp2-test"); - MockitoAnnotations.initMocks(this); + MockitoAnnotations.openMocks(this).close(); Mockito.when(mockSocket.sendAndReceive(Mockito.any(byte[].class), Mockito.anyString())).thenReturn(response); } diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3HandlerTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3HandlerTest.java index 74ff3a6406d9e..99d4ce80b4621 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3HandlerTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3HandlerTest.java @@ -56,8 +56,8 @@ public BroadlinkSocketModel3HandlerTest() { } @BeforeEach - public void setUp() { - MockitoAnnotations.initMocks(this); + public void setUp() throws Exception { + MockitoAnnotations.openMocks(this).close(); Mockito.when(mockSocket.sendAndReceive(Mockito.any(byte[].class), Mockito.anyString())).thenReturn(response); } diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandlerTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandlerTest.java index 0782dffbf7187..66ee5bce37663 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandlerTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandlerTest.java @@ -50,8 +50,8 @@ public BroadlinkSocketModel3SHandlerTest() { } @BeforeEach - public void setUp() { - MockitoAnnotations.initMocks(this); + public void setUp() throws Exception { + MockitoAnnotations.openMocks(this).close(); } @Test From 1cfbc2d018725ddfa6f36515442cdaf23d2f1f48 Mon Sep 17 00:00:00 2001 From: Ricardo Larranaga Date: Fri, 3 Mar 2023 15:17:49 -0400 Subject: [PATCH 4/9] Override Null pointer warnings where appropiate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ricardo Larrañaga Signed-off-by: Ricardo Larranaga --- .../broadlink/handler/BroadlinkBaseThingHandler.java | 10 ++++++++++ .../broadlink/handler/BroadlinkRemoteHandler.java | 2 ++ .../broadlink/internal/BroadlinkMappingService.java | 3 +++ .../internal/discovery/DiscoveryProtocol.java | 1 - .../broadlink/internal/socket/BroadlinkSocket.java | 5 ++++- .../broadlink/internal/socket/RetryableSocket.java | 3 +++ 6 files changed, 22 insertions(+), 2 deletions(-) diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkBaseThingHandler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkBaseThingHandler.java index cee90194ca1ca..89ab64bd2a077 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkBaseThingHandler.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkBaseThingHandler.java @@ -112,6 +112,7 @@ public void run() { } } + @SuppressWarnings("null") public void dispose() { logger.debug("Disposing of {}", getThing().getLabel()); if (refreshHandle != null && !refreshHandle.isDone()) { @@ -159,6 +160,7 @@ private boolean authenticate() { } } + @SuppressWarnings("null") protected byte @Nullable [] sendAndReceiveDatagram(byte message[], String purpose) { return socket.sendAndReceive(message, purpose); } @@ -167,6 +169,7 @@ protected byte[] buildMessage(byte command, byte payload[]) throws IOException { return buildMessage(command, payload, thingConfig.getDeviceType()); } + @SuppressWarnings("null") private byte[] buildMessage(byte command, byte payload[], int deviceType) throws IOException { count = count + 1 & 0xffff; @@ -179,6 +182,7 @@ private byte[] buildMessage(byte command, byte payload[], int deviceType) throws HexUtils.hexToBytes(BroadlinkBindingConstants.BROADLINK_IV), deviceKey, deviceType, logger); } + @SuppressWarnings("null") protected byte[] decodeDevicePacket(byte[] responseBytes) throws IOException { byte[] rxBytes = BroadlinkProtocol.decodePacket(responseBytes, this.deviceKey, BroadlinkBindingConstants.BROADLINK_IV); @@ -273,6 +277,12 @@ private void transitionToOnline() { } } + @SuppressWarnings("null") + @SuppressWarnings("null") + @SuppressWarnings("null") + @SuppressWarnings("null") + @SuppressWarnings("null") + @SuppressWarnings("null") private void forceOffline(ThingStatusDetail detail, String reason) { logger.warn("Online -> Offline due to: {}", reason); authenticated = false; // This session is dead; we'll need to re-authenticate next time diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteHandler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteHandler.java index 7a2d0c452223b..8d7817a5ab1de 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteHandler.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteHandler.java @@ -59,6 +59,7 @@ public void initialize() { new ChannelUID(thing.getUID(), BroadlinkBindingConstants.COMMAND_CHANNEL)); } + @SuppressWarnings("null") public void dispose() { if (this.mappingService != null) { this.mappingService.dispose(); @@ -174,6 +175,7 @@ public void handleCommand(ChannelUID channelUID, Command command) { } } + @SuppressWarnings("null") private byte @Nullable [] lookupCode(Command command, ChannelUID channelUID) { byte code[] = null; String value = this.mappingService.lookup(command.toString()); diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkMappingService.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkMappingService.java index 175c054c42068..57f2d34cc2b02 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkMappingService.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkMappingService.java @@ -69,6 +69,7 @@ public BroadlinkMappingService(String mapFileName, logger.debug("BroadlinkMappingService constructed on behalf of {}", this.targetChannelUID); } + @SuppressWarnings("null") public void dispose() { try { if (watchThread != null && !watchThread.isInterrupted()) { @@ -92,6 +93,7 @@ public void dispose() { return commandMap.get(command); } + @SuppressWarnings("null") private Runnable watchingRunnable = new Runnable() { @Override public void run() { @@ -116,6 +118,7 @@ public void run() { } }; + @SuppressWarnings("null") private void startWatching() { try { this.watchService = FileSystems.getDefault().newWatchService(); diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DiscoveryProtocol.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DiscoveryProtocol.java index 51c8d1b3309eb..ca9607bdbc53b 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DiscoveryProtocol.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DiscoveryProtocol.java @@ -28,7 +28,6 @@ @NonNullByDefault public class DiscoveryProtocol { - @NonNullByDefault private static class AsyncDiscoveryThread extends Thread { private final BroadlinkSocketListener listener; private final long timeoutMillis; diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/BroadlinkSocket.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/BroadlinkSocket.java index 50364d008f669..c549458c7416e 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/BroadlinkSocket.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/BroadlinkSocket.java @@ -63,7 +63,6 @@ public static String decodeMAC(byte mac[]) { return sb.toString(); } - @NonNullByDefault private static class ReceiverThread extends Thread { private Logger logger; @@ -71,6 +70,7 @@ public void run() { receiveData(BroadlinkSocket.socket, BroadlinkSocket.datagramPacket); } + @SuppressWarnings("null") private void receiveData(@Nullable MulticastSocket socket, DatagramPacket dgram) { try { while (true) { @@ -117,6 +117,7 @@ public static void unregisterListener(BroadlinkSocketListener listener, Logger l } } + @SuppressWarnings("null") private static void setupSocket(Logger logger) { synchronized (BroadlinkSocket.class) { try { @@ -129,6 +130,7 @@ private static void setupSocket(Logger logger) { } } + @SuppressWarnings("null") private static void closeSocket(Logger logger) { synchronized (BroadlinkSocket.class) { if (socketReceiveThread != null) { @@ -146,6 +148,7 @@ public static void sendMessage(byte message[], Logger logger) { sendMessage(message, "255.255.255.255", 80, logger); } + @SuppressWarnings("null") public static void sendMessage(byte message[], String host, int port, Logger logger) { try { DatagramPacket sendPacket = new DatagramPacket(message, message.length, InetAddress.getByName(host), port); diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/RetryableSocket.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/RetryableSocket.java index 17d345868903e..92da6204a418e 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/RetryableSocket.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/RetryableSocket.java @@ -68,6 +68,7 @@ public RetryableSocket(BroadlinkDeviceConfiguration thingConfig, Logger logger) return null; } + @SuppressWarnings("null") private boolean sendDatagram(byte message[], String purpose) { try { logger.trace("Sending {} to {}:{}", purpose, thingConfig.getIpAddress(), thingConfig.getPort()); @@ -90,6 +91,7 @@ private boolean sendDatagram(byte message[], String purpose) { } } + @SuppressWarnings("null") private @Nullable DatagramPacket receiveDatagram(String purpose, DatagramPacket receivePacket) { logger.trace("Awaiting {} response", purpose); @@ -110,6 +112,7 @@ private boolean sendDatagram(byte message[], String purpose) { return null; } + @SuppressWarnings("null") public void close() { if (socket != null) { socket.close(); From 2bd74fc60880f00171e84e3de9f47e2b5d0084ae Mon Sep 17 00:00:00 2001 From: Ricardo Larranaga Date: Fri, 3 Mar 2023 15:37:12 -0400 Subject: [PATCH 5/9] Added warning suppression for unchecked type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ricardo Larrañaga Signed-off-by: Ricardo Larranaga --- .../binding/broadlink/internal/BroadlinkMappingService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkMappingService.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkMappingService.java index 57f2d34cc2b02..4252512b6c07c 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkMappingService.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkMappingService.java @@ -93,7 +93,7 @@ public void dispose() { return commandMap.get(command); } - @SuppressWarnings("null") + @SuppressWarnings({ "null", "unchecked" }) private Runnable watchingRunnable = new Runnable() { @Override public void run() { From b0029599f26de3f3a9311c0c5b02fe0a223a12bd Mon Sep 17 00:00:00 2001 From: Ricardo Larranaga Date: Fri, 3 Mar 2023 15:37:44 -0400 Subject: [PATCH 6/9] Fix error in file that added multiple Suppress Annotations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ricardo Larrañaga Signed-off-by: Ricardo Larranaga --- .../binding/broadlink/handler/BroadlinkBaseThingHandler.java | 5 ----- .../broadlink/handler/BroadlinkSocketModel3SHandler.java | 1 - 2 files changed, 6 deletions(-) diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkBaseThingHandler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkBaseThingHandler.java index 89ab64bd2a077..1630c29d005d3 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkBaseThingHandler.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkBaseThingHandler.java @@ -277,11 +277,6 @@ private void transitionToOnline() { } } - @SuppressWarnings("null") - @SuppressWarnings("null") - @SuppressWarnings("null") - @SuppressWarnings("null") - @SuppressWarnings("null") @SuppressWarnings("null") private void forceOffline(ThingStatusDetail detail, String reason) { logger.warn("Online -> Offline due to: {}", reason); diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandler.java index e47bf2791ef59..52e20b77f6d5c 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandler.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandler.java @@ -61,7 +61,6 @@ public BroadlinkSocketModel3SHandler(Thing thing) { if (consumptionResponsePayload.length > 7) { return (fromBCD(consumptionResponsePayload[7]) * 100) + fromBCD(consumptionResponsePayload[6]) + (fromBCD(consumptionResponsePayload[5]) / 100); - } return 0D; } From 0086f4e47be7e8e46e0c9baf2ac25d1f7ebb08fb Mon Sep 17 00:00:00 2001 From: Ricardo Larranaga Date: Fri, 3 Mar 2023 15:53:15 -0400 Subject: [PATCH 7/9] Made requested changes for logging level as per src/main/java/org/openhab/binding/broadlink/handler/BroadlinkBaseThingHandler.java MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ricardo Larrañaga Signed-off-by: Ricardo Larranaga --- .../binding/broadlink/handler/BroadlinkBaseThingHandler.java | 2 +- .../binding/broadlink/internal/BroadlinkMappingService.java | 2 +- .../internal/discovery/BroadlinkDiscoveryService.java | 2 +- .../broadlink/internal/discovery/DeviceRediscoveryAgent.java | 2 +- .../binding/broadlink/internal/socket/BroadlinkSocket.java | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkBaseThingHandler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkBaseThingHandler.java index 1630c29d005d3..91a5ea0784498 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkBaseThingHandler.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkBaseThingHandler.java @@ -247,7 +247,7 @@ public void updateItemStatus() { } public void onDeviceRediscovered(String newIpAddress) { - logger.info("Rediscovered this device at IP {}", newIpAddress); + logger.debug("Rediscovered this device at IP {}", newIpAddress); thingConfig.setIpAddress(newIpAddress); transitionToOnline(); } diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkMappingService.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkMappingService.java index 4252512b6c07c..38a91c2966459 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkMappingService.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkMappingService.java @@ -141,7 +141,7 @@ private void reloadFromFile() { props.stringPropertyNames().forEach(k -> { commandMap.put(k, props.getProperty(k)); }); - logger.info("Read {} commands from {}", commandMap.size(), mapFilePath); + logger.debug("Read {} commands from {}", commandMap.size(), mapFilePath); notifyAvailableCommands(commandMap.keySet()); } catch (IOException e) { logger.warn("Couldn't read {}: {}", mapFilePath, e.getMessage()); diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/BroadlinkDiscoveryService.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/BroadlinkDiscoveryService.java index 5c1d2b38e0489..b90dbf5ed9dbf 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/BroadlinkDiscoveryService.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/BroadlinkDiscoveryService.java @@ -45,7 +45,7 @@ public class BroadlinkDiscoveryService extends AbstractDiscoveryService public BroadlinkDiscoveryService() { super(BroadlinkBindingConstants.SUPPORTED_THING_TYPES_UIDS_TO_NAME_MAP.keySet(), 10, true); - logger.info("BroadlinkDiscoveryService - Constructed"); + logger.debug("BroadlinkDiscoveryService - Constructed"); } public void startScan() { diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DeviceRediscoveryAgent.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DeviceRediscoveryAgent.java index 60d20891aea63..e486c14cc6889 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DeviceRediscoveryAgent.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DeviceRediscoveryAgent.java @@ -58,7 +58,7 @@ public void onDataReceived(String remoteAddress, int remotePort, String remoteMA logger.trace("Comparing with desired mac: {}", missingThingConfig.getMacAddressAsString()); if (missingThingConfig.getMacAddressAsString().equals(remoteMAC)) { - logger.info("We have a match for target MAC {} at {} - reassociate!", remoteMAC, remoteAddress); + logger.debug("We have a match for target MAC {} at {} - reassociate!", remoteMAC, remoteAddress); foundDevice = true; this.drl.onDeviceRediscovered(remoteAddress); } diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/BroadlinkSocket.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/BroadlinkSocket.java index c549458c7416e..d2b058b4715de 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/BroadlinkSocket.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/BroadlinkSocket.java @@ -95,7 +95,7 @@ private void receiveData(@Nullable MulticastSocket socket, DatagramPacket dgram) logger.warn("Error while receiving", e); } } - logger.info("Receiver thread ended"); + logger.debug("Receiver thread ended"); } private ReceiverThread(Logger logger) { @@ -137,7 +137,7 @@ private static void closeSocket(Logger logger) { socketReceiveThread.interrupt(); } if (socket != null) { - logger.info("Socket closed"); + logger.debug("Socket closed"); socket.close(); socket = null; } From ee7211e3756043c010500051465846d11f0f5202 Mon Sep 17 00:00:00 2001 From: Ricardo Larranaga Date: Sun, 5 Mar 2023 23:56:04 -0400 Subject: [PATCH 8/9] Fix definition of Humidity Parameter, to get rid of warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ricardo Larrañaga Signed-off-by: Ricardo Larranaga --- .../broadlink/handler/BroadlinkRemoteModel4HandlerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4HandlerTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4HandlerTest.java index 60665e5b0d756..c0e4e9a6a9314 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4HandlerTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4HandlerTest.java @@ -187,7 +187,7 @@ public void setsTheTemperatureAndHumidityChannelsAfterGettingStatus() { ChannelUID expectedHumidityChannel = new ChannelUID(thing.getUID(), CHANNEL_HUMIDITY); assertEquals(expectedHumidityChannel, channelCaptures.get(1)); - QuantityType expectedHumidity = new QuantityType(39.4, + QuantityType expectedHumidity = new QuantityType<>(39.4, BroadlinkBindingConstants.BROADLINK_HUMIDITY_UNIT); assertEquals(expectedHumidity, stateCaptures.get(1)); } From af18539ec9c9bd7f3e4a4a5441e4878f5cee9936 Mon Sep 17 00:00:00 2001 From: Ricardo Larranaga Date: Sat, 11 Mar 2023 14:22:33 -0400 Subject: [PATCH 9/9] Bump binding version to 4.0.0-Snapshot. Update code headers to 2023 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ricardo Larrañaga Signed-off-by: Ricardo Larranaga --- bundles/org.openhab.binding.broadlink/pom.xml | 2 +- .../openhab/binding/broadlink/BroadlinkBindingConstants.java | 2 +- .../binding/broadlink/config/BroadlinkDeviceConfiguration.java | 2 +- .../openhab/binding/broadlink/handler/BroadlinkA1Handler.java | 2 +- .../binding/broadlink/handler/BroadlinkBaseThingHandler.java | 2 +- .../binding/broadlink/handler/BroadlinkRemoteHandler.java | 2 +- .../binding/broadlink/handler/BroadlinkRemoteModel2Handler.java | 2 +- .../binding/broadlink/handler/BroadlinkRemoteModel3Handler.java | 2 +- .../broadlink/handler/BroadlinkRemoteModel3V44057Handler.java | 2 +- .../binding/broadlink/handler/BroadlinkRemoteModel4Handler.java | 2 +- .../binding/broadlink/handler/BroadlinkSocketHandler.java | 2 +- .../binding/broadlink/handler/BroadlinkSocketModel1Handler.java | 2 +- .../binding/broadlink/handler/BroadlinkSocketModel2Handler.java | 2 +- .../binding/broadlink/handler/BroadlinkSocketModel3Handler.java | 2 +- .../broadlink/handler/BroadlinkSocketModel3SHandler.java | 2 +- .../broadlink/handler/BroadlinkStripModel11K3S2UHandler.java | 2 +- .../binding/broadlink/handler/BroadlinkStripModel1Handler.java | 2 +- .../binding/broadlink/handler/BroadlinkStripModel2Handler.java | 2 +- .../binding/broadlink/internal/BroadlinkBindingConstants.java | 2 +- .../binding/broadlink/internal/BroadlinkHandlerFactory.java | 2 +- .../binding/broadlink/internal/BroadlinkMappingService.java | 2 +- .../openhab/binding/broadlink/internal/BroadlinkProtocol.java | 2 +- .../BroadlinkRemoteDynamicCommandDescriptionProvider.java | 2 +- .../org/openhab/binding/broadlink/internal/ModelMapper.java | 2 +- .../org/openhab/binding/broadlink/internal/NetworkUtils.java | 2 +- .../main/java/org/openhab/binding/broadlink/internal/Utils.java | 2 +- .../broadlink/internal/discovery/BroadlinkDiscoveryService.java | 2 +- .../broadlink/internal/discovery/DeviceRediscoveryAgent.java | 2 +- .../broadlink/internal/discovery/DeviceRediscoveryListener.java | 2 +- .../broadlink/internal/discovery/DiscoveryFinishedListener.java | 2 +- .../binding/broadlink/internal/discovery/DiscoveryProtocol.java | 2 +- .../binding/broadlink/internal/socket/BroadlinkSocket.java | 2 +- .../broadlink/internal/socket/BroadlinkSocketListener.java | 2 +- .../broadlink/internal/socket/NetworkTrafficObserver.java | 2 +- .../binding/broadlink/internal/socket/RetryableSocket.java | 2 +- .../org/openhab/binding/broadlink/AbstractBroadlinkTest.java | 2 +- .../broadlink/handler/AbstractBroadlinkThingHandlerTest.java | 2 +- .../broadlink/handler/BroadlinkRemoteModel2HandlerTest.java | 2 +- .../broadlink/handler/BroadlinkRemoteModel3HandlerTest.java | 2 +- .../broadlink/handler/BroadlinkRemoteModel4HandlerTest.java | 2 +- .../broadlink/handler/BroadlinkSocketModel2HandlerTest.java | 2 +- .../broadlink/handler/BroadlinkSocketModel3HandlerTest.java | 2 +- .../broadlink/handler/BroadlinkSocketModel3SHandlerTest.java | 2 +- .../binding/broadlink/internal/BroadlinkMappingServiceTest.java | 2 +- .../binding/broadlink/internal/BroadlinkProtocolTest.java | 2 +- .../org/openhab/binding/broadlink/internal/ModelMapperTest.java | 2 +- .../java/org/openhab/binding/broadlink/internal/UtilsTest.java | 2 +- 47 files changed, 47 insertions(+), 47 deletions(-) diff --git a/bundles/org.openhab.binding.broadlink/pom.xml b/bundles/org.openhab.binding.broadlink/pom.xml index dcd8dad2f197a..0c6030200123a 100644 --- a/bundles/org.openhab.binding.broadlink/pom.xml +++ b/bundles/org.openhab.binding.broadlink/pom.xml @@ -7,7 +7,7 @@ org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.4.3-SNAPSHOT + 4.0.0-SNAPSHOT org.openhab.binding.broadlink diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/BroadlinkBindingConstants.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/BroadlinkBindingConstants.java index 5a6d3ed362830..6dc36dc07c022 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/BroadlinkBindingConstants.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/BroadlinkBindingConstants.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/config/BroadlinkDeviceConfiguration.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/config/BroadlinkDeviceConfiguration.java index e81c6dfb89456..03e74b507ad5e 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/config/BroadlinkDeviceConfiguration.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/config/BroadlinkDeviceConfiguration.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkA1Handler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkA1Handler.java index 02519fda51e0d..fbe9e40a7438b 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkA1Handler.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkA1Handler.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkBaseThingHandler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkBaseThingHandler.java index 91a5ea0784498..50dc9660b12ae 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkBaseThingHandler.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkBaseThingHandler.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteHandler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteHandler.java index 8d7817a5ab1de..dd0a1ada5aa95 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteHandler.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteHandler.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel2Handler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel2Handler.java index 3a6622f69a1cd..0f2c588d5622f 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel2Handler.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel2Handler.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3Handler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3Handler.java index 55210f7c3a6eb..2403a606ff6f4 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3Handler.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3Handler.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3V44057Handler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3V44057Handler.java index 84904cc07275c..1b12ac1cfbf9b 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3V44057Handler.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3V44057Handler.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4Handler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4Handler.java index 30ce697a03701..6c95fe2307543 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4Handler.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4Handler.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketHandler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketHandler.java index b0cf04e6b4828..7f11226362505 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketHandler.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketHandler.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel1Handler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel1Handler.java index 0f16f88fb4773..d2d6b12b97e5a 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel1Handler.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel1Handler.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel2Handler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel2Handler.java index 01e3722d1a36c..e09289b098367 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel2Handler.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel2Handler.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3Handler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3Handler.java index 855be00b58877..cfd1c1074953f 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3Handler.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3Handler.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandler.java index 52e20b77f6d5c..d399772e8c7c1 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandler.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandler.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkStripModel11K3S2UHandler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkStripModel11K3S2UHandler.java index 79588ea773d00..e2fbbd2240725 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkStripModel11K3S2UHandler.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkStripModel11K3S2UHandler.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkStripModel1Handler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkStripModel1Handler.java index 946e4331e3103..753fc9b2830cb 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkStripModel1Handler.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkStripModel1Handler.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkStripModel2Handler.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkStripModel2Handler.java index e136293f17b7e..e3576ad9c9805 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkStripModel2Handler.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/handler/BroadlinkStripModel2Handler.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkBindingConstants.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkBindingConstants.java index bae11ef5d30be..a885190a5b1a5 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkBindingConstants.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkBindingConstants.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkHandlerFactory.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkHandlerFactory.java index 2b0e8f91d2625..28266ce6adf7f 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkHandlerFactory.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkHandlerFactory.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkMappingService.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkMappingService.java index 38a91c2966459..9e67ff95e2e10 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkMappingService.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkMappingService.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkProtocol.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkProtocol.java index e2965ebf98e83..1e5c1ff9007c5 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkProtocol.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkProtocol.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkRemoteDynamicCommandDescriptionProvider.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkRemoteDynamicCommandDescriptionProvider.java index 6a677f14ab069..efd400e9e827b 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkRemoteDynamicCommandDescriptionProvider.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/BroadlinkRemoteDynamicCommandDescriptionProvider.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/ModelMapper.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/ModelMapper.java index b654f9b4d9ea7..e0c194f9a3bbd 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/ModelMapper.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/ModelMapper.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/NetworkUtils.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/NetworkUtils.java index 7fd6e766ee84f..4aecdd0930f29 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/NetworkUtils.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/NetworkUtils.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/Utils.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/Utils.java index a4b9b6ea34630..b495a5163b0a9 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/Utils.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/Utils.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/BroadlinkDiscoveryService.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/BroadlinkDiscoveryService.java index b90dbf5ed9dbf..d9796c918e770 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/BroadlinkDiscoveryService.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/BroadlinkDiscoveryService.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DeviceRediscoveryAgent.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DeviceRediscoveryAgent.java index e486c14cc6889..6113b0ebf907f 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DeviceRediscoveryAgent.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DeviceRediscoveryAgent.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DeviceRediscoveryListener.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DeviceRediscoveryListener.java index c45fbf903a579..1fb063e512330 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DeviceRediscoveryListener.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DeviceRediscoveryListener.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DiscoveryFinishedListener.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DiscoveryFinishedListener.java index 2bda9265cf472..60a2dee0aba3d 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DiscoveryFinishedListener.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DiscoveryFinishedListener.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DiscoveryProtocol.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DiscoveryProtocol.java index ca9607bdbc53b..e8fdd912ab689 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DiscoveryProtocol.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/discovery/DiscoveryProtocol.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/BroadlinkSocket.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/BroadlinkSocket.java index d2b058b4715de..ae77ea862b6cb 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/BroadlinkSocket.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/BroadlinkSocket.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/BroadlinkSocketListener.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/BroadlinkSocketListener.java index 9fe835fa427cf..590ef4da3fbd3 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/BroadlinkSocketListener.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/BroadlinkSocketListener.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/NetworkTrafficObserver.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/NetworkTrafficObserver.java index 679376e6d424f..a1e56e3f6b172 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/NetworkTrafficObserver.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/NetworkTrafficObserver.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/RetryableSocket.java b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/RetryableSocket.java index 92da6204a418e..b35d96fcd16dd 100644 --- a/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/RetryableSocket.java +++ b/bundles/org.openhab.binding.broadlink/src/main/java/org/openhab/binding/broadlink/internal/socket/RetryableSocket.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/AbstractBroadlinkTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/AbstractBroadlinkTest.java index 50e6978e4f2cb..2d8632af0d046 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/AbstractBroadlinkTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/AbstractBroadlinkTest.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/AbstractBroadlinkThingHandlerTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/AbstractBroadlinkThingHandlerTest.java index 1e933f82f0756..1a48973e08fcf 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/AbstractBroadlinkThingHandlerTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/AbstractBroadlinkThingHandlerTest.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel2HandlerTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel2HandlerTest.java index e8f7d6fd97933..8a684100333bc 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel2HandlerTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel2HandlerTest.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3HandlerTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3HandlerTest.java index c45be66f6c46b..96584cd944919 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3HandlerTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel3HandlerTest.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4HandlerTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4HandlerTest.java index c0e4e9a6a9314..1b0f57bc6c3a9 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4HandlerTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkRemoteModel4HandlerTest.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel2HandlerTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel2HandlerTest.java index a7777c202919f..15d3b78bc1d9e 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel2HandlerTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel2HandlerTest.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3HandlerTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3HandlerTest.java index 99d4ce80b4621..61090e008aa25 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3HandlerTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3HandlerTest.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandlerTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandlerTest.java index 66ee5bce37663..fa5408dd4d3fa 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandlerTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/handler/BroadlinkSocketModel3SHandlerTest.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/BroadlinkMappingServiceTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/BroadlinkMappingServiceTest.java index 523d3c34ce5f6..67afac2315743 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/BroadlinkMappingServiceTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/BroadlinkMappingServiceTest.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/BroadlinkProtocolTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/BroadlinkProtocolTest.java index ce3daab10c333..01d2bb91e7bc9 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/BroadlinkProtocolTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/BroadlinkProtocolTest.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/ModelMapperTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/ModelMapperTest.java index 3f3d6a1e82b1d..af08ac7bfded8 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/ModelMapperTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/ModelMapperTest.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information. diff --git a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/UtilsTest.java b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/UtilsTest.java index 5be1e8517aae4..6fd22db0b7363 100644 --- a/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/UtilsTest.java +++ b/bundles/org.openhab.binding.broadlink/src/test/java/org/openhab/binding/broadlink/internal/UtilsTest.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2022 Contributors to the openHAB project + * Copyright (c) 2010-2023 Contributors to the openHAB project * * See the NOTICE file(s) distributed with this work for additional * information.