[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
8 changed files with 250 additions and 38 deletions

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>