]> git.basschouten.com Git - openhab-addons.git/commitdiff
[shelly] Support for Plus Smoke, Plus Plug-S/IT/UK/US, Plus Dimmer US, Pro 3EM; ...
authorMarkus Michels <markus7017@gmail.com>
Wed, 24 May 2023 12:20:11 +0000 (14:20 +0200)
committerGitHub <noreply@github.com>
Wed, 24 May 2023 12:20:11 +0000 (14:20 +0200)
* support for Pro 3EM (WIP)
* Support for Plug-S and Smoke added
* new channel resetTotals for emeters, new channel sensor#mute for Smoke
* Validate Temp reported by CoAP before updating channel, ignore 999
* Support device temp for Pro3, fix emeter.current rouding on 1 instead of
3 deciaml digits, check for reinit before executing channel command,
avoid NPE in Shelly Manaher
* Fix NPE in Shelly Manager with Plus/Pro devices (not having all Gen1
settings initialized)
* Avoid NPE if device time is not set; check thing stopping state to
prevent "handler already disposed"

Signed-off-by: Markus Michels <markus7017@gmail.com>
25 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/ShellyApiInterface.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/Shelly1CoIoTProtocol.java
bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1CoIoTVersion2.java
bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1CoapHandler.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/discovery/ShellyThingCreator.java
bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyBaseHandler.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/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/manager/ShellyManagerActionPage.java
bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/provider/ShellyChannelDefinitions.java
bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/util/ShellyUtils.java
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/shellyGen1_sensor.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

index 84a2e72e1ccd0172806aee566092e13a06201148..b00cb97aa37f42fa97c91ea8aa3fe1dbc9a443c3 100644 (file)
@@ -76,27 +76,33 @@ The binding provides the same feature set across all devices as good as possible
 
 ### Generation 2 Plus series
 
-| thing-type           | Model                                                    | Vendor ID     |
-| -------------------- | -------------------------------------------------------- | ------------- |
-| shellyplus1          | Shelly Plus 1 with 1x relay                              | SNSW-001X16EU |
-| shellyplus1pm        | Shelly Plus 1PM with 1x relay + power meter              | SNSW-001P16EU |
-| shellyplus2pm-relay  | Shelly Plus 2PM with 2x relay + power meter, relay mode  | SNSW-002P16EU |
-| shellyplus2pm-roller | Shelly Plus 2PM with 2x relay + power meter, roller mode | SNSW-002P16EU |
-| shellyplusi4         | Shelly Plus i4 with 4x AC input                          | SNSN-0024X    |
-| shellyplusi4dc       | Shelly Plus i4 with 4x DC input                          | SNSN-0D24X    |
-| shellyplusht         | Shelly Plus HT with temperature + humidity sensor        | SNSN-0013A    |
+| thing-type           | Model                                                    | Vendor ID                                     |
+| -------------------- | -------------------------------------------------------- | --------------------------------------------- |
+| shellyplus1          | Shelly Plus 1 with 1x relay                              | SNSW-001X16EU                                 |
+| shellyplus1pm        | Shelly Plus 1PM with 1x relay + power meter              | SNSW-001P16EU                                 |
+| shellyplus2pm-relay  | Shelly Plus 2PM with 2x relay + power meter, relay mode  | SNSW-002P16EU, SNSW-102P16EU                  |
+| shellyplus2pm-roller | Shelly Plus 2PM with 2x relay + power meter, roller mode | SNSW-002P16EU, SNSW-102P16EU                  |
+| shellyplusplug       | Shelly Plug-S                                            | SNPL-00112EU                                  |
+| shellyplusplug       | Shelly Plug-IT                                           | SNPL-00110IT                                  |
+| shellyplusplug       | Shelly Plug-UK                                           | SNPL-00112UK                                  |
+| shellyplusplug       | Shelly Plug-US                                           | SNPL-00116US                                  |
+| shellyplusi4         | Shelly Plus i4 with 4x AC input                          | SNSN-0024X                                    |
+| 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                                    |
 
 ### Generation 2 Pro series
 
-| thing-type          | Model                                                    | Vendor ID      |
-| ------------------- | -------------------------------------------------------- | -------------- |
-| shellypro1          | Shelly Pro 1 with 1x relay                               | SPSW-001XE16EU |
-| shellypro1pm        | Shelly Pro 1 PM with 1x relay + power meter              | SPSW-001PE16EU |
-| shellypro2-relay    | Shelly Pro 2 with 2x relay, relay mode                   | SPSW-002XE16EU |
-| shellypro2pm-relay  | Shelly Pro 2 PM with 2x relay + power meter, relay mode  | SPSW-002PE16EU |
-| shellypro2pm-roller | Shelly Pro 2 PM with 2x relay + power meter, roller mode | SPSW-002PE16EU |
-| shellypro3          | Shelly Pro 3 with 3x relay (dry contacts)                | SPSW-003XE16EU |
-| shellypro4pm        | Shelly Pro 4 PM with 4x relay + power meter              | SPSW-004PE16EU |
+| thing-type          | Model                                                    | Vendor ID                                      |
+| ------------------- | -------------------------------------------------------- | ---------------------------------------------- |
+| shellypro1          | Shelly Pro 1 with 1x relay                               | SPSW-001XE16EU, SPSW-101XE16EU, SPSW-201XE16EU |
+| shellypro1pm        | Shelly Pro 1 PM with 1x relay + power meter              | SPSW-001PE16EU, SPSW-101PE16EU, SPSW-201PE16EU |
+| shellypro2-relay    | Shelly Pro 2 with 2x relay, relay mode                   | SPSW-002XE16EU, SPSW-102XE16EU, SPSW-202XE16EU |
+| shellypro2pm-relay  | Shelly Pro 2 PM with 2x relay + power meter, relay mode  | SPSW-002PE16EU, SPSW-102PE16EU, SPSW-202PE16EU |
+| shellypro2pm-roller | Shelly Pro 2 PM with 2x relay + power meter, roller mode | SPSW-002PE16EU, SPSW-102PE16EU, SPSW-202PE16EU |
+| shellypro3          | Shelly Pro 3 with 3x relay (dry contacts)                | SPSW-003XE16EU                                 |
+| shellypro3em        | Shelly Pro 3 with 3 integrated power meters              | SPEM-003CEBEU                                  |
+| shellypro4pm        | Shelly Pro 4 PM with 4x relay + power meter              | SPSW-004PE16EU, SPSW-104PE16EU                 |
 
 ## Binding Configuration
 
@@ -374,7 +380,7 @@ A new alarm will be triggered on a new condition or every 5 minutes if the condi
 | TEMP_OVER  | Above "temperature over" threshold                                                               |
 | VIBRATION  | A vibration/tamper was detected (DW2 only)                                                       |
 
