]> git.basschouten.com Git - openhab-addons.git/commitdiff
[shelly] Add support for Shelly Wall Dimmer US and Wall Display (#15051)
authorMarkus Michels <markus7017@gmail.com>
Sat, 8 Jul 2023 15:05:49 +0000 (17:05 +0200)
committerGitHub <noreply@github.com>
Sat, 8 Jul 2023 15:05:49 +0000 (17:05 +0200)
Signed-off-by: Markus Michels <markus7017@gmail.com>
23 files changed:
bundles/org.openhab.binding.shelly/README.md
bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/ShellyBindingConstants.java
bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyDeviceProfile.java
bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1ApiJsonDTO.java
bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1CoIoTVersion1.java
bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1HttpApi.java
bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api2/Shelly2ApiClient.java
bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api2/Shelly2ApiJsonDTO.java
bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api2/Shelly2ApiRpc.java
bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api2/Shelly2RpctInterface.java
bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/config/ShellyThingConfiguration.java
bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/discovery/ShellyThingCreator.java
bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyComponents.java
bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyDeviceListener.java
bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyRelayHandler.java
bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyThingInterface.java
bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/provider/ShellyChannelDefinitions.java
bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/config/config2.xml
bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/i18n/shelly.properties
bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/thing/shellyGen1_relay.xml
bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/thing/shellyGen2_relay.xml
bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/thing/shellyGen2_sensor.xml
bundles/org.openhab.binding.shelly/src/main/resources/scripts/oh-blu-scanner.js

index 07d6e97eddc1e3f4db3739542641e1bee2428dbe..be851c340050d2c7c7c3cfaa9194d2eeb2445004 100644 (file)
@@ -90,6 +90,8 @@ The binding provides the same feature set across all devices as good as possible
 | shellyplusi4dc       | Shelly Plus i4 with 4x DC input                          | SNSN-0D24X                   |
 | shellyplusht         | Shelly Plus HT with temperature + humidity sensor        | SNSN-0013A                   |
 | shellyplussmoke      | Shelly Plus Smoke sensor                                 | SNSN-0031Z                   |
+| shellypluswdus       | Shelly Plus Wall Dimmer US                               | SNDM-0013US                  |
+| shellypluswalldisplay| Shelly Plus Wall Display                                 | SAWD-0A1XX10EU1              |
 
 ### Generation 2 Pro series
 
@@ -175,6 +177,7 @@ The binding can't communicate directly with the device, but the Plus/Pro series
 The binding automatically installs a script on the Shelly Device (oh-blu-scanner), which forwards the BLU events to the binding using the WebSocket channel.
 
 Follow these steps to add the Shelly BLU Device to openHAB
+
 - Make sure a Shelly is near by the BLU device, enable Bluetooh on this device (the Bluetooth Gateway mode is not required)
 - Add this thing to openHAB, make sure thing gets online
 - Enable "BLU Gateway Support" in the thing configuration of the Shelly device acting as gateway.
@@ -1202,6 +1205,16 @@ Channels lastEvent and eventCount are only available if input type is set to mom
 | battery | batteryLevel | Number   | yes       | Battery Level in %                                      |
 |         | lowBattery   | Switch   | yes       | Low battery alert (< 20%)                               |
 
+### Shelly Plus Wall Dimmer US (thing-type: shellypluswdus)
+
+|Group  | Channel     |Type     |read-only |Description                                                                         |
+|-------|-------------|---------|----------|------------------------------------------------------------------------------------|
+| relay | brightness  | Dimmer  | r/w       | Currently selected brightness.                                                    |
+|       | outputName  | String  | yes       | Logical name of this relay output as configured in the Shelly App                 |
+|       | autoOn      | Number  | r/w       | Relay #1: Sets a  timer to turn the device ON after every OFF command; in seconds |
+|       | autoOff     | Number  | r/w       | Relay #1: Sets a  timer to turn the device OFF after every ON command; in seconds |
+|       | timerActive | Switch  | yes       | Relay #1: ON: An auto-on/off timer is active                                      |
+| 
 
 ## Shelly Pro Series
 
@@ -1405,6 +1418,22 @@ See notes on discovery of Shelly BLU devices above.
 |         | lowBattery    | Switch   | yes       | Low battery alert (< 20%)                                                           |
 | device  | gatewayDevice | String   | yes       | Shelly forwarded last status update (BLU gateway), could vary from packet to packet |
 
+## Shelly Wall Displays
+
+| Group   | Channel     | Type     | read-only | Description                                                                       |
+| ------- | ----------- | -------- | --------- | --------------------------------------------------------------------------------- |
+| relay   | output      | Switch   | r/w       | Controls the relay's output channel (on/off)                                      |
+|         | outputName  | String   | yes       | Logical name of this relay output as configured in the Shelly App                 |
+|         | input       | Switch   | yes       | ON: Input/Button is powered, see General Notes on Channels                        |
+|         | autoOn      | Number   | r/w       | Relay #1: Sets a  timer to turn the device ON after every OFF command; in seconds |
+|         | autoOff     | Number   | r/w       | Relay #1: Sets a  timer to turn the device OFF after every ON command; in seconds |
+|         | timerActive | Switch   | yes       | Relay #1: ON: An auto-on/off timer is active                                      |
+|         | button      | Trigger  | yes       | Event trigger, see section Button Events                                          |
+| sensors | temperature | Number   | yes       | Temperature reported by the integrated sensor                                     |
+|         | humidity    | Number   | yes       | Relative Humidity in percent reported by the integrated sensor                    |
+|         | lux         | Number   | yes       | Brightness in Lux reported by the integrated sensor                               |
+|         | lastUpdate  | DateTime | yes       | Timestamp of the last update (any sensor value changed)                           |
+
 ## Full Example
 
 ### shelly.things
index 6ef2c453f5cc09b96446fc70231e8495ec27c37d..c80e6b09c6462d7093f226fe42bf732c8e6b63f1 100755 (executable)
@@ -67,10 +67,22 @@ public class ShellyBindingConstants {
             THING_TYPE_SHELLYBUTTON1, //
             THING_TYPE_SHELLYBUTTON2, //
             THING_TYPE_SHELLMOTION, //
+
+            // Shelly Plus
             THING_TYPE_SHELLYPLUS1, //
             THING_TYPE_SHELLYPLUS1PM, //
             THING_TYPE_SHELLYPLUS2PM_RELAY, //
             THING_TYPE_SHELLYPLUS2PM_ROLLER, //
+            THING_TYPE_SHELLYPLUSI4, //
+            THING_TYPE_SHELLYPLUSI4DC, //
+            THING_TYPE_SHELLYPLUSHT, //
+            THING_TYPE_SHELLYPLUSSMOKE, //
+            THING_TYPE_SHELLYPLUSPLUGS, //
+            THING_TYPE_SHELLYPLUSPLUGUS, //
+            THING_TYPE_SHELLYPLUSDIMMERUS, //
+            THING_TYPE_SHELLYPLUSWALLDISPLAY, //
+
+            // Shelly Pro
             THING_TYPE_SHELLYPRO1, //
             THING_TYPE_SHELLYPRO1PM, //
             THING_TYPE_SHELLYPRO2_RELAY, //
@@ -79,14 +91,11 @@ public class ShellyBindingConstants {
             THING_TYPE_SHELLYPRO3, //
             THING_TYPE_SHELLYPRO3EM, //
             THING_TYPE_SHELLYPRO4PM, //
-            THING_TYPE_SHELLYPLUSI4, //
-            THING_TYPE_SHELLYPLUSI4DC, //
-            THING_TYPE_SHELLYPLUSHT, //
-            THING_TYPE_SHELLYPLUSSMOKE, //
-            THING_TYPE_SHELLYPLUSPLUGS, //
-            THING_TYPE_SHELLYPLUSPLUGUS, //
+
+            // Shelly BLU
             THING_TYPE_SHELLYBLUBUTTON, //
             THING_TYPE_SHELLYBLUDW, //
+
             THING_TYPE_SHELLYPROTECTED, //
             THING_TYPE_SHELLYUNKNOWN);
 
index 6230bbeb03532c35366ae9d681d7acc57bfe0261..2fcb6f711f00a4ab651e778291a729e6dfc601fb 100644 (file)
@@ -102,6 +102,8 @@ public class ShellyDeviceProfile {
     public boolean isIX = false; // true for a Shelly IX
     public boolean isTRV = false; // true for a Shelly TRV
     public boolean isSmoke = false; // true for Shelly Smoke
+    public boolean isWall = false; // true: Shelly Wall Display
+    public boolean is3EM = false; // true for Shelly 3EM and Pro 3EM
 
     public int minTemp = 0; // Bulb/Duo: Min Light Temp
     public int maxTemp = 0; // Bulb/Duo: Max Light Temp
@@ -138,9 +140,8 @@ public class ShellyDeviceProfile {
         name = getString(settings.name);
         deviceType = getString(settings.device.type);
         mac = getString(settings.device.mac);
-        hostname = settings.device.hostname != null && !settings.device.hostname.isEmpty()
-                ? settings.device.hostname.toLowerCase()
-                : "shelly-" + mac.toUpperCase().substring(6, 11);
+        hostname = !getString(settings.device.hostname).isEmpty() ? settings.device.hostname.toLowerCase()
+                : mac.length() >= 12 ? "shelly-" + mac.toUpperCase().substring(6, 11) : "unknown";
         mode = getString(settings.mode).toLowerCase();
         hwRev = settings.hwinfo != null ? getString(settings.hwinfo.hwRevision) : "";
         hwBatchId = settings.hwinfo != null ? getString(settings.hwinfo.batchId.toString()) : "";
@@ -193,7 +194,9 @@ public class ShellyDeviceProfile {
 
         isBlu = thingType.startsWith("shellyblu"); // e.g. SBBT for BU Button
 
-        isDimmer = deviceType.equalsIgnoreCase(SHELLYDT_DIMMER) || deviceType.equalsIgnoreCase(SHELLYDT_DIMMER2);
+        isDimmer = deviceType.equalsIgnoreCase(SHELLYDT_DIMMER) || deviceType.equalsIgnoreCase(SHELLYDT_DIMMER2)
+                || deviceType.equalsIgnoreCase(SHELLYDT_PLUSDIMMERUS)
+                || thingType.equalsIgnoreCase(THING_TYPE_SHELLYPLUSDIMMERUS_STR);
         isBulb = thingType.equals(THING_TYPE_SHELLYBULB_STR);
         isDuo = thingType.equals(THING_TYPE_SHELLYDUO_STR) || thingType.equals(THING_TYPE_SHELLYVINTAGE_STR)
                 || thingType.equals(THING_TYPE_SHELLYDUORGBW_STR);
@@ -217,10 +220,13 @@ public class ShellyDeviceProfile {
                 || thingType.equals(THING_TYPE_SHELLYPLUSI4DC_STR);
         isButton = thingType.equals(THING_TYPE_SHELLYBUTTON1_STR) || thingType.equals(THING_TYPE_SHELLYBUTTON2_STR)
                 || thingType.equals(THING_TYPE_SHELLYBLUBUTTON_STR);
-        isSensor = isHT || isFlood || isDW || isSmoke || isGas || isButton || isUNI || isMotion || isSense || isTRV;
-        hasBattery = isHT || isFlood || isDW || isSmoke || isButton || isMotion || isTRV;
         isTRV = thingType.equals(THING_TYPE_SHELLYTRV_STR);
+        isWall = thingType.equals(THING_TYPE_SHELLYPLUSWALLDISPLAY_STR);
+        is3EM = thingType.equals(THING_TYPE_SHELLY3EM_STR) || thingType.equals(THING_TYPE_SHELLYPRO3EM_STR);
 
+        isSensor = isHT || isFlood || isDW || isSmoke || isGas || isButton || isUNI || isMotion || isSense || isTRV
+                || isWall;
+        hasBattery = isHT || isFlood || isDW || isSmoke || isButton || isMotion || isTRV;
         alwaysOn = !hasBattery || isMotion || isSense; // true means: device is reachable all the time (no sleep mode)
     }
 
index 44f87beb044434ca1661c2c23ac414f2f28592ec..c5304fe4e1ce102c3d4d84af8a37eefe61351219 100644 (file)
@@ -405,6 +405,7 @@ public class Shelly1ApiJsonDTO {
         public String pushShortUrl; // to access when roller stopped
 
         // Status information
+        public Integer id;
         public Boolean ison;
         public Boolean overpower;
         @SerializedName("is_valid")
@@ -756,7 +757,7 @@ public class Shelly1ApiJsonDTO {
         public ShellyStatusSensor.ShellyExtSwitchStatus extSwitch;
 
         // Internal device temp
-        public ShellySensorTmp tmp = new ShellySensorTmp(); // Shelly 1PM
+        public ShellySensorTmp tmp; // Shelly 1PM
         public Double temperature; // Shelly 2.5
         public Boolean overtemperature;
 
@@ -825,6 +826,8 @@ public class Shelly1ApiJsonDTO {
         public Integer brightness; // brightness: 0.100%
         @SerializedName("has_timer")
         public Boolean hasTimer;
+        @SerializedName("timer_duration")
+        public Integer timerDuration;
     }
 
     public static class ShellyStatusRelay {
index 263da597aef1ca595ce96755915b4963b4c32345..d7116528dd6ea9803b9f11456a2c3deedccbe69d 100644 (file)
@@ -149,7 +149,7 @@ public class Shelly1CoIoTVersion1 extends Shelly1CoIoTProtocol implements Shelly
                         break;
                     case "current":
                         updateChannel(updates, rGroup, CHANNEL_EMETER_CURRENT,
-                                toQuantityType(getDouble(s.value), DIGITS_VOLT, Units.AMPERE));
+                                toQuantityType(getDouble(s.value), DIGITS_AMPERE, Units.AMPERE));
                         break;
                     case "pf":
                         updateChannel(updates, rGroup, CHANNEL_EMETER_PFACTOR, getDecimal(s.value));
index 5160f9ac91a26731fcd4ff4efecb9fea369ae9d8..d271e1c993b03d5fb4fb56f837762c4844d52e83 100644 (file)
@@ -90,7 +90,9 @@ public class Shelly1HttpApi extends ShellyHttpClient implements ShellyApiInterfa
 
     @Override
     public ShellySettingsDevice getDeviceInfo() throws ShellyApiException {
-        return callApi(SHELLY_URL_DEVINFO, ShellySettingsDevice.class);
+        ShellySettingsDevice info = callApi(SHELLY_URL_DEVINFO, ShellySettingsDevice.class);
+        info.gen = 1;
+        return info;
     }
 
     @Override
index 3736bc300742e5ddeeeb4977549710f454ca0cf1..5351ef096c10d11c0e4e0b4d5eaf9497ca29140f 100644 (file)
@@ -32,12 +32,14 @@ import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyFavPos;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyInputState;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyRollerStatus;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySensorTmp;
+import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsDimmer;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsEMeter;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsInput;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsMeter;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsRelay;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsRoller;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsStatus;
+import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyShortLightStatus;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyShortStatusRelay;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusRelay;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor;
@@ -49,16 +51,19 @@ import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSe
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellyExtVoltage;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellySensorBat;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellySensorHum;
+import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellySensorLux;
 import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2AuthRequest;
 import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2AuthResponse;
 import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceConfig.Shelly2DevConfigCover;
 import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceConfig.Shelly2DevConfigInput;
 import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceConfig.Shelly2DevConfigSwitch;
 import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceConfig.Shelly2GetConfigResult;
+import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceStatus.Shelly2DeviceStatusLight;
 import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceStatus.Shelly2DeviceStatusResult;
 import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceStatus.Shelly2DeviceStatusResult.Shelly2CoverStatus;
 import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceStatus.Shelly2DeviceStatusResult.Shelly2DeviceStatusEm;
 import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceStatus.Shelly2DeviceStatusResult.Shelly2DeviceStatusHumidity;
+import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceStatus.Shelly2DeviceStatusResult.Shelly2DeviceStatusIlluminance;
 import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceStatus.Shelly2DeviceStatusResult.Shelly2DeviceStatusPower;
 import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceStatus.Shelly2DeviceStatusResult.Shelly2DeviceStatusSmoke;
 import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceStatus.Shelly2DeviceStatusResult.Shelly2DeviceStatusTempId;
@@ -164,6 +169,8 @@ public class Shelly2ApiClient extends ShellyHttpClient {
         }
 
         ShellySettingsRelay rsettings = new ShellySettingsRelay();
+        rsettings.id = cs.id;
+        rsettings.isValid = cs.id != null;
         rsettings.name = cs.name;
         rsettings.ison = false;
         rsettings.autoOn = getBool(cs.autoOn) ? cs.autoOnDelay : 0;
@@ -177,7 +184,10 @@ public class Shelly2ApiClient extends ShellyHttpClient {
             boolean channelUpdate) throws ShellyApiException {
         boolean updated = false;
 
-        if (result.temperature0 != null && !getProfile().isSensor) {
+        if (result.temperature0 != null && result.temperature0.tC != null && !getProfile().isSensor) {
+            if (status.tmp == null) {
+                status.tmp = new ShellySensorTmp();
+            }
             status.temperature = status.tmp.tC = result.temperature0.tC;
         }
 
@@ -188,12 +198,14 @@ public class Shelly2ApiClient extends ShellyHttpClient {
         updated |= updateRelayStatus(status, result.switch3, channelUpdate);
         updated |= updateEmStatus(status, result.em0, channelUpdate);
         updated |= updateRollerStatus(status, result.cover0, channelUpdate);
+        updated |= updateDimmerStatus(status, result.light0, channelUpdate);
         if (channelUpdate) {
             updated |= ShellyComponents.updateMeters(getThing(), status);
         }
 
         updateHumidityStatus(sensorData, result.humidity0);
         updateTemperatureStatus(sensorData, result.temperature0);
+        updateIlluminanceStatus(sensorData, result.illuminance0);
         updateSmokeStatus(sensorData, result.smoke0);
         updateBatteryStatus(sensorData, result.devicepower0);
         updateAddonStatus(status, result);
@@ -222,7 +234,13 @@ public class Shelly2ApiClient extends ShellyHttpClient {
             int duration = (int) (now() - rs.timerStartetAt);
             sr.timerRemaining = duration;
         }
+        if (status.tmp == null) {
+            status.tmp = new ShellySensorTmp();
+        }
         if (rs.temperature != null) {
+            if (status.tmp == null) {
+                status.tmp = new ShellySensorTmp();
+            }
             status.tmp.isValid = true;
             status.tmp.tC = rs.temperature.tC;
             status.tmp.tF = rs.temperature.tF;
@@ -231,8 +249,6 @@ public class Shelly2ApiClient extends ShellyHttpClient {
             if (status.temperature == null || getDouble(rs.temperature.tC) > status.temperature) {
                 status.temperature = sr.temperature;
             }
-        } else {
-            status.tmp.isValid = false;
         }
         if (rs.voltage != null) {
             if (status.voltage == null || rs.voltage > status.voltage) {
@@ -250,11 +266,11 @@ public class Shelly2ApiClient extends ShellyHttpClient {
 
         ShellySettingsMeter sm = new ShellySettingsMeter();
         ShellySettingsEMeter emeter = status.emeters.get(rs.id);
-        sm.isValid = emeter.isValid = true;
         if (rs.apower != null) {
             sm.power = emeter.power = rs.apower;
         }
         if (rs.aenergy != null) {
+            // Gen2 reports Watt, needs to be converted to W/h
             sm.total = emeter.total = rs.aenergy.total;
             sm.counters = rs.aenergy.byMinute;
             sm.timestamp = rs.aenergy.minuteTs;
@@ -278,6 +294,12 @@ public class Shelly2ApiClient extends ShellyHttpClient {
 
     private void updateMeter(ShellySettingsStatus status, int id, ShellySettingsMeter sm, ShellySettingsEMeter emeter,
             boolean channelUpdate) throws ShellyApiException {
+        if (getProfile().numMeters == 0) {
+            return;
+        }
+        sm.isValid = sm.power != null || sm.total != null;
+        emeter.isValid = emeter.current != null || emeter.voltage != null || emeter.power != null;
+        emeter.isValid = emeter.current != null || emeter.voltage != null || emeter.power != null;
         status.meters.set(id, sm);
         status.emeters.set(id, emeter);
         relayStatus.meters.set(id, sm);
@@ -301,7 +323,6 @@ public class Shelly2ApiClient extends ShellyHttpClient {
 
         ShellySettingsMeter sm = new ShellySettingsMeter();
         ShellySettingsEMeter emeter = status.emeters.get(0);
-        sm.isValid = emeter.isValid = true;
         if (em.aActPower != null) {
             sm.power = emeter.power = em.aActPower;
         }
@@ -322,7 +343,6 @@ public class Shelly2ApiClient extends ShellyHttpClient {
 
         sm = new ShellySettingsMeter();
         emeter = status.emeters.get(1);
-        sm.isValid = emeter.isValid = true;
         if (em.bActPower != null) {
             sm.power = emeter.power = em.bActPower;
         }
@@ -446,6 +466,9 @@ public class Shelly2ApiClient extends ShellyHttpClient {
             rs.duration = (int) (now() - cs.moveStartedAt.longValue());
         }
         if (cs.temperature != null && cs.temperature.tC > getDouble(status.temperature)) {
+            if (status.tmp == null) {
+                status.tmp = new ShellySensorTmp();
+            }
             status.temperature = status.tmp.tC = getDouble(cs.temperature.tC);
         }
         if (cs.apower != null) {
@@ -482,6 +505,46 @@ public class Shelly2ApiClient extends ShellyHttpClient {
         return updateChannels ? ShellyComponents.updateRoller((ShellyBaseHandler) getThing(), rs, cs.id) : false;
     }
 
+    protected void fillDimmerSettings(ShellyDeviceProfile profile, Shelly2GetConfigResult dc) {
+        if (!profile.isDimmer || dc.light0 == null) {
+            return;
+        }
+
+        if (profile.settings.dimmers != null) {
+            ShellySettingsDimmer ds = profile.settings.dimmers.get(0);
+            ds.autoOn = dc.light0.autoOnDelay;
+            ds.autoOff = dc.light0.autoOffDelay;
+            ds.name = dc.light0.name;
+            profile.settings.dimmers.set(0, ds);
+        }
+    }
+
+    private boolean updateDimmerStatus(ShellySettingsStatus status, @Nullable Shelly2DeviceStatusLight value,
+            boolean channelUpdate) throws ShellyApiException {
+        ShellyDeviceProfile profile = getProfile();
+        if (!profile.isDimmer || value == null) {
+            return false;
+        }
+
+        ShellyShortLightStatus ds = status.dimmers.get(0);
+        if (value.brightness != null) {
+            ds.brightness = value.brightness.intValue();
+        }
+        ds.ison = value.output;
+        ds.hasTimer = value.timerStartedAt != null;
+        ds.timerDuration = getDuration(value.timerStartedAt, value.timerDuration);
+        status.dimmers.set(0, ds);
+        return channelUpdate ? ShellyComponents.updateDimmers(getThing(), status) : false;
+    }
+
+    protected @Nullable Integer getDuration(@Nullable Double timerStartedAt, @Nullable Integer timerDuration) {
+        if (timerStartedAt == null || timerDuration == null) {
+            return null;
+        }
+        int duration = (int) (now() - timerStartedAt.longValue());
+        return duration <= timerDuration ? timerDuration - duration : 0;
+    }
+
     // Addon
     private void updateAddonStatus(ShellySettingsStatus status, @Nullable Shelly2DeviceStatusResult ds)
             throws ShellyApiException {
@@ -544,6 +607,18 @@ public class Shelly2ApiClient extends ShellyHttpClient {
         sdata.tmp.tF = value.tF;
     }
 
+    protected void updateIlluminanceStatus(ShellyStatusSensor sdata, @Nullable Shelly2DeviceStatusIlluminance value) {
+        if (value == null) {
+            return;
+        }
+        if (sdata.lux == null) {
+            sdata.lux = new ShellySensorLux();
+        }
+        sdata.lux.isValid = value.lux != null;
+        sdata.lux.value = value.lux;
+        sdata.lux.illumination = value.illumination;
+    }
+
     protected void updateSmokeStatus(ShellyStatusSensor sdata, @Nullable Shelly2DeviceStatusSmoke value) {
         if (value == null) {
             return;
index 58dcddfb7da090da2e2d8de9fe90a714dd14cc9c..37ebc620a544141ec129fdc564f9ae0135001c51 100644 (file)
@@ -47,6 +47,10 @@ public class Shelly2ApiJsonDTO {
     public static final String SHELLY2_COVER_CMD_OPEN = "Open";
     public static final String SHELLY2_COVER_CMD_CLOSE = "Close";
     public static final String SHELLY2_COVER_CMD_STOP = "Stop";
+    public static final String SHELLYRPC_METHOD_LIGHT_STATUS = "Light.GetStatus";
+    public static final String SHELLYRPC_METHOD_LIGHT_SET = "Light.Set";
+    public static final String SHELLYRPC_METHOD_LIGHT_SETCONFIG = "Light.SetConfig";
+    public static final String SHELLYRPC_METHOD_LED_SETCONFIG = "WD_UI.SetConfig";
     public static final String SHELLYRPC_METHOD_WIFIGETCONG = "Wifi.GetConfig";
     public static final String SHELLYRPC_METHOD_WIFISETCONG = "Wifi.SetConfig";
     public static final String SHELLYRPC_METHOD_ETHGETCONG = "Eth.GetConfig";
@@ -56,6 +60,7 @@ public class Shelly2ApiJsonDTO {
     public static final String SHELLYRPC_METHOD_CLOUDSET = "Cloud.SetConfig";
     public static final String SHELLYRPC_METHOD_WSGETCONFIG = "WS.GetConfig";
     public static final String SHELLYRPC_METHOD_WSSETCONFIG = "WS.SetConfig";
+    public static final String SHELLYRPC_METHOD_EMDATARESET = "EMData.DeleteAllData";
     public static final String SHELLYRPC_METHOD_SMOKE_SETCONFIG = "Smoke.SetConfig";
     public static final String SHELLYRPC_METHOD_SMOKE_MUTE = "Smoke.Mute";
     public static final String SHELLYRPC_METHOD_SCRIPT_LIST = "Script.List";
@@ -151,6 +156,12 @@ public class Shelly2ApiJsonDTO {
     public static final String SHELLY2_WAKEUPOCAUSE_UPDATE = "status_update";
     public static final String SHELLY2_WAKEUPOCAUSE_UNDEFINED = "undefined";
 
+    // Dimmer US: LED power modes
+    public static final String SHELLY2_POWERLED_ON = "on";
+    public static final String SHELLY2_POWERLED_OFF = "off";
+    public static final String SHELLY2_POWERLED_MATCH = "match_output";
+    public static final String SHELLY2_POWERLED_INVERT = "inverted_output";
+
     public class Shelly2DevConfigBle {
         public Boolean enable;
     }
@@ -265,7 +276,7 @@ public class Shelly2ApiJsonDTO {
         }
 
         public class Shelly2DevConfigInput {
-            public String id;
+            public Integer id;
             public String name;
             public String type;
             public Boolean invert;
@@ -276,7 +287,7 @@ public class Shelly2ApiJsonDTO {
         }
 
         public class Shelly2DevConfigSwitch {
-            public String id;
+            public Integer id;
             public String name;
 
             @SerializedName("in_mode")
@@ -367,6 +378,41 @@ public class Shelly2ApiJsonDTO {
             public Boolean mute;
         }
 
+        public static class Shelly2GetConfigLight {
+            public static class Shelly2GetConfigLightDefault {
+                public Integer brightness;
+            }
+
+            public static class Shelly2GetConfigLightNightMode {
+                public boolean enable;
+                public Integer brightness;
+            }
+
+            public Integer id;
+            public String name;
+            @SerializedName("initial_state")
+            public String initialState;
+            @SerializedName("auto_on")
+            public Boolean autoOn;
+            @SerializedName("auto_off")
+            public Boolean autoOff;
+            @SerializedName("auto_on_delay")
+            public Double autoOnDelay;
+            @SerializedName("auto_off_delay")
+            public Double autoOffDelay;
+            @SerializedName("default")
+            public Shelly2GetConfigLightDefault defaultCfg;
+            @SerializedName("night_mode")
+            public Shelly2GetConfigLightNightMode nightMode;
+        }
+
+        public class Shelly2DeviceConfigLed {
+            @SerializedName("sys_led_enable")
+            public Boolean sysLedEnable;
+            @SerializedName("power_led")
+            public String powerLed;
+        }
+
         public static class Shelly2GetConfigResult {
 
             public class Shelly2DevConfigCloud {
@@ -392,6 +438,8 @@ public class Shelly2ApiJsonDTO {
             public Shelly2DevConfigMqtt mqtt;
             public Shelly2DeviceConfigSys sys;
             public Shelly2DeviceConfigWiFi wifi;
+            @SerializedName("wd_ui")
+            public Shelly2DeviceConfigLed led;
 
             @SerializedName("input:0")
             public Shelly2DevConfigInput input0;
@@ -417,6 +465,9 @@ public class Shelly2ApiJsonDTO {
             @SerializedName("cover:0")
             public Shelly2DevConfigCover cover0;
 
+            @SerializedName("light:0")
+            public Shelly2GetConfigLight light0;
+
             @SerializedName("smoke:0")
             public Shelly2ConfigSmoke smoke0;
         }
@@ -460,6 +511,17 @@ public class Shelly2ApiJsonDTO {
             public ArrayList<String> errors;// shown only if at least one error is present.
         }
 
+        public static class Shelly2DeviceStatusLight {
+            public Integer id;
+            public String source;
+            public Boolean output;
+            public Double brightness;
+            @SerializedName("timer_started_at")
+            public Double timerStartedAt;
+            @SerializedName("timer_duration")
+            public Integer timerDuration;
+        }
+
         public static class Shelly2DeviceStatusResult {
             public class Shelly2DeviceStatusBle {
 
@@ -501,6 +563,12 @@ public class Shelly2ApiJsonDTO {
                 public Double rh;
             }
 
+            public class Shelly2DeviceStatusIlluminance {
+                public Integer id;
+                public Double lux;
+                public String illumination;
+            }
+
             public class Shelly2DeviceStatusVoltage {
                 public Integer id;
                 public Double voltage;
@@ -618,6 +686,9 @@ public class Shelly2ApiJsonDTO {
             @SerializedName("cover:0")
             public Shelly2CoverStatus cover0;
 
+            @SerializedName("light:0")
+            public Shelly2DeviceStatusLight light0;
+
             @SerializedName("temperature:0")
             public Shelly2DeviceStatusTempId temperature0;
             @SerializedName("temperature:100")
@@ -635,6 +706,10 @@ public class Shelly2ApiJsonDTO {
             public Shelly2DeviceStatusHumidity humidity0;
             @SerializedName("humidity:100")
             public Shelly2DeviceStatusHumidity humidity100;
+
+            @SerializedName("illuminance:0")
+            Shelly2DeviceStatusIlluminance illuminance0;
+
             @SerializedName("smoke:0")
             public Shelly2DeviceStatusSmoke smoke0;
 
@@ -751,6 +826,12 @@ public class Shelly2ApiJsonDTO {
         public Boolean autoOff;
         @SerializedName("auto_off_delay")
         public Double autoOffDelay;
+
+        // WD_UI.SetConfig
+        @SerializedName("sys_led_enable")
+        public Boolean sysLedEnable;
+        @SerializedName("power_led")
+        public String powerLed;
     }
 
     public static class Shelly2RpcRequest {
@@ -764,6 +845,11 @@ public class Shelly2ApiJsonDTO {
             public Integer pos;
             public Boolean on;
 
+            // Dimmer / Light
+            public Integer brightness;
+            @SerializedName("toggle_after")
+            public Integer toggleAfter;
+
             // Shelly.SetAuth
             public String user;
             public String realm;
index a1d9f69f5cfbbf8f466ee3b81750a8e004d93188..2efb6c6c4ebb114fd6f3e78e824f697b8bd5561b 100644 (file)
@@ -41,6 +41,7 @@ import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyOtaCheck
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyRollerStatus;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySensorSleepMode;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsDevice;
+import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsDimmer;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsEMeter;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsLogin;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsMeter;
@@ -60,6 +61,7 @@ import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceC
 import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceConfigAp;
 import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceConfigAp.Shelly2DeviceConfigApRE;
 import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceSettings;
+import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceStatus.Shelly2DeviceStatusLight;
 import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceStatus.Shelly2DeviceStatusResult;
 import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceStatus.Shelly2DeviceStatusSys.Shelly2DeviceStatusSysAvlUpdate;
 import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2NotifyEvent;
@@ -151,11 +153,9 @@ public class Shelly2ApiRpc extends Shelly2ApiClient implements ShellyApiInterfac
 
     @Override
     public void startScan() {
-        if (config.enableBluGateway) {
-            try {
-                installScript(SHELLY2_BLU_GWSCRIPT);
-            } catch (ShellyApiException e) {
-            }
+        try {
+            installScript(SHELLY2_BLU_GWSCRIPT, config.enableBluGateway);
+        } catch (ShellyApiException e) {
         }
     }
 
@@ -206,6 +206,7 @@ public class Shelly2ApiRpc extends Shelly2ApiClient implements ShellyApiInterfac
         profile.deviceType = device.type;
         profile.mac = device.mac;
         profile.auth = device.auth;
+        profile.isGen2 = device.gen == 2;
         if (config.serviceName.isEmpty()) {
             config.serviceName = getString(profile.hostname);
         }
@@ -275,7 +276,13 @@ public class Shelly2ApiRpc extends Shelly2ApiClient implements ShellyApiInterfac
             }
         }
 
-        profile.status.dimmers = profile.isDimmer ? new ArrayList<>() : null;
+        if (profile.isDimmer) {
+            profile.settings.dimmers = new ArrayList<>();
+            profile.settings.dimmers.add(new ShellySettingsDimmer());
+            profile.status.dimmers = new ArrayList<>();
+            profile.status.dimmers.add(new ShellyShortLightStatus());
+            fillDimmerSettings(profile, dc);
+        }
         profile.status.lights = profile.isBulb ? new ArrayList<>() : null;
         profile.status.thermostats = profile.isTRV ? new ArrayList<>() : null;
 
@@ -286,19 +293,25 @@ public class Shelly2ApiRpc extends Shelly2ApiClient implements ShellyApiInterfac
             checkSetWsCallback();
         }
 
+        if (dc.led != null) {
+            profile.settings.ledStatusDisable = !getBool(dc.led.sysLedEnable);
+            profile.settings.ledPowerDisable = getString(dc.led.powerLed).equals("off");
+        }
+
         profile.initialized = true;
         if (!discovery) {
             getStatus(); // make sure profile.status is initialized (e.g,. relay/meter status)
             asyncApiRequest(SHELLYRPC_METHOD_GETSTATUS); // request periodic status updates from device
 
             try {
-                logger.debug("{}: BLU Gateway support enabled for this device: {}", thingName, config.enableBluGateway);
-                if (config.enableBluGateway) {
-                    if (getBool(profile.settings.bluetooth)) {
-                        installScript(SHELLY2_BLU_GWSCRIPT);
-                    } else {
-                        logger.debug("{}: Bluetooth needs to be enabled to activate BLU Gateway mode", thingName);
+                if (config.enableBluGateway != null) {
+                    logger.debug("{}: BLU Gateway support is {} for this device", thingName,
+                            config.enableBluGateway ? "enabled" : "disabled");
+                    boolean bluetooth = getBool(profile.settings.bluetooth);
+                    if (config.enableBluGateway && !bluetooth) {
+                        logger.info("{}: Bluetooth needs to be enabled to activate BLU Gateway mode", thingName);
                     }
+                    installScript(SHELLY2_BLU_GWSCRIPT, config.enableBluGateway && bluetooth);
                 }
             } catch (ShellyApiException e) {
                 logger.debug("{}: Device config failed", thingName, e);
@@ -340,22 +353,32 @@ public class Shelly2ApiRpc extends Shelly2ApiClient implements ShellyApiInterfac
         }
     }
 
-    protected void installScript(String script) throws ShellyApiException {
-        String json = apiRequest(new Shelly2RpcRequest().withMethod(SHELLYRPC_METHOD_SCRIPT_LIST));
-        ShellyScriptListResponse scriptList = gson.fromJson(json, ShellyScriptListResponse.class);
+    protected void installScript(String script, boolean install) throws ShellyApiException {
+        ShellyScriptListResponse scriptList = apiRequest(
+                new Shelly2RpcRequest().withMethod(SHELLYRPC_METHOD_SCRIPT_LIST), ShellyScriptListResponse.class);
         Integer ourId = -1;
         String code = "";
 
-        logger.debug("{}: Install or restart script {} on Shelly Device", thingName, script);
+        if (install) {
+            logger.debug("{}: Install or restart script {} on Shelly Device", thingName, script);
+        }
         boolean running = false, upload = false;
-        if (scriptList != null) {
-            for (ShellyScriptListEntry s : scriptList.scripts) {
-                if (s.name.startsWith(script)) {
-                    ourId = s.id;
-                    running = s.running;
-                    logger.debug("{}: Script {} is already installed, id={}", thingName, script, ourId);
-                }
+        for (ShellyScriptListEntry s : scriptList.scripts) {
+            if (s.name.startsWith(script)) {
+                ourId = s.id;
+                running = s.running;
+                logger.debug("{}: Script {} is already installed, id={}", thingName, script, ourId);
+                break;
+            }
+        }
+
+        if (!install) {
+            if (ourId != -1) {
+                startScript(ourId, false);
+                enableScript(script, false);
+                logger.debug("{}: Script {} was disabledd, id={}", thingName, script, ourId);
             }
+            return;
         }
 
         // get script code from bundle resources
@@ -380,8 +403,9 @@ public class Shelly2ApiRpc extends Shelly2ApiClient implements ShellyApiInterfac
         } else {
             try {
                 // verify that the same code version is active (avoid unnesesary flash updates)
-                json = apiRequest(new Shelly2RpcRequest().withMethod(SHELLYRPC_METHOD_SCRIPT_GETCODE).withId(ourId));
-                ShellyScriptResponse rsp = gson.fromJson(json, ShellyScriptResponse.class);
+                ShellyScriptResponse rsp = apiRequest(
+                        new Shelly2RpcRequest().withMethod(SHELLYRPC_METHOD_SCRIPT_GETCODE).withId(ourId),
+                        ShellyScriptResponse.class);
                 if (!rsp.data.trim().equals(code.trim())) {
                     logger.debug("{}: A script version was found, update to newest one", thingName);
                     upload = true;
@@ -397,27 +421,26 @@ public class Shelly2ApiRpc extends Shelly2ApiClient implements ShellyApiInterfac
         }
 
         if (restart || (running && upload)) {
-            json = apiRequest(new Shelly2RpcRequest().withMethod(SHELLYRPC_METHOD_SCRIPT_STOP).withId(ourId));
             // first stop running script
+            startScript(ourId, false);
             running = false;
         }
         if (upload && ourId != -1) {
             // Delete existing script
             logger.debug("{}: Delete existing script", thingName);
-            json = apiRequest(new Shelly2RpcRequest().withMethod(SHELLYRPC_METHOD_SCRIPT_DELETE).withId(ourId));
+            apiRequest(new Shelly2RpcRequest().withMethod(SHELLYRPC_METHOD_SCRIPT_DELETE).withId(ourId));
         }
 
         if (upload) {
             logger.debug("{}: Script will be installed...", thingName);
 
             // Create new script, get id
-            json = apiRequest(new Shelly2RpcRequest().withMethod(SHELLYRPC_METHOD_SCRIPT_CREATE).withName(script));
-            ShellyScriptResponse rsp = gson.fromJson(json, ShellyScriptResponse.class);
-            if (rsp != null) {
-                ourId = rsp.id;
-                logger.debug("{}: Script has been created, id={}", thingName, ourId);
-                upload = true;
-            }
+            ShellyScriptResponse rsp = apiRequest(
+                    new Shelly2RpcRequest().withMethod(SHELLYRPC_METHOD_SCRIPT_CREATE).withName(script),
+                    ShellyScriptResponse.class);
+            ourId = rsp.id;
+            logger.debug("{}: Script has been created, id={}", thingName, ourId);
+            upload = true;
         }
 
         if (upload) {
@@ -437,17 +460,40 @@ public class Shelly2ApiRpc extends Shelly2ApiClient implements ShellyApiInterfac
                 parms.append = true;
             } while (processed < length);
             running = false;
-
-            Shelly2RpcRequestParams params = new Shelly2RpcRequestParams().withConfig();
-            params.config.enable = true;
-            apiRequest(SHELLYRPC_METHOD_SCRIPT_SETCONFIG, params, String.class);
+        }
+        if (enableScript(script, true)) {
+            logger.info("{}: Script {} was {} installed successful", thingName, thingName, script);
         }
 
         if (!running) {
-            // Script was created or is there and stopped -> start it
-            json = apiRequest(new Shelly2RpcRequest().withMethod(SHELLYRPC_METHOD_SCRIPT_START).withId(ourId));
-            logger.debug("{}: Script {} was {} successful", thingName, script,
-                    restart ? "restarted" : "installed and started");
+            running = startScript(ourId, true);
+        }
+        logger.info("{}: Script {} {}", thingName, script,
+                running ? "was successfully (re)started" : "failed to start");
+    }
+
+    private boolean startScript(int ourId, boolean start) {
+        if (ourId != -1) {
+            try {
+                apiRequest(new Shelly2RpcRequest()
+                        .withMethod(start ? SHELLYRPC_METHOD_SCRIPT_START : SHELLYRPC_METHOD_SCRIPT_STOP)
+                        .withId(ourId));
+                return true;
+            } catch (ShellyApiException e) {
+            }
+        }
+        return false;
+    }
+
+    private boolean enableScript(String script, boolean enable) {
+        try {
+            Shelly2RpcRequestParams params = new Shelly2RpcRequestParams().withConfig();
+            params.config.name = script;
+            params.config.enable = enable;
+            apiRequest(SHELLYRPC_METHOD_SCRIPT_SETCONFIG, params, String.class);
+            return true;
+        } catch (ShellyApiException e) {
+            return false;
         }
     }
 
@@ -519,6 +565,15 @@ public class Shelly2ApiRpc extends Shelly2ApiClient implements ShellyApiInterfac
                             toQuantityType(getDouble(status.tmp.tC), DIGITS_NONE, SIUnits.CELSIUS));
                 }
 
+                if (status.meters.size() > 0) {
+                    boolean validMeter = false;
+                    for (ShellySettingsMeter meter : status.meters) {
+                        validMeter |= meter.isValid;
+                    }
+                    if (!validMeter) {
+                        profile.numMeters = 0;
+                    }
+                }
                 profile.status = status;
                 if (updated) {
                     getThing().restartWatchdog();
@@ -765,6 +820,44 @@ public class Shelly2ApiRpc extends Shelly2ApiClient implements ShellyApiInterfac
                 new Shelly2RpcRequest().withMethod(SHELLYRPC_METHOD_COVER_SETPOS).withId(relayIndex).withPos(position));
     }
 
+    @Override
+    public ShellyStatusLight getLightStatus() throws ShellyApiException {
+        throw new ShellyApiException("API call not implemented");
+    }
+
+    @Override
+    public ShellyShortLightStatus getLightStatus(int index) throws ShellyApiException {
+        ShellyShortLightStatus status = new ShellyShortLightStatus();
+        Shelly2DeviceStatusLight ls = apiRequest(
+                new Shelly2RpcRequest().withMethod(SHELLYRPC_METHOD_LIGHT_STATUS).withId(index),
+                Shelly2DeviceStatusLight.class);
+        status.ison = ls.output;
+        status.hasTimer = ls.timerStartedAt != null;
+        status.timerDuration = getDuration(ls.timerStartedAt, ls.timerDuration);
+        if (ls.brightness != null) {
+            status.brightness = ls.brightness.intValue();
+        }
+        return status;
+    }
+
+    @Override
+    public void setBrightness(int id, int brightness, boolean autoOn) throws ShellyApiException {
+        Shelly2RpcRequestParams params = new Shelly2RpcRequestParams();
+        params.id = id;
+        params.brightness = brightness;
+        params.on = brightness > 0;
+        apiRequest(SHELLYRPC_METHOD_LIGHT_SET, params, String.class);
+    }
+
+    @Override
+    public ShellyShortLightStatus setLightTurn(int id, String turnMode) throws ShellyApiException {
+        Shelly2RpcRequestParams params = new Shelly2RpcRequestParams();
+        params.id = id;
+        params.on = turnMode.equals(SHELLY_API_ON);
+        apiRequest(SHELLYRPC_METHOD_LIGHT_SET, params, String.class);
+        return getLightStatus(id);
+    }
+
     @Override
     public ShellyStatusSensor getSensorStatus() throws ShellyApiException {
         return sensorData;
@@ -772,10 +865,13 @@ public class Shelly2ApiRpc extends Shelly2ApiClient implements ShellyApiInterfac
 
     @Override
     public void setAutoTimer(int index, String timerName, double value) throws ShellyApiException {
-        Shelly2RpcRequest req = new Shelly2RpcRequest().withMethod(SHELLYRPC_METHOD_SWITCH_SETCONFIG).withId(index);
-
+        ShellyDeviceProfile profile = getProfile();
+        boolean isLight = profile.isLight || profile.isDimmer;
+        String method = isLight ? SHELLYRPC_METHOD_LIGHT_SETCONFIG : SHELLYRPC_METHOD_SWITCH_SETCONFIG;
+        String component = isLight ? "Light" : "Switch";
+        Shelly2RpcRequest req = new Shelly2RpcRequest().withMethod(method).withId(index);
         req.params.withConfig();
-        req.params.config.name = "Switch" + index;
+        req.params.config.name = component + index;
         if (timerName.equals(SHELLY_TIMER_AUTOON)) {
             req.params.config.autoOn = value > 0;
             req.params.config.autoOnDelay = value;
@@ -786,8 +882,23 @@ public class Shelly2ApiRpc extends Shelly2ApiClient implements ShellyApiInterfac
         apiRequest(req);
     }
 
+    @Override
+    public void setLedStatus(String ledName, boolean value) throws ShellyApiException {
+        Shelly2RpcRequestParams params = new Shelly2RpcRequestParams().withConfig();
+        params.id = 0;
+        if (ledName.equals(SHELLY_LED_STATUS_DISABLE)) {
+            params.config.sysLedEnable = value;
+        } else if (ledName.equals(SHELLY_LED_POWER_DISABLE)) {
+            params.config.powerLed = value ? SHELLY2_POWERLED_OFF : SHELLY2_POWERLED_MATCH;
+        } else {
+            throw new ShellyApiException("API call not implemented for this LED type");
+        }
+        apiRequest(SHELLYRPC_METHOD_LED_SETCONFIG, params, Shelly2WsConfigResult.class);
+    }
+
     @Override
     public void resetMeterTotal(int id) throws ShellyApiException {
+        apiRequest(new Shelly2RpcRequest().withMethod(SHELLYRPC_METHOD_EMDATARESET).withId(id));
     }
 
     @Override
@@ -899,20 +1010,6 @@ public class Shelly2ApiRpc extends Shelly2ApiClient implements ShellyApiInterfac
      * The following API calls are not yet relevant, because currently there a no Plus/Pro (Gen2) devices of those
      * categories (e.g. bulbs)
      */
-    @Override
-    public void setLedStatus(String ledName, boolean value) throws ShellyApiException {
-        throw new ShellyApiException("API call not implemented");
-    }
-
-    @Override
-    public ShellyStatusLight getLightStatus() throws ShellyApiException {
-        throw new ShellyApiException("API call not implemented");
-    }
-
-    @Override
-    public ShellyShortLightStatus getLightStatus(int index) throws ShellyApiException {
-        throw new ShellyApiException("API call not implemented");
-    }
 
     @Override
     public void setLightParm(int lightIndex, String parm, String value) throws ShellyApiException {
@@ -924,16 +1021,6 @@ public class Shelly2ApiRpc extends Shelly2ApiClient implements ShellyApiInterfac
         throw new ShellyApiException("API call not implemented");
     }
 
-    @Override
-    public ShellyShortLightStatus setLightTurn(int id, String turnMode) throws ShellyApiException {
-        throw new ShellyApiException("API call not implemented");
-    }
-
-    @Override
-    public void setBrightness(int id, int brightness, boolean autoOn) throws ShellyApiException {
-        throw new ShellyApiException("API call not implemented");
-    }
-
     @Override
     public void setLightMode(String mode) throws ShellyApiException {
         throw new ShellyApiException("API call not implemented");
@@ -1058,10 +1145,12 @@ public class Shelly2ApiRpc extends Shelly2ApiClient implements ShellyApiInterfac
         if (response.result != null) {
             // return sub element result as requested class type
             json = gson.toJson(gson.fromJson(json, Shelly2RpcBaseMessage.class).result);
-            return fromJson(gson, json, classOfT);
+            boolean isString = response.result instanceof String;
+            return fromJson(gson, isString && ((String) response.result).equalsIgnoreCase("null") ? "{}" : json,
+                    classOfT);
         } else {
             // return direct format
-            return gson.fromJson(json, classOfT);
+            return gson.fromJson(json, classOfT == String.class ? Shelly2RpcBaseMessage.class : classOfT);
         }
     }
 
@@ -1069,8 +1158,8 @@ public class Shelly2ApiRpc extends Shelly2ApiClient implements ShellyApiInterfac
         return apiRequest(request.method, request.params, classOfT);
     }
 
-    public String apiRequest(Shelly2RpcRequest request) throws ShellyApiException {
-        return apiRequest(request.method, request.params, String.class);
+    public void apiRequest(Shelly2RpcRequest request) throws ShellyApiException {
+        apiRequest(request.method, request.params, Shelly2RpcBaseMessage.class);
     }
 
     private String rpcPost(String postData) throws ShellyApiException {
index 82ffdee92cb2f081cd84d143c23712ce8a08728c..4387db1413cd623a00d787f8127aca619699dcd9 100644 (file)
@@ -24,15 +24,15 @@ import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2RpcNoti
 @NonNullByDefault
 public interface Shelly2RpctInterface {
 
-    public void onConnect(String deviceIp, boolean connected);
+    void onConnect(String deviceIp, boolean connected);
 
-    public void onMessage(String decodedmessage);
+    void onMessage(String decodedmessage);
 
-    public void onNotifyStatus(Shelly2RpcNotifyStatus message);
+    void onNotifyStatus(Shelly2RpcNotifyStatus message);
 
-    public void onNotifyEvent(Shelly2RpcNotifyEvent message);
+    void onNotifyEvent(Shelly2RpcNotifyEvent message);
 
-    public void onClose(int statusCode, String reason);
+    void onClose(int statusCode, String reason);
 
-    public void onError(Throwable cause);
+    void onError(Throwable cause);
 }
index eb7ed5091e84adb0d59ba7bd87aeaa14e42ca2be..b08e74edb6a25b8314ae937f3ad584920a5999cb 100755 (executable)
@@ -44,5 +44,5 @@ public class ShellyThingConfiguration {
     public String localPort = "8080";
     public String serviceName = "";
 
-    public boolean enableBluGateway = false;
+    public Boolean enableBluGateway = false;
 }
index 664047b9014c999c7876bdb43086d8300ad022a6..b142c6291310bfa82c37a65fb40be8182b00a39f 100644 (file)
@@ -79,6 +79,8 @@ public class ShellyThingCreator {
     public static final String SHELLYDT_PLUSI4DC = "SNSN-0D24X";
     public static final String SHELLYDT_PLUSHT = "SNSN-0013A";
     public static final String SHELLYDT_PLUSSMOKE = "SNSN-0031Z";
+    public static final String SHELLYDT_PLUSDIMMERUS = "SNDM-0013US";
+    public static final String SHELLYDT_PLUSWALLDISPLAY = "SAWD-0A1XX10EU1";
 
     // Shelly Pro Series
     public static final String SHELLYDT_PRO1 = "SPSW-001XE16EU";
@@ -157,6 +159,8 @@ public class ShellyThingCreator {
     public static final String THING_TYPE_SHELLYPLUSSMOKE_STR = "shellyplussmoke";
     public static final String THING_TYPE_SHELLYPLUSPLUGS_STR = "shellyplusplug";
     public static final String THING_TYPE_SHELLYPLUSPLUGUS_STR = "shellyplusplugus";
+    public static final String THING_TYPE_SHELLYPLUSDIMMERUS_STR = "shellypluswdus";
+    public static final String THING_TYPE_SHELLYPLUSWALLDISPLAY_STR = "shellywalldisplay";
 
     // Shelly Pro Series
     public static final String THING_TYPE_SHELLYPRO1_STR = "shellypro1";
@@ -233,7 +237,7 @@ public class ShellyThingCreator {
     public static final ThingTypeUID THING_TYPE_SHELLYUNKNOWN = new ThingTypeUID(BINDING_ID,
             THING_TYPE_SHELLYUNKNOWN_STR);
 
-    // Shelly Plus/Pro
+    // Shelly Plus
     public static final ThingTypeUID THING_TYPE_SHELLYPLUS1 = new ThingTypeUID(BINDING_ID, THING_TYPE_SHELLYPLUS1_STR);
     public static final ThingTypeUID THING_TYPE_SHELLYPLUS1PM = new ThingTypeUID(BINDING_ID,
             THING_TYPE_SHELLYPLUS1PM_STR);
@@ -253,6 +257,12 @@ public class ShellyThingCreator {
             THING_TYPE_SHELLYPLUSPLUGS_STR);
     public static final ThingTypeUID THING_TYPE_SHELLYPLUSPLUGUS = new ThingTypeUID(BINDING_ID,
             THING_TYPE_SHELLYPLUSPLUGUS_STR);
+    public static final ThingTypeUID THING_TYPE_SHELLYPLUSDIMMERUS = new ThingTypeUID(BINDING_ID,
+            THING_TYPE_SHELLYPLUSDIMMERUS_STR);
+    public static final ThingTypeUID THING_TYPE_SHELLYPLUSWALLDISPLAY = new ThingTypeUID(BINDING_ID,
+            THING_TYPE_SHELLYPLUSWALLDISPLAY_STR);
+
+    // Shelly Pro
     public static final ThingTypeUID THING_TYPE_SHELLYPRO1 = new ThingTypeUID(BINDING_ID, THING_TYPE_SHELLYPRO1_STR);
     public static final ThingTypeUID THING_TYPE_SHELLYPRO1PM = new ThingTypeUID(BINDING_ID,
             THING_TYPE_SHELLYPRO1PM_STR);
@@ -317,6 +327,7 @@ public class ShellyThingCreator {
         THING_TYPE_MAPPING.put(SHELLYDT_PLUSI4, THING_TYPE_SHELLYPLUSI4_STR);
         THING_TYPE_MAPPING.put(SHELLYDT_PLUSHT, THING_TYPE_SHELLYPLUSHT_STR);
         THING_TYPE_MAPPING.put(SHELLYDT_PLUSSMOKE, THING_TYPE_SHELLYPLUSSMOKE_STR);
+        THING_TYPE_MAPPING.put(SHELLYDT_PLUSDIMMERUS, THING_TYPE_SHELLYPLUSDIMMERUS_STR);
 
         // Pro Series
         THING_TYPE_MAPPING.put(SHELLYDT_PRO1, THING_TYPE_SHELLYPRO1_STR);
@@ -343,6 +354,9 @@ public class ShellyThingCreator {
         THING_TYPE_MAPPING.put(SHELLYDT_BLUBUTTON, THING_TYPE_SHELLYBLUBUTTON_STR);
         THING_TYPE_MAPPING.put(SHELLYDT_BLUDW, THING_TYPE_SHELLYBLUDW_STR);
 
+        // Wall displays
+        THING_TYPE_MAPPING.put(SHELLYDT_PLUSWALLDISPLAY, THING_TYPE_SHELLYPLUSWALLDISPLAY_STR);
+
         // mapping by thing type
         THING_TYPE_MAPPING.put(THING_TYPE_SHELLY1_STR, THING_TYPE_SHELLY1_STR);
         THING_TYPE_MAPPING.put(THING_TYPE_SHELLY1PM_STR, THING_TYPE_SHELLY1PM_STR);
@@ -385,6 +399,8 @@ public class ShellyThingCreator {
         THING_TYPE_MAPPING.put(THING_TYPE_SHELLYPLUSI4_STR, THING_TYPE_SHELLYPLUSI4_STR);
         THING_TYPE_MAPPING.put(THING_TYPE_SHELLYPLUSHT_STR, THING_TYPE_SHELLYPLUSHT_STR);
         THING_TYPE_MAPPING.put(THING_TYPE_SHELLYPLUSSMOKE_STR, THING_TYPE_SHELLYPLUSSMOKE_STR);
+        THING_TYPE_MAPPING.put(THING_TYPE_SHELLYPLUSDIMMERUS_STR, THING_TYPE_SHELLYPLUSDIMMERUS_STR);
+        THING_TYPE_MAPPING.put(THING_TYPE_SHELLYPLUSWALLDISPLAY_STR, THING_TYPE_SHELLYPLUSWALLDISPLAY_STR);
 
         THING_TYPE_MAPPING.put(THING_TYPE_SHELLYPRO1_STR, THING_TYPE_SHELLYPRO1_STR);
         THING_TYPE_MAPPING.put(THING_TYPE_SHELLYPRO1PM_STR, THING_TYPE_SHELLYPRO1PM_STR);
index 3e6e0a22919d16ba63b613cfdefe5168c0cdb894..bdea3aa76ccddeb00bf2b0854151797c507d43d6 100644 (file)
@@ -20,22 +20,28 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.shelly.internal.api.ShellyApiException;
 import org.openhab.binding.shelly.internal.api.ShellyDeviceProfile;
+import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyRollerStatus;
+import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsDimmer;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsEMeter;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsMeter;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsRelay;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsStatus;
+import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyShortLightStatus;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellyADC;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor.ShellyExtTemperature.ShellyShortTemp;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyThermnostat;
 import org.openhab.binding.shelly.internal.provider.ShellyChannelDefinitions;
+import org.openhab.core.library.types.OnOffType;
 import org.openhab.core.library.types.StringType;
 import org.openhab.core.library.unit.ImperialUnits;
 import org.openhab.core.library.unit.SIUnits;
 import org.openhab.core.library.unit.Units;
 import org.openhab.core.types.UnDefType;
 
+import com.google.gson.Gson;
+
 /***
  * The{@link ShellyComponents} implements updates for supplemental components
  * Meter will be used by Relay + Light; Sensor is part of H&T, Flood, Door Window, Sense
@@ -69,14 +75,12 @@ public class ShellyComponents {
 
         Integer rssi = getInteger(status.wifiSta.rssi);
         thingHandler.updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_RSSI, mapSignalStrength(rssi));
-        if (getDouble(status.temperature) != SHELLY_API_INVTEMP) {
-            if (status.tmp != null && !thingHandler.getProfile().isSensor) {
-                thingHandler.updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_ITEMP,
-                        toQuantityType(getDouble(status.tmp.tC), DIGITS_NONE, SIUnits.CELSIUS));
-            } else if (status.temperature != null) {
-                thingHandler.updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_ITEMP,
-                        toQuantityType(getDouble(status.temperature), DIGITS_NONE, SIUnits.CELSIUS));
-            }
+        if (status.tmp != null && !thingHandler.getProfile().isSensor && status.tmp.tC != SHELLY_API_INVTEMP) {
+            thingHandler.updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_ITEMP,
+                    toQuantityType(getDouble(status.tmp.tC), DIGITS_NONE, SIUnits.CELSIUS));
+        } else if (status.temperature != null && status.temperature != SHELLY_API_INVTEMP) {
+            thingHandler.updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_ITEMP,
+                    toQuantityType(getDouble(status.temperature), DIGITS_NONE, SIUnits.CELSIUS));
         }
         thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_SLEEPTIME,
                 toQuantityType(getInteger(status.sleepTime), Units.SECOND));
@@ -268,8 +272,8 @@ public class ShellyComponents {
                                         .createEMeterChannels(thingHandler.getThing(), profile, emeter, groupName));
                             }
 
-                            // convert Watt/Hour to kw/h
-                            double total = getDouble(emeter.total) / 1000 / 60;
+                            // convert Watt/h to KW/h
+                            double total = getDouble(emeter.total) / 1000;
                             double totalReturned = getDouble(emeter.totalReturned) / 1000;
                             updated |= thingHandler.updateChannel(groupName, CHANNEL_METER_CURRENTWATTS,
                                     toQuantityType(getDouble(emeter.power), DIGITS_WATT, Units.WATT));
@@ -332,7 +336,7 @@ public class ShellyComponents {
                 // convert totalWatts into kw/h
                 totalWatts = totalWatts / (60.0 * 1000.0);
                 updated |= thingHandler.updateChannel(groupName, CHANNEL_METER_CURRENTWATTS,
-                        toQuantityType(getDouble(currentWatts), DIGITS_WATT, Units.WATT));
+                        toQuantityType(currentWatts, DIGITS_WATT, Units.WATT));
                 updated |= thingHandler.updateChannel(groupName, CHANNEL_METER_TOTALKWH,
                         toQuantityType(totalWatts, DIGITS_KWH, Units.KILOWATT_HOUR));
 
@@ -537,6 +541,64 @@ public class ShellyComponents {
         return updated;
     }
 
+    public static boolean updateDimmers(ShellyThingInterface thingHandler, ShellySettingsStatus orgStatus)
+            throws ShellyApiException {
+        boolean updated = false;
+        ShellyDeviceProfile profile = thingHandler.getProfile();
+        if (profile.isDimmer) {
+            // We need to fixup the returned Json: The dimmer returns light[] element, which is ok, but it doesn't have
+            // the same structure as lights[] from Bulb,RGBW2 and Duo. The tag gets replaced by dimmers[] so that Gson
+            // maps to a different structure (ShellyShortLight).
+            Gson gson = new Gson();
+            ShellySettingsStatus dstatus = !profile.isGen2
+                    ? fromJson(gson, Shelly1ApiJsonDTO.fixDimmerJson(orgStatus.json), ShellySettingsStatus.class)
+                    : orgStatus;
+
+            int l = 0;
+            for (ShellyShortLightStatus dimmer : dstatus.dimmers) {
+                Integer r = l + 1;
+                String groupName = profile.numRelays <= 1 ? CHANNEL_GROUP_DIMMER_CONTROL
+                        : CHANNEL_GROUP_DIMMER_CONTROL + r.toString();
+
+                if (!thingHandler.areChannelsCreated()) {
+                    thingHandler.updateChannelDefinitions(ShellyChannelDefinitions
+                            .createDimmerChannels(thingHandler.getThing(), profile, dstatus, l));
+                }
+
+                ShellySettingsDimmer ds = profile.settings.dimmers.get(l);
+                if (ds.name != null) {
+                    updated |= thingHandler.updateChannel(groupName, CHANNEL_OUTPUT_NAME, getStringType(ds.name));
+                }
+
+                // On a status update we map a dimmer.ison = false to brightness 0 rather than the device's brightness
+                // and send an OFF status to the same channel.
+                // When the device's brightness is > 0 we send the new value to the channel and an ON command
+                if (dimmer.ison) {
+                    updated |= thingHandler.updateChannel(groupName, CHANNEL_BRIGHTNESS + "$Switch", OnOffType.ON);
+                    updated |= thingHandler.updateChannel(groupName, CHANNEL_BRIGHTNESS + "$Value",
+                            toQuantityType((double) getInteger(dimmer.brightness), DIGITS_NONE, Units.PERCENT));
+                } else {
+                    updated |= thingHandler.updateChannel(groupName, CHANNEL_BRIGHTNESS + "$Switch", OnOffType.OFF);
+                    updated |= thingHandler.updateChannel(groupName, CHANNEL_BRIGHTNESS + "$Value",
+                            toQuantityType(0.0, DIGITS_NONE, Units.PERCENT));
+                }
+
+                if (profile.settings.dimmers != null) {
+                    ShellySettingsDimmer dsettings = profile.settings.dimmers.get(l);
+                    if (dsettings != null) {
+                        updated |= thingHandler.updateChannel(groupName, CHANNEL_TIMER_AUTOON,
+                                toQuantityType(getDouble(dsettings.autoOn), Units.SECOND));
+                        updated |= thingHandler.updateChannel(groupName, CHANNEL_TIMER_AUTOOFF,
+                                toQuantityType(getDouble(dsettings.autoOff), Units.SECOND));
+                    }
+                }
+
+                l++;
+            }
+        }
+        return updated;
+    }
+
     public static boolean updateTempChannel(@Nullable ShellyShortTemp sensor, ShellyThingInterface thingHandler,
             String channel) {
         return sensor != null ? updateTempChannel(thingHandler, CHANNEL_GROUP_SENSOR, channel, sensor.tC, "") : false;
index 187c1875924c4a6c0bec76e91c49a6c431aeba87..98cbf7ea6d1f526228a43147a0d3409524fb3518 100644 (file)
@@ -28,6 +28,6 @@ public interface ShellyDeviceListener {
     /**
      * This method is called when new device information is received.
      */
-    public boolean onEvent(String ipAddress, String deviceName, String deviceIndex, String eventType,
+    boolean onEvent(String ipAddress, String deviceName, String deviceIndex, String eventType,
             Map<String, String> parameters);
 }
index ca15d5491595da59807d01551f7013517e61a486..ce3895fd67c4e4446ffcd5ad9e3fab224197103d 100644 (file)
@@ -19,9 +19,7 @@ import static org.openhab.binding.shelly.internal.util.ShellyUtils.*;
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jetty.client.HttpClient;
 import org.openhab.binding.shelly.internal.api.ShellyApiException;
-import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyRollerStatus;
-import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsDimmer;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsRelay;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsStatus;
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyShortLightStatus;
@@ -42,8 +40,6 @@ import org.openhab.core.types.Command;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.gson.Gson;
-
 /***
  * The{@link ShellyRelayHandler} handles light (bulb+rgbw2) specific commands and status. All other commands will be
  * handled by the generic thing handler.
@@ -193,7 +189,7 @@ public class ShellyRelayHandler extends ShellyBaseHandler {
         if (brightness > 0) {
             api.setBrightness(lightId, brightness, config.brightnessAutoOn);
         } else {
-            api.setRelayTurn(lightId, power == OnOffType.ON ? SHELLY_API_ON : SHELLY_API_OFF);
+            api.setLightTurn(lightId, power == OnOffType.ON ? SHELLY_API_ON : SHELLY_API_OFF);
             if (brightness >= 0) { // ignore -1
                 updateChannel(CHANNEL_COLOR_WHITE, CHANNEL_BRIGHTNESS + "$Value",
                         toQuantityType((double) (power == OnOffType.ON ? brightness : 0), DIGITS_NONE, Units.PERCENT));
@@ -206,7 +202,7 @@ public class ShellyRelayHandler extends ShellyBaseHandler {
         // map status to channels
         boolean updated = false;
         updated |= updateRelays(status);
-        updated |= updateDimmers(status);
+        updated |= ShellyComponents.updateDimmers(this, status);
         updated |= updateLed(status);
         return updated;
     }
@@ -300,12 +296,6 @@ public class ShellyRelayHandler extends ShellyBaseHandler {
         }
     }
 
-    private void createDimmerChannels(ShellySettingsStatus dstatus, int idx) {
-        if (!areChannelsCreated()) {
-            updateChannelDefinitions(ShellyChannelDefinitions.createDimmerChannels(getThing(), profile, dstatus, idx));
-        }
-    }
-
     private void createRollerChannels(ShellyRollerStatus roller) {
         if (!areChannelsCreated()) {
             updateChannelDefinitions(ShellyChannelDefinitions.createRollerChannels(getThing(), roller));
@@ -356,63 +346,6 @@ public class ShellyRelayHandler extends ShellyBaseHandler {
         return updated;
     }
 
-    /**
-     * Update Relay/Roller channels
-     *
-     * @param th Thing Handler instance
-     * @param profile ShellyDeviceProfile
-     * @param status Last ShellySettingsStatus
-     *
-     * @throws ShellyApiException
-     */
-    public boolean updateDimmers(ShellySettingsStatus orgStatus) throws ShellyApiException {
-        boolean updated = false;
-        if (profile.isDimmer) {
-            // We need to fixup the returned Json: The dimmer returns light[] element, which is ok, but it doesn't have
-            // the same structure as lights[] from Bulb,RGBW2 and Duo. The tag gets replaced by dimmers[] so that Gson
-            // maps to a different structure (ShellyShortLight).
-            Gson gson = new Gson();
-            ShellySettingsStatus dstatus = fromJson(gson, Shelly1ApiJsonDTO.fixDimmerJson(orgStatus.json),
-                    ShellySettingsStatus.class);
-
-            logger.trace("{}: Updating {} dimmers(s)", thingName, dstatus.dimmers.size());
-            int l = 0;
-            for (ShellyShortLightStatus dimmer : dstatus.dimmers) {
-                Integer r = l + 1;
-                String groupName = profile.numRelays <= 1 ? CHANNEL_GROUP_DIMMER_CONTROL
-                        : CHANNEL_GROUP_DIMMER_CONTROL + r.toString();
-
-                createDimmerChannels(dstatus, l);
-
-                // On a status update we map a dimmer.ison = false to brightness 0 rather than the device's brightness
-                // and send an OFF status to the same channel.
-                // When the device's brightness is > 0 we send the new value to the channel and an ON command
-                if (dimmer.ison) {
-                    updated |= updateChannel(groupName, CHANNEL_BRIGHTNESS + "$Switch", OnOffType.ON);
-                    updated |= updateChannel(groupName, CHANNEL_BRIGHTNESS + "$Value",
-                            toQuantityType((double) getInteger(dimmer.brightness), DIGITS_NONE, Units.PERCENT));
-                } else {
-                    updated |= updateChannel(groupName, CHANNEL_BRIGHTNESS + "$Switch", OnOffType.OFF);
-                    updated |= updateChannel(groupName, CHANNEL_BRIGHTNESS + "$Value",
-                            toQuantityType(0.0, DIGITS_NONE, Units.PERCENT));
-                }
-
-                if (profile.settings.dimmers != null) {
-                    ShellySettingsDimmer dsettings = profile.settings.dimmers.get(l);
-                    if (dsettings != null) {
-                        updated |= updateChannel(groupName, CHANNEL_TIMER_AUTOON,
-                                toQuantityType(getDouble(dsettings.autoOn), Units.SECOND));
-                        updated |= updateChannel(groupName, CHANNEL_TIMER_AUTOOFF,
-                                toQuantityType(getDouble(dsettings.autoOff), Units.SECOND));
-                    }
-                }
-
-                l++;
-            }
-        }
-        return updated;
-    }
-
     /**
      * Update LED channels
      *
index 2285f66f2cb37812818902a16b30f3fa5226b8f2..5483b0ff1cf271d46987c52667a0eac3fec790fd 100644 (file)
@@ -39,85 +39,86 @@ import org.openhab.core.types.StateOption;
 @NonNullByDefault
 public interface ShellyThingInterface {
 
-    public ShellyDeviceProfile getProfile(boolean forceRefresh) throws ShellyApiException;
+    ShellyDeviceProfile getProfile(boolean forceRefresh) throws ShellyApiException;
 
-    public @Nullable List<StateOption> getStateOptions(ChannelTypeUID uid);
+    @Nullable
+    List<StateOption> getStateOptions(ChannelTypeUID uid);
 
-    public double getChannelDouble(String group, String channel);
+    double getChannelDouble(String group, String channel);
 
-    public boolean updateChannel(String group, String channel, State value);
+    boolean updateChannel(String group, String channel, State value);
 
-    public boolean updateChannel(String channelId, State value, boolean force);
+    boolean updateChannel(String channelId, State value, boolean force);
 
-    public void setThingOnline();
+    void setThingOnline();
 
-    public void setThingOffline(ThingStatusDetail detail, String messageKey, Object... arguments);
+    void setThingOffline(ThingStatusDetail detail, String messageKey, Object... arguments);
 
-    public boolean isStopping();
+    boolean isStopping();
 
-    public String getThingType();
+    String getThingType();
 
-    public ThingStatus getThingStatus();
+    ThingStatus getThingStatus();
 
-    public ThingStatusDetail getThingStatusDetail();
+    ThingStatusDetail getThingStatusDetail();
 
-    public boolean isThingOnline();
+    boolean isThingOnline();
 
-    public boolean requestUpdates(int requestCount, boolean refreshSettings);
+    boolean requestUpdates(int requestCount, boolean refreshSettings);
 
-    public void triggerUpdateFromCoap();
+    void triggerUpdateFromCoap();
 
-    public void reinitializeThing();
+    void reinitializeThing();
 
-    public void restartWatchdog();
+    void restartWatchdog();
 
-    public void publishState(String channelId, State value);
+    void publishState(String channelId, State value);
 
-    public boolean areChannelsCreated();
+    boolean areChannelsCreated();
 
-    public State getChannelValue(String group, String channel);
+    State getChannelValue(String group, String channel);
 
-    public boolean updateInputs(ShellySettingsStatus status);
+    boolean updateInputs(ShellySettingsStatus status);
 
-    public void updateChannelDefinitions(Map<String, Channel> dynChannels);
+    void updateChannelDefinitions(Map<String, Channel> dynChannels);
 
-    public void postEvent(String event, boolean force);
+    void postEvent(String event, boolean force);
 
-    public void triggerChannel(String group, String channelID, String event);
+    void triggerChannel(String group, String channelID, String event);
 
-    public void triggerButton(String group, int idx, String value);
+    void triggerButton(String group, int idx, String value);
 
-    public ShellyDeviceStats getStats();
+    ShellyDeviceStats getStats();
 
-    public void resetStats();
+    void resetStats();
 
-    public Thing getThing();
+    Thing getThing();
 
-    public String getThingName();
+    String getThingName();
 
-    public ShellyThingConfiguration getThingConfig();
+    ShellyThingConfiguration getThingConfig();
 
-    public HttpClient getHttpClient();
+    HttpClient getHttpClient();
 
-    public String getProperty(String key);
+    String getProperty(String key);
 
-    public void updateProperties(String key, String value);
+    void updateProperties(String key, String value);
 
-    public boolean updateWakeupReason(@Nullable List<Object> valueArray);
+    boolean updateWakeupReason(@Nullable List<Object> valueArray);
 
-    public ShellyApiInterface getApi();
+    ShellyApiInterface getApi();
 
-    public ShellyDeviceProfile getProfile();
+    ShellyDeviceProfile getProfile();
 
-    public long getScheduledUpdates();
+    long getScheduledUpdates();
 
-    public void fillDeviceStatus(ShellySettingsStatus status, boolean updated);
+    void fillDeviceStatus(ShellySettingsStatus status, boolean updated);
 
-    public boolean checkRepresentation(String key);
+    boolean checkRepresentation(String key);
 
-    public void incProtMessages();
+    void incProtMessages();
 
-    public void incProtErrors();
+    void incProtErrors();
 
-    public void startScan();
+    void startScan();
 }
index 71dfe33d4cf6dee65f452c144544b9eeb84ba4d1..94ee502781e7f8a2247717908679bc28db4f06dd 100644 (file)
@@ -78,7 +78,7 @@ public class ShellyChannelDefinitions {
     public static final String ITEMT_POWER = "Number:Power";
     public static final String ITEMT_ENERGY = "Number:Energy";
     public static final String ITEMT_VOLT = "Number:ElectricPotential";
-    public static final String ITEMT_AMP = "Number:ElectricPotential";
+    public static final String ITEMT_AMP = "Number:ElectricCurrent";
     public static final String ITEMT_ANGLE = "Number:Angle";
     public static final String ITEMT_DISTANCE = "Number:Length";
     public static final String ITEMT_SPEED = "Number:Speed";
@@ -129,8 +129,8 @@ public class ShellyChannelDefinitions {
                 .add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_ITEMP, "deviceTemp", ITEMT_TEMP))
                 .add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_WAKEUP, "sensorWakeup", ITEMT_STRING))
                 .add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_ACCUWATTS, "meterAccuWatts", ITEMT_POWER))
-                .add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_ACCUTOTAL, "meterAccuTotal", ITEMT_POWER))
-                .add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_ACCURETURNED, "meterAccuReturned", ITEMT_POWER))
+                .add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_ACCUTOTAL, "meterAccuTotal", ITEMT_ENERGY))
+                .add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_ACCURETURNED, "meterAccuReturned", ITEMT_ENERGY))
                 .add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_VOLTAGE, "supplyVoltage", ITEMT_VOLT))
                 .add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_CHARGER, "charger", ITEMT_SWITCH))
                 .add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_LED_STATUS_DISABLE, "ledStatusDisable", ITEMT_SWITCH))
@@ -191,7 +191,7 @@ public class ShellyChannelDefinitions {
                 // Power Meter
                 .add(new ShellyChannel(m, CHGR_METER, CHANNEL_METER_CURRENTWATTS, "meterWatts", ITEMT_POWER))
                 .add(new ShellyChannel(m, CHGR_METER, CHANNEL_METER_TOTALKWH, "meterTotal", ITEMT_ENERGY))
-                .add(new ShellyChannel(m, CHGR_METER, CHANNEL_METER_LASTMIN1, "lastPower1", ITEMT_ENERGY))
+                .add(new ShellyChannel(m, CHGR_METER, CHANNEL_METER_LASTMIN1, "lastPower1", ITEMT_POWER))
                 .add(new ShellyChannel(m, CHGR_METER, CHANNEL_LAST_UPDATE, "lastUpdate", ITEMT_DATETIME))
 
                 // EMeter
@@ -215,7 +215,7 @@ public class ShellyChannelDefinitions {
                 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_MOTION, "sensorMotion", ITEMT_SWITCH))
                 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_MOTION_TS, "motionTimestamp", ITEMT_DATETIME))
                 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_MOTION_ACT, "motionActive", ITEMT_SWITCH))
-                .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_VIBRATION, "vibration", ITEMT_SWITCH))
+                .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_VIBRATION, "sensorVibration", ITEMT_SWITCH))
                 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_FLOOD, "sensorFlood", ITEMT_SWITCH))
                 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_SMOKE, "sensorSmoke", ITEMT_SWITCH))
                 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_MUTE, "sensorMute", ITEMT_SWITCH))
@@ -304,13 +304,14 @@ public class ShellyChannelDefinitions {
                 && ((status.temperature != null && getDouble(status.temperature) != SHELLY_API_INVTEMP)
                         || (status.tmp != null && getDouble(status.tmp.tC) != SHELLY_API_INVTEMP))) {
             // Only some devices report the internal device temp
-            addChannel(thing, add, status.tmp != null || status.temperature != null, CHGR_DEVST, CHANNEL_DEVST_ITEMP);
+            addChannel(thing, add,
+                    !profile.isLight && (status.temperature != null || (status.tmp != null && !profile.isSensor)),
+                    CHGR_DEVST, CHANNEL_DEVST_ITEMP);
         }
         addChannel(thing, add, profile.settings.sleepTime != null, CHGR_SENSOR, CHANNEL_SENSOR_SLEEPTIME);
 
         // If device has more than 1 meter the channel accumulatedWatts receives the accumulated value
-        boolean accuChannel = (((status.meters != null) && (status.meters.size() > 1) && !profile.isRoller
-                && !profile.isRGBW2) || ((status.emeters != null && status.emeters.size() > 1)));
+        boolean accuChannel = profile.numMeters > 1 && !profile.isRoller && !profile.isRGBW2;
         addChannel(thing, add, accuChannel, CHGR_DEVST, CHANNEL_DEVST_ACCUWATTS);
         addChannel(thing, add, accuChannel, CHGR_DEVST, CHANNEL_DEVST_ACCUTOTAL);
         addChannel(thing, add, accuChannel && (status.emeters != null), CHGR_DEVST, CHANNEL_DEVST_ACCURETURNED);
@@ -350,9 +351,11 @@ public class ShellyChannelDefinitions {
         }
 
         // Shelly 1/1PM and Plus 1/1PM Addon
-        if (profile.settings.extSwitch != null && profile.settings.extSwitch.input0 != null
-                && idx == getInteger(profile.settings.extSwitch.input0.relayNum)) {
-            addChannel(thing, add, true, CHGR_SENSOR, CHANNEL_ESENSOR_INPUT + (idx + 1));
+        boolean addon = profile.settings.extSwitch != null && profile.settings.extSwitch.input0 != null
+                && idx == getInteger(profile.settings.extSwitch.input0.relayNum);
+        if (addon) {
+            addChannel(thing, add, addon, CHGR_SENSOR,
+                    CHANNEL_ESENSOR_INPUT + (profile.settings.extSwitch.input0.relayNum + 1));
         }
         if (profile.status.extTemperature != null) {
             addChannel(thing, add, profile.status.extTemperature.sensor1 != null, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP1);
@@ -361,7 +364,8 @@ public class ShellyChannelDefinitions {
             addChannel(thing, add, profile.status.extTemperature.sensor4 != null, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP4);
             addChannel(thing, add, profile.status.extTemperature.sensor5 != null, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP5);
         }
-        addChannel(thing, add, profile.status.extHumidity != null, CHGR_SENSOR, CHANNEL_ESENSOR_HUMIDITY);
+        addChannel(thing, add, profile.status.extHumidity != null && profile.status.extHumidity.sensor1 != null,
+                CHGR_SENSOR, CHANNEL_ESENSOR_HUMIDITY);
         addChannel(thing, add, profile.status.extVoltage != null, CHGR_SENSOR, CHANNEL_ESENSOR_VOLTAGE);
         addChannel(thing, add, profile.status.extDigitalInput != null, CHGR_SENSOR, CHANNEL_ESENSOR_DIGITALINPUT);
         addChannel(thing, add, profile.status.extAnalogInput != null, CHGR_SENSOR, CHANNEL_ESENSOR_ANALOGINPUT);
@@ -379,6 +383,7 @@ public class ShellyChannelDefinitions {
 
         if (profile.settings.dimmers != null) {
             ShellySettingsDimmer ds = profile.settings.dimmers.get(idx);
+            addChannel(thing, add, ds.name != null, group, CHANNEL_OUTPUT_NAME);
             addChannel(thing, add, ds.autoOn != null, group, CHANNEL_TIMER_AUTOON);
             addChannel(thing, add, ds.autoOff != null, group, CHANNEL_TIMER_AUTOOFF);
             ShellyShortLightStatus dss = dstatus.dimmers.get(idx);
@@ -473,7 +478,7 @@ public class ShellyChannelDefinitions {
         addChannel(thing, newChannels, emeter.voltage != null, group, CHANNEL_EMETER_VOLTAGE);
         addChannel(thing, newChannels, emeter.current != null, group, CHANNEL_EMETER_CURRENT);
         addChannel(thing, newChannels, emeter.pf != null, group, CHANNEL_EMETER_PFACTOR); // EM has no PF. but power
-        addChannel(thing, newChannels, emeter.total != null && profile.numMeters > 1, group, CHANNEL_EMETER_RESETTOTAL); // 3EM
+        addChannel(thing, newChannels, profile.is3EM, group, CHANNEL_EMETER_RESETTOTAL); // 3EM
         addChannel(thing, newChannels, true, group, CHANNEL_LAST_UPDATE);
         return newChannels;
     }
@@ -505,7 +510,8 @@ public class ShellyChannelDefinitions {
             addChannel(thing, newChannels, sdata.sensor.vibration != null, CHANNEL_GROUP_SENSOR,
                     CHANNEL_SENSOR_VIBRATION);
         }
-        if (sdata.accel != null) { // DW2
+        // Create tilt for DW/DW2, for BLU DW create channel even tilt is currently not reported
+        if (sdata.accel != null || (profile.isBlu && sdata.lux != null)) {
             addChannel(thing, newChannels, sdata.accel.tilt != null, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_TILT);
         }
 
index bdc569513e71b2d493a088b3e45b748456128af7..bc212f828b2bb6eb3fb21148e087ebed5172c719 100644 (file)
                        <advanced>true</advanced>
                </parameter>
        </config-description>
+
+       <config-description uri="thing-type:shelly:dimmer-gen2">
+               <parameter name="deviceIp" type="text" required="true">
+                       <label>@text/thing-type.config.shelly.deviceIp.label</label>
+                       <description>@text/thing-type.config.shelly.deviceIp.description</description>
+                       <context>network-address</context>
+               </parameter>
+               <parameter name="userId" type="text" required="false">
+                       <label>@text/thing-type.config.shelly.userId.label</label>
+                       <description>@text/thing-type.config.shelly.userId.description</description>
+               </parameter>
+               <parameter name="password" type="text" required="false">
+                       <label>@text/thing-type.config.shelly.password.label</label>
+                       <description>@text/thing-type.config.shelly.password.description</description>
+                       <context>password</context>
+               </parameter>
+               <parameter name="brightnessAutoOn" type="boolean" required="false">
+                       <label>@text/thing-type.config.shelly.light.brightnessAutoOn.label</label>
+                       <description>@text/thing-type.config.shelly.light.brightnessAutoOn.description</description>
+                       <default>true</default>
+               </parameter>
+               <parameter name="updateInterval" type="integer" min="10" required="true" unit="s">
+                       <label>@text/thing-type.config.shelly.updateInterval.label</label>
+                       <description>@text/thing-type.config.shelly.updateInterval.description</description>
+                       <default>60</default>
+                       <unitLabel>seconds</unitLabel>
+                       <advanced>true</advanced>
+               </parameter>
+       </config-description>
 </config-description:config-descriptions>
index 94d969f5a7e452041a985ba3cdfc24831f286460..ba3a492064a484e62c21e269be9327de671a73e8 100644 (file)
@@ -88,6 +88,22 @@ thing-type.shelly.shellytrv.description = Shelly TRV (Radiator value, battery po
 thing-type.shelly.shellyix3.description = Shelly ix3 (Activation Device with 3 inputs)
 thing-type.shelly.shellypludht.description = Shelly Plus HT - Temperature and Humidity Sensor
 
+# Plus Devices
+thing-type.shelly.shellyplus1.description = Shelly Plus 1 (Single Relay Switch)
+thing-type.shelly.shellyplus1pm.description =  Shelly Plus 1PM - Single Relay Switch with Power Meter
+thing-type.shelly.shellyplus2-relay.description = Shelly Plus 2PM - Dual Relay Switch with Power Meter
+thing-type.shelly.shellyplus2pm-roller.description = Shelly Plus 2PM - Roller Control with Power Meter
+thing-type.shelly.shellyplusplug.description = Shelly Plus Plug S/IT/UK/US . Outlet with Power Meter
+thing-type.shelly.shellyplusi4.description = Shelly Plus i4 - 4xInput Device
+thing-type.shelly.shellyplusi4dc.description = Shelly Plus i4DC - 4xDC Input Device
+thing-type.shelly.shellyplusht.description = Shelly Plus HT - Humidity and Temperature sensor with display
+thing-type.shelly.shellyplussmoke.description = Shelly Plus Smoke - Smoke Detector with Alarm
+thing-type.shelly.shellyplussmoke.description = Shelly Plus Smoke - Smoke Detector with Alarm
+thing-type.shelly.shellypluswdus.description = Shelly Wall Dimmer US Device
+
+# Wall displays
+thing-type.shelly.shellywalldisplay.description = Shelly Plus Wall Display with sensors and input/output
+
 # Pro Devices
 thing-type.shelly.shellypro1.description = Shelly Pro 1 - Single Relay Switch
 thing-type.shelly.shellypro1pm.description = Shelly Pro 1PM - Single Relay Switch with Power Meter
@@ -97,31 +113,10 @@ thing-type.shelly.shellypro2pm-roller.description = Shelly Pro 2PM - Roller Cont
 thing-type.shelly.shellypro3.description = Shelly Pro 3 - 3xRelay Switch
 thing-type.shelly.shellypro3em.description = Shelly Pro 3EM - 3xPower Meter
 thing-type.shelly.shellypro4pm.description = Shelly Pro 4PM - 4xRelay Switch with Power Meter
-
-# Plus devices
- thing-type.shelly.shellyplus1.description = Shelly Plus 1 (Single Relay Switch)
- thing-type.shelly.shellyplus1pm.description =  Shelly Plus 1PM - Single Relay Switch with Power Meter
- thing-type.shelly.shellyplus2-relay.description = Shelly Plus 2PM - Dual Relay Switch with Power Meter
- thing-type.shelly.shellyplus2pm-roller.description = Shelly Plus 2PM - Roller Control with Power Meter
- thing-type.shelly.shellyplusplug.description = Shelly Plus Plug S/IT/UK/US . Outlet with Power Meter
- thing-type.shelly.shellyplusht.description = Shelly Plus HT - Humidity and Temperature sensor with display
- thing-type.shelly.shellyplussmoke.description = Shelly Plus Smoke - Smoke Detector with Alarm
- thing-type.shelly.shellyplusi4.description = Shelly Plus i4 - 4xInput Device
- thing-type.shelly.shellyplusi4dc.description = Shelly Plus i4DC - 4xDC Input Device
- # Pro devices
- thing-type.shelly.shellypro1.description = Shelly Pro 1 - Single Relay Switch
- thing-type.shelly.shellypro1pm.description = Shelly Pro 1PM - Single Relay Switch with Power Meter
- thing-type.shelly.shellypro2-relay.description = Shelly Pro 2 - Dual Relay Switch
- thing-type.shelly.shellypro2-roller.description = Shelly Pro 2 - Roller Control
- thing-type.shelly.shellypro2pm-relay.description= Shelly Pro 2PM - Dual Relay Switch with Power Meter
- thing-type.shelly.shellypro2pm-roller.description = Shelly Pro 2PM - Roller Control with Power Meter
- thing-type.shelly.shellypro3.description = Shelly Pro 3 - 3xRelay Switch
- thing-type.shelly.shellypro4pm.description = Shelly Pro 4PM - 4xRelay Switch with Power Meter
  
- # BLU devices
- thing-type.shelly.shellypblubutton.description = Shelly BLU Button
- thing-type.shelly.shellybludw.description = Shelly BLU Door/Window Sensor
+# BLU devices
+thing-type.shelly.shellypblubutton.description = Shelly BLU Button
+thing-type.shelly.shellybludw.description = Shelly BLU Door/Window Sensor
  
 # thing config - shellydevice
 thing-type.config.shelly.deviceIp.label = IP Address
index e7e5e13ef92db3ee8bb1908ca8d43a4dc835eeb7..ee99d012969789807394ed57519c3d5ca599888f 100644 (file)
                <category>Energy</category>
                <tags>
                        <tag>Measurement</tag>
-                       <tag>Current</tag>
+                       <tag>Power</tag>
                </tags>
                <state readOnly="true" pattern="%.2f %unit%">
                </state>
                <label>@text/channel-type.shelly.meterAccuWatts.label</label>
                <description>@text/channel-type.shelly.meterAccuWatts.description</description>
                <category>Energy</category>
+               <tags>
+                       <tag>Measurement</tag>
+                       <tag>Power</tag>
+               </tags>
                <state readOnly="true" pattern="%.2f %unit%">
                </state>
        </channel-type>
 
        <channel-type id="meterAccuTotal" advanced="true">
-               <item-type>Number:Power</item-type>
+               <item-type>Number:Energy</item-type>
                <label>@text/channel-type.shelly.meterAccuTotal.label</label>
                <description>@text/channel-type.shelly.meterAccuTotal.description</description>
                <category>Energy</category>
+               <tags>
+                       <tag>Measurement</tag>
+                       <tag>Energy</tag>
+               </tags>
                <state readOnly="true" pattern="%.3f %unit%">
                </state>
        </channel-type>
 
        <channel-type id="meterAccuReturned" advanced="true">
-               <item-type>Number:Power</item-type>
+               <item-type>Number:Energy</item-type>
                <label>@text/channel-type.shelly.meterAccuReturned.label</label>
                <description>@text/channel-type.shelly.meterAccuReturned.description</description>
                <category>Energy</category>
+               <tags>
+                       <tag>Measurement</tag>
+                       <tag>Energy</tag>
+               </tags>
                <state readOnly="true" pattern="%.3f %unit%">
                </state>
        </channel-type>
        </channel-type>
 
        <channel-type id="lastPower1" advanced="true">
-               <item-type>Number:Energy</item-type>
+               <item-type>Number:Power</item-type>
                <label>@text/channel-type.shelly.lastPower1.label</label>
                <description>@text/channel-type.shelly.lastPower1.description</description>
                <category>Energy</category>
+               <tags>
+                       <tag>Measurement</tag>
+                       <tag>Power</tag>
+               </tags>
                <state readOnly="true" pattern="%.3f %unit%">
                </state>
        </channel-type>
                <item-type>Number:Energy</item-type>
                <label>@text/channel-type.shelly.meterTotal.label</label>
                <description>@text/channel-type.shelly.meterTotal.description</description>
-               <category>Energy</category>
                <state readOnly="true" pattern="%.3f %unit%">
                </state>
        </channel-type>
                <label>@text/channel-type.shelly.meterReturned.label</label>
                <description>@text/channel-type.shelly.meterReturned.description</description>
                <category>Energy</category>
+               <tags>
+                       <tag>Measurement</tag>
+                       <tag>Energy</tag>
+               </tags>
                <state readOnly="true" pattern="%.3f %unit%">
                </state>
        </channel-type>
                <item-type>Number:ElectricPotential</item-type>
                <label>@text/channel-type.shelly.meterVoltage.label</label>
                <description>@text/channel-type.shelly.meterVoltage.description</description>
+               <category>Energy</category>
                <tags>
                        <tag>Measurement</tag>
                        <tag>Voltage</tag>
        </channel-type>
 
        <channel-type id="meterCurrent">
-               <item-type>Number:ElectricPotential</item-type>
+               <item-type>Number:ElectricCurrent</item-type>
                <label>@text/channel-type.shelly.meterCurrent.label</label>
                <description>@text/channel-type.shelly.meterCurrent.description</description>
                <category>Energy</category>
                <tags>
                        <tag>Measurement</tag>
-                       <tag>Power</tag>
+                       <tag>Current</tag>
                </tags>
                <state readOnly="true" pattern="%.3f %unit%">
                </state>
index d98a8440bca7cda31913630d9b59b060dbd8a923..51722ee74ab36cd6644310cc18de5937e95b0806 100644 (file)
                <config-description-ref uri="thing-type:shelly:relay-gen2"/>
        </thing-type>
 
+       <thing-type id="shellypluswdus">
+               <label>Shelly Plus Dimmer US</label>
+               <description>@text/thing-type.shelly.shellypluswdus.description</description>
+               <category>DimmableLight</category>
+               <channel-groups>
+                       <channel-group id="relay" typeId="dimmerChannel"/>
+                       <channel-group id="meter" typeId="meter"/>
+                       <channel-group id="device" typeId="deviceStatus"/>
+               </channel-groups>
+
+               <representation-property>serviceName</representation-property>
+               <config-description-ref uri="thing-type:shelly:dimmer-gen2"/>
+       </thing-type>
+
 </thing:thing-descriptions>
index 3b3384b2816c9e67256944d2546dbb76fb205d44..482379537fef94dc606c46db499003bd974318a5 100644 (file)
                <config-description-ref uri="thing-type:shelly:battery-gen2"/>
        </thing-type>
 
+       <thing-type id="shellywalldisplay">
+               <label>Shelly Wall Display</label>
+               <description>@text/thing-type.shelly.shellywalldisplay.description</description>
+               <category>Sensor</category>
+               <channel-groups>
+                       <channel-group id="sensors" typeId="sensorData"/>
+                       <channel-group id="device" typeId="deviceStatus"/>
+               </channel-groups>
+
+               <representation-property>serviceName</representation-property>
+               <config-description-ref uri="thing-type:shelly:relay-gen2"/>
+       </thing-type>
 </thing:thing-descriptions>
index a7b73899f88ba9f131d652941f1850c64a80b31a..c02dbc95320806f3a1606d8d0fe802d2c3945027 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * This script uses the BLE scan functionality in scripting to pass scan reults to openHAB
  * Supported BLU Devices: SBBT , SBDW
+ * Version 0.2
  */
 
 let ALLTERCO_DEVICE_NAME_PREFIX = ["SBBT", "SBDW"];
@@ -147,21 +148,11 @@ function scanCB(ev, res) {
   }
 }
 
-// retry several times to start the scanner if script was started before
-// BLE infrastructure was up in the Shelly
-function startBLEScan() {
-  let bleScanSuccess = BLE.Scanner.Start({ duration_ms: SCAN_DURATION, active: true }, scanCB);
-  if( bleScanSuccess === false ) {
-    Timer.set(1000, false, startBLEScan);
-  } else {
-    console.log('Success: OH-BLU Event Gateway running');
-  }
-}
-
 let BLEConfig = Shelly.getComponentConfig('ble');
 if(BLEConfig.enable === false) {
-  console.log('Error: BLE not enabled');
+  console.log('Error: BLE not enabled, unable to start OH-BLU Scanner');
 } else {
-  Timer.set(1000, false, startBLEScan);
+    BLE.Scanner.Start({ duration_ms: SCAN_DURATION, active: true }, scanCB);
+    console.log('OH-BLU Event Gateway running');
 }
-  
\ No newline at end of file
\ No newline at end of file