added migrated 2.x add-ons

Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
Kai Kreuzer
2020-09-21 01:58:32 +02:00
parent bbf1a7fd29
commit 6df6783b60
11662 changed files with 1302875 additions and 11 deletions

View File

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="target/generated-sources/annotations">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="m2e-apt" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="m2e-apt" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.openhab.binding.somfymylink</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,13 @@
This content is produced and maintained by the openHAB project.
* Project home: https://www.openhab.org
== Declared Project Licenses
This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.
== Source Code
https://github.com/openhab/openhab2-addons

View File

@@ -0,0 +1,65 @@
# Somfy myLink Binding
This binding supports the [Somfy myLink](https://www.somfysystems.com/en-us/products/1811403/mylink-) device for control of Somfy RTS blinds/shades.
## Supported Things
Currently these things are supported:
- bridge (Somfy MyLink bridge, which can discover roller shades and scenes)
- roller shades (UP, DOWN, STOP control of a roller shade).
This binding has been tested with myLink firmware 5.23.
## Discovery
To start a discovery:
- install this binding
- open Paper UI
- add a new thing in menu Configuration/Things
- choose SomfyMyLink Binding and select Somfy MyLink Bridge
- enter it's IP Address and system id. The system id This can be found in the integration settings -> Control4 section of your My Link app
If the supplied ip address and system id are correct, the automatic discovery starts immediately and detected roller shades appear in Paper UI inbox.
## Thing Configuration
### mylink
| Parameter | Parameter ID | Required/Optional | Description |
|------------------|-------------------|-------------------|-------------|
| IP or Hostname | ipAddress | Required | Hostname or IP Address of the myLink device |
| System Id | systemId | Required | The system id configured on the myLink device |
### shade
| Parameter | Parameter ID | Required/Optional | Description |
|------------------|-------------------|-------------------|-------------|
| Target ID | targetId | Required | Address of shade in the Somfy system |
### scene
| Parameter | Parameter ID | Required/Optional | Description |
|------------------|-------------------|-------------------|-------------|
| Scene ID | sceneId | Required | Address of scene in the Somfy system |
## Channels
The following channels are supported by the binding. Note that specific weather station models may support only some or all of these channels.
| Channel ID | Item Type | Description |
|---------------------------------|-------------------------|---------------------------------------------------------------|
| shadeControl | Rollershutter | Device control (UP, DOWN, STOP) |
| scenelist | String | Comma-separated list of scenes of form sceneId=sceneName |
| button | Switch | Button to trigger a scene or rule |
## Example
### Things
```
Bridge somfymylink:mylink:mylink1 "myLink Bridge" @ "Office" [ ipAddress="192.168.1.1", systemId="mysystemidhere" ] {
Thing shade shade1 "Living Room" [ targetId="CC114A21.1" ]
}
```

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
<version>3.0.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.binding.somfymylink</artifactId>
<name>openHAB Add-ons :: Bundles :: Somfy MyLink Binding</name>
</project>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.somfymylink-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
<feature name="openhab-binding-somfymylink" description="Somfy MyLink Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.somfymylink/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,39 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfyMyLinkBindingConstants {
private static final String BINDING_ID = "somfymylink";
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_SHADE = new ThingTypeUID(BINDING_ID, "shade");
public static final ThingTypeUID THING_TYPE_SCENE = new ThingTypeUID(BINDING_ID, "scene");
public static final ThingTypeUID THING_TYPE_MYLINK = new ThingTypeUID(BINDING_ID, "mylink");
// List of all Channel ids
public static final String CHANNEL_SHADELEVEL = "shadelevel";
public static final String CHANNEL_SCENECONTROL = "scenecontrol";
public static final String CHANNEL_SCENES = "sceneid";
// Thing config properties
public static final String TARGET_ID = "targetId";
public static final String SCENE_ID = "sceneId";
}

View File

