Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[shelly] Shelly Motion, minor improvements #10054

Merged
merged 7 commits into from
Feb 23, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions bundles/org.openhab.binding.shelly/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Refer to [Advanced Users](doc/AdvancedUsers.md) for more information on openHAB
| shellydimmer | Shelly Dimmer | SHDM-1 |
| shellydimmer2 | Shelly Dimmer2 | SHDM-2 |
| shellyix3 | Shelly ix3 | SHIX3-1 |
| shellyuni | Shelly UNI | SHUNI-1 |
| shellyplug | Shelly Plug | SHPLG2-1 |
| shellyplugs | Shelly Plug-S | SHPLG-S |
| shellyem | Shelly EM with integrated Power Meters | SHEM |
Expand Down Expand Up @@ -578,6 +579,23 @@ Using the Thing configuration option `brightnessAutoOn` you could decide if the
| |lastEvent |String |yes |S/SS/SSS for 1/2/3x Shortpush or L for Longpush |
| |eventCount |Number |yes |Counter gets incremented every time the device issues a button event. |

### Shelly UNI - Low voltage sensor/actor: shellyuni)

|Group |Channel |Type |read-only|Description |
|----------|-------------|---------|---------|----------------------------------------------------------------------------|
|relay1 | | | |See group relay1 for Shelly 2, no autoOn/autoOff/timerActive channels |
|relay2 | | | |See group relay1 for Shelly 2, no autoOn/autoOff/timerActive channels |
|sensors |temperature1 |Number |yes |Temperature value of external sensor #1 (if connected to temp/hum addon) |
| |temperature2 |Number |yes |Temperature value of external sensor #2 (if connected to temp/hum addon) |
| |temperature3 |Number |yes |Temperature value of external sensor #3 (if connected to temp/hum addon) |
| |humidity |Number |yes |Humidity in percent (if connected to temp/hum addon) |
| |voltage |Number |yes |ADCS voltage |
|status |input1 |Switch |yes |State of Input 1 |
| |input2 |Switch |yes |State of Input 2 |
| |button |Trigger |yes |Event trigger, see section Button Events |
| |lastEvent |String |yes |S/SS/SSS for 1/2/3x Shortpush or L for Longpush |
| |eventCount |Number |yes |Counter gets incremented every time the device issues a button event. |

### Shelly Bulb (thing-type: shellybulb)

|Group |Channel |Type |read-only|Description |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ public class ShellyBindingConstants {
THING_TYPE_SHELLYVINTAGE, THING_TYPE_SHELLYDUORGBW, THING_TYPE_SHELLYRGBW2_COLOR,
THING_TYPE_SHELLYRGBW2_WHITE, THING_TYPE_SHELLYHT, THING_TYPE_SHELLYSENSE, THING_TYPE_SHELLYEYE,
THING_TYPE_SHELLYSMOKE, THING_TYPE_SHELLYGAS, THING_TYPE_SHELLYFLOOD, THING_TYPE_SHELLYDOORWIN,
THING_TYPE_SHELLYDOORWIN2, THING_TYPE_SHELLYBUTTON1, /* THING_TYPE_SHELLMOTION, */
THING_TYPE_SHELLYDOORWIN2, THING_TYPE_SHELLYBUTTON1, THING_TYPE_SHELLMOTION,
THING_TYPE_SHELLYPROTECTED, THING_TYPE_SHELLYUNKNOWN).collect(Collectors.toSet()));

