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