@@ -0,0 +1,81 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal;
import static org.openhab.binding.somfymylink.internal.SomfyMyLinkBindingConstants.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.somfymylink.internal.handler.SomfyMyLinkBridgeHandler;
import org.openhab.binding.somfymylink.internal.handler.SomfyMyLinkStateDescriptionOptionsProvider;
import org.openhab.binding.somfymylink.internal.handler.SomfySceneHandler;
import org.openhab.binding.somfymylink.internal.handler.SomfyShadeHandler;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
/**
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
@Component(configurationPid = "binding.somfymylink", service = ThingHandlerFactory.class)
public class SomfyMyLinkHandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = new HashSet<>(
Arrays.asList(THING_TYPE_MYLINK, THING_TYPE_SHADE, THING_TYPE_SCENE));
public static final Set<ThingTypeUID> DISCOVERABLE_DEVICE_TYPES_UIDS = new HashSet<>(
Arrays.asList(THING_TYPE_SHADE, THING_TYPE_SCENE));
private @Nullable SomfyMyLinkStateDescriptionOptionsProvider stateDescriptionProvider;
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (thingTypeUID.equals(THING_TYPE_MYLINK)) {
return new SomfyMyLinkBridgeHandler((Bridge) thing, stateDescriptionProvider);
}
if (THING_TYPE_SHADE.equals(thingTypeUID)) {
return new SomfyShadeHandler(thing);
}
if (THING_TYPE_SCENE.equals(thingTypeUID)) {
return new SomfySceneHandler(thing);
}
return null;
}
@Reference
protected void setDynamicStateDescriptionProvider(SomfyMyLinkStateDescriptionOptionsProvider provider) {
this.stateDescriptionProvider = provider;
}
protected void unsetDynamicStateDescriptionProvider(SomfyMyLinkStateDescriptionOptionsProvider provider) {
this.stateDescriptionProvider = null;
}
}

View File

@@ -0,0 +1,27 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link SomfyMyLinkConfiguration} class contains fields mapping thing configuration parameters.
*
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfyMyLinkConfiguration {
public String ipAddress = "";
public String systemId = "";
}

View File

@@ -0,0 +1,190 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.discovery;
import static org.openhab.binding.somfymylink.internal.SomfyMyLinkBindingConstants.*;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.somfymylink.internal.SomfyMyLinkHandlerFactory;
import org.openhab.binding.somfymylink.internal.handler.SomfyMyLinkBridgeHandler;
import org.openhab.binding.somfymylink.internal.handler.SomfyMyLinkException;
import org.openhab.binding.somfymylink.internal.model.SomfyMyLinkScene;
import org.openhab.binding.somfymylink.internal.model.SomfyMyLinkShade;
import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.config.discovery.ScanListener;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Deactivate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link SomfyMyLinkDeviceDiscoveryService} is responsible discovering things connected to the mylink.
*
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfyMyLinkDeviceDiscoveryService extends AbstractDiscoveryService
implements DiscoveryService, ThingHandlerService {
private static final int DISCOVERY_REFRESH_SEC = 900;
private final Logger logger = LoggerFactory.getLogger(SomfyMyLinkDeviceDiscoveryService.class);
private @NonNullByDefault({}) SomfyMyLinkBridgeHandler mylinkHandler;
private @Nullable Future<?> scanTask;
private @Nullable ScheduledFuture<?> discoveryJob;
public SomfyMyLinkDeviceDiscoveryService() {
super(SomfyMyLinkHandlerFactory.DISCOVERABLE_DEVICE_TYPES_UIDS, 10);
}
@Override
public void setThingHandler(@Nullable ThingHandler handler) {
if (handler instanceof SomfyMyLinkBridgeHandler) {
this.mylinkHandler = (SomfyMyLinkBridgeHandler) handler;
}
}
@Override
public @Nullable ThingHandler getThingHandler() {
return mylinkHandler;
}
@Override
@Activate
public void activate() {
super.activate(null);
}
@Override
@Deactivate
public void deactivate() {
super.deactivate();
}
@Override
protected void startBackgroundDiscovery() {
logger.debug("Starting Somfy My Link background discovery");
ScheduledFuture<?> discoveryJob = this.discoveryJob;
if (discoveryJob == null || discoveryJob.isCancelled()) {
discoveryJob = scheduler.scheduleWithFixedDelay(this::discoverDevices, 10, DISCOVERY_REFRESH_SEC,
TimeUnit.SECONDS);
}
}
@Override
protected void stopBackgroundDiscovery() {
logger.debug("Stopping Somfy MyLink background discovery");
ScheduledFuture<?> discoveryJob = this.discoveryJob;
if (discoveryJob != null) {
discoveryJob.cancel(true);
this.discoveryJob = null;
}
}
@Override
protected synchronized void startScan() {
Future<?> scanTask = this.scanTask;
if (scanTask == null || scanTask.isDone()) {
logger.debug("Starting somfy mylink discovery scan");
scanTask = scheduler.submit(this::discoverDevices);
}
}
@Override
public void stopScan() {
Future<?> scanTask = this.scanTask;
if (scanTask != null) {
logger.debug("Stopping somfy mylink discovery scan");
scanTask.cancel(true);
}
super.stopScan();
}
private synchronized void discoverDevices() {
logger.info("Scanning for things...");
if (this.mylinkHandler.getThing().getStatus() != ThingStatus.ONLINE) {
logger.info("Skipping device discover as bridge is {}", this.mylinkHandler.getThing().getStatus());
return;
}
try {
// get the shade list
SomfyMyLinkShade[] shades = this.mylinkHandler.getShadeList();
for (SomfyMyLinkShade shade : shades) {
String id = shade.getTargetID();
String label = "Somfy Shade " + shade.getName();
if (id != null) {
logger.debug("Adding device {}", id);
notifyThingDiscovery(THING_TYPE_SHADE, id, label, TARGET_ID);
}
}
SomfyMyLinkScene[] scenes = this.mylinkHandler.getSceneList();
for (SomfyMyLinkScene scene : scenes) {
String id = scene.getTargetID();
String label = "Somfy Scene " + scene.getName();
logger.debug("Adding device {}", id);
notifyThingDiscovery(THING_TYPE_SCENE, id, label, SCENE_ID);
}
} catch (SomfyMyLinkException e) {
logger.warn("Error scanning for devices: {}", e.getMessage(), e);
ScanListener scanListener = this.scanListener;
if (scanListener != null) {
scanListener.onErrorOccurred(e);
}
}
}
private void notifyThingDiscovery(ThingTypeUID thingTypeUID, String id, String label, String idType) {
if (id.isEmpty()) {
logger.info("Discovered {} with no ID", label);
return;
}
ThingUID bridgeUID = this.mylinkHandler.getThing().getUID();
ThingUID uid = new ThingUID(thingTypeUID, bridgeUID, id);
Map<String, Object> properties = new HashMap<>();
properties.put(idType, id);
DiscoveryResult result = DiscoveryResultBuilder.create(uid).withBridge(bridgeUID).withLabel(label)
.withProperties(properties).withRepresentationProperty(idType).build();
thingDiscovered(result);
logger.debug("Discovered {}", uid);
}
}

View File

@@ -0,0 +1,387 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.handler;
import static org.openhab.binding.somfymylink.internal.SomfyMyLinkBindingConstants.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.somfymylink.internal.SomfyMyLinkBindingConstants;
import org.openhab.binding.somfymylink.internal.config.SomfyMyLinkConfiguration;
import org.openhab.binding.somfymylink.internal.discovery.SomfyMyLinkDeviceDiscoveryService;
import org.openhab.binding.somfymylink.internal.model.SomfyMyLinkCommandBase;
import org.openhab.binding.somfymylink.internal.model.SomfyMyLinkCommandSceneList;
import org.openhab.binding.somfymylink.internal.model.SomfyMyLinkCommandSceneSet;
import org.openhab.binding.somfymylink.internal.model.SomfyMyLinkCommandShadeDown;
import org.openhab.binding.somfymylink.internal.model.SomfyMyLinkCommandShadeList;
import org.openhab.binding.somfymylink.internal.model.SomfyMyLinkCommandShadePing;
import org.openhab.binding.somfymylink.internal.model.SomfyMyLinkCommandShadeStop;
import org.openhab.binding.somfymylink.internal.model.SomfyMyLinkCommandShadeUp;
import org.openhab.binding.somfymylink.internal.model.SomfyMyLinkErrorResponse;
import org.openhab.binding.somfymylink.internal.model.SomfyMyLinkPingResponse;
import org.openhab.binding.somfymylink.internal.model.SomfyMyLinkResponseBase;
import org.openhab.binding.somfymylink.internal.model.SomfyMyLinkScene;
import org.openhab.binding.somfymylink.internal.model.SomfyMyLinkScenesResponse;
import org.openhab.binding.somfymylink.internal.model.SomfyMyLinkShade;
import org.openhab.binding.somfymylink.internal.model.SomfyMyLinkShadesResponse;
import org.openhab.core.common.NamedThreadFactory;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.Bridge;
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.thing.binding.BaseBridgeHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.types.StateOption;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
/**
* The {@link SomfyMyLinkBridgeHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfyMyLinkBridgeHandler extends BaseBridgeHandler {
private final Logger logger = LoggerFactory.getLogger(SomfyMyLinkBridgeHandler.class);
private static final int HEARTBEAT_MINUTES = 2;
private static final int MYLINK_PORT = 44100;
private static final int MYLINK_DEFAULT_TIMEOUT = 5000;
private static final int CONNECTION_DELAY = 1000;
private static final SomfyMyLinkShade[] EMPTY_SHADE_LIST = new SomfyMyLinkShade[0];
private static final SomfyMyLinkScene[] EMPTY_SCENE_LIST = new SomfyMyLinkScene[0];
private SomfyMyLinkConfiguration config = new SomfyMyLinkConfiguration();
private @Nullable ScheduledFuture<?> heartbeat;
private @Nullable SomfyMyLinkStateDescriptionOptionsProvider stateDescriptionProvider;
private @Nullable ExecutorService commandExecutor;
// Gson & parser
private final Gson gson = new Gson();
public SomfyMyLinkBridgeHandler(Bridge bridge,
@Nullable SomfyMyLinkStateDescriptionOptionsProvider stateDescriptionProvider) {
super(bridge);
this.stateDescriptionProvider = stateDescriptionProvider;
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
logger.debug("Command received on mylink {}", command);
try {
if (CHANNEL_SCENES.equals(channelUID.getId())) {
if (command instanceof RefreshType) {
return;
}
if (command instanceof StringType) {
Integer sceneId = Integer.decode(command.toString());
commandScene(sceneId);
}
}
} catch (SomfyMyLinkException e) {
logger.info("Error handling command: {}", e.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
}
}
@Override
public void initialize() {
logger.info("Initializing mylink");
config = getThing().getConfiguration().as(SomfyMyLinkConfiguration.class);
commandExecutor = Executors.newSingleThreadExecutor(new NamedThreadFactory(thing.getUID().getAsString(), true));
if (validConfiguration(config)) {
// start the keepalive process
if (heartbeat == null) {
logger.info("Starting heartbeat job every {} min", HEARTBEAT_MINUTES);
heartbeat = this.scheduler.scheduleWithFixedDelay(this::sendHeartbeat, 0, HEARTBEAT_MINUTES,
TimeUnit.MINUTES);
}
}
}
@Override
public Collection<Class<? extends ThingHandlerService>> getServices() {
return Collections.singleton(SomfyMyLinkDeviceDiscoveryService.class);
}
private boolean validConfiguration(@Nullable SomfyMyLinkConfiguration config) {
if (config == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "mylink configuration missing");
return false;
}
if (config.ipAddress.isEmpty() || config.systemId.isEmpty()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"mylink address or system id not specified");
return false;
}
return true;
}
private void cancelHeartbeat() {
logger.debug("Stopping heartbeat");
ScheduledFuture<?> heartbeat = this.heartbeat;
if (heartbeat != null) {
logger.debug("Cancelling heartbeat job");
heartbeat.cancel(true);
this.heartbeat = null;
} else {
logger.debug("Heartbeat was not active");
}
}
private void sendHeartbeat() {
try {
logger.debug("Sending heartbeat");
SomfyMyLinkCommandShadePing command = new SomfyMyLinkCommandShadePing(config.systemId);
sendCommandWithResponse(command, SomfyMyLinkPingResponse.class).get();
updateStatus(ThingStatus.ONLINE);
} catch (SomfyMyLinkException | InterruptedException | ExecutionException e) {
logger.warn("Problem with mylink during heartbeat: {}", e.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
}
}
public SomfyMyLinkShade[] getShadeList() throws SomfyMyLinkException {
SomfyMyLinkCommandShadeList command = new SomfyMyLinkCommandShadeList(config.systemId);
try {
SomfyMyLinkShadesResponse response = sendCommandWithResponse(command, SomfyMyLinkShadesResponse.class)
.get();
if (response != null) {
return response.getResult();
} else {
return EMPTY_SHADE_LIST;
}
} catch (InterruptedException | ExecutionException e) {
throw new SomfyMyLinkException("Problem while getting shade list.", e);
}
}
public SomfyMyLinkScene[] getSceneList() throws SomfyMyLinkException {
SomfyMyLinkCommandSceneList command = new SomfyMyLinkCommandSceneList(config.systemId);
SomfyMyLinkStateDescriptionOptionsProvider stateDescriptionProvider = this.stateDescriptionProvider;
try {
SomfyMyLinkScenesResponse response = sendCommandWithResponse(command, SomfyMyLinkScenesResponse.class)
.get();
if (response != null && stateDescriptionProvider != null) {
List<StateOption> options = new ArrayList<>();
for (SomfyMyLinkScene scene : response.result) {
options.add(new StateOption(scene.getTargetID(), scene.getName()));
}
logger.debug("Setting {} options on bridge", options.size());
stateDescriptionProvider.setStateOptions(
new ChannelUID(getThing().getUID(), SomfyMyLinkBindingConstants.CHANNEL_SCENES), options);
return response.getResult();
} else {
return EMPTY_SCENE_LIST;
}
} catch (InterruptedException | ExecutionException e) {
throw new SomfyMyLinkException("Problem getting scene list.", e);
}
}
public void commandShadeUp(String targetId) throws SomfyMyLinkException {
SomfyMyLinkCommandShadeUp cmd = new SomfyMyLinkCommandShadeUp(targetId, config.systemId);
sendCommand(cmd);
}
public void commandShadeDown(String targetId) throws SomfyMyLinkException {
SomfyMyLinkCommandShadeDown cmd = new SomfyMyLinkCommandShadeDown(targetId, config.systemId);
sendCommand(cmd);
}
public void commandShadeStop(String targetId) throws SomfyMyLinkException {
SomfyMyLinkCommandShadeStop cmd = new SomfyMyLinkCommandShadeStop(targetId, config.systemId);
sendCommand(cmd);
}
public void commandScene(Integer sceneId) throws SomfyMyLinkException {
SomfyMyLinkCommandSceneSet cmd = new SomfyMyLinkCommandSceneSet(sceneId, config.systemId);
sendCommand(cmd);
}
private CompletableFuture<@Nullable Void> sendCommand(SomfyMyLinkCommandBase command) {
CompletableFuture<@Nullable Void> future = new CompletableFuture<>();
ExecutorService commandExecutor = this.commandExecutor;
if (commandExecutor != null) {
commandExecutor.execute(() -> {
String json = gson.toJson(command);
try (Socket socket = getConnection();
Writer out = new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.US_ASCII)) {
logger.debug("Sending: {}", json);
out.write(json);
out.flush();
logger.debug("Sent: {}", json);
// give time for mylink to process
Thread.sleep(CONNECTION_DELAY);
} catch (SocketTimeoutException e) {
logger.warn("Timeout sending command to mylink: {} Message: {}", json, e.getMessage());
} catch (IOException e) {
logger.warn("Problem sending command to mylink: {} Message: {}", json, e.getMessage());
} catch (InterruptedException e) {
logger.warn("Interrupted while waiting after sending command to mylink: {} Message: {}", json,
e.getMessage());
} catch (Exception e) {
logger.warn("Unexpected exception while sending command to mylink: {} Message: {}", json,
e.getMessage());
}
future.complete(null);
});
} else {
future.complete(null);
}
return future;
}
private <T extends SomfyMyLinkResponseBase> CompletableFuture<@Nullable T> sendCommandWithResponse(
SomfyMyLinkCommandBase command, Class<T> responseType) {
CompletableFuture<@Nullable T> future = new CompletableFuture<>();
ExecutorService commandExecutor = this.commandExecutor;
if (commandExecutor != null) {
commandExecutor.submit(() -> {
String json = gson.toJson(command);
try (Socket socket = getConnection();
Writer out = new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.US_ASCII);
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream(), StandardCharsets.US_ASCII))) {
// send the command
logger.debug("Sending: {}", json);
out.write(json);
out.flush();
// read the response
try {
T response = parseResponse(in, responseType);
future.complete(response);
Thread.sleep(CONNECTION_DELAY);
return;
} catch (SomfyMyLinkException e) {
future.completeExceptionally(e);
return;
}
} catch (SocketTimeoutException e) {
logger.warn("Timeout sending command to mylink: {} Message: {}", json, e.getMessage());
future.completeExceptionally(new SomfyMyLinkException("Timeout sending command to mylink", e));
} catch (IOException e) {
logger.warn("Problem sending command to mylink: {} Message: {}", json, e.getMessage());
future.completeExceptionally(new SomfyMyLinkException("Problem sending command to mylink", e));
} catch (InterruptedException e) {
logger.warn("Interrupted while waiting after sending command to mylink: {} Message: {}", json,
e.getMessage());
future.complete(null);
} catch (Exception e) {
logger.warn("Unexpected exception while sending command to mylink: {} Message: {}", json,
e.getMessage());
future.completeExceptionally(e);
}
});
} else {
future.complete(null);
}
return future;
}
private <T extends SomfyMyLinkResponseBase> T parseResponse(Reader reader, Class<T> responseType) {
JsonParser parser = new JsonParser();
JsonObject jsonObj = parser.parse(gson.newJsonReader(reader)).getAsJsonObject();
logger.debug("Got full message: {}", jsonObj.toString());
if (jsonObj.has("error")) {
SomfyMyLinkErrorResponse errorResponse = gson.fromJson(jsonObj, SomfyMyLinkErrorResponse.class);
logger.info("Error parsing mylink response: {}", errorResponse.error.message);
throw new SomfyMyLinkException("Incomplete message.");
}
return gson.fromJson(jsonObj, responseType);
}
private Socket getConnection() throws IOException, SomfyMyLinkException {
try {
logger.debug("Getting connection to mylink on: {} Post: {}", config.ipAddress, MYLINK_PORT);
String myLinkAddress = config.ipAddress;
Socket socket = new Socket(myLinkAddress, MYLINK_PORT);
socket.setSoTimeout(MYLINK_DEFAULT_TIMEOUT);
return socket;
} catch (IOException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
throw e;
}
}
@Override
public void thingUpdated(Thing thing) {
SomfyMyLinkConfiguration newConfig = thing.getConfiguration().as(SomfyMyLinkConfiguration.class);
config = newConfig;
}
@Override
public void dispose() {
cancelHeartbeat();
dispose(commandExecutor);
}
private static void dispose(@Nullable ExecutorService executor) {
if (executor != null) {
executor.shutdownNow();
}
}
}

View File

@@ -0,0 +1,42 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link SomfyMyLinkException} is for throwing errors from the mylink binding
*
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfyMyLinkException extends RuntimeException {
private static final long serialVersionUID = 1L;
public SomfyMyLinkException() {
super();
}
public SomfyMyLinkException(String message) {
super(message);
}
public SomfyMyLinkException(String message, Throwable cause) {
super(message, cause);
}
public SomfyMyLinkException(Throwable cause) {
super(cause);
}
}

View File

@@ -0,0 +1,42 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.binding.BaseDynamicStateDescriptionProvider;
import org.openhab.core.thing.i18n.ChannelTypeI18nLocalizationService;
import org.openhab.core.thing.type.DynamicStateDescriptionProvider;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
/**
* Dynamic provider of state options while leaving other state description fields as original.
*
* @author Gregory Moyer - Initial contribution
* @author Mark Hilbush - Adapted to squeezebox binding
*/
@Component(service = { DynamicStateDescriptionProvider.class, SomfyMyLinkStateDescriptionOptionsProvider.class })
@NonNullByDefault
public class SomfyMyLinkStateDescriptionOptionsProvider extends BaseDynamicStateDescriptionProvider {
@Reference
protected void setChannelTypeI18nLocalizationService(
final ChannelTypeI18nLocalizationService channelTypeI18nLocalizationService) {
this.channelTypeI18nLocalizationService = channelTypeI18nLocalizationService;
}
protected void unsetChannelTypeI18nLocalizationService(
final ChannelTypeI18nLocalizationService channelTypeI18nLocalizationService) {
this.channelTypeI18nLocalizationService = null;
}
}