-Refer to section [Full Example:shelly.rules](#shellyrules) for examples how to catch alarm triggers in openHAB rules
+Refer to section [Full Example](#full-example) for examples how to catch alarm triggers in openHAB rules
 
 ## Channels
 
@@ -498,6 +504,7 @@ The Thing id is derived from the service name, so that's the reason why the Thin
 |        | voltage       | Number   | yes       | RMS voltage, Volts                                                                |
 |        | current       | Number   | yes       | Current in A                                                                      |
 |        | powerFactor   | Number   | yes       | Power Factor in percent                                                           |
+|        | resetTotals   | Switch   | yes       | ON: Resets total values for the power meter                                       |
 |        | lastUpdate    | DateTime | yes       | Timestamp of the last measurement                                                 |
 | meter2 | currentWatts  | Number   | yes       | Current power consumption in Watts                                                |
 |        | totalKWH      | Number   | yes       | Total energy consumption in kwh since the device powered up (resets on restart)   |
@@ -506,6 +513,7 @@ The Thing id is derived from the service name, so that's the reason why the Thin
 |        | voltage       | Number   | yes       | RMS voltage, Volts                                                                |
 |        | current       | Number   | yes       | Current in A                                                                      |
 |        | powerFactor   | Number   | yes       | Power Factor in percent                                                           |
+|        | resetTotals   | Switch   | yes       | ON: Resets total values for the power meter                                       |
 |        | lastUpdate    | DateTime | yes       | Timestamp of the last measurement                                                 |
 | meter3 | currentWatts  | Number   | yes       | Current power consumption in Watts                                                |
 |        | totalKWH      | Number   | yes       | Total energy consumption in kwh since the device powered up (resets on restart)   |
@@ -514,6 +522,7 @@ The Thing id is derived from the service name, so that's the reason why the Thin
 |        | voltage       | Number   | yes       | RMS voltage, Volts                                                                |
 |        | current       | Number   | yes       | Current in A                                                                      |
 |        | powerFactor   | Number   | yes       | Power Factor in percent                                                           |
+|        | resetTotals   | Switch   | yes       | ON: Resets total values for the power meter                                       |
 |        | lastUpdate    | DateTime | yes       | Timestamp of the last measurement                                                 |
 
 ### Shelly 2 - relay mode (thing-type: shelly2-relay)
@@ -945,6 +954,7 @@ You should calibrate the valve using the device Web UI or Shelly App before star
 | ------- | --------------- | -------- | --------- | ------------------------------------------------------------------- |
 | sensors | temperature     | Number   | yes       | Current Temperature in °C                                           |
 |         | state           | Contact  | yes       | Valve status: OPEN or CLOSED (position = 0)                         |
+|         | open            | Contact  | yes       | ON: "window is open" was detected, OFF: window is closed            |
 |         | lastUpdate      | DateTime | yes       | Timestamp of the last update (any sensor value changed)             |
 | control | targetTemp      | Number   | no        | Temperature in °C: 4=Low/Min; 5..30=target temperature;31=Hi/Max    |
 |         | position        | Dimmer   | no        | Set valve to manual mode (0..100%) disables auto-temp)              |
@@ -1108,6 +1118,23 @@ If the Shelly Add-On is installed:
 The roller positioning calibration has to be performed using the Shelly Web UI or App before the position can be set in percent.
 Refer to [Smartify Roller Shutters with openHAB and Shelly](doc/UseCaseSmartRoller.md) for more information on roller integration.
 
+### Shelly Plus Plug-S/IT/UK/US (thing-type: shellyplusplug)
+
+| 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       | Sets a  timer to turn the device ON after every OFF command; in seconds           |
+|       | autoOff      | Number   | r/w       | Sets a  timer to turn the device OFF after every ON command; in seconds           |
+|       | timerActive  | Switch   | yes       | ON: An auto-on/off timer is active                                                |
+|       | button       | Trigger  | yes       | Event trigger, see section Button Events                                          |
+| meter | currentWatts | Number   | yes       | Current power consumption in Watts                                                |
+|       | lastPower1   | Number   | yes       | Energy consumption for a round minute, 1 minute  ago                              |
+|       | totalKWH     | Number   | yes       | Total energy consumption in kwh since the device powered up (resets on restart)   |
+|       | lastUpdate   | DateTime | yes       | Timestamp of the last measurement                                                 |
+
+
 ### Shelly Plus i4, i4DC (thing-types: shellyplusi4, shellyplusi4dc)
 
 | Group   | Channel    | Type    | read-only | Description                                                           |
@@ -1132,6 +1159,18 @@ 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 Smoke (thing-type: shellyplussmoke)
+
+| Group   | Channel      | Type     | read-only | Description                                             |
+| ------- | ------------ | -------- | --------- | ------------------------------------------------------- |
+| sensors | smoke        | Switch   | yes       | ON: Smoke detected                                      |
+|         | mute         | Switch   | no        | ON: Alarm muted                                         |
+|         | lastUpdate   | DateTime | yes       | Timestamp of the last update (any sensor value changed) |
+|         | lastError    | String   | yes       | Last device error.                                      |
+| battery | batteryLevel | Number   | yes       | Battery Level in %                                      |
+|         | lowBattery   | Switch   | yes       | Low battery alert (< 20%)                               |
+
+
 ## Shelly Pro Series
 
 ### Shelly Pro 1 (thing-type: shellypro1)
@@ -1258,6 +1297,38 @@ Channels lastEvent and eventCount are only available if input type is set to mom
 |        | timerActive | Switch  | yes       | Relay #3: ON: An auto-on/off timer is active                                      |
 |        | button      | Trigger | yes       | Relay #3:  Event trigger, see section Button Events                               |
 
+### Shelly Pro 3EM (thing-type: shellypro3em)
+
+| Group  | Channel       | Type     | read-only | Description                                                                       |
+| ------ | ------------- | -------- | --------- | --------------------------------------------------------------------------------- |
+| meter1 | currentWatts  | Number   | yes       | Current power consumption in Watts                                                |
+|        | totalKWH      | Number   | yes       | Total energy consumption in kwh since the device powered up (resets on restart)   |
+|        | returnedKWH   | Number   | yes       | Total returned energy, kwh                                                        |
+|        | reactiveWatts | Number   | yes       | Instantaneous reactive power, Watts                                               |
+|        | voltage       | Number   | yes       | RMS voltage, Volts                                                                |
+|        | current       | Number   | yes       | Current in A                                                                      |
+|        | powerFactor   | Number   | yes       | Power Factor in percent                                                           |
+|        | resetTotals   | Switch   | yes       | ON: Resets total values for the power meter                                       |
+|        | lastUpdate    | DateTime | yes       | Timestamp of the last measurement                                                 |
+| meter2 | currentWatts  | Number   | yes       | Current power consumption in Watts                                                |
+|        | totalKWH      | Number   | yes       | Total energy consumption in kwh since the device powered up (resets on restart)   |
+|        | returnedKWH   | Number   | yes       | Total returned energy, kwh                                                        |
+|        | reactiveWatts | Number   | yes       | Instantaneous reactive power, Watts                                               |
+|        | voltage       | Number   | yes       | RMS voltage, Volts                                                                |
+|        | current       | Number   | yes       | Current in A                                                                      |
+|        | powerFactor   | Number   | yes       | Power Factor in percent                                                           |
+|        | resetTotals   | Switch   | yes       | ON: Resets total values for the power meter                                       |
+|        | lastUpdate    | DateTime | yes       | Timestamp of the last measurement                                                 |
+| meter3 | currentWatts  | Number   | yes       | Current power consumption in Watts                                                |
+|        | totalKWH      | Number   | yes       | Total energy consumption in kwh since the device powered up (resets on restart)   |
+|        | returnedKWH   | Number   | yes       | Total returned energy, kwh                                                        |
+|        | reactiveWatts | Number   | yes       | Instantaneous reactive power, Watts                                               |
+|        | voltage       | Number   | yes       | RMS voltage, Volts                                                                |
+|        | current       | Number   | yes       | Current in A                                                                      |
+|        | powerFactor   | Number   | yes       | Power Factor in percent                                                           |
+|        | resetTotals   | Switch   | yes       | ON: Resets total values for the power meter                                       |
+|        | lastUpdate    | DateTime | yes       | Timestamp of the last measurement                                                 |
+
 ### Shelly Pro 4PM (thing-type: shelly4pro)
 
 | Group  | Channel     | Type    | read-only | Description                                                                       |
index 8b30cf31cac4cc1ea21c00276f447f222609e7bd..57d68c68842849ec29ac486ac42d22096cf71bcb 100755 (executable)
@@ -77,10 +77,13 @@ public class ShellyBindingConstants {
             THING_TYPE_SHELLYPRO2PM_RELAY, //
             THING_TYPE_SHELLYPRO2PM_ROLLER, //
             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, //
             THING_TYPE_SHELLYPROTECTED, //
             THING_TYPE_SHELLYUNKNOWN);
@@ -149,6 +152,7 @@ public class ShellyBindingConstants {
     public static final String CHANNEL_EMETER_VOLTAGE = "voltage";
     public static final String CHANNEL_EMETER_CURRENT = "current";
     public static final String CHANNEL_EMETER_PFACTOR = "powerFactor";
+    public static final String CHANNEL_EMETER_RESETTOTAL = "resetTotals";
 
     public static final String CHANNEL_GROUP_SENSOR = "sensors";
     public static final String CHANNEL_SENSOR_TEMP = "temperature";
@@ -161,7 +165,9 @@ public class ShellyBindingConstants {
     public static final String CHANNEL_SENSOR_TILT = "tilt";
     public static final String CHANNEL_SENSOR_FLOOD = "flood";
     public static final String CHANNEL_SENSOR_SMOKE = "smoke";
+    public static final String CHANNEL_SENSOR_MUTE = "mute";
     public static final String CHANNEL_SENSOR_STATE = "state";
+    public static final String CHANNEL_SENSOR_OPEN = "open";
     public static final String CHANNEL_SENSOR_VALVE = "valve";
     public static final String CHANNEL_SENSOR_SSTATE = "status"; // Shelly Gas
     public static final String CHANNEL_SENSOR_MOTION_ACT = "motionActive";
@@ -293,6 +299,7 @@ public class ShellyBindingConstants {
     public static final int DIGITS_WATT = 2;
     public static final int DIGITS_KWH = 3;
     public static final int DIGITS_VOLT = 1;
+    public static final int DIGITS_AMPERE = 3;
     public static final int DIGITS_TEMP = 1;
     public static final int DIGITS_LUX = 0;
     public static final int DIGITS_PERCENT = 1;
index 9904ed97f9261dc3f1a526b897b8a2fd4e5a9dcc..f238ba501925bdf7ba1822d43382fec2482398e8 100644 (file)
@@ -54,7 +54,9 @@ public interface ShellyApiInterface {
 
     void setRelayTurn(int id, String turnMode) throws ShellyApiException;
 
-    ShellyRollerStatus getRollerStatus(int rollerIndex) throws ShellyApiException;
+    public void resetMeterTotal(int id) throws ShellyApiException;
+
+    public ShellyRollerStatus getRollerStatus(int rollerIndex) throws ShellyApiException;
 
     void setRollerTurn(int relayIndex, String turnMode) throws ShellyApiException;
 
@@ -91,6 +93,8 @@ public interface ShellyApiInterface {
 
     void startValveBoost(int valveId, int value) throws ShellyApiException;
 
+    void muteSmokeAlarm(int smokeId) throws ShellyApiException;
+
     ShellyOtaCheckResult checkForUpdate() throws ShellyApiException;
 
     ShellySettingsUpdate firmwareUpdate(String uri) throws ShellyApiException;
index 0d1b05dbf6b9cf1435d75042a0f4d87af8fadcc6..5f96c5280e5571a6435376db76bda32fec231ef6 100644 (file)
@@ -99,6 +99,7 @@ public class ShellyDeviceProfile {
     public boolean isButton = false; // true for a Shelly Button 1
     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 int minTemp = 0; // Bulb/Duo: Min Light Temp
     public int maxTemp = 0; // Bulb/Duo: Max Light Temp
@@ -196,7 +197,7 @@ public class ShellyDeviceProfile {
         }
 
         boolean isFlood = thingType.equals(THING_TYPE_SHELLYFLOOD_STR);
-        boolean isSmoke = thingType.equals(THING_TYPE_SHELLYSMOKE_STR);
+        isSmoke = thingType.equals(THING_TYPE_SHELLYSMOKE_STR) || thingType.equals(THING_TYPE_SHELLYPLUSSMOKE_STR);
         boolean isGas = thingType.equals(THING_TYPE_SHELLYGAS_STR);
         boolean isUNI = thingType.equals(THING_TYPE_SHELLYUNI_STR);
         isHT = thingType.equals(THING_TYPE_SHELLYHT_STR) || thingType.equals(THING_TYPE_SHELLYPLUSHT_STR);
index c730aa8d9f98a592f41bf080e243d33fe8aa625f..6c1f1ff8cdb2393fbb6d6a9967fc198aa55b4a4f 100644 (file)
@@ -124,7 +124,7 @@ public class Shelly1ApiJsonDTO {
     //
     // API values
     //
-    public static final double SHELLY_API_INVTEMP = -999.0;
+    public static final double SHELLY_API_INVTEMP = 999.0;
 
     public static final String SHELLY_BTNT_MOMENTARY = "momentary";
     public static final String SHELLY_BTNT_MOM_ON_RELEASE = "momentary_on_release";
@@ -920,6 +920,8 @@ public class Shelly1ApiJsonDTO {
         public ShellyThermTemp tmp;
         @SerializedName("boost_minutes")
         public Integer boostMinutes;
+        @SerializedName("window_open")
+        public Boolean windowOpen;
     }
 
     public static class ShellySensorTmp {
@@ -1103,6 +1105,7 @@ public class Shelly1ApiJsonDTO {
         public ShellySensorState sensor;
         public Boolean smoke; // SHelly Smoke
         public Boolean flood; // Shelly Flood: true = flood condition detected
+        public Boolean mute; // mute enabled/disabled
         @SerializedName("rain_sensor")
         public Boolean rainSensor; // Shelly Flood: true=in rain mode
 
index 733b3c513c1d1931866f104571344cca02e78bac..50f614ce7a9c4e57e7f5b255d4df33ffa1fb9c58 100644 (file)
@@ -207,11 +207,11 @@ public class Shelly1CoIoTProtocol {
             // event count
             updateChannel(updates, group, CHANNEL_STATUS_EVENTCOUNT + profile.getInputSuffix(idx), getDecimal(count));
             logger.trace(
-                    "{}: Check button[{}] for event trigger (isButtonMode={}, isButton={}, hasBattery={}, serial={}, count={}, lastEventCount[{}]={}",
+                    "{}: Check button[{}] for event trigger (inButtonMode={}, isButton={}, hasBattery={}, serial={}, count={}, lastEventCount[{}]={}",
                     thingName, idx, profile.inButtonMode(idx), profile.isButton, profile.hasBattery, serial, count, idx,
                     lastEventCount[idx]);
-            if (profile.inButtonMode(idx) && ((profile.hasBattery && (count == 1))
-                    || ((lastEventCount[idx] != -1) && (count != lastEventCount[idx])))) {
+            if (profile.inButtonMode(idx) && ((profile.hasBattery && count == 1)
+                    || (lastEventCount[idx] != -1 && count != lastEventCount[idx]))) {
                 if (!profile.isButton || (profile.isButton && (serial != 0x200))) { // skip duplicate on wake-up
                     logger.debug("{}: Trigger event {}", thingName, inputEvent[idx]);
                     thingHandler.triggerButton(group, idx, inputEvent[idx]);
index 438ba5a894f960269622a3f33ac8105b0aebfb27..0e5384791f8baee7caa385420c1004b34def4423 100644 (file)
@@ -93,8 +93,10 @@ public class Shelly1CoIoTVersion2 extends Shelly1CoIoTProtocol implements Shelly
             // Special handling for TRV, because it uses duplicate ID values with different meanings
             switch (sen.id) {
                 case "3101": // current temp
-                    updateChannel(updates, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_TEMP,
-                            toQuantityType(value, DIGITS_TEMP, SIUnits.CELSIUS));
+                    if (value != SHELLY_API_INVTEMP) {
+                        updateChannel(updates, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_TEMP,
+                                toQuantityType(value, DIGITS_TEMP, SIUnits.CELSIUS));
+                    }
                     break;
                 case "3103": // target temp in C. 4/31, 999=unknown
                     updateChannel(updates, CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_SETTEMP,
@@ -196,7 +198,7 @@ public class Shelly1CoIoTVersion2 extends Shelly1CoIoTProtocol implements Shelly
             case "3201": // sensor_1: T, extTemp, C, -55/125; unknown 999
             case "3301": // sensor_2: T, extTemp, C, -55/125; unknown 999
                 int idx = getExtTempId(sen.id);
-                if (idx >= 0) {
+                if (idx >= 0 && value != SHELLY_API_INVTEMP) {
                     // H&T, Fllod, DW only have 1 channel, 1/1PM with Addon have up to to 3 sensors
                     String channel = profile.isSensor ? CHANNEL_SENSOR_TEMP : CHANNEL_SENSOR_TEMP + idx;
                     // Some devices report values = -999 or 99 during fw update
index 2d605dba427ad89672d16d79835ec11c977e08e5..68a4e9262f41f8736f39288a198fab8ceb911add 100644 (file)
@@ -208,6 +208,11 @@ public class Shelly1CoapHandler implements Shelly1CoapListener {
                 logger.debug("{}: CoIoT Message from {} (MID={}): {}", thingName,
                         response.getSourceContext().getPeerAddress(), response.getMID(), response.getPayloadString());
             }
+            if (thingHandler.isStopping()) {
+                logger.debug("{}: Thing is shutting down, ignore CoIOT message", thingName);
+                return;
+            }
+
             if (response.isCanceled() || response.isDuplicate() || response.isRejected()) {
                 logger.debug("{} ({}): Packet was canceled, rejected or is a duplicate -> discard", thingName, devId);
                 thingHandler.incProtErrors();
index eb5f7ba9d9a671c9d6bb4053f4df76dbf93e6aca..0972cfec81b98639e56cc00cc0b1284049558527 100644 (file)
@@ -172,8 +172,12 @@ public class Shelly1HttpApi extends ShellyHttpClient implements ShellyApiInterfa
 
     @Override
     public void setRelayTurn(int id, String turnMode) throws ShellyApiException {
-        callApi(getControlUriPrefix(id) + "?" + SHELLY_LIGHT_TURN + "=" + turnMode.toLowerCase(),
-                ShellyShortLightStatus.class);
+        callApi(getControlUriPrefix(id) + "?" + SHELLY_LIGHT_TURN + "=" + turnMode.toLowerCase(), String.class);
+    }
+
+    @Override
+    public void resetMeterTotal(int id) throws ShellyApiException {
+        callApi(SHELLY_URL_STATUS_EMETER + "/" + id + "/reset_totals=1", ShellyStatusRelay.class);
     }
 
     @Override
@@ -531,6 +535,11 @@ public class Shelly1HttpApi extends ShellyHttpClient implements ShellyApiInterfa
         }
     }
 
+    @Override
+    public void muteSmokeAlarm(int id) throws ShellyApiException {
+        throw new ShellyApiException("Request not supported");
+    }
+
     /**
      * Set sensor Action URLs
      *
index 97fb99ca26da89bb0c95cab2b21b9c3e8b0dff70..c871e20dc4a3307dc6b8c7ad7be8bed9ca8df222 100644 (file)
@@ -57,8 +57,10 @@ import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceC
 import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceConfig.Shelly2GetConfigResult;
 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.Shelly2DeviceStatusPower;
+import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceStatus.Shelly2DeviceStatusResult.Shelly2DeviceStatusSmoke;
 import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceStatus.Shelly2DeviceStatusResult.Shelly2DeviceStatusTempId;
 import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceStatus.Shelly2InputStatus;
 import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2RelayStatus;
@@ -175,11 +177,16 @@ public class Shelly2ApiClient extends ShellyHttpClient {
             boolean channelUpdate) throws ShellyApiException {
         boolean updated = false;
 
+        if (result.temperature0 != null && !getProfile().isSensor) {
+            status.temperature = status.tmp.tC = result.temperature0.tC;
+        }
+
         updated |= updateInputStatus(status, result, channelUpdate);
         updated |= updateRelayStatus(status, result.switch0, channelUpdate);
         updated |= updateRelayStatus(status, result.switch1, channelUpdate);
         updated |= updateRelayStatus(status, result.switch2, channelUpdate);
         updated |= updateRelayStatus(status, result.switch3, channelUpdate);
+        updated |= updateEmStatus(status, result.em0, channelUpdate);
         updated |= updateRollerStatus(status, result.cover0, channelUpdate);
         if (channelUpdate) {
             updated |= ShellyComponents.updateMeters(getThing(), status);
@@ -187,6 +194,7 @@ public class Shelly2ApiClient extends ShellyHttpClient {
 
         updateHumidityStatus(sensorData, result.humidity0);
         updateTemperatureStatus(sensorData, result.temperature0);
+        updateSmokeStatus(sensorData, result.smoke0);
         updateBatteryStatus(sensorData, result.devicepower0);
         updateAddonStatus(status, result);
         updated |= ShellyComponents.updateSensors(getThing(), status);
@@ -263,14 +271,91 @@ public class Shelly2ApiClient extends ShellyHttpClient {
 
         // Update internal structures
         status.relays.set(rs.id, rstatus);
-        status.meters.set(rs.id, sm);
-        status.emeters.set(rs.id, emeter);
         relayStatus.relays.set(rs.id, sr);
-        relayStatus.meters.set(rs.id, sm);
-
+        updateMeter(status, rs.id, sm, emeter, channelUpdate);
         return channelUpdate ? ShellyComponents.updateRelay((ShellyBaseHandler) getThing(), status, rs.id) : false;
     }
 
+    private void updateMeter(ShellySettingsStatus status, int id, ShellySettingsMeter sm, ShellySettingsEMeter emeter,
+            boolean channelUpdate) throws ShellyApiException {
+        status.meters.set(id, sm);
+        status.emeters.set(id, emeter);
+        relayStatus.meters.set(id, sm);
+    }
+
+    private boolean updateEmStatus(ShellySettingsStatus status, @Nullable Shelly2DeviceStatusEm em,
+            boolean channelUpdate) throws ShellyApiException {
+        if (em == null) {
+            return false;
+        }
+
+        boolean updated = false;
+        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;
+        }
+        if (em.aAprtPower != null) {
+            emeter.totalReturned = em.aAprtPower;
+        }
+        if (em.aVoltage != null) {
+            emeter.voltage = em.aVoltage;
+        }
+        if (em.aCurrent != null) {
+            emeter.current = em.aCurrent;
+        }
+        if (em.aPF != null) {
+            emeter.pf = em.aPF;
+        }
+        // Update internal structures
+        updateMeter(status, 0, sm, emeter, channelUpdate);
+
+        sm = new ShellySettingsMeter();
+        emeter = status.emeters.get(1);
+        sm.isValid = emeter.isValid = true;
+        if (em.bActPower != null) {
+            sm.power = emeter.power = em.bActPower;
+        }
+        if (em.bAprtPower != null) {
+            emeter.totalReturned = em.bAprtPower;
+        }
+        if (em.bVoltage != null) {
+            emeter.voltage = em.bVoltage;
+        }
+        if (em.bCurrent != null) {
+            emeter.current = em.bCurrent;
+        }
+        if (em.bPF != null) {
+            emeter.pf = em.bPF;
+        }
+        // Update internal structures
+        updateMeter(status, 1, sm, emeter, channelUpdate);
+
+        sm = new ShellySettingsMeter();
+        emeter = status.emeters.get(2);
+        sm.isValid = emeter.isValid = true;
+        if (em.cActPower != null) {
+            sm.power = emeter.power = em.cActPower;
+        }
+        if (em.cAprtPower != null) {
+            emeter.totalReturned = em.cAprtPower;
+        }
+        if (em.cVoltage != null) {
+            emeter.voltage = em.cVoltage;
+        }
+        if (em.cCurrent != null) {
+            emeter.current = em.cCurrent;
+        }
+        if (em.cPF != null) {
+            emeter.pf = em.cPF;
+        }
+        // Update internal structures
+        updateMeter(status, 2, sm, emeter, channelUpdate);
+
+        return channelUpdate ? ShellyComponents.updateMeters(getThing(), status) : false;
+    }
+
     protected @Nullable ArrayList<@Nullable ShellySettingsRoller> fillRollerSettings(ShellyDeviceProfile profile,
             Shelly2GetConfigResult dc) {
         if (dc.cover0 == null) {
@@ -360,7 +445,9 @@ public class Shelly2ApiClient extends ShellyHttpClient {
         if (cs.aenergy != null) {
             sm.total = emeter.total = cs.aenergy.total;
             sm.counters = cs.aenergy.byMinute;
-            sm.timestamp = (long) cs.aenergy.minuteTs;
+            if (cs.aenergy.minuteTs != null) {
+                sm.timestamp = (long) cs.aenergy.minuteTs;
+            }
         }
         if (cs.voltage != null) {
             emeter.voltage = cs.voltage;
@@ -448,6 +535,14 @@ public class Shelly2ApiClient extends ShellyHttpClient {
         sdata.tmp.tF = value.tF;
     }
 
+    protected void updateSmokeStatus(ShellyStatusSensor sdata, @Nullable Shelly2DeviceStatusSmoke value) {
+        if (value == null) {
+            return;
+        }
+        sdata.smoke = getBool(value.alarm);
+        sdata.mute = getBool(value.mute);
+    }
+
     protected void updateBatteryStatus(ShellyStatusSensor sdata, @Nullable Shelly2DeviceStatusPower value) {
         if (value == null) {
             return;
index ff33990f74c74ab48c51bbe64ee9e2524a8bdbe8..e52ead4605473e6e2a2b1c2a5b52bf9c1430604c 100644 (file)
@@ -56,6 +56,8 @@ 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_SMOKE_SETCONFIG = "Smoke.SetConfig";
+    public static final String SHELLYRPC_METHOD_SMOKE_MUTE = "Smoke.Mute";
 
     public static final String SHELLYRPC_METHOD_NOTIFYSTATUS = "NotifyStatus"; // inbound status
     public static final String SHELLYRPC_METHOD_NOTIFYFULLSTATUS = "NotifyFullStatus"; // inbound status from bat device
@@ -283,6 +285,17 @@ public class Shelly2ApiJsonDTO {
             public Double currentLimit;
         }
 
+        public static class Shelly2DevConfigEm {
+            public Integer id;
+            public String name;
+            @SerializedName("blink_mode_selector")
+            public String blinkModeSelector;
+            @SerializedName("phase_selector")
+            public String phase_selector;
+            @SerializedName("monitor_phase_sequence")
+            public Boolean monitorPhaseSequence;
+        }
+
         public class Shelly2DevConfigCover {
             public class Shelly2DeviceConfigCoverMotor {
                 @SerializedName("idle_power_thr")
@@ -333,6 +346,12 @@ public class Shelly2ApiJsonDTO {
             public Shelly2DeviceConfigCoverObstructionDetection obstructionDetection;
         }
 
+        public static class Shelly2ConfigSmoke {
+            public Integer id;
+            public Boolean alarm;
+            public Boolean mute;
+        }
+
         public static class Shelly2GetConfigResult {
 
             public class Shelly2DevConfigCloud {
@@ -377,8 +396,14 @@ public class Shelly2ApiJsonDTO {
             @SerializedName("switch:3")
             public Shelly2DevConfigSwitch switch3;
 
+            @SerializedName("em:0")
+            public Shelly2DevConfigEm em0;
+
             @SerializedName("cover:0")
             public Shelly2DevConfigCover cover0;
+
+            @SerializedName("smoke:0")
+            public Shelly2ConfigSmoke smoke0;
         }
 
         public class Shelly2DeviceConfigSta {
@@ -486,6 +511,57 @@ public class Shelly2ApiJsonDTO {
                 public Shelly2DeviceStatusCharger external;
             }
 
+            public static class Shelly2DeviceStatusEm {
+                public Integer id;
+
+                @SerializedName("a_current")
+                public Double aCurrent;
+                @SerializedName("a_voltage")
+                public Double aVoltage;
+                @SerializedName("a_act_power")
+                public Double aActPower;
+                @SerializedName("a_aprt_power")
+                public Double aAprtPower;
+                @SerializedName("a_pf")
+                public Double aPF;
+
+                @SerializedName("b_current")
+                public Double bCurrent;
+                @SerializedName("b_voltage")
+                public Double bVoltage;
+                @SerializedName("b_act_power")
+                public Double bActPower;
+                @SerializedName("b_aprt_power")
+                public Double bAprtPower;
+                @SerializedName("b_pf")
+                public Double bPF;
+
+                @SerializedName("c_current")
+                public Double cCurrent;
+                @SerializedName("c_voltage")
+                public Double cVoltage;
+                @SerializedName("c_act_power")
+                public Double cActPower;
+                @SerializedName("c_aprt_power")
+                public Double cAprtPower;
+                @SerializedName("c_pf")
+                public Double cPF;
+
+                @SerializedName("n_current")
+                public Double nCurrent;
+            }
+
+            public static class Shelly2DeviceStatusEmData {
+                public Integer id;
+                public String[] errors;
+            }
+
+            public class Shelly2DeviceStatusSmoke {
+                public Integer id;
+                public Boolean alarm;
+                public Boolean mute;
+            }
+
             public Shelly2DeviceStatusBle ble;
             public Shelly2DeviceStatusCloud cloud;
             public Shelly2DeviceStatusMqqt mqtt;
@@ -512,6 +588,11 @@ public class Shelly2ApiJsonDTO {
             @SerializedName("switch:3")
             public Shelly2RelayStatus switch3;
 
+            @SerializedName("em:0")
+            Shelly2DeviceStatusEm em0;
+            @SerializedName("emdata:0")
+            Shelly2DeviceStatusEmData emdata0;
+
             @SerializedName("cover:0")
             public Shelly2CoverStatus cover0;
 
@@ -532,6 +613,8 @@ public class Shelly2ApiJsonDTO {
             public Shelly2DeviceStatusHumidity humidity0;
             @SerializedName("humidity:100")
             public Shelly2DeviceStatusHumidity humidity100;
+            @SerializedName("smoke:0")
+            public Shelly2DeviceStatusSmoke smoke0;
 
             @SerializedName("voltmeter:100")
             public Shelly2DeviceStatusVoltage voltmeter100;
index c054b9256d7bd44dc56acd3c2589edd794853a0d..e387019333efbe2a6d71ef16c807f5dc292cacac 100644 (file)
@@ -205,22 +205,15 @@ public class Shelly2ApiRpc extends Shelly2ApiClient implements ShellyApiInterfac
         fillWiFiSta(dc.wifi.sta, profile.settings.wifiSta);
         fillWiFiSta(dc.wifi.sta1, profile.settings.wifiSta1);
 
+        profile.numMeters = 0;
         if (profile.hasRelays) {
             profile.status.relays = new ArrayList<>();
-            profile.status.meters = new ArrayList<>();
-            profile.status.emeters = new ArrayList<>();
             relayStatus.relays = new ArrayList<>();
-            relayStatus.meters = new ArrayList<>();
             profile.numMeters = profile.isRoller ? profile.numRollers : profile.numRelays;
             for (int i = 0; i < profile.numRelays; i++) {
                 profile.status.relays.add(new ShellySettingsRelay());
                 relayStatus.relays.add(new ShellyShortStatusRelay());
             }
-            for (int i = 0; i < profile.numMeters; i++) {
-                profile.status.meters.add(new ShellySettingsMeter());
-                profile.status.emeters.add(new ShellySettingsEMeter());
-                relayStatus.meters.add(new ShellySettingsMeter());
-            }
         }
 
         if (profile.numInputs > 0) {
@@ -236,6 +229,22 @@ public class Shelly2ApiRpc extends Shelly2ApiClient implements ShellyApiInterfac
             }
         }
 
+        if (dc.em0 != null) {
+            profile.numMeters = 3;
+        }
+
+        if (profile.numMeters > 0) {
+            profile.status.meters = new ArrayList<>();
+            profile.status.emeters = new ArrayList<>();
+            relayStatus.meters = new ArrayList<>();
+
+            for (int i = 0; i < profile.numMeters; i++) {
+                profile.status.meters.add(new ShellySettingsMeter());
+                profile.status.emeters.add(new ShellySettingsEMeter());
+                relayStatus.meters.add(new ShellySettingsMeter());
+            }
+        }
+
         if (profile.isRoller) {
             profile.status.rollers = new ArrayList<>();
             for (int i = 0; i < profile.numRollers; i++) {
@@ -278,7 +287,8 @@ public class Shelly2ApiRpc extends Shelly2ApiClient implements ShellyApiInterfac
     private void checkSetWsCallback() throws ShellyApiException {
         Shelly2ConfigParms wsConfig = apiRequest(SHELLYRPC_METHOD_WSGETCONFIG, null, Shelly2ConfigParms.class);
         String url = "ws://" + config.localIp + ":" + config.localPort + "/shelly/wsevent";
-        if (!getBool(wsConfig.enable) || !url.equalsIgnoreCase(getString(wsConfig.server))) {
+        if (!config.localIp.isEmpty() && !getBool(wsConfig.enable)
+                || !url.equalsIgnoreCase(getString(wsConfig.server))) {
             logger.debug("{}: A battery device was detected without correct callback, fix it", thingName);
             wsConfig.enable = true;
             wsConfig.server = url;
@@ -314,6 +324,10 @@ public class Shelly2ApiRpc extends Shelly2ApiClient implements ShellyApiInterfac
                         thingName, thingName, message.src, message.dst, discovery);
                 return;
             }
+            if (t.isStopping()) {
+                logger.debug("{}: Thing is shutting down, ignore WebSocket message", thingName);
+                return;
+            }
             if (!t.isThingOnline() && t.getThingStatusDetail() != ThingStatusDetail.CONFIGURATION_PENDING) {
                 logger.debug("{}: Thing is not in online state/connectable, ignore NotifyStatus", thingName);
                 return;
@@ -627,6 +641,15 @@ public class Shelly2ApiRpc extends Shelly2ApiClient implements ShellyApiInterfac
         apiRequest(req);
     }
 
+    @Override
+    public void resetMeterTotal(int id) throws ShellyApiException {
+    }
+
+    @Override
+    public void muteSmokeAlarm(int index) throws ShellyApiException {
+        apiRequest(new Shelly2RpcRequest().withMethod(SHELLYRPC_METHOD_SMOKE_MUTE).withId(index));
+    }
+
     @Override
     public ShellySettingsLogin getLoginSettings() throws ShellyApiException {
         return new ShellySettingsLogin();
index 49857062b1a5f5214dda5c93c0826eb8bab13837..9d443d0237e217884d7059cbf126951a417765ee 100644 (file)
@@ -71,10 +71,14 @@ public class ShellyThingCreator {
     public static final String SHELLYDT_PLUS2PM_ROLLER = "SNSW-002P16EU-roller";
     public static final String SHELLYDT_PLUS2PM_RELAY_2 = "SNSW-102P16EU-relay";
     public static final String SHELLYDT_PLUS2PM_ROLLER_2 = "SNSW-102P16EU-roller";
+    public static final String SHELLYDT_PLUSPLUGS = "SNPL-00112EU";
+    public static final String SHELLYDT_PLUSPLUGIT = "SNPL-00110IT";
+    public static final String SHELLYDT_PLUSPLUGUK = "SNPL-00112UK";
     public static final String SHELLYDT_PLUSPLUGUS = "SNPL-00116US";
     public static final String SHELLYDT_PLUSI4 = "SNSN-0024X";
     public static final String SHELLYDT_PLUSI4DC = "SNSN-0D24X";
     public static final String SHELLYDT_PLUSHT = "SNSN-0013A";
+    public static final String SHELLYDT_PLUSSMOKE = "SNSN-0031Z";
 
     // Shelly Pro Series
     public static final String SHELLYDT_PRO1 = "SPSW-001XE16EU";
@@ -93,6 +97,7 @@ public class ShellyThingCreator {
     public static final String SHELLYDT_PRO2PM_RELAY_3 = "SPSW-202PE16EU-relay";
     public static final String SHELLYDT_PRO2PM_ROLLER_3 = "SPSW-202PE16EU-roller";
     public static final String SHELLYDT_PRO3 = "SPSW-003XE16EU";
+    public static final String SHELLYDT_PRO3EM = "SPEM-003CEBEU";
     public static final String SHELLYDT_PRO4PM = "SPSW-004PE16EU";
     public static final String SHELLYDT_PRO4PM_2 = "SPSW-104PE16EU";
 
@@ -145,6 +150,8 @@ public class ShellyThingCreator {
     public static final String THING_TYPE_SHELLYPLUSI4_STR = "shellyplusi4";
     public static final String THING_TYPE_SHELLYPLUSI4DC_STR = "shellyplusi4dc";
     public static final String THING_TYPE_SHELLYPLUSHT_STR = "shellyplusht";
+    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";
 
     // Shelly Pro Series
@@ -154,6 +161,7 @@ public class ShellyThingCreator {
     public static final String THING_TYPE_SHELLYPRO2PM_RELAY_STR = "shellypro2pm-relay";
     public static final String THING_TYPE_SHELLYPRO2PM_ROLLER_STR = "shellypro2pm-roller";
     public static final String THING_TYPE_SHELLYPRO3_STR = "shellypro3";
+    public static final String THING_TYPE_SHELLYPRO3EM_STR = "shellypro3em";
     public static final String THING_TYPE_SHELLYPRO4PM_STR = "shellypro4pm";
 
     public static final String THING_TYPE_SHELLYPROTECTED_STR = "shellydevice";
@@ -229,6 +237,10 @@ public class ShellyThingCreator {
             THING_TYPE_SHELLYPLUSI4DC_STR);
     public static final ThingTypeUID THING_TYPE_SHELLYPLUSHT = new ThingTypeUID(BINDING_ID,
             THING_TYPE_SHELLYPLUSHT_STR);
+    public static final ThingTypeUID THING_TYPE_SHELLYPLUSSMOKE = new ThingTypeUID(BINDING_ID,
+            THING_TYPE_SHELLYPLUSSMOKE_STR);
+    public static final ThingTypeUID THING_TYPE_SHELLYPLUSPLUGS = new ThingTypeUID(BINDING_ID,
+            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_SHELLYPRO1 = new ThingTypeUID(BINDING_ID, THING_TYPE_SHELLYPRO1_STR);
@@ -241,6 +253,8 @@ public class ShellyThingCreator {
     public static final ThingTypeUID THING_TYPE_SHELLYPRO2PM_ROLLER = new ThingTypeUID(BINDING_ID,
             THING_TYPE_SHELLYPRO2PM_ROLLER_STR);
     public static final ThingTypeUID THING_TYPE_SHELLYPRO3 = new ThingTypeUID(BINDING_ID, THING_TYPE_SHELLYPRO3_STR);
+    public static final ThingTypeUID THING_TYPE_SHELLYPRO3EM = new ThingTypeUID(BINDING_ID,
+            THING_TYPE_SHELLYPRO3EM_STR);
     public static final ThingTypeUID THING_TYPE_SHELLYPRO4PM = new ThingTypeUID(BINDING_ID,
             THING_TYPE_SHELLYPRO4PM_STR);
 
@@ -280,10 +294,14 @@ public class ShellyThingCreator {
         THING_TYPE_MAPPING.put(SHELLYDT_PLUS2PM_ROLLER, THING_TYPE_SHELLYPLUS2PM_ROLLER_STR);
         THING_TYPE_MAPPING.put(SHELLYDT_PLUS2PM_RELAY_2, THING_TYPE_SHELLYPLUS2PM_RELAY_STR);
         THING_TYPE_MAPPING.put(SHELLYDT_PLUS2PM_ROLLER_2, THING_TYPE_SHELLYPLUS2PM_ROLLER_STR);
+        THING_TYPE_MAPPING.put(SHELLYDT_PLUSPLUGS, THING_TYPE_SHELLYPLUSPLUGS_STR);
+        THING_TYPE_MAPPING.put(SHELLYDT_PLUSPLUGIT, THING_TYPE_SHELLYPLUSPLUGS_STR);
+        THING_TYPE_MAPPING.put(SHELLYDT_PLUSPLUGUK, THING_TYPE_SHELLYPLUSPLUGS_STR);
         THING_TYPE_MAPPING.put(SHELLYDT_PLUSPLUGUS, THING_TYPE_SHELLYPLUSPLUGUS_STR);
         THING_TYPE_MAPPING.put(SHELLYDT_PLUSI4DC, THING_TYPE_SHELLYPLUSI4DC_STR);
         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);
 
         // Pro Series
         THING_TYPE_MAPPING.put(SHELLYDT_PRO1, THING_TYPE_SHELLYPRO1_STR);
@@ -302,6 +320,7 @@ public class ShellyThingCreator {
         THING_TYPE_MAPPING.put(SHELLYDT_PRO2PM_ROLLER_2, THING_TYPE_SHELLYPRO2PM_ROLLER_STR);
         THING_TYPE_MAPPING.put(SHELLYDT_PRO2PM_ROLLER_3, THING_TYPE_SHELLYPRO2PM_ROLLER_STR);
         THING_TYPE_MAPPING.put(SHELLYDT_PRO3, THING_TYPE_SHELLYPRO3_STR);
+        THING_TYPE_MAPPING.put(SHELLYDT_PRO3EM, THING_TYPE_SHELLYPRO3EM_STR);
         THING_TYPE_MAPPING.put(SHELLYDT_PRO4PM, THING_TYPE_SHELLYPRO4PM_STR);
         THING_TYPE_MAPPING.put(SHELLYDT_PRO4PM_2, THING_TYPE_SHELLYPRO4PM_STR);
 
@@ -309,12 +328,12 @@ public class ShellyThingCreator {
         THING_TYPE_MAPPING.put(THING_TYPE_SHELLY1_STR, THING_TYPE_SHELLY1_STR);
         THING_TYPE_MAPPING.put(THING_TYPE_SHELLY1PM_STR, THING_TYPE_SHELLY1PM_STR);
         THING_TYPE_MAPPING.put(THING_TYPE_SHELLY1L_STR, THING_TYPE_SHELLY1L_STR);
+        THING_TYPE_MAPPING.put(THING_TYPE_SHELLY3EM_STR, THING_TYPE_SHELLY3EM_STR);
+        THING_TYPE_MAPPING.put(THING_TYPE_SHELLYEM_STR, THING_TYPE_SHELLYEM_STR);
         THING_TYPE_MAPPING.put(THING_TYPE_SHELLY4PRO_STR, THING_TYPE_SHELLY4PRO_STR);
         THING_TYPE_MAPPING.put(THING_TYPE_SHELLYDIMMER2_STR, THING_TYPE_SHELLYDIMMER2_STR);
         THING_TYPE_MAPPING.put(THING_TYPE_SHELLYDIMMER_STR, THING_TYPE_SHELLYDIMMER_STR);
         THING_TYPE_MAPPING.put(THING_TYPE_SHELLYIX3_STR, THING_TYPE_SHELLYIX3_STR);
-        THING_TYPE_MAPPING.put(THING_TYPE_SHELLY3EM_STR, THING_TYPE_SHELLY3EM_STR);
-        THING_TYPE_MAPPING.put(THING_TYPE_SHELLYEM_STR, THING_TYPE_SHELLYEM_STR);
         THING_TYPE_MAPPING.put(THING_TYPE_SHELLYDUORGBW_STR, THING_TYPE_SHELLYDUORGBW_STR);
         THING_TYPE_MAPPING.put(THING_TYPE_SHELLYDUO_STR, THING_TYPE_SHELLYDUO_STR);
         THING_TYPE_MAPPING.put(THING_TYPE_SHELLYVINTAGE_STR, THING_TYPE_SHELLYVINTAGE_STR);
@@ -334,6 +353,29 @@ public class ShellyThingCreator {
         THING_TYPE_MAPPING.put(THING_TYPE_SHELLYUNI_STR, THING_TYPE_SHELLYUNI_STR);
         THING_TYPE_MAPPING.put(THING_TYPE_SHELLYMOTION2_STR, THING_TYPE_SHELLYMOTION_STR);
 
+        THING_TYPE_MAPPING.put(THING_TYPE_SHELLYPLUS1PM_STR, THING_TYPE_SHELLYPLUS1PM_STR);
+        THING_TYPE_MAPPING.put(THING_TYPE_SHELLYPLUS1_STR, THING_TYPE_SHELLYPLUS1_STR);
+        THING_TYPE_MAPPING.put(THING_TYPE_SHELLYPLUS1PM_STR, THING_TYPE_SHELLYPLUS1PM_STR);
+        THING_TYPE_MAPPING.put(THING_TYPE_SHELLYPLUS2PM_RELAY_STR, THING_TYPE_SHELLYPLUS2PM_RELAY_STR);
+        THING_TYPE_MAPPING.put(THING_TYPE_SHELLYPLUS2PM_ROLLER_STR, THING_TYPE_SHELLYPLUS2PM_ROLLER_STR);
+        THING_TYPE_MAPPING.put(THING_TYPE_SHELLYPLUS2PM_RELAY_STR, THING_TYPE_SHELLYPLUS2PM_RELAY_STR);
+        THING_TYPE_MAPPING.put(THING_TYPE_SHELLYPLUS2PM_ROLLER_STR, THING_TYPE_SHELLYPLUS2PM_ROLLER_STR);
+        THING_TYPE_MAPPING.put(THING_TYPE_SHELLYPLUSPLUGS_STR, THING_TYPE_SHELLYPLUSPLUGS_STR);
+        THING_TYPE_MAPPING.put(THING_TYPE_SHELLYPLUSPLUGUS_STR, THING_TYPE_SHELLYPLUSPLUGUS_STR);
+        THING_TYPE_MAPPING.put(THING_TYPE_SHELLYPLUSI4DC_STR, THING_TYPE_SHELLYPLUSI4DC_STR);
+        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_SHELLYPRO1_STR, THING_TYPE_SHELLYPRO1_STR);
+        THING_TYPE_MAPPING.put(THING_TYPE_SHELLYPRO1PM_STR, THING_TYPE_SHELLYPRO1PM_STR);
+        THING_TYPE_MAPPING.put(THING_TYPE_SHELLYPRO2PM_RELAY_STR, THING_TYPE_SHELLYPRO2PM_RELAY_STR);
+        THING_TYPE_MAPPING.put(THING_TYPE_SHELLYPRO2PM_ROLLER_STR, THING_TYPE_SHELLYPRO2PM_ROLLER_STR);
+        THING_TYPE_MAPPING.put(THING_TYPE_SHELLYPRO2_RELAY_STR, THING_TYPE_SHELLYPRO2_RELAY_STR);
+        THING_TYPE_MAPPING.put(THING_TYPE_SHELLYPRO3EM_STR, THING_TYPE_SHELLYPRO3EM_STR);
+        THING_TYPE_MAPPING.put(THING_TYPE_SHELLYPRO3_STR, THING_TYPE_SHELLYPRO3_STR);
+        THING_TYPE_MAPPING.put(THING_TYPE_SHELLYPRO4PM_STR, THING_TYPE_SHELLYPRO4PM_STR);
+
         THING_TYPE_MAPPING.put(THING_TYPE_SHELLYPROTECTED_STR, THING_TYPE_SHELLYPROTECTED_STR);
     }
 
index c3bd77c34037c1379bfb95cf2abec4b06055aa08..332f4962de0353f2a213214840caeb61ce8a3ed8 100755 (executable)
@@ -235,7 +235,8 @@ public abstract class ShellyBaseHandler extends BaseThingHandler
         if (coap != null) {
             coap.stop();
         }
-        requestUpdates(1, true);// force re-initialization
+        stopping = false;
+        reinitializeThing();// force re-initialization
     }
 
     /**
@@ -249,7 +250,6 @@ public abstract class ShellyBaseHandler extends BaseThingHandler
      */
     public boolean initializeThing() throws ShellyApiException {
         // Init from thing type to have a basic profile, gets updated when device info is received from API
-        stopping = false;
         refreshSettings = false;
         lastWakeupReason = "";
         cache.setThingName(thingName);
@@ -263,6 +263,8 @@ public abstract class ShellyBaseHandler extends BaseThingHandler
             return false;
         }
 
+        profile.initFromThingType(thingType); // do some basic initialization
+
         // Gen 1 only: Setup CoAP listener to we get the CoAP message, which triggers initialization even the thing
         // could not be fully initialized here. In this case the CoAP messages triggers auto-initialization (like the
         // Action URL does when enabled)
@@ -272,7 +274,6 @@ public abstract class ShellyBaseHandler extends BaseThingHandler
 
         // Initialize API access, exceptions will be catched by initialize()
         api.initialize();
-        profile.initFromThingType(thingType);
         ShellySettingsDevice devInfo = api.getDeviceInfo();
         if (getBool(devInfo.auth) && config.password.isEmpty()) {
             setThingOffline(ThingStatusDetail.CONFIGURATION_ERROR, "offline.conf-error-no-credentials");
@@ -357,7 +358,7 @@ public abstract class ShellyBaseHandler extends BaseThingHandler
                 return;
             }
 
-            if (!profile.isInitialized()) {
+            if (!profile.isInitialized() || (isThingOffline() && profile.alwaysOn)) {
                 logger.debug("{}: {}", thingName, messages.get("command.init", command));
                 initializeThing();
             } else {
@@ -440,7 +441,13 @@ public abstract class ShellyBaseHandler extends BaseThingHandler
                     logger.debug("{}: Set boost timer to {}", thingName, command);
                     api.setValveBoostTime(0, (int) getNumber(command));
                     break;
-
+                case CHANNEL_SENSOR_MUTE:
+                    if (profile.isSmoke && ((OnOffType) command) == OnOffType.ON) {
+                        logger.debug("{}: Mute Smoke Alarm", thingName);
+                        api.muteSmokeAlarm(0);
+                        updateChannel(getString(channelUID.getGroupId()), CHANNEL_SENSOR_MUTE, OnOffType.OFF);
+                    }
+                    break;
                 default:
                     update = handleDeviceCommand(channelUID, command);
                     break;
@@ -500,11 +507,7 @@ public abstract class ShellyBaseHandler extends BaseThingHandler
                     logger.debug("{}: Status update triggered thing initialization", thingName);
                     initializeThing(); // may fire an exception if initialization failed
                 }
-                // Get profile, if refreshSettings == true reload settings from device
                 ShellySettingsStatus status = api.getStatus();
-                if (status.uptime != null && status.uptime == 0 && profile.alwaysOn) {
-                    status = api.getStatus();
-                }
                 boolean restarted = checkRestarted(status);
                 profile = getProfile(refreshSettings || restarted);
                 profile.status = status;
@@ -541,7 +544,7 @@ public abstract class ShellyBaseHandler extends BaseThingHandler
                 status = "offline.conf-error-access-denied";
             } else if (isWatchdogStarted()) {
                 if (!isWatchdogExpired()) {
-                    logger.debug("{}: Ignore API Timeout, retry later", thingName);
+                    logger.debug("{}: Ignore API Timeout on {} {}, retry later", thingName, res.method, res.url);
                 } else {
                     if (isThingOnline()) {
                         status = "offline.status-error-watchdog";
@@ -692,7 +695,7 @@ public abstract class ShellyBaseHandler extends BaseThingHandler
     @Override
     public void reinitializeThing() {
         logger.debug("{}: Re-Initialize Thing", thingName);
-        if (stopping) {
+        if (isStopping()) {
             logger.debug("{}: Handler is shutting down, ignore", thingName);
             return;
         }
@@ -701,6 +704,11 @@ public abstract class ShellyBaseHandler extends BaseThingHandler
         requestUpdates(0, true);
     }
 
+    @Override
+    public boolean isStopping() {
+        return stopping;
+    }
+
     @Override
     public void fillDeviceStatus(ShellySettingsStatus status, boolean updated) {
         String alarm = "";
index 572bd4c78977739e5b97e306e85ad3206784ef08..7846afde876a33c60103e10c5e1a92b083ef4a1f 100644 (file)
@@ -27,10 +27,9 @@ import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettings
 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsStatus;
 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.OpenClosedType;
 import org.openhab.core.library.types.StringType;
 import org.openhab.core.library.unit.ImperialUnits;
 import org.openhab.core.library.unit.SIUnits;
@@ -113,33 +112,17 @@ public class ShellyComponents {
             if (status.extSwitch != null) {
                 if (status.extSwitch.input0 != null) {
                     updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_ESENSOR_INPUT1,
-                            getInteger(status.extSwitch.input0.input) == 1 ? OpenClosedType.OPEN
-                                    : OpenClosedType.CLOSED);
+                            getOpenClosed(getInteger(status.extSwitch.input0.input) == 1));
                 }
             }
             if (status.extTemperature != null) {
                 // Shelly 1/1PM support up to 3 external sensors
                 // for whatever reason those are not represented as an array, but 3 elements
-                if (status.extTemperature.sensor1 != null) {
-                    updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_ESENSOR_TEMP1,
-                            toQuantityType(getDouble(status.extTemperature.sensor1.tC), DIGITS_TEMP, SIUnits.CELSIUS));
-                }
-                if (status.extTemperature.sensor2 != null) {
-                    updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_ESENSOR_TEMP2,
-                            toQuantityType(getDouble(status.extTemperature.sensor2.tC), DIGITS_TEMP, SIUnits.CELSIUS));
-                }
-                if (status.extTemperature.sensor3 != null) {
-                    updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_ESENSOR_TEMP3,
-                            toQuantityType(getDouble(status.extTemperature.sensor3.tC), DIGITS_TEMP, SIUnits.CELSIUS));
-                }
-                if (status.extTemperature.sensor4 != null) {
-                    updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_ESENSOR_TEMP4,
-                            toQuantityType(getDouble(status.extTemperature.sensor4.tC), DIGITS_TEMP, SIUnits.CELSIUS));
-                }
-                if (status.extTemperature.sensor5 != null) {
-                    updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_ESENSOR_TEMP5,
-                            toQuantityType(getDouble(status.extTemperature.sensor5.tC), DIGITS_TEMP, SIUnits.CELSIUS));
-                }
+                updated |= updateTempChannel(status.extTemperature.sensor1, thingHandler, CHANNEL_ESENSOR_TEMP1);
+                updated |= updateTempChannel(status.extTemperature.sensor2, thingHandler, CHANNEL_ESENSOR_TEMP2);
+                updated |= updateTempChannel(status.extTemperature.sensor3, thingHandler, CHANNEL_ESENSOR_TEMP3);
+                updated |= updateTempChannel(status.extTemperature.sensor4, thingHandler, CHANNEL_ESENSOR_TEMP4);
+                updated |= updateTempChannel(status.extTemperature.sensor5, thingHandler, CHANNEL_ESENSOR_TEMP5);
             }
             if ((status.extHumidity != null) && (status.extHumidity.sensor1 != null)) {
                 updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_ESENSOR_HUMIDITY,
@@ -277,7 +260,7 @@ public class ShellyComponents {
                             String groupName = profile.getMeterGroup(m);
                             if (!thingHandler.areChannelsCreated()) {
                                 thingHandler.updateChannelDefinitions(ShellyChannelDefinitions
-                                        .createEMeterChannels(thingHandler.getThing(), emeter, groupName));
+                                        .createEMeterChannels(thingHandler.getThing(), profile, emeter, groupName));
                             }
 
                             // convert Watt/Hour tok w/h
@@ -292,7 +275,7 @@ public class ShellyComponents {
                             updated |= thingHandler.updateChannel(groupName, CHANNEL_EMETER_VOLTAGE,
                                     toQuantityType(getDouble(emeter.voltage), DIGITS_VOLT, Units.VOLT));
                             updated |= thingHandler.updateChannel(groupName, CHANNEL_EMETER_CURRENT,
-                                    toQuantityType(getDouble(emeter.current), DIGITS_VOLT, Units.AMPERE));
+                                    toQuantityType(getDouble(emeter.current), DIGITS_AMPERE, Units.AMPERE));
                             updated |= thingHandler.updateChannel(groupName, CHANNEL_EMETER_PFACTOR,
                                     toQuantityType(computePF(emeter), Units.PERCENT));
 
@@ -404,8 +387,7 @@ public class ShellyComponents {
             if ((sdata.sensor != null) && sdata.sensor.isValid) {
                 // Shelly DW: “sensor”:{“state”:“open”, “is_valid”:true},
                 updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_STATE,
-                        getString(sdata.sensor.state).equalsIgnoreCase(SHELLY_API_DWSTATE_OPEN) ? OpenClosedType.OPEN
-                                : OpenClosedType.CLOSED);
+                        getOpenClosed(getString(sdata.sensor.state).equalsIgnoreCase(SHELLY_API_DWSTATE_OPEN)));
                 String sensorError = sdata.sensorError;
                 boolean changed = thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_ERROR,
                         getStringType(sensorError));
@@ -414,17 +396,12 @@ public class ShellyComponents {
                 }
                 updated |= changed;
             }
-            if ((sdata.tmp != null) && getBool(sdata.tmp.isValid)) {
+            if (sdata.tmp != null && getBool(sdata.tmp.isValid)) {
                 Double temp = getString(sdata.tmp.units).toUpperCase().equals(SHELLY_TEMP_CELSIUS)
                         ? getDouble(sdata.tmp.tC)
                         : getDouble(sdata.tmp.tF);
-                if (getString(sdata.tmp.units).toUpperCase().equals(SHELLY_TEMP_FAHRENHEIT)) {
-                    // convert Fahrenheit to Celsius
-                    temp = ImperialUnits.FAHRENHEIT.getConverterTo(SIUnits.CELSIUS).convert(temp).doubleValue();
-                }
-                temp = convertToC(temp, getString(sdata.tmp.units));
-                updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_TEMP,
-                        toQuantityType(temp.doubleValue(), DIGITS_TEMP, SIUnits.CELSIUS));
+                updated |= updateTempChannel(thingHandler, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_TEMP,
+                        temp.doubleValue(), getString(sdata.tmp.units));
             } else if (status.thermostats != null) {
                 // Shelly TRV
                 if (profile.settings.thermostats != null) {
@@ -438,24 +415,25 @@ public class ShellyComponents {
                             toQuantityType((double) bminutes, DIGITS_NONE, Units.MINUTE));
                     updated |= thingHandler.updateChannel(CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_MODE, getStringType(
                             getBool(t.targetTemp.enabled) ? SHELLY_TRV_MODE_AUTO : SHELLY_TRV_MODE_MANUAL));
+                    updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_OPEN,
+                            getOpenClosed(t.windowOpen));
+
                     int pid = getBool(t.schedule) ? getInteger(t.profile) : 0;
                     updated |= thingHandler.updateChannel(CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_SCHEDULE,
                             getOnOff(t.schedule));
                     updated |= thingHandler.updateChannel(CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_PROFILE,
                             getStringType(profile.getValueProfile(0, pid)));
                     if (t.tmp != null) {
-                        Double temp = convertToC(t.tmp.value, getString(t.tmp.units));
-                        updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_TEMP,
-                                toQuantityType(temp.doubleValue(), DIGITS_TEMP, SIUnits.CELSIUS));
-                        temp = convertToC(t.targetTemp.value, getString(t.targetTemp.unit));
-                        updated |= thingHandler.updateChannel(CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_SETTEMP,
-                                toQuantityType(t.targetTemp.value, DIGITS_TEMP, SIUnits.CELSIUS));
+                        updated |= updateTempChannel(thingHandler, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_TEMP,
+                                t.tmp.value, t.tmp.units);
+                        updated |= updateTempChannel(thingHandler, CHANNEL_GROUP_SENSOR, CHANNEL_CONTROL_SETTEMP,
+                                t.targetTemp.value, t.targetTemp.unit);
                     }
                     if (t.pos != null) {
                         updated |= thingHandler.updateChannel(CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_POSITION,
                                 t.pos != -1 ? toQuantityType(t.pos, DIGITS_NONE, Units.PERCENT) : UnDefType.UNDEF);
                         updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_STATE,
-                                getDouble(t.pos) > 0 ? OpenClosedType.OPEN : OpenClosedType.CLOSED);
+                                getOpenClosed(getDouble(t.pos) > 0));
                     }
                 }
             }
@@ -485,6 +463,10 @@ public class ShellyComponents {
                 updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_SMOKE,
                         getOnOff(sdata.smoke));
             }
+            if (sdata.mute != null) {
+                updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_MUTE, getOnOff(sdata.mute));
+            }
+
             if (sdata.gasSensor != null) {
                 updated |= thingHandler.updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_SELFTTEST,
                         getStringType(sdata.gasSensor.selfTestState));
@@ -506,7 +488,7 @@ public class ShellyComponents {
             boolean charger = (getInteger(profile.settings.externalPower) == 1) || getBool(sdata.charger);
             if ((profile.settings.externalPower != null) || (sdata.charger != null)) {
                 updated |= thingHandler.updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_CHARGER,
-                        charger ? OnOffType.ON : OnOffType.OFF);
+                        getOnOff(charger));
             }
             if (sdata.bat != null) { // no update for Sense
                 updated |= thingHandler.updateChannel(CHANNEL_GROUP_BATTERY, CHANNEL_SENSOR_BAT_LEVEL,
@@ -514,7 +496,7 @@ public class ShellyComponents {
 
                 int lowBattery = thingHandler.getThingConfig().lowBattery;
                 boolean changed = thingHandler.updateChannel(CHANNEL_GROUP_BATTERY, CHANNEL_SENSOR_BAT_LOW,
-                        !charger && getDouble(sdata.bat.value) < lowBattery ? OnOffType.ON : OnOffType.OFF);
+                        getOnOff(!charger && getDouble(sdata.bat.value) < lowBattery));
                 updated |= changed;
                 if (!charger && changed && getDouble(sdata.bat.value) < lowBattery) {
                     thingHandler.postEvent(ALARM_TYPE_LOW_BATTERY, false);
@@ -546,11 +528,25 @@ public class ShellyComponents {
         return updated;
     }
 
-    private static Double convertToC(@Nullable Double temp, String unit) {
-        if (temp == null) {
-            return 0.0;
+    public static boolean updateTempChannel(@Nullable ShellyShortTemp sensor, ShellyThingInterface thingHandler,
+            String channel) {
+        return sensor != null ? updateTempChannel(thingHandler, CHANNEL_GROUP_SENSOR, channel, sensor.tC, "") : false;
+    }
+
+    public static boolean updateTempChannel(ShellyThingInterface thingHandler, String group, String channel,
+            @Nullable Double temp, @Nullable String unit) {
+        if (temp == null || temp == SHELLY_API_INVTEMP) {
+            return false;
+        }
+        return thingHandler.updateChannel(group, channel,
+                toQuantityType(convertToC(temp, unit), DIGITS_TEMP, SIUnits.CELSIUS));
+    }
+
+    private static Double convertToC(@Nullable Double temp, @Nullable String unit) {
+        if (temp == null || temp == SHELLY_API_INVTEMP) {
+            return SHELLY_API_INVTEMP;
         }
-        if (SHELLY_TEMP_FAHRENHEIT.equalsIgnoreCase(unit)) {
+        if (SHELLY_TEMP_FAHRENHEIT.equalsIgnoreCase(getString(unit))) {
             // convert Fahrenheit to Celsius
             return ImperialUnits.FAHRENHEIT.getConverterTo(SIUnits.CELSIUS).convert(temp).doubleValue();
         }
index c52cffc5ba0ff23f6b6d988e90f5e4b416c27276..ca15d5491595da59807d01551f7013517e61a486 100644 (file)
@@ -137,6 +137,12 @@ public class ShellyRelayHandler extends ShellyBaseHandler {
                 logger.debug("{}: Set Auto-OFF timer to {}", thingName, command);
                 api.setAutoTimer(rIndex, SHELLY_TIMER_AUTOOFF, getNumber(command).doubleValue());
                 break;
+            case CHANNEL_EMETER_RESETTOTAL:
+                logger.debug("{}: Reset Meter Totals", thingName);
+                int mIndex = Integer.parseInt(substringAfter(groupName, CHANNEL_GROUP_METER)) - 1;
+                api.resetMeterTotal(mIndex);
+                updateChannel(groupName, CHANNEL_EMETER_RESETTOTAL, OnOffType.OFF);
+                break;
         }
         return true;
     }
index 92fc5b788e843a698dca49ec148105bd6f5c60a8..8fc932094d279fc32f6db689d38aed7c06fd0e68 100644 (file)
@@ -54,6 +54,8 @@ public interface ShellyThingInterface {
 
     void setThingOffline(ThingStatusDetail detail, String messageKey, Object... arguments);
 
+    boolean isStopping();
+
     String getThingType();
 
     ThingStatus getThingStatus();
index 91c1a5bb0dd21424a9b5384240e42d5bfe354122..ef47191441e1cab1f939443560bcf662a1377ca2 100644 (file)
@@ -381,18 +381,18 @@ public class ShellyManagerActionPage extends ShellyManagerPage {
             list.put(ACTION_PROTECT, "Protect Device");
         }
 
-        if ((profile.settings.coiot != null) && profile.settings.coiot.peer != null) {
+        if (profile.settings.coiot != null && profile.settings.coiot.peer != null) {
             boolean mcast = profile.settings.coiot.peer.isEmpty()
                     || SHELLY_COIOT_MCAST.equalsIgnoreCase(profile.settings.coiot.peer) || profile.isMotion;
             list.put(mcast ? ACTION_SETCOIOT_PEER : ACTION_SETCOIOT_MCAST,
                     mcast ? "Set CoIoT Peer Mode" : "Set CoIoT Multicast Mode");
         }
         if (profile.isSensor && !profile.isMotion && profile.settings.wifiSta != null
-                && profile.settings.wifiSta.enabled) {
+                && getBool(profile.settings.wifiSta.enabled)) {
             // FW 1.10+: Reset STA list, force WiFi rescan and connect to stringest AP
             list.put(ACTION_RESSTA, "Reconnect WiFi");
         }
-        if (!gen2 && profile.settings.apRoaming != null) {
+        if (!gen2 && profile.settings.apRoaming != null && profile.settings.apRoaming.enabled != null) {
             list.put(!profile.settings.apRoaming.enabled ? ACTION_ENAPROAMING : ACTION_DISAPROAMING,
                     !profile.settings.apRoaming.enabled ? "Enable WiFi Roaming" : "Disable WiFi Roaming");
         }
@@ -413,7 +413,7 @@ public class ShellyManagerActionPage extends ShellyManagerPage {
                     !profile.settings.bluetooth ? "Enable Bluetooth" : "Disable Bluetooth");
         }
 
-        boolean set = profile.settings.cloud != null && profile.settings.cloud.enabled;
+        boolean set = profile.settings.cloud != null && getBool(profile.settings.cloud.enabled);
         list.put(set ? ACTION_DISCLOUD : ACTION_ENCLOUD, set ? "Disable Cloud" : "Enable Cloud");
 
         list.put(ACTION_RESET, "-Factory Reset");
index ed7d9eecf772470f16bb0a36ed1ad51c7e94f0d5..7dd2d9c3d37d7c6139948855d5ffb4ba9faacaeb 100644 (file)
@@ -199,6 +199,7 @@ public class ShellyChannelDefinitions {
                 .add(new ShellyChannel(m, CHGR_METER, CHANNEL_EMETER_VOLTAGE, "meterVoltage", ITEMT_VOLT))
                 .add(new ShellyChannel(m, CHGR_METER, CHANNEL_EMETER_CURRENT, "meterCurrent", ITEMT_AMP))
                 .add(new ShellyChannel(m, CHGR_METER, CHANNEL_EMETER_PFACTOR, "meterPowerFactor", ITEMT_NUMBER))
+                .add(new ShellyChannel(m, CHGR_METER, CHANNEL_EMETER_RESETTOTAL, "meterResetTotals", ITEMT_SWITCH))
 
                 // Sensors
                 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_TEMP, "sensorTemp", ITEMT_TEMP))
@@ -207,6 +208,7 @@ public class ShellyChannelDefinitions {
                 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_ILLUM, "sensorIllumination", ITEMT_STRING))
                 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_VOLTAGE, "sensorADC", ITEMT_VOLT))
                 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_STATE, "sensorContact", ITEMT_CONTACT))
+                .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_OPEN, "sensorOpen", ITEMT_CONTACT))
                 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_SSTATE, "sensorState", ITEMT_STRING))
                 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_TILT, "sensorTilt", ITEMT_ANGLE))
                 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_MOTION, "sensorMotion", ITEMT_SWITCH))
@@ -215,6 +217,7 @@ public class ShellyChannelDefinitions {
                 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_VIBRATION, "vibration", 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))
                 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_PPM, "sensorPPM", ITEMT_NUMBER))
                 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_VALVE, "sensorValve", ITEMT_STRING))
                 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_ALARM_STATE, "alarmState", ITEMT_STRING))
