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

[mystrom] Add support for myStrom Bulb #9910

Merged
merged 6 commits into from
Feb 23, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
43 changes: 38 additions & 5 deletions bundles/org.openhab.binding.mystrom/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ This bundle adds the following thing types:
| Thing | ThingTypeID | Description |
| ------------------ | ----------- | -------------------------------------------------- |
| myStrom Smart Plug | mystromplug | A myStrom smart plug |
| myStrom Bulb | mystrombulb | A myStrom bulb |

According to the myStrom API documentation all request specific to the myStrom Bulb are also work on the LED strip.

## Discovery

Expand All @@ -24,13 +27,43 @@ 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 |

## Properties

In addition to the configuration a myStrom thing has the following properties.

| Property-Name | Description |
| ------------- | --------------------------------------------------------------------- |
| version | Current firmware version |
| type | The type of the device (i.e. bulb = 102) |
| ssid | SSID of the currently connected network |
| ip | Current ip address |
| mask | Mask of the current network |
| gateway | Gateway of the current network |
| dns | DNS of the current network |
| static | Whether or not the ip address is static |
| connected | Whether or not the device is connected to the internet |
| mac | The mac address of the bridge in upper case letters without delimiter |

## Channels

| Channel ID | Item Type | Read only | Description |
| ---------------- | -------------------- | --------- | ------------------------------------------------------------- |
| switch | Switch | false | Turn the smart plug on or off |
| power | Number:Power | true | The currently delivered power |
| temperature | Number:Temperature | true | The temperature at the plug |
| Channel ID | Item Type | Read only | Description | Thing types supporting this channel |
| ---------------- | -------------------- | --------- | --------------------------------------------------------------------- |-------------------------------------|
| 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 |
| color | Color | false | The color we set the bulb to (mode 'hsv') | mystrombulb |
| colorTemperature | Number | false | The color temperature of the bulb in mode 'mono' | mystrombulb |
| brightness | Dimmer | false | The brightness of the bulb in mode 'mono' | mystrombulb |
| ramp | Number:Time | false | Transition time from the light’s 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 |

## Thing actions

The myStrom things support the following actions.

| Name | Description | Specification |
|---------------------------------|----------------------------------------------------------------|-------------------------- |
| refreshProperties | Query the device information and Refresh the device properties | void refreshProperties() |
Fredo70 marked this conversation as resolved.
Show resolved Hide resolved

## Full Example

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
/**
* Copyright (c) 2010-2021 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.PROPERTY_CONNECTED;
import static org.openhab.binding.mystrom.internal.MyStromBindingConstants.PROPERTY_DNS;
J-N-K marked this conversation as resolved.
Show resolved Hide resolved
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 java.text.DateFormat;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.http.HttpMethod;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.ThingHandlerService;

import com.google.gson.Gson;

/**
* The {@link MyStromAbstractHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Frederic Chastagnol - Initial contribution
*/
@NonNullByDefault
public abstract class MyStromAbstractHandler extends BaseThingHandler {
protected static final int HTTP_OK_CODE = 200;
Fredo70 marked this conversation as resolved.
Show resolved Hide resolved
protected static final String COMMUNICATION_ERROR = "Error while communicating to the myStrom plug: ";
protected static final String HTTP_REQUEST_URL_PREFIX = "http://";

private final HttpClient httpClient;
private String hostname = "";
private String mac = "";

private @Nullable ScheduledFuture<?> pollingJob;
private final Gson gson = new Gson();

public MyStromAbstractHandler(Thing thing, HttpClient httpClient) {
Fredo70 marked this conversation as resolved.
Show resolved Hide resolved
super(thing);
this.httpClient = httpClient;
}

@Override
public final void initialize() {
MyStromConfiguration config = getConfigAs(MyStromConfiguration.class);
this.hostname = HTTP_REQUEST_URL_PREFIX + config.hostname;

updateStatus(ThingStatus.UNKNOWN);
scheduler.schedule(this::initializeInternal, 0, TimeUnit.SECONDS);
}

@Override
public final void dispose() {
if (pollingJob != null) {
Fredo70 marked this conversation as resolved.
Show resolved Hide resolved
pollingJob.cancel(true);
pollingJob = null;
Fredo70 marked this conversation as resolved.
Show resolved Hide resolved
}
super.dispose();
}

@Override
public final Collection<Class<? extends ThingHandlerService>> getServices() {
return Collections.singleton(MyStromDeviceActions.class);
Fredo70 marked this conversation as resolved.
Show resolved Hide resolved
}

public final void updateProperties() throws MyStromException {
@Nullable
Fredo70 marked this conversation as resolved.
Show resolved Hide resolved
MyStromDeviceInfo deviceInfo = getDeviceInfo();
if (deviceInfo == null) {
throw new MyStromException("Cannot retrieve device info from myStrom device " + getThing().getUID());
}
this.mac = deviceInfo.mac;
Map<String, String> properties = editProperties();
properties.put(PROPERTY_MAC, deviceInfo.mac);
properties.put(PROPERTY_VERSION, deviceInfo.version);
properties.put(PROPERTY_TYPE, Long.toString(deviceInfo.type));
properties.put(PROPERTY_SSID, deviceInfo.ssid);
properties.put(PROPERTY_IP, deviceInfo.ip);
properties.put(PROPERTY_MASK, deviceInfo.mask);
properties.put(PROPERTY_GW, deviceInfo.gw);
properties.put(PROPERTY_DNS, deviceInfo.dns);
properties.put(PROPERTY_STATIC, Boolean.toString(deviceInfo.staticState));
properties.put(PROPERTY_CONNECTED, Boolean.toString(deviceInfo.connected));
Calendar calendar = Calendar.getInstance();
DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, Locale.getDefault());
properties.put(PROPERTY_LAST_REFRESH, formatter.format(calendar.getTime()));
updateProperties(properties);
}