View File

@@ -0,0 +1,79 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.handler;
import static org.openhab.binding.somfymylink.internal.SomfyMyLinkBindingConstants.CHANNEL_SCENECONTROL;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.Bridge;
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.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.BridgeHandler;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link SomfySceneHandler} is responsible for handling commands for scenes
*
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfySceneHandler extends BaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(SomfySceneHandler.class);
public SomfySceneHandler(Thing thing) {
super(thing);
}
@Override
public void initialize() {
updateStatus(ThingStatus.ONLINE);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
try {
if (CHANNEL_SCENECONTROL.equals(channelUID.getId()) && command instanceof OnOffType) {
Integer targetId = Integer.decode(channelUID.getThingUID().getId());
if (command.equals(OnOffType.ON)) {
getBridgeHandler().commandScene(targetId);
updateState(channelUID, OnOffType.OFF);
}
}
} catch (SomfyMyLinkException e) {
logger.warn("Error handling command: {}", e.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
}
}
protected SomfyMyLinkBridgeHandler getBridgeHandler() {
Bridge bridge = this.getBridge();
if (bridge == null) {
throw new SomfyMyLinkException("No bridge was found");
}
BridgeHandler handler = bridge.getHandler();
if (handler == null) {
throw new SomfyMyLinkException("No handler was found");
}
return (SomfyMyLinkBridgeHandler) handler;
}
}

