[myStrom] Added Motionsensor and API Token (#13201)

* Added API Token to configuration.
* Added motionsensor to myStrom binding.
* Added SPDX Header.
* fix: removed unnecessary updateStatus().

Signed-off-by: Stefan Navratil <stefan@navratil.ch>
This commit is contained in:
Pumpur 2022-08-09 16:03:29 +02:00 committed by GitHub
parent 5b038786d5
commit e3be803948
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 250 additions and 38 deletions

View File

@ -1,15 +1,17 @@
# myStrom Binding
This extension adds support for the myStrom devices. Currently only the smart plug is implemented.
This extension adds support for the myStrom devices.
As of today only the Smart Plug, Bulb and the Motionsensor are implemented.
## Supported Things
This bundle adds the following thing types:
| Thing | ThingTypeID | Description |
| ------------------ | ----------- | -------------------------------------------------- |
| myStrom Smart Plug | mystromplug | A myStrom smart plug |
| myStrom Bulb | mystrombulb | A myStrom bulb |
| Thing | ThingTypeID | Description |
| ----------------------| ----------- | -------------------------------------------------- |
| myStrom Smart Plug | mystromplug | A myStrom smart plug |
| myStrom Bulb | mystrombulb | A myStrom bulb |
| myStrom Motion Sensor | mystrompir | A myStrom bulb |
According to the myStrom API documentation all request specific to the myStrom Bulb are also work on the LED strip.
@ -26,6 +28,7 @@ The following parameters are valid for all thing types:
| --------- | ------- | -------- | ------------------ | -------------------------------------------------------------------------- |
| hostname | string | yes | localhost | The IP address or hostname of the myStrom smart plug |
| refresh | integer | no | 10 | Poll interval in seconds. Increase this if you encounter connection errors |
| apiToken | string | no | | Specifies the API Token, if required. |
## Properties
@ -52,12 +55,14 @@ Disabling/enabling the thing can be used to update the properties.
| ---------------- | -------------------- | --------- | --------------------------------------------------------------------- |-------------------------------------|
| switch | Switch | false | Turn the device on or off | mystromplug, mystrombulb |
| power | Number:Power | true | The currently delivered power | mystromplug, mystrombulb |
| temperature | Number:Temperature | true | The temperature at the plug | mystromplug |
| temperature | Number:Temperature | true | The temperature at the plug | mystromplug, mystrompir |
| color | Color | false | The color we set the bulb to (mode 'hsv') | mystrombulb |
| colorTemperature | Dimmer | false | The color temperature of the bulb in mode 'mono' (percentage) | mystrombulb |
| brightness | Dimmer | false | The brightness of the bulb in mode 'mono' | mystrombulb |
| ramp | Number:Time | false | Transition time from the lights current state to the new state. [ms] | mystrombulb |
| mode | String | false | The color mode we want the Bulb to set to (rgb, hsv or mono) | mystrombulb |
| light | Dimmer | true | The brightness of the Room. | mystrompir |
| motion | Switch | true | Motionstatus of the sensor | mystrompir |
## Full Example

View File

@ -12,17 +12,7 @@
*/
package org.openhab.binding.mystrom.internal;
import static org.openhab.binding.mystrom.internal.MyStromBindingConstants.PROPERTY_CONNECTED;
import static org.openhab.binding.mystrom.internal.MyStromBindingConstants.PROPERTY_DNS;
import static org.openhab.binding.mystrom.internal.MyStromBindingConstants.PROPERTY_GW;
import static org.openhab.binding.mystrom.internal.MyStromBindingConstants.PROPERTY_IP;
import static org.openhab.binding.mystrom.internal.MyStromBindingConstants.PROPERTY_LAST_REFRESH;
import static org.openhab.binding.mystrom.internal.MyStromBindingConstants.PROPERTY_MAC;
import static org.openhab.binding.mystrom.internal.MyStromBindingConstants.PROPERTY_MASK;
import static org.openhab.binding.mystrom.internal.MyStromBindingConstants.PROPERTY_SSID;
import static org.openhab.binding.mystrom.internal.MyStromBindingConstants.PROPERTY_STATIC;
import static org.openhab.binding.mystrom.internal.MyStromBindingConstants.PROPERTY_TYPE;
import static org.openhab.binding.mystrom.internal.MyStromBindingConstants.PROPERTY_VERSION;
import static org.openhab.binding.mystrom.internal.MyStromBindingConstants.*;
import java.text.DateFormat;
import java.util.Calendar;
@ -61,10 +51,9 @@ import com.google.gson.JsonSyntaxException;
@NonNullByDefault
public abstract class AbstractMyStromHandler extends BaseThingHandler {
protected static final String COMMUNICATION_ERROR = "Error while communicating to the myStrom plug: ";
protected static final String HTTP_REQUEST_URL_PREFIX = "http://";
protected MyStromConfiguration config;
protected final HttpClient httpClient;
protected String hostname = "";
protected String mac = "";
private final Logger logger = LoggerFactory.getLogger(AbstractMyStromHandler.class);
@ -73,14 +62,13 @@ public abstract class AbstractMyStromHandler extends BaseThingHandler {
public AbstractMyStromHandler(Thing thing, HttpClient httpClient) {
super(thing);
config = getConfigAs(MyStromConfiguration.class);
this.httpClient = httpClient;
}
@Override
public final void initialize() {
MyStromConfiguration config = getConfigAs(MyStromConfiguration.class);
this.hostname = HTTP_REQUEST_URL_PREFIX + config.hostname;
config = getConfigAs(MyStromConfiguration.class);
updateStatus(ThingStatus.UNKNOWN);
scheduler.schedule(this::initializeInternal, 0, TimeUnit.SECONDS);
}
@ -135,9 +123,12 @@ public abstract class AbstractMyStromHandler extends BaseThingHandler {
*/
protected final String sendHttpRequest(HttpMethod method, String path, @Nullable String requestData)
throws MyStromException {
String url = hostname + path;
String url = config.getHostname() + path;
try {
Request request = httpClient.newRequest(url).timeout(10, TimeUnit.SECONDS).method(method);
if (!config.getApiToken().isEmpty()) {
request.getHeaders().add("Token", config.getApiToken());
}
if (requestData != null) {
request = request.content(new StringContentProvider(requestData)).header(HttpHeader.CONTENT_TYPE,
"application/x-www-form-urlencoded");
@ -157,9 +148,7 @@ public abstract class AbstractMyStromHandler extends BaseThingHandler {
try {
updateProperties();
checkRequiredInfo();
updateStatus(ThingStatus.ONLINE);
MyStromConfiguration config = getConfigAs(MyStromConfiguration.class);
pollingJob = scheduler.scheduleWithFixedDelay(this::pollDevice, 0, config.refresh, TimeUnit.SECONDS);
pollingJob = scheduler.scheduleWithFixedDelay(this::pollDevice, 0, config.getRefresh(), TimeUnit.SECONDS);
} catch (MyStromException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
}

View File

@ -26,12 +26,14 @@ import org.openhab.core.thing.ThingTypeUID;
public class MyStromBindingConstants {
public static final int DEFAULT_REFRESH_RATE_SECONDS = 10;
public static final int DEFAULT_BACKOFF_TIME_SECONDS = 10;
private static final String BINDING_ID = "mystrom";
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_PLUG = new ThingTypeUID(BINDING_ID, "mystromplug");
public static final ThingTypeUID THING_TYPE_BULB = new ThingTypeUID(BINDING_ID, "mystrombulb");
public static final ThingTypeUID THING_TYPE_PIR = new ThingTypeUID(BINDING_ID, "mystrompir");
// List of all Channel ids
public static final String CHANNEL_SWITCH = "switch";
@ -42,6 +44,8 @@ public class MyStromBindingConstants {
public static final String CHANNEL_MODE = "mode";
public static final String CHANNEL_COLOR_TEMPERATURE = "colorTemperature";
public static final String CHANNEL_BRIGHTNESS = "brightness";
public static final String CHANNEL_MOTION = "motion";
public static final String CHANNEL_LIGHT = "light";
// Config
public static final String CONFIG_MAC = "mac";

View File

@ -12,7 +12,7 @@
*/
package org.openhab.binding.mystrom.internal;
import static org.openhab.binding.mystrom.internal.MyStromBindingConstants.DEFAULT_REFRESH_RATE_SECONDS;
import static org.openhab.binding.mystrom.internal.MyStromBindingConstants.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
@ -20,16 +20,69 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
* The {@link MyStromConfiguration} class contains fields mapping thing configuration parameters.
*
* @author Paul Frank - Initial contribution
* @author Stefan Navratil - Added configuration for myStrom PIR
*/
@NonNullByDefault
public class MyStromConfiguration {
private final String urlPrefix = "http://";
private String hostname = "localhost";
private String apiToken = "";
private int refresh = DEFAULT_REFRESH_RATE_SECONDS;
private int backoffTime = DEFAULT_BACKOFF_TIME_SECONDS;
private boolean ledEnable = true;
/**
* Hostname of the myStrom device.
* Returns the hostname with http prefix if missing.
*
* @return hostname
*/
public String hostname = "localhost";
public String getHostname() {
String prefix = "";
if (!this.hostname.contains(urlPrefix)) {
prefix = urlPrefix;
}
return prefix + this.hostname;
}
/**
* Number of seconds in between refreshes from the myStrom device.
* returns API Token
*
* @return apiToken
*/
public int refresh = DEFAULT_REFRESH_RATE_SECONDS;
public String getApiToken() {
return apiToken;
}
/**
* Returns the refreshrate in SECONDS.
*
* @return refresh
*/
public int getRefresh() {
return refresh;
}
/**
* Returns the Backoff time of the MotionSensor in SECONDS.
*
* @return backoff_time
*/
public int getBackoffTime() {
return backoffTime;
}
/**
* Returns the Status LED Configuration.
*
* @return led_enable
*/
public boolean getLedEnable() {
return ledEnable;
}
}

View File

@ -12,8 +12,7 @@
*/
package org.openhab.binding.mystrom.internal;
import static org.openhab.binding.mystrom.internal.MyStromBindingConstants.THING_TYPE_BULB;
import static org.openhab.binding.mystrom.internal.MyStromBindingConstants.THING_TYPE_PLUG;
import static org.openhab.binding.mystrom.internal.MyStromBindingConstants.*;
import java.util.Set;
@ -40,7 +39,8 @@ import org.osgi.service.component.annotations.Reference;
@Component(configurationPid = "binding.mystrom", service = ThingHandlerFactory.class)
public class MyStromHandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_PLUG, THING_TYPE_BULB);
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_PLUG, THING_TYPE_BULB,
THING_TYPE_PIR);
private final HttpClientFactory httpClientFactory;
@ -62,6 +62,8 @@ public class MyStromHandlerFactory extends BaseThingHandlerFactory {
return new MyStromPlugHandler(thing, httpClientFactory.getCommonHttpClient());
} else if (THING_TYPE_BULB.equals(thingTypeUID)) {
return new MyStromBulbHandler(thing, httpClientFactory.getCommonHttpClient());
} else if (THING_TYPE_PIR.equals(thingTypeUID)) {
return new MyStromPIRHandler(thing, httpClientFactory.getCommonHttpClient());
}
return null;

View File

@ -0,0 +1,85 @@
/**
* 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.mystrom.internal;
import static org.openhab.binding.mystrom.internal.MyStromBindingConstants.*;
import static org.openhab.core.library.unit.SIUnits.CELSIUS;
import static org.openhab.core.library.unit.Units.PERCENT;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.http.HttpMethod;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.types.Command;
import com.google.gson.JsonParseException;
/**
*
* @author Stefan Navratil - Initial Contribution
*
*/
@NonNullByDefault
public class MyStromPIRHandler extends AbstractMyStromHandler {
private static class MyStromReport {
public float light;
public boolean motion;
public float temperature;
}
public MyStromPIRHandler(Thing thing, HttpClient httpClient) {
super(thing, httpClient);
try {
sendHttpRequest(HttpMethod.POST, "/api/v1/settings/pir",
"{\"backoff_time\":" + config.getBackoffTime() + ",\"led_enable\":" + config.getLedEnable() + "}");
} catch (MyStromException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
}
@Override
protected void pollDevice() {
MyStromReport report = getReport();
if (report != null) {
updateState(CHANNEL_MOTION, OnOffType.from(report.motion));
updateState(CHANNEL_TEMPERATURE, QuantityType.valueOf(report.temperature, CELSIUS));
// The Default Light thresholds are from 30 to 300.
updateState(CHANNEL_LIGHT, QuantityType.valueOf(report.light / 3, PERCENT));
}
}
private @Nullable MyStromReport getReport() {
try {
String json = sendHttpRequest(HttpMethod.GET, "/api/v1/sensors", null);
MyStromReport report = gson.fromJson(json, MyStromReport.class);
updateStatus(ThingStatus.ONLINE);
return report;
} catch (MyStromException | JsonParseException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
return null;
}
}
}

View File

@ -7,17 +7,32 @@ binding.mystrom.description = This is the binding for myStrom devices.
thing-type.mystrom.mystrombulb.label = myStrom Bulb
thing-type.mystrom.mystrombulb.description = Controls the myStrom bulb
thing-type.mystrom.mystrompir.label = myStrom Motion Sensor
thing-type.mystrom.mystromplug.label = myStrom Smart Plug
thing-type.mystrom.mystromplug.description = Controls the myStrom smart plug
# thing types config
thing-type.config.mystrom.mystrombulb.apiToken.label = API Token
thing-type.config.mystrom.mystrombulb.apiToken.description = Specifies the API token, if required (optional).
thing-type.config.mystrom.mystrombulb.hostname.label = Hostname
thing-type.config.mystrom.mystrombulb.hostname.description = The host name or IP address of the myStrom bulb.
thing-type.config.mystrom.mystrombulb.hostname.description = The hostname or IP address of the myStrom bulb.
thing-type.config.mystrom.mystrombulb.refresh.label = Refresh Interval
thing-type.config.mystrom.mystrombulb.refresh.description = Specifies the refresh interval in seconds.
thing-type.config.mystrom.mystrompir.apiToken.label = API Token
thing-type.config.mystrom.mystrompir.apiToken.description = Specifies the API token, if required (optional).
thing-type.config.mystrom.mystrompir.backoffTime.label = Backoff Time
thing-type.config.mystrom.mystrompir.backoffTime.description = Specifies the minimum frequency between successive motion detections in seconds.
thing-type.config.mystrom.mystrompir.hostname.label = Hostname
thing-type.config.mystrom.mystrompir.hostname.description = The hostname or IP address of the myStrom sensor.
thing-type.config.mystrom.mystrompir.ledEnable.label = LED Enabled
thing-type.config.mystrom.mystrompir.ledEnable.description = Enables the status LED on the device.
thing-type.config.mystrom.mystrompir.refresh.label = Refresh Interval
thing-type.config.mystrom.mystrompir.refresh.description = Specifies the refresh interval in seconds.
thing-type.config.mystrom.mystromplug.apiToken.label = API Token
thing-type.config.mystrom.mystromplug.apiToken.description = Specifies the API token, if required (optional).
thing-type.config.mystrom.mystromplug.hostname.label = Hostname
thing-type.config.mystrom.mystromplug.hostname.description = The host name or IP address of the myStrom plug.
thing-type.config.mystrom.mystromplug.hostname.description = The hostname or IP address of the myStrom plug.
thing-type.config.mystrom.mystromplug.refresh.label = Refresh Interval
thing-type.config.mystrom.mystromplug.refresh.description = Specifies the refresh interval in seconds.

View File

@ -32,7 +32,7 @@
<config-description>
<parameter name="hostname" type="text">
<label>Hostname</label>
<description>The host name or IP address of the myStrom plug.</description>
<description>The hostname or IP address of the myStrom plug.</description>
<context>network-address</context>
<default>localhost</default>
</parameter>
@ -41,6 +41,10 @@
<description>Specifies the refresh interval in seconds.</description>
<default>10</default>
</parameter>
<parameter name="apiToken" type="text">
<label>API Token</label>
<description>Specifies the API token, if required (optional).</description>
</parameter>
</config-description>
</thing-type>
@ -77,7 +81,7 @@
<config-description>
<parameter name="hostname" type="text" required="true">
<label>Hostname</label>
<description>The host name or IP address of the myStrom bulb.</description>
<description>The hostname or IP address of the myStrom bulb.</description>
<context>network-address</context>
<default>localhost</default>
</parameter>
@ -86,10 +90,65 @@
<description>Specifies the refresh interval in seconds.</description>
<default>10</default>
</parameter>
<parameter name="apiToken" type="text">
<label>API Token</label>
<description>Specifies the API token, if required (optional).</description>
</parameter>
</config-description>
</thing-type>
<thing-type id="mystrompir">
<label>myStrom Motion Sensor</label>
<channels>
<channel id="motion" typeId="system.motion"/>
<channel id="temperature" typeId="system.indoor-temperature"></channel>
<channel id="light" typeId="system.brightness"></channel>
</channels>
<properties>
<property name="mac"/>
<property name="version"/>
<property name="type"/>
<property name="ssid"/>
<property name="ip"/>
<property name="mask"/>
<property name="gw"/>
<property name="dns"/>
<property name="static"/>
<property name="connected"/>
</properties>
<representation-property>mac</representation-property>
<config-description>
<parameter name="hostname" type="text">
<label>Hostname</label>
<description>The hostname or IP address of the myStrom sensor.</description>
<context>network-address</context>
<default>localhost</default>
</parameter>
<parameter name="refresh" type="integer" unit="s" min="1">
<label>Refresh Interval</label>
<description>Specifies the refresh interval in seconds.</description>
<default>10</default>
</parameter>
<parameter name="apiToken" type="text">
<label>API Token</label>
<description>Specifies the API token, if required (optional).</description>
</parameter>
<parameter name="backoffTime" type="integer" unit="s" min="1">
<default>10</default>
<label>Backoff Time</label>
<description>Specifies the minimum frequency between successive motion detections in seconds.</description>
</parameter>
<parameter name="ledEnable" type="boolean">
<default>true</default>
<label>LED Enabled</label>
<description>Enables the status LED on the device.</description>
</parameter>
</config-description>
</thing-type>
<channel-type id="power-channel">
<item-type>Number:Power</item-type>