mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[shelly] Auto-numbering for channel labels & bugfixes (#13066)
* - new device types added - min firmware set to 1.8.2 - unit for gas concentration fixed (ppm) - Auto numbering on channel labels for groups with multiple instances (add sequence suffix) - API and Thing interfaces defined to restrict access to those classes - fix on TRV boost update via CoAP - fix for status.temperature and status.uptime, internalTemp channels - don’t use meter timestamp if not present (RGBW2) - low battery indicator for sensor devices fixed - device detection based on model/type improved - various messages/translations fixed/improved - README updated (missing thing types added) Signed-off-by: Markus Michels <markus7017@gmail.com> (github: markus7017) Signed-off-by: Markus Michels <markus7017@gmail.com> * missing properties added Signed-off-by: Markus Michels <markus7017@gmail.com> (github: markus7017) Signed-off-by: Markus Michels <markus7017@gmail.com> * minor changes Signed-off-by: Markus Michels <markus7017@gmail.com> (github: markus7017) Signed-off-by: Markus Michels <markus7017@gmail.com> * markdown fixed Signed-off-by: Markus Michels <markus7017@gmail.com> (github: markus7017) Signed-off-by: Markus Michels <markus7017@gmail.com> * review changes applied Signed-off-by: Markus Michels <markus7017@gmail.com> * shelly_de.properties restored from main branch Signed-off-by: Markus Michels <markus7017@gmail.com>
This commit is contained in:
parent
d814640727
commit
4f8c1722a2
@ -45,8 +45,10 @@ Also check out the [Shelly Manager](doc/ShellyManager.md), which
|
||||
| shellyplugs | Shelly Plug-S | SHPLG-S |
|
||||
| shellyem | Shelly EM with integrated Power Meters | SHEM |
|
||||
| shellyem3 | Shelly 3EM with 3 integrated Power Meter | SHEM-3 |
|
||||
| shellyrgbw2 | Shelly RGB Controller | SHRGBW2 |
|
||||
| shellybulb | Shelly Bulb in Color or White Mode | SHBLB-1 |
|
||||
| shellyrgbw2-color | Shelly RGBW2 Controller in Color Mode | SHRGBW2 |
|
||||
| shellyrgbw2-white | Shelly RGBW2 Controller in White Mode | SHRGBW2 |
|
||||
| shellybulb-color | Shelly Bulb in Color Mode | SHBLB-1 |
|
||||
| shellybulb-white | Shelly Bulb in White Mode | SHBLB-1 |
|
||||
| shellybulbduo | Shelly Duo White | SHBDUO-1 |
|
||||
| shellybulbduo | Shelly Duo White G10 | SHBDUO-1 |
|
||||
| shellycolorbulb | Shelly Duo Color G10 | SHCB-1 |
|
||||
@ -55,6 +57,7 @@ Also check out the [Shelly Manager](doc/ShellyManager.md), which
|
||||
| shellyflood | Shelly Flood Sensor | SHWT-1 |
|
||||
| shellysmoke | Shelly Smoke Sensor | SHSM-1 |
|
||||
| shellymotion | Shelly Motion Sensor | SHMOS-01 |
|
||||
| shellymotion2 | Shelly Motion Sensor 2 | SHMOS-02 |
|
||||
| shellygas | Shelly Gas Sensor | SHGS-1 |
|
||||
| shellydw | Shelly Door/Window | SHDW-1 |
|
||||
| shellydw2 | Shelly Door/Window 2 | SHDW-2 |
|
||||
@ -742,6 +745,23 @@ Using the Thing configuration option `brightnessAutoOn` you could decide if the
|
||||
`true`: Brightness will be set and device output is powered = light turns on with the new brightness
|
||||
`false`: Brightness will be set, but output stays unchanged so light will not be switched on when it's currently off.
|
||||
|
||||
### Shelly RGBW2 in White Mode (thing-type: shellyrgbw2-color)
|
||||
|
||||
|Group |Channel |Type |read-only|Description |
|
||||
|----------|-------------|---------|---------|-----------------------------------------------------------------------|
|
||||
|control |power |Switch |r/w |Switch light ON/OFF |
|
||||
| |input |Switch |yes |State of Input |
|
||||
| |autoOn |Number |r/w |Sets a timer to turn the device ON after every OFF; in sec |
|
||||
| |autoOff |Number |r/w |Sets a timer to turn the device OFF after every ON: in sec |
|
||||
| |timerActive |Switch |yes |ON: An auto-on/off timer is active |
|
||||
|color | | | |Color settings: only valid in COLOR mode |
|
||||
| |hsb |HSB |r/w |Represents the color picker (HSBType), control r/g/b, but not white |
|
||||
|meter |currentWatts |Number |yes |Current power consumption in Watts (all channels) |
|
||||
|
||||
Please note that the settings of channel group color are only valid in color mode and vice versa for white mode.
|
||||
The current firmware doesn't support the timestamp report for the meters.
|
||||
The binding emulates this by using the system time on every update.
|
||||
|
||||
### Shelly RGBW2 in White Mode (thing-type: shellyrgbw2-white)
|
||||
|
||||
|Group |Channel |Type |read-only|Description |
|
||||
@ -845,6 +865,23 @@ You have a Motion controlling your light.
|
||||
You switch off the light and want to leave the room, but the motion sensor immediately switches light back on.
|
||||
Using 'sensorSleepTime' you could suppress motion events while leaving the room, e.g. for 5sec and the light doesn's switch on.
|
||||
|
||||
### Shelly Motion 2 (thing-type: shellymotion2)
|
||||
|
||||
|Group |Channel |Type |read-only|Description |
|
||||
|----------|---------------|---------|---------|---------------------------------------------------------------------|
|
||||
|sensors |motion |Switch |yes |ON: Motion was detected |
|
||||
| |motionTimestamp|DateTime |yes |Time when motion started/was detected |
|
||||
| |lux |Number |yes |Brightness in Lux |
|
||||
| |illumination |String |yes |Current illumination: dark/twilight/bright |
|
||||
| |temperature |Number |yes |Temperature measured by the sensor |
|
||||
| |vibration |Switch |yes |ON: Vibration detected |
|
||||
| |charger |Switch |yes |ON: USB charging cable is connected external power supply activated. |
|
||||
| |motionActive |Switch |yes |ON: Motion detection is currently active |
|
||||
| |sensorSleepTime|Number |no |Specifies the number of sec the sensor should not report events ]
|
||||
| |lastUpdate |DateTime |yes |Timestamp of the last update (any sensor value changed) |
|
||||
|battery |batteryLevel |Number |yes |Battery Level in % |
|
||||
| |lowBattery |Switch |yes |Low battery alert (< 20%) |
|
||||
|
||||
### Shelly TRV (thing-type: shellytrv)
|
||||
|
||||
Note: You might need to reboot the device to enable the discovery mode for 3 minutes(use the Web UI).
|
||||
|
@ -69,9 +69,29 @@ public class ShellyBindingConstants {
|
||||
public static final String THING_TYPE_SHELLYSENSE_STR = "shellysense";
|
||||
public static final String THING_TYPE_SHELLYTRV_STR = "shellytrv";
|
||||
public static final String THING_TYPE_SHELLYMOTION_STR = "shellymotion";
|
||||
public static final String THING_TYPE_SHELLYMOTION2_STR = "shellymotion2";
|
||||
public static final String THING_TYPE_SHELLYBUTTON1_STR = "shellybutton1";
|
||||
public static final String THING_TYPE_SHELLYBUTTON2_STR = "shellybutton2";
|
||||
public static final String THING_TYPE_SHELLYUNI_STR = "shellyuni";
|
||||
|
||||
// Shelly Plus Seriens
|
||||
public static final String THING_TYPE_SHELLYPLUS1_STR = "shellyplus1";
|
||||
public static final String THING_TYPE_SHELLYPLUS1PM_STR = "shellyplus1pm";
|
||||
public static final String THING_TYPE_SHELLYPLUS2PM_RELAY_STR = "shellyplus2pm-relay";
|
||||
public static final String THING_TYPE_SHELLYPLUS2PM_ROLLER_STR = "shellyplus2pm-roller";
|
||||
public static final String THING_TYPE_SHELLYPLUSI4_STR = "shellyplusi4";
|
||||
public static final String THING_TYPE_SHELLYPLUSHT_STR = "shellyplusht";
|
||||
public static final String THING_TYPE_SHELLYPLUSPLUGUS_STR = "shellyplusplugus";
|
||||
|
||||
// Shelly Pro Series
|
||||
public static final String THING_TYPE_SHELLYPRO1_STR = "shellypro1";
|
||||
public static final String THING_TYPE_SHELLYPRO1PM_STR = "shellypro1pm";
|
||||
public static final String THING_TYPE_SHELLYPRO2_RELAY_STR = "shellypro2-relay";
|
||||
public static final String THING_TYPE_SHELLYPRO2_ROLLER_STR = "shellypro2-roller";
|
||||
public static final String THING_TYPE_SHELLYPRO2PM_RELAY_STR = "shellypro2pm-relay";
|
||||
public static final String THING_TYPE_SHELLYPRO2PM_ROLLER_STR = "shellypro2pm-roller";
|
||||
public static final String THING_TYPE_SHELLYPRO4PM_STR = "shellypro4pm";
|
||||
|
||||
public static final String THING_TYPE_SHELLYPROTECTED_STR = "shellydevice";
|
||||
public static final String THING_TYPE_SHELLYUNKNOWN_STR = "shellyunknown";
|
||||
|
||||
@ -107,6 +127,24 @@ public class ShellyBindingConstants {
|
||||
public static final String SHELLYDT_UNI = "SHUNI-1";
|
||||
public static final String SHELLYDT_TRV = "SHTRV-01";
|
||||
|
||||
// Shelly Plus Series
|
||||
public static final String SHELLYDT_PLUS1 = "SNSW-001X16EU";
|
||||
public static final String SHELLYDT_PLUS1PM = "SNSW-001P16EU";
|
||||
public static final String SHELLYDT_PLUS2PM_RELAY = "SNSW-002P16EU-relay";
|
||||
public static final String SHELLYDT_PLUS2PM_ROLLER = "SNSW-002P16EU-roller";
|
||||
public static final String SHELLYDT_PLUSPLUGUS = "SNPL-00116US";
|
||||
public static final String SHELLYDT_PLUSI4 = "SNSN-0024X";
|
||||
public static final String SHELLYDT_PLUSHT = "SNSN-0013A";
|
||||
|
||||
// Shelly Pro Series
|
||||
public static final String SHELLYDT_PRO1 = "SPSW-001XE16EU";
|
||||
public static final String SHELLYDT_PRO1PM = "SPSW-001PE16EU";
|
||||
public static final String SHELLYDT_PRO2_RELAY = "SPSW-002XE16EU-relay";
|
||||
public static final String SHELLYDT_PRO2_ROLLER = "SPSW-002XE16EU-roller";
|
||||
public static final String SHELLYDT_PRO2PM_RELAY = "SPSW-002PE16EU-relay";
|
||||
public static final String SHELLYDT_PRO2PM_ROLLER = "SPSW-002PE16EU-roller";
|
||||
public static final String SHELLYDT_PRO4PM = "SPSW-004PE16EU";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_SHELLY1 = new ThingTypeUID(BINDING_ID, THING_TYPE_SHELLY1_STR);
|
||||
public static final ThingTypeUID THING_TYPE_SHELLY1L = new ThingTypeUID(BINDING_ID, THING_TYPE_SHELLY1L_STR);
|
||||
@ -186,6 +224,7 @@ public class ShellyBindingConstants {
|
||||
public static final String PROPERTY_DEV_NAME = "deviceName";
|
||||
public static final String PROPERTY_DEV_TYPE = "deviceType";
|
||||
public static final String PROPERTY_DEV_MODE = "deviceMode";
|
||||
public static final String PROPERTY_DEV_GEN = "deviceGeneration";
|
||||
public static final String PROPERTY_HWREV = "deviceHwRev";
|
||||
public static final String PROPERTY_HWBATCH = "deviceHwBatch";
|
||||
public static final String PROPERTY_UPDATE_PERIOD = "devUpdatePeriod";
|
||||
@ -340,7 +379,7 @@ public class ShellyBindingConstants {
|
||||
public static final String CHANNEL_BUTTON_TRIGGER2 = CHANNEL_BUTTON_TRIGGER + "2";
|
||||
|
||||
public static final String SERVICE_TYPE = "_http._tcp.local.";
|
||||
public static final String SHELLY_API_MIN_FWVERSION = "v1.5.7";// v1.5.7+
|
||||
public static final String SHELLY_API_MIN_FWVERSION = "v1.8.2";
|
||||
public static final String SHELLY_API_MIN_FWCOIOT = "v1.6";// v1.6.0+
|
||||
public static final String SHELLY_API_FWCOIOT2 = "v1.8";// CoAP 2 with FW 1.8+
|
||||
public static final String SHELLY_API_FW_110 = "v1.10"; // FW 1.10 or newer detected, activates some add feature
|
||||
|
@ -17,7 +17,6 @@ import static org.openhab.binding.shelly.internal.ShellyBindingConstants.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
@ -29,6 +28,8 @@ import org.openhab.binding.shelly.internal.handler.ShellyLightHandler;
|
||||
import org.openhab.binding.shelly.internal.handler.ShellyManagerInterface;
|
||||
import org.openhab.binding.shelly.internal.handler.ShellyProtectedHandler;
|
||||
import org.openhab.binding.shelly.internal.handler.ShellyRelayHandler;
|
||||
import org.openhab.binding.shelly.internal.handler.ShellyThingInterface;
|
||||
import org.openhab.binding.shelly.internal.handler.ShellyThingTable;
|
||||
import org.openhab.binding.shelly.internal.provider.ShellyTranslationProvider;
|
||||
import org.openhab.binding.shelly.internal.util.ShellyUtils;
|
||||
import org.openhab.core.io.net.http.HttpClientFactory;
|
||||
@ -63,7 +64,7 @@ public class ShellyHandlerFactory extends BaseThingHandlerFactory {
|
||||
private final ShellyTranslationProvider messages;
|
||||
private final ShellyCoapServer coapServer;
|
||||
|
||||
private final Map<String, ShellyBaseHandler> deviceListeners = new ConcurrentHashMap<>();
|
||||
private final ShellyThingTable thingTable;
|
||||
private ShellyBindingConfiguration bindingConfig = new ShellyBindingConfiguration();
|
||||
private String localIP = "";
|
||||
private int httpPort = -1;
|
||||
@ -77,8 +78,9 @@ public class ShellyHandlerFactory extends BaseThingHandlerFactory {
|
||||
*/
|
||||
@Activate
|
||||
public ShellyHandlerFactory(@Reference NetworkAddressService networkAddressService,
|
||||
@Reference ShellyTranslationProvider translationProvider, @Reference HttpClientFactory httpClientFactory,
|
||||
ComponentContext componentContext, Map<String, Object> configProperties) {
|
||||
@Reference ShellyTranslationProvider translationProvider, @Reference ShellyThingTable thingTable,
|
||||
@Reference HttpClientFactory httpClientFactory, ComponentContext componentContext,
|
||||
Map<String, Object> configProperties) {
|
||||
logger.debug("Activate Shelly HandlerFactory");
|
||||
super.activate(componentContext);
|
||||
messages = translationProvider;
|
||||
@ -100,6 +102,7 @@ public class ShellyHandlerFactory extends BaseThingHandlerFactory {
|
||||
}
|
||||
logger.debug("Using OH HTTP port {}", httpPort);
|
||||
|
||||
this.thingTable = thingTable;
|
||||
this.coapServer = new ShellyCoapServer();
|
||||
|
||||
// Promote Shelly Manager usage
|
||||
@ -137,8 +140,8 @@ public class ShellyHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
if (handler != null) {
|
||||
String uid = thing.getUID().getAsString();
|
||||
deviceListeners.put(uid, handler);
|
||||
logger.debug("Thing handler for uid {} added, total things = {}", uid, deviceListeners.size());
|
||||
thingTable.addThing(uid, handler);
|
||||
logger.debug("Thing handler for uid {} added, total things = {}", uid, thingTable.size());
|
||||
return handler;
|
||||
}
|
||||
|
||||
@ -147,7 +150,11 @@ public class ShellyHandlerFactory extends BaseThingHandlerFactory {
|
||||
}
|
||||
|
||||
public Map<String, ShellyManagerInterface> getThingHandlers() {
|
||||
return new HashMap<>(deviceListeners);
|
||||
Map<String, ShellyManagerInterface> table = new HashMap<>();
|
||||
for (Map.Entry<String, ShellyThingInterface> entry : thingTable.getTable().entrySet()) {
|
||||
table.put(entry.getKey(), (ShellyManagerInterface) entry.getValue());
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -157,7 +164,7 @@ public class ShellyHandlerFactory extends BaseThingHandlerFactory {
|
||||
protected synchronized void removeHandler(@NonNull ThingHandler thingHandler) {
|
||||
if (thingHandler instanceof ShellyBaseHandler) {
|
||||
String uid = thingHandler.getThing().getUID().getAsString();
|
||||
deviceListeners.remove(uid);
|
||||
thingTable.removeThing(uid);
|
||||
}
|
||||
}
|
||||
|
||||
@ -172,8 +179,8 @@ public class ShellyHandlerFactory extends BaseThingHandlerFactory {
|
||||
public void onEvent(String ipAddress, String deviceName, String componentIndex, String eventType,
|
||||
Map<String, String> parameters) {
|
||||
logger.trace("{}: Dispatch event to thing handler", deviceName);
|
||||
for (Map.Entry<String, ShellyBaseHandler> listener : deviceListeners.entrySet()) {
|
||||
ShellyBaseHandler thingHandler = listener.getValue();
|
||||
for (Map.Entry<String, ShellyThingInterface> listener : thingTable.getTable().entrySet()) {
|
||||
ShellyBaseHandler thingHandler = (ShellyBaseHandler) listener.getValue();
|
||||
if (thingHandler.onEvent(ipAddress, deviceName, componentIndex, eventType, parameters)) {
|
||||
// event processed
|
||||
return;
|
||||
|
@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.shelly.internal.api;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellyControlRoller;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellyOtaCheckResult;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellySettingsDevice;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellySettingsLogin;
|
||||
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;
|
||||
|
||||
/**
|
||||
* The {@link ShellyApiInterface} Defines device API
|
||||
*
|
||||
* @author Markus Michels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface ShellyApiInterface {
|
||||
public boolean isInitialized();
|
||||
|
||||
public void setConfig(String thingName, ShellyThingConfiguration config);
|
||||
|
||||
public ShellySettingsDevice getDeviceInfo() throws ShellyApiException;
|
||||
|
||||
public ShellyDeviceProfile getDeviceProfile(String thingType) throws ShellyApiException;
|
||||
|
||||
public ShellySettingsStatus getStatus() throws ShellyApiException;
|
||||
|
||||
public void setLedStatus(String ledName, Boolean value) throws ShellyApiException;
|
||||
|
||||
public void setSleepTime(int value) throws ShellyApiException;
|
||||
|
||||
public ShellyStatusRelay getRelayStatus(Integer relayIndex) throws ShellyApiException;
|
||||
|
||||
public void setRelayTurn(int id, String turnMode) throws ShellyApiException;
|
||||
|
||||
public ShellyControlRoller getRollerStatus(int rollerIndex) throws ShellyApiException;
|
||||
|
||||
public void setRollerTurn(int relayIndex, String turnMode) throws ShellyApiException;
|
||||
|
||||
public void setRollerPos(int relayIndex, int position) throws ShellyApiException;
|
||||
|
||||
public void setTimer(int index, String timerName, int value) throws ShellyApiException;
|
||||
|
||||
public ShellyStatusSensor getSensorStatus() throws ShellyApiException;
|
||||
|
||||
public ShellyStatusLight getLightStatus() throws ShellyApiException;
|
||||
|
||||
public ShellyShortLightStatus getLightStatus(int index) throws ShellyApiException;
|
||||
|
||||
public void setLightMode(String mode) throws ShellyApiException;
|
||||
|
||||
public void setLightParm(int lightIndex, String parm, String value) throws ShellyApiException;
|
||||
|
||||
public void setLightParms(int lightIndex, Map<String, String> parameters) throws ShellyApiException;
|
||||
|
||||
public ShellyShortLightStatus setLightTurn(int id, String turnMode) throws ShellyApiException;
|
||||
|
||||
public void setBrightness(int id, int brightness, boolean autoOn) throws ShellyApiException;
|
||||
|
||||
// Valve
|
||||
public void setValveMode(int id, boolean auto) throws ShellyApiException;
|
||||
|
||||
public void setValveTemperature(int valveId, int value) throws ShellyApiException;
|
||||
|
||||
public void setValveProfile(int valveId, int value) throws ShellyApiException;
|
||||
|
||||
public void setValvePosition(int valveId, double value) throws ShellyApiException;
|
||||
|
||||
public void setValveBoostTime(int valveId, int value) throws ShellyApiException;
|
||||
|
||||
public void startValveBoost(int valveId, int value) throws ShellyApiException;
|
||||
|
||||
public ShellyOtaCheckResult checkForUpdate() throws ShellyApiException;
|
||||
|
||||
public ShellySettingsLogin getLoginSettings() throws ShellyApiException;
|
||||
|
||||
public ShellySettingsLogin setLoginCredentials(String user, String password) throws ShellyApiException;
|
||||
|
||||
public String setWiFiRecovery(boolean enable) throws ShellyApiException;
|
||||
|
||||
public String deviceReboot() throws ShellyApiException;
|
||||
|
||||
public String setDebug(boolean enabled) throws ShellyApiException;
|
||||
|
||||
public String getDebugLog(String id) throws ShellyApiException;
|
||||
|
||||
public String setCloud(boolean enabled) throws ShellyApiException;
|
||||
|
||||
public String setApRoaming(boolean enable) throws ShellyApiException;
|
||||
|
||||
public String factoryReset() throws ShellyApiException;
|
||||
|
||||
public String resetStaCache() throws ShellyApiException;
|
||||
|
||||
public int getTimeoutsRecovered();
|
||||
|
||||
public int getTimeoutErrors();
|
||||
|
||||
public String getCoIoTDescription() throws ShellyApiException;
|
||||
|
||||
public ShellySettingsLogin setCoIoTPeer(String peer) throws ShellyApiException;
|
||||
|
||||
public void setActionURLs() throws ShellyApiException;
|
||||
|
||||
public void sendIRKey(String keyCode) throws ShellyApiException, IllegalArgumentException;
|
||||
}
|
@ -60,6 +60,7 @@ public class ShellyApiJsonDTO {
|
||||
public static final String SHELLY_WAKEUPT_PERIODIC = "PERIODIC"; // periodic wakeup
|
||||
public static final String SHELLY_WAKEUPT_BUTTON = "BUTTON"; // button pressed
|
||||
public static final String SHELLY_WAKEUPT_POWERON = "POWERON"; // device powered up
|
||||
public static final String SHELLY_WAKEUPT_EXT_POWER = "EXT_POWER"; // charger connected
|
||||
public static final String SHELLY_WAKEUPT_UNKNOWN = "UNKNOWN"; // other event
|
||||
|
||||
//
|
||||
@ -94,6 +95,12 @@ public class ShellyApiJsonDTO {
|
||||
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_ROLLER_CALIB = "roller_calibrating";
|
||||
|
||||
// Roller states
|
||||
public static final String SHELLY_RSTATE_OPEN = "open";
|
||||
public static final String SHELLY_RSTATE_STOP = "stop";
|
||||
public static final String SHELLY_RSTATE_CLOSE = "close";
|
||||
|
||||
// Sensors
|
||||
public static final String SHELLY_EVENT_SENSORREPORT = "report";
|
||||
@ -116,6 +123,8 @@ public class ShellyApiJsonDTO {
|
||||
//
|
||||
// API values
|
||||
//
|
||||
public static final double SHELLY_API_INVTEMP = -999.0;
|
||||
|
||||
public static final String SHELLY_BTNT_MOMENTARY = "momentary";
|
||||
public static final String SHELLY_BTNT_MOM_ON_RELEASE = "momentary_on_release";
|
||||
public static final String SHELLY_BTNT_ONE_BUTTON = "one_button";
|
||||
@ -128,6 +137,8 @@ public class ShellyApiJsonDTO {
|
||||
public static final String SHELLY_STATE_STOP = "stop";
|
||||
|
||||
public static final String SHELLY_INP_MODE_OPENCLOSE = "openclose";
|
||||
public static final String SHELLY_INP_MODE_ONEBUTTON = "onebutton";
|
||||
|
||||
public static final String SHELLY_OBSTMODE_DISABLED = "disabled";
|
||||
public static final String SHELLY_SAFETYM_WHILEOPENING = "while_opening";
|
||||
|
||||
@ -359,8 +370,6 @@ public class ShellyApiJsonDTO {
|
||||
|
||||
public static class ShellySettingsRelay {
|
||||
public String name;
|
||||
public Boolean ison;
|
||||
public Boolean overpower;
|
||||
@SerializedName("default_state")
|
||||
public String defaultState; // Accepted values: off, on, last, switch
|
||||
@SerializedName("btn_type")
|
||||
@ -393,6 +402,16 @@ public class ShellyApiJsonDTO {
|
||||
public String pushLongUrl; // to access when roller stopped
|
||||
@SerializedName("shortpush_url")
|
||||
public String pushShortUrl; // to access when roller stopped
|
||||
|
||||
// Status information
|
||||
public Boolean ison;
|
||||
public Boolean overpower;
|
||||
@SerializedName("is_valid")
|
||||
public Boolean isValid;
|
||||
@SerializedName("ext_temperature")
|
||||
public ShellyStatusSensor.ShellyExtTemperature extTemperature; // Shelly 1/1PM: sensor values
|
||||
@SerializedName("ext_humidity")
|
||||
public ShellyStatusSensor.ShellyExtHumidity extHumidity; // Shelly 1/1PM: sensor values
|
||||
}
|
||||
|
||||
public static class ShellySettingsDimmer {
|
||||
@ -591,18 +610,19 @@ public class ShellyApiJsonDTO {
|
||||
public Boolean calibrated;
|
||||
|
||||
public ArrayList<ShellySettingsRelay> relays;
|
||||
public Double voltage; // AC voltage for Shelly 2.5
|
||||
@SerializedName("supply_voltage")
|
||||
public Long supplyVoltage; // Shelly 1PM/1L: 0=110V, 1=220V
|
||||
public ArrayList<ShellySettingsRoller> rollers;
|
||||
public ArrayList<ShellySettingsDimmer> dimmers;
|
||||
public ArrayList<ShellySettingsRgbwLight> lights;
|
||||
public ArrayList<ShellySettingsEMeter> emeters;
|
||||
public ArrayList<ShellySettingsInput> inputs; // ix3
|
||||
|
||||
public ArrayList<ShellyThermnostat> thermostats; // TRV
|
||||
|
||||
public Double voltage; // AC voltage for Shelly 2.5
|
||||
@SerializedName("supply_voltage")
|
||||
public Long supplyVoltage; // Shelly 1PM/1L: 0=110V, 1=220V
|
||||
|
||||
@SerializedName("temperature_units")
|
||||
public String temperatureUnits; // Either'C'or'F'
|
||||
public String temperatureUnits = "C"; // Either'C'or'F'
|
||||
|
||||
@SerializedName("led_status_disable")
|
||||
public Boolean ledStatusDisable; // PlugS only Disable LED indication for network
|
||||
@ -641,7 +661,7 @@ public class ShellyApiJsonDTO {
|
||||
|
||||
// Roller with FW 1.9.2+
|
||||
@SerializedName("favorites_enabled")
|
||||
public Boolean favoritesEnabled;
|
||||
public Boolean favoritesEnabled = false;
|
||||
public ArrayList<ShellyFavPos> favorites;
|
||||
|
||||
// Motion
|
||||
@ -686,7 +706,7 @@ public class ShellyApiJsonDTO {
|
||||
public ShellyStatusMqtt mqtt;
|
||||
|
||||
public String time;
|
||||
public Integer serial;
|
||||
public Integer serial = -1;
|
||||
@SerializedName("has_update")
|
||||
public Boolean hasUpdate;
|
||||
public String mac;
|
||||
@ -709,7 +729,7 @@ public class ShellyApiJsonDTO {
|
||||
|
||||
// Internal device temp
|
||||
public ShellyStatusSensor.ShellySensorTmp tmp; // Shelly 1PM
|
||||
public Double temperature; // Shelly 2.5
|
||||
public Double temperature = SHELLY_API_INVTEMP; // Shelly 2.5
|
||||
public Boolean overtemperature;
|
||||
|
||||
// Shelly Dimmer only
|
||||
@ -838,16 +858,16 @@ public class ShellyApiJsonDTO {
|
||||
public Integer currentPos; // current position 0..100, 100=open
|
||||
}
|
||||
|
||||
public class ShellyOtaCheckResult {
|
||||
public static class ShellyOtaCheckResult {
|
||||
public String status;
|
||||
}
|
||||
|
||||
public class ShellyApRoaming {
|
||||
public static class ShellyApRoaming {
|
||||
public Boolean enabled;
|
||||
public Integer threshold;
|
||||
}
|
||||
|
||||
public class ShellySensorSleepMode {
|
||||
public static class ShellySensorSleepMode {
|
||||
public Integer period;
|
||||
public String unit;
|
||||
}
|
||||
|
@ -58,6 +58,7 @@ public class ShellyDeviceProfile {
|
||||
public ShellySettingsStatus status = new ShellySettingsStatus();
|
||||
|
||||
public String hostname = "";
|
||||
public String name = "";
|
||||
public String mode = "";
|
||||
public boolean discoverable = true;
|
||||
public boolean auth = false;
|
||||
@ -118,6 +119,7 @@ public class ShellyDeviceProfile {
|
||||
settings = gs; // only update when no exception
|
||||
|
||||
// General settings
|
||||
name = getString(settings.name);
|
||||
deviceType = getString(settings.device.type);
|
||||
mac = getString(settings.device.mac);
|
||||
hostname = settings.device.hostname != null && !settings.device.hostname.isEmpty()
|
||||
@ -251,6 +253,10 @@ public class ShellyDeviceProfile {
|
||||
return numRelays == 1 ? CHANNEL_GROUP_STATUS : CHANNEL_GROUP_STATUS + idx;
|
||||
}
|
||||
|
||||
public String getMeterGroup(int idx) {
|
||||
return numMeters > 1 ? CHANNEL_GROUP_METER + (idx + 1) : CHANNEL_GROUP_METER;
|
||||
}
|
||||
|
||||
public String getInputGroup(int i) {
|
||||
int idx = i + 1; // group names are 1-based
|
||||
if (isRGBW2) {
|
||||
@ -275,7 +281,7 @@ public class ShellyDeviceProfile {
|
||||
// Roller has 2 relays, but it will be mapped to 1 roller with 2 inputs
|
||||
return String.valueOf(idx);
|
||||
} else if (hasRelays) {
|
||||
return (numRelays) == 1 && (numInputs >= 2) ? String.valueOf(idx) : "";
|
||||
return numRelays == 1 && numInputs >= 2 ? String.valueOf(idx) : "";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
@ -288,7 +294,7 @@ public class ShellyDeviceProfile {
|
||||
String btnType = "";
|
||||
if (isButton) {
|
||||
return true;
|
||||
} else if (isIX3 && (settings.inputs != null) && (idx < settings.inputs.size())) {
|
||||
} else if (isIX3 && settings.inputs != null && idx < settings.inputs.size()) {
|
||||
ShellySettingsInput input = settings.inputs.get(idx);
|
||||
btnType = getString(input.btnType);
|
||||
} else if (isDimmer) {
|
||||
@ -315,7 +321,6 @@ public class ShellyDeviceProfile {
|
||||
btnType = light.btnType;
|
||||
}
|
||||
|
||||
logger.trace("{}: Checking for trigger, button-type[{}] is {}", thingName, idx, btnType);
|
||||
return btnType.equalsIgnoreCase(SHELLY_BTNT_MOMENTARY) || btnType.equalsIgnoreCase(SHELLY_BTNT_MOM_ON_RELEASE)
|
||||
|| btnType.equalsIgnoreCase(SHELLY_BTNT_ONE_BUTTON) || btnType.equalsIgnoreCase(SHELLY_BTNT_TWO_BUTTON)
|
||||
|| btnType.equalsIgnoreCase(SHELLY_BTNT_DETACHED);
|
||||
|
@ -60,7 +60,7 @@ import com.google.gson.JsonSyntaxException;
|
||||
* @author Markus Michels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ShellyHttpApi {
|
||||
public class ShellyHttpApi implements ShellyApiInterface {
|
||||
public static final String HTTP_HEADER_AUTH = "Authorization";
|
||||
public static final String HTTP_AUTH_TYPE_BASIC = "Basic";
|
||||
public static final String CONTENT_TYPE_JSON = "application/json; charset=UTF-8";
|
||||
@ -82,19 +82,23 @@ public class ShellyHttpApi {
|
||||
profile.initFromThingType(thingName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConfig(String thingName, ShellyThingConfiguration config) {
|
||||
this.thingName = thingName;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public ShellySettingsDevice getDevInfo() throws ShellyApiException {
|
||||
@Override
|
||||
public ShellySettingsDevice getDeviceInfo() throws ShellyApiException {
|
||||
return callApi(SHELLY_URL_DEVINFO, ShellySettingsDevice.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String setDebug(boolean enabled) throws ShellyApiException {
|
||||
return callApi(SHELLY_URL_SETTINGS + "?debug_enable=" + Boolean.valueOf(enabled), String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDebugLog(String id) throws ShellyApiException {
|
||||
return callApi("/debug/" + id, String.class);
|
||||
}
|
||||
@ -106,6 +110,7 @@ public class ShellyHttpApi {
|
||||
* @return Initialized ShellyDeviceProfile
|
||||
* @throws ShellyApiException
|
||||
*/
|
||||
@Override
|
||||
public ShellyDeviceProfile getDeviceProfile(String thingType) throws ShellyApiException {
|
||||
String json = request(SHELLY_URL_SETTINGS);
|
||||
if (json.contains("\"type\":\"SHDM-")) {
|
||||
@ -131,6 +136,7 @@ public class ShellyHttpApi {
|
||||
return profile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return profile.initialized;
|
||||
}
|
||||
@ -141,6 +147,7 @@ public class ShellyHttpApi {
|
||||
* @return Device settings/status as ShellySettingsStatus object
|
||||
* @throws ShellyApiException
|
||||
*/
|
||||
@Override
|
||||
public ShellySettingsStatus getStatus() throws ShellyApiException {
|
||||
String json = "";
|
||||
try {
|
||||
@ -156,42 +163,55 @@ public class ShellyHttpApi {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShellyStatusRelay getRelayStatus(Integer relayIndex) throws ShellyApiException {
|
||||
return callApi(SHELLY_URL_STATUS_RELEAY + "/" + relayIndex.toString(), ShellyStatusRelay.class);
|
||||
}
|
||||
|
||||
public ShellyShortLightStatus setRelayTurn(Integer id, String turnMode) throws ShellyApiException {
|
||||
@Override
|
||||
public void setRelayTurn(int id, String turnMode) throws ShellyApiException {
|
||||
callApi(getControlUriPrefix(id) + "?" + SHELLY_LIGHT_TURN + "=" + turnMode.toLowerCase(),
|
||||
ShellyShortLightStatus.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShellyShortLightStatus setLightTurn(int id, String turnMode) throws ShellyApiException {
|
||||
return callApi(getControlUriPrefix(id) + "?" + SHELLY_LIGHT_TURN + "=" + turnMode.toLowerCase(),
|
||||
ShellyShortLightStatus.class);
|
||||
}
|
||||
|
||||
public void setBrightness(Integer id, Integer brightness, boolean autoOn) throws ShellyApiException {
|
||||
@Override
|
||||
public void setBrightness(int id, int brightness, boolean autoOn) throws ShellyApiException {
|
||||
String turn = autoOn ? SHELLY_LIGHT_TURN + "=" + SHELLY_API_ON + "&" : "";
|
||||
request(getControlUriPrefix(id) + "?" + turn + "brightness=" + brightness.toString());
|
||||
request(getControlUriPrefix(id) + "?" + turn + "brightness=" + brightness);
|
||||
}
|
||||
|
||||
public ShellyControlRoller getRollerStatus(Integer rollerIndex) throws ShellyApiException {
|
||||
String uri = SHELLY_URL_CONTROL_ROLLER + "/" + rollerIndex.toString() + "/pos";
|
||||
@Override
|
||||
public ShellyControlRoller getRollerStatus(int idx) throws ShellyApiException {
|
||||
String uri = SHELLY_URL_CONTROL_ROLLER + "/" + idx + "/pos";
|
||||
return callApi(uri, ShellyControlRoller.class);
|
||||
}
|
||||
|
||||
public void setRollerTurn(Integer relayIndex, String turnMode) throws ShellyApiException {
|
||||
request(SHELLY_URL_CONTROL_ROLLER + "/" + relayIndex.toString() + "?go=" + turnMode);
|
||||
@Override
|
||||
public void setRollerTurn(int idx, String turnMode) throws ShellyApiException {
|
||||
request(SHELLY_URL_CONTROL_ROLLER + "/" + idx + "?go=" + turnMode);
|
||||
}
|
||||
|
||||
public void setRollerPos(Integer relayIndex, Integer position) throws ShellyApiException {
|
||||
request(SHELLY_URL_CONTROL_ROLLER + "/" + relayIndex.toString() + "?go=to_pos&roller_pos="
|
||||
+ position.toString());
|
||||
@Override
|
||||
public void setRollerPos(int id, int position) throws ShellyApiException {
|
||||
request(SHELLY_URL_CONTROL_ROLLER + "/" + id + "?go=to_pos&roller_pos=" + position);
|
||||
}
|
||||
|
||||
public void setRollerTimer(Integer relayIndex, Integer timer) throws ShellyApiException {
|
||||
request(SHELLY_URL_CONTROL_ROLLER + "/" + relayIndex.toString() + "?timer=" + timer.toString());
|
||||
public void setRollerTimer(int idx, int timer) throws ShellyApiException {
|
||||
request(SHELLY_URL_CONTROL_ROLLER + "/" + idx + "?timer=" + timer);
|
||||
}
|
||||
|
||||
public ShellyShortLightStatus getLightStatus(Integer index) throws ShellyApiException {
|
||||
@Override
|
||||
public ShellyShortLightStatus getLightStatus(int index) throws ShellyApiException {
|
||||
return callApi(getControlUriPrefix(index), ShellyShortLightStatus.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShellyStatusSensor getSensorStatus() throws ShellyApiException {
|
||||
ShellyStatusSensor status = callApi(SHELLY_URL_STATUS, ShellyStatusSensor.class);
|
||||
if (profile.isSense) {
|
||||
@ -210,6 +230,7 @@ public class ShellyHttpApi {
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimer(int index, String timerName, int value) throws ShellyApiException {
|
||||
String type = SHELLY_CLASS_RELAY;
|
||||
if (profile.isRoller) {
|
||||
@ -221,14 +242,17 @@ public class ShellyHttpApi {
|
||||
request(uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSleepTime(int value) throws ShellyApiException {
|
||||
request(SHELLY_URL_SETTINGS + "?sleep_time=" + value);
|
||||
}
|
||||
|
||||
public void setTemperature(int valveId, int value) throws ShellyApiException {
|
||||
@Override
|
||||
public void setValveTemperature(int valveId, int value) throws ShellyApiException {
|
||||
request("/thermostat/" + valveId + "?target_t_enabled=1&target_t=" + value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValveMode(int valveId, boolean auto) throws ShellyApiException {
|
||||
String uri = "/settings/thermostat/" + valveId + "?target_t_enabled=" + (auto ? "1" : "0");
|
||||
if (auto) {
|
||||
@ -237,24 +261,29 @@ public class ShellyHttpApi {
|
||||
request(uri); // percentage to open the valve
|
||||
}
|
||||
|
||||
public void setProfile(int valveId, int value) throws ShellyApiException {
|
||||
@Override
|
||||
public void setValveProfile(int valveId, int value) throws ShellyApiException {
|
||||
String uri = "/settings/thermostat/" + valveId + "?";
|
||||
request(uri + (value == 0 ? "schedule=0" : "schedule=1&schedule_profile=" + value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValvePosition(int valveId, double value) throws ShellyApiException {
|
||||
request("/thermostat/" + valveId + "?pos=" + value); // percentage to open the valve
|
||||
}
|
||||
|
||||
public void setBoostTime(int valveId, int value) throws ShellyApiException {
|
||||
@Override
|
||||
public void setValveBoostTime(int valveId, int value) throws ShellyApiException {
|
||||
request("/settings/thermostat/" + valveId + "?boost_minutes=" + value);
|
||||
}
|
||||
|
||||
public void startBoost(int valveId, int value) throws ShellyApiException {
|
||||
@Override
|
||||
public void startValveBoost(int valveId, int value) throws ShellyApiException {
|
||||
int minutes = value != -1 ? value : getInteger(profile.settings.thermostats.get(0).boostMinutes);
|
||||
request("/thermostat/" + valveId + "?boost_minutes=" + minutes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLedStatus(String ledName, Boolean value) throws ShellyApiException {
|
||||
request(SHELLY_URL_SETTINGS + "?" + ledName + "=" + (value ? SHELLY_API_TRUE : SHELLY_API_FALSE));
|
||||
}
|
||||
@ -263,6 +292,7 @@ public class ShellyHttpApi {
|
||||
return callApi(SHELLY_URL_SETTINGS_LIGHT, ShellySettingsLight.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShellyStatusLight getLightStatus() throws ShellyApiException {
|
||||
return callApi(SHELLY_URL_STATUS, ShellyStatusLight.class);
|
||||
}
|
||||
@ -271,15 +301,18 @@ public class ShellyHttpApi {
|
||||
request(SHELLY_URL_SETTINGS + "?" + parm + "=" + value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShellySettingsLogin getLoginSettings() throws ShellyApiException {
|
||||
return callApi(SHELLY_URL_SETTINGS + "/login", ShellySettingsLogin.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShellySettingsLogin setLoginCredentials(String user, String password) throws ShellyApiException {
|
||||
return callApi(SHELLY_URL_SETTINGS + "/login?enabled=yes&username=" + urlEncode(user) + "&password="
|
||||
+ urlEncode(password), ShellySettingsLogin.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCoIoTDescription() throws ShellyApiException {
|
||||
try {
|
||||
return callApi("/cit/d", String.class);
|
||||
@ -291,31 +324,38 @@ public class ShellyHttpApi {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShellySettingsLogin setCoIoTPeer(String peer) throws ShellyApiException {
|
||||
return callApi(SHELLY_URL_SETTINGS + "?coiot_enable=true&coiot_peer=" + peer, ShellySettingsLogin.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String deviceReboot() throws ShellyApiException {
|
||||
return callApi(SHELLY_URL_RESTART, String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String factoryReset() throws ShellyApiException {
|
||||
return callApi(SHELLY_URL_SETTINGS + "?reset=true", String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShellyOtaCheckResult checkForUpdate() throws ShellyApiException {
|
||||
return callApi("/ota/check", ShellyOtaCheckResult.class); // nw FW 1.10+: trigger update check
|
||||
}
|
||||
|
||||
@Override
|
||||
public String setWiFiRecovery(boolean enable) throws ShellyApiException {
|
||||
return callApi(SHELLY_URL_SETTINGS + "?wifirecovery_reboot_enabled=" + (enable ? "true" : "false"),
|
||||
String.class); // FW 1.10+: Enable auto-restart on WiFi problems
|
||||
}
|
||||
|
||||
@Override
|
||||
public String setApRoaming(boolean enable) throws ShellyApiException { // FW 1.10+: Enable AP Roadming
|
||||
return callApi(SHELLY_URL_SETTINGS + "?ap_roaming_enabled=" + (enable ? "true" : "false"), String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resetStaCache() throws ShellyApiException { // FW 1.10+: Reset cached STA/AP list and to a rescan
|
||||
return callApi("/sta_cache_reset", String.class);
|
||||
}
|
||||
@ -324,6 +364,7 @@ public class ShellyHttpApi {
|
||||
return callApi("/ota?" + uri, ShellySettingsUpdate.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String setCloud(boolean enabled) throws ShellyApiException {
|
||||
return callApi("/settings/cloud/?enabled=" + (enabled ? "1" : "0"), String.class);
|
||||
}
|
||||
@ -334,6 +375,7 @@ public class ShellyHttpApi {
|
||||
* @param mode
|
||||
* @throws ShellyApiException
|
||||
*/
|
||||
@Override
|
||||
public void setLightMode(String mode) throws ShellyApiException {
|
||||
if (!mode.isEmpty() && !profile.mode.equals(mode)) {
|
||||
setLightSetting(SHELLY_API_MODE, mode);
|
||||
@ -350,13 +392,15 @@ public class ShellyHttpApi {
|
||||
* @param value The value
|
||||
* @throws ShellyApiException
|
||||
*/
|
||||
public void setLightParm(Integer lightIndex, String parm, String value) throws ShellyApiException {
|
||||
@Override
|
||||
public void setLightParm(int lightIndex, String parm, String value) throws ShellyApiException {
|
||||
// Bulb, RGW2: /<color mode>/<light id>?parm?value
|
||||
// Dimmer: /light/<light id>?parm=value
|
||||
request(getControlUriPrefix(lightIndex) + "?" + parm + "=" + value);
|
||||
}
|
||||
|
||||
public void setLightParms(Integer lightIndex, Map<String, String> parameters) throws ShellyApiException {
|
||||
@Override
|
||||
public void setLightParms(int lightIndex, Map<String, String> parameters) throws ShellyApiException {
|
||||
String url = getControlUriPrefix(lightIndex) + "?";
|
||||
int i = 0;
|
||||
for (String key : parameters.keySet()) {
|
||||
@ -405,6 +449,7 @@ public class ShellyHttpApi {
|
||||
* @throws ShellyApiException
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
@Override
|
||||
public void sendIRKey(String keyCode) throws ShellyApiException, IllegalArgumentException {
|
||||
String type = "";
|
||||
if (profile.irCodes.containsKey(keyCode)) {
|
||||
@ -437,6 +482,7 @@ public class ShellyHttpApi {
|
||||
* @param ShellyApiException
|
||||
* @throws ShellyApiException
|
||||
*/
|
||||
@Override
|
||||
public void setActionURLs() throws ShellyApiException {
|
||||
setRelayEvents();
|
||||
setDimmerEvents();
|
||||
@ -659,10 +705,12 @@ public class ShellyHttpApi {
|
||||
return uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTimeoutErrors() {
|
||||
return timeoutErrors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTimeoutsRecovered() {
|
||||
return timeoutsRecovered;
|
||||
}
|
||||
|
@ -21,13 +21,13 @@ import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyApiInterface;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyDeviceProfile;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyHttpApi;
|
||||
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.CoIotSensor;
|
||||
import org.openhab.binding.shelly.internal.handler.ShellyBaseHandler;
|
||||
import org.openhab.binding.shelly.internal.handler.ShellyColorUtils;
|
||||
import org.openhab.binding.shelly.internal.handler.ShellyThingInterface;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.OpenClosedType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
@ -49,9 +49,9 @@ import com.google.gson.JsonSyntaxException;
|
||||
public class ShellyCoIoTProtocol {
|
||||
private final Logger logger = LoggerFactory.getLogger(ShellyCoIoTProtocol.class);
|
||||
protected final String thingName;
|
||||
protected final ShellyBaseHandler thingHandler;
|
||||
protected final ShellyThingInterface thingHandler;
|
||||
protected final ShellyDeviceProfile profile;
|
||||
protected final ShellyHttpApi api;
|
||||
protected final ShellyApiInterface api;
|
||||
protected final Map<String, CoIotDescrBlk> blkMap;
|
||||
protected final Map<String, CoIotDescrSen> sensorMap;
|
||||
private final Gson gson = new GsonBuilder().create();
|
||||
@ -63,7 +63,7 @@ public class ShellyCoIoTProtocol {
|
||||
protected String[] inputEvent = { "", "", "", "", "", "", "", "" };
|
||||
protected String lastWakeup = "";
|
||||
|
||||
public ShellyCoIoTProtocol(String thingName, ShellyBaseHandler thingHandler, Map<String, CoIotDescrBlk> blkMap,
|
||||
public ShellyCoIoTProtocol(String thingName, ShellyThingInterface thingHandler, Map<String, CoIotDescrBlk> blkMap,
|
||||
Map<String, CoIotDescrSen> sensorMap) {
|
||||
this.thingName = thingName;
|
||||
this.thingHandler = thingHandler;
|
||||
|
@ -24,8 +24,8 @@ import org.eclipse.jdt.annotation.Nullable;
|
||||
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.CoIotSensor;
|
||||
import org.openhab.binding.shelly.internal.handler.ShellyBaseHandler;
|
||||
import org.openhab.binding.shelly.internal.handler.ShellyColorUtils;
|
||||
import org.openhab.binding.shelly.internal.handler.ShellyThingInterface;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.unit.ImperialUnits;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
@ -43,7 +43,7 @@ import org.slf4j.LoggerFactory;
|
||||
public class ShellyCoIoTVersion1 extends ShellyCoIoTProtocol implements ShellyCoIoTInterface {
|
||||
private final Logger logger = LoggerFactory.getLogger(ShellyCoIoTVersion1.class);
|
||||
|
||||
public ShellyCoIoTVersion1(String thingName, ShellyBaseHandler thingHandler, Map<String, CoIotDescrBlk> blkMap,
|
||||
public ShellyCoIoTVersion1(String thingName, ShellyThingInterface thingHandler, Map<String, CoIotDescrBlk> blkMap,
|
||||
Map<String, CoIotDescrSen> sensorMap) {
|
||||
super(thingName, thingHandler, blkMap, sensorMap);
|
||||
}
|
||||
@ -207,7 +207,8 @@ public class ShellyCoIoTVersion1 extends ShellyCoIoTProtocol implements ShellyCo
|
||||
getStringType(s.valueStr));
|
||||
break;
|
||||
case "concentration":// Shelly Gas
|
||||
updateChannel(updates, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_PPM, getDecimal(s.value));
|
||||
updateChannel(updates, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_PPM,
|
||||
toQuantityType(getDouble(s.value), DIGITS_NONE, Units.PARTS_PER_MILLION));
|
||||
break;
|
||||
case "sensorerror":
|
||||
updateChannel(updates, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_ERROR, getStringType(s.valueStr));
|
||||
|
@ -29,8 +29,8 @@ import org.eclipse.jdt.annotation.Nullable;
|
||||
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.CoIotSensor;
|
||||
import org.openhab.binding.shelly.internal.handler.ShellyBaseHandler;
|
||||
import org.openhab.binding.shelly.internal.handler.ShellyColorUtils;
|
||||
import org.openhab.binding.shelly.internal.handler.ShellyThingInterface;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.OpenClosedType;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
@ -49,7 +49,7 @@ import org.slf4j.LoggerFactory;
|
||||
public class ShellyCoIoTVersion2 extends ShellyCoIoTProtocol implements ShellyCoIoTInterface {
|
||||
private final Logger logger = LoggerFactory.getLogger(ShellyCoIoTVersion2.class);
|
||||
|
||||
public ShellyCoIoTVersion2(String thingName, ShellyBaseHandler thingHandler, Map<String, CoIotDescrBlk> blkMap,
|
||||
public ShellyCoIoTVersion2(String thingName, ShellyThingInterface thingHandler, Map<String, CoIotDescrBlk> blkMap,
|
||||
Map<String, CoIotDescrSen> sensorMap) {
|
||||
super(thingName, thingHandler, blkMap, sensorMap);
|
||||
}
|
||||
@ -114,12 +114,13 @@ public class ShellyCoIoTVersion2 extends ShellyCoIoTProtocol implements ShellyCo
|
||||
value != 0 ? OpenClosedType.OPEN : OpenClosedType.CLOSED);
|
||||
break;
|
||||
case "3121": // valvePos, Type=S, Range=0/100;
|
||||
updateChannel(updates, CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_POSITION,
|
||||
boolean updated = updateChannel(updates, CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_POSITION,
|
||||
s.value != -1 ? toQuantityType(getDouble(s.value), 0, Units.PERCENT) : UnDefType.UNDEF);
|
||||
break;
|
||||
case "3122": // boostMinutes
|
||||
updateChannel(updates, CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_BTIMER,
|
||||
s.value != -1 ? toQuantityType(s.value, DIGITS_NONE, Units.MINUTE) : UnDefType.UNDEF);
|
||||
if (updated && s.value >= 0 && s.value != thingHandler.getChannelDouble(CHANNEL_GROUP_CONTROL,
|
||||
CHANNEL_CONTROL_POSITION)) {
|
||||
logger.debug("{}: Valve position changed, force update", thingName);
|
||||
thingHandler.requestUpdates(1, false);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
processed = false;
|
||||
@ -197,9 +198,8 @@ public class ShellyCoIoTVersion2 extends ShellyCoIoTProtocol implements ShellyCo
|
||||
// H&T, Fllod, DW only have 1 channel, 1/1PM with Addon have up to to 3 sensors
|
||||
String channel = profile.isSensor ? CHANNEL_SENSOR_TEMP : CHANNEL_SENSOR_TEMP + idx;
|
||||
// Some devices report values = -999 or 99 during fw update
|
||||
boolean valid = value > -50 && value < 90;
|
||||
updateChannel(updates, CHANNEL_GROUP_SENSOR, channel,
|
||||
valid ? toQuantityType(value, DIGITS_TEMP, SIUnits.CELSIUS) : UnDefType.UNDEF);
|
||||
toQuantityType(value, DIGITS_TEMP, SIUnits.CELSIUS));
|
||||
} else {
|
||||
logger.debug("{}: Unable to get extSensorId {} from {}/{}", thingName, sen.id, sen.type, sen.desc);
|
||||
}
|
||||
@ -258,7 +258,6 @@ public class ShellyCoIoTVersion2 extends ShellyCoIoTProtocol implements ShellyCo
|
||||
case "4305": // emeter_2: P, power, W
|
||||
case "4102": // roller_0: P, rollerPower, W, 0-2300, unknown -1
|
||||
case "4202": // roller_1: P, rollerPower, W, 0-2300, unknown -1
|
||||
logger.debug("{}: Updating {}:currentWatts with {}", thingName, mGroup, s.value);
|
||||
updateChannel(updates, mGroup, CHANNEL_METER_CURRENTWATTS,
|
||||
toQuantityType(s.value, DIGITS_WATT, Units.WATT));
|
||||
if (!profile.isRGBW2 && !profile.isRoller) {
|
||||
@ -386,7 +385,7 @@ public class ShellyCoIoTVersion2 extends ShellyCoIoTProtocol implements ShellyCo
|
||||
}
|
||||
break;
|
||||
case "9103": // EVC, cfgChanged, U16
|
||||
if ((lastCfgCount != -1) && (lastCfgCount != s.value)) {
|
||||
if (lastCfgCount == -1 || lastCfgCount != s.value) {
|
||||
thingHandler.requestUpdates(1, true); // refresh config
|
||||
}
|
||||
lastCfgCount = (int) s.value;
|
||||
|
@ -36,8 +36,8 @@ import org.eclipse.californium.core.network.Endpoint;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyApiException;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyApiInterface;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyDeviceProfile;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyHttpApi;
|
||||
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.CoIotDevDescrTypeAdapter;
|
||||
@ -46,8 +46,8 @@ import org.openhab.binding.shelly.internal.coap.ShellyCoapJSonDTO.CoIotGenericSe
|
||||
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.openhab.binding.shelly.internal.handler.ShellyColorUtils;
|
||||
import org.openhab.binding.shelly.internal.handler.ShellyThingInterface;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
import org.openhab.core.types.State;
|
||||
import org.slf4j.Logger;
|
||||
@ -67,7 +67,7 @@ public class ShellyCoapHandler implements ShellyCoapListener {
|
||||
private static final byte[] EMPTY_BYTE = new byte[0];
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(ShellyCoapHandler.class);
|
||||
private final ShellyBaseHandler thingHandler;
|
||||
private final ShellyThingInterface thingHandler;
|
||||
private ShellyThingConfiguration config = new ShellyThingConfiguration();
|
||||
private final GsonBuilder gsonBuilder = new GsonBuilder();
|
||||
private final Gson gson;
|
||||
@ -91,11 +91,11 @@ public class ShellyCoapHandler implements ShellyCoapListener {
|
||||
private Map<String, CoIotDescrBlk> blkMap = new LinkedHashMap<>();
|
||||
private Map<String, CoIotDescrSen> sensorMap = new LinkedHashMap<>();
|
||||
private ShellyDeviceProfile profile;
|
||||
private ShellyHttpApi api;
|
||||
private ShellyApiInterface api;
|
||||
|
||||
public ShellyCoapHandler(ShellyBaseHandler thingHandler, ShellyCoapServer coapServer) {
|
||||
public ShellyCoapHandler(ShellyThingInterface thingHandler, ShellyCoapServer coapServer) {
|
||||
this.thingHandler = thingHandler;
|
||||
this.thingName = thingHandler.thingName;
|
||||
this.thingName = thingHandler.getThingName();
|
||||
this.profile = thingHandler.getProfile();
|
||||
this.api = thingHandler.getApi();
|
||||
this.coapServer = coapServer;
|
||||
@ -506,15 +506,11 @@ public class ShellyCoapHandler implements ShellyCoapListener {
|
||||
String meter = CHANNEL_GROUP_METER + i;
|
||||
double current = thingHandler.getChannelDouble(meter, CHANNEL_METER_CURRENTWATTS);
|
||||
double total = thingHandler.getChannelDouble(meter, CHANNEL_METER_TOTALKWH);
|
||||
logger.debug("{}: {}#{}={}, total={}", thingName, meter, CHANNEL_METER_CURRENTWATTS, current,
|
||||
totalCurrent);
|
||||
totalCurrent += current >= 0 ? current : 0;
|
||||
totalKWH += total >= 0 ? total : 0;
|
||||
updateMeter |= current >= 0 | total >= 0;
|
||||
i++;
|
||||
}
|
||||
logger.debug("{}: totalCurrent={}, totalKWH={}, update={}", thingName, totalCurrent, totalKWH,
|
||||
updateMeter);
|
||||
if (updateMeter) {
|
||||
thingHandler.updateChannel(CHANNEL_GROUP_METER, CHANNEL_METER_CURRENTWATTS,
|
||||
toQuantityType(totalCurrent, DIGITS_WATT, Units.WATT));
|
||||
@ -525,10 +521,7 @@ public class ShellyCoapHandler implements ShellyCoapListener {
|
||||
// Old firmware release are lacking various status values, which are not updated using CoIoT.
|
||||
// In this case we keep a refresh so it gets polled using REST. Beginning with Firmware 1.6 most
|
||||
// of the values are available
|
||||
if ((!thingHandler.autoCoIoT && (thingHandler.scheduledUpdates < 1))
|
||||
|| (thingHandler.autoCoIoT && !profile.isLight && !profile.hasBattery)) {
|
||||
thingHandler.requestUpdates(1, false);
|
||||
}
|
||||
thingHandler.triggerUpdateFromCoap();
|
||||
} else {
|
||||
if (failed == sensorUpdates.size()) {
|
||||
logger.debug("{}: Device description problem detected, re-discover", thingName);
|
||||
|
@ -38,6 +38,7 @@ public class ShellyBindingConfiguration {
|
||||
public String defaultUserId = "admin"; // default for http basic user id
|
||||
public String defaultPassword = "admin"; // default for http basic auth password
|
||||
public String localIP = ""; // default:use OH network config
|
||||
public int httpPort = -1;
|
||||
public boolean autoCoIoT = true;
|
||||
|
||||
public void updateFromProperties(Map<String, Object> properties) {
|
||||
|
@ -41,4 +41,5 @@ public class ShellyThingConfiguration {
|
||||
|
||||
public String localIp = ""; // local ip addresses used to create callback url
|
||||
public String localPort = "8080";
|
||||
public String serviceName = "";
|
||||
}
|
||||
|
@ -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.util.ShellyUtils.*;
|
||||
import static org.openhab.binding.shelly.internal.util.ShellyUtils.substringBeforeLast;
|
||||
import static org.openhab.core.thing.Thing.PROPERTY_MODEL_ID;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -100,7 +100,7 @@ public class ShellyDiscoveryParticipant implements MDNSDiscoveryParticipant {
|
||||
@Nullable
|
||||
@Override
|
||||
public DiscoveryResult createResult(final ServiceInfo service) {
|
||||
String name = service.getName().toLowerCase(); // Duao: Name starts with" Shelly" rather than "shelly"
|
||||
String name = service.getName().toLowerCase(); // Shelly Duo: Name starts with" Shelly" rather than "shelly"
|
||||
if (!name.startsWith("shelly")) {
|
||||
return null;
|
||||
}
|
||||
@ -111,7 +111,7 @@ public class ShellyDiscoveryParticipant implements MDNSDiscoveryParticipant {
|
||||
String model = "unknown";
|
||||
String deviceName = "";
|
||||
ThingUID thingUID = null;
|
||||
ShellyDeviceProfile profile = null;
|
||||
ShellyDeviceProfile profile;
|
||||
Map<String, Object> properties = new TreeMap<>();
|
||||
|
||||
name = service.getName().toLowerCase();
|
||||
@ -144,8 +144,8 @@ public class ShellyDiscoveryParticipant implements MDNSDiscoveryParticipant {
|
||||
|
||||
profile = api.getDeviceProfile(thingType);
|
||||
logger.debug("{}: Shelly settings : {}", name, profile.settingsJson);
|
||||
deviceName = getString(profile.settings.name);
|
||||
model = getString(profile.settings.device.type);
|
||||
deviceName = profile.name;
|
||||
model = profile.deviceType;
|
||||
mode = profile.mode;
|
||||
|
||||
properties = ShellyBaseHandler.fillDeviceProperties(profile);
|
||||
@ -174,6 +174,7 @@ public class ShellyDiscoveryParticipant implements MDNSDiscoveryParticipant {
|
||||
addProperty(properties, PROPERTY_SERVICE_NAME, name);
|
||||
addProperty(properties, PROPERTY_DEV_NAME, deviceName);
|
||||
addProperty(properties, PROPERTY_DEV_TYPE, thingType);
|
||||
addProperty(properties, PROPERTY_DEV_GEN, "1");
|
||||
addProperty(properties, PROPERTY_DEV_MODE, mode);
|
||||
|
||||
logger.debug("{}: Adding Shelly {}, UID={}", name, deviceName, thingUID.getAsString());
|
||||
|
@ -84,6 +84,7 @@ public class ShellyThingCreator {
|
||||
THING_TYPE_MAPPING.put(THING_TYPE_SHELLYBUTTON1_STR, THING_TYPE_SHELLYBUTTON1_STR);
|
||||
THING_TYPE_MAPPING.put(THING_TYPE_SHELLYBUTTON2_STR, THING_TYPE_SHELLYBUTTON2_STR);
|
||||
THING_TYPE_MAPPING.put(THING_TYPE_SHELLYUNI_STR, THING_TYPE_SHELLYUNI_STR);
|
||||
THING_TYPE_MAPPING.put(THING_TYPE_SHELLYMOTION2_STR, THING_TYPE_SHELLYMOTION_STR);
|
||||
|
||||
THING_TYPE_MAPPING.put(THING_TYPE_SHELLYPROTECTED_STR, THING_TYPE_SHELLYPROTECTED_STR);
|
||||
}
|
||||
@ -144,11 +145,19 @@ public class ShellyThingCreator {
|
||||
|
||||
// Check general mapping
|
||||
if (!deviceType.isEmpty()) {
|
||||
String res = THING_TYPE_MAPPING.get(deviceType);
|
||||
String res = THING_TYPE_MAPPING.get(deviceType); // by device type
|
||||
if (res != null) {
|
||||
return res;
|
||||
}
|
||||
|
||||
String dt = mode.equals(SHELLY_MODE_RELAY) || mode.equals(SHELLY_MODE_ROLLER) ? deviceType + "-" + mode
|
||||
: deviceType;
|
||||
res = THING_TYPE_MAPPING.get(dt); // <DT>-relay / <DT>-roller
|
||||
if (res != null) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
String res = THING_TYPE_MAPPING.get(type);
|
||||
if (res != null) {
|
||||
return res;
|
||||
|
@ -30,6 +30,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyApiException;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyApiInterface;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellyInputState;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellyOtaCheckResult;
|
||||
@ -74,14 +75,15 @@ import org.slf4j.LoggerFactory;
|
||||
* @author Markus Michels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceListener, ShellyManagerInterface {
|
||||
public class ShellyBaseHandler extends BaseThingHandler
|
||||
implements ShellyDeviceListener, ShellyManagerInterface, ShellyThingInterface {
|
||||
protected final Logger logger = LoggerFactory.getLogger(ShellyBaseHandler.class);
|
||||
protected final ShellyChannelDefinitions channelDefinitions;
|
||||
|
||||
public String thingName = "";
|
||||
public String thingType = "";
|
||||
|
||||
protected final ShellyHttpApi api;
|
||||
protected final ShellyApiInterface api;
|
||||
protected ShellyBindingConfiguration bindingConfig;
|
||||
protected ShellyThingConfiguration config = new ShellyThingConfiguration();
|
||||
protected ShellyDeviceProfile profile = new ShellyDeviceProfile(); // init empty profile to avoid NPE
|
||||
@ -126,10 +128,12 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
int httpPort, final HttpClient httpClient) {
|
||||
super(thing);
|
||||
|
||||
this.thingName = getString(thing.getLabel());
|
||||
this.messages = translationProvider;
|
||||
this.cache = new ShellyChannelCache(this);
|
||||
this.channelDefinitions = new ShellyChannelDefinitions(messages);
|
||||
this.bindingConfig = bindingConfig;
|
||||
this.config = getConfigAs(ShellyThingConfiguration.class);
|
||||
|
||||
this.localIP = localIP;
|
||||
this.localPort = String.valueOf(httpPort);
|
||||
@ -138,6 +142,16 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
coap = new ShellyCoapHandler(this, coapServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkRepresentation(String key) {
|
||||
return key.equalsIgnoreCase(getUID()) || key.equalsIgnoreCase(config.deviceIp)
|
||||
|| key.equalsIgnoreCase(config.serviceName) || key.equalsIgnoreCase(thing.getUID().getAsString());
|
||||
}
|
||||
|
||||
public String getUID() {
|
||||
return getThing().getUID().getAsString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule asynchronous Thing initialization, register thing to event dispatcher
|
||||
*/
|
||||
@ -177,6 +191,11 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
}, 2, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShellyThingConfiguration getThingConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* This routine is called every time the Thing configuration has been changed
|
||||
*/
|
||||
@ -222,11 +241,14 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
}
|
||||
|
||||
// Initialize API access, exceptions will be catched by initialize()
|
||||
ShellySettingsDevice devInfo = api.getDevInfo();
|
||||
if (devInfo.auth && config.userId.isEmpty()) {
|
||||
ShellySettingsDevice devInfo = api.getDeviceInfo();
|
||||
if (getBool(devInfo.auth) && config.userId.isEmpty()) {
|
||||
setThingOffline(ThingStatusDetail.CONFIGURATION_ERROR, "offline.conf-error-no-credentials");
|
||||
return false;
|
||||
}
|
||||
if (config.serviceName.isEmpty()) {
|
||||
config.serviceName = getString(profile.hostname).toLowerCase();
|
||||
}
|
||||
|
||||
ShellyDeviceProfile tmpPrf = api.getDeviceProfile(thingType);
|
||||
if (this.getThing().getThingTypeUID().equals(THING_TYPE_SHELLYPROTECTED)) {
|
||||
@ -244,24 +266,12 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
tmpPrf.coiotEndpoint = devInfo.coiot;
|
||||
}
|
||||
tmpPrf.auth = devInfo.auth; // missing in /settings
|
||||
|
||||
logger.debug("{}: Initializing device {}, type {}, Hardware: Rev: {}, batch {}; Firmware: {} / {}", thingName,
|
||||
tmpPrf.hostname, tmpPrf.deviceType, tmpPrf.hwRev, tmpPrf.hwBatchId, tmpPrf.fwVersion, tmpPrf.fwDate);
|
||||
logger.debug("{}: Shelly settings info for {}: {}", thingName, tmpPrf.hostname, tmpPrf.settingsJson);
|
||||
logger.debug("{}: Device "
|
||||
+ "hasRelays:{} (numRelays={}),isRoller:{} (numRoller={}),isDimmer:{},numMeter={},isEMeter:{})"
|
||||
+ ",isSensor:{},isDS:{},hasBattery:{}{},isSense:{},isMotion:{},isLight:{},isBulb:{},isDuo:{},isRGBW2:{},inColor:{}"
|
||||
+ ",alwaysOn:{}, ,updatePeriod:{}sec", thingName, tmpPrf.hasRelays, tmpPrf.numRelays, tmpPrf.isRoller,
|
||||
tmpPrf.numRollers, tmpPrf.isDimmer, tmpPrf.numMeters, tmpPrf.isEMeter, tmpPrf.isSensor, tmpPrf.isDW,
|
||||
tmpPrf.hasBattery, tmpPrf.hasBattery ? " (low battery threshold=" + config.lowBattery + "%)" : "",
|
||||
tmpPrf.isSense, tmpPrf.isMotion, tmpPrf.isLight, profile.isBulb, tmpPrf.isDuo, tmpPrf.isRGBW2,
|
||||
tmpPrf.inColor, tmpPrf.alwaysOn, tmpPrf.updatePeriod);
|
||||
|
||||
// update thing properties
|
||||
tmpPrf.status = api.getStatus();
|
||||
tmpPrf.updateFromStatus(tmpPrf.status);
|
||||
updateProperties(tmpPrf, tmpPrf.status);
|
||||
|
||||
showThingConfig(tmpPrf);
|
||||
checkVersion(tmpPrf, tmpPrf.status);
|
||||
|
||||
if (config.eventsCoIoT && (tmpPrf.settings.coiot != null) && (tmpPrf.settings.coiot.enabled != null)) {
|
||||
String devpeer = getString(tmpPrf.settings.coiot.peer);
|
||||
String ourpeer = config.localIp + ":" + ShellyCoapJSonDTO.COIOT_PORT;
|
||||
@ -298,11 +308,28 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
|
||||
logger.debug("{}: Thing successfully initialized.", thingName);
|
||||
profile = tmpPrf;
|
||||
setThingOnline(); // if API call was successful the thing must be online
|
||||
|
||||
updateProperties(tmpPrf, tmpPrf.status);
|
||||
setThingOnline(); // if API call was successful the thing must be online
|
||||
return true; // success
|
||||
}
|
||||
|
||||
private void showThingConfig(ShellyDeviceProfile profile) {
|
||||
logger.debug("{}: Initializing device {}, type {}, Hardware: Rev: {}, batch {}; Firmware: {} / {}", thingName,
|
||||
profile.hostname, profile.deviceType, profile.hwRev, profile.hwBatchId, profile.fwVersion,
|
||||
profile.fwDate);
|
||||
logger.debug("{}: Shelly settings info for {}: {}", thingName, profile.hostname, profile.settingsJson);
|
||||
logger.debug("{}: Device "
|
||||
+ "hasRelays:{} (numRelays={}),isRoller:{} (numRoller={}),isDimmer:{},numMeter={},isEMeter:{})"
|
||||
+ ",isSensor:{},isDS:{},hasBattery:{}{},isSense:{},isMotion:{},isLight:{},isBulb:{},isDuo:{},isRGBW2:{},inColor:{}"
|
||||
+ ",alwaysOn:{}, updatePeriod:{}sec", thingName, profile.hasRelays, profile.numRelays, profile.isRoller,
|
||||
profile.numRollers, profile.isDimmer, profile.numMeters, profile.isEMeter, profile.isSensor,
|
||||
profile.isDW, profile.hasBattery,
|
||||
profile.hasBattery ? " (low battery threshold=" + config.lowBattery + "%)" : "", profile.isSense,
|
||||
profile.isMotion, profile.isLight, profile.isBulb, profile.isDuo, profile.isRGBW2, profile.inColor,
|
||||
profile.alwaysOn, profile.updatePeriod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Channel Commands
|
||||
*/
|
||||
@ -356,7 +383,7 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
logger.warn("{}: Invalid profile Id {} requested", thingName, profile);
|
||||
break;
|
||||
}
|
||||
api.setProfile(0, profile);
|
||||
api.setValveProfile(0, profile);
|
||||
break;
|
||||
case CHANNEL_CONTROL_MODE:
|
||||
logger.debug("{}: Set mode to {}", thingName, command);
|
||||
@ -364,7 +391,7 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
break;
|
||||
case CHANNEL_CONTROL_SETTEMP:
|
||||
logger.debug("{}: Set temperature to {}", thingName, command);
|
||||
api.setTemperature(0, (int) getNumber(command));
|
||||
api.setValveTemperature(0, (int) getNumber(command));
|
||||
break;
|
||||
case CHANNEL_CONTROL_POSITION:
|
||||
logger.debug("{}: Set position to {}", thingName, command);
|
||||
@ -372,11 +399,11 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
break;
|
||||
case CHANNEL_CONTROL_BCONTROL:
|
||||
logger.debug("{}: Set boost mode to {}", thingName, command);
|
||||
api.startBoost(0, command == OnOffType.ON ? -1 : 0);
|
||||
api.startValveBoost(0, command == OnOffType.ON ? -1 : 0);
|
||||
break;
|
||||
case CHANNEL_CONTROL_BTIMER:
|
||||
logger.debug("{}: Set boost timer to {}", thingName, command);
|
||||
api.setBoostTime(0, (int) getNumber(command));
|
||||
api.setValveBoostTime(0, (int) getNumber(command));
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -386,7 +413,7 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
|
||||
restartWatchdog();
|
||||
if (update && !autoCoIoT && !isUpdateScheduled()) {
|
||||
logger.debug("{}: Command process, request status update", thingName);
|
||||
logger.debug("{}: Command processed, request status update", thingName);
|
||||
requestUpdates(1, false);
|
||||
}
|
||||
} catch (ShellyApiException e) {
|
||||
@ -467,9 +494,6 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
|
||||
// All channels must be created after the first cycle
|
||||
channelsCreated = true;
|
||||
|
||||
// Restart watchdog when status update was successful (no exception)
|
||||
restartWatchdog();
|
||||
}
|
||||
} catch (ShellyApiException e) {
|
||||
// http call failed: go offline except for battery devices, which might be in
|
||||
@ -526,6 +550,10 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
|
||||
@Override
|
||||
public void setThingOnline() {
|
||||
if (stopping) {
|
||||
logger.debug("{}: Thing should go ONLINE, but handler is shutting down, ignore!", thingName);
|
||||
return;
|
||||
}
|
||||
if (!isThingOnline()) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
|
||||
@ -538,14 +566,22 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
|
||||
@Override
|
||||
public void setThingOffline(ThingStatusDetail detail, String messageKey) {
|
||||
String message = messages.get(messageKey);
|
||||
if (stopping) {
|
||||
logger.debug("{}: Thing should go OFFLINE with status {}, but handler is shutting down -> ignore",
|
||||
thingName, message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isThingOffline()) {
|
||||
updateStatus(ThingStatus.OFFLINE, detail, messages.get(messageKey));
|
||||
updateStatus(ThingStatus.OFFLINE, detail, message);
|
||||
watchdog = 0;
|
||||
channelsCreated = false; // check for new channels after devices gets re-initialized (e.g. new
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void restartWatchdog() {
|
||||
@Override
|
||||
public void restartWatchdog() {
|
||||
watchdog = now();
|
||||
updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_HEARTBEAT, getTimestamp());
|
||||
logger.trace("{}: Watchdog restarted (expires in {} sec)", thingName, profile.updatePeriod);
|
||||
@ -564,13 +600,20 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
return watchdog > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reinitializeThing() {
|
||||
logger.debug("{}: Re-Initialize Thing", thingName);
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
if (stopping) {
|
||||
logger.debug("{}: Handler is shutting down, ignore", thingName);
|
||||
return;
|
||||
}
|
||||
updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.CONFIGURATION_PENDING,
|
||||
messages.get("offline.status-error-restarted"));
|
||||
requestUpdates(0, true);
|
||||
}
|
||||
|
||||
private void fillDeviceStatus(ShellySettingsStatus status, boolean updated) {
|
||||
@Override
|
||||
public void fillDeviceStatus(ShellySettingsStatus status, boolean updated) {
|
||||
String alarm = "";
|
||||
|
||||
// Update uptime and WiFi, internal temp
|
||||
@ -586,9 +629,7 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
// Check various device indicators like overheating
|
||||
if (checkRestarted(status)) {
|
||||
// Force re-initialization on next status update
|
||||
if (profile.alwaysOn) {
|
||||
reinitializeThing();
|
||||
}
|
||||
reinitializeThing();
|
||||
} else if (getBool(status.overtemperature)) {
|
||||
alarm = ALARM_TYPE_OVERTEMP;
|
||||
} else if (getBool(status.overload)) {
|
||||
@ -600,12 +641,13 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
if (internalTemp != UnDefType.NULL) {
|
||||
int temp = ((Number) internalTemp).intValue();
|
||||
if (temp > stats.maxInternalTemp) {
|
||||
logger.debug("{}: Max Internal Temp for device changed to {}", thingName, temp);
|
||||
stats.maxInternalTemp = temp;
|
||||
}
|
||||
}
|
||||
|
||||
stats.lastUptime = getLong(status.uptime);
|
||||
if (status.uptime != null) {
|
||||
stats.lastUptime = getLong(status.uptime);
|
||||
}
|
||||
stats.coiotMessages = coap.getMessageCount();
|
||||
stats.coiotErrors = coap.getErrorCount();
|
||||
|
||||
@ -622,8 +664,9 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
|
||||
private boolean checkRestarted(ShellySettingsStatus status) {
|
||||
if (profile.isInitialized() && profile.alwaysOn /* exclude battery powered devices */
|
||||
&& (status.uptime < stats.lastUptime || !profile.status.update.oldVersion.isEmpty()
|
||||
&& !status.update.oldVersion.equals(profile.status.update.oldVersion))) {
|
||||
&& (status.uptime != null && status.uptime < stats.lastUptime
|
||||
|| !profile.status.update.oldVersion.isEmpty()
|
||||
&& !status.update.oldVersion.equals(profile.status.update.oldVersion))) {
|
||||
updateProperties(profile, status);
|
||||
return true;
|
||||
}
|
||||
@ -635,6 +678,7 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
*
|
||||
* @param alarm Alarm Message
|
||||
*/
|
||||
@Override
|
||||
public void postEvent(String event, boolean force) {
|
||||
String channelId = mkChannelId(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_ALARM);
|
||||
State value = cache.getValue(channelId);
|
||||
@ -643,20 +687,21 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
if (force || !lastAlarm.equals(event)
|
||||
|| (lastAlarm.equals(event) && now() > stats.lastAlarmTs + HEALTH_CHECK_INTERVAL_SEC)) {
|
||||
switch (event) {
|
||||
case "":
|
||||
case "0": // DW2 1.8
|
||||
case SHELLY_WAKEUPT_SENSOR:
|
||||
case SHELLY_WAKEUPT_PERIODIC:
|
||||
case SHELLY_WAKEUPT_BUTTON:
|
||||
case SHELLY_WAKEUPT_POWERON:
|
||||
case SHELLY_WAKEUPT_EXT_POWER:
|
||||
case SHELLY_WAKEUPT_UNKNOWN:
|
||||
logger.debug("{}: {}", thingName, messages.get("event.filtered", event));
|
||||
case "":
|
||||
case ALARM_TYPE_NONE:
|
||||
break;
|
||||
default:
|
||||
logger.debug("{}: {}", thingName, messages.get("event.triggered", event));
|
||||
triggerChannel(channelId, event);
|
||||
cache.updateChannel(channelId, getStringType(event));
|
||||
cache.updateChannel(channelId, getStringType(event.toUpperCase()));
|
||||
stats.lastAlarm = event;
|
||||
stats.lastAlarmTs = now();
|
||||
stats.alarms++;
|
||||
@ -808,7 +853,7 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
|
||||
config = getConfigAs(ShellyThingConfiguration.class);
|
||||
if (config.deviceIp.isEmpty()) {
|
||||
logger.warn("{}: IP address for the device must not be empty", thingName); // may not set in .things file
|
||||
logger.debug("{}: IP address for the device must not be empty", thingName); // may not set in .things file
|
||||
return;
|
||||
}
|
||||
try {
|
||||
@ -822,6 +867,7 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
logger.debug("{}: Unable to resolve hostname {}", thingName, config.deviceIp);
|
||||
}
|
||||
|
||||
config.serviceName = getString(properties.get(PROPERTY_SERVICE_NAME));
|
||||
config.localIp = localIP;
|
||||
config.localPort = localPort;
|
||||
if (config.userId.isEmpty() && !bindingConfig.defaultUserId.isEmpty()) {
|
||||
@ -866,7 +912,7 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
if (bindingConfig.autoCoIoT && ((version.compare(prf.fwVersion, SHELLY_API_MIN_FWCOIOT)) >= 0)
|
||||
|| (prf.fwVersion.equalsIgnoreCase("production_test"))) {
|
||||
if (!config.eventsCoIoT) {
|
||||
logger.debug("{}: {}", thingName, messages.get("versioncheck.autocoiot"));
|
||||
logger.info("{}: {}", thingName, messages.get("versioncheck.autocoiot"));
|
||||
}
|
||||
autoCoIoT = true;
|
||||
}
|
||||
@ -887,10 +933,9 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
* @param response exception details including the http respone
|
||||
* @return true if the authorization failed
|
||||
*/
|
||||
private boolean isAuthorizationFailed(ShellyApiResult result) {
|
||||
protected boolean isAuthorizationFailed(ShellyApiResult result) {
|
||||
if (result.isHttpAccessUnauthorized()) {
|
||||
// If the device is password protected the API doesn't provide settings to the device settings
|
||||
logger.warn("{}: {}", thingName, messages.get("init.protected"));
|
||||
setThingOffline(ThingStatusDetail.CONFIGURATION_ERROR, "offline.conf-error-access-denied");
|
||||
return true;
|
||||
}
|
||||
@ -972,6 +1017,7 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
* @param status Shelly device status
|
||||
* @return true: one or more inputs were updated
|
||||
*/
|
||||
@Override
|
||||
public boolean updateInputs(ShellySettingsStatus status) {
|
||||
boolean updated = false;
|
||||
|
||||
@ -1004,6 +1050,7 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
return updated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateWakeupReason(@Nullable List<Object> valueArray) {
|
||||
boolean changed = false;
|
||||
if (valueArray != null && !valueArray.isEmpty()) {
|
||||
@ -1019,6 +1066,7 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void triggerButton(String group, int idx, String value) {
|
||||
String trigger = mapButtonEvent(value);
|
||||
if (trigger.isEmpty()) {
|
||||
@ -1036,6 +1084,7 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishState(String channelId, State value) {
|
||||
String id = channelId.contains("$") ? substringBefore(channelId, "$") : channelId;
|
||||
if (!stopping && isLinked(id)) {
|
||||
@ -1044,10 +1093,12 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateChannel(String group, String channel, State value) {
|
||||
return updateChannel(mkChannelId(group, channel), value, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateChannel(String channelId, State value, boolean force) {
|
||||
return !stopping && cache.updateChannel(channelId, value, force);
|
||||
}
|
||||
@ -1057,6 +1108,7 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
return cache.getValue(group, channel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getChannelDouble(String group, String channel) {
|
||||
State value = getChannelValue(group, channel);
|
||||
if (value != UnDefType.NULL) {
|
||||
@ -1075,7 +1127,8 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
*
|
||||
* @param thingHandler
|
||||
*/
|
||||
protected void updateChannelDefinitions(Map<String, Channel> dynChannels) {
|
||||
@Override
|
||||
public void updateChannelDefinitions(Map<String, Channel> dynChannels) {
|
||||
if (channelsCreated) {
|
||||
return; // already done
|
||||
}
|
||||
@ -1106,6 +1159,7 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areChannelsCreated() {
|
||||
return channelsCreated;
|
||||
}
|
||||
@ -1119,13 +1173,9 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
protected void updateProperties(ShellyDeviceProfile profile, ShellySettingsStatus status) {
|
||||
logger.debug("{}: Update properties", thingName);
|
||||
Map<String, Object> properties = fillDeviceProperties(profile);
|
||||
String serviceName = getString(getThing().getProperties().get(PROPERTY_SERVICE_NAME));
|
||||
String hostname = getString(profile.settings.device.hostname).toLowerCase();
|
||||
if (serviceName.isEmpty()) {
|
||||
properties.put(PROPERTY_SERVICE_NAME, hostname);
|
||||
logger.trace("{}: Updated serrviceName to {}", thingName, hostname);
|
||||
}
|
||||
String deviceName = getString(profile.settings.name);
|
||||
properties.put(PROPERTY_SERVICE_NAME, config.serviceName);
|
||||
properties.put(PROPERTY_DEV_GEN, "1");
|
||||
if (!deviceName.isEmpty()) {
|
||||
properties.put(PROPERTY_DEV_NAME, deviceName);
|
||||
}
|
||||
@ -1155,6 +1205,7 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
* @param key Name of the property
|
||||
* @param value Value of the property
|
||||
*/
|
||||
@Override
|
||||
public void updateProperties(String key, String value) {
|
||||
Map<String, String> thingProperties = editProperties();
|
||||
if (thingProperties.containsKey(key)) {
|
||||
@ -1184,6 +1235,7 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
* @param key property name
|
||||
* @return property value or "" if property is not set
|
||||
*/
|
||||
@Override
|
||||
public String getProperty(String key) {
|
||||
Map<String, String> thingProperties = getThing().getProperties();
|
||||
return getString(thingProperties.get(key));
|
||||
@ -1230,7 +1282,7 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
if (refreshSettings) {
|
||||
profile = api.getDeviceProfile(thingType);
|
||||
if (!isThingOnline()) {
|
||||
logger.debug("{}:Device profile re-initialized (thingType={})", thingName, thingType);
|
||||
logger.debug("{}: Device profile re-initialized (thingType={})", thingName, thingType);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
@ -1244,14 +1296,11 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
return profile;
|
||||
}
|
||||
|
||||
protected ShellyHttpApi getShellyApi() {
|
||||
return api;
|
||||
}
|
||||
|
||||
protected ShellyDeviceProfile getDeviceProfile() {
|
||||
return profile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void triggerChannel(String group, String channel, String payload) {
|
||||
String triggerCh = mkChannelId(group, channel);
|
||||
logger.debug("{}: Send event {} to channel {}", thingName, triggerCh, payload);
|
||||
@ -1324,7 +1373,7 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShellyHttpApi getApi() {
|
||||
public ShellyApiInterface getApi() {
|
||||
return api;
|
||||
}
|
||||
|
||||
@ -1332,6 +1381,11 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
return stats.asProperties();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getScheduledUpdates() {
|
||||
return scheduledUpdates;
|
||||
}
|
||||
|
||||
public String checkForUpdate() {
|
||||
try {
|
||||
ShellyOtaCheckResult result = api.checkForUpdate();
|
||||
@ -1340,4 +1394,11 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void triggerUpdateFromCoap() {
|
||||
if ((!autoCoIoT && (getScheduledUpdates() < 1)) || (autoCoIoT && !profile.isLight && !profile.hasBattery)) {
|
||||
requestUpdates(1, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,29 +49,35 @@ public class ShellyComponents {
|
||||
* @param th Thing Handler instance
|
||||
* @param profile ShellyDeviceProfile
|
||||
*/
|
||||
public static boolean updateDeviceStatus(ShellyBaseHandler thingHandler, ShellySettingsStatus status) {
|
||||
public static boolean updateDeviceStatus(ShellyThingInterface thingHandler, ShellySettingsStatus status) {
|
||||
ShellyDeviceProfile profile = thingHandler.getProfile();
|
||||
|
||||
if (!thingHandler.areChannelsCreated()) {
|
||||
thingHandler.updateChannelDefinitions(ShellyChannelDefinitions.createDeviceChannels(thingHandler.getThing(),
|
||||
thingHandler.getProfile(), status));
|
||||
}
|
||||
|
||||
if (getLong(status.uptime) > 10) {
|
||||
thingHandler.updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_UPTIME,
|
||||
toQuantityType((double) getLong(status.uptime), DIGITS_NONE, Units.SECOND));
|
||||
}
|
||||
|
||||
Integer rssi = getInteger(status.wifiSta.rssi);
|
||||
thingHandler.updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_UPTIME,
|
||||
toQuantityType((double) getLong(status.uptime), DIGITS_NONE, Units.SECOND));
|
||||
thingHandler.updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_RSSI, mapSignalStrength(rssi));
|
||||
if ((status.tmp != null) && !thingHandler.getProfile().isSensor) {
|
||||
thingHandler.updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_ITEMP,
|
||||
toQuantityType(getDouble(status.tmp.tC), DIGITS_NONE, SIUnits.CELSIUS));
|
||||
} else if (status.temperature != null) {
|
||||
thingHandler.updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_ITEMP,
|
||||
toQuantityType(getDouble(status.temperature), DIGITS_NONE, SIUnits.CELSIUS));
|
||||
if (getDouble(status.temperature) != SHELLY_API_INVTEMP) {
|
||||
if (status.tmp != null && !thingHandler.getProfile().isSensor) {
|
||||
thingHandler.updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_ITEMP,
|
||||
toQuantityType(getDouble(status.tmp.tC), DIGITS_NONE, SIUnits.CELSIUS));
|
||||
} else if (status.temperature != null) {
|
||||
thingHandler.updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_ITEMP,
|
||||
toQuantityType(getDouble(status.temperature), DIGITS_NONE, SIUnits.CELSIUS));
|
||||
}
|
||||
}
|
||||
thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_SLEEPTIME,
|
||||
toQuantityType(getInteger(status.sleepTime), Units.SECOND));
|
||||
|
||||
thingHandler.updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_UPDATE, getOnOff(status.hasUpdate));
|
||||
|
||||
ShellyDeviceProfile profile = thingHandler.getProfile();
|
||||
if (profile.settings.calibrated != null) {
|
||||
thingHandler.updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_CALIBRATED,
|
||||
getOnOff(profile.settings.calibrated));
|
||||
@ -87,7 +93,7 @@ public class ShellyComponents {
|
||||
* @param profile ShellyDeviceProfile
|
||||
* @param status Last ShellySettingsStatus
|
||||
*/
|
||||
public static boolean updateMeters(ShellyBaseHandler thingHandler, ShellySettingsStatus status) {
|
||||
public static boolean updateMeters(ShellyThingInterface thingHandler, ShellySettingsStatus status) {
|
||||
ShellyDeviceProfile profile = thingHandler.getProfile();
|
||||
|
||||
double accumulatedWatts = 0.0;
|
||||
@ -99,25 +105,15 @@ public class ShellyComponents {
|
||||
// We need to differ
|
||||
// Roler+RGBW2 have multiple meters -> aggregate consumption to the functional device
|
||||
// Meter and EMeter have a different set of channels
|
||||
if ((profile.numMeters > 0) && ((status.meters != null) || (status.emeters != null))) {
|
||||
if (status.meters != null || status.emeters != null) {
|
||||
if (!profile.isRoller && !profile.isRGBW2) {
|
||||
thingHandler.logger.trace("{}: Updating {} {}meter(s)", thingHandler.thingName, profile.numMeters,
|
||||
!profile.isEMeter ? "standard " : "e-");
|
||||
|
||||
// In Relay mode we map eacher meter to the matching channel group
|
||||
int m = 0;
|
||||
if (!profile.isEMeter) {
|
||||
for (ShellySettingsMeter meter : status.meters) {
|
||||
Integer meterIndex = m + 1;
|
||||
if (getBool(meter.isValid) || profile.isLight) { // RGBW2-white doesn't report valid flag
|
||||
// correctly in white mode
|
||||
String groupName = "";
|
||||
if (profile.numMeters > 1) {
|
||||
groupName = CHANNEL_GROUP_METER + meterIndex.toString();
|
||||
} else {
|
||||
groupName = CHANNEL_GROUP_METER;
|
||||
}
|
||||
|
||||
String groupName = profile.getMeterGroup(m);
|
||||
if (!thingHandler.areChannelsCreated()) {
|
||||
// skip for Shelly Bulb: JSON has a meter, but values don't get updated
|
||||
if (!profile.isBulb) {
|
||||
@ -141,17 +137,17 @@ public class ShellyComponents {
|
||||
updated |= thingHandler.updateChannel(groupName, CHANNEL_METER_LASTMIN1,
|
||||
toQuantityType(getDouble(meter.counters[0]), DIGITS_WATT, Units.WATT));
|
||||
}
|
||||
thingHandler.updateChannel(groupName, CHANNEL_LAST_UPDATE,
|
||||
getTimestamp(getString(profile.settings.timezone), getLong(meter.timestamp)));
|
||||
if (meter.timestamp != null) {
|
||||
thingHandler.updateChannel(groupName, CHANNEL_LAST_UPDATE,
|
||||
getTimestamp(getString(profile.settings.timezone), meter.timestamp));
|
||||
}
|
||||
}
|
||||
m++;
|
||||
}
|
||||
} else {
|
||||
for (ShellySettingsEMeter emeter : status.emeters) {
|
||||
Integer meterIndex = m + 1;
|
||||
if (getBool(emeter.isValid)) {
|
||||
String groupName = profile.numMeters > 1 ? CHANNEL_GROUP_METER + meterIndex.toString()
|
||||
: CHANNEL_GROUP_METER;
|
||||
String groupName = profile.getMeterGroup(m);
|
||||
if (!thingHandler.areChannelsCreated()) {
|
||||
thingHandler.updateChannelDefinitions(ShellyChannelDefinitions
|
||||
.createEMeterChannels(thingHandler.getThing(), emeter, groupName));
|
||||
@ -185,14 +181,23 @@ public class ShellyComponents {
|
||||
}
|
||||
} else {
|
||||
// In Roller Mode we accumulate all meters to a single set of meters
|
||||
thingHandler.logger.trace("{}: Updating Meter (accumulated)", thingHandler.thingName);
|
||||
double currentWatts = 0.0;
|
||||
double totalWatts = 0.0;
|
||||
double lastMin1 = 0.0;
|
||||
long timestamp = 0l;
|
||||
String groupName = CHANNEL_GROUP_METER;
|
||||
|
||||
if (!thingHandler.areChannelsCreated()) {
|
||||
ShellySettingsMeter m = status.meters.get(0);
|
||||
if (getBool(m.isValid)) {
|
||||
// Create channels for 1 Meter
|
||||
thingHandler.updateChannelDefinitions(
|
||||
ShellyChannelDefinitions.createMeterChannels(thingHandler.getThing(), m, groupName));
|
||||
}
|
||||
}
|
||||
|
||||
for (ShellySettingsMeter meter : status.meters) {
|
||||
if (meter.isValid) {
|
||||
if (getBool(meter.isValid)) {
|
||||
currentWatts += getDouble(meter.power);
|
||||
totalWatts += getDouble(meter.total);
|
||||
if (meter.counters != null) {
|
||||
@ -203,11 +208,6 @@ public class ShellyComponents {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Create channels for 1 Meter
|
||||
if (!thingHandler.areChannelsCreated()) {
|
||||
thingHandler.updateChannelDefinitions(ShellyChannelDefinitions
|
||||
.createMeterChannels(thingHandler.getThing(), status.meters.get(0), groupName));
|
||||
}
|
||||
|
||||
updated |= thingHandler.updateChannel(groupName, CHANNEL_METER_LASTMIN1,
|
||||
toQuantityType(getDouble(lastMin1), DIGITS_WATT, Units.WATT));
|
||||
@ -244,7 +244,7 @@ public class ShellyComponents {
|
||||
}
|
||||
|
||||
// EM: compute from provided values
|
||||
if (Math.abs(emeter.power) + Math.abs(emeter.reactive) > 1.5) {
|
||||
if (emeter.reactive != null && Math.abs(emeter.power) + Math.abs(emeter.reactive) > 1.5) {
|
||||
double pf = emeter.power / Math.sqrt(emeter.power * emeter.power + emeter.reactive * emeter.reactive);
|
||||
return pf;
|
||||
}
|
||||
@ -260,15 +260,14 @@ public class ShellyComponents {
|
||||
*
|
||||
* @throws ShellyApiException
|
||||
*/
|
||||
public static boolean updateSensors(ShellyBaseHandler thingHandler, ShellySettingsStatus status)
|
||||
public static boolean updateSensors(ShellyThingInterface thingHandler, ShellySettingsStatus status)
|
||||
throws ShellyApiException {
|
||||
ShellyDeviceProfile profile = thingHandler.getProfile();
|
||||
|
||||
boolean updated = false;
|
||||
if (profile.isSensor || profile.hasBattery) {
|
||||
ShellyStatusSensor sdata = thingHandler.api.getSensorStatus();
|
||||
ShellyStatusSensor sdata = thingHandler.getApi().getSensorStatus();
|
||||
if (!thingHandler.areChannelsCreated()) {
|
||||
thingHandler.logger.trace("{}: Create missing sensor channel(s)", thingHandler.thingName);
|
||||
thingHandler.updateChannelDefinitions(
|
||||
ShellyChannelDefinitions.createSensorChannels(thingHandler.getThing(), profile, sdata));
|
||||
}
|
||||
@ -283,13 +282,12 @@ public class ShellyComponents {
|
||||
String sensorError = sdata.sensorError;
|
||||
boolean changed = thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_ERROR,
|
||||
getStringType(sensorError));
|
||||
if (!"0".equals(sensorError) && changed) {
|
||||
if (changed && !"0".equals(sensorError)) {
|
||||
thingHandler.postEvent(getString(sdata.sensorError), true);
|
||||
updated |= changed;
|
||||
}
|
||||
updated |= changed;
|
||||
}
|
||||
if ((sdata.tmp != null) && getBool(sdata.tmp.isValid)) {
|
||||
thingHandler.logger.trace("{}: Updating temperature", thingHandler.thingName);
|
||||
Double temp = getString(sdata.tmp.units).toUpperCase().equals(SHELLY_TEMP_CELSIUS)
|
||||
? getDouble(sdata.tmp.tC)
|
||||
: getDouble(sdata.tmp.tF);
|
||||
@ -300,7 +298,7 @@ public class ShellyComponents {
|
||||
temp = convertToC(temp, getString(sdata.tmp.units));
|
||||
updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_TEMP,
|
||||
toQuantityType(temp.doubleValue(), DIGITS_TEMP, SIUnits.CELSIUS));
|
||||
} else if (status.thermostats != null && status.thermostats.size() > 0) {
|
||||
} else if (status.thermostats != null && profile.settings.thermostats != null) {
|
||||
// Shelly TRV
|
||||
ShellyThermnostat t = status.thermostats.get(0);
|
||||
ShellyThermnostat ps = profile.settings.thermostats.get(0);
|
||||
@ -313,13 +311,11 @@ public class ShellyComponents {
|
||||
updated |= thingHandler.updateChannel(CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_MODE,
|
||||
getStringType(getBool(t.targetTemp.enabled) ? SHELLY_TRV_MODE_AUTO : SHELLY_TRV_MODE_MANUAL));
|
||||
updated |= thingHandler.updateChannel(CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_PROFILE,
|
||||
getDecimal(getBool(t.schedule) ? t.profile : 0));
|
||||
getDecimal(getBool(t.schedule) ? t.profile + 1 : 0));
|
||||
updated |= thingHandler.updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_SCHEDULE,
|
||||
getOnOff(t.schedule));
|
||||
if (t.tmp != null) {
|
||||
Double temp = convertToC(t.tmp.value, getString(t.tmp.units));
|
||||
// Some devices report values = -999 or 99 during fw update
|
||||
boolean valid = temp.intValue() > -50 && temp.intValue() < 90;
|
||||
updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_TEMP,
|
||||
toQuantityType(temp.doubleValue(), DIGITS_TEMP, SIUnits.CELSIUS));
|
||||
temp = convertToC(t.targetTemp.value, getString(t.targetTemp.unit));
|
||||
@ -333,14 +329,13 @@ public class ShellyComponents {
|
||||
getDouble(t.pos) > 0 ? OpenClosedType.OPEN : OpenClosedType.CLOSED);
|
||||
}
|
||||
}
|
||||
|
||||
if (sdata.hum != null) {
|
||||
thingHandler.logger.trace("{}: Updating humidity", thingHandler.thingName);
|
||||
updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_HUM,
|
||||
toQuantityType(getDouble(sdata.hum.value), DIGITS_PERCENT, Units.PERCENT));
|
||||
}
|
||||
if ((sdata.lux != null) && getBool(sdata.lux.isValid)) {
|
||||
// “lux”:{“value”:30, “illumination”: “dark”, “is_valid”:true},
|
||||
thingHandler.logger.trace("{}: Updating lux", thingHandler.thingName);
|
||||
updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_LUX,
|
||||
toQuantityType(getDouble(sdata.lux.value), DIGITS_LUX, Units.LUX));
|
||||
if (sdata.lux.illumination != null) {
|
||||
@ -369,8 +364,8 @@ public class ShellyComponents {
|
||||
getStringType(sdata.gasSensor.sensorState));
|
||||
}
|
||||
if ((sdata.concentration != null) && sdata.concentration.isValid) {
|
||||
updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_PPM,
|
||||
getDecimal(sdata.concentration.ppm));
|
||||
updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_PPM, toQuantityType(
|
||||
getInteger(sdata.concentration.ppm).doubleValue(), DIGITS_NONE, Units.PARTS_PER_MILLION));
|
||||
}
|
||||
if ((sdata.adcs != null) && (sdata.adcs.size() > 0)) {
|
||||
ShellyADC adc = sdata.adcs.get(0);
|
||||
@ -384,18 +379,14 @@ public class ShellyComponents {
|
||||
charger ? OnOffType.ON : OnOffType.OFF);
|
||||
}
|
||||
if (sdata.bat != null) { // no update for Sense
|
||||
// Shelly HT has external_power under settings, Sense and Motion charger under status
|
||||
if (!charger || !profile.isHT) {
|
||||
updated |= thingHandler.updateChannel(CHANNEL_GROUP_BATTERY, CHANNEL_SENSOR_BAT_LEVEL,
|
||||
toQuantityType(getDouble(sdata.bat.value), 0, Units.PERCENT));
|
||||
} else {
|
||||
updated |= thingHandler.updateChannel(CHANNEL_GROUP_BATTERY, CHANNEL_SENSOR_BAT_LEVEL,
|
||||
UnDefType.UNDEF);
|
||||
}
|
||||
updated |= thingHandler.updateChannel(CHANNEL_GROUP_BATTERY, CHANNEL_SENSOR_BAT_LEVEL,
|
||||
toQuantityType(getDouble(sdata.bat.value), 0, Units.PERCENT));
|
||||
|
||||
int lowBattery = thingHandler.getThingConfig().lowBattery;
|
||||
boolean changed = thingHandler.updateChannel(CHANNEL_GROUP_BATTERY, CHANNEL_SENSOR_BAT_LOW,
|
||||
getDouble(sdata.bat.value) < thingHandler.config.lowBattery ? OnOffType.ON : OnOffType.OFF);
|
||||
!charger && getDouble(sdata.bat.value) < lowBattery ? OnOffType.ON : OnOffType.OFF);
|
||||
updated |= changed;
|
||||
if (changed && getDouble(sdata.bat.value) < thingHandler.config.lowBattery) {
|
||||
if (!charger && changed && getDouble(sdata.bat.value) < lowBattery) {
|
||||
thingHandler.postEvent(ALARM_TYPE_LOW_BATTERY, false);
|
||||
}
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ public class ShellyLightHandler extends ShellyBaseHandler {
|
||||
int value = -1;
|
||||
if (command instanceof OnOffType) { // Switch
|
||||
logger.debug("{}: Switch light {}", thingName, command);
|
||||
ShellyShortLightStatus light = api.setRelayTurn(lightId,
|
||||
ShellyShortLightStatus light = api.setLightTurn(lightId,
|
||||
command == OnOffType.ON ? SHELLY_API_ON : SHELLY_API_OFF);
|
||||
col.power = getOnOff(light.ison);
|
||||
col.setBrightness(light.brightness);
|
||||
@ -164,7 +164,7 @@ public class ShellyLightHandler extends ShellyBaseHandler {
|
||||
}
|
||||
if (value == 0) {
|
||||
logger.debug("{}: Brightness=0 -> switch light OFF", thingName);
|
||||
api.setRelayTurn(lightId, SHELLY_API_OFF);
|
||||
api.setLightTurn(lightId, SHELLY_API_OFF);
|
||||
update = false;
|
||||
} else {
|
||||
if (command instanceof IncreaseDecreaseType) {
|
||||
@ -347,12 +347,14 @@ public class ShellyLightHandler extends ShellyBaseHandler {
|
||||
ShellyColorUtils col = getCurrentColors(lightId);
|
||||
col.power = getOnOff(light.ison);
|
||||
|
||||
// Channel control/timer
|
||||
ShellySettingsRgbwLight ls = profile.settings.lights.get(lightId);
|
||||
updated |= updateChannel(controlGroup, CHANNEL_TIMER_AUTOON, getDecimal(ls.autoOn));
|
||||
updated |= updateChannel(controlGroup, CHANNEL_TIMER_AUTOOFF, getDecimal(ls.autoOff));
|
||||
updated |= updateChannel(controlGroup, CHANNEL_LIGHT_POWER, col.power);
|
||||
updated |= updateChannel(controlGroup, CHANNEL_TIMER_ACTIVE, getOnOff(light.hasTimer));
|
||||
if (profile.settings.lights != null) {
|
||||
// Channel control/timer
|
||||
ShellySettingsRgbwLight ls = profile.settings.lights.get(lightId);
|
||||
updated |= updateChannel(controlGroup, CHANNEL_TIMER_AUTOON, getDecimal(ls.autoOn));
|
||||
updated |= updateChannel(controlGroup, CHANNEL_TIMER_AUTOOFF, getDecimal(ls.autoOff));
|
||||
updated |= updateChannel(controlGroup, CHANNEL_TIMER_ACTIVE, getOnOff(light.hasTimer));
|
||||
updated |= updateChannel(controlGroup, CHANNEL_LIGHT_POWER, col.power);
|
||||
}
|
||||
|
||||
if (getBool(light.overpower)) {
|
||||
postEvent(ALARM_TYPE_OVERPOWER, false);
|
||||
|
@ -14,8 +14,8 @@ package org.openhab.binding.shelly.internal.handler;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyApiException;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyApiInterface;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyDeviceProfile;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyHttpApi;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.types.State;
|
||||
@ -36,7 +36,7 @@ public interface ShellyManagerInterface {
|
||||
|
||||
public ShellyDeviceProfile getProfile(boolean forceRefresh) throws ShellyApiException;
|
||||
|
||||
public ShellyHttpApi getApi();
|
||||
public ShellyApiInterface getApi();
|
||||
|
||||
public ShellyDeviceStats getStats();
|
||||
|
||||
|
@ -335,7 +335,7 @@ public class ShellyRelayHandler extends ShellyBaseHandler {
|
||||
public boolean updateRelays(ShellySettingsStatus status) throws ShellyApiException {
|
||||
boolean updated = false;
|
||||
// Check for Relay in Standard Mode
|
||||
if (profile.hasRelays && !profile.isRoller && !profile.isDimmer) {
|
||||
if (profile.hasRelays && !profile.isDimmer) {
|
||||
double voltage = -1;
|
||||
if (status.voltage == null && profile.settings.supplyVoltage != null) {
|
||||
// Shelly 1PM/1L (fix)
|
||||
@ -348,7 +348,9 @@ public class ShellyRelayHandler extends ShellyBaseHandler {
|
||||
updated |= updateChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_VOLTAGE,
|
||||
toQuantityType(voltage, DIGITS_VOLT, Units.VOLT));
|
||||
}
|
||||
}
|
||||
|
||||
if (profile.hasRelays && !profile.isRoller && !profile.isDimmer) {
|
||||
logger.trace("{}: Updating {} relay(s)", thingName, profile.numRelays);
|
||||
int i = 0;
|
||||
ShellyStatusRelay rstatus = api.getRelayStatus(i);
|
||||
@ -479,12 +481,14 @@ public class ShellyRelayHandler extends ShellyBaseHandler {
|
||||
toQuantityType(0.0, DIGITS_NONE, Units.PERCENT));
|
||||
}
|
||||
|
||||
ShellySettingsDimmer dsettings = profile.settings.dimmers.get(l);
|
||||
if (dsettings != null) {
|
||||
updated |= updateChannel(groupName, CHANNEL_TIMER_AUTOON,
|
||||
toQuantityType(getDouble(dsettings.autoOn), Units.SECOND));
|
||||
updated |= updateChannel(groupName, CHANNEL_TIMER_AUTOOFF,
|
||||
toQuantityType(getDouble(dsettings.autoOff), Units.SECOND));
|
||||
if (profile.settings.dimmers != null) {
|
||||
ShellySettingsDimmer dsettings = profile.settings.dimmers.get(l);
|
||||
if (dsettings != null) {
|
||||
updated |= updateChannel(groupName, CHANNEL_TIMER_AUTOON,
|
||||
toQuantityType(getDouble(dsettings.autoOn), Units.SECOND));
|
||||
updated |= updateChannel(groupName, CHANNEL_TIMER_AUTOOFF,
|
||||
toQuantityType(getDouble(dsettings.autoOff), Units.SECOND));
|
||||
}
|
||||
}
|
||||
|
||||
l++;
|
||||
|
@ -0,0 +1,99 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.shelly.internal.handler;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyApiException;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyApiInterface;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellySettingsStatus;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyDeviceProfile;
|
||||
import org.openhab.binding.shelly.internal.config.ShellyThingConfiguration;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* The {@link ShellyThingInterface} implements the interface for Shelly Manager to access the thing handler
|
||||
*
|
||||
* @author Markus Michels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface ShellyThingInterface {
|
||||
|
||||
public ShellyDeviceProfile getProfile(boolean forceRefresh) throws ShellyApiException;
|
||||
|
||||
public double getChannelDouble(String group, String channel);
|
||||
|
||||
public boolean updateChannel(String group, String channel, State value);
|
||||
|
||||
public boolean updateChannel(String channelId, State value, boolean force);
|
||||
|
||||
public void setThingOnline();
|
||||
|
||||
public void setThingOffline(ThingStatusDetail detail, String messageKey);
|
||||
|
||||
public boolean requestUpdates(int requestCount, boolean refreshSettings);
|
||||
|
||||
public void triggerUpdateFromCoap();
|
||||
|
||||
public void reinitializeThing();
|
||||
|
||||
public void restartWatchdog();
|
||||
|
||||
public void publishState(String channelId, State value);
|
||||
|
||||
public boolean areChannelsCreated();
|
||||
|
||||
public State getChannelValue(String group, String channel);
|
||||
|
||||
public boolean updateInputs(ShellySettingsStatus status);
|
||||
|
||||
public void updateChannelDefinitions(Map<String, Channel> dynChannels);
|
||||
|
||||
public void postEvent(String event, boolean force);
|
||||
|
||||
public void triggerChannel(String group, String channelID, String event);
|
||||
|
||||
public void triggerButton(String group, int idx, String value);
|
||||
|
||||
public ShellyDeviceStats getStats();
|
||||
|
||||
public void resetStats();
|
||||
|
||||
public Thing getThing();
|
||||
|
||||
public String getThingName();
|
||||
|
||||
public ShellyThingConfiguration getThingConfig();
|
||||
|
||||
public String getProperty(String key);
|
||||
|
||||
public void updateProperties(String key, String value);
|
||||
|
||||
public boolean updateWakeupReason(@Nullable List<Object> valueArray);
|
||||
|
||||
public ShellyApiInterface getApi();
|
||||
|
||||
public ShellyDeviceProfile getProfile();
|
||||
|
||||
public long getScheduledUpdates();
|
||||
|
||||
public void fillDeviceStatus(ShellySettingsStatus status, boolean updated);
|
||||
|
||||
public boolean checkRepresentation(String key);
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.shelly.internal.handler;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.ConfigurationPolicy;
|
||||
|
||||
/***
|
||||
* The{@link ShellyThingTable} implements a simple table to allow dispatching incoming events to the proper thing
|
||||
* handler
|
||||
*
|
||||
* @author Markus Michels - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = ShellyThingTable.class, configurationPolicy = ConfigurationPolicy.OPTIONAL)
|
||||
public class ShellyThingTable {
|
||||
private Map<String, ShellyThingInterface> thingTable = new ConcurrentHashMap<>();
|
||||
|
||||
public void addThing(String key, ShellyThingInterface thing) {
|
||||
thingTable.put(key, thing);
|
||||
}
|
||||
|
||||
public ShellyThingInterface getThing(String key) {
|
||||
ShellyThingInterface t = thingTable.get(key);
|
||||
if (t != null) {
|
||||
return t;
|
||||
}
|
||||
for (Map.Entry<String, ShellyThingInterface> entry : thingTable.entrySet()) {
|
||||
t = entry.getValue();
|
||||
if (t.checkRepresentation(key)) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
public void removeThing(String key) {
|
||||
if (thingTable.containsKey(key)) {
|
||||
thingTable.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, ShellyThingInterface> getTable() {
|
||||
return thingTable;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return thingTable.size();
|
||||
}
|
||||
}
|
@ -26,6 +26,7 @@ import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.openhab.binding.shelly.internal.ShellyHandlerFactory;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyApiException;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyApiInterface;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellyOtaCheckResult;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellySettingsLogin;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyDeviceProfile;
|
||||
@ -81,7 +82,7 @@ public class ShellyManagerActionPage extends ShellyManagerPage {
|
||||
|
||||
ShellyThingConfiguration config = getThingConfig(th, properties);
|
||||
ShellyDeviceProfile profile = th.getProfile();
|
||||
ShellyHttpApi api = th.getApi();
|
||||
ShellyApiInterface api = th.getApi();
|
||||
new ShellyHttpApi(uid, config, httpClient);
|
||||
|
||||
int refreshTimer = 0;
|
||||
@ -326,7 +327,7 @@ public class ShellyManagerActionPage extends ShellyManagerPage {
|
||||
!profile.settings.wifiRecoveryReboot ? "Enable WiFi Recovery" : "Disable WiFi Recovery");
|
||||
}
|
||||
|
||||
boolean set = (profile.settings.cloud != null) && profile.settings.cloud.enabled;
|
||||
boolean set = profile.settings.cloud != null && profile.settings.cloud.enabled;
|
||||
list.put(set ? ACTION_DISCLOUD : ACTION_ENCLOUD, set ? "Disable Cloud" : "Enable Cloud");
|
||||
|
||||
list.put(ACTION_RESET, "-Factory Reset");
|
||||
|
@ -78,7 +78,8 @@ public class ShellyManagerServlet extends HttpServlet {
|
||||
|
||||
try {
|
||||
httpService.registerServlet(SERVLET_URI, this, null, httpService.createDefaultHttpContext());
|
||||
logger.debug("{}: Started at '{}'", className, SERVLET_URI);
|
||||
// Promote Shelly Manager usage
|
||||
logger.info("{}", translationProvider.get("status.managerstarted", localIp, localPort + ""));
|
||||
} catch (NamespaceException | ServletException | IllegalArgumentException e) {
|
||||
logger.warn("{}: Unable to initialize bindingConfig", className, e);
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
package org.openhab.binding.shelly.internal.provider;
|
||||
|
||||
import static org.openhab.binding.shelly.internal.ShellyBindingConstants.*;
|
||||
import static org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.SHELLY_API_INVTEMP;
|
||||
import static org.openhab.binding.shelly.internal.util.ShellyUtils.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
@ -41,7 +42,7 @@ import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellyStatusLigh
|
||||
import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellyStatusRelay;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellyStatusSensor;
|
||||
import org.openhab.binding.shelly.internal.api.ShellyDeviceProfile;
|
||||
import org.openhab.binding.shelly.internal.handler.ShellyBaseHandler;
|
||||
import org.openhab.binding.shelly.internal.handler.ShellyThingInterface;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
@ -261,26 +262,24 @@ public class ShellyChannelDefinitions {
|
||||
|
||||
addChannel(thing, add, profile.settings.name != null, CHGR_DEVST, CHANNEL_DEVST_NAME);
|
||||
|
||||
if (!profile.isSensor) {
|
||||
if (!profile.isSensor && !profile.isIX3 && getDouble(status.temperature) != SHELLY_API_INVTEMP) {
|
||||
// Only some devices report the internal device temp
|
||||
addChannel(thing, add, (status.tmp != null) || (status.temperature != null), CHGR_DEVST,
|
||||
CHANNEL_DEVST_ITEMP);
|
||||
addChannel(thing, add, status.tmp != null || status.temperature != null, CHGR_DEVST, CHANNEL_DEVST_ITEMP);
|
||||
}
|
||||
addChannel(thing, add, profile.settings.sleepTime != null, CHGR_SENSOR, CHANNEL_SENSOR_SLEEPTIME);
|
||||
|
||||
// If device has more than 1 meter the channel accumulatedWatts receives the accumulated value
|
||||
boolean accuChannel = !profile.isRoller && !profile.isRGBW2
|
||||
&& (((status.meters != null) && (status.meters.size() > 1))
|
||||
|| ((status.emeters != null && status.emeters.size() > 1)));
|
||||
boolean accuChannel = (((status.meters != null) && (status.meters.size() > 1) && !profile.isRoller
|
||||
&& !profile.isRGBW2) || ((status.emeters != null && status.emeters.size() > 1)));
|
||||
addChannel(thing, add, accuChannel, CHGR_DEVST, CHANNEL_DEVST_ACCUWATTS);
|
||||
addChannel(thing, add, accuChannel, CHGR_DEVST, CHANNEL_DEVST_ACCUTOTAL);
|
||||
addChannel(thing, add, accuChannel && (status.emeters != null), CHGR_DEVST, CHANNEL_DEVST_ACCURETURNED);
|
||||
addChannel(thing, add, status.voltage != null || profile.settings.supplyVoltage != null, CHGR_DEVST,
|
||||
CHANNEL_DEVST_VOLTAGE);
|
||||
addChannel(thing, add,
|
||||
!profile.isRoller && !profile.isRGBW2
|
||||
&& (status.voltage != null || profile.settings.supplyVoltage != null),
|
||||
CHGR_DEVST, CHANNEL_DEVST_VOLTAGE);
|
||||
profile.status.uptime != null && (!profile.hasBattery || profile.isMotion || profile.isTRV), CHGR_DEVST,
|
||||
CHANNEL_DEVST_UPTIME);
|
||||
addChannel(thing, add, true, CHGR_DEVST, CHANNEL_DEVST_UPDATE);
|
||||
addChannel(thing, add, true, CHGR_DEVST, CHANNEL_DEVST_UPTIME);
|
||||
addChannel(thing, add, true, CHGR_DEVST, CHANNEL_DEVST_HEARTBEAT);
|
||||
addChannel(thing, add, profile.settings.ledPowerDisable != null, CHGR_DEVST, CHANNEL_LED_POWER_DISABLE);
|
||||
addChannel(thing, add, profile.settings.ledStatusDisable != null, CHGR_DEVST, CHANNEL_LED_STATUS_DISABLE); // WiFi
|
||||
@ -360,8 +359,7 @@ public class ShellyChannelDefinitions {
|
||||
if (status.inputs != null) {
|
||||
// Create channels per input. For devices with more than 1 input (Dimmer, 1L) multiple channel sets are
|
||||
// created by adding the index to the channel name
|
||||
boolean multi = ((profile.numRelays == 1) || profile.isDimmer || profile.isRoller)
|
||||
&& (profile.numInputs >= 2);
|
||||
boolean multi = (profile.numRelays == 1 || profile.isDimmer || profile.isRoller) && profile.numInputs >= 2;
|
||||
for (int i = 0; i < profile.numInputs; i++) {
|
||||
String suffix = multi ? String.valueOf(i + 1) : "";
|
||||
ShellyInputState input = status.inputs.get(i);
|
||||
@ -390,7 +388,7 @@ public class ShellyChannelDefinitions {
|
||||
addChannel(thing, add, roller.stopReason != null, CHGR_ROLLER, CHANNEL_ROL_CONTROL_STOPR);
|
||||
addChannel(thing, add, roller.safetySwitch != null, CHGR_ROLLER, CHANNEL_ROL_CONTROL_SAFETY);
|
||||
|
||||
ShellyBaseHandler handler = (ShellyBaseHandler) thing.getHandler();
|
||||
ShellyThingInterface handler = (ShellyThingInterface) thing.getHandler();
|
||||
if (handler != null) {
|
||||
ShellySettingsGlobal settings = handler.getProfile().settings;
|
||||
if (getBool(settings.favoritesEnabled) && (settings.favorites != null)) {
|
||||
@ -404,7 +402,7 @@ public class ShellyChannelDefinitions {
|
||||
Map<String, Channel> newChannels = new LinkedHashMap<>();
|
||||
addChannel(thing, newChannels, meter.power != null, group, CHANNEL_METER_CURRENTWATTS);
|
||||
addChannel(thing, newChannels, meter.total != null, group, CHANNEL_METER_TOTALKWH);
|
||||
addChannel(thing, newChannels, (meter.counters != null) && (meter.counters[0] != null), group,
|
||||
addChannel(thing, newChannels, meter.counters != null && meter.counters[0] != null, group,
|
||||
CHANNEL_METER_LASTMIN1);
|
||||
addChannel(thing, newChannels, meter.timestamp != null, group, CHANNEL_LAST_UPDATE);
|
||||
return newChannels;
|
||||
@ -509,14 +507,23 @@ public class ShellyChannelDefinitions {
|
||||
ChannelTypeUID channelTypeUID = channelDef.typeId.contains("system:")
|
||||
? new ChannelTypeUID(channelDef.typeId)
|
||||
: new ChannelTypeUID(BINDING_ID, channelDef.typeId);
|
||||
Channel channel;
|
||||
ChannelBuilder builder;
|
||||
if (channelDef.typeId.equalsIgnoreCase("system:button")) {
|
||||
channel = ChannelBuilder.create(channelUID, null).withKind(ChannelKind.TRIGGER)
|
||||
.withType(channelTypeUID).build();
|
||||
builder = ChannelBuilder.create(channelUID, null).withKind(ChannelKind.TRIGGER);
|
||||
} else {
|
||||
channel = ChannelBuilder.create(channelUID, channelDef.itemType).withType(channelTypeUID).build();
|
||||
builder = ChannelBuilder.create(channelUID, channelDef.itemType);
|
||||
}
|
||||
newChannels.put(channelId, channel);
|
||||
if (!channelDef.label.isEmpty()) {
|
||||
char grseq = lastChar(group);
|
||||
char chseq = lastChar(channelName);
|
||||
char sequence = isDigit(chseq) ? chseq : grseq;
|
||||
String label = !isDigit(sequence) ? channelDef.label : channelDef.label + " " + sequence;
|
||||
builder.withLabel(label);
|
||||
}
|
||||
if (!channelDef.description.isEmpty()) {
|
||||
builder.withDescription(channelDef.description);
|
||||
}
|
||||
newChannels.put(channelId, builder.withType(channelTypeUID).build());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -549,9 +556,21 @@ public class ShellyChannelDefinitions {
|
||||
this.typeId = typeId;
|
||||
|
||||
groupLabel = getText(PREFIX_GROUP + group + ".label");
|
||||
if (groupLabel.contains(PREFIX_GROUP)) {
|
||||
groupLabel = "";
|
||||
}
|
||||
groupDescription = getText(PREFIX_GROUP + group + ".description");
|
||||
label = getText(PREFIX_CHANNEL + channel + ".label");
|
||||
description = getText(PREFIX_CHANNEL + channel + ".description");
|
||||
if (groupDescription.contains(PREFIX_GROUP)) {
|
||||
groupDescription = "";
|
||||
}
|
||||
label = getText(PREFIX_CHANNEL + typeId.replace(':', '.') + ".label");
|
||||
if (label.contains(PREFIX_CHANNEL)) {
|
||||
label = "";
|
||||
}
|
||||
description = getText(PREFIX_CHANNEL + typeId + ".description");
|
||||
if (description.contains(PREFIX_CHANNEL)) {
|
||||
description = "";
|
||||
}
|
||||
}
|
||||
|
||||
public String getChanneId() {
|
||||
|
@ -18,7 +18,7 @@ import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.shelly.internal.handler.ShellyBaseHandler;
|
||||
import org.openhab.binding.shelly.internal.handler.ShellyThingInterface;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
@ -33,14 +33,14 @@ import org.slf4j.LoggerFactory;
|
||||
public class ShellyChannelCache {
|
||||
private final Logger logger = LoggerFactory.getLogger(ShellyChannelCache.class);
|
||||
|
||||
private final ShellyBaseHandler thingHandler;
|
||||
private final ShellyThingInterface thingHandler;
|
||||
private final Map<String, State> channelData = new ConcurrentHashMap<>();
|
||||
private String thingName = "";
|
||||
private boolean enabled = false;
|
||||
|
||||
public ShellyChannelCache(ShellyBaseHandler thingHandler) {
|
||||
public ShellyChannelCache(ShellyThingInterface thingHandler) {
|
||||
this.thingHandler = thingHandler;
|
||||
setThingName(thingHandler.thingName);
|
||||
setThingName(thingHandler.getThingName());
|
||||
}
|
||||
|
||||
public void setThingName(String thingName) {
|
||||
|
@ -289,9 +289,6 @@ public class ShellyUtils {
|
||||
|
||||
public static DateTimeType getTimestamp(String zone, long timestamp) {
|
||||
try {
|
||||
if (timestamp == 0) {
|
||||
throw new IllegalArgumentException("Timestamp value 0 is invalid");
|
||||
}
|
||||
ZoneId zoneId = !zone.isEmpty() ? ZoneId.of(zone) : ZoneId.systemDefault();
|
||||
ZonedDateTime zdt = LocalDateTime.now().atZone(zoneId);
|
||||
int delta = zdt.getOffset().getTotalSeconds();
|
||||
@ -346,4 +343,12 @@ public class ShellyUtils {
|
||||
}
|
||||
return new DecimalType(strength);
|
||||
}
|
||||
|
||||
public static boolean isDigit(char c) {
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
public static char lastChar(String s) {
|
||||
return s.length() > 1 ? s.charAt(s.length() - 1) : '*';
|
||||
}
|
||||
}
|
||||
|
@ -163,6 +163,6 @@ public class ShellyVersionDTO {
|
||||
return false;
|
||||
}
|
||||
return version.isEmpty() || version.contains("???") || version.toLowerCase().contains("master")
|
||||
|| (version.toLowerCase().contains("-rc"));
|
||||
|| (version.toLowerCase().contains("-rc") || version.toLowerCase().contains("beta"));
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +78,7 @@
|
||||
<default>0</default>
|
||||
</parameter>
|
||||
<parameter name="eventsRoller" type="boolean" required="false">
|
||||
<label>@text/thing-type.config.shelly.roller.eventsRoller.label)</label>
|
||||
<label>@text/thing-type.config.shelly.roller.eventsRoller.label</label>
|
||||
<description>@text/thing-type.config.shelly.roller.eventsRoller.description</description>
|
||||
<advanced>true</advanced>
|
||||
<default>false</default>
|
||||
|
@ -18,7 +18,8 @@ message.config-status.error.missing-userid = No user ID in the Thing configurati
|
||||
message.offline.conf-error-no-credentials = Device is password protected, but no credentials have been configured.
|
||||
message.offline.conf-error-access-denied = Access denied, check user id and password.
|
||||
message.offline.conf-error-wrong-mode = Device is no longer in the configured device mode {0}, required {1}. Delete the thing and re-discover the device.
|
||||
message.offline.status-error-timeout = Device is not reachable (API timeout).
|
||||
message.offline.status-error-timeout = Device is not reachable (API timeout)
|
||||
message.offline.status-error-unexpected-error = Unexpected error
|
||||
message.offline.status-error-unexpected-api-result = An unexpected API response. Please verify the logfile to get more detailed information.
|
||||
message.offline.status-error-watchdog = Device is not responding, seems to be unavailable.
|
||||
message.offline.status-error-restarted = The device has restarted and will be re-initialized.
|
||||
@ -31,12 +32,11 @@ message.versioncheck.tooold = WARNING: Firmware might be too old, installed: {0}
|
||||
message.versioncheck.update = INFO: New firmware available: current version: {0}, new version: {1}
|
||||
message.versioncheck.autocoiot = INFO: Firmware is full-filling the minimum version to auto-enable CoIoT
|
||||
message.init.noipaddress = Unable to detect local IP address. Please make sure that IPv4 is enabled for this interface and check openHAB Network Configuration.
|
||||
message.init.protected = Device is password protected, enter correct credentials in thing configuration.
|
||||
message.command.failed = ERROR: Unable to process command {0} for channel {1}
|
||||
message.command.init = Thing not yet initialized, command {0} triggers initialization
|
||||
message.command.init = Thing not yet initialized, command {0} triggered initialization
|
||||
message.status.unknown.initializing = Initializing or device in sleep mode.
|
||||
message.statusupdate.failed = Unable to update status
|
||||
message.status.managerstarted = Shelly Manager started at http(s)://{0}:{1}/shelly/manager"
|
||||
message.status.managerstarted = Shelly Manager started at http(s)://{0}:{1}/shelly/manager
|
||||
message.event.triggered = Event triggered: {0}
|
||||
message.event.filtered = Event filtered: {0}
|
||||
message.coap.init.failed = Unable to start CoIoT: {0}
|
||||
@ -106,7 +106,6 @@ thing-type.config.shelly.eventsCoIoT.description = Activates the CoIoT-Protocol
|
||||
thing-type.config.shelly.eventsSensorReport.label = Enable Sensor Events
|
||||
thing-type.config.shelly.eventsSensorReport.description = True: Register event URL for sensor updates.
|
||||
|
||||
|
||||
# thing config - roller
|
||||
thing-type.config.shelly.roller.favoriteUP.label = Favorite ID for UP
|
||||
thing-type.config.shelly.roller.favoriteUP.description = Specifies the favorite ID that is used during the command UP on the roller#control channel (use the Shelly App to configure favorites)
|
||||
@ -167,6 +166,7 @@ channel-group-type.shelly.dimmerChannel.description = A Shelly Dimmer channel
|
||||
channel-group-type.shelly.ix3Channel1.label = Input 1
|
||||
channel-group-type.shelly.ix3Channel2.label = Input 2
|
||||
channel-group-type.shelly.ix3Channel3.label = Input 3
|
||||
channel-group-type.shelly.ix3Channel4.label = Input 4
|
||||
channel-group-type.shelly.ix3Channel.description = Input Status
|
||||
channel-group-type.shelly.rollerControl.label = Roller Control
|
||||
channel-group-type.shelly.rollerControl.description = Controlling the roller mode
|
||||
@ -183,9 +183,9 @@ channel-group-type.shelly.externalSensors.description = Temperatures from extern
|
||||
channel-type.shelly.outputName.label = Output Name
|
||||
channel-type.shelly.outputName.description = Output/Channel Name as configured in the Shelly App
|
||||
channel-type.shelly.timerAutoOn.label = Auto-ON Timer
|
||||
channel-type.shelly.timerAutoOn.description = When the relay is switched off, it will be switched on automatically after n seconds
|
||||
channel-type.shelly.timerAutoOn.description = When the output of the relay is switched on, it will be switched off automatically after n seconds
|
||||
channel-type.shelly.timerAutoOff.label = Auto-OFF Timer
|
||||
channel-type.shelly.timerAutoOff.description = When the relay is switched on, it will be switched off automatically after n seconds
|
||||
channel-type.shelly.timerAutoOff.description = When the output of the relay is switched off, it will be switched on automatically after n seconds
|
||||
channel-type.shelly.timerActive.label = Auto ON/OFF timer active
|
||||
channel-type.shelly.timerActive.description = ON: A timer is active, OFF: no timer active
|
||||
channel-type.shelly.temperature.label = Temperature
|
||||
@ -208,9 +208,12 @@ channel-type.shelly.rollerFavorite.label = Position Favorite
|
||||
channel-type.shelly.rollerFavorite.description = Set roller position by selecting favorite 1-4 (needs to be defined in the Shelly App, 0=n/a)
|
||||
channel-type.shelly.rollerState.label = Roller State
|
||||
channel-type.shelly.rollerState.description = State of the roller (open/close/stop)
|
||||
channel-type.shelly.rollerState.state.option.open = opening
|
||||
channel-type.shelly.rollerState.state.option.close = closing
|
||||
channel-type.shelly.rollerState.state.option.opening = opening
|
||||
channel-type.shelly.rollerState.state.option.open = open
|
||||
channel-type.shelly.rollerState.state.option.closing = closing
|
||||
channel-type.shelly.rollerState.state.option.close = closed
|
||||
channel-type.shelly.rollerState.state.option.stop = stopped
|
||||
channel-type.shelly.rollerState.state.option.calibrating = calibrating
|
||||
channel-type.shelly.rollerStop.label = Roller stop reason
|
||||
channel-type.shelly.rollerStop.description = Last reason for stopping the Roller Shutter (normal, safety switch, obstacle detected)
|
||||
channel-type.shelly.rollerStop.state.option.normal = normal
|
||||
@ -223,12 +226,12 @@ channel-type.shelly.rollerDirection.state.option.close = close
|
||||
channel-type.shelly.rollerDirection.state.option.stop = stopped
|
||||
channel-type.shelly.rollerSafety.label = Safety Switch
|
||||
channel-type.shelly.rollerSafety.description = Status of the safety switch
|
||||
channel-type.shelly.inputState.label = Input
|
||||
channel-type.shelly.inputState.description = Input/Button state
|
||||
channel-type.shelly.inputState.label = Input/Button
|
||||
channel-type.shelly.inputState.description = Current state of the Input/Button
|
||||
channel-type.shelly.inputState1.label = Input #1
|
||||
channel-type.shelly.inputState1.description = Input/Button state #1
|
||||
channel-type.shelly.inputState1.description = Current state of the Input #1
|
||||
channel-type.shelly.inputState2.label = Input #2
|
||||
channel-type.shelly.inputState2.description = Input/Button state #2
|
||||
channel-type.shelly.inputState2.description = Current state of the Input #2
|
||||
channel-type.shelly.dimmerBrightness.label = Brightness
|
||||
channel-type.shelly.dimmerBrightness.description = Light Brightness in percent (0-100%, 0=OFF)
|
||||
channel-type.shelly.whiteBrightness.label = Brightness
|
||||
@ -243,8 +246,8 @@ channel-type.shelly.meterAccuReturned.label = Accumulated Returned Power
|
||||
channel-type.shelly.meterAccuReturned.description = Accumulated Returned Power in kW/h of the device (including all meters)
|
||||
channel-type.shelly.meterReactive.label = Reactive Energy
|
||||
channel-type.shelly.meterReactive.description = Instantaneous reactive power in Watts (W)
|
||||
channel-type.shelly.lastPower1.label = Last Power #1
|
||||
channel-type.shelly.lastPower1.description = Last power consumption #1 - one rounded minute
|
||||
channel-type.shelly.lastPower1.label = Last Power
|
||||
channel-type.shelly.lastPower1.description = Rounded power consumption during last minute
|
||||
channel-type.shelly.meterTotal.label = Total Energy Consumption
|
||||
channel-type.shelly.meterTotal.description = Total energy consumption in kW/h since the device powered up (resets on restart)
|
||||
channel-type.shelly.meterReturned.label = Total Returned Energy
|
||||
@ -398,7 +401,7 @@ channel-type.shelly.supplyVoltage.label = Supply Voltage
|
||||
channel-type.shelly.supplyVoltage.description = External voltage supplied to the device
|
||||
channel-type.shelly.lastUpdate.label = Last Update
|
||||
channel-type.shelly.lastUpdate.description = Timestamp of last status update
|
||||
channel-type.shelly.lastEvent.label = Event
|
||||
channel-type.shelly.lastEvent.label = Last Event
|
||||
channel-type.shelly.lastEvent.description = Event Type (S=Short push, SS=Double-Short push, SSS=Triple-Short push, L=Long push, SL=Short-Long push, LS=Long-Short push)
|
||||
channel-type.shelly.lastEvent.state.option.S = Short push
|
||||
channel-type.shelly.lastEvent.state.option.SS = Double-Short push
|
||||
@ -448,6 +451,9 @@ channel-type.shelly.sensorSleepTime.label = Sensor Sleep Time
|
||||
channel-type.shelly.sensorSleepTime.description = The sensor will not send notifications and will not perform actions until the specified time expires (0=disable)
|
||||
channel-type.shelly.deviceSchedule.label = Schedule active
|
||||
channel-type.shelly.deviceSchedule.description = ON: A scheduled program is active
|
||||
channel-type.shelly.system.power.label = Power
|
||||
channel-type.shelly.system.button.label = Event Trigger
|
||||
channel-type.shelly.system.brightness.label = Brightness
|
||||
|
||||
# Shelly Manager
|
||||
message.manager.invalid-url = Invalid URL or syntax
|
||||
|
@ -10,7 +10,6 @@
|
||||
<channels>
|
||||
<channel id="alarm" typeId="alarmTrigger"/>
|
||||
<channel id="wifiSignal" typeId="system.signal-strength"/>
|
||||
<channel id="uptime" typeId="uptime"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
@ -123,7 +122,7 @@
|
||||
</state>
|
||||
</channel-type>
|
||||
<channel-type id="supplyVoltage" advanced="true">
|
||||
<item-type>Number:ElectricPotentia</item-type>
|
||||
<item-type>Number:ElectricPotential</item-type>
|
||||
<label>@text/channel-type.shelly.supplyVoltage.label</label>
|
||||
<description>@text/channel-type.shelly.supplyVoltage.description</description>
|
||||
<category>Energy</category>
|
||||
@ -131,6 +130,7 @@
|
||||
<tag>Measurement</tag>
|
||||
<tag>Voltage</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern="%.0f %unit%"></state>
|
||||
</channel-type>
|
||||
<channel-type id="selfTest">
|
||||
<item-type>String</item-type>
|
||||
|
@ -379,7 +379,6 @@
|
||||
<item-type>Dimmer</item-type>
|
||||
<label>@text/channel-type.shelly.rollerPosition.label</label>
|
||||
<description>@text/channel-type.shelly.rollerPosition.description</description>
|
||||
<category>Blinds</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Level</tag>
|
||||
|
@ -162,7 +162,7 @@
|
||||
<item-type>String</item-type>
|
||||
<label>@text/channel-type.shelly.controlMode.label</label>
|
||||
<description>@text/channel-type.shelly.controlMode.description</description>
|
||||
<state>
|
||||
<state readOnly="false">
|
||||
<options>
|
||||
<option value="manual">@text/channel-type.shelly.controlMode.state.option.manual</option>
|
||||
<option value="automatic">@text/channel-type.shelly.controlMode.state.option.automatic</option>
|
||||
@ -433,7 +433,7 @@
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="sensorPPM">
|
||||
<item-type>Number:Density</item-type>
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>@text/channel-type.shelly.sensorPPM.label</label>
|
||||
<description>@text/channel-type.shelly.sensorPPM.description</description>
|
||||
<category>Gas</category>
|
||||
@ -441,7 +441,7 @@
|
||||
<tag>Measurement</tag>
|
||||
<tag>Gas</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern="%.0f %unit%">
|
||||
<state readOnly="true" pattern="%.0f ppm">
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user