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,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>