private @Nullable MyStromDeviceInfo getDeviceInfo() throws MyStromException {
String url = hostname + "/api/v1/info";
ContentResponse response;
try {
Request request = httpClient.newRequest(url).timeout(10, TimeUnit.SECONDS).method(HttpMethod.GET);
response = request.send();
} catch (InterruptedException | TimeoutException | ExecutionException e) {
throw new MyStromException(COMMUNICATION_ERROR + e.getMessage());
}

if (response.getStatus() != HTTP_OK_CODE) {
throw new MyStromException(
"Error sending HTTP GET request to " + url + ". Got response code: " + response.getStatus());
}

String gs = response.getContentAsString();
if (gs == null) {
return null;
}
J-N-K marked this conversation as resolved.
Show resolved Hide resolved
return gson.fromJson(gs, MyStromDeviceInfo.class);
}

private void initializeInternal() {
try {
updateProperties();
updateStatus(ThingStatus.ONLINE);
MyStromConfiguration config = getConfigAs(MyStromConfiguration.class);
pollingJob = scheduler.scheduleWithFixedDelay(this::pollDevice, 0, config.refresh, TimeUnit.SECONDS);
} catch (MyStromException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
}
}

protected final HttpClient getHttpClient() {
return httpClient;
}

protected final String getHostname() {
return hostname;
}

protected final String getMac() {
return mac;
}

protected final Gson getGson() {
return gson;
}
Fredo70 marked this conversation as resolved.
Show resolved Hide resolved

protected abstract void pollDevice();
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
* used across the whole binding.
*
* @author Paul Frank - Initial contribution
* @author Frederic Chastagnol - Add constants for myStrom bulb support
*/
@NonNullByDefault
public class MyStromBindingConstants {
Expand All @@ -30,9 +31,36 @@ public class MyStromBindingConstants {

// 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");

// List of all Channel ids
public static final String CHANNEL_SWITCH = "switch";
public static final String CHANNEL_POWER = "power";
public static final String CHANNEL_TEMPERATURE = "temperature";
public static final String CHANNEL_COLOR = "color";
public static final String CHANNEL_RAMP = "ramp";
public static final String CHANNEL_MODE = "mode";
public static final String CHANNEL_COLOR_TEMPERATURE = "colorTemperature";
public static final String CHANNEL_BRIGHTNESS = "brightness";

// Config
public static final String CONFIG_MAC = "mac";

// List of all Properties
public static final String PROPERTY_MAC = "mac";
public static final String PROPERTY_VERSION = "version";
public static final String PROPERTY_TYPE = "type";
public static final String PROPERTY_SSID = "ssid";
public static final String PROPERTY_IP = "ip";
public static final String PROPERTY_MASK = "mask";
public static final String PROPERTY_GW = "gw";
public static final String PROPERTY_DNS = "dns";
public static final String PROPERTY_STATIC = "static";
public static final String PROPERTY_CONNECTED = "connected";
public static final String PROPERTY_LAST_REFRESH = "lastRefresh";

// myStrom Bulb modes
public static final String RGB = "rgb";
public static final String HSV = "hsv";
public static final String MONO = "mono";
}
Loading