[shelly] Support for Plus Smoke, Plus Plug-S/IT/UK/US, Plus Dimmer US, Pro 3EM; fix Gen1 sensor initialization (#14532)

* 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>
This commit is contained in:
Markus Michels
2023-05-24 14:20:11 +02:00
committed by GitHub
parent df9c270acf
commit 1f774db959
25 changed files with 568 additions and 116 deletions

View File

@@ -76,27 +76,33 @@ The binding provides the same feature set across all devices as good as possible
### Generation 2 Plus series ### Generation 2 Plus series
| thing-type | Model | Vendor ID | | thing-type | Model | Vendor ID |
| -------------------- | -------------------------------------------------------- | ------------- | | -------------------- | -------------------------------------------------------- | --------------------------------------------- |
| shellyplus1 | Shelly Plus 1 with 1x relay | SNSW-001X16EU | | shellyplus1 | Shelly Plus 1 with 1x relay | SNSW-001X16EU |
| shellyplus1pm | Shelly Plus 1PM with 1x relay + power meter | SNSW-001P16EU | | 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-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 | | shellyplus2pm-roller | Shelly Plus 2PM with 2x relay + power meter, roller mode | SNSW-002P16EU, SNSW-102P16EU |
| shellyplusi4 | Shelly Plus i4 with 4x AC input | SNSN-0024X | | shellyplusplug | Shelly Plug-S | SNPL-00112EU |
| shellyplusi4dc | Shelly Plus i4 with 4x DC input | SNSN-0D24X | | shellyplusplug | Shelly Plug-IT | SNPL-00110IT |
| shellyplusht | Shelly Plus HT with temperature + humidity sensor | SNSN-0013A | | 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 ### Generation 2 Pro series
| thing-type | Model | Vendor ID | | thing-type | Model | Vendor ID |
| ------------------- | -------------------------------------------------------- | -------------- | | ------------------- | -------------------------------------------------------- | ---------------------------------------------- |
| shellypro1 | Shelly Pro 1 with 1x relay | SPSW-001XE16EU | | 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 | | 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 | | 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 | | 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 | | 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 | | shellypro3 | Shelly Pro 3 with 3x relay (dry contacts) | SPSW-003XE16EU |
| shellypro4pm | Shelly Pro 4 PM with 4x relay + power meter | SPSW-004PE16EU | | 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 ## 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 | | TEMP_OVER | Above "temperature over" threshold |
| VIBRATION | A vibration/tamper was detected (DW2 only) | | 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 ## 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 | | | voltage | Number | yes | RMS voltage, Volts |
| | current | Number | yes | Current in A | | | current | Number | yes | Current in A |
| | powerFactor | Number | yes | Power Factor in percent | | | 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 | | | lastUpdate | DateTime | yes | Timestamp of the last measurement |
| meter2 | currentWatts | Number | yes | Current power consumption in Watts | | 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) | | | 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 | | | voltage | Number | yes | RMS voltage, Volts |
| | current | Number | yes | Current in A | | | current | Number | yes | Current in A |
| | powerFactor | Number | yes | Power Factor in percent | | | 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 | | | lastUpdate | DateTime | yes | Timestamp of the last measurement |
| meter3 | currentWatts | Number | yes | Current power consumption in Watts | | 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) | | | 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 | | | voltage | Number | yes | RMS voltage, Volts |
| | current | Number | yes | Current in A | | | current | Number | yes | Current in A |
| | powerFactor | Number | yes | Power Factor in percent | | | 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 | | | lastUpdate | DateTime | yes | Timestamp of the last measurement |
### Shelly 2 - relay mode (thing-type: shelly2-relay) ### 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 | | sensors | temperature | Number | yes | Current Temperature in °C |
| | state | Contact | yes | Valve status: OPEN or CLOSED (position = 0) | | | 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) | | | 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 | | 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) | | | 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. 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. 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) ### Shelly Plus i4, i4DC (thing-types: shellyplusi4, shellyplusi4dc)
| Group | Channel | Type | read-only | Description | | 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 % | | battery | batteryLevel | Number | yes | Battery Level in % |
| | lowBattery | Switch | yes | Low battery alert (< 20%) | | | 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 Series
### Shelly Pro 1 (thing-type: shellypro1) ### 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 | | | timerActive | Switch | yes | Relay #3: ON: An auto-on/off timer is active |
| | button | Trigger | yes | Relay #3: Event trigger, see section Button Events | | | 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) ### Shelly Pro 4PM (thing-type: shelly4pro)
| Group | Channel | Type | read-only | Description | | Group | Channel | Type | read-only | Description |

View File

