diff --git a/CODEOWNERS b/CODEOWNERS
index 41b26932599a9..bc976170a2733 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -183,6 +183,7 @@
/bundles/org.openhab.binding.snmp/ @J-N-K
/bundles/org.openhab.binding.solaredge/ @alexf2015
/bundles/org.openhab.binding.solarlog/ @johannrichard
+/bundles/org.openhab.binding.somfymylink/ @loungeflyz
/bundles/org.openhab.binding.somfytahoma/ @octa22
/bundles/org.openhab.binding.sonos/ @kgoderis @lolodomo
/bundles/org.openhab.binding.sonyaudio/ @freke
diff --git a/bundles/org.openhab.binding.somfymylink/.classpath b/bundles/org.openhab.binding.somfymylink/.classpath
new file mode 100644
index 0000000000000..39abf1c5e9102
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/.classpath
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bundles/org.openhab.binding.somfymylink/.project b/bundles/org.openhab.binding.somfymylink/.project
new file mode 100644
index 0000000000000..104819095ccf0
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/.project
@@ -0,0 +1,23 @@
+
+
+ org.openhab.binding.somfymylink
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ org.eclipse.m2e.core.maven2Nature
+
+
diff --git a/bundles/org.openhab.binding.somfymylink/NOTICE b/bundles/org.openhab.binding.somfymylink/NOTICE
new file mode 100644
index 0000000000000..4c20ef446c1e4
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/NOTICE
@@ -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
diff --git a/bundles/org.openhab.binding.somfymylink/README.md b/bundles/org.openhab.binding.somfymylink/README.md
new file mode 100644
index 0000000000000..bde3b39634e62
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/README.md
@@ -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" ]
+}
+```
\ No newline at end of file
diff --git a/bundles/org.openhab.binding.somfymylink/pom.xml b/bundles/org.openhab.binding.somfymylink/pom.xml
new file mode 100644
index 0000000000000..fa97d7feeef9c
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/pom.xml
@@ -0,0 +1,17 @@
+
+
+
+ 4.0.0
+
+
+ org.openhab.addons.bundles
+ org.openhab.addons.reactor.bundles
+ 2.5.6-SNAPSHOT
+
+
+ org.openhab.binding.somfymylink
+
+ openHAB Add-ons :: Bundles :: Somfy MyLink Binding
+
+
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/SomfyMyLinkBindingConstants.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/SomfyMyLinkBindingConstants.java
new file mode 100644
index 0000000000000..69ed4b06c4972
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/SomfyMyLinkBindingConstants.java
@@ -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.eclipse.smarthome.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";
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/SomfyMyLinkHandlerFactory.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/SomfyMyLinkHandlerFactory.java
new file mode 100644
index 0000000000000..ff9fbdd6ae631
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/SomfyMyLinkHandlerFactory.java
@@ -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.eclipse.smarthome.core.thing.Bridge;
+import org.eclipse.smarthome.core.thing.Thing;
+import org.eclipse.smarthome.core.thing.ThingTypeUID;
+import org.eclipse.smarthome.core.thing.binding.BaseThingHandlerFactory;
+import org.eclipse.smarthome.core.thing.binding.ThingHandler;
+import org.eclipse.smarthome.core.thing.binding.ThingHandlerFactory;
+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.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 SUPPORTED_THING_TYPES_UIDS = new HashSet<>(
+ Arrays.asList(THING_TYPE_MYLINK, THING_TYPE_SHADE, THING_TYPE_SCENE));
+
+ public static final Set 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;
+ }
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/config/SomfyMyLinkConfiguration.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/config/SomfyMyLinkConfiguration.java
new file mode 100644
index 0000000000000..7ed4569b90967
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/config/SomfyMyLinkConfiguration.java
@@ -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 = "";
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/discovery/SomfyMyLinkDeviceDiscoveryService.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/discovery/SomfyMyLinkDeviceDiscoveryService.java
new file mode 100644
index 0000000000000..f78b1ad8d8d41
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/discovery/SomfyMyLinkDeviceDiscoveryService.java
@@ -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.eclipse.smarthome.config.discovery.AbstractDiscoveryService;
+import org.eclipse.smarthome.config.discovery.DiscoveryResult;
+import org.eclipse.smarthome.config.discovery.DiscoveryResultBuilder;
+import org.eclipse.smarthome.config.discovery.DiscoveryService;
+import org.eclipse.smarthome.config.discovery.ScanListener;
+import org.eclipse.smarthome.core.thing.ThingStatus;
+import org.eclipse.smarthome.core.thing.ThingTypeUID;
+import org.eclipse.smarthome.core.thing.ThingUID;
+import org.eclipse.smarthome.core.thing.binding.ThingHandler;
+import org.eclipse.smarthome.core.thing.binding.ThingHandlerService;
+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.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 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);
+ }
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/handler/SomfyMyLinkBridgeHandler.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/handler/SomfyMyLinkBridgeHandler.java
new file mode 100644
index 0000000000000..ed8b02cb8e9fe
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/handler/SomfyMyLinkBridgeHandler.java
@@ -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.eclipse.smarthome.core.common.NamedThreadFactory;
+import org.eclipse.smarthome.core.library.types.StringType;
+import org.eclipse.smarthome.core.thing.Bridge;
+import org.eclipse.smarthome.core.thing.ChannelUID;
+import org.eclipse.smarthome.core.thing.Thing;
+import org.eclipse.smarthome.core.thing.ThingStatus;
+import org.eclipse.smarthome.core.thing.ThingStatusDetail;
+import org.eclipse.smarthome.core.thing.binding.BaseBridgeHandler;
+import org.eclipse.smarthome.core.thing.binding.ThingHandlerService;
+import org.eclipse.smarthome.core.types.Command;
+import org.eclipse.smarthome.core.types.RefreshType;
+import org.eclipse.smarthome.core.types.StateOption;
+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.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> 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 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 CompletableFuture<@Nullable T> sendCommandWithResponse(
+ SomfyMyLinkCommandBase command, Class 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 parseResponse(Reader reader, Class 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();
+ }
+ }
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/handler/SomfyMyLinkException.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/handler/SomfyMyLinkException.java
new file mode 100644
index 0000000000000..374caf6125932
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/handler/SomfyMyLinkException.java
@@ -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);
+ }
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/handler/SomfyMyLinkStateDescriptionOptionsProvider.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/handler/SomfyMyLinkStateDescriptionOptionsProvider.java
new file mode 100644
index 0000000000000..df736baa7fe3d
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/handler/SomfyMyLinkStateDescriptionOptionsProvider.java
@@ -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.eclipse.smarthome.core.thing.binding.BaseDynamicStateDescriptionProvider;
+import org.eclipse.smarthome.core.thing.i18n.ChannelTypeI18nLocalizationService;
+import org.eclipse.smarthome.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;
+ }
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/handler/SomfySceneHandler.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/handler/SomfySceneHandler.java
new file mode 100644
index 0000000000000..d7f5716a64051
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/handler/SomfySceneHandler.java
@@ -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.eclipse.smarthome.core.library.types.OnOffType;
+import org.eclipse.smarthome.core.thing.Bridge;
+import org.eclipse.smarthome.core.thing.ChannelUID;
+import org.eclipse.smarthome.core.thing.Thing;
+import org.eclipse.smarthome.core.thing.ThingStatus;
+import org.eclipse.smarthome.core.thing.ThingStatusDetail;
+import org.eclipse.smarthome.core.thing.binding.BaseThingHandler;
+import org.eclipse.smarthome.core.thing.binding.BridgeHandler;
+import org.eclipse.smarthome.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;
+ }
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/handler/SomfyShadeHandler.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/handler/SomfyShadeHandler.java
new file mode 100644
index 0000000000000..62c5a664e40fb
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/handler/SomfyShadeHandler.java
@@ -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.eclipse.smarthome.core.library.types.StopMoveType;
+import org.eclipse.smarthome.core.library.types.UpDownType;
+import org.eclipse.smarthome.core.thing.Bridge;
+import org.eclipse.smarthome.core.thing.ChannelUID;
+import org.eclipse.smarthome.core.thing.Thing;
+import org.eclipse.smarthome.core.thing.ThingStatus;
+import org.eclipse.smarthome.core.thing.ThingStatusDetail;
+import org.eclipse.smarthome.core.thing.ThingStatusInfo;
+import org.eclipse.smarthome.core.thing.binding.BaseThingHandler;
+import org.eclipse.smarthome.core.thing.binding.BridgeHandler;
+import org.eclipse.smarthome.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;
+ }
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandBase.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandBase.java
new file mode 100644
index 0000000000000..1c6c8d138b887
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandBase.java
@@ -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);
+ }
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandParamsBase.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandParamsBase.java
new file mode 100644
index 0000000000000..31f45ba4ee0bb
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandParamsBase.java
@@ -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;
+ }
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandSceneBase.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandSceneBase.java
new file mode 100644
index 0000000000000..14a4b70b83be7
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandSceneBase.java
@@ -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);
+ }
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandSceneList.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandSceneList.java
new file mode 100644
index 0000000000000..2c9fd70051765
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandSceneList.java
@@ -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);
+ }
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandSceneParams.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandSceneParams.java
new file mode 100644
index 0000000000000..f8e346a2d529b
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandSceneParams.java
@@ -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;
+ }
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandSceneSet.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandSceneSet.java
new file mode 100644
index 0000000000000..816e89d91d0fd
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandSceneSet.java
@@ -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);
+ }
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandShadeBase.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandShadeBase.java
new file mode 100644
index 0000000000000..69afe9700ac0d
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandShadeBase.java
@@ -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);
+ }
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandShadeDown.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandShadeDown.java
new file mode 100644
index 0000000000000..61d64d0f73632
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandShadeDown.java
@@ -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);
+ }
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandShadeList.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandShadeList.java
new file mode 100644
index 0000000000000..951d4b855f9bd
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandShadeList.java
@@ -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);
+ }
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandShadeParams.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandShadeParams.java
new file mode 100644
index 0000000000000..27719cc321c53
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandShadeParams.java
@@ -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('-', '.');
+ }
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandShadePing.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandShadePing.java
new file mode 100644
index 0000000000000..723fa65ca2df0
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandShadePing.java
@@ -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);
+ }
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandShadeStop.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandShadeStop.java
new file mode 100644
index 0000000000000..d493b2658b17d
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandShadeStop.java
@@ -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);
+ }
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandShadeUp.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandShadeUp.java
new file mode 100644
index 0000000000000..9c45876280d51
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkCommandShadeUp.java
@@ -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);
+ }
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkError.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkError.java
new file mode 100644
index 0000000000000..8e02254cbcaef
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkError.java
@@ -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 = "";
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkErrorResponse.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkErrorResponse.java
new file mode 100644
index 0000000000000..eed7ece48776b
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkErrorResponse.java
@@ -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;
+ }
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkPingResponse.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkPingResponse.java
new file mode 100644
index 0000000000000..5f27584417110
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkPingResponse.java
@@ -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;
+ }
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkResponseBase.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkResponseBase.java
new file mode 100644
index 0000000000000..77e4e1033c13e
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkResponseBase.java
@@ -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;
+ }
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkScene.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkScene.java
new file mode 100644
index 0000000000000..9b8810df9c046
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkScene.java
@@ -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;
+ }
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkScenesResponse.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkScenesResponse.java
new file mode 100644
index 0000000000000..aa716d6f2729d
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkScenesResponse.java
@@ -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;
+ }
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkShade.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkShade.java
new file mode 100644
index 0000000000000..f779faa52ec1f
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkShade.java
@@ -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;
+ }
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkShadesResponse.java b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkShadesResponse.java
new file mode 100644
index 0000000000000..4d62c60a5d241
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/java/org/openhab/binding/somfymylink/internal/model/SomfyMyLinkShadesResponse.java
@@ -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;
+ }
+}
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/resources/ESH-INF/binding/binding.xml b/bundles/org.openhab.binding.somfymylink/src/main/resources/ESH-INF/binding/binding.xml
new file mode 100644
index 0000000000000..32c5789abcf6e
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/resources/ESH-INF/binding/binding.xml
@@ -0,0 +1,10 @@
+
+
+
+ Somfy MyLink Binding
+ This is the binding for Somfy MyLink.
+ Chris Johnson
+
+
diff --git a/bundles/org.openhab.binding.somfymylink/src/main/resources/ESH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.somfymylink/src/main/resources/ESH-INF/thing/thing-types.xml
new file mode 100644
index 0000000000000..6145de863201c
--- /dev/null
+++ b/bundles/org.openhab.binding.somfymylink/src/main/resources/ESH-INF/thing/thing-types.xml
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+ Somfy MyLink bridge enabling communication with Somfy devices
+
+
+
+
+
+ network-address
+
+ The IP or hostname of the Somfy MyLink
+
+
+
+ The system id of the My Link bridge. This can be found in the integration settings on your My Link app
+
+
+
+
+
+
+
+
+
+
+ Scene control
+
+
+
+
+
+
+
+ Address of scene in the Somfy system
+
+
+
+
+
+
+
+
+
+
+ Controls shades
+
+
+
+
+
+
+
+ Address of shade in the Somfy system
+
+
+
+
+
+ String
+
+ Comma-separated list of scenes of form sceneId=sceneName
+
+
+
+
+ Rollershutter
+
+ Device control (UP, DOWN, MY/STOP, closure 0-100%)
+
+
+
+ Switch
+
+ Button to trigger a scene or rule
+ Switch
+
+
+
diff --git a/bundles/pom.xml b/bundles/pom.xml
index 15a93b0d8377c..18eb9219efa96 100644
--- a/bundles/pom.xml
+++ b/bundles/pom.xml
@@ -220,6 +220,7 @@
org.openhab.binding.snmp
org.openhab.binding.solaredge
org.openhab.binding.solarlog
+ org.openhab.binding.somfymylink
org.openhab.binding.somfytahoma
org.openhab.binding.sonos
org.openhab.binding.sonyaudio