// Thing Configuration Properties
Expand Down Expand Up @@ -265,6 +265,7 @@ public class ShellyBindingConstants {
public static final String CHANNEL_GROUP_BATTERY = "battery";
public static final String CHANNEL_SENSOR_BAT_LEVEL = "batteryLevel";
public static final String CHANNEL_SENSOR_BAT_LOW = "lowBattery";
public static final String CHANNEL_BAT_EXT_POWER = "externalPower";

public static final String CHANNEL_GROUP_LIGHT_CONTROL = "control";
public static final String CHANNEL_LIGHT_COLOR_MODE = "mode";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,14 @@
@NonNullByDefault
@Component(service = { ThingHandlerFactory.class, ShellyHandlerFactory.class }, configurationPid = "binding.shelly")
public class ShellyHandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = ShellyBindingConstants.SUPPORTED_THING_TYPES_UIDS;

private final Logger logger = LoggerFactory.getLogger(ShellyHandlerFactory.class);
private final HttpClient httpClient;
private final ShellyTranslationProvider messages;
private final ShellyCoapServer coapServer;
private final Set<ShellyBaseHandler> deviceListeners = ConcurrentHashMap.newKeySet();
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = ShellyBindingConstants.SUPPORTED_THING_TYPES_UIDS;

private final Map<String, ShellyBaseHandler> deviceListeners = new ConcurrentHashMap<>();
private ShellyBindingConfiguration bindingConfig = new ShellyBindingConfiguration();
private String localIP = "";
private int httpPort = -1;
Expand Down Expand Up @@ -129,21 +131,28 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) {
}

if (handler != null) {
deviceListeners.add(handler);
String uid = thing.getUID().getAsString();
deviceListeners.put(uid, handler);
logger.debug("Thing handler for uid {} added, total things = {}", uid, deviceListeners.size());
return handler;
}

logger.debug("Unable to create Thing Handler instance!");
return null;
}

public Map<String, ShellyBaseHandler> getThingHandlers() {
return deviceListeners;
}

/**
* Remove handler of things.
*/
@Override
protected synchronized void removeHandler(@NonNull ThingHandler thingHandler) {
if (thingHandler instanceof ShellyBaseHandler) {
deviceListeners.remove(thingHandler);
String uid = thingHandler.getThing().getUID().getAsString();
deviceListeners.remove(uid);
}
}