@@ -77,10 +77,13 @@ public class ShellyBindingConstants {
THING_TYPE_SHELLYPRO2PM_RELAY, // THING_TYPE_SHELLYPRO2PM_RELAY, //
THING_TYPE_SHELLYPRO2PM_ROLLER, // THING_TYPE_SHELLYPRO2PM_ROLLER, //
THING_TYPE_SHELLYPRO3, // THING_TYPE_SHELLYPRO3, //
THING_TYPE_SHELLYPRO3EM, //
THING_TYPE_SHELLYPRO4PM, // THING_TYPE_SHELLYPRO4PM, //
THING_TYPE_SHELLYPLUSI4, // THING_TYPE_SHELLYPLUSI4, //
THING_TYPE_SHELLYPLUSI4DC, // THING_TYPE_SHELLYPLUSI4DC, //
THING_TYPE_SHELLYPLUSHT, // THING_TYPE_SHELLYPLUSHT, //
THING_TYPE_SHELLYPLUSSMOKE, //
THING_TYPE_SHELLYPLUSPLUGS, //
THING_TYPE_SHELLYPLUSPLUGUS, // THING_TYPE_SHELLYPLUSPLUGUS, //
THING_TYPE_SHELLYPROTECTED, // THING_TYPE_SHELLYPROTECTED, //
THING_TYPE_SHELLYUNKNOWN); THING_TYPE_SHELLYUNKNOWN);
@@ -149,6 +152,7 @@ public class ShellyBindingConstants {
public static final String CHANNEL_EMETER_VOLTAGE = "voltage"; public static final String CHANNEL_EMETER_VOLTAGE = "voltage";
public static final String CHANNEL_EMETER_CURRENT = "current"; public static final String CHANNEL_EMETER_CURRENT = "current";
public static final String CHANNEL_EMETER_PFACTOR = "powerFactor"; 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_GROUP_SENSOR = "sensors";
public static final String CHANNEL_SENSOR_TEMP = "temperature"; 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_TILT = "tilt";
public static final String CHANNEL_SENSOR_FLOOD = "flood"; public static final String CHANNEL_SENSOR_FLOOD = "flood";
public static final String CHANNEL_SENSOR_SMOKE = "smoke"; 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_STATE = "state";
public static final String CHANNEL_SENSOR_OPEN = "open";
public static final String CHANNEL_SENSOR_VALVE = "valve"; public static final String CHANNEL_SENSOR_VALVE = "valve";
public static final String CHANNEL_SENSOR_SSTATE = "status"; // Shelly Gas public static final String CHANNEL_SENSOR_SSTATE = "status"; // Shelly Gas
public static final String CHANNEL_SENSOR_MOTION_ACT = "motionActive"; 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_WATT = 2;
public static final int DIGITS_KWH = 3; public static final int DIGITS_KWH = 3;
public static final int DIGITS_VOLT = 1; 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_TEMP = 1;
public static final int DIGITS_LUX = 0; public static final int DIGITS_LUX = 0;
public static final int DIGITS_PERCENT = 1; public static final int DIGITS_PERCENT = 1;

View File

@@ -54,7 +54,9 @@ public interface ShellyApiInterface {
void setRelayTurn(int id, String turnMode) throws ShellyApiException; 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; void setRollerTurn(int relayIndex, String turnMode) throws ShellyApiException;
@@ -91,6 +93,8 @@ public interface ShellyApiInterface {
void startValveBoost(int valveId, int value) throws ShellyApiException; void startValveBoost(int valveId, int value) throws ShellyApiException;
void muteSmokeAlarm(int smokeId) throws ShellyApiException;
ShellyOtaCheckResult checkForUpdate() throws ShellyApiException; ShellyOtaCheckResult checkForUpdate() throws ShellyApiException;
ShellySettingsUpdate firmwareUpdate(String uri) throws ShellyApiException; ShellySettingsUpdate firmwareUpdate(String uri) throws ShellyApiException;

View File

@@ -99,6 +99,7 @@ public class ShellyDeviceProfile {
public boolean isButton = false; // true for a Shelly Button 1 public boolean isButton = false; // true for a Shelly Button 1
public boolean isIX = false; // true for a Shelly IX public boolean isIX = false; // true for a Shelly IX
public boolean isTRV = false; // true for a Shelly TRV 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 minTemp = 0; // Bulb/Duo: Min Light Temp
public int maxTemp = 0; // Bulb/Duo: Max 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 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 isGas = thingType.equals(THING_TYPE_SHELLYGAS_STR);
boolean isUNI = thingType.equals(THING_TYPE_SHELLYUNI_STR); boolean isUNI = thingType.equals(THING_TYPE_SHELLYUNI_STR);
isHT = thingType.equals(THING_TYPE_SHELLYHT_STR) || thingType.equals(THING_TYPE_SHELLYPLUSHT_STR); isHT = thingType.equals(THING_TYPE_SHELLYHT_STR) || thingType.equals(THING_TYPE_SHELLYPLUSHT_STR);

View File

@@ -124,7 +124,7 @@ public class Shelly1ApiJsonDTO {
// //
// API values // 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_MOMENTARY = "momentary";
public static final String SHELLY_BTNT_MOM_ON_RELEASE = "momentary_on_release"; public static final String SHELLY_BTNT_MOM_ON_RELEASE = "momentary_on_release";
@@ -920,6 +920,8 @@ public class Shelly1ApiJsonDTO {
public ShellyThermTemp tmp; public ShellyThermTemp tmp;
@SerializedName("boost_minutes") @SerializedName("boost_minutes")
public Integer boostMinutes; public Integer boostMinutes;
@SerializedName("window_open")
public Boolean windowOpen;
} }
public static class ShellySensorTmp { public static class ShellySensorTmp {
@@ -1103,6 +1105,7 @@ public class Shelly1ApiJsonDTO {
public ShellySensorState sensor; public ShellySensorState sensor;
public Boolean smoke; // SHelly Smoke public Boolean smoke; // SHelly Smoke
public Boolean flood; // Shelly Flood: true = flood condition detected public Boolean flood; // Shelly Flood: true = flood condition detected
public Boolean mute; // mute enabled/disabled
@SerializedName("rain_sensor") @SerializedName("rain_sensor")
public Boolean rainSensor; // Shelly Flood: true=in rain mode public Boolean rainSensor; // Shelly Flood: true=in rain mode

View File

@@ -207,11 +207,11 @@ public class Shelly1CoIoTProtocol {
// event count // event count
updateChannel(updates, group, CHANNEL_STATUS_EVENTCOUNT + profile.getInputSuffix(idx), getDecimal(count)); updateChannel(updates, group, CHANNEL_STATUS_EVENTCOUNT + profile.getInputSuffix(idx), getDecimal(count));
logger.trace( 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, thingName, idx, profile.inButtonMode(idx), profile.isButton, profile.hasBattery, serial, count, idx,
lastEventCount[idx]); lastEventCount[idx]);
if (profile.inButtonMode(idx) && ((profile.hasBattery && (count == 1)) if (profile.inButtonMode(idx) && ((profile.hasBattery && count == 1)
|| ((lastEventCount[idx] != -1) && (count != lastEventCount[idx])))) { || (lastEventCount[idx] != -1 && count != lastEventCount[idx]))) {
if (!profile.isButton || (profile.isButton && (serial != 0x200))) { // skip duplicate on wake-up if (!profile.isButton || (profile.isButton && (serial != 0x200))) { // skip duplicate on wake-up
logger.debug("{}: Trigger event {}", thingName, inputEvent[idx]); logger.debug("{}: Trigger event {}", thingName, inputEvent[idx]);
thingHandler.triggerButton(group, idx, inputEvent[idx]); thingHandler.triggerButton(group, idx, inputEvent[idx]);

View 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 // Special handling for TRV, because it uses duplicate ID values with different meanings
switch (sen.id) { switch (sen.id) {
case "3101": // current temp case "3101": // current temp
updateChannel(updates, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_TEMP, if (value != SHELLY_API_INVTEMP) {
toQuantityType(value, DIGITS_TEMP, SIUnits.CELSIUS)); updateChannel(updates, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_TEMP,
toQuantityType(value, DIGITS_TEMP, SIUnits.CELSIUS));
}
break; break;
case "3103": // target temp in C. 4/31, 999=unknown case "3103": // target temp in C. 4/31, 999=unknown
updateChannel(updates, CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_SETTEMP, 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 "3201": // sensor_1: T, extTemp, C, -55/125; unknown 999
case "3301": // sensor_2: T, extTemp, C, -55/125; unknown 999 case "3301": // sensor_2: T, extTemp, C, -55/125; unknown 999
int idx = getExtTempId(sen.id); 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 // 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; String channel = profile.isSensor ? CHANNEL_SENSOR_TEMP : CHANNEL_SENSOR_TEMP + idx;
// Some devices report values = -999 or 99 during fw update // Some devices report values = -999 or 99 during fw update

View File

@@ -208,6 +208,11 @@ public class Shelly1CoapHandler implements Shelly1CoapListener {
logger.debug("{}: CoIoT Message from {} (MID={}): {}", thingName, logger.debug("{}: CoIoT Message from {} (MID={}): {}", thingName,
response.getSourceContext().getPeerAddress(), response.getMID(), response.getPayloadString()); 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()) { if (response.isCanceled() || response.isDuplicate() || response.isRejected()) {
logger.debug("{} ({}): Packet was canceled, rejected or is a duplicate -> discard", thingName, devId); logger.debug("{} ({}): Packet was canceled, rejected or is a duplicate -> discard", thingName, devId);
thingHandler.incProtErrors(); thingHandler.incProtErrors();

View File

@@ -172,8 +172,12 @@ public class Shelly1HttpApi extends ShellyHttpClient implements ShellyApiInterfa
@Override @Override
public void setRelayTurn(int id, String turnMode) throws ShellyApiException { public void setRelayTurn(int id, String turnMode) throws ShellyApiException {
callApi(getControlUriPrefix(id) + "?" + SHELLY_LIGHT_TURN + "=" + turnMode.toLowerCase(), callApi(getControlUriPrefix(id) + "?" + SHELLY_LIGHT_TURN + "=" + turnMode.toLowerCase(), String.class);
ShellyShortLightStatus.class); }
@Override
public void resetMeterTotal(int id) throws ShellyApiException {
callApi(SHELLY_URL_STATUS_EMETER + "/" + id + "/reset_totals=1", ShellyStatusRelay.class);
} }
@Override @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 * Set sensor Action URLs
* *

View 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.Shelly2DeviceConfig.Shelly2GetConfigResult;
import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceStatus.Shelly2DeviceStatusResult; 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.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.Shelly2DeviceStatusHumidity;
import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceStatus.Shelly2DeviceStatusResult.Shelly2DeviceStatusPower; 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.Shelly2DeviceStatusResult.Shelly2DeviceStatusTempId;
import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceStatus.Shelly2InputStatus; import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2DeviceStatus.Shelly2InputStatus;
import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2RelayStatus; import org.openhab.binding.shelly.internal.api2.Shelly2ApiJsonDTO.Shelly2RelayStatus;
@@ -175,11 +177,16 @@ public class Shelly2ApiClient extends ShellyHttpClient {
boolean channelUpdate) throws ShellyApiException { boolean channelUpdate) throws ShellyApiException {
boolean updated = false; boolean updated = false;
if (result.temperature0 != null && !getProfile().isSensor) {
status.temperature = status.tmp.tC = result.temperature0.tC;
}
updated |= updateInputStatus(status, result, channelUpdate); updated |= updateInputStatus(status, result, channelUpdate);
updated |= updateRelayStatus(status, result.switch0, channelUpdate); updated |= updateRelayStatus(status, result.switch0, channelUpdate);
updated |= updateRelayStatus(status, result.switch1, channelUpdate); updated |= updateRelayStatus(status, result.switch1, channelUpdate);
updated |= updateRelayStatus(status, result.switch2, channelUpdate); updated |= updateRelayStatus(status, result.switch2, channelUpdate);
updated |= updateRelayStatus(status, result.switch3, channelUpdate); updated |= updateRelayStatus(status, result.switch3, channelUpdate);
updated |= updateEmStatus(status, result.em0, channelUpdate);
updated |= updateRollerStatus(status, result.cover0, channelUpdate); updated |= updateRollerStatus(status, result.cover0, channelUpdate);
if (channelUpdate) { if (channelUpdate) {
updated |= ShellyComponents.updateMeters(getThing(), status); updated |= ShellyComponents.updateMeters(getThing(), status);
@@ -187,6 +194,7 @@ public class Shelly2ApiClient extends ShellyHttpClient {
updateHumidityStatus(sensorData, result.humidity0); updateHumidityStatus(sensorData, result.humidity0);
updateTemperatureStatus(sensorData, result.temperature0); updateTemperatureStatus(sensorData, result.temperature0);
updateSmokeStatus(sensorData, result.smoke0);
updateBatteryStatus(sensorData, result.devicepower0); updateBatteryStatus(sensorData, result.devicepower0);
updateAddonStatus(status, result); updateAddonStatus(status, result);
updated |= ShellyComponents.updateSensors(getThing(), status); updated |= ShellyComponents.updateSensors(getThing(), status);
@@ -263,14 +271,91 @@ public class Shelly2ApiClient extends ShellyHttpClient {
// Update internal structures // Update internal structures
status.relays.set(rs.id, rstatus); 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.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; 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, protected @Nullable ArrayList<@Nullable ShellySettingsRoller> fillRollerSettings(ShellyDeviceProfile profile,
Shelly2GetConfigResult dc) { Shelly2GetConfigResult dc) {
if (dc.cover0 == null) { if (dc.cover0 == null) {
@@ -360,7 +445,9 @@ public class Shelly2ApiClient extends ShellyHttpClient {
if (cs.aenergy != null) { if (cs.aenergy != null) {
sm.total = emeter.total = cs.aenergy.total; sm.total = emeter.total = cs.aenergy.total;
sm.counters = cs.aenergy.byMinute; 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) { if (cs.voltage != null) {
emeter.voltage = cs.voltage; emeter.voltage = cs.voltage;
@@ -448,6 +535,14 @@ public class Shelly2ApiClient extends ShellyHttpClient {
sdata.tmp.tF = value.tF; 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) { protected void updateBatteryStatus(ShellyStatusSensor sdata, @Nullable Shelly2DeviceStatusPower value) {
if (value == null) { if (value == null) {
return; return;

View File

@@ -56,6 +56,8 @@ public class Shelly2ApiJsonDTO {
public static final String SHELLYRPC_METHOD_CLOUDSET = "Cloud.SetConfig"; public static final String SHELLYRPC_METHOD_CLOUDSET = "Cloud.SetConfig";
public static final String SHELLYRPC_METHOD_WSGETCONFIG = "WS.GetConfig"; public static final String SHELLYRPC_METHOD_WSGETCONFIG = "WS.GetConfig";
public static final String SHELLYRPC_METHOD_WSSETCONFIG = "WS.SetConfig"; 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_NOTIFYSTATUS = "NotifyStatus"; // inbound status
public static final String SHELLYRPC_METHOD_NOTIFYFULLSTATUS = "NotifyFullStatus"; // inbound status from bat device public static final String SHELLYRPC_METHOD_NOTIFYFULLSTATUS = "NotifyFullStatus"; // inbound status from bat device
@@ -283,6 +285,17 @@ public class Shelly2ApiJsonDTO {
public Double currentLimit; 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 Shelly2DevConfigCover {
public class Shelly2DeviceConfigCoverMotor { public class Shelly2DeviceConfigCoverMotor {
@SerializedName("idle_power_thr") @SerializedName("idle_power_thr")
@@ -333,6 +346,12 @@ public class Shelly2ApiJsonDTO {
public Shelly2DeviceConfigCoverObstructionDetection obstructionDetection; public Shelly2DeviceConfigCoverObstructionDetection obstructionDetection;
} }
public static class Shelly2ConfigSmoke {
public Integer id;
public Boolean alarm;
public Boolean mute;
}
public static class Shelly2GetConfigResult { public static class Shelly2GetConfigResult {
public class Shelly2DevConfigCloud { public class Shelly2DevConfigCloud {
@@ -377,8 +396,14 @@ public class Shelly2ApiJsonDTO {
@SerializedName("switch:3") @SerializedName("switch:3")
public Shelly2DevConfigSwitch switch3; public Shelly2DevConfigSwitch switch3;
@SerializedName("em:0")
public Shelly2DevConfigEm em0;
@SerializedName("cover:0") @SerializedName("cover:0")
public Shelly2DevConfigCover cover0; public Shelly2DevConfigCover cover0;
@SerializedName("smoke:0")
public Shelly2ConfigSmoke smoke0;
} }
public class Shelly2DeviceConfigSta { public class Shelly2DeviceConfigSta {
@@ -486,6 +511,57 @@ public class Shelly2ApiJsonDTO {
public Shelly2DeviceStatusCharger external; 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 Shelly2DeviceStatusBle ble;
public Shelly2DeviceStatusCloud cloud; public Shelly2DeviceStatusCloud cloud;
public Shelly2DeviceStatusMqqt mqtt; public Shelly2DeviceStatusMqqt mqtt;
@@ -512,6 +588,11 @@ public class Shelly2ApiJsonDTO {
@SerializedName("switch:3") @SerializedName("switch:3")
public Shelly2RelayStatus switch3; public Shelly2RelayStatus switch3;
@SerializedName("em:0")
Shelly2DeviceStatusEm em0;
@SerializedName("emdata:0")
Shelly2DeviceStatusEmData emdata0;
@SerializedName("cover:0") @SerializedName("cover:0")
public Shelly2CoverStatus cover0; public Shelly2CoverStatus cover0;
@@ -532,6 +613,8 @@ public class Shelly2ApiJsonDTO {
public Shelly2DeviceStatusHumidity humidity0; public Shelly2DeviceStatusHumidity humidity0;
@SerializedName("humidity:100") @SerializedName("humidity:100")
public Shelly2DeviceStatusHumidity humidity100; public Shelly2DeviceStatusHumidity humidity100;
@SerializedName("smoke:0")
public Shelly2DeviceStatusSmoke smoke0;
@SerializedName("voltmeter:100") @SerializedName("voltmeter:100")
public Shelly2DeviceStatusVoltage voltmeter100; public Shelly2DeviceStatusVoltage voltmeter100;

View File

@@ -205,22 +205,15 @@ public class Shelly2ApiRpc extends Shelly2ApiClient implements ShellyApiInterfac
fillWiFiSta(dc.wifi.sta, profile.settings.wifiSta); fillWiFiSta(dc.wifi.sta, profile.settings.wifiSta);
fillWiFiSta(dc.wifi.sta1, profile.settings.wifiSta1); fillWiFiSta(dc.wifi.sta1, profile.settings.wifiSta1);
profile.numMeters = 0;
if (profile.hasRelays) { if (profile.hasRelays) {
profile.status.relays = new ArrayList<>(); profile.status.relays = new ArrayList<>();
profile.status.meters = new ArrayList<>();
profile.status.emeters = new ArrayList<>();
relayStatus.relays = new ArrayList<>(); relayStatus.relays = new ArrayList<>();
relayStatus.meters = new ArrayList<>();
profile.numMeters = profile.isRoller ? profile.numRollers : profile.numRelays; profile.numMeters = profile.isRoller ? profile.numRollers : profile.numRelays;
for (int i = 0; i < profile.numRelays; i++) { for (int i = 0; i < profile.numRelays; i++) {
profile.status.relays.add(new ShellySettingsRelay()); profile.status.relays.add(new ShellySettingsRelay());
relayStatus.relays.add(new ShellyShortStatusRelay()); 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) { 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) { if (profile.isRoller) {
profile.status.rollers = new ArrayList<>(); profile.status.rollers = new ArrayList<>();
for (int i = 0; i < profile.numRollers; i++) { for (int i = 0; i < profile.numRollers; i++) {
@@ -278,7 +287,8 @@ public class Shelly2ApiRpc extends Shelly2ApiClient implements ShellyApiInterfac
private void checkSetWsCallback() throws ShellyApiException { private void checkSetWsCallback() throws ShellyApiException {
Shelly2ConfigParms wsConfig = apiRequest(SHELLYRPC_METHOD_WSGETCONFIG, null, Shelly2ConfigParms.class); Shelly2ConfigParms wsConfig = apiRequest(SHELLYRPC_METHOD_WSGETCONFIG, null, Shelly2ConfigParms.class);
String url = "ws://" + config.localIp + ":" + config.localPort + "/shelly/wsevent"; 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); logger.debug("{}: A battery device was detected without correct callback, fix it", thingName);
wsConfig.enable = true; wsConfig.enable = true;
wsConfig.server = url; wsConfig.server = url;
@@ -314,6 +324,10 @@ public class Shelly2ApiRpc extends Shelly2ApiClient implements ShellyApiInterfac
thingName, thingName, message.src, message.dst, discovery); thingName, thingName, message.src, message.dst, discovery);
return; return;
} }
if (t.isStopping()) {
logger.debug("{}: Thing is shutting down, ignore WebSocket message", thingName);
return;
}
if (!t.isThingOnline() && t.getThingStatusDetail() != ThingStatusDetail.CONFIGURATION_PENDING) { if (!t.isThingOnline() && t.getThingStatusDetail() != ThingStatusDetail.CONFIGURATION_PENDING) {
logger.debug("{}: Thing is not in online state/connectable, ignore NotifyStatus", thingName); logger.debug("{}: Thing is not in online state/connectable, ignore NotifyStatus", thingName);
return; return;
@@ -627,6 +641,15 @@ public class Shelly2ApiRpc extends Shelly2ApiClient implements ShellyApiInterfac
apiRequest(req); 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 @Override
public ShellySettingsLogin getLoginSettings() throws ShellyApiException { public ShellySettingsLogin getLoginSettings() throws ShellyApiException {
return new ShellySettingsLogin(); return new ShellySettingsLogin();

View File

@@ -71,10 +71,14 @@ public class ShellyThingCreator {
public static final String SHELLYDT_PLUS2PM_ROLLER = "SNSW-002P16EU-roller"; 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_RELAY_2 = "SNSW-102P16EU-relay";
public static final String SHELLYDT_PLUS2PM_ROLLER_2 = "SNSW-102P16EU-roller"; 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_PLUSPLUGUS = "SNPL-00116US";
public static final String SHELLYDT_PLUSI4 = "SNSN-0024X"; public static final String SHELLYDT_PLUSI4 = "SNSN-0024X";
public static final String SHELLYDT_PLUSI4DC = "SNSN-0D24X"; public static final String SHELLYDT_PLUSI4DC = "SNSN-0D24X";
public static final String SHELLYDT_PLUSHT = "SNSN-0013A"; public static final String SHELLYDT_PLUSHT = "SNSN-0013A";
public static final String SHELLYDT_PLUSSMOKE = "SNSN-0031Z";
// Shelly Pro Series // Shelly Pro Series
public static final String SHELLYDT_PRO1 = "SPSW-001XE16EU"; 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_RELAY_3 = "SPSW-202PE16EU-relay";
public static final String SHELLYDT_PRO2PM_ROLLER_3 = "SPSW-202PE16EU-roller"; public static final String SHELLYDT_PRO2PM_ROLLER_3 = "SPSW-202PE16EU-roller";
public static final String SHELLYDT_PRO3 = "SPSW-003XE16EU"; 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 = "SPSW-004PE16EU";
public static final String SHELLYDT_PRO4PM_2 = "SPSW-104PE16EU"; 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_SHELLYPLUSI4_STR = "shellyplusi4";
public static final String THING_TYPE_SHELLYPLUSI4DC_STR = "shellyplusi4dc"; public static final String THING_TYPE_SHELLYPLUSI4DC_STR = "shellyplusi4dc";
public static final String THING_TYPE_SHELLYPLUSHT_STR = "shellyplusht"; 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"; public static final String THING_TYPE_SHELLYPLUSPLUGUS_STR = "shellyplusplugus";
// Shelly Pro Series // 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_RELAY_STR = "shellypro2pm-relay";
public static final String THING_TYPE_SHELLYPRO2PM_ROLLER_STR = "shellypro2pm-roller"; 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_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_SHELLYPRO4PM_STR = "shellypro4pm";
public static final String THING_TYPE_SHELLYPROTECTED_STR = "shellydevice"; public static final String THING_TYPE_SHELLYPROTECTED_STR = "shellydevice";
@@ -229,6 +237,10 @@ public class ShellyThingCreator {
THING_TYPE_SHELLYPLUSI4DC_STR); THING_TYPE_SHELLYPLUSI4DC_STR);
public static final ThingTypeUID THING_TYPE_SHELLYPLUSHT = new ThingTypeUID(BINDING_ID, public static final ThingTypeUID THING_TYPE_SHELLYPLUSHT = new ThingTypeUID(BINDING_ID,
THING_TYPE_SHELLYPLUSHT_STR); 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, public static final ThingTypeUID THING_TYPE_SHELLYPLUSPLUGUS = new ThingTypeUID(BINDING_ID,
THING_TYPE_SHELLYPLUSPLUGUS_STR); THING_TYPE_SHELLYPLUSPLUGUS_STR);
public static final ThingTypeUID THING_TYPE_SHELLYPRO1 = new ThingTypeUID(BINDING_ID, THING_TYPE_SHELLYPRO1_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, public static final ThingTypeUID THING_TYPE_SHELLYPRO2PM_ROLLER = new ThingTypeUID(BINDING_ID,
THING_TYPE_SHELLYPRO2PM_ROLLER_STR); 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_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, public static final ThingTypeUID THING_TYPE_SHELLYPRO4PM = new ThingTypeUID(BINDING_ID,
THING_TYPE_SHELLYPRO4PM_STR); 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_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_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_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_PLUSPLUGUS, THING_TYPE_SHELLYPLUSPLUGUS_STR);
THING_TYPE_MAPPING.put(SHELLYDT_PLUSI4DC, THING_TYPE_SHELLYPLUSI4DC_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_PLUSI4, THING_TYPE_SHELLYPLUSI4_STR);
THING_TYPE_MAPPING.put(SHELLYDT_PLUSHT, THING_TYPE_SHELLYPLUSHT_STR); THING_TYPE_MAPPING.put(SHELLYDT_PLUSHT, THING_TYPE_SHELLYPLUSHT_STR);
THING_TYPE_MAPPING.put(SHELLYDT_PLUSSMOKE, THING_TYPE_SHELLYPLUSSMOKE_STR);
// Pro Series // Pro Series
THING_TYPE_MAPPING.put(SHELLYDT_PRO1, THING_TYPE_SHELLYPRO1_STR); 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_2, THING_TYPE_SHELLYPRO2PM_ROLLER_STR);
THING_TYPE_MAPPING.put(SHELLYDT_PRO2PM_ROLLER_3, 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_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, THING_TYPE_SHELLYPRO4PM_STR);
THING_TYPE_MAPPING.put(SHELLYDT_PRO4PM_2, 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_SHELLY1_STR, THING_TYPE_SHELLY1_STR);
THING_TYPE_MAPPING.put(THING_TYPE_SHELLY1PM_STR, THING_TYPE_SHELLY1PM_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_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_SHELLY4PRO_STR, THING_TYPE_SHELLY4PRO_STR);
THING_TYPE_MAPPING.put(THING_TYPE_SHELLYDIMMER2_STR, THING_TYPE_SHELLYDIMMER2_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_SHELLYDIMMER_STR, THING_TYPE_SHELLYDIMMER_STR);
THING_TYPE_MAPPING.put(THING_TYPE_SHELLYIX3_STR, THING_TYPE_SHELLYIX3_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_SHELLYDUORGBW_STR, THING_TYPE_SHELLYDUORGBW_STR);
THING_TYPE_MAPPING.put(THING_TYPE_SHELLYDUO_STR, THING_TYPE_SHELLYDUO_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); 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_SHELLYUNI_STR, THING_TYPE_SHELLYUNI_STR);
THING_TYPE_MAPPING.put(THING_TYPE_SHELLYMOTION2_STR, THING_TYPE_SHELLYMOTION_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); THING_TYPE_MAPPING.put(THING_TYPE_SHELLYPROTECTED_STR, THING_TYPE_SHELLYPROTECTED_STR);
} }

View File

@@ -235,7 +235,8 @@ public abstract class ShellyBaseHandler extends BaseThingHandler
if (coap != null) { if (coap != null) {
coap.stop(); 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 { public boolean initializeThing() throws ShellyApiException {
// Init from thing type to have a basic profile, gets updated when device info is received from API // Init from thing type to have a basic profile, gets updated when device info is received from API
stopping = false;
refreshSettings = false; refreshSettings = false;
lastWakeupReason = ""; lastWakeupReason = "";
cache.setThingName(thingName); cache.setThingName(thingName);
@@ -263,6 +263,8 @@ public abstract class ShellyBaseHandler extends BaseThingHandler
return false; 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 // 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 // could not be fully initialized here. In this case the CoAP messages triggers auto-initialization (like the
// Action URL does when enabled) // Action URL does when enabled)
@@ -272,7 +274,6 @@ public abstract class ShellyBaseHandler extends BaseThingHandler
// Initialize API access, exceptions will be catched by initialize() // Initialize API access, exceptions will be catched by initialize()
api.initialize(); api.initialize();
profile.initFromThingType(thingType);
ShellySettingsDevice devInfo = api.getDeviceInfo(); ShellySettingsDevice devInfo = api.getDeviceInfo();
if (getBool(devInfo.auth) && config.password.isEmpty()) { if (getBool(devInfo.auth) && config.password.isEmpty()) {
setThingOffline(ThingStatusDetail.CONFIGURATION_ERROR, "offline.conf-error-no-credentials"); setThingOffline(ThingStatusDetail.CONFIGURATION_ERROR, "offline.conf-error-no-credentials");
@@ -357,7 +358,7 @@ public abstract class ShellyBaseHandler extends BaseThingHandler
return; return;
} }
if (!profile.isInitialized()) { if (!profile.isInitialized() || (isThingOffline() && profile.alwaysOn)) {
logger.debug("{}: {}", thingName, messages.get("command.init", command)); logger.debug("{}: {}", thingName, messages.get("command.init", command));
initializeThing(); initializeThing();
} else { } else {
@@ -440,7 +441,13 @@ public abstract class ShellyBaseHandler extends BaseThingHandler
logger.debug("{}: Set boost timer to {}", thingName, command); logger.debug("{}: Set boost timer to {}", thingName, command);
api.setValveBoostTime(0, (int) getNumber(command)); api.setValveBoostTime(0, (int) getNumber(command));
break; 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: default:
update = handleDeviceCommand(channelUID, command); update = handleDeviceCommand(channelUID, command);
break; break;
@@ -500,11 +507,7 @@ public abstract class ShellyBaseHandler extends BaseThingHandler
logger.debug("{}: Status update triggered thing initialization", thingName); logger.debug("{}: Status update triggered thing initialization", thingName);
initializeThing(); // may fire an exception if initialization failed initializeThing(); // may fire an exception if initialization failed
} }
// Get profile, if refreshSettings == true reload settings from device
ShellySettingsStatus status = api.getStatus(); ShellySettingsStatus status = api.getStatus();
if (status.uptime != null && status.uptime == 0 && profile.alwaysOn) {
status = api.getStatus();
}
boolean restarted = checkRestarted(status); boolean restarted = checkRestarted(status);
profile = getProfile(refreshSettings || restarted); profile = getProfile(refreshSettings || restarted);
profile.status = status; profile.status = status;
@@ -541,7 +544,7 @@ public abstract class ShellyBaseHandler extends BaseThingHandler
status = "offline.conf-error-access-denied"; status = "offline.conf-error-access-denied";
} else if (isWatchdogStarted()) { } else if (isWatchdogStarted()) {
if (!isWatchdogExpired()) { if (!isWatchdogExpired()) {
logger.debug("{}: Ignore API Timeout, retry later", thingName); logger.debug("{}: Ignore API Timeout on {} {}, retry later", thingName, res.method, res.url);
} else { } else {
if (isThingOnline()) { if (isThingOnline()) {
status = "offline.status-error-watchdog"; status = "offline.status-error-watchdog";
@@ -692,7 +695,7 @@ public abstract class ShellyBaseHandler extends BaseThingHandler
@Override @Override
public void reinitializeThing() { public void reinitializeThing() {
logger.debug("{}: Re-Initialize Thing", thingName); logger.debug("{}: Re-Initialize Thing", thingName);
if (stopping) { if (isStopping()) {
logger.debug("{}: Handler is shutting down, ignore", thingName); logger.debug("{}: Handler is shutting down, ignore", thingName);
return; return;
} }
@@ -701,6 +704,11 @@ public abstract class ShellyBaseHandler extends BaseThingHandler
requestUpdates(0, true); requestUpdates(0, true);
} }
@Override
public boolean isStopping() {
return stopping;
}
@Override @Override
public void fillDeviceStatus(ShellySettingsStatus status, boolean updated) { public void fillDeviceStatus(ShellySettingsStatus status, boolean updated) {
String alarm = ""; String alarm = "";

View 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.ShellySettingsStatus;
import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor; 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.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.api1.Shelly1ApiJsonDTO.ShellyThermnostat;
import org.openhab.binding.shelly.internal.provider.ShellyChannelDefinitions; 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.types.StringType;
import org.openhab.core.library.unit.ImperialUnits; import org.openhab.core.library.unit.ImperialUnits;
import org.openhab.core.library.unit.SIUnits; import org.openhab.core.library.unit.SIUnits;
@@ -113,33 +112,17 @@ public class ShellyComponents {
if (status.extSwitch != null) { if (status.extSwitch != null) {
if (status.extSwitch.input0 != null) { if (status.extSwitch.input0 != null) {
updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_ESENSOR_INPUT1, updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_ESENSOR_INPUT1,
getInteger(status.extSwitch.input0.input) == 1 ? OpenClosedType.OPEN getOpenClosed(getInteger(status.extSwitch.input0.input) == 1));
: OpenClosedType.CLOSED);
} }
} }
if (status.extTemperature != null) { if (status.extTemperature != null) {
// Shelly 1/1PM support up to 3 external sensors // Shelly 1/1PM support up to 3 external sensors
// for whatever reason those are not represented as an array, but 3 elements // for whatever reason those are not represented as an array, but 3 elements
if (status.extTemperature.sensor1 != null) { updated |= updateTempChannel(status.extTemperature.sensor1, thingHandler, CHANNEL_ESENSOR_TEMP1);
updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_ESENSOR_TEMP1, updated |= updateTempChannel(status.extTemperature.sensor2, thingHandler, CHANNEL_ESENSOR_TEMP2);
toQuantityType(getDouble(status.extTemperature.sensor1.tC), DIGITS_TEMP, SIUnits.CELSIUS)); updated |= updateTempChannel(status.extTemperature.sensor3, thingHandler, CHANNEL_ESENSOR_TEMP3);
} updated |= updateTempChannel(status.extTemperature.sensor4, thingHandler, CHANNEL_ESENSOR_TEMP4);
if (status.extTemperature.sensor2 != null) { updated |= updateTempChannel(status.extTemperature.sensor5, thingHandler, CHANNEL_ESENSOR_TEMP5);
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));
}
} }
if ((status.extHumidity != null) && (status.extHumidity.sensor1 != null)) { if ((status.extHumidity != null) && (status.extHumidity.sensor1 != null)) {
updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_ESENSOR_HUMIDITY, updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_ESENSOR_HUMIDITY,
@@ -277,7 +260,7 @@ public class ShellyComponents {
String groupName = profile.getMeterGroup(m); String groupName = profile.getMeterGroup(m);
if (!thingHandler.areChannelsCreated()) { if (!thingHandler.areChannelsCreated()) {
thingHandler.updateChannelDefinitions(ShellyChannelDefinitions thingHandler.updateChannelDefinitions(ShellyChannelDefinitions
.createEMeterChannels(thingHandler.getThing(), emeter, groupName)); .createEMeterChannels(thingHandler.getThing(), profile, emeter, groupName));
} }
// convert Watt/Hour tok w/h // convert Watt/Hour tok w/h
@@ -292,7 +275,7 @@ public class ShellyComponents {
updated |= thingHandler.updateChannel(groupName, CHANNEL_EMETER_VOLTAGE, updated |= thingHandler.updateChannel(groupName, CHANNEL_EMETER_VOLTAGE,
toQuantityType(getDouble(emeter.voltage), DIGITS_VOLT, Units.VOLT)); toQuantityType(getDouble(emeter.voltage), DIGITS_VOLT, Units.VOLT));
updated |= thingHandler.updateChannel(groupName, CHANNEL_EMETER_CURRENT, 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, updated |= thingHandler.updateChannel(groupName, CHANNEL_EMETER_PFACTOR,
toQuantityType(computePF(emeter), Units.PERCENT)); toQuantityType(computePF(emeter), Units.PERCENT));
@@ -404,8 +387,7 @@ public class ShellyComponents {
if ((sdata.sensor != null) && sdata.sensor.isValid) { if ((sdata.sensor != null) && sdata.sensor.isValid) {
// Shelly DW: “sensor”:{“state”:“open”, “is_valid”:true}, // Shelly DW: “sensor”:{“state”:“open”, “is_valid”:true},
updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_STATE, updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_STATE,
getString(sdata.sensor.state).equalsIgnoreCase(SHELLY_API_DWSTATE_OPEN) ? OpenClosedType.OPEN getOpenClosed(getString(sdata.sensor.state).equalsIgnoreCase(SHELLY_API_DWSTATE_OPEN)));
: OpenClosedType.CLOSED);
String sensorError = sdata.sensorError; String sensorError = sdata.sensorError;
boolean changed = thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_ERROR, boolean changed = thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_ERROR,
getStringType(sensorError)); getStringType(sensorError));
@@ -414,17 +396,12 @@ public class ShellyComponents {
} }
updated |= changed; 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) Double temp = getString(sdata.tmp.units).toUpperCase().equals(SHELLY_TEMP_CELSIUS)
? getDouble(sdata.tmp.tC) ? getDouble(sdata.tmp.tC)
: getDouble(sdata.tmp.tF); : getDouble(sdata.tmp.tF);
if (getString(sdata.tmp.units).toUpperCase().equals(SHELLY_TEMP_FAHRENHEIT)) { updated |= updateTempChannel(thingHandler, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_TEMP,
// convert Fahrenheit to Celsius temp.doubleValue(), getString(sdata.tmp.units));
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));
} else if (status.thermostats != null) { } else if (status.thermostats != null) {
// Shelly TRV // Shelly TRV
if (profile.settings.thermostats != null) { if (profile.settings.thermostats != null) {
@@ -438,24 +415,25 @@ public class ShellyComponents {
toQuantityType((double) bminutes, DIGITS_NONE, Units.MINUTE)); toQuantityType((double) bminutes, DIGITS_NONE, Units.MINUTE));
updated |= thingHandler.updateChannel(CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_MODE, getStringType( updated |= thingHandler.updateChannel(CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_MODE, getStringType(
getBool(t.targetTemp.enabled) ? SHELLY_TRV_MODE_AUTO : SHELLY_TRV_MODE_MANUAL)); 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; int pid = getBool(t.schedule) ? getInteger(t.profile) : 0;
updated |= thingHandler.updateChannel(CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_SCHEDULE, updated |= thingHandler.updateChannel(CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_SCHEDULE,
getOnOff(t.schedule)); getOnOff(t.schedule));
updated |= thingHandler.updateChannel(CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_PROFILE, updated |= thingHandler.updateChannel(CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_PROFILE,
getStringType(profile.getValueProfile(0, pid))); getStringType(profile.getValueProfile(0, pid)));
if (t.tmp != null) { if (t.tmp != null) {
Double temp = convertToC(t.tmp.value, getString(t.tmp.units)); updated |= updateTempChannel(thingHandler, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_TEMP,
updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_TEMP, t.tmp.value, t.tmp.units);
toQuantityType(temp.doubleValue(), DIGITS_TEMP, SIUnits.CELSIUS)); updated |= updateTempChannel(thingHandler, CHANNEL_GROUP_SENSOR, CHANNEL_CONTROL_SETTEMP,
temp = convertToC(t.targetTemp.value, getString(t.targetTemp.unit)); t.targetTemp.value, t.targetTemp.unit);
updated |= thingHandler.updateChannel(CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_SETTEMP,
toQuantityType(t.targetTemp.value, DIGITS_TEMP, SIUnits.CELSIUS));
} }
if (t.pos != null) { if (t.pos != null) {
updated |= thingHandler.updateChannel(CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_POSITION, updated |= thingHandler.updateChannel(CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_POSITION,
t.pos != -1 ? toQuantityType(t.pos, DIGITS_NONE, Units.PERCENT) : UnDefType.UNDEF); t.pos != -1 ? toQuantityType(t.pos, DIGITS_NONE, Units.PERCENT) : UnDefType.UNDEF);
updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_STATE, 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, updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_SMOKE,
getOnOff(sdata.smoke)); getOnOff(sdata.smoke));
} }
if (sdata.mute != null) {
updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_MUTE, getOnOff(sdata.mute));
}
if (sdata.gasSensor != null) { if (sdata.gasSensor != null) {
updated |= thingHandler.updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_SELFTTEST, updated |= thingHandler.updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_SELFTTEST,
getStringType(sdata.gasSensor.selfTestState)); getStringType(sdata.gasSensor.selfTestState));
@@ -506,7 +488,7 @@ public class ShellyComponents {
boolean charger = (getInteger(profile.settings.externalPower) == 1) || getBool(sdata.charger); boolean charger = (getInteger(profile.settings.externalPower) == 1) || getBool(sdata.charger);
if ((profile.settings.externalPower != null) || (sdata.charger != null)) { if ((profile.settings.externalPower != null) || (sdata.charger != null)) {
updated |= thingHandler.updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_CHARGER, 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 if (sdata.bat != null) { // no update for Sense
updated |= thingHandler.updateChannel(CHANNEL_GROUP_BATTERY, CHANNEL_SENSOR_BAT_LEVEL, updated |= thingHandler.updateChannel(CHANNEL_GROUP_BATTERY, CHANNEL_SENSOR_BAT_LEVEL,
@@ -514,7 +496,7 @@ public class ShellyComponents {
int lowBattery = thingHandler.getThingConfig().lowBattery; int lowBattery = thingHandler.getThingConfig().lowBattery;
boolean changed = thingHandler.updateChannel(CHANNEL_GROUP_BATTERY, CHANNEL_SENSOR_BAT_LOW, 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; updated |= changed;
if (!charger && changed && getDouble(sdata.bat.value) < lowBattery) { if (!charger && changed && getDouble(sdata.bat.value) < lowBattery) {
thingHandler.postEvent(ALARM_TYPE_LOW_BATTERY, false); thingHandler.postEvent(ALARM_TYPE_LOW_BATTERY, false);
@@ -546,11 +528,25 @@ public class ShellyComponents {
return updated; return updated;
} }
private static Double convertToC(@Nullable Double temp, String unit) { public static boolean updateTempChannel(@Nullable ShellyShortTemp sensor, ShellyThingInterface thingHandler,
if (temp == null) { String channel) {
return 0.0; 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 // convert Fahrenheit to Celsius
return ImperialUnits.FAHRENHEIT.getConverterTo(SIUnits.CELSIUS).convert(temp).doubleValue(); return ImperialUnits.FAHRENHEIT.getConverterTo(SIUnits.CELSIUS).convert(temp).doubleValue();
} }

View File

@@ -137,6 +137,12 @@ public class ShellyRelayHandler extends ShellyBaseHandler {
logger.debug("{}: Set Auto-OFF timer to {}", thingName, command); logger.debug("{}: Set Auto-OFF timer to {}", thingName, command);
api.setAutoTimer(rIndex, SHELLY_TIMER_AUTOOFF, getNumber(command).doubleValue()); api.setAutoTimer(rIndex, SHELLY_TIMER_AUTOOFF, getNumber(command).doubleValue());
break; 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; return true;
} }

View File

@@ -54,6 +54,8 @@ public interface ShellyThingInterface {
void setThingOffline(ThingStatusDetail detail, String messageKey, Object... arguments); void setThingOffline(ThingStatusDetail detail, String messageKey, Object... arguments);
boolean isStopping();
String getThingType(); String getThingType();
ThingStatus getThingStatus(); ThingStatus getThingStatus();

View File

@@ -381,18 +381,18 @@ public class ShellyManagerActionPage extends ShellyManagerPage {
list.put(ACTION_PROTECT, "Protect Device"); 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() boolean mcast = profile.settings.coiot.peer.isEmpty()
|| SHELLY_COIOT_MCAST.equalsIgnoreCase(profile.settings.coiot.peer) || profile.isMotion; || SHELLY_COIOT_MCAST.equalsIgnoreCase(profile.settings.coiot.peer) || profile.isMotion;
list.put(mcast ? ACTION_SETCOIOT_PEER : ACTION_SETCOIOT_MCAST, list.put(mcast ? ACTION_SETCOIOT_PEER : ACTION_SETCOIOT_MCAST,
mcast ? "Set CoIoT Peer Mode" : "Set CoIoT Multicast Mode"); mcast ? "Set CoIoT Peer Mode" : "Set CoIoT Multicast Mode");
} }
if (profile.isSensor && !profile.isMotion && profile.settings.wifiSta != null 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 // FW 1.10+: Reset STA list, force WiFi rescan and connect to stringest AP
list.put(ACTION_RESSTA, "Reconnect WiFi"); 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, list.put(!profile.settings.apRoaming.enabled ? ACTION_ENAPROAMING : ACTION_DISAPROAMING,
!profile.settings.apRoaming.enabled ? "Enable WiFi Roaming" : "Disable WiFi Roaming"); !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"); !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(set ? ACTION_DISCLOUD : ACTION_ENCLOUD, set ? "Disable Cloud" : "Enable Cloud");
list.put(ACTION_RESET, "-Factory Reset"); list.put(ACTION_RESET, "-Factory Reset");

View 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_VOLTAGE, "meterVoltage", ITEMT_VOLT))
.add(new ShellyChannel(m, CHGR_METER, CHANNEL_EMETER_CURRENT, "meterCurrent", ITEMT_AMP)) .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_PFACTOR, "meterPowerFactor", ITEMT_NUMBER))
.add(new ShellyChannel(m, CHGR_METER, CHANNEL_EMETER_RESETTOTAL, "meterResetTotals", ITEMT_SWITCH))
// Sensors // Sensors
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_TEMP, "sensorTemp", ITEMT_TEMP)) .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_ILLUM, "sensorIllumination", ITEMT_STRING))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_VOLTAGE, "sensorADC", ITEMT_VOLT)) .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_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_SSTATE, "sensorState", ITEMT_STRING))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_TILT, "sensorTilt", ITEMT_ANGLE)) .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_TILT, "sensorTilt", ITEMT_ANGLE))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_MOTION, "sensorMotion", ITEMT_SWITCH)) .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_VIBRATION, "vibration", ITEMT_SWITCH))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_FLOOD, "sensorFlood", 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_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_PPM, "sensorPPM", ITEMT_NUMBER))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_VALVE, "sensorValve", ITEMT_STRING)) .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)) .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_ALARM_STATE, "alarmState", ITEMT_STRING))
@@ -455,8 +458,8 @@ public class ShellyChannelDefinitions {
return newChannels; return newChannels;
} }
public static Map<String, Channel> createEMeterChannels(final Thing thing, final ShellySettingsEMeter emeter, public static Map<String, Channel> createEMeterChannels(final Thing thing, final ShellyDeviceProfile profile,
String group) { final ShellySettingsEMeter emeter, String group) {
Map<String, Channel> newChannels = new LinkedHashMap<>(); Map<String, Channel> newChannels = new LinkedHashMap<>();
addChannel(thing, newChannels, emeter.power != null, group, CHANNEL_METER_CURRENTWATTS); addChannel(thing, newChannels, emeter.power != null, group, CHANNEL_METER_CURRENTWATTS);
addChannel(thing, newChannels, emeter.total != null, group, CHANNEL_METER_TOTALKWH); 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.voltage != null, group, CHANNEL_EMETER_VOLTAGE);
addChannel(thing, newChannels, emeter.current != null, group, CHANNEL_EMETER_CURRENT); 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.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); addChannel(thing, newChannels, true, group, CHANNEL_LAST_UPDATE);
return newChannels; return newChannels;
} }
@@ -482,7 +485,8 @@ public class ShellyChannelDefinitions {
addChannel(thing, newChannels, sdata.lux != null && sdata.lux.illumination != null, CHANNEL_GROUP_SENSOR, addChannel(thing, newChannels, sdata.lux != null && sdata.lux.illumination != null, CHANNEL_GROUP_SENSOR,
CHANNEL_SENSOR_ILLUM); CHANNEL_SENSOR_ILLUM);
addChannel(thing, newChannels, sdata.flood != null, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_FLOOD); 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, addChannel(thing, newChannels, profile.settings.externalPower != null || sdata.charger != null, CHGR_DEVST,
CHANNEL_DEVST_CHARGER); CHANNEL_DEVST_CHARGER);
addChannel(thing, newChannels, sdata.motion != null || (sdata.sensor != null && sdata.sensor.motion != null), 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_PROFILE);
addChannel(thing, newChannels, true, CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_SCHEDULE); 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_STATE);
addChannel(thing, newChannels, true, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_OPEN);
} }
// Battery // Battery

View 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.DateTimeType;
import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType; 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.PercentType;
import org.openhab.core.library.types.QuantityType; import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.types.StringType; import org.openhab.core.library.types.StringType;
@@ -245,7 +246,11 @@ public class ShellyUtils {
} }
public static OnOffType getOnOff(@Nullable Boolean value) { 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) { public static OnOffType getOnOff(int value) {

View 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.shellyix3.description = Shelly ix3 (Activation Device with 3 inputs)
thing-type.shelly.shellypludht.description = Shelly Plus HT - Temperature and Humidity Sensor 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.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.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.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.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.shellyplusht.description = Shelly Plus HT - Humidity and Temperature sensor with display
thing-type.shelly.shellyplusi4.description = Shelly Plus i4 - 4xInput Device thing-type.shelly.shellyplusi4.description = Shelly Plus i4 - 4xInput Device
thing-type.shelly.shellyplusi4dc.description = Shelly Plus i4DC - 4xDC Input 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.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.shellypro1pm.description = Shelly Pro 1PM - Single Relay Switch with Power Meter
thing-type.shelly.shellypro2-relay.description = Shelly Pro 2 - Dual Relay Switch thing-type.shelly.shellypro2-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-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.shellypro2pm-roller.description = Shelly Pro 2PM - Roller Control with Power Meter
thing-type.shelly.shellypro3.description = Shelly Pro 3 - 3xRelay Switch 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 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.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.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.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.shellyplusi4.description = Shelly Plus i4 - 4xInput Device
thing-type.shelly.shellyplusi4dc.description = Shelly Plus i4DC - 4xDC Input Device thing-type.shelly.shellyplusi4dc.description = Shelly Plus i4DC - 4xDC Input Device
thing-type.shelly.shellypro1.description = Shelly Pro 1 - Single Relay Switch 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.lastPower1.description = Last power consumption #1 - one rounded minute
channel-type.shelly.meterTotal.label = Total Energy Consumption 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.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.label = Total Returned Energy
channel-type.shelly.meterReturned.description = Total returned energy in kW/h channel-type.shelly.meterReturned.description = Total returned energy in kW/h
channel-type.shelly.meterVoltage.label = Voltage 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.sensorFlood.description = Indicates flood / water detection when toggled ON
channel-type.shelly.sensorSmoke.label = Smoke Alarm channel-type.shelly.sensorSmoke.label = Smoke Alarm
channel-type.shelly.sensorSmoke.description = Indicates smoke detection when toggled ON 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.label = Lux
channel-type.shelly.sensorLux.description = Brightness from the sensor (Lux) channel-type.shelly.sensorLux.description = Brightness from the sensor (Lux)
channel-type.shelly.sensorIllumination.label = Illumination 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.description = State of the contact (open/closed)
channel-type.shelly.sensorContact.state.option.OPEN = Open channel-type.shelly.sensorContact.state.option.OPEN = Open
channel-type.shelly.sensorContact.state.option.CLOSED = Closed 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.label = Sensor State
channel-type.shelly.sensorState.description = Sensor State (Warm-Up/Normal/Fault/Unknown) channel-type.shelly.sensorState.description = Sensor State (Warm-Up/Normal/Fault/Unknown)
channel-type.shelly.sensorState.state.option.warmup = Warm-Up channel-type.shelly.sensorState.state.option.warmup = Warm-Up

View File

@@ -580,6 +580,12 @@
</state> </state>
</channel-type> </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"> <channel-type id="timestamp">
<item-type>DateTime</item-type> <item-type>DateTime</item-type>
<label>@text/channel-type.shelly.timestamp.label</label> <label>@text/channel-type.shelly.timestamp.label</label>

View File

@@ -243,6 +243,18 @@
</state> </state>
</channel-type> </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"> <channel-type id="sensorState">
<item-type>String</item-type> <item-type>String</item-type>
<label>@text/channel-type.shelly.sensorState.label</label> <label>@text/channel-type.shelly.sensorState.label</label>
@@ -339,6 +351,12 @@
</state> </state>
</channel-type> </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"> <channel-type id="sensorLux">
<item-type>Number:Illuminance</item-type> <item-type>Number:Illuminance</item-type>
<label>@text/channel-type.shelly.sensorLux.label</label> <label>@text/channel-type.shelly.sensorLux.label</label>

View File

@@ -60,6 +60,20 @@
<config-description-ref uri="thing-type:shelly:roller-gen2"/> <config-description-ref uri="thing-type:shelly:roller-gen2"/>
</thing-type> </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"> <thing-type id="shellyplusi4">
<label>ShellyPlus i4</label> <label>ShellyPlus i4</label>
@@ -219,6 +233,26 @@
<config-description-ref uri="thing-type:shelly:relay-gen2"/> <config-description-ref uri="thing-type:shelly:relay-gen2"/>
</thing-type> </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"> <thing-type id="shellypro4pm">
<label>ShellyPro 4PM</label> <label>ShellyPro 4PM</label>

View File

@@ -18,4 +18,18 @@
<config-description-ref uri="thing-type:shelly:battery-gen2"/> <config-description-ref uri="thing-type:shelly:battery-gen2"/>
</thing-type> </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> </thing:thing-descriptions>