diff --git a/bundles/org.openhab.binding.shelly/README.md b/bundles/org.openhab.binding.shelly/README.md index 84a2e72e1cc..b00cb97aa37 100644 --- a/bundles/org.openhab.binding.shelly/README.md +++ b/bundles/org.openhab.binding.shelly/README.md @@ -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 | diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/ShellyBindingConstants.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/ShellyBindingConstants.java index 8b30cf31cac..57d68c68842 100755 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/ShellyBindingConstants.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/ShellyBindingConstants.java @@ -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; diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyApiInterface.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyApiInterface.java index 9904ed97f92..f238ba50192 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyApiInterface.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyApiInterface.java @@ -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; diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyDeviceProfile.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyDeviceProfile.java index 0d1b05dbf6b..5f96c5280e5 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyDeviceProfile.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyDeviceProfile.java @@ -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); diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1ApiJsonDTO.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1ApiJsonDTO.java index c730aa8d9f9..6c1f1ff8cdb 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1ApiJsonDTO.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1ApiJsonDTO.java @@ -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 diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1CoIoTProtocol.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1CoIoTProtocol.java index 733b3c513c1..50f614ce7a9 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1CoIoTProtocol.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1CoIoTProtocol.java @@ -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]); diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1CoIoTVersion2.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1CoIoTVersion2.java index 438ba5a894f..0e5384791f8 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1CoIoTVersion2.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1CoIoTVersion2.java @@ -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 diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1CoapHandler.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1CoapHandler.java index 2d605dba427..68a4e9262f4 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1CoapHandler.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1CoapHandler.java @@ -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(); diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1HttpApi.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1HttpApi.java index eb5f7ba9d9a..0972cfec81b 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1HttpApi.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api1/Shelly1HttpApi.java @@ -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 * diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api2/Shelly2ApiClient.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api2/Shelly2ApiClient.java index 97fb99ca26d..c871e20dc4a 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api2/Shelly2ApiClient.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api2/Shelly2ApiClient.java @@ -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; diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api2/Shelly2ApiJsonDTO.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api2/Shelly2ApiJsonDTO.java index ff33990f74c..e52ead46054 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api2/Shelly2ApiJsonDTO.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api2/Shelly2ApiJsonDTO.java @@ -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; diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api2/Shelly2ApiRpc.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api2/Shelly2ApiRpc.java index c054b9256d7..e387019333e 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api2/Shelly2ApiRpc.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api2/Shelly2ApiRpc.java @@ -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(); diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/discovery/ShellyThingCreator.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/discovery/ShellyThingCreator.java index 49857062b1a..9d443d0237e 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/discovery/ShellyThingCreator.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/discovery/ShellyThingCreator.java @@ -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); } diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyBaseHandler.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyBaseHandler.java index c3bd77c3403..332f4962de0 100755 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyBaseHandler.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyBaseHandler.java @@ -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 = ""; diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyComponents.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyComponents.java index 572bd4c7897..7846afde876 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyComponents.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyComponents.java @@ -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; } - if (SHELLY_TEMP_FAHRENHEIT.equalsIgnoreCase(unit)) { + 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(getString(unit))) { // convert Fahrenheit to Celsius return ImperialUnits.FAHRENHEIT.getConverterTo(SIUnits.CELSIUS).convert(temp).doubleValue(); } diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyRelayHandler.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyRelayHandler.java index c52cffc5ba0..ca15d549159 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyRelayHandler.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyRelayHandler.java @@ -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; } diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyThingInterface.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyThingInterface.java index 92fc5b788e8..8fc932094d2 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyThingInterface.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyThingInterface.java @@ -54,6 +54,8 @@ public interface ShellyThingInterface { void setThingOffline(ThingStatusDetail detail, String messageKey, Object... arguments); + boolean isStopping(); + String getThingType(); ThingStatus getThingStatus(); diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/manager/ShellyManagerActionPage.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/manager/ShellyManagerActionPage.java index 91c1a5bb0dd..ef47191441e 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/manager/ShellyManagerActionPage.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/manager/ShellyManagerActionPage.java @@ -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"); diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/provider/ShellyChannelDefinitions.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/provider/ShellyChannelDefinitions.java index ed7d9eecf77..7dd2d9c3d37 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/provider/ShellyChannelDefinitions.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/provider/ShellyChannelDefinitions.java @@ -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 createEMeterChannels(final Thing thing, final ShellySettingsEMeter emeter, - String group) { + public static Map createEMeterChannels(final Thing thing, final ShellyDeviceProfile profile, + final ShellySettingsEMeter emeter, String group) { Map 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 diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/util/ShellyUtils.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/util/ShellyUtils.java index f0cb354b2c9..4cc05cd21e5 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/util/ShellyUtils.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/util/ShellyUtils.java @@ -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) { diff --git a/bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/i18n/shelly.properties b/bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/i18n/shelly.properties index 68fa3f2f1c0..bec2fb5ce18 100644 --- a/bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/i18n/shelly.properties +++ b/bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/i18n/shelly.properties @@ -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 diff --git a/bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/thing/shellyGen1_relay.xml b/bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/thing/shellyGen1_relay.xml index ebf4375ff75..e7e5e13ef92 100644 --- a/bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/thing/shellyGen1_relay.xml +++ b/bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/thing/shellyGen1_relay.xml @@ -580,6 +580,12 @@ + + Switch + + @text/channel-type.shelly.meterResetTotals.description + + DateTime diff --git a/bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/thing/shellyGen1_sensor.xml b/bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/thing/shellyGen1_sensor.xml index 0959c98b7c7..dc52f955ff9 100644 --- a/bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/thing/shellyGen1_sensor.xml +++ b/bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/thing/shellyGen1_sensor.xml @@ -243,6 +243,18 @@ + + Contact + + @text/channel-type.shelly.sensorOpen.description + + + + + + + + String @@ -339,6 +351,12 @@ + + Switch + + @text/channel-type.shelly.sensorMute.description + + Number:Illuminance diff --git a/bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/thing/shellyGen2_relay.xml b/bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/thing/shellyGen2_relay.xml index 3e270263b56..d98a8440bca 100644 --- a/bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/thing/shellyGen2_relay.xml +++ b/bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/thing/shellyGen2_relay.xml @@ -60,6 +60,20 @@ + + + @text/thing-type.shelly.shellyplusplug.description + PowerOutlet + + + + + + + serviceName + + + @@ -219,6 +233,26 @@ + + + @text/thing-type.shelly.shellypro3em.description + + + + + + + + + + + + + + + serviceName + + diff --git a/bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/thing/shellyGen2_sensor.xml b/bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/thing/shellyGen2_sensor.xml index 3a11e580fc3..3b3384b2816 100644 --- a/bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/thing/shellyGen2_sensor.xml +++ b/bundles/org.openhab.binding.shelly/src/main/resources/OH-INF/thing/shellyGen2_sensor.xml @@ -18,4 +18,18 @@ + + + @text/thing-type.shelly.shellyplussmoke.description + SmokeDetector + + + + + + + serviceName + + +