diff --git a/bundles/org.openhab.binding.shelly/README.md b/bundles/org.openhab.binding.shelly/README.md index 81f781aa7038c..677c768888e99 100644 --- a/bundles/org.openhab.binding.shelly/README.md +++ b/bundles/org.openhab.binding.shelly/README.md @@ -1,6 +1,6 @@ # Shelly Binding -This Binding integrated Shelly devices. +This Binding integrates [Shelly devices](https://shelly.cloud/). ## Supported Devices @@ -15,19 +15,19 @@ This Binding integrated Shelly devices. | shelly25-roller | Shelly 2.5 in Roller Mode | | shelly4pro | Shelly 4x Relay Switch | | shellydimmer | Shelly Dimmer | -| shellyplugs | Shelly Plug-S | | shellyplug | Shelly Plug | +| shellyplugs | Shelly Plug-S | | shellyrgbw2 | Shelly RGB Controller | | shellybulb | Shelly Bulb in Color or White Mode | -| shellyht | Shelly Sensor (temp+humidity) | +| shellyht | Shelly Sensor (temperature + humidity) | | shellyflood | Shelly Flood Sensor | | shellysmoke | Shelly Smoke Sensor | | shellysense | Shelly Motion and IR Controller | -| shellydevice | A password protected Shelly device or anunknown type | +| shellydevice | A password protected device or an unknown type | -## Firmware +### Firmware -To utilize all features the binding requires firmware version 1.5.2 or newer. +To utilize all features, the binding requires firmware version 1.5.2 or newer. This should be available for all devices. Older versions work in general, but have impacts to functionality (e.g. no events for battery powered devices). @@ -70,8 +70,10 @@ The binding has the following configuration options: |deviceIp |IP address of the Shelly device | yes |none | |userId |The user id used for HTTP authentication | no |none | |password |Password for HTTP authentication* | no |none | -|lowBattery |Threshold for battery level. Set alert when level is below. | no |20 (=20%), only for battery powered devices | +|lowBattery |An alarm is raised when battery level is < this threshold | no |20 (=20%), only for battery powered devices | +|weakSignal |An alarm is raised when wifi signal strength is < this threshold | no |-80 dBm | |updateInterval |Interval for the background status check in seconds. | no |1h for battery powered devices, 60s for all others| +|brightnessAutoOn |true: Setting brightness > 0 automatically turns on the device| no |true | |eventsButton |true: register event "trigger when a button is pushed" | no |false | |eventsPush |true: register event "trigger on short and long push" | no |false | |eventsSwitch |true: register event "trigger of switching the relay output" | no |true | @@ -83,17 +85,17 @@ The binding has the following configuration options: ### General Notes -- The channels `input` and `input1`/`input2` are only updated with firmware 1.5.6+. -- Use the channel `rollerpos` only if you need the inverted value, otherwise use the control channel with item type `Number`, see example below. -- Short push and long push events require firmware version 1.5.6+. +- channels `input` and `input1`/`input2` get only updated with firmware 1.5.6+. +- channel button: Short push and long push events require firmware version 1.5.6+. +- Use the channel `rollerpos` only if you need the inverted roller position, otherwise use the `control` channel with item type `Number` - The different devices have different types of power meters, i.e. different sets of channels. Every device has a channel group `device` with the following channels: -|Group |Channel |Type |read-only|Desciption | +|Group |Channel |Type |read-only|Description | |----------|-------------|---------|---------|---------------------------------------------------------------------------------| |device |uptime |Number |yes |Number of seconds since the device was powered up | -| |signal |Number |yes |WiFi signal strength (RSSI) | +| |wifiSignal |Number |yes |WiFi signal strength (4=excellent, 3=good, 2=not strong, 1=unreliable, 0=none) | | |alarm |Trigger |yes |Most recent alarm for health check | @@ -110,6 +112,7 @@ When an alarm condition is detected the channel alarm gets triggered and provide |OVER_LOAD |An over load condition has been detected, e.g. from the roller motor. | |OVER_POWER |Maximum allowed power was exceeded. The relay was turned off. | |LOAD_ERROR |Device reported a load problem. | +|LOW_BATTERY |A low battery level was detected. | A new alarm will be triggered on a new condition or every 5 minutes if the condition persists. @@ -124,17 +127,18 @@ end ### Shelly 1 (thing-type: shelly1) -|Group |Channel |Type |read-only|Desciption | +|Group |Channel |Type |read-only|Description | |----------|-------------|---------|---------|---------------------------------------------------------------------------------| |relay |output |Switch |r/w |Controls the relay's output channel (on/off) | | |input |Switch |yes |ON: Input/Button is powered, see General Notes on Channels | ### Shelly 1PM (thing-type: shelly1pm) -|Group |Channel |Type |read-only|Desciption | +|Group |Channel |Type |read-only|Description | |----------|-------------|---------|---------|---------------------------------------------------------------------------------| |relay |output |Switch |r/w |Controls the relay's output channel (on/off) | | |input |Switch |yes |ON: Input/Button is powered, see General Notes on Channels | +| |button |Trigger |yes |Event trigger with payload SHORT_PRESSED or LONG_PRESSED (FW 1.5.6+) | |meter |currentWatts |Number |yes |Current power consumption in Watts | | |lastPower1 |Number |yes |Energy consumption in Watts for a round minute, 1 minute ago | | |lastPower2 |Number |yes |Energy consumption in Watts for a round minute, 2 minutes ago | @@ -148,7 +152,7 @@ end |----------|-------------|---------|---------|---------------------------------------------------------------------------------| |relay |output |Switch |r/w |Controls the relay's output channel (on/off) | | |input |Switch |yes |ON: Input/Button is powered, see General Notes on Channels | -| |event |Trigger |yes |Triggers an event from the device, see general notes for details | +| |button |Trigger |yes |Event trigger with payload SHORT_PRESSED or LONG_PRESSED (FW 1.5.6+) | |meter1 |currentWatts |Number |yes |Current power consumption in Watts | | |totalKWH |Number |yes |Total energy consumption in Watts since the device powered up (reset on restart) | | |returnedKWH |Number |yes |Total returned energy, kw/h | @@ -168,16 +172,16 @@ end |----------|-------------|---------|---------|---------------------------------------------------------------------------------| |relay1 |output |Switch |r/w |Relay #1: Controls the relay's output channel (on/off) | | |input |Switch |yes |ON: Input/Button is powered, see General Notes on Channels | +| |button |Trigger |yes |Relay #1: Event trigger with payload SHORT_PRESSED or LONG_PRESSED (FW 1.5.6+) | | |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 | -| |event |Trigger |yes |Relay #1: Triggers an event from the device, see general notes for details | |relay2 |output |Switch |r/w |Relay #2: Controls the relay's output channel (on/off) | | |input |Switch |yes |ON: Input/Button is powered, see General Notes on Channels | +| |button |Trigger |yes |Relay #2: Event trigger with payload SHORT_PRESSED or LONG_PRESSED (FW 1.5.6+) | | |autoOn |Number |r/w |Relay #2: Sets a timer to turn the device ON after every OFF command; in seconds| | |autoOff |Number |r/w |Relay #2: Sets a timer to turn the device OFF after every ON command; in seconds| | |timerActive |Switch |yes |Relay #2: ON: An auto-on/off timer is active | -| |event |Trigger |yes |Relay #2: Triggers an event from the device, see general notes for details | |meter |currentWatts |Number |yes |Current power consumption in Watts | | |lastPower1 |Number |yes |Energy consumption in Watts for a round minute, 1 minute ago | | |lastPower2 |Number |yes |Energy consumption in Watts for a round minute, 2 minutes ago | @@ -194,7 +198,7 @@ end | |rollerpos |Number |r/w |Roller position: 100%=open...0%=closed; gets updated when the roller stops, see Notes | | |lastDirection|String |yes |Last direction: open or close | | |stopReason |String |yes |Last stop reasons: normal, safety_switch or obstacle | -| |event |Trigger |yes |Triggers an event from the device, see general notes for details | +| |event |Trigger |yes |Roller event/trigger with payload ROLLER_OPEN / ROLLER_CLOSE / ROLLER_STOP | |meter |currentWatts |Number |yes |Current power consumption in Watts | | |lastPower1 |Number |yes |Energy consumption in Watts for a round minute, 1 minute ago | | |lastPower2 |Number |yes |Energy consumption in Watts for a round minute, 2 minutes ago | @@ -219,17 +223,17 @@ The Shelly 2.5 includes 2 meters, one for each channel. However, it doesn't make sense to differ power consumption for the roller moving up vs. moving down. For this the binding aggregates the power consumption of both relays and includes the values in "meter1". -|Group |Channel |Type |read-only|Description | -|----------|-------------|---------|---------|-------------------------------------------------------------------------------------------| -|roller |control |Rollershutter |r/w |can be open (0%), stop, or close (100%); could also handle ON (open) and OFF (close)| -| |rollerpos |Dimmer |r/w |Roller position: 100%=open...0%=closed; gets updated when the roller stopped | -| |input |Switch |yes |ON: Input/Button is powered, see General Notes on Channels | -| |lastDirection|String |yes |Last direction: open or close | -| |stopReason |String |yes |Last stop reasons: normal, safety_switch or obstacle | -| |calibrating |Switch |yes |ON: Roller is in calibration mode, OFF: normal mode (no calibration) | -| |positioning |Switch |yes |ON: Roller is positioning/moving | -| |event |Trigger |yes |Triggers an event from the device, see general notes for details | -|meter | | | |See group meter1 for Shelly 2 | +|Group |Channel |Type |read-only|Description | +|----------|-------------|---------|---------|--------------------------------------------------------------------------------------| +|roller |control |Rollershutter|r/w |can be open (0%), stop, or close (100%); could also handle ON (open) and OFF (close) | +| |rollerpos |Dimmer |r/w |Roller position: 100%=open...0%=closed; gets updated when the roller stopped | +| |input |Switch |yes |ON: Input/Button is powered, see General Notes on Channels | +| |lastDirection|String |yes |Last direction: open or close | +| |stopReason |String |yes |Last stop reasons: normal, safety_switch or obstacle | +| |calibrating |Switch |yes |ON: Roller is in calibration mode, OFF: normal mode (no calibration) | +| |positioning |Switch |yes |ON: Roller is positioning/moving | +| |event |Trigger |yes |Roller event/trigger with payload ROLLER_OPEN / ROLLER_CLOSE / ROLLER_STOP | +|meter | | | |See group meter1 for Shelly 2 | ### Shelly4 Pro (thing-type: shelly4pro) @@ -246,6 +250,13 @@ The Shelly 4Pro provides 4 relays and 4 power meters. |meter3 | | | |See group meter1 for Shelly 2 | |meter4 | | | |See group meter1 for Shelly 2 | +### Shelly Plug (thing-type: shellyplug) + +|Group |Channel |Type |read-only|Description | +|----------|-------------|---------|---------|---------------------------------------------------------------------------------| +|relay | | | |See group relay1 for Shelly 2 | +|meter | | | |See group meter1 for Shelly 2 | + ### Shelly Plug-S (thing-type: shellyplugs) |Group |Channel |Type |read-only|Description | @@ -264,7 +275,7 @@ The Shelly 4Pro provides 4 relays and 4 power meters. | |input2 |Switch |yes |State of Input 2 (S2) | | |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 | -| |event |Trigger |yes |Triggers an event from the device, see general notes for details | +| |button |Trigger |yes |Event trigger with payload SHORT_PRESSED or LONG_PRESSED (FW 1.5.6+) | |status |loaderror |Switch |yes |Last error, "no" if none | | |overload |Switch |yes |Overload condition detected, switch dimmer off or reduce load! | | |overtemperature |Switch|yes |Internal device temperature over maximum. Switch off, check physical installation| @@ -302,9 +313,11 @@ The Shelly 4Pro provides 4 relays and 4 power meters. ### Shelly RGBW2 in Color Mode (thing-type: shellyrgbw2-color) -|Group |Channel |Type |read-only|Desciption | +|Group |Channel |Type |read-only|Description | |----------|-------------|---------|---------|-----------------------------------------------------------------------| |control |power |Switch |r/w |Switch light ON/OFF | +| |input |Switch |yes |ON: Input/Button is powered, see General Notes on Channels | +| |button |Trigger |yes |Relay #1: Event trigger with payload SHORT_PRESSED or LONG_PRESSED (FW 1.5.6+) | | |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 | @@ -322,10 +335,12 @@ The Shelly 4Pro provides 4 relays and 4 power meters. ### Shelly RGBW2 in White Mode (thing-type: shellyrgbw2-white) -|Group |Channel |Type |read-only|Desciption | +|Group |Channel |Type |read-only|Description | |----------|-------------|---------|---------|-----------------------------------------------------------------------| |control |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| +| |input |Switch |yes |ON: Input/Button is powered, see General Notes on Channels | +| |button |Trigger |yes |Relay #1: Event trigger with payload SHORT_PRESSED or LONG_PRESSED (FW 1.5.6+) | | |timerActive |Switch |yes |ON: An auto-on/off timer is active | |channel1 |power |Switch |r/w |Channel 1: Turn channel on/off | | |brightness |Dimmer |r/w |Channel 1: Brightness: 0..100 | @@ -352,7 +367,6 @@ Maybe an upcoming firmware release adds this attribute, then the correct value i |sensors |temperature |Number |yes |Temperature, unit is reported by tempUnit | | |humidity |Number |yes |Relative humidity in % | | |last_update |String |yes |Timestamp of the last update (values read by the binding) | -| |event |Trigger |yes |Triggers an event from the device, see general notes for details | |battery |batteryLevel |Number |yes |Battery Level in % | | |voltage |Number |yes |Voltage of the battery | | |lowBattery |Switch |yes |Low battery alert (< 20%) | @@ -364,7 +378,6 @@ Maybe an upcoming firmware release adds this attribute, then the correct value i |sensors |temperature |Number |yes |Temperature, unit is reported by tempUnit | | |flood |Switch |yes |ON: Flooding condition detected, OFF: no flooding | | |last_update |String |yes |Timestamp of the last update (values read by the binding) | -| |event |Trigger |yes |Triggers an event from the device, see general notes for details | |battery |batteryLevel |Number |yes |Battery Level in % | | |voltage |Number |yes |Voltage of the battery | | |lowBattery |Switch |yes |Low battery alert (< 20%) | @@ -385,7 +398,6 @@ Maybe an upcoming firmware release adds this attribute, then the correct value i | |lux |Number |yes |Brightness in Lux | | |motion |Switch |yes |ON: Motion detected, OFF: No motion (check also motionTimer) | | |last_update |String |yes |Timestamp of the last update (values read by the binding) | -| |event |Trigger |yes |Triggers an event from the device, see general notes for details | |battery |batteryLevel |Number |yes |Battery Level in % | | |batteryAlert |Switch |yes |Low battery alert | @@ -405,8 +417,8 @@ Thing shelly:shelly25-relay:XXXXX4 "Shelly 25 Relay XXXXX4" @ "Dining Room" [dev Thing shelly:shelly25-relay:XXXXX5 "Shelly 25 Relay XXXXX5" @ "Bed Room" [deviceIp="x.x.x.x", userId="", password=""] /* Other * -Thing shelly:shellyht:e01691 "ShellyChimenea" @ "lowerground" [ deviceIp="10.0.55.101", userId="", password="", lowBattery=15 , eventsCoIoT=true ] -Thing shelly:shellyht:e01681 "ShellyDormitorio" @ "upperground" [ deviceIp="10.0.55.102", userId="", password="", lowBattery=15 , eventsCoIoT=true ] +Thing shelly:shellyht:XXXXXX "ShellyChimenea" @ "lowerground" [ deviceIp="10.0.55.101", userId="", password="", lowBattery=15 , eventsCoIoT=true ] +Thing shelly:shellyht:XXXXXX "ShellyDormitorio" @ "upperground" [ deviceIp="10.0.55.102", userId="", password="", lowBattery=15 , eventsCoIoT=true ] Thing shelly:shellyflood:XXXXXX "ShellyFlood" @ "cellar" [ deviceIp="10.0.0.103", userId="", password="", lowBattery=15, eventsSwitch=true, eventsButton=true, eventsCoIoT=true ] ``` @@ -420,7 +432,8 @@ Switch Shelly_XXXXX3_OverPower "Garage Light Over Power" {channel="shel Switch Shelly_XXXXX3_OverTemp "Garage Light Over Temperature" {channel="shelly:shelly1:XXXXX3:relay#overtemperature"} Number Shelly_XXXXX3_AutoOnTimer "Garage Light Auto On Timer" {channel="shelly:shelly1:XXXXX3:relay#autoOn"} Number Shelly_XXXXX3_AutoOffTimer "Garage Light Auto Off Timer" {channel="shelly:shelly1:BA2F18:relay#autoOff"} -Switch Shelly__TimerActive "Garage Light Timer Active" {channel="shelly:shelly1:BA2F18:relay#timerActive"} +Switch Shelly_XXXXX3_Relay "Garage Light" {channel="shelly:shelly1:XXXXX3:relay#output"} +Switch Shelly_XXXXX3_Input "Garage Switch (Input)" {channel="shelly:shelly1:XXXXX3:relay#input"} /* Sensors */ Number ShellyHT_Dormitorio_Temp "Dormitorio Temperature" {channel="shelly:shellyht:e01681:sensors#temperature"} @@ -449,7 +462,35 @@ reading colors from color picker: ``` import org.openhab.core.library.types.* -rule "color" +rule "Get input change from garage light" +when + Item Shelly_XXXXX3_Input changed to ON +then + logInfo("Garage", "Light input is ON") + BackDoorLight.sendCommand(ON) +end + +rule "Momentary Switch events" +when + Channel "shelly:shellydevice:XXXXXX:relay1#button" triggered SHORT_PRESSED +then + logInfo("Relay", "A short push was detected") +end + + +rule "Shelly alarms" +when + Channel "shelly:shellydevice:XXXXXX:device#alarm" triggered or + Channel "shelly:shelly25-roller:XXXXXX:device#alarm" triggered +then + if (receivedEvent !== null) { // A (channel) event triggered the rule + eventSource = receivedEvent.getChannel().asString + eventType = receivedEvent.getEvent() + ... + } +end + +rule "Color changed" when Item ShellyColor changed then diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/ShellyBindingConstants.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/ShellyBindingConstants.java index ada6456e2ff69..fa5ed11c2aeb5 100755 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/ShellyBindingConstants.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/ShellyBindingConstants.java @@ -31,6 +31,7 @@ public class ShellyBindingConstants { public static final String VENDOR = "Shelly"; public static final String BINDING_ID = "shelly"; + public static final String SYSTEM_ID = "system"; // Type names public static final String THING_TYPE_SHELLY1_STR = "shelly1"; @@ -212,16 +213,19 @@ public class ShellyBindingConstants { // Device Status public static final String CHANNEL_GROUP_DEV_STATUS = "device"; public static final String CHANNEL_DEVST_UPTIME = "uptime"; - public static final String CHANNEL_DEVST_RSSI = "signal"; + public static final String CHANNEL_DEVST_RSSI = "wifiSignal"; public static final String CHANNEL_DEVST_ALARM = "alarm"; + public static final String CHANNEL_DEVST_TERRORS = "timeoutErrors"; + public static final String CHANNEL_DEVST_TRECOVERED = "timeoutsRecovered"; // General public static final String CHANNEL_LAST_UPDATE = "lastUpdate"; public static final String CHANNEL_EVENT_TRIGGER = "event"; + public static final String CHANNEL_BUTTON_TRIGGER = "button"; public static final String SERVICE_TYPE = "_http._tcp.local."; public static final String SHELLY_API_MIN_FWVERSION = "v1.5.2"; - public static final int SHELLY_API_TIMEOUT_MS = 6000; + public static final int SHELLY_API_TIMEOUT_MS = 3000; // Alarm types/messages public static final String ALARM_TYPE_NONE = "NONE"; @@ -231,6 +235,7 @@ public class ShellyBindingConstants { public static final String ALARM_TYPE_OVERPOWER = "OVERPOWER"; public static final String ALARM_TYPE_OVERLOAD = "OVERLOAD"; public static final String ALARM_TYPE_LOADERR = "LOAD_ERROR"; + public static final String ALARM_TYPE_LOW_BATTERY = "LOW_BATTERY"; // Coap public static final int COIOT_PORT = 5683; @@ -295,7 +300,6 @@ public class ShellyBindingConstants { // Minimum signal strength for basic connectivity. Packet delivery may be unreliable. public static final int HEALTH_CHECK_INTERVAL_SEC = 300; - public static final int SIGNAL_ALARM_MIN_RSSI = -80; public static final int DIM_STEPSIZE = 5; diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/ShellyHandlerFactory.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/ShellyHandlerFactory.java index f272a1d64ea7c..46fb372047356 100755 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/ShellyHandlerFactory.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/ShellyHandlerFactory.java @@ -42,6 +42,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import io.reactivex.annotations.NonNull; + /** * The {@link ShellyHandlerFactory} is responsible for creating things and thing handlers. * @@ -51,7 +53,6 @@ @Component(service = { ThingHandlerFactory.class, ShellyHandlerFactory.class }, configurationPid = "binding.shelly") public class ShellyHandlerFactory extends BaseThingHandlerFactory { private final Logger logger = LoggerFactory.getLogger(ShellyHandlerFactory.class); - private final ShellyCoapServer coapServer; private final Set deviceListeners = new CopyOnWriteArraySet<>(); @@ -69,7 +70,7 @@ public class ShellyHandlerFactory extends BaseThingHandlerFactory { */ @Activate public ShellyHandlerFactory(@Reference NetworkAddressService networkAddressService, - ComponentContext componentContext, Map configProperties) { + ComponentContext componentContext, Map configProperties) { logger.debug("Activate Shelly HandlerFactory"); super.activate(componentContext); @@ -114,7 +115,7 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { } if (handler != null) { - registerDeviceListener(handler); + deviceListeners.add(handler); return handler; } @@ -122,6 +123,17 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { return null; } + /** + * Remove handler of things. + */ + @SuppressWarnings("unlikely-arg-type") + @Override + protected synchronized void removeHandler(@NonNull ThingHandler thingHandler) { + if (thingHandler instanceof ShellyBaseHandler) { + deviceListeners.remove(thingHandler); + } + } + /** * Dispatch event to registered devices. * @@ -132,9 +144,9 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { */ public void onEvent(String deviceName, String componentIndex, String eventType, Map parameters) { logger.trace("Dispatch event to device handler {}", deviceName); - for (ShellyDeviceListener l : deviceListeners) { + for (ShellyDeviceListener listener : deviceListeners) { try { - if (l.onEvent(deviceName, componentIndex, eventType, parameters)) { + if (listener.onEvent(deviceName, componentIndex, eventType, parameters)) { // event processed break; } @@ -147,24 +159,6 @@ public void onEvent(String deviceName, String componentIndex, String eventType, } } - /** - * Registers a listener, which is informed about device details. - * - * @param listener the listener to register - */ - public void registerDeviceListener(ShellyDeviceListener listener) { - this.deviceListeners.add(listener); - } - - /** - * Unregisters a given listener. - * - * @param listener the listener to unregister - */ - public void unregisterDeviceListener(ShellyDeviceListener listener) { - this.deviceListeners.remove(listener); - } - @Nullable public ShellyBindingConfiguration getBindingConfig() { return bindingConfig; diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/ShellyUtils.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/ShellyUtils.java index 9c1764102ff07..887c85bef816a 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/ShellyUtils.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/ShellyUtils.java @@ -93,6 +93,10 @@ public static OnOffType getOnOff(@Nullable Boolean value) { return (value != null ? value ? OnOffType.ON : OnOffType.OFF : OnOffType.OFF); } + public static OnOffType getOnOff(int value) { + return value == 0 ? OnOffType.OFF : OnOffType.ON; + } + @SuppressWarnings("null") public static State toQuantityType(@Nullable Double value, int digits, Unit unit) { BigDecimal bd = new BigDecimal(value.doubleValue()); @@ -168,4 +172,20 @@ public static String buildWhiteGroupName(@Nullable ShellyDeviceProfile profile, return profile.isBulb && !profile.inColor ? CHANNEL_GROUP_WHITE_CONTROL : CHANNEL_GROUP_LIGHT_CHANNEL + channelId.toString(); } + + public static DecimalType mapSignalStrength(int dbm) { + int strength = -1; + if (dbm > -60) { + strength = 4; + } else if (dbm > -70) { + strength = 3; + } else if (dbm > -80) { + strength = 2; + } else if (dbm > -90) { + strength = 1; + } else { + strength = 0; + } + return new DecimalType(strength); + } } diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyApiJson.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyApiJsonDTO.java similarity index 96% rename from bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyApiJson.java rename to bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyApiJsonDTO.java index 58b863eb8fe95..3d8f4a3c52607 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyApiJson.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyApiJsonDTO.java @@ -17,11 +17,11 @@ import com.google.gson.annotations.SerializedName; /** - * The {@link ShellyApiJson} is used for the JSon/GSon mapping + * The {@link ShellyApiJsonDTO} is used for the JSon/GSon mapping * * @author Markus Michels - Initial contribution */ -public class ShellyApiJson { +public class ShellyApiJsonDTO { public static final String SHELLY_API_ON = "on"; public static final String SHELLY_API_OFF = "off"; @@ -215,6 +215,21 @@ public static class ShellySettingsDimmer { public static final String SHELLY_API_EVENTURL_ROLLER_STOP = "roller_stop_url"; public static final String SHELLY_API_EVENTURL_REPORT = "report_url"; + public static final String SHELLY_EVENT_BTN_ON = "btn_on"; + public static final String SHELLY_EVENT_BTN_OFF = "btn_off"; + public static final String SHELLY_EVENT_BTN1_OFF = "btn1_on"; + public static final String SHELLY_EVENT_BTN1_ON = "btn1_off"; + public static final String SHELLY_EVENT_BTN2_ON = "btn2_on"; + public static final String SHELLY_EVENT_BTN2_OFF = "btn2_off"; + public static final String SHELLY_EVENT_SHORTPUSH = "shortpush"; + public static final String SHELLY_EVENT_LONGPUSH = "longpush"; + public static final String SHELLY_EVENT_OUT_ON = "out_on"; + public static final String SHELLY_EVENT_OUT_OFF = "out_off"; + public static final String SHELLY_EVENT_ROLLER_OPEN = "roller_open"; + public static final String SHELLY_EVENT_ROLLER_CLOSE = "roller_close"; + public static final String SHELLY_EVENT_ROLLER_STOP = "roller_stop"; + public static final String SHELLY_EVENT_SENSORDATA = "sensordata"; + public static final String SHELLY_BTNT_MOMENTARY = "momentary"; public static final String SHELLY_BTNT_TOGGLE = "toggle"; public static final String SHELLY_BTNT_EDGE = "edge"; @@ -295,7 +310,6 @@ public static class ShellySettingsEMeter { // ShellyEM meter public Double total; // Total consumed energy, Wh @SerializedName("total_returned") public Double totalReturned; // Total returned energy, Wh - public Long timestamp; } public static class ShellySettingsUpdate { @@ -395,6 +409,7 @@ public static class ShellySettingsStatus { public String mac; public ArrayList relays; public ArrayList rollers; + public Integer input; // RGBW2 has no JSON array public ArrayList inputs; public ArrayList lights; public ArrayList dimmers; diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyDeviceProfile.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyDeviceProfile.java index 44a64e48dfb5f..1371b5740a9e4 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyDeviceProfile.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyDeviceProfile.java @@ -14,16 +14,18 @@ import static org.openhab.binding.shelly.internal.ShellyBindingConstants.SHELLYDT_DIMMER; import static org.openhab.binding.shelly.internal.ShellyUtils.*; -import static org.openhab.binding.shelly.internal.api.ShellyApiJson.*; +import static org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.*; import java.util.HashMap; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.shelly.internal.ShellyBindingConstants; import org.openhab.binding.shelly.internal.ShellyUtils; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellySettingsGlobal; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellySettingsGlobal; import com.google.gson.Gson; @@ -34,51 +36,51 @@ * * @author Markus Michels - Initial contribution */ +@NonNullByDefault public class ShellyDeviceProfile { public String thingName = ""; - public String deviceType; - - public String settingsJson; - public ShellySettingsGlobal settings; - - public String hostname; - public String mode; - - public String hwRev; - public String hwBatchId; - public String mac; - public String fwId; - public String fwVersion; - public String fwDate; - - public Boolean hasRelays; // true if it has at least 1 power meter - public Integer numRelays; // number of relays/outputs - public Integer numRollers; // number of Rollers, usually 1 - public Boolean isRoller; // true for Shelly2 in roller mode - public Boolean isDimmer; // true for a Shelly Dimmer (SHDM-1) - - public Boolean hasMeter; // true if it has at least 1 power meter - public Integer numMeters; - public Boolean isEMeter; // true for ShellyEM - public Double maxPower; - - public Boolean hasBattery; // true if battery device - public Boolean hasLed; // true if battery device - public Boolean isPlugS; // true if it is a Shelly Plug S - public Boolean isLight; // true if it is a Shelly Bulb/RGBW2 - public Boolean isBulb; // true pnly if it is a Bulb - public Boolean isSense; // true if thing is a Shelly Sense - public Boolean inColor; // true if bulb/rgbw2 is in color mode - public Boolean isSensor; // true for HT & Smoke - public Boolean isSmoke; // true for Smoke + public String deviceType = ""; + + public String settingsJson = ""; + public @Nullable ShellySettingsGlobal settings; + + public String hostname = ""; + public String mode = ""; + + public String hwRev = ""; + public String hwBatchId = ""; + public String mac = ""; + public String fwId = ""; + public String fwVersion = ""; + public String fwDate = ""; + + public Boolean hasRelays = false; // true if it has at least 1 power meter + public Integer numRelays = 0; // number of relays/outputs + public Integer numRollers = 9; // number of Rollers, usually 1 + public Boolean isRoller = false; // true for Shelly2 in roller mode + public Boolean isDimmer = false; // true for a Shelly Dimmer (SHDM-1) + + public Boolean hasMeter = false; // true if it has at least 1 power meter + public Integer numMeters = 0; + public Boolean isEMeter = false; // true for ShellyEM + + public Boolean hasBattery = false; // true if battery device + public Boolean hasLed = false; // true if battery device + public Boolean isPlugS = false; // true if it is a Shelly Plug S + public Boolean isLight = false; // true if it is a Shelly Bulb/RGBW2 + public Boolean isBulb = false; // true pnly if it is a Bulb + public Boolean isSense = false; // true if thing is a Shelly Sense + public Boolean inColor = false; // true if bulb/rgbw2 is in color mode + public Boolean isSensor = false; // true for HT & Smoke + public Boolean isSmoke = false; // true for Smoke public Map irCodes = new HashMap(); // Sense: list of stored IR codes - public Boolean supportsButtonUrls; // true if the btn_xxx urls are supported - public Boolean supportsOutUrls; // true if the out_xxx urls are supported - public Boolean supportsPushUrls; // true if sensor report_url is supported - public Boolean supportsRollerUrls; // true if the roller_xxx urls are supported - public Boolean supportsSensorUrls; // true if sensor report_url is supported + public Boolean supportsButtonUrls = false; // true if the btn_xxx urls are supported + public Boolean supportsOutUrls = false; // true if the out_xxx urls are supported + public Boolean supportsPushUrls = false; // true if sensor report_url is supported + public Boolean supportsRollerUrls = false; // true if the roller_xxx urls are supported + public Boolean supportsSensorUrls = false; // true if sensor report_url is supported @SuppressWarnings("null") public static ShellyDeviceProfile initialize(String thingType, String json) { @@ -141,7 +143,6 @@ public static ShellyDeviceProfile initialize(String thingType, String json) { profile.numMeters = profile.inColor ? 1 : getInteger(profile.settings.device.numOutputs); } profile.hasMeter = (profile.numMeters > 0); - profile.maxPower = profile.settings.maxPower != null ? profile.settings.maxPower : 0; profile.supportsButtonUrls = profile.settingsJson.contains(SHELLY_API_EVENTURL_BTN_ON) || profile.settingsJson.contains(SHELLY_API_EVENTURL_BTN1_ON) @@ -153,5 +154,4 @@ public static ShellyDeviceProfile initialize(String thingType, String json) { return profile; } - } diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyEventServlet.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyEventServlet.java index 8f6f58fdebee3..5a95b4e37a8c8 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyEventServlet.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyEventServlet.java @@ -69,6 +69,7 @@ protected void activate(Map config) { } @Deactivate + @SuppressWarnings("null") protected void deactivate() { if (httpService != null) { httpService.unregister(SHELLY_CALLBACK_URI); diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyHttpApi.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyHttpApi.java index af23fe28fb3cd..d41a72eb8832f 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyHttpApi.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/api/ShellyHttpApi.java @@ -14,7 +14,7 @@ import static org.openhab.binding.shelly.internal.ShellyBindingConstants.*; import static org.openhab.binding.shelly.internal.ShellyUtils.*; -import static org.openhab.binding.shelly.internal.api.ShellyApiJson.*; +import static org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.*; import java.io.IOException; import java.util.Base64; @@ -29,16 +29,16 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.smarthome.io.net.http.HttpUtil; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellyControlRoller; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellySendKeyList; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellySenseKeyCode; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellySettingsDevice; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellySettingsLight; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellySettingsStatus; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellyShortLightStatus; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellyStatusLight; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellyStatusRelay; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellyStatusSensor; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellyControlRoller; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellySendKeyList; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellySenseKeyCode; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellySettingsDevice; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellySettingsLight; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellySettingsStatus; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellyShortLightStatus; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellyStatusLight; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellyStatusRelay; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellyStatusSensor; import org.openhab.binding.shelly.internal.config.ShellyThingConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -56,6 +56,8 @@ public class ShellyHttpApi { private final Logger logger = LoggerFactory.getLogger(ShellyHttpApi.class); private final ShellyThingConfiguration config; private final String thingName = ""; + private int timeoutErrors = 0; + private int timeoutsRecovered = 0; private Gson gson = new Gson(); private @Nullable ShellyDeviceProfile profile; @@ -135,9 +137,14 @@ public void setRelayTurn(Integer relayIndex, String turnMode) throws IOException + "?" + SHELLY_LIGHT_TURN + "=" + turnMode.toLowerCase()); } - public void setDimmerBrightness(Integer relayIndex, Integer brightness) throws IOException { - request(SHELLY_URL_CONTROL_LIGHT + "/" + relayIndex.toString() + "?" + SHELLY_LIGHT_TURN + "=" + SHELLY_API_ON - + "&brightness=" + brightness.toString()); + public void setDimmerBrightness(Integer relayIndex, Integer brightness, boolean autoOn) throws IOException { + if (autoOn) { + request(SHELLY_URL_CONTROL_LIGHT + "/" + relayIndex.toString() + "?" + SHELLY_LIGHT_TURN + "=" + + SHELLY_API_ON + "&brightness=" + brightness.toString()); + } else { + request(SHELLY_URL_CONTROL_LIGHT + "/" + relayIndex.toString() + "?" + "&brightness=" + + brightness.toString()); + } } @Nullable @@ -267,6 +274,7 @@ public void setLightParms(Integer lightIndex, Map parameters) th * @return Map of key codes * @throws IOException */ + @SuppressWarnings("null") public Map getIRCodeList() throws IOException { String result = request(SHELLY_URL_LIST_IR); @@ -302,7 +310,6 @@ public Map getIRCodeList() throws IOException { String json = "{\"key_codes\" : [" + keyList + "] }"; ShellySendKeyList codes = gson.fromJson(json, ShellySendKeyList.class); - Validate.notNull(codes); Map list = new HashMap(); for (ShellySenseKeyCode key : codes.keyCodes) { list.put(key.id, key.name); @@ -459,40 +466,68 @@ private void setEventUrls(Integer index) throws IOException { * @param uri: URI (e.g. "/settings") */ private String request(String uri) throws IOException { - String httpResponse = "ERROR"; - String url = "http://" + config.deviceIp + uri; - // boolean acquired = false; + String result = ""; + boolean retry = false; try { - logger.trace("HTTP GET for {}: {}", thingName, url); - - Properties headers = new Properties(); - if (!config.userId.isEmpty()) { - String value = config.userId + ":" + config.password; - headers.put(HTTP_HEADER_AUTH, - HTTP_AUTH_TYPE_BASIC + " " + Base64.getEncoder().encodeToString(value.getBytes())); - } - - httpResponse = HttpUtil.executeUrl(HttpMethod.GET, url, headers, null, "", SHELLY_API_TIMEOUT_MS); - Validate.notNull(httpResponse, "httpResponse must not be null"); - // all api responses are returning the result in Json format. If we are getting - // something else it must - // be an error message, e.g. http result code - if (httpResponse.contains(APIERR_HTTP_401_UNAUTHORIZED)) { - throw new IOException( - APIERR_HTTP_401_UNAUTHORIZED + ", set/correct userid and password in the thing/binding config"); - } - if (!httpResponse.startsWith("{") && !httpResponse.startsWith("[")) { - throw new IOException("Unexpected http response: " + httpResponse); - } - - logger.trace("HTTP response from {}: {}", thingName, httpResponse); - return httpResponse; + result = innerRequest(uri); } catch (IOException e) { if (e.getMessage().contains("Timeout")) { - throw new IOException("Shelly API call failed: Timeout (" + SHELLY_API_TIMEOUT_MS + " ms)"); + timeoutErrors++; + retry = true; } else { - throw new IOException("Shelly API call failed: " + e.getMessage() + ", url=" + url); + throw new IOException("Shelly API call failed: " + e.getMessage() + ", uri=" + uri); + } + } + if (retry) { + try { + // retry to recover + result = innerRequest(uri); + timeoutsRecovered++; + } catch (IOException e) { + if (e.getMessage().contains("Timeout")) { + throw new IOException("Shelly API timeout, uri=" + uri); + } else { + throw new IOException("Shelly API call failed: " + e.getMessage() + ", uri=" + uri); + } } } + return result; + } + + private String innerRequest(String uri) throws IOException { + String httpResponse = "ERROR"; + String url = "http://" + config.deviceIp + uri; + logger.trace("HTTP GET for {}: {}", thingName, url); + + Properties headers = new Properties(); + if (!config.userId.isEmpty()) { + String value = config.userId + ":" + config.password; + headers.put(HTTP_HEADER_AUTH, + HTTP_AUTH_TYPE_BASIC + " " + Base64.getEncoder().encodeToString(value.getBytes())); + } + + httpResponse = HttpUtil.executeUrl(HttpMethod.GET, url, headers, null, "", SHELLY_API_TIMEOUT_MS); + Validate.notNull(httpResponse, "httpResponse must not be null"); + // all api responses are returning the result in Json format. If we are getting + // something else it must + // be an error message, e.g. http result code + if (httpResponse.contains(APIERR_HTTP_401_UNAUTHORIZED)) { + throw new IOException( + APIERR_HTTP_401_UNAUTHORIZED + ", set/correct userid and password in the thing/binding config"); + } + if (!httpResponse.startsWith("{") && !httpResponse.startsWith("[")) { + throw new IOException("Unexpected http response: " + httpResponse); + } + + logger.trace("HTTP response from {}: {}", thingName, httpResponse); + return httpResponse; + } + + public int getTimeoutErrors() { + return timeoutErrors; + } + + public int getTimeoutsRecovered() { + return timeoutsRecovered; } } diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/coap/ShellyCoapHandler.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/coap/ShellyCoapHandler.java index a23ba7dbcdeb4..ff0d875353624 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/coap/ShellyCoapHandler.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/coap/ShellyCoapHandler.java @@ -14,8 +14,8 @@ import static org.openhab.binding.shelly.internal.ShellyBindingConstants.*; import static org.openhab.binding.shelly.internal.ShellyUtils.*; -import static org.openhab.binding.shelly.internal.api.ShellyApiJson.*; -import static org.openhab.binding.shelly.internal.coap.ShellyCoapJSon.*; +import static org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.*; +import static org.openhab.binding.shelly.internal.coap.ShellyCoapJSonDTO.*; import java.io.IOException; import java.util.HashMap; @@ -40,12 +40,12 @@ import org.eclipse.smarthome.core.library.unit.SmartHomeUnits; import org.eclipse.smarthome.core.types.State; import org.openhab.binding.shelly.internal.api.ShellyDeviceProfile; -import org.openhab.binding.shelly.internal.coap.ShellyCoapJSon.CoIotDescrBlk; -import org.openhab.binding.shelly.internal.coap.ShellyCoapJSon.CoIotDescrSen; -import org.openhab.binding.shelly.internal.coap.ShellyCoapJSon.CoIotDevDescription; -import org.openhab.binding.shelly.internal.coap.ShellyCoapJSon.CoIotGenericSensorList; -import org.openhab.binding.shelly.internal.coap.ShellyCoapJSon.CoIotSensor; -import org.openhab.binding.shelly.internal.coap.ShellyCoapJSon.CoIotSensorTypeAdapter; +import org.openhab.binding.shelly.internal.coap.ShellyCoapJSonDTO.CoIotDescrBlk; +import org.openhab.binding.shelly.internal.coap.ShellyCoapJSonDTO.CoIotDescrSen; +import org.openhab.binding.shelly.internal.coap.ShellyCoapJSonDTO.CoIotDevDescription; +import org.openhab.binding.shelly.internal.coap.ShellyCoapJSonDTO.CoIotGenericSensorList; +import org.openhab.binding.shelly.internal.coap.ShellyCoapJSonDTO.CoIotSensor; +import org.openhab.binding.shelly.internal.coap.ShellyCoapJSonDTO.CoIotSensorTypeAdapter; import org.openhab.binding.shelly.internal.config.ShellyThingConfiguration; import org.openhab.binding.shelly.internal.handler.ShellyBaseHandler; import org.slf4j.Logger; @@ -344,7 +344,7 @@ private void handleStatusUpdate(String devId, String payload, int serial) throws return; } - logger.debug("{}: {} status updates received", thingName, list.generic.size()); + logger.debug("{}: {} status updates received", thingName, new Integer(list.generic.size()).toString()); for (int i = 0; i < list.generic.size(); i++) { CoIotSensor s = list.generic.get(i); CoIotDescrSen sen = sensorMap.get(s.index); @@ -389,6 +389,9 @@ private void handleStatusUpdate(String devId, String payload, int serial) throws String mGroup = profile.numMeters == 1 ? CHANNEL_GROUP_METER : CHANNEL_GROUP_METER + rIndex; updateChannel(updates, mGroup, CHANNEL_METER_CURRENTWATTS, toQuantityType(s.value, DIGITS_WATT, SmartHomeUnits.WATT)); + if (profile.isEMeter) { + updateChannel(updates, mGroup, CHANNEL_LAST_UPDATE, getTimestamp()); + } break; case "o": // Overtemp // will be handled by status update @@ -420,19 +423,22 @@ private void handleStatusUpdate(String devId, String payload, int serial) throws toQuantityType(pos, SmartHomeUnits.PERCENT)); break; case "input": - if (!profile.isDimmer) { - // Device has 1 input: 0=off, 1+2 depend on switch mode - updateChannel(updates, rGroup, CHANNEL_INPUT, - s.value == 0 ? OnOffType.OFF : OnOffType.ON); - } else { - // only Dimmer has 2 inputs - Integer idx = getInputId(sen.id); - if (idx != null) { - updateChannel(updates, rGroup, CHANNEL_INPUT + idx.toString(), - s.value == 1 ? OnOffType.ON : OnOffType.OFF); + Integer idx = getInputId(sen.id); + String iGroup = rGroup; + String iChannel = CHANNEL_INPUT; + if (idx != null) { + if (profile.isDimmer || profile.isRoller) { + // Dimmer and Roller things have 2 inputs + iChannel = CHANNEL_INPUT + idx.toString(); + } else { + // Device has 1 input per relay: 0=off, 1+2 depend on switch mode + iGroup = profile.numRelays <= 1 ? CHANNEL_GROUP_RELAY_CONTROL + : CHANNEL_GROUP_RELAY_CONTROL + idx; } } + updateChannel(updates, iGroup, iChannel, s.value == 0 ? OnOffType.OFF : OnOffType.ON); break; + case "flood": updateChannel(updates, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_FLOOD, s.value == 1 ? OnOffType.ON : OnOffType.OFF); diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/coap/ShellyCoapJSon.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/coap/ShellyCoapJSonDTO.java similarity index 97% rename from bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/coap/ShellyCoapJSon.java rename to bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/coap/ShellyCoapJSonDTO.java index 84ff21e4c52da..ea95f580e5782 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/coap/ShellyCoapJSon.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/coap/ShellyCoapJSonDTO.java @@ -23,11 +23,11 @@ import com.google.gson.stream.JsonWriter; /** - * The {@link ShellyCoapJSon} helps the CoIoT Json into Java objects + * The {@link ShellyCoapJSonDTO} helps the CoIoT Json into Java objects * * @author Markus Michels - Initial contribution */ -public class ShellyCoapJSon { +public class ShellyCoapJSonDTO { public static final String COIOT_TAG_BLK = "blk"; public static final String COIOT_TAG_SEN = "sen"; diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/coap/ShellyCoapServer.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/coap/ShellyCoapServer.java index 9fdc8279d9cb7..8295b39fc2713 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/coap/ShellyCoapServer.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/coap/ShellyCoapServer.java @@ -140,6 +140,7 @@ public CoapEndpoint getEndpoint() { /** * Cancel pending requests and shutdown the client */ + @SuppressWarnings("null") public void stop() { if (started) { if (server != null) { diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/config/ShellyBindingConfiguration.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/config/ShellyBindingConfiguration.java index 496962533fc17..160c284c74a84 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/config/ShellyBindingConfiguration.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/config/ShellyBindingConfiguration.java @@ -21,6 +21,7 @@ import org.apache.commons.lang.Validate; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; /** * The {@link ShellyBindingConfiguration} class contains fields mapping binding configuration parameters. @@ -36,16 +37,18 @@ public class ShellyBindingConfiguration { public String defaultUserId = ""; // default for http basic user id public String defaultPassword = ""; // default for http basic auth password - public void updateFromProperties(Map properties) { + public void updateFromProperties(Map properties) { Validate.notNull(properties); - for (Map.Entry e : properties.entrySet()) { + for (Map.Entry e : properties.entrySet()) { switch (e.getKey()) { case CONFIG_DEF_HTTP_USER: - defaultUserId = (String) e.getValue(); + String v = (String) e.getValue(); + defaultUserId = v != null ? v : ""; break; case CONFIG_DEF_HTTP_PWD: - defaultPassword = (String) e.getValue(); + v = (String) e.getValue(); + defaultPassword = v != null ? v : ""; break; } @@ -55,7 +58,8 @@ public void updateFromProperties(Map properties) { public void updateFromProperties(Dictionary properties) { Validate.notNull(properties); List keys = Collections.list(properties.keys()); - Map dictCopy = keys.stream().collect(Collectors.toMap(Function.identity(), properties::get)); + Map dictCopy = keys.stream() + .collect(Collectors.toMap(Function.identity(), properties::get)); updateFromProperties(dictCopy); } } diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/config/ShellyThingConfiguration.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/config/ShellyThingConfiguration.java index 9f38a3eba93cb..0427b6c5a90e0 100755 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/config/ShellyThingConfiguration.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/config/ShellyThingConfiguration.java @@ -22,12 +22,14 @@ @NonNullByDefault public class ShellyThingConfiguration { public String deviceIp = ""; // ip address of thedevice - public int updateInterval = 60; // schedule interval for the update job - public float lowBattery = 20; // threshold for battery value - public String userId = ""; // userid for http basic auth public String password = ""; // password for http basic auth + public int updateInterval = 60; // schedule interval for the update job + public int lowBattery = 20; // threshold for battery value + public int weakSignal = -80; // threshold for weak wifi signal + public boolean brightnessAutoOn = true; // true: turn on device if brightness > 0 is set + public boolean eventsButton = false; // true: register for Relay btn_xxx events public boolean eventsSwitch = true; // true: register for device out_xxx events public boolean eventsPush = true; // true: register for short/long push events diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/discovery/ShellyDiscoveryParticipant.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/discovery/ShellyDiscoveryParticipant.java index 0513e60d4146e..2f2d29c6a4da4 100755 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/discovery/ShellyDiscoveryParticipant.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/discovery/ShellyDiscoveryParticipant.java @@ -74,6 +74,7 @@ public String getServiceType() { * * @param componentContext */ + @SuppressWarnings("null") @Activate protected void activate(ComponentContext componentContext) { logger.debug("Shelly Discovery service activated"); diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/discovery/ShellyThingCreator.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/discovery/ShellyThingCreator.java index 4137ee86e3daf..f92d0a96db068 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/discovery/ShellyThingCreator.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/discovery/ShellyThingCreator.java @@ -13,7 +13,7 @@ package org.openhab.binding.shelly.internal.discovery; import static org.openhab.binding.shelly.internal.ShellyBindingConstants.*; -import static org.openhab.binding.shelly.internal.api.ShellyApiJson.*; +import static org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.*; import org.apache.commons.lang.StringUtils; import org.eclipse.jdt.annotation.NonNullByDefault; diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyBaseHandler.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyBaseHandler.java index b85bc3a42986e..9803edad3ab73 100755 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyBaseHandler.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyBaseHandler.java @@ -15,6 +15,7 @@ import static org.eclipse.smarthome.core.thing.Thing.*; import static org.openhab.binding.shelly.internal.ShellyBindingConstants.*; import static org.openhab.binding.shelly.internal.ShellyUtils.*; +import static org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.*; import static org.openhab.binding.shelly.internal.discovery.ShellyThingCreator.getThingTypeUID; import java.io.IOException; @@ -28,8 +29,10 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.smarthome.core.library.types.DecimalType; +import org.eclipse.smarthome.core.library.types.OnOffType; import org.eclipse.smarthome.core.library.unit.SmartHomeUnits; import org.eclipse.smarthome.core.thing.ChannelUID; +import org.eclipse.smarthome.core.thing.CommonTriggerEvents; import org.eclipse.smarthome.core.thing.Thing; import org.eclipse.smarthome.core.thing.ThingStatus; import org.eclipse.smarthome.core.thing.ThingStatusDetail; @@ -38,7 +41,8 @@ import org.eclipse.smarthome.core.types.Command; import org.eclipse.smarthome.core.types.RefreshType; import org.eclipse.smarthome.core.types.State; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellySettingsStatus; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellyInputState; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellySettingsStatus; import org.openhab.binding.shelly.internal.api.ShellyDeviceProfile; import org.openhab.binding.shelly.internal.api.ShellyHttpApi; import org.openhab.binding.shelly.internal.coap.ShellyCoapHandler; @@ -114,7 +118,6 @@ public ShellyBaseHandler(Thing thing, ShellyBindingConfiguration bindingConfig, */ @Override public void initialize() { - updateStatus(ThingStatus.UNKNOWN); // start background initialization: scheduler.schedule(() -> { boolean start = true; @@ -124,7 +127,7 @@ public void initialize() { logger.debug("{}: Device config: ipAddress={}, http user/password={}/{}, update interval={}", getThing().getLabel(), config.deviceIp, config.userId.isEmpty() ? "" : config.userId, config.password.isEmpty() ? "" : "***", config.updateInterval); - initializeThing(); + start = initializeThing(); } catch (NullPointerException | IOException e) { if (authorizationFailed(e.getMessage())) { start = false; @@ -164,7 +167,7 @@ public void handleConfigurationUpdate(Map configurationParameter * @throws IOException e.g. http returned non-ok response, check e.getMessage() for details. */ @SuppressWarnings("null") - private void initializeThing() throws IOException { + private boolean initializeThing() throws IOException { // Get the thing global settings and initialize device capabilities channelData = new HashMap<>(); // clear any cached channels refreshSettings = false; @@ -172,19 +175,24 @@ private void initializeThing() throws IOException { Map properties = getThing().getProperties(); thingName = properties.get(PROPERTY_SERVICE_NAME) != null ? properties.get(PROPERTY_SERVICE_NAME).toLowerCase() - : ""; - logger.debug("{}: Start initializing, ip address {}, CoIoT: {}", getThing().getLabel(), config.deviceIp, - config.eventsCoIoT); + : this.getThing().getThingTypeUID().getId(); + logger.debug("{}: Start initializing thing {}, ip address {}, CoIoT: {}", thingName, getThing().getLabel(), + config.deviceIp, config.eventsCoIoT); + if (config.deviceIp.isEmpty()) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, + "@text/config-status.error.missing-device-ip"); + return false; + } // Initialize API access, exceptions will be catched by initialize() api = new ShellyHttpApi(config); - ShellyDeviceProfile tmpPrf = api.getDeviceProfile(this.getThing().getThingTypeUID().getId()); + ShellyDeviceProfile tmpPrf = api.getDeviceProfile(thingName); thingName = (!thingName.isEmpty() ? thingName : tmpPrf.hostname).toLowerCase(); Validate.isTrue(!thingName.isEmpty(), "initializeThing(): thingName must not be empty!"); if (this.getThing().getThingTypeUID().equals(THING_TYPE_SHELLYUNKNOWN)) { changeThingType(thingName, tmpPrf.mode); - return; // force re-initialization + return false; // force re-initialization } logger.debug("{}: Initializing device {}, type {}, Hardware: Rev: {}, batch {}; Firmware: {} / {} ({})", @@ -193,11 +201,11 @@ private void initializeThing() throws IOException { logger.debug("{}: Shelly settings info: {}", thingName, tmpPrf.settingsJson); logger.debug( "{}: Device has relays: {} (numRelays={}, is roller: {} (numRoller={}), is Plug S: {}, is Dimmer: {}, " - + "has LEDs: {}, is Light: {}, has Meter: {} (numMeter={}, EMeter: {}), is Sensor: {}, is Sense: {}, has Battery: {} {}, " + + "has LEDs: {}, is Light: {}, has Meter: {} (numMeter={}, EMeter: {}), is Sensor: {}, is Sense: {}, weak signal threshold: {} dBm, has Battery: {} {}, " + "event urls: btn:{},out:{},push{},roller:{},sensor:{}", tmpPrf.hostname, tmpPrf.hasRelays, tmpPrf.numRelays, tmpPrf.isRoller, tmpPrf.numRollers, tmpPrf.isPlugS, tmpPrf.isDimmer, tmpPrf.hasLed, tmpPrf.isLight, tmpPrf.hasMeter, tmpPrf.numMeters, tmpPrf.isEMeter, - tmpPrf.isSensor, tmpPrf.isSense, tmpPrf.hasBattery, + tmpPrf.isSensor, tmpPrf.isSense, config.weakSignal, tmpPrf.hasBattery, tmpPrf.hasBattery ? "(low battery threshold=" + config.lowBattery + "%)" : "", tmpPrf.supportsButtonUrls, tmpPrf.supportsOutUrls, tmpPrf.supportsPushUrls, tmpPrf.supportsRollerUrls, tmpPrf.supportsSensorUrls); @@ -229,10 +237,12 @@ private void initializeThing() throws IOException { String thingType = getThing().getThingTypeUID().getId(); String reqMode = thingType.contains("-") ? StringUtils.substringAfter(thingType, "-") : ""; if (!reqMode.isEmpty() && !tmpPrf.mode.equals(reqMode)) { + logger.info( + "{}: Thing is in mode {}, expecting mode {} - going offline. Re-run discovery to changed device mode.", + thingName, profile.mode, reqMode); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, - "Thing is in mode " + profile.mode + ", required is " + reqMode - + " - going offline. Re-run discovery to find the thing for the requested mode."); - return; + "@text/offline.conf-error-wrong-mode"); + return false; } if (config.eventsCoIoT && (coap == null)) { @@ -244,12 +254,13 @@ private void initializeThing() throws IOException { } fillDeviceStatus(status, false); + postAlarm(ALARM_TYPE_NONE, false); logger.debug("{}: Thing successfully initialized.", thingName); updateStatus(ThingStatus.ONLINE); // if API call was successful the thing must be online requestUpdates(3, false); // request 3 updates in a row (during the first 2+3*3 sec) - postAlarm(ALARM_TYPE_NONE, false); + return true; // success } /** @@ -353,19 +364,25 @@ protected void updateStatus() { } } catch (IOException e) { // http call failed: go offline except for battery devices, which might be in - // sleep mode - // once the next update is successful the device goes back online + // sleep mode. Once the next update is successful the device goes back online + String status = ""; if (e.getMessage().contains("Timeout")) { - logger.debug("Device {} is not reachable, update canceled ({} skips, {} scheduledUpdates)!", thingName, + logger.debug("{}: Device is not reachable, update canceled ({} skips, {} scheduledUpdates)!", thingName, skipCount, scheduledUpdates); + status = "@text/offline.status-error-timeout"; + } else if (e.getMessage().contains(APIERR_HTTP_401_UNAUTHORIZED)) { + logger.debug("{}: Unable to access device, check credentials!", thingName); + status = "@text/offline.conf-error-access-denied"; } else if (e.getMessage().contains("Not calibrated!")) { logger.debug("{}: Roller is not calibrated! Use the Shelly App or Web UI to run calibration.", thingName); + status = "@text/offline.conf-error-not-calibrated"; } else { logger.debug("{}: Unable to update status: {} ({})", thingName, e.getMessage(), e.getClass()); + status = "@text/offline.status-error-unexpected-api-result"; } if (e.getMessage().contains(APIERR_HTTP_401_UNAUTHORIZED) || (profile != null && !profile.isSensor)) { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage()); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, status); } } catch (NullPointerException e) { logger.warn("{}: Unable to update status: {} ({})", thingName, e.getMessage(), e.getClass()); @@ -398,7 +415,11 @@ private void fillDeviceStatus(ShellySettingsStatus status, boolean updated) { Integer rssi = getInteger(status.wifiSta.rssi); updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_UPTIME, toQuantityType(new DecimalType(uptime), SmartHomeUnits.SECOND)); - updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_RSSI, new DecimalType(rssi)); + updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_RSSI, mapSignalStrength(rssi)); + + Validate.notNull(api); + updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_TERRORS, new DecimalType(api.getTimeoutErrors())); + updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_TRECOVERED, new DecimalType(api.getTimeoutsRecovered())); // Check various device indicators like overheating if ((status.uptime < lastUptime) && (profile != null) && !profile.hasBattery) { @@ -407,7 +428,7 @@ private void fillDeviceStatus(ShellySettingsStatus status, boolean updated) { } lastUptime = uptime; - if ((rssi < SIGNAL_ALARM_MIN_RSSI) && ((lastAlarmTs == 0))) { + if ((rssi < config.weakSignal) && ((lastAlarmTs == 0))) { alarm = ALARM_TYPE_WEAKSIGNAL; } if (getBool(status.overtemperature)) { @@ -459,45 +480,94 @@ public void postAlarm(String alarm, boolean force) { @SuppressWarnings({ "null" }) @Override public boolean onEvent(String deviceName, String deviceIndex, String type, Map parameters) { - if (profile == null) { - logger.debug("OnEvent: Thing not yet initialized, skip event"); - } if (thingName.equalsIgnoreCase(deviceName) || config.deviceIp.equals(deviceName)) { logger.debug("{}: Event received: class={}, index={}, parameters={}", deviceName, type, deviceIndex, parameters.toString()); boolean hasBattery = profile != null && profile.hasBattery ? true : false; if (profile == null) { logger.debug("{}: Device is not yet initialized, event triggers initialization", deviceName); - } + requestUpdates(1, true); + } else { + String group = ""; + Integer rindex = !deviceIndex.isEmpty() ? Integer.parseInt(deviceIndex) + 1 : -1; + if (type.equals(EVENT_TYPE_RELAY)) { + group = profile.numRelays <= 1 ? CHANNEL_GROUP_RELAY_CONTROL + : CHANNEL_GROUP_RELAY_CONTROL + rindex.toString(); + } + if (type.equals(EVENT_TYPE_ROLLER)) { + group = profile.numRollers <= 1 ? CHANNEL_GROUP_ROL_CONTROL + : CHANNEL_GROUP_ROL_CONTROL + rindex.toString(); + } + if (type.equals(EVENT_TYPE_LIGHT)) { + group = profile.numRelays <= 1 ? CHANNEL_GROUP_LIGHT_CONTROL + : CHANNEL_GROUP_LIGHT_CONTROL + rindex.toString(); + } + if (type.equals(EVENT_TYPE_SENSORDATA)) { + group = CHANNEL_GROUP_SENSOR; + } + if (group.isEmpty()) { + logger.debug("Unsupported event class: {}", type); + return false; + } - String group = ""; - Integer rindex = !deviceIndex.isEmpty() ? Integer.parseInt(deviceIndex) + 1 : -1; - String payload = parameters.get("type"); - if (type.equals(EVENT_TYPE_RELAY)) { - group = profile.numRelays <= 1 ? CHANNEL_GROUP_RELAY_CONTROL - : CHANNEL_GROUP_RELAY_CONTROL + rindex.toString(); - } - if (type.equals(EVENT_TYPE_ROLLER)) { - group = profile.numRollers <= 1 ? CHANNEL_GROUP_ROL_CONTROL - : CHANNEL_GROUP_ROL_CONTROL + rindex.toString(); - } - if (type.equals(EVENT_TYPE_LIGHT)) { - group = profile.numRelays <= 1 ? CHANNEL_GROUP_LIGHT_CONTROL - : CHANNEL_GROUP_LIGHT_CONTROL + rindex.toString(); - } - if (type.equals(EVENT_TYPE_SENSORDATA)) { - group = CHANNEL_GROUP_SENSOR; - payload = type; - } - if (group.isEmpty()) { - logger.debug("Unsupported event class: {}", type); - return false; - } + // map some of the events to system defined button triggers + String channel = ""; + String payload = ""; + String event = type.contentEquals(EVENT_TYPE_SENSORDATA) ? SHELLY_EVENT_SENSORDATA + : parameters.get("type"); + switch (event) { + case SHELLY_EVENT_SHORTPUSH: + channel = CHANNEL_BUTTON_TRIGGER; + payload = CommonTriggerEvents.SHORT_PRESSED; + break; + case SHELLY_EVENT_LONGPUSH: + channel = CHANNEL_BUTTON_TRIGGER; + payload = CommonTriggerEvents.LONG_PRESSED; + break; + + case SHELLY_EVENT_ROLLER_OPEN: + case SHELLY_EVENT_ROLLER_CLOSE: + case SHELLY_EVENT_ROLLER_STOP: + channel = CHANNEL_EVENT_TRIGGER; + payload = event; + break; + + case SHELLY_EVENT_BTN_ON: + updateChannel(group, CHANNEL_INPUT, OnOffType.ON); + break; + case SHELLY_EVENT_BTN_OFF: + updateChannel(group, CHANNEL_INPUT, OnOffType.OFF); + break; + case SHELLY_EVENT_BTN1_ON: + updateChannel(group, CHANNEL_INPUT1, OnOffType.ON); + break; + case SHELLY_EVENT_BTN1_OFF: + updateChannel(group, CHANNEL_INPUT1, OnOffType.OFF); + break; + case SHELLY_EVENT_BTN2_ON: + updateChannel(group, CHANNEL_INPUT2, OnOffType.ON); + break; + case SHELLY_EVENT_BTN2_OFF: + updateChannel(group, CHANNEL_INPUT2, OnOffType.OFF); + break; + case SHELLY_EVENT_OUT_ON: + updateChannel(group, CHANNEL_OUTPUT, OnOffType.ON); + break; + case SHELLY_EVENT_OUT_OFF: + updateChannel(group, CHANNEL_OUTPUT, OnOffType.OFF); + break; + + default: + // trigger will be provided by input/output channel or sensor channels + } - // Pass event to trigger channel - payload = payload.toUpperCase(); - logger.debug("{}: Post event {}", thingName, payload); - triggerChannel(mkChannelId(group, CHANNEL_EVENT_TRIGGER), payload.toUpperCase()); + if (!payload.isEmpty()) { + // Pass event to trigger channel + payload = payload.toUpperCase(); + logger.debug("{}: Post event {}", thingName, payload); + triggerChannel(mkChannelId(group, channel), payload); + } + } // request update on next interval (2x for non-battery devices) requestUpdates(scheduledUpdates >= 2 ? 0 : !hasBattery ? 2 : 1, true); @@ -541,7 +611,7 @@ private boolean authorizationFailed(String response) { logger.warn("{}: Device {} reported 'Access Denied' (user id/password mismatch)", getThing().getLabel(), config.deviceIp); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, - "Access denied, configure user id and password"); + "@text/offline.conf-error-access-denied"); changeThingType(THING_TYPE_SHELLYPROTECTED_STR, ""); return true; } @@ -551,8 +621,8 @@ private boolean authorizationFailed(String response) { /** * Change type of this thing. * - * @param serviceName mDNS service name from thing discovery - will be used to build the Thing type name - * @param mode + * @param thingType thing type acc. to the xml definition + * @param mode Device mode (e.g. relay, roller) */ private void changeThingType(String thingType, String mode) { ThingTypeUID thingTypeUID = getThingTypeUID(thingType, mode); @@ -560,6 +630,7 @@ private void changeThingType(String thingType, String mode) { logger.debug("{}: Changing thing type to {}", getThing().getLabel(), thingTypeUID.toString()); Map properties = editProperties(); properties.replace(PROPERTY_DEV_TYPE, thingType); + properties.replace(PROPERTY_DEV_MODE, mode); updateProperties(properties); changeThingType(thingTypeUID, getConfig()); } @@ -602,6 +673,39 @@ public boolean requestUpdates(int requestCount, boolean refreshSettings) { return false; } + /** + * Map input states to channels + * + * @param groupName Channel Group (relay / relay1...) + * + * @param status Shelly device status + * @return true: one or more inputs were updated + */ + @SuppressWarnings({ "null", "unused" }) + public boolean updateInputs(String groupName, ShellySettingsStatus status, int index) { + boolean updated = false; + if ((status.input != null) && (index == 0)) { + // RGBW2: a single int rather than an array + logger.trace("{}: Updating input with {}", thingName, getInteger(status.input)); + updated |= updateChannel(groupName, CHANNEL_INPUT, + getInteger(status.input) == 0 ? OnOffType.OFF : OnOffType.ON); + } else if (status.inputs != null) { + if (profile.isDimmer || profile.isRoller) { + ShellyInputState state1 = status.inputs.get(0); + ShellyInputState state2 = status.inputs.get(1); + logger.trace("{}: Updating {}#input1 with {}, input2 with {}", thingName, groupName, + getOnOff(state1.input), getOnOff(state2.input)); + updated |= updateChannel(groupName, CHANNEL_INPUT + "1", getOnOff(state1.input)); + updated |= updateChannel(groupName, CHANNEL_INPUT + "2", getOnOff(state2.input)); + } else { + ShellyInputState state = status.inputs.get(index); + logger.trace("{}: Updating input[{}] with {}", thingName, index, getOnOff(state.input)); + updated |= updateChannel(groupName, CHANNEL_INPUT, getOnOff(state.input)); + } + } + return updated; + } + /** * Update one channel. Use Channel Cache to avoid unnecessary updates (and avoid * messing up the log with those updates) @@ -621,7 +725,9 @@ public boolean updateChannel(String channelId, State value, Boolean forceUpdate) // logger.trace("{}: Predict channel {}.{} to become {} (type {}).", thingName, // group, channel, value, value.getClass()); if (!channelCache || forceUpdate || (current == null) || !current.equals(value)) { - updateState(channelId, value); + // For channels that support multiple types (like brightness) a suffix is added + // this gets removed to get the channelId for updateState + updateState(channelId.contains("$") ? StringUtils.substringBefore(channelId, "$") : channelId, value); if (current == null) { channelData.put(channelId, value); } else { @@ -648,8 +754,15 @@ public boolean updateChannel(String group, String channel, State value) { * @param profile The device profile * @param status the /status result */ + @SuppressWarnings("null") protected void updateProperties(ShellyDeviceProfile profile, ShellySettingsStatus status) { Map properties = fillDeviceProperties(profile); + String serviceName = getThing().getProperties().get(PROPERTY_SERVICE_NAME); + String hostname = getString(profile.settings.device.hostname).toLowerCase(); + if ((serviceName == null) || serviceName.isEmpty()) { + properties.put(PROPERTY_SERVICE_NAME, hostname); + logger.trace("{}: Updated serrviceName to {}", thingName, hostname); + } // add status properties Validate.notNull(status, "updateProperties(): status must not be null!"); @@ -787,6 +900,7 @@ public void triggerChannel(String group, String channel, String payload) { /** * Shutdown thing, make sure background jobs are canceled */ + @SuppressWarnings("null") @Override public void dispose() { logger.debug("{}: Shutdown thing", thingName); diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyColorUtils.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyColorUtils.java index e91a8d1cd1e6a..c9219c8b99e7e 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyColorUtils.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyColorUtils.java @@ -12,7 +12,7 @@ */ package org.openhab.binding.shelly.internal.handler; -import static org.openhab.binding.shelly.internal.api.ShellyApiJson.*; +import static org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.*; import java.math.BigDecimal; diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyComponents.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyComponents.java index 9dc9e10a4a608..ac201dc0bed61 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyComponents.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyComponents.java @@ -15,7 +15,7 @@ import static org.openhab.binding.shelly.internal.ShellyBindingConstants.*; import static org.openhab.binding.shelly.internal.ShellyUtils.*; -import static org.openhab.binding.shelly.internal.api.ShellyApiJson.*; +import static org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.*; import java.io.IOException; @@ -25,10 +25,10 @@ import org.eclipse.smarthome.core.library.types.OnOffType; import org.eclipse.smarthome.core.library.unit.SIUnits; import org.eclipse.smarthome.core.library.unit.SmartHomeUnits; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellySettingsEMeter; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellySettingsMeter; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellySettingsStatus; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellyStatusSensor; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellySettingsEMeter; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellySettingsMeter; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellySettingsStatus; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellyStatusSensor; import org.openhab.binding.shelly.internal.api.ShellyDeviceProfile; /*** @@ -40,7 +40,6 @@ */ @NonNullByDefault public class ShellyComponents { - /** * Update Meter channel * @@ -87,8 +86,10 @@ public static boolean updateMeters(ShellyBaseHandler th, ShellySettingsStatus st updated |= th.updateChannel(groupName, CHANNEL_METER_LASTMIN3, toQuantityType(getDouble(meter.counters[2]), DIGITS_WATT, SmartHomeUnits.WATT)); } - th.updateChannel(groupName, CHANNEL_LAST_UPDATE, - getTimestamp(getString(profile.settings.timezone), getLong(meter.timestamp))); + if (updated) { + th.updateChannel(groupName, CHANNEL_LAST_UPDATE, + getTimestamp(getString(profile.settings.timezone), getLong(meter.timestamp))); + } m++; } } @@ -109,8 +110,9 @@ public static boolean updateMeters(ShellyBaseHandler th, ShellySettingsStatus st toQuantityType(getDouble(emeter.reactive), DIGITS_WATT, SmartHomeUnits.WATT)); updated |= th.updateChannel(groupName, CHANNEL_EMETER_VOLTAGE, toQuantityType(getDouble(emeter.voltage), DIGITS_VOLT, SmartHomeUnits.VOLT)); - th.updateChannel(groupName, CHANNEL_LAST_UPDATE, - getTimestamp(getString(profile.settings.timezone), getLong(emeter.timestamp))); + if (updated) { + th.updateChannel(groupName, CHANNEL_LAST_UPDATE, getTimestamp()); + } m++; } } @@ -153,8 +155,10 @@ public static boolean updateMeters(ShellyBaseHandler th, ShellySettingsStatus st updated |= th.updateChannel(groupName, CHANNEL_METER_TOTALKWH, toQuantityType(getDouble(totalWatts), DIGITS_KWH, SmartHomeUnits.KILOWATT_HOUR)); - updated |= th.updateChannel(groupName, CHANNEL_LAST_UPDATE, - getTimestamp(getString(profile.settings.timezone), timestamp)); + if (updated) { + th.updateChannel(groupName, CHANNEL_LAST_UPDATE, + getTimestamp(getString(profile.settings.timezone), timestamp)); + } } } return updated; @@ -205,15 +209,16 @@ public static boolean updateSensors(ShellyBaseHandler th, ShellySettingsStatus s th.logger.trace("{}: Updating flood", th.thingName); updated |= th.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_FLOOD, getOnOff(sdata.flood)); } - if (sdata.bat != null) { + if ((sdata.bat != null) && (sdata.bat.value != null)) { // no update for Sense th.logger.trace("{}: Updating battery", th.thingName); updated |= th.updateChannel(CHANNEL_GROUP_BATTERY, CHANNEL_SENSOR_BAT_LEVEL, toQuantityType(getDouble(sdata.bat.value), DIGITS_PERCENT, SmartHomeUnits.PERCENT)); + updated |= th.updateChannel(CHANNEL_GROUP_BATTERY, CHANNEL_SENSOR_BAT_VOLT, + toQuantityType(getDouble(sdata.bat.voltage), DIGITS_VOLT, SmartHomeUnits.VOLT)); updated |= th.updateChannel(CHANNEL_GROUP_BATTERY, CHANNEL_SENSOR_BAT_LOW, getDouble(sdata.bat.value) < th.config.lowBattery ? OnOffType.ON : OnOffType.OFF); - if (sdata.bat.value != null) { // no update for Sense - updated |= th.updateChannel(CHANNEL_GROUP_BATTERY, CHANNEL_SENSOR_BAT_VOLT, - toQuantityType(getDouble(sdata.bat.voltage), DIGITS_VOLT, SmartHomeUnits.VOLT)); + if (getDouble(sdata.bat.value) < th.config.lowBattery) { + th.postAlarm(ALARM_TYPE_LOW_BATTERY, false); } } if (profile.isSense) { @@ -221,7 +226,9 @@ public static boolean updateSensors(ShellyBaseHandler th, ShellySettingsStatus s updated |= th.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_CHARGER, getOnOff(sdata.charger)); } - th.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_LAST_UPDATE, getTimestamp()); + if (updated) { + th.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_LAST_UPDATE, getTimestamp()); + } } } return updated; diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyLightHandler.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyLightHandler.java index bc8051d34219c..154b1436824ff 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyLightHandler.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyLightHandler.java @@ -14,7 +14,7 @@ import static org.openhab.binding.shelly.internal.ShellyBindingConstants.*; import static org.openhab.binding.shelly.internal.ShellyUtils.*; -import static org.openhab.binding.shelly.internal.api.ShellyApiJson.*; +import static org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.*; import java.io.IOException; import java.util.HashMap; @@ -32,10 +32,10 @@ import org.eclipse.smarthome.core.thing.ChannelUID; import org.eclipse.smarthome.core.thing.Thing; import org.eclipse.smarthome.core.types.Command; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellySettingsStatus; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellyShortLightStatus; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellyStatusLight; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellyStatusLightChannel; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellySettingsStatus; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellyShortLightStatus; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellyStatusLight; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellyStatusLightChannel; import org.openhab.binding.shelly.internal.api.ShellyDeviceProfile; import org.openhab.binding.shelly.internal.coap.ShellyCoapServer; import org.openhab.binding.shelly.internal.config.ShellyBindingConfiguration; @@ -70,7 +70,7 @@ public ShellyLightHandler(Thing thing, ShellyBindingConfiguration bindingConfig, @Override public void initialize() { - logger.debug("Thing is using class {}", this.getClass()); + logger.debug("Thing is using {}", this.getClass()); super.initialize(); } @@ -208,7 +208,7 @@ public boolean handleDeviceCommand(ChannelUID channelUID, Command command) throw } // send changed colors to the device - sendColors(profile, lightId, oldCol, col); + sendColors(profile, lightId, oldCol, col, config.brightnessAutoOn); } return true; @@ -349,6 +349,7 @@ public boolean updateDeviceStatus(ShellySettingsStatus genericStatus) throws IOE updated |= updateChannel(controlGroup, CHANNEL_LIGHT_POWER, getOnOff(light.ison)); updated |= updateChannel(controlGroup, CHANNEL_TIMER_AUTOON, getDecimal(light.autoOn)); updated |= updateChannel(controlGroup, CHANNEL_TIMER_AUTOOFF, getDecimal(light.autoOff)); + updated |= updateInputs(controlGroup, genericStatus, lightId); if (getBool(light.overpower)) { postAlarm(ALARM_TYPE_OVERPOWER, false); } @@ -436,8 +437,9 @@ private void setFullColor(String colorGroup, ShellyColorUtils col) { } } + @SuppressWarnings("null") private void sendColors(@Nullable ShellyDeviceProfile profile, Integer lightId, ShellyColorUtils oldCol, - ShellyColorUtils newCol) throws IOException { + ShellyColorUtils newCol, boolean autoOn) throws IOException { Validate.notNull(profile); // boolean updated = false; @@ -448,7 +450,9 @@ private void sendColors(@Nullable ShellyDeviceProfile profile, Integer lightId, "{}: New color settings for channel {}: RGB {}/{}/{}, white={}, gain={}, brightness={}, color-temp={}", thingName, channelId, newCol.red, newCol.green, newCol.blue, newCol.white, newCol.gain, newCol.brightness, newCol.temp); - parms.put(SHELLY_LIGHT_TURN, profile.inColor || newCol.brightness > 0 ? SHELLY_API_ON : SHELLY_API_OFF); + if (autoOn) { + parms.put(SHELLY_LIGHT_TURN, profile.inColor || newCol.brightness > 0 ? SHELLY_API_ON : SHELLY_API_OFF); + } if (profile.inColor) { if (!oldCol.red.equals(newCol.red) || !oldCol.green.equals(newCol.green) || !oldCol.blue.equals(newCol.blue) || !oldCol.white.equals(newCol.white)) { diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyProtectedHandler.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyProtectedHandler.java index 405b5eb1f5145..f9a1e78abac54 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyProtectedHandler.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyProtectedHandler.java @@ -45,7 +45,7 @@ public ShellyProtectedHandler(Thing thing, ShellyBindingConfiguration bindingCon @Override public void initialize() { - logger.debug("Thing is using class {}", this.getClass()); + logger.debug("Thing is using {}", this.getClass()); super.initialize(); } } diff --git a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyRelayHandler.java b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyRelayHandler.java index d2241c4c8a77e..06c7121bf9ea4 100644 --- a/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyRelayHandler.java +++ b/bundles/org.openhab.binding.shelly/src/main/java/org/openhab/binding/shelly/internal/handler/ShellyRelayHandler.java @@ -15,7 +15,7 @@ import static org.openhab.binding.shelly.internal.ShellyBindingConstants.*; import static org.openhab.binding.shelly.internal.ShellyUtils.*; -import static org.openhab.binding.shelly.internal.api.ShellyApiJson.*; +import static org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.*; import java.io.IOException; @@ -33,16 +33,15 @@ import org.eclipse.smarthome.core.thing.ChannelUID; import org.eclipse.smarthome.core.thing.Thing; import org.eclipse.smarthome.core.types.Command; -import org.openhab.binding.shelly.internal.api.ShellyApiJson; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellyControlRoller; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellyInputState; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellySettingsDimmer; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellySettingsRelay; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellySettingsRoller; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellySettingsStatus; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellyShortLightStatus; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellyShortStatusRelay; -import org.openhab.binding.shelly.internal.api.ShellyApiJson.ShellyStatusRelay; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellyControlRoller; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellySettingsDimmer; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellySettingsRelay; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellySettingsRoller; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellySettingsStatus; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellyShortLightStatus; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellyShortStatusRelay; +import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellyStatusRelay; import org.openhab.binding.shelly.internal.api.ShellyDeviceProfile; import org.openhab.binding.shelly.internal.coap.ShellyCoapServer; import org.openhab.binding.shelly.internal.config.ShellyBindingConfiguration; @@ -77,7 +76,7 @@ public ShellyRelayHandler(Thing thing, ShellyBindingConfiguration bindingConfig, @Override public void initialize() { - logger.debug("Thing is using class {}", this.getClass()); + logger.debug("Thing is using {}", this.getClass()); super.initialize(); } @@ -200,7 +199,7 @@ private void handleBrightness(Command command, Integer index) throws IOException validateRange("brightness", value, 0, 100); logger.debug("{}: Setting dimmer brightness to {}", thingName, value); - api.setDimmerBrightness(index, value); + api.setDimmerBrightness(index, value, config.brightnessAutoOn); } @@ -332,7 +331,7 @@ public boolean updateRelays(ShellySettingsStatus status) throws IOException { updated |= updateChannel(groupName, CHANNEL_TIMER_AUTOOFF, toQuantityType(getDouble(rsettings.autoOff), SmartHomeUnits.SECOND)); } - updated |= updateInputs(groupName, status); + updated |= updateInputs(groupName, status, i); i++; } @@ -361,7 +360,7 @@ public boolean updateRelays(ShellySettingsStatus status) throws IOException { updated |= updateChannel(groupName, CHANNEL_ROL_CONTROL_DIR, getStringType(control.lastDirection)); updated |= updateChannel(groupName, CHANNEL_ROL_CONTROL_STOPR, getStringType(control.stopReason)); - updated |= updateInputs(groupName, status); + updated |= updateInputs(groupName, status, i); i++; } @@ -391,7 +390,7 @@ public boolean updateDimmers(ShellySettingsStatus orgStatus) throws IOException // the same structure as lights[] from Bulb and RGBW2. The tag gets replaced by dimmers[] so that Gson maps // to a different structure (ShellyShortLight). Gson gson = new Gson(); - ShellySettingsStatus dstatus = gson.fromJson(ShellyApiJson.fixDimmerJson(orgStatus.json), + ShellySettingsStatus dstatus = gson.fromJson(ShellyApiJsonDTO.fixDimmerJson(orgStatus.json), ShellySettingsStatus.class); Validate.notNull(dstatus.dimmers, "dstatus.dimmers must not be null!"); Validate.notNull(dstatus.tmp, "dstatus.tmp must not be null!"); @@ -410,12 +409,12 @@ public boolean updateDimmers(ShellySettingsStatus orgStatus) throws IOException // and send a OFF status to the same channel. // When the device's brightness is > 0 we send the new value to the channel and a ON command if (dimmer.ison) { - updated |= updateChannel(groupName, CHANNEL_BRIGHTNESS, OnOffType.ON); - updated |= updateChannel(groupName, CHANNEL_BRIGHTNESS, toQuantityType( + updated |= updateChannel(groupName, CHANNEL_BRIGHTNESS + "$Switch", OnOffType.ON); + updated |= updateChannel(groupName, CHANNEL_BRIGHTNESS + "$Value", toQuantityType( new Double(getInteger(dimmer.brightness)), DIGITS_NONE, SmartHomeUnits.PERCENT)); } else { - updated |= updateChannel(groupName, CHANNEL_BRIGHTNESS, OnOffType.OFF); - updated |= updateChannel(groupName, CHANNEL_BRIGHTNESS, + updated |= updateChannel(groupName, CHANNEL_BRIGHTNESS + "$Switch", OnOffType.OFF); + updated |= updateChannel(groupName, CHANNEL_BRIGHTNESS + "$Value", toQuantityType(new Double(0), DIGITS_NONE, SmartHomeUnits.PERCENT)); } @@ -425,40 +424,15 @@ public boolean updateDimmers(ShellySettingsStatus orgStatus) throws IOException toQuantityType(getDouble(dsettings.autoOn), SmartHomeUnits.SECOND)); updated |= updateChannel(groupName, CHANNEL_TIMER_AUTOOFF, toQuantityType(getDouble(dsettings.autoOff), SmartHomeUnits.SECOND)); - } - updated |= updateInputs(groupName, orgStatus); + updated |= updateInputs(groupName, orgStatus, l); l++; } } return updated; } - /** - * Map input states to channels - * - * @param groupName Channel Group (relay / relay1...) - * - * @param status Shelly device status - * @return true: one or more inputs were updated - */ - private boolean updateInputs(String groupName, ShellySettingsStatus status) { - boolean updated = false; - if (status.inputs != null) { - int count = status.inputs.size(); - logger.trace("{}: Updating {} input state(s)", thingName, count); - for (int input = 0; input < count; input++) { - ShellyInputState state = status.inputs.get(input); - String channel = (profile.isDimmer || profile.isRoller) && count > 1 - ? CHANNEL_INPUT + Integer.toString(input + 1) - : CHANNEL_INPUT; - updated |= updateChannel(groupName, channel, state.input == 0 ? OnOffType.OFF : OnOffType.ON); - } - } - return updated; - } - /** * Update LED channels * diff --git a/bundles/org.openhab.binding.shelly/src/main/resources/ESH-INF/config/config.xml b/bundles/org.openhab.binding.shelly/src/main/resources/ESH-INF/config/config.xml index 0eaf93c0a3baa..6631a029365ff 100644 --- a/bundles/org.openhab.binding.shelly/src/main/resources/ESH-INF/config/config.xml +++ b/bundles/org.openhab.binding.shelly/src/main/resources/ESH-INF/config/config.xml @@ -10,7 +10,7 @@ - + User ID for HTTP API access. @@ -23,6 +23,17 @@ IP-Address of the Shelly device. network-address + + + An alarm is triggered if a device reports WiFi signal strength below this threshold. Default: -80 dBm + -80 + % + + + + true: Turn device ON if brightness > 0 is set; false: don't touch power status when brightness is set. + true + True if the binding should register to get the Buttons Events. @@ -39,7 +50,7 @@ True if the binding should register to get the Short/Long Push Events. true - true + false @@ -72,8 +83,8 @@ network-address - - Threshold for the battery level, alert will be signed when battery level is below.. + + Threshold for the battery level, alert will be signed when battery level is below. Default: 20% 20 % @@ -89,11 +100,19 @@ true true + + + An alarm is triggered if a device reports WiFi signal strength below this threshold. Default: -80 dBm + true + 80 + % + Interval in seconds to query an update from the device. 3600 sec + true diff --git a/bundles/org.openhab.binding.shelly/src/main/resources/ESH-INF/i18n/shelly.properties b/bundles/org.openhab.binding.shelly/src/main/resources/ESH-INF/i18n/shelly.properties new file mode 100644 index 0000000000000..80423eef0ebe1 --- /dev/null +++ b/bundles/org.openhab.binding.shelly/src/main/resources/ESH-INF/i18n/shelly.properties @@ -0,0 +1,9 @@ +# Config status messages +config-status.error.missing-device-ip=IP address of the Shelly device is missing. + +# Thing status descriptions +offline.conf-error-wrong-mode=Device is no longer in the configured device mode. Delete the thing and re-discover the device. +offline.conf-error-access-denied=Access denied, check user id and password. +offline.conf-error-not-calibrated=Roller is not calibrated, run calibration in Shelly App. +offline.status-error-timeout=Device is not reachable (API timeout). +offline.status-error-unexpected-api-result=An unexpected API response. Please verify the logfile to get more detailed information. diff --git a/bundles/org.openhab.binding.shelly/src/main/resources/ESH-INF/i18n/shelly_de.properties b/bundles/org.openhab.binding.shelly/src/main/resources/ESH-INF/i18n/shelly_de.properties new file mode 100644 index 0000000000000..f8411b1b2a48c --- /dev/null +++ b/bundles/org.openhab.binding.shelly/src/main/resources/ESH-INF/i18n/shelly_de.properties @@ -0,0 +1,346 @@ +# binding +binding.shelly.name = Shelly Binding +binding.shelly.description = Dieses Binding integriert Shelly-Komponenten, die über WiFi gesteuert werden können. + +# Config status messages +config-status.error.missing-deviceip=Die IP-Adresse des Shelly Gerätes ist nicht konfiguriert. + +# Thing status descriptions +offline.conf-error-wrong-mode=Das Gerät befindet sich nicht mehr in der erwarteten Betriebsart. Löschen Sie das Gerät und führen Sie eine erneute Geräteerkennung durch. +offline.conf-error-access-denied=Der Zugriff wurde verweigert. Überprüfen Sie die konfigurierten Zugangsdaten, oder setzen diese entsprechend (analog zur Shelly App). +offline.conf-error-not-calibrated=Der Rollladen ist nicht kalibriert. Verwenden Sie die Shelly App, um eine Kalibrierung durchzuführen. +offline.status-error-timeout=Das Gerät ist nicht erreichbar (API Timeout). +offline.status-error-unexpected-api-result=Es trat ein unerwartetes Problem beim API-Zugriff auf. Überprüfen Sie die Logdatei für genauere Informationen. + +# thing types +thing-type.shelly.shelly1.label = Shelly1 (SHSW-1) +thing-type.shelly.shelly1.description = Shelly 1 (1 Relay) +thing-type.shelly.shelly1pm.label = Shelly1PM (SHSW-PM) +thing-type.shelly.shelly1pm.description = Shelly 1PM mit 1xRelais und Strommesser +thing-type.shelly.shellyem.label = ShellyEM (SHEM) +thing-type.shelly.shellyem.description = ShellyEM zur Energiemessung +thing-type.shelly.shelly2-relay.label = Shelly2 Relay (SHSW-21) +thing-type.shelly.shelly2-relay.description = Shelly2 im Relais-Modus (2xRelay, Strommesser) +thing-type.shelly.shelly2-roller.label = Shelly2 Relay (SHSW-21) +thing-type.shelly.shelly2-roller.description = Shelly2 im Rollanden-Modus (1xRolladen, Strommesser) +thing-type.shelly.shelly25-relay.label = Shelly2.5 Relay (SHSW-25) +thing-type.shelly.shelly25-relay.description = Shelly2.5 im Relais-Modus (2xRelais, 2 Strommesser) +thing-type.shelly.shelly25-roller.label = Shelly2.5 Roller (SHSW-25) +thing-type.shelly.shelly25-roller.description = Shelly2.5 im Rollanden-Modus (1xRolladen, Strommesser) +thing-type.shelly.shelly4pro.label = Shelly4 Pro Relay (SHSW-4) +thing-type.shelly.shelly4pro.description = Shelly 4 Pro mit 4 Relais und Strommessern +thing-type.shelly.shellyplug.label = Shelly Plug (SHPLG) +thing-type.shelly.shellyplug.description = Shelly Plug als schaltbare Steckdose +thing-type.shelly.shellyplugs.label = Shelly Plug-S (SHPLG-S) +thing-type.shelly.shellyplugs.description = Shelly Plug-S als schaltbare Steckdose und LEDs zur Statusanzeige +thing-type.shelly.shellydimmer.label = Shelly Dimmer (SHDM-1) +thing-type.shelly.shellydimmer.description = Shelly mit Dimmer-Funktion +thing-type.shelly.shellyht.label = Shelly HT (SHHT-1) +thing-type.shelly.shellyht.description = Shelly HT zur Temperatur- und Feuchtigkeitsmessung +thing-type.shelly.shellysmoke.label = Shelly Smoke +thing-type.shelly.shellysmoke.description = Shelly Rauchmelder +thing-type.shelly.shellyflood.label = Shelly Flood (SHWT-1) +thing-type.shelly.shellyflood.description = Shelly Wassermelder +thing-type.shelly.shellysense.label = Shelly Sense (SHSEN-1) +thing-type.shelly.shellysense.description = Shelly Bewegungsmelder +thing-type.shelly.shellybulb.label = Shelly Bulb (SHBLB-1) +thing-type.shelly.shellybulb.description = Shelly Glühbirne weiß/Farbe +thing-type.shelly.shellyrgbw2-color.label = Shelly RGBW2 Color Mode (SHRGBW2) +thing-type.shelly.shellyrgbw2-color.description = Shelly RGBW-Controller im Farbmodus +thing-type.shelly.shellyrgbw2-white.label = Shelly RGBW2 White Mode (SHRGBW2) +thing-type.shelly.shellyrgbw2-white.description = Shelly RGBW-Controller im Weiß-Modus, 4 Streifen + +# thing config - generic +thing-type.config.shelly.generic.userId.label = Benutzer +thing-type.config.shelly.generic.userId.description = Benutzerkennung für API-Zugriff +thing-type.config.shelly.generic.password.label = Passwort +thing-type.config.shelly.generic.password.description = Passwort für API-Zugriff +thing-type.config.shelly.generic.deviceIp.label = IP Adresse +thing-type.config.shelly.generic.deviceIp.description = IP Adresse der Shelly-Komponente +thing-type.config.shelly.generic.weakSignal.label = Schwaches Signal (dBm) +thing-type.config.shelly.generic.weakSignal.description = Ein Alarm wird ausgelöst, wenn das WiFi-Signal diesen Wert unterschreitet. Voreinstellung: -80 dBm +thing-type.config.shelly.generic.brightnessAutoOn.label = Helligkeit Auto-EIN +thing-type.config.shelly.generic.brightnessAutoOn.description = AN: Setzen einer Helligkeit > 0 schaltet das Gerät automatisch ein; AUS: Gerätestatus wird nicht geändert +thing-type.config.shelly.generic.eventsButton.label = Button Events +thing-type.config.shelly.generic.eventsButton.description = Aktiviert die Button Action URLS +thing-type.config.shelly.generic.eventsPush.label = Push Events +thing-type.config.shelly.generic.eventsPush.description = Aktiviert die Push Button Action URLS +thing-type.config.shelly.generic.eventsSwitch.label = Output Events +thing-type.config.shelly.generic.eventsSwitch.description = Aktiviert die Output Action URLS +thing-type.config.shelly.generic.eventsCoIoT.label = CoIoT aktivieren +thing-type.config.shelly.generic.eventsCoIoT.description = Aktiviert CoIoT-Protokoll (Coap-baisert) +thing-type.config.shelly.generic.updateInterval.label = Status-Intervall +thing-type.config.shelly.generic.updateInterval.description = Intervall für die Hintergundaktualisiert + +# thing config - battery +thing-type.config.shelly.battery.userId.label = Benutzer +thing-type.config.shelly.battery.userId.description = Benutzerkennung für API-Zugriff +thing-type.config.shelly.battery.password.label = Passwort +thing-type.config.shelly.battery.password.description = Passwort für API-Zugriff +thing-type.config.shelly.battery.deviceIp.label = IP Adresse +thing-type.config.shelly.battery.deviceIp.description = IP Adresse der Shelly-Komponente +thing-type.config.shelly.battery.eventsSensorReport.label = Sensor Events +thing-type.config.shelly.battery.eventsSensorReport.description = Aktiviert die Sensor Action URLS +thing-type.config.shelly.battery.eventsCoIoT.label = CoIoT aktivieren +thing-type.config.shelly.battery.eventsCoIoT.description = Aktiviert CoIoT-Protokoll (Coap-baisert) +thing-type.config.shelly.battery.weakSignal.label = Schwaches Signal (dBm) +thing-type.config.shelly.battery.weakSignal.description = Ein Alarm wird ausgelöst, wenn das WiFi-Signal diesen Wert unterschreitet. Voreinstellung: -80 dBm +thing-type.config.shelly.battery.lowBattery.label = Batterie niedrig (%) +thing-type.config.shelly.battery.lowBattery.description = Ein Alarm wird ausgelöst, wenn das Gerät eine Batterieladung kleiner diesem Schwellwert meldet. Default: 20% +thing-type.config.shelly.battery.updateInterval.label = Status-Intervall +thing-type.config.shelly.battery.updateInterval.description = Intervall für die Hintergundaktualisiert + +# thing config - unknown +thing-type.config.shellydevice.userId.label = Benutzer +thing-type.config.shellydevice.userId.description = Benutzerkennung für API-Zugriff +thing-type.config.shellydevice.password.label = Passwort +thing-type.config.shellydevice.password.description = Passwort für API-Zugriff +thing-type.config.shellydevice.deviceIp.label = IP Adresse +thing-type.config.shellydevice.deviceIp.description = IP Adresse der Shelly-Komponente + +# channel-groups +#thing-type.astro.sun.group.rise.label = Sonnenaufgang +thing-type.shelly.shelly1.group.relay.label = Relais +thing-type.shelly.shelly1.group.relay.description = Relais Ein-/ausgänge und Status +thing-type.shelly.shelly1.group.device.label = Gerätestatus +thing-type.shelly.shelly1.group.device.description = Informationen zum Gerätestatus +thing-type.shelly.shelly1pm.group.relay.label = Relais +thing-type.shelly.shelly1pm.group.relay.description = Relais Ein-/ausgänge und Status +thing-type.shelly.shelly1pm.group.meter.label = Verbrauch +thing-type.shelly.shelly1pm.group.meter.description = Verbrauchswerte und andere Informationen +thing-type.shelly.shelly1pm.group.device.label = Gerätestatus +thing-type.shelly.shelly1pm.group.device.description = Informationen zum Gerätestatus +thing-type.shelly.shellyem.group.relay.label = Relais +thing-type.shelly.shellyem.group.relay.description = Relais Ein-/ausgänge und Status +thing-type.shelly.shellyem.group.meter1.label = Verbrauch 1 +thing-type.shelly.shellye,.group.meter1.description = Verbrauchswerte und andere Informationen +thing-type.shelly.shellyem.group.meter2.label = Verbrauch 2 +thing-type.shelly.shellyem.group.meter2.description = Verbrauchswerte und andere Informationen +thing-type.shelly.shellyem.group.device.label = Gerätestatus +thing-type.shelly.shellyem.group.device.description = Informationen zum Gerätestatus +thing-type.shelly.shelly2-relay.group.relay1.label = Relais 1 +thing-type.shelly.shelly2-relay.group.relay1.description = Relaisein-/ausgänge und Status +thing-type.shelly.shelly2-relay.group.relay2.label = Relais 2 +thing-type.shelly.shelly2-relay.group.relay2.description = Relaisein-/ausgänge und Status +thing-type.shelly.shelly2-relay.group.meter.label = Verbrauch +thing-type.shelly.shelly2-relay.group.meter.description = Verbrauchswerte und andere Informationen +thing-type.shelly.shelly2-relay.group.device.label = Gerätestatus +thing-type.shelly.shelly2-relay.group.device.description = Informationen zum Gerätestatus +thing-type.shelly.shelly2-roller.group.roller.label = Rollladen +thing-type.shelly.shelly2-roller.group.roller.description = Rolladensteuerung und Status +thing-type.shelly.shelly2-roller.group.meter.label = Verbrauch +thing-type.shelly.shelly2-roller.group.meter.description = Verbrauchswerte und andere Informationen +thing-type.shelly.shelly2-roller.group.device.label = Gerätestatus +thing-type.shelly.shelly2-roller.group.device.description = Informationen zum Gerätestatus +thing-type.shelly.shelly25-relay.group.relay1.label = Relais 1 +thing-type.shelly.shelly25-relay.group.relay1.description = Relais Ein-/ausgänge und -Funktionen +thing-type.shelly.shelly25-relay.group.relay2.label = Relais 2 +thing-type.shelly.shelly25-relay.group.relay2.description = Relais Ein-/ausgänge und -Funktionen +thing-type.shelly.shelly25-relay.group.meter1.label = Verbrauch 1 +thing-type.shelly.shelly25-relay.group.meter1.description = Verbrauchswerte und andere Informationen +thing-type.shelly.shelly25-relay.group.meter2.label = Verbrauch 2 +thing-type.shelly.shelly25-relay.group.meter2.description = Verbrauchswerte und andere Informationen +thing-type.shelly.shelly25-relay.group.device.label = Gerätestatus +thing-type.shelly.shelly25-relay.group.device.description = Informationen zum Gerätestatus +thing-type.shelly.shelly25-roller.group.roller.label = Rollladen +thing-type.shelly.shelly25-roller.group.meter.label = Verbrauch +thing-type.shelly.shelly25-roller.group.meter.description = Verbrauchswerte und andere Informationen +thing-type.shelly.shelly25-roller.group.device.label = Gerätestatus +thing-type.shelly.shelly25-roller.group.device.description = Informationen zum Gerätestatus +thing-type.shelly.shelly4pro.group.relay1.label = Relais 1 +thing-type.shelly.shelly4pro.group.relay1.description = Relais Ein-/ausgänge und Status +thing-type.shelly.shelly4pro.group.relay2.label = Relais 2 +thing-type.shelly.shelly4pro.group.relay2.description = Relais Ein-/ausgänge und Status +thing-type.shelly.shelly4pro.group.relay3.label = Relais 3 +thing-type.shelly.shelly4pro.group.relay3.description = Relais Ein-/ausgänge und Status +thing-type.shelly.shelly4pro.group.relay4.label = Relais 3 +thing-type.shelly.shelly4pro.group.relay4.description = Relais Ein-/ausgänge und Status +thing-type.shelly.shelly4pro.group.meter1.label = Verbrauch 1 +thing-type.shelly.shelly4pro.group.meter1.description = Verbrauchswerte und andere Informationen +thing-type.shelly.shelly4pro.group.meter2.label = Verbrauch 2 +thing-type.shelly.shelly4pro.group.meter2.description = Verbrauchswerte und andere Informationen +thing-type.shelly.shelly4pro.group.meter3.label = Verbrauch 3 +thing-type.shelly.shelly4pro.group.meter3.description = Verbrauchswerte und andere Informationen +thing-type.shelly.shelly4pro.group.meter4.label = Verbrauch 4 +thing-type.shelly.shelly4pro.group.meter4.description = Verbrauchswerte und andere Informationen +thing-type.shelly.shelly4pro.group.device.label = Gerätestatus +thing-type.shelly.shelly4pro.group.device.description = Informationen zum Gerätestatus +thing-type.shelly.shellyplug.group.relay.label = Relais +thing-type.shelly.shellyplug.group.relay.description = Relais Ein-/ausgänge und Status +thing-type.shelly.shellyplug.group.meter.label = Verbrauch +thing-type.shelly.shellyplug.group.meter.description = Verbrauchswerte und andere Informationen +thing-type.shelly.shellyplug.group.device.label = Gerätestatus +thing-type.shelly.shellyplug.group.device.description = Informationen zum Gerätestatus +thing-type.shelly.shellyplugs.group.relay.label = Relais +thing-type.shelly.shellyplugs.group.relay.description = Relais Ein-/ausgänge und Status +thing-type.shelly.shellyplugs.group.meter.label = Verbrauch +thing-type.shelly.shellyplugs.group.meter.description = Verbrauchswerte und andere Informationen +thing-type.shelly.shellyplugs.group.led.label = LEDs +thing-type.shelly.shellyplugs.group.led.description = Einstellungen zur Deaktivierung der LEDS +thing-type.shelly.shellyplugs.group.device.label = Gerätestatus +thing-type.shelly.shellyplugs.group.device.description = Informationen zum Gerätestatus +thing-type.shelly.shellydimmer.group.relay.label = Relais +thing-type.shelly.shellydimmer.group.relay.description = Relais Ein-/ausgänge und Status +thing-type.shelly.shellydimmer.group.meter.label = Verbrauch +thing-type.shelly.shellypdimmer.group.meter.description = Verbrauchswerte und andere Informationen +thing-type.shelly.shellydimmer.group.device.label = Gerätestatus +thing-type.shelly.shellydimmer.group.device.description = Informationen zum Gerätestatus +thing-type.shelly.shellybulb.group.control.label = Steuerung +thing-type.shelly.shellybulb.group.control.description = Steuerung des Lichts +thing-type.shelly.shellybulb.group.color.label = Farbmodus +thing-type.shelly.shellybulb.group.color.description = Einstellungen für den Farbmodus +thing-type.shelly.shellybulb.group.white.label = Weißwerte +thing-type.shelly.shellybulb.group.white.description = Einstellungen für den Weiß-Modus +thing-type.shelly.shellybulb.group.device.label = Gerätestatus +thing-type.shelly.shellybulb.group.device.description = Informationen zum Gerätestatus +thing-type.shelly.shellyrgbw2-color.group.control.label = Steuerung +thing-type.shelly.shellyrgbw2-color.group.control.description = Steuerung des Controllers +thing-type.shelly.shellyrgbw2-color.group.color.label = Farben +thing-type.shelly.shellyrgbw2-color.group.color.description = Farbwerte und Profile +thing-type.shelly.shellyrgbw2-color.group.meter.label = Verbrauch +thing-type.shelly.shellyrgbw2-color.group.meter.description = Verbrauchswerte und andere Informationen +thing-type.shelly.shellyrgbw2-color.group.device.label = Gerätestatus +thing-type.shelly.shellyrgbw2-color.group.device.description = Informationen zum Gerätestatus +thing-type.shelly.shellyrgbw2-white.group.channel1.label = Kanal 1 +thing-type.shelly.shellyrgbw2-white.group.channel1.description = Einstellungen für Kanal 1 +thing-type.shelly.shellyrgbw2-white.group.channel2.label = Kanal 2 +thing-type.shelly.shellyrgbw2-white.group.channel2.description = Einstellungen für Kanal 2 +thing-type.shelly.shellyrgbw2-white.group.channel3.label = Kanal 3 +thing-type.shelly.shellyrgbw2-white.group.channel3.description = Einstellungen für Kanal 3 +thing-type.shelly.shellyrgbw2-white.group.channel4.label = Kanal 4 +thing-type.shelly.shellyrgbw2-white.group.channel4.description = Einstellungen für Kanal 4 +thing-type.shelly.shellyrgbw2-white.group.meter1.label = Verbrauch 1 +thing-type.shelly.shellyrgbw2-white.group.meter1.description = Verbrauchswerte und andere Informationen +thing-type.shelly.shellyrgbw2-white.group.meter2.label = Verbrauch 2 +thing-type.shelly.shellyrgbw2-white.group.meter2.description = Verbrauchswerte und andere Informationen +thing-type.shelly.shellyrgbw2-white.group.meter3.label = Verbrauch 3 +thing-type.shelly.shellyrgbw2-white.group.meter3.description = Verbrauchswerte und andere Informationen +thing-type.shelly.shellyrgbw2-white.group.meter4.label = Verbrauch 4 +thing-type.shelly.shellyrgbw2-white.group.meter4.description = Verbrauchswerte und andere Informationen +thing-type.shelly.shellyrgbw2-white.group.device.label = Gerätestatus +thing-type.shelly.shellyrgbw2-white.group.device.description = Informationen zum Gerätestatus + + +# channels +channel-type.shelly.timerAutoOn.label = Auto-ON Timer +channel-type.shelly.timerAutoOn.description = Wenn das Relais ausgeschaltet wird, wird dieses autom. wieder nach n Sekunden eingeschaltet. +channel-type.shelly.timerAutoOff.label = Auto-OFF Timer +channel-type.shelly.timerAutoOff.description = Wenn das Relais eingeschaltet wird, wird dieses autom. wieder nach n Sekunden eingeschaltet. +channel-type.shelly.timerActive.label = Timer aktiv +channel-type.shelly.timerActive.description = ON: Auto-On/Off Timer ist aktiv +channel-type.shelly.rollerShutter.label = Steuerung (0=offen, 100=geschlossen) +channel-type.shelly.rollerShutter.description = Steuerung für den Rollladen: UP, DOWN, STOP, Position (0=offen, 100=geschlossen) +channel-type.shelly.rollerPosition.label = Position (100=offen, 0=zu) +channel-type.shelly.rollerPosition.description = Invertierte Position des Rollladen: 100=offen, 0=zu +channel-type.shelly.rollerStop.label = Stop-Grund +channel-type.shelly.rollerStop.description = Letzter Grund für das stoppen des Rollandens (normal=normaler Stop, safety_switch=Sicherheits-Stop, obstacle=Rollladen verhakt (Wiederstand erkannt) +channel-type.shelly.rollerDirection.label = Laufrichtung +channel-type.shelly.rollerDirection.description = Letzte Laufrichtung des Rollladen (open=auf, close=zu) +channel-type.shelly.inputState.label = Eingang +channel-type.shelly.inputState.description = Status des Relais-Eingangs +channel-type.shelly.inputState1.label = Eingang 1 +channel-type.shelly.inputState1.description = Status des Relais-Eingangs 1 +channel-type.shelly.inputState2.label = Eingang 2 +channel-type.shelly.inputState2.description = Status des Relais-Eingangs 2 +channel-type.shelly.dimmerBrightness.label = Helligkeit +channel-type.shelly.dimmerBrightness.description = Helligkeit (0-100%, 0=aus) +channel-type.shelly.meterWatts.label = Strom +channel-type.shelly.meterWatts.description = Aktueller Stromverbrauch in Watt +channel-type.shelly.meterReactive.label = Rücklauf +channel-type.shelly.meterReactive.description = Aktueller Stromverbrauch (Watt) des Rücklaufs +channel-type.shelly.lastPower1.label = Schnitte letzte Min +channel-type.shelly.lastPower1.description = Durchschnittsverbrauch der letzten Minute, 60s in Watt/Min +channel-type.shelly.lastPower2.label = Schnitt vorletzte Min +channel-type.shelly.lastPower2.description = Durchschnittsverbrauch der vorletzten Minute, 60s in Watt/Min +channel-type.shelly.lastPower3.label =Schnitt vor 3 Min +channel-type.shelly.lastPower3.description = Durchschnittsverbrauch vor 3 Minuten, 60s in Watt/Min +channel-type.shelly.meterTotal.label = Gesamtverbrauch +channel-type.shelly.meterTotal.description = Gesamtverbrauch seit Neustart in KW/h +channel-type.shelly.meterReturned.label = Rück-Strom +channel-type.shelly.meterReturned.description = Rücklauf in KW/h +channel-type.shelly.meterVoltage.label = Spanning +channel-type.shelly.meterVoltage.description = Spannung in Volt +channel-type.shelly.meterReturned.label = Rück-Strom KW/h +channel-type.shelly.meterReturned.description = Rücklauf in KW/h +channel-type.shelly.timestamp.label = Letzte Aktualisierung +channel-type.shelly.timestamp.description = Zeitstempel der letzten Aktualisierung (lokale Zeitzone) +channel-type.shelly.ledStatusDisable.label = WiFi Status-LED aus +channel-type.shelly.ledStatusDisable.description = ON: Die WiFi Status-LED am Gerät ist deaktiviert +channel-type.shelly.ledPowerDisable.label = Betrieb LED +channel-type.shelly.ledPowerDisable.description = ON: Die Betriebsanzeige (LED) am Gerät ist deaktiviert +channel-type.shelly.colorMode.label = Farbmodus +channel-type.shelly.colorMode.description = Betriebsart: ON: Farbe, OFF: Weiß +channel-type.shelly.colorFull.label = Voll-Farbe +channel-type.shelly.colorFull.description = Ausgewählte Farbe (red/green/blue/yellow/white) wird auf volle Intensität gesetzt (255) +channel-type.shelly.colorFull.option.red = Rot +channel-type.shelly.colorFull.option.green = Grün +channel-type.shelly.colorFull.option.blue = Blau +channel-type.shelly.colorFull.option.yellow = Gelb +channel-type.shelly.colorFull.option.white = Weiß +channel-type.shelly.colorRed.label = Rot +channel-type.shelly.colorRed.description = Rot-Anteil des RGB-Wertes (0-255) +channel-type.shelly.colorGreen.label = Grün +channel-type.shelly.colorGreen.description = Grün-Anteil des RGB-Wertes (0-255) +channel-type.shelly.colorBlue.label = Blau +channel-type.shelly.colorBlue.description = Blau-Anteil des RGB-Wertes (0-255) +channel-type.shelly.colorWhite.label = Weiß +channel-type.shelly.colorWhite.description = Weiß-Anteil des RGBW-Wertes (0-255) +channel-type.shelly.colorGain.label = Verstärkung +channel-type.shelly.colorGain.description = Verstärkung des Farbwertes (1-100%) +channel-type.shelly.whiteTemp.label = Lichttemperatur +channel-type.shelly.whiteTemp.description = Temperatur des Weißlichtes (3000..6500K) +channel-type.shelly.whiteTemp.label = Helligkeit +channel-type.shelly.whiteTemp.description = Helligkeit des Weißlichtes (0-100%, 0=aus) +channel-type.shelly.colorEffectBulb.label = Lichteffekt +channel-type.shelly.colorEffectBulb.description = Lichteffekt: 0: keiner, 1: Meteoritenregen, 2: Verlauf, 3: Atmen, 4: Blitzen, 5: Übergang ein/aus, 6: Rot/Grün-Wechsel +channel-type.shelly.colorEffectBulb.option.0 = Aus +channel-type.shelly.colorEffectBulb.option.1 = Meteoritenregen +channel-type.shelly.colorEffectBulb.option.2 = Verlauf +channel-type.shelly.colorEffectBulb.option.3 = Atmen +channel-type.shelly.colorEffectBulb.option.4 = Blitzen +channel-type.shelly.colorEffectBulb.option.5 = Übergang ein/aus +channel-type.shelly.colorEffectBulb.option.6 = Rot/Grün-Wechsel +channel-type.shelly.colorEffectRGBW2.label = Farbeffekt +channel-type.shelly.colorEffectRGBW2.description = Lichteffekt: 0: keiner, 1: Meteoritenregen, 2: Farbverlauf, 3: Blitzen +channel-type.shelly.colorEffectRGBW2.option.0 = Aus +channel-type.shelly.colorEffectRGBW2.option.1 = Meteoritenregen +channel-type.shelly.colorEffectRGBW2.option.2 = Farbverlauf +channel-type.shelly.colorEffectRGBW2.option.3 =Blitzen +channel-type.shelly.sensorTemp.label = Temperatur +channel-type.shelly.sensorTemp.description = Aktuelle Temperatur in °C +channel-type.shelly.sensorHumidity.label = Luftfeuchtigkeit +channel-type.shelly.sensorHumidity.description = Relative Luftfeuchtigkeit in % +channel-type.shelly.sensorFlood.label = Wasseralarm +channel-type.shelly.sensorFlood.description = Alarm: Es wurde Wasser erkannt +channel-type.shelly.sensorSmoke.label = Rauchalarm +channel-type.shelly.sensorSmoke.description = Alarm: Es wurde Rauch erkannt +channel-type.shelly.sensorLux.label = Beleuchtungsstärke +channel-type.shelly.sensorLux.description = Beleuchtungsstärke in Lux +channel-type.shelly.sensorCharger.label = Ladegerät +channel-type.shelly.sensorCharger.description = ON: Ein Ladegerät ist angeschlossen +channel-type.shelly.batVoltage.label = Batteriespannung +channel-type.shelly.batVoltage.description = Batteriespannung in Volt (V) +channel-type.shelly.senseKey.label = IR-Code +channel-type.shelly.senseKey.description = IR Code senden im Pronto- oder HEX64-Format +channel-type.shelly.uptime.label = Laufzeit +channel-type.shelly.uptime.description = Anzahl Sekunden seit dem das Gerät mit Strom versorgt wurde +channel-type.shelly.lastUpdate.label = Letzte Aktualisierung +channel-type.shelly.lastUpdate.description = Zeitstempel der letzten Aktualisierung (lokale Zeitzone) +channel-type.shelly.eventTrigger.label = Ereignis +channel-type.shelly.eventTrigger.description = Signalisiert Ereignisse (Trigger): ROLLER_OPEN=Rollanden geöffnet, ROLLER_CLOSE=Rollanden geschlossen, ROLLER_STOP=Rollanden angehalten +channel-type.shelly.eventTrigger.option.ROLLER_OPEN = Rollanden geöffnet +channel-type.shelly.eventTrigger.option.ROLLER_CLOSE = Rollanden geschlossen +channel-type.shelly.eventTrigger.option.ROLLER_STOP = Rollanden gestoppt +channel-type.shelly.eventTrigger.label = Alarm +channel-type.shelly.eventTrigger.description = Signalisiert Alarme (Trigger): NONE=kein Alarm, WEAK_SIGNAL=Schlechte WiFi-Verbindung, RESTARTED=Gerät neu gestartet, OVERTEMP=Überhitzung, OVERLOAD=Überlast, OVERPOWER=Maximale Last überschritten, LOAD_ERROR=Lastfehler, LOW_BATTERY=Batterie schwach +channel-type.shelly.eventTrigger.option.NONE = kein Alarm +channel-type.shelly.eventTrigger.option.WEAK_SIGNAL=Schlechte WiFi-Verbindung +channel-type.shelly.eventTrigger.option.RESTARTED=Gerät neu gestartet +channel-type.shelly.eventTrigger.option.OVERTEMP=Überhitzung +channel-type.shelly.eventTrigger.option.OVERLOAD=Überlast +channel-type.shelly.eventTrigger.option.OVERPOWER=Maximale Last überschritten +channel-type.shelly.eventTrigger.option.LOAD_ERROR=Lastfehler +channel-type.shelly.eventTrigger.option.LOW_BATTERY=Batterie schwach + +# Status error messages +config-status.error.missing-userid = Keine Benutzerkennung in der Thing Konfiguration diff --git a/bundles/org.openhab.binding.shelly/src/main/resources/ESH-INF/thing/channels.xml b/bundles/org.openhab.binding.shelly/src/main/resources/ESH-INF/thing/channels.xml index 878f02431c3bb..0ad32804d4eb8 100644 --- a/bundles/org.openhab.binding.shelly/src/main/resources/ESH-INF/thing/channels.xml +++ b/bundles/org.openhab.binding.shelly/src/main/resources/ESH-INF/thing/channels.xml @@ -58,11 +58,6 @@ - - Switch - - Turn light ON or OFF - Switch @@ -90,13 +85,6 @@ Light brightness in % DimmableLight - - Switch - - Error reported load error - - - Number:Power @@ -266,6 +254,9 @@ Temperature from the sensor Temperature + + CurrentTemperature + @@ -273,6 +264,9 @@ Number:Dimensionless Relative humidity in % (0..100%) + + CurrentHumidity + @@ -323,13 +317,6 @@ - - Number - - WiFi signal strength, should be greater than -75 to stable communication - - - DateTime @@ -341,12 +328,45 @@ trigger Event Trigger, e.g. button on/off, Output on/off - + + + + + + + trigger Alarm Trigger, e.g. weak WiFi Signal detected or over heating. - + + + + + + + + + + + + + + + + Number + + Number of timeouts while accessing the device API + + + + Number + + Number of device API timeouts, which could be recovered + + + + diff --git a/bundles/org.openhab.binding.shelly/src/main/resources/ESH-INF/thing/device.xml b/bundles/org.openhab.binding.shelly/src/main/resources/ESH-INF/thing/device.xml new file mode 100644 index 0000000000000..adc9d11dc18a7 --- /dev/null +++ b/bundles/org.openhab.binding.shelly/src/main/resources/ESH-INF/thing/device.xml @@ -0,0 +1,19 @@ + + + + + + Some details on the device status + + + + + + + + + + diff --git a/bundles/org.openhab.binding.shelly/src/main/resources/ESH-INF/thing/lights.xml b/bundles/org.openhab.binding.shelly/src/main/resources/ESH-INF/thing/lights.xml index e8809e969260a..30728fe7d3faf 100644 --- a/bundles/org.openhab.binding.shelly/src/main/resources/ESH-INF/thing/lights.xml +++ b/bundles/org.openhab.binding.shelly/src/main/resources/ESH-INF/thing/lights.xml @@ -85,6 +85,8 @@ Control your light channels + + @@ -131,6 +133,8 @@ Switch channel and adjust settings + + diff --git a/bundles/org.openhab.binding.shelly/src/main/resources/ESH-INF/thing/relay.xml b/bundles/org.openhab.binding.shelly/src/main/resources/ESH-INF/thing/relay.xml index ae3a68846e8c5..edfd4c2afe410 100644 --- a/bundles/org.openhab.binding.shelly/src/main/resources/ESH-INF/thing/relay.xml +++ b/bundles/org.openhab.binding.shelly/src/main/resources/ESH-INF/thing/relay.xml @@ -148,7 +148,7 @@ Shelly Plug device with relay and power meter - + @@ -189,10 +189,10 @@ + - @@ -204,7 +204,6 @@ - @@ -215,9 +214,9 @@ + - @@ -273,16 +272,4 @@ - - - - - Some details on the device status - - - - - - - diff --git a/tools/static-code-analysis/checkstyle/suppressions.xml b/tools/static-code-analysis/checkstyle/suppressions.xml index a18a917e1c421..2c483d016f1f1 100644 --- a/tools/static-code-analysis/checkstyle/suppressions.xml +++ b/tools/static-code-analysis/checkstyle/suppressions.xml @@ -3,7 +3,7 @@ - +