View File

@@ -0,0 +1,117 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.handler;
import static org.openhab.binding.somfymylink.internal.SomfyMyLinkBindingConstants.CHANNEL_SHADELEVEL;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.library.types.StopMoveType;
import org.openhab.core.library.types.UpDownType;
import org.openhab.core.thing.Bridge;
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.thing.ThingStatusInfo;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.BridgeHandler;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link SomfyShadeHandler} is responsible for handling commands for shades
*
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfyShadeHandler extends BaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(SomfyShadeHandler.class);
public SomfyShadeHandler(Thing thing) {
super(thing);
}
@Override
public void initialize() {
initDeviceState();
}
@Override
public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
logger.info("Bridge status changed to {} updating {}", bridgeStatusInfo.getStatus(), getThing().getLabel());
if (bridgeStatusInfo.getStatus() == ThingStatus.ONLINE
&& getThing().getStatusInfo().getStatusDetail() == ThingStatusDetail.BRIDGE_OFFLINE) {
initDeviceState();
} else if (bridgeStatusInfo.getStatus() == ThingStatus.OFFLINE) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
}
}
public void initDeviceState() {
Bridge bridge = getBridge();
if (bridge == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "No bridge configured");
logger.debug("Initialized device state for shade {} {}", ThingStatus.OFFLINE,
ThingStatusDetail.CONFIGURATION_ERROR);
} else if (bridge.getStatus() == ThingStatus.ONLINE) {
updateStatus(ThingStatus.ONLINE);
logger.debug("Initialized device state for shade {}", ThingStatus.ONLINE);
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
logger.debug("Initialized device state for shade {} {}", ThingStatus.OFFLINE,
ThingStatusDetail.BRIDGE_OFFLINE);
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
try {
if (CHANNEL_SHADELEVEL.equals(channelUID.getId())) {
String targetId = channelUID.getThingUID().getId();
if (command instanceof UpDownType) {
if (command.equals(UpDownType.DOWN)) {
getBridgeHandler().commandShadeDown(targetId);
} else {
getBridgeHandler().commandShadeUp(targetId);
}
}
if (command instanceof StopMoveType) {
getBridgeHandler().commandShadeStop(targetId);
}
}
} catch (SomfyMyLinkException e) {
logger.warn("Error handling command: {}", e.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
}
}
protected SomfyMyLinkBridgeHandler getBridgeHandler() {
Bridge bridge = this.getBridge();
if (bridge == null) {
throw new SomfyMyLinkException("No bridge was found");
}
BridgeHandler handler = bridge.getHandler();
if (handler == null) {
throw new SomfyMyLinkException("No handler was found");
}
return (SomfyMyLinkBridgeHandler) handler;
}
}