@@ -455,8 +458,8 @@ public class ShellyChannelDefinitions {
         return newChannels;
     }
 
-    public static Map<String, Channel> createEMeterChannels(final Thing thing, final ShellySettingsEMeter emeter,
-            String group) {
+    public static Map<String, Channel> createEMeterChannels(final Thing thing, final ShellyDeviceProfile profile,
+            final ShellySettingsEMeter emeter, String group) {
         Map<String, Channel> newChannels = new LinkedHashMap<>();
         addChannel(thing, newChannels, emeter.power != null, group, CHANNEL_METER_CURRENTWATTS);
         addChannel(thing, newChannels, emeter.total != null, group, CHANNEL_METER_TOTALKWH);
@@ -465,7 +468,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, true, group, CHANNEL_LAST_UPDATE);
         return newChannels;
     }
@@ -482,7 +485,8 @@ public class ShellyChannelDefinitions {
         addChannel(thing, newChannels, sdata.lux != null && sdata.lux.illumination != null, CHANNEL_GROUP_SENSOR,
                 CHANNEL_SENSOR_ILLUM);
         addChannel(thing, newChannels, sdata.flood != null, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_FLOOD);
-        addChannel(thing, newChannels, sdata.smoke != null, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_FLOOD);
+        addChannel(thing, newChannels, sdata.smoke != null, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_SMOKE);
+        addChannel(thing, newChannels, sdata.mute != null, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_MUTE);
         addChannel(thing, newChannels, profile.settings.externalPower != null || sdata.charger != null, CHGR_DEVST,
                 CHANNEL_DEVST_CHARGER);
         addChannel(thing, newChannels, sdata.motion != null || (sdata.sensor != null && sdata.sensor.motion != null),
@@ -528,6 +532,7 @@ public class ShellyChannelDefinitions {
             addChannel(thing, newChannels, true, CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_PROFILE);
             addChannel(thing, newChannels, true, CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_SCHEDULE);
             addChannel(thing, newChannels, true, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_STATE);
+            addChannel(thing, newChannels, true, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_OPEN);
         }
 
         // Battery
index f0cb354b2c91e52fe33bceafbf4c09818db834e5..4cc05cd21e541117c73eb823834aad450470355d 100644 (file)
@@ -37,6 +37,7 @@ import org.openhab.binding.shelly.internal.api.ShellyDeviceProfile;
 import org.openhab.core.library.types.DateTimeType;
 import org.openhab.core.library.types.DecimalType;
 import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.library.types.OpenClosedType;
 import org.openhab.core.library.types.PercentType;
 import org.openhab.core.library.types.QuantityType;
 import org.openhab.core.library.types.StringType;
@@ -245,7 +246,11 @@ public class ShellyUtils {
     }
 
     public static OnOffType getOnOff(@Nullable Boolean value) {
-        return (value != null ? value ? OnOffType.ON : OnOffType.OFF : OnOffType.OFF);
+        return (value != null && value ? OnOffType.ON : OnOffType.OFF);
+    }
+
+    public static OpenClosedType getOpenClosed(@Nullable Boolean value) {
+        return (value != null && value ? OpenClosedType.OPEN : OpenClosedType.CLOSED);
     }
 
     public static OnOffType getOnOff(int value) {
index 68fa3f2f1c06d3d72f60543f4aebe509b0e9219e..bec2fb5ce18db0f8b0cb4ad1a7ed6414a6e3fa68 100644 (file)
@@ -88,20 +88,24 @@ 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/Pro devices
+# 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.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.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.shellypro3em.description = Shelly Pro 3EM - 3xPower Meter
 thing-type.shelly.shellypro4pm.description = Shelly Pro 4PM - 4xRelay Switch with Power Meter
 
 
@@ -111,6 +115,7 @@ thing-type.shelly.shellypro4pm.description = Shelly Pro 4PM - 4xRelay Switch wit
  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.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
  thing-type.shelly.shellypro1.description = Shelly Pro 1 - Single Relay Switch
@@ -290,6 +295,8 @@ channel-type.shelly.lastPower1.label = Last Power
 channel-type.shelly.lastPower1.description = Last power consumption #1 - one rounded minute
 channel-type.shelly.meterTotal.label = Total Energy Consumption
 channel-type.shelly.meterTotal.description = Total energy consumption in kW/h since the device powered up (resets on restart)
+channel-type.shelly.meterResetTotals.label = Reset Totals
+channel-type.shelly.meterResetTotals.description = Resets totals measurement data
 channel-type.shelly.meterReturned.label = Total Returned Energy
 channel-type.shelly.meterReturned.description = Total returned energy in kW/h
 channel-type.shelly.meterVoltage.label = Voltage
@@ -348,6 +355,8 @@ channel-type.shelly.sensorFlood.label = Flood Alarm
 channel-type.shelly.sensorFlood.description = Indicates flood / water detection when toggled ON
 channel-type.shelly.sensorSmoke.label = Smoke Alarm
 channel-type.shelly.sensorSmoke.description = Indicates smoke detection when toggled ON
+channel-type.shelly.sensorMute.label = Mute
+channel-type.shelly.sensorMute.description = Indicates mute setting (ON=muted)
 channel-type.shelly.sensorLux.label = Lux
 channel-type.shelly.sensorLux.description = Brightness from the sensor (Lux)
 channel-type.shelly.sensorIllumination.label = Illumination
@@ -398,6 +407,10 @@ channel-type.shelly.sensorContact.label = State
 channel-type.shelly.sensorContact.description = State of the contact (open/closed)
 channel-type.shelly.sensorContact.state.option.OPEN = Open
 channel-type.shelly.sensorContact.state.option.CLOSED = Closed
+channel-type.shelly.sensorOpen.label = Open
+channel-type.shelly.sensorOpen.description = OPEN or CLOSED
+channel-type.shelly.sensorOpen.state.option.OPEN = Open
+channel-type.shelly.sensorOpen.state.option.CLOSED = Closed
 channel-type.shelly.sensorState.label = Sensor State
 channel-type.shelly.sensorState.description = Sensor State (Warm-Up/Normal/Fault/Unknown)
 channel-type.shelly.sensorState.state.option.warmup = Warm-Up
index ebf4375ff7567d99fc97980bf99b872677c90632..e7e5e13ef92db3ee8bb1908ca8d43a4dc835eeb7 100644 (file)
                </state>
        </channel-type>
 
+       <channel-type id="meterResetTotals">
+               <item-type>Switch</item-type>
+               <label>@text/channel-type.shelly.meterResetTotals.label</label>
+               <description>@text/channel-type.shelly.meterResetTotals.description</description>
+       </channel-type>
+
        <channel-type id="timestamp">
                <item-type>DateTime</item-type>
                <label>@text/channel-type.shelly.timestamp.label</label>
index 0959c98b7c7035c0a402ddc0ec95fcd4de5c3436..dc52f955ff906324112ebc852e64e2137a6c39c2 100644 (file)
                </state>
        </channel-type>
 
+       <channel-type id="sensorOpen">
+               <item-type>Contact</item-type>
+               <label>@text/channel-type.shelly.sensorOpen.label</label>
+               <description>@text/channel-type.shelly.sensorOpen.description</description>
+               <state pattern="%s" readOnly="true">
+                       <options>
+                               <option value="OPEN">@text/channel-type.shelly.sensorOpen.state.option.OPEN</option>
+                               <option value="CLOSED">@text/channel-type.shelly.sensorOpen.state.option.CLOSED</option>
+                       </options>
+               </state>
+       </channel-type>
+
        <channel-type id="sensorState">
                <item-type>String</item-type>
                <label>@text/channel-type.shelly.sensorState.label</label>
                </state>
        </channel-type>
 
+       <channel-type id="sensorMute">
+               <item-type>Switch</item-type>
+               <label>@text/channel-type.shelly.sensorMute.label</label>
+               <description>@text/channel-type.shelly.sensorMute.description</description>
+       </channel-type>
+
        <channel-type id="sensorLux">
                <item-type>Number:Illuminance</item-type>
                <label>@text/channel-type.shelly.sensorLux.label</label>
index 3e270263b56a98abd4661144b5fe7490b80b8bbb..d98a8440bca7cda31913630d9b59b060dbd8a923 100644 (file)
                <config-description-ref uri="thing-type:shelly:roller-gen2"/>
        </thing-type>
 
+       <thing-type id="shellyplusplug">
+               <label>ShellyPlus Plug</label>
+               <description>@text/thing-type.shelly.shellyplusplug.description</description>
+               <category>PowerOutlet</category>
+               <channel-groups>
+                       <channel-group id="relay" typeId="relayChannelPlug"/>
+                       <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:relay-gen2"/>
+       </thing-type>
+
 
        <thing-type id="shellyplusi4">
                <label>ShellyPlus i4</label>
                <config-description-ref uri="thing-type:shelly:relay-gen2"/>
        </thing-type>
 
+       <thing-type id="shellypro3em">
+               <label>Shelly Pro 3EM</label>
+               <description>@text/thing-type.shelly.shellypro3em.description</description>
+               <channel-groups>
+                       <channel-group id="meter1" typeId="meter">
+                               <label>@text/channel-group-type.shelly.meter1.label</label>
+                       </channel-group>
+                       <channel-group id="meter2" typeId="meter">
+                               <label>@text/channel-group-type.shelly.meter2.label</label>
+                       </channel-group>
+                       <channel-group id="meter3" typeId="meter">
+                               <label>@text/channel-group-type.shelly.meter3.label</label>
+                       </channel-group>
+                       <channel-group id="relay" typeId="relayChannel"/>
+                       <channel-group id="device" typeId="deviceStatus"/>
+               </channel-groups>
+
+               <representation-property>serviceName</representation-property>
+               <config-description-ref uri="thing-type:shelly:relay"/>
+       </thing-type>
 
        <thing-type id="shellypro4pm">
                <label>ShellyPro 4PM</label>
index 3a11e580fc33bf64eb5d303c8a2bd76daa03840c..3b3384b2816c9e67256944d2546dbb76fb205d44 100644 (file)
                <config-description-ref uri="thing-type:shelly:battery-gen2"/>
        </thing-type>
 
+       <thing-type id="shellyplussmoke">
+               <label>Shelly Plus Smoke</label>
+               <description>@text/thing-type.shelly.shellyplussmoke.description</description>
+               <category>SmokeDetector</category>
+               <channel-groups>
+                       <channel-group id="sensors" typeId="sensorData"/>
+                       <channel-group id="battery" typeId="batteryStatus"/>
+                       <channel-group id="device" typeId="deviceStatus"/>
+               </channel-groups>
+
+               <representation-property>serviceName</representation-property>
+               <config-description-ref uri="thing-type:shelly:battery-gen2"/>
+       </thing-type>
+
 </thing:thing-descriptions>