Expand All @@ -158,8 +167,9 @@ protected synchronized void removeHandler(@NonNull ThingHandler thingHandler) {
public void onEvent(String ipAddress, String deviceName, String componentIndex, String eventType,
Map<String, String> parameters) {
logger.trace("{}: Dispatch event to thing handler", deviceName);
for (ShellyBaseHandler listener : deviceListeners) {
if (listener.onEvent(ipAddress, deviceName, componentIndex, eventType, parameters)) {
for (Map.Entry<String, ShellyBaseHandler> listener : deviceListeners.entrySet()) {
ShellyBaseHandler thingHandler = listener.getValue();
if (thingHandler.onEvent(ipAddress, deviceName, componentIndex, eventType, parameters)) {
// event processed
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public class ShellyApiJsonDTO {
public static final String SHELLY_URL_SETTINGS_CLOUD = "/settings/cloud";
public static final String SHELLY_URL_LIST_IR = "/ir/list";
public static final String SHELLY_URL_SEND_IR = "/ir/emit";
public static final String SHELLY_URL_RESTART = "/reboot";

public static final String SHELLY_URL_SETTINGS_RELAY = "/settings/relay";
public static final String SHELLY_URL_STATUS_RELEAY = "/status/relay";
Expand Down Expand Up @@ -231,6 +232,11 @@ public static class ShellySettingsDevice {
public String hostname;
public String fw;
public Boolean auth;

@SerializedName("coiot") // Shelly Motion Multicast Endpoint
public String coiot;
public Integer longid;

@SerializedName("num_outputs")
public Integer numOutputs;
@SerializedName("num_meters")
Expand Down Expand Up @@ -513,6 +519,8 @@ public static class ShellySettingsUpdate {
public String newVersion;
@SerializedName("old_version")
public String oldVersion;
@SerializedName("beta_version")
public String betaVersion;
}

public static class ShellySettingsGlobal {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public class ShellyDeviceProfile {
public boolean isSensor = false; // true for HT & Smoke
public boolean hasBattery = false; // true if battery device
public boolean isSense = false; // true if thing is a Shelly Sense
public boolean isMotion = false; // true if thing is a Shelly Sense
public boolean isHT = false; // true for H&T
public boolean isDW = false; // true for Door Window sensor
public boolean isButton = false; // true for a Shelly Button 1
Expand All @@ -91,6 +92,8 @@ public class ShellyDeviceProfile {

public int updatePeriod = 2 * UPDATE_SETTINGS_INTERVAL_SECONDS + 10;

public String coiotEndpoint = "";

public Map<String, String> irCodes = new HashMap<>(); // Sense: list of stored IR codes

public ShellyDeviceProfile() {
Expand Down Expand Up @@ -188,13 +191,13 @@ public void initFromThingType(String name) {
boolean isSmoke = thingType.equals(THING_TYPE_SHELLYSMOKE_STR);
boolean isGas = thingType.equals(THING_TYPE_SHELLYGAS_STR);
boolean isUNI = thingType.equals(THING_TYPE_SHELLYUNI_STR);
boolean isMotion = thingType.equals(THING_TYPE_SHELLYMOTION_STR);
isHT = thingType.equals(THING_TYPE_SHELLYHT_STR);
isDW = thingType.equals(THING_TYPE_SHELLYDOORWIN_STR) || thingType.equals(THING_TYPE_SHELLYDOORWIN2_STR);
isMotion = thingType.startsWith(THING_TYPE_SHELLYMOTION_STR);
isSense = thingType.equals(THING_TYPE_SHELLYSENSE_STR);
isIX3 = thingType.equals(THING_TYPE_SHELLYIX3_STR);
isButton = thingType.equals(THING_TYPE_SHELLYBUTTON1_STR);
isSensor = isHT || isFlood || isDW || isSmoke || isGas || isButton || isUNI || isSense;
isSensor = isHT || isFlood || isDW || isSmoke || isGas || isButton || isUNI || isMotion || isSense;
hasBattery = isHT || isFlood || isDW || isSmoke || isButton || isMotion; // we assume that Sense is connected to
// the charger
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@
import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellySenseKeyCode;
import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellySettingsDevice;
import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellySettingsLight;
import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellySettingsLogin;
import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellySettingsStatus;
import org.openhab.binding.shelly.internal.api.ShellyApiJsonDTO.ShellySettingsUpdate;
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;
Expand Down Expand Up @@ -228,6 +230,27 @@ public void setLightSetting(String parm, String value) throws ShellyApiException
request(SHELLY_URL_SETTINGS + "?" + parm + "=" + value);
}

public ShellySettingsLogin getLoginSettings() throws ShellyApiException {
return callApi(SHELLY_URL_SETTINGS + "/login", ShellySettingsLogin.class);
}

public ShellySettingsLogin setLoginCredentials(String user, String password) throws ShellyApiException {
return callApi(SHELLY_URL_SETTINGS + "/login?enabled=yes&username=" + user + "&password=" + password,
ShellySettingsLogin.class);
}

public String deviceReboot() throws ShellyApiException {
return callApi(SHELLY_URL_RESTART, String.class);
}

public String factoryReset() throws ShellyApiException {
return callApi(SHELLY_URL_SETTINGS + "?reset=true", String.class);
}

public ShellySettingsUpdate firmwareUpdate(String uri) throws ShellyApiException {
return callApi("/ota?" + uri, ShellySettingsUpdate.class);
}

/**
* Change between White and Color Mode
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ protected boolean handleStatusUpdate(List<CoIotSensor> sensorUpdates, CoIotDescr
switch (sen.type.toLowerCase()) {
case "b": // BatteryLevel +
updateChannel(updates, CHANNEL_GROUP_BATTERY, CHANNEL_SENSOR_BAT_LEVEL,
toQuantityType(s.value, DIGITS_PERCENT, Units.PERCENT));
toQuantityType(s.value, 0, Units.PERCENT));
break;
case "h" /* Humidity */:
updateChannel(updates, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_HUM,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.library.unit.Units;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -298,7 +299,8 @@ public boolean handleStatusUpdate(List<CoIotSensor> sensorUpdates, CoIotDescrSen
case "3119": // Motion timestamp
// {"I":3119,"T":"S","D":"timestamp","U":"s","R":["U32","-1"],"L":1},
updateChannel(updates, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_MOTION_TS,
getTimestamp(getString(profile.settings.timezone), (long) s.value));
s.value != 0 ? getTimestamp(getString(profile.settings.timezone), (long) s.value)
: UnDefType.UNDEF);
break;
case "3120": // motionActive
// {"I":3120,"T":"S","D":"motionActive","R":["0/1","-1"],"L":1},
Expand Down
Loading