View File

@@ -0,0 +1,30 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.model;
import java.util.concurrent.ThreadLocalRandom;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfyMyLinkCommandBase {
public final int id;
public SomfyMyLinkCommandBase() {
this.id = ThreadLocalRandom.current().nextInt(1, 1000);
}
}

View File

@@ -0,0 +1,29 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.model;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfyMyLinkCommandParamsBase {
public final String auth;
public SomfyMyLinkCommandParamsBase(String auth) {
this.auth = auth;
}
}

View File

@@ -0,0 +1,31 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.model;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfyMyLinkCommandSceneBase extends SomfyMyLinkCommandBase {
public final String method;
public final SomfyMyLinkCommandSceneParams params;
public SomfyMyLinkCommandSceneBase(int sceneId, String method, String auth) {
this.method = method;
this.params = new SomfyMyLinkCommandSceneParams(sceneId, auth);
}
}

View File

@@ -0,0 +1,26 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.model;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfyMyLinkCommandSceneList extends SomfyMyLinkCommandShadeBase {
public SomfyMyLinkCommandSceneList(String auth) {
super("*.*", "mylink.scene.list", auth);
}
}

View File

@@ -0,0 +1,30 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.model;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfyMyLinkCommandSceneParams extends SomfyMyLinkCommandParamsBase {
public final int sceneId;
public SomfyMyLinkCommandSceneParams(int sceneId, String auth) {
super(auth);
this.sceneId = sceneId;
}
}

View File

@@ -0,0 +1,26 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.model;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfyMyLinkCommandSceneSet extends SomfyMyLinkCommandSceneBase {
public SomfyMyLinkCommandSceneSet(int sceneId, String auth) {
super(sceneId, "mylink.scene.run", auth);
}
}

View File

@@ -0,0 +1,31 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.model;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfyMyLinkCommandShadeBase extends SomfyMyLinkCommandBase {
public final String method;
public final SomfyMyLinkCommandShadeParams params;
public SomfyMyLinkCommandShadeBase(String targetId, String method, String auth) {
this.method = method;
this.params = new SomfyMyLinkCommandShadeParams(targetId, auth);
}
}

View File

@@ -0,0 +1,27 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.model;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfyMyLinkCommandShadeDown extends SomfyMyLinkCommandShadeBase {
public SomfyMyLinkCommandShadeDown(String targetId, String auth) {
super(targetId, "mylink.move.down", auth);
}
}

View File

@@ -0,0 +1,27 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.model;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfyMyLinkCommandShadeList extends SomfyMyLinkCommandShadeBase {
public SomfyMyLinkCommandShadeList(String auth) {
super("*.*", "mylink.status.info", auth);
}
}

View File

@@ -0,0 +1,30 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.model;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfyMyLinkCommandShadeParams extends SomfyMyLinkCommandParamsBase {
public final String targetId;
public SomfyMyLinkCommandShadeParams(String targetId, String auth) {
super(auth);
this.targetId = targetId.replace('-', '.');
}
}

View File

@@ -0,0 +1,27 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.model;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfyMyLinkCommandShadePing extends SomfyMyLinkCommandShadeBase {
public SomfyMyLinkCommandShadePing(String auth) {
super("*.*", "mylink.status.ping", auth);
}
}

View File

@@ -0,0 +1,27 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.model;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfyMyLinkCommandShadeStop extends SomfyMyLinkCommandShadeBase {
public SomfyMyLinkCommandShadeStop(String targetId, String auth) {
super(targetId, "mylink.move.stop", auth);
}
}

View File

@@ -0,0 +1,27 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.model;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfyMyLinkCommandShadeUp extends SomfyMyLinkCommandShadeBase {
public SomfyMyLinkCommandShadeUp(String targetId, String auth) {
super(targetId, "mylink.move.up", auth);
}
}

View File

@@ -0,0 +1,26 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.model;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfyMyLinkError {
public String code = "";
public String message = "";
}

View File

@@ -0,0 +1,29 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.model;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfyMyLinkErrorResponse extends SomfyMyLinkResponseBase {
public SomfyMyLinkError error = new SomfyMyLinkError();
public @Nullable SomfyMyLinkError getError() {
return error;
}
}

View File

@@ -0,0 +1,28 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.model;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfyMyLinkPingResponse extends SomfyMyLinkResponseBase {
public String[] result = new String[0];
public String[] getResult() {
return result;
}
}

View File

@@ -0,0 +1,35 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.model;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfyMyLinkResponseBase {
public @Nullable String jsonrpc;
public @Nullable String id;
public @Nullable String getId() {
return id;
}
public @Nullable String getJsonRpc() {
return jsonrpc;
}
}

View File

@@ -0,0 +1,34 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.model;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfyMyLinkScene {
private String sceneID = "";
private String name = "";
public String getTargetID() {
return sceneID;
}
public String getName() {
return name;
}
}

View File

@@ -0,0 +1,28 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.model;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfyMyLinkScenesResponse extends SomfyMyLinkResponseBase {
public SomfyMyLinkScene[] result = new SomfyMyLinkScene[0];
public SomfyMyLinkScene[] getResult() {
return result;
}
}

View File

@@ -0,0 +1,36 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.model;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfyMyLinkShade {
private @Nullable String targetID;
private @Nullable String name;
public @Nullable String getTargetID() {
String targetID = this.targetID;
return targetID != null ? targetID.replace('.', '-') : null;
}
public @Nullable String getName() {
return name;
}
}

View File

@@ -0,0 +1,28 @@
/**
* Copyright (c) 2010-2020 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.somfymylink.internal.model;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* @author Chris Johnson - Initial contribution
*/
@NonNullByDefault
public class SomfyMyLinkShadesResponse extends SomfyMyLinkResponseBase {
public SomfyMyLinkShade[] result = new SomfyMyLinkShade[0];
public SomfyMyLinkShade[] getResult() {
return result;
}
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="somfymylink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
<name>Somfy MyLink Binding</name>
<description>This is the binding for Somfy MyLink.</description>
<author>Chris Johnson</author>
</binding:binding>

View File

@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="somfymylink"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<!-- Bridge -->
<bridge-type id="mylink">
<label>Somfy MyLink</label>
<description>Somfy MyLink bridge enabling communication with Somfy devices</description>
<channels>
<channel id="sceneid" typeId="scenelist"/>
</channels>
<config-description>
<parameter name="ipAddress" type="text" required="true">
<context>network-address</context>
<label>IP or Hostname</label>
<description>The IP or hostname of the Somfy MyLink</description>
</parameter>
<parameter name="systemId" type="text">
<label>System Id</label>
<description>The system id of the My Link bridge. This can be found in the integration settings on your My Link app</description>
</parameter>
</config-description>
</bridge-type>
<!-- Scene Type -->
<thing-type id="scene">
<supported-bridge-type-refs>
<bridge-type-ref id="mylink"/>
</supported-bridge-type-refs>
<label>Somfy Scene</label>
<description>Scene control</description>
<channels>
<channel id="scenecontrol" typeId="button"/>
</channels>
<config-description>
<parameter name="sceneId" type="text" required="true">
<label>Scene ID</label>
<description>Address of scene in the Somfy system</description>
</parameter>
</config-description>
</thing-type>
<!-- Shade Type -->
<thing-type id="shade">
<supported-bridge-type-refs>
<bridge-type-ref id="mylink"/>
</supported-bridge-type-refs>
<label>Somfy Shade</label>
<description>Controls shades</description>
<channels>
<channel id="shadelevel" typeId="shadeControl"/>
</channels>
<config-description>
<parameter name="targetId" type="text" required="true">
<label>Target ID</label>
<description>Address of shade in the Somfy system</description>
</parameter>
</config-description>
</thing-type>
<channel-type id="scenelist">
<item-type>String</item-type>
<label>Scene List</label>
<description>Comma-separated list of scenes of form sceneId=sceneName</description>
<state pattern="%s"></state>
</channel-type>
<channel-type id="shadeControl">
<item-type>Rollershutter</item-type>
<label>Control</label>
<description>Device control (UP, DOWN, MY/STOP, closure 0-100%)</description>
</channel-type>
<channel-type id="button">
<item-type>Switch</item-type>
<label>Scene button</label>
<description>Button to trigger a scene or rule</description>
<category>Switch</category>
</channel-type>
</thing:thing-descriptions>