/bundles/org.openhab.binding.digitalstrom/ @MichaelOchel @msiegele
/bundles/org.openhab.binding.dlinksmarthome/ @MikeJMajor
/bundles/org.openhab.binding.dmx/ @openhab/add-ons-maintainers
+/bundles/org.openhab.binding.dominoswiss/ @Friesoch
/bundles/org.openhab.binding.doorbird/ @mhilbush
/bundles/org.openhab.binding.draytonwiser/ @andrew-schofield
/bundles/org.openhab.binding.dscalarm/ @RSStephens
<artifactId>org.openhab.binding.dmx</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.openhab.addons.bundles</groupId>
+ <artifactId>org.openhab.binding.dominoswiss</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.doorbird</artifactId>
--- /dev/null
+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/openhab-addons
--- /dev/null
+# Dominoswiss Binding
+
+This binding allows the control of rollershutters, using an eGate as gateway and Dominoswiss radio receivers.
+The eGate-gateway is connected via ethernet to openHAB and sends its commands via radio to all rollershutters.
+See https://www.brelag.com/ for more information.
+
+
+## Supported Things
+
+eGate: Dominoswiss eGate Server. The eGate is the gateway which sends the commands to the connected rollershutters. The bridge-type ID is egate.
+Blind: represents one rollershutter, that can be controlled via eGate. The thing-type ID is blind.
+
+
+## Discovery
+
+Unfortunately no automatic discovery is possible due to protocol restrictions.
+Every rollershutter must be known by eGate and can be called by it's number of storage-place on eGate gateway.
+
+
+
+## Thing Configuration
+
+The bridge "eGate" has one channel "getconfig" which returns the config of this bridge.
+The eGate is configured with both an `ipAddress` and a port.
+
+|Property|Default|Required|Description|
+|--------|-------|--------|-----------|
+|ipAddress|none|Yes|The IP or host name of the Dominoswiss EGate Serve|
+|port|1318|Yes|Port interface of the Dominoswiss EGate Server|
+
+```
+Bridge dominoswiss:egate:myeGate "My eGate Server" @ "Home" [ ipAddres="localhost", port=5700 ]
+```
+
+
+The thing blind represents one blind on the eGate. Each blind is represented by an id set on your eGate.
+
+```
+Thing blind officeBlind "Office" @ "1stFloor" [ id="1"]
+```
+
+The blind-Thing has the following channels:
+
+|Channel Type ID|Item Type|Description|
+|---------------|---------|-----------|
+|pulseUp|Rollershutter|sends one pulse up to this blind.|
+|pulseDown|Rollershutter|sends one pulse down to this blind|
+|continuousUp|Rollershutter|sends a continuous up to this blind. The blind will automatically stop as it is fully up.|
+|continuousDown|Rollershutter|send a continous down to this blind. The blind will automatically stop as it is fully down.|
+|stop|Rollershutter|stop the action of the blind. The command will be imadiatly sent to the blind.|
+|shutter|Rollershutter|this is used to bind the channel to the shutter item. There are no further rules needed this channel will handel the up/down/stop commands. See example for usage.|
+|tilt|Rollershutter|same as shutter, this will handel all up/down/stop - tilt commands to be used with the shutter-item.|
+|tiltUp|Rollershutter|sends 3 pulse-up commands to this blind to tilt the blind. If your blind needs more than 3 pulse-up, create a rule yourself with three pluse-up commands. Between each pulse-up you should wait 150ms to let the command be processed.
+|tiltDown|Rollershutter|sends 3 pulse-down commands to this blind to tilt the blind. If your blind needs more than 3 pulse-down, create a rule yourself with three pluse-down commands. Between each pulse-down you should wait 150ms to let the command be processed. |
+
+## Full Example
+
+Sample things file:
+
+```
+Bridge dominoswiss:egate:myeGate "My eGate Server" @ "Home" [ ipAddres="localhost", port="5500" ]
+{
+ Thing blind officeBlind "Office" @ "1stFloor" [ id="1"]
+ Thing blind diningRoomBlind "Dining Room" @ "EG" [id="2"]
+ Thing blind kitchenBlind "Kitchen" @ "EG" [id="12"]
+}
+```
+
+Sample items file:
+
+```
+Rollershutter OfficeBlindShutter "Office blind" <rollershutter> (g_blinds) { channel="dominoswiss:blind:myeGate:officeBlind:shutter"}
+
+Rollershutter OfficeBlindShutterTilt "Tilt Office" <rollershutter> (g_blinds_tilt) { channel="dominoswiss:blind:meGgate:bueroBlind:tilt"}
+
+```
+
+Sample sitemap file
+
+```
+Switch item=OfficeBlindShutter
+Switch item=OfficeBlindShutterTilt
+```
+
+Sample rule file
+
+This example moves the blind of the office up as the sun passed 110 azimuth (so the sun is no longer shining directly into the office).
+
+```
+rule "OneSide up"
+when
+ Item Azimuth changed
+then
+ val azimuth = Math::round((Azimuth.state as DecimalType).intValue)
+ if (azimuth == 110)
+ {
+ OfficeBlindShutter.sendCommand(UP)
+ }
+end
+```
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.openhab.addons.bundles</groupId>
+ <artifactId>org.openhab.addons.reactor.bundles</artifactId>
+ <version>3.2.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>org.openhab.binding.dominoswiss</artifactId>
+
+ <name>openHAB Add-ons :: Bundles :: Dominoswiss Binding</name>
+
+</project>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<features name="org.openhab.binding.dominoswiss-${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-dominoswiss" description="dominoswiss Binding" version="${project.version}">
+ <feature>openhab-runtime-base</feature>
+ <bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.dominoswiss/${project.version}</bundle>
+ </feature>
+</features>
--- /dev/null
+/**
+ * Copyright (c) 2010-2021 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.dominoswiss.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * Configuration of a blind.
+ *
+ * @author Frieso Aeschbacher - Initial contribution
+ */
+@NonNullByDefault
+public class BlindConfig {
+
+ /*
+ * The ID of that blind
+ */
+ public String id = "";
+}
--- /dev/null
+/**
+ * Copyright (c) 2010-2021 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.dominoswiss.internal;
+
+import static org.openhab.binding.dominoswiss.internal.DominoswissBindingConstants.*;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+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.types.Command;
+import org.openhab.core.types.RefreshType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@link BlindHandler} is responsible for handling commands, which are
+ * sent to one of the channels.The class defines common constants, which are
+ * used across the whole binding
+ *
+ * @author Frieso Aeschbacher - Initial contribution
+ */
+@NonNullByDefault
+public class BlindHandler extends BaseThingHandler {
+
+ private Logger logger = LoggerFactory.getLogger(BlindHandler.class);
+
+ private @Nullable EGateHandler dominoswissHandler;
+
+ private String id = "";
+
+ public BlindHandler(Thing thing) {
+ super(thing);
+ }
+
+ @Override
+ public void handleCommand(ChannelUID channelUID, Command command) {
+ logger.debug("Blind got command: {} and ChannelUID: {} ", command.toFullString(),
+ channelUID.getIdWithoutGroup());
+ Bridge bridge = getBridge();
+ EGateHandler localDominoswissHandler = dominoswissHandler;
+ if (bridge != null) {
+ localDominoswissHandler = (EGateHandler) bridge.getHandler();
+ }
+ if (localDominoswissHandler == null) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED, "EGate not available");
+ logger.debug("Blind thing {} has no server configured, ignoring command: {}", getThing().getUID(), command);
+ return;
+ }
+
+ // Some of the code below is not designed to handle REFRESH
+ if (command == RefreshType.REFRESH) {
+ return;
+ }
+ switch (channelUID.getIdWithoutGroup()) {
+ case CHANNEL_PULSEUP:
+ if (command instanceof Number) {
+ localDominoswissHandler.pulseUp(id);
+ }
+ break;
+ case CHANNEL_PULSEDOWN:
+ if (command instanceof Number) {
+ localDominoswissHandler.pulseDown(id);
+ }
+ break;
+ case CHANNEL_CONTINOUSUP:
+ if (command instanceof Number) {
+ localDominoswissHandler.continuousUp(id);
+ }
+ break;
+ case CHANNEL_CONTINOUSDOWN:
+ if (command instanceof Number) {
+ localDominoswissHandler.continuousDown(id);
+ }
+ break;
+ case CHANNEL_STOP:
+ if (command instanceof Number) {
+ localDominoswissHandler.stop(id);
+ }
+ break;
+ case UP:
+ if (command instanceof Number) {
+ localDominoswissHandler.continuousUp(id);
+ }
+ break;
+ case DOWN:
+ if (command instanceof Number) {
+ localDominoswissHandler.continuousDown(id);
+ }
+ break;
+ case SHUTTER:
+ if (command.toFullString() == DOWN) {
+ localDominoswissHandler.continuousDown(id);
+ } else if (command.toFullString() == UP) {
+ localDominoswissHandler.continuousUp(id);
+ } else if (command.toFullString() == CHANNEL_STOP) {
+ localDominoswissHandler.stop(id);
+ } else {
+ logger.debug("Blind got command but nothing executed: {} and ChannelUID: {}",
+ command.toFullString(), channelUID.getIdWithoutGroup());
+ }
+
+ case TILTDOWN:
+ if (command instanceof Number) {
+ try {
+ localDominoswissHandler.tiltDown(id);
+ } catch (InterruptedException e) {
+ logger.debug("EGate tiltDown error: {} ", e.toString());
+ }
+ }
+ break;
+
+ case TILTUP:
+ if (command instanceof Number) {
+ try {
+ localDominoswissHandler.tiltUp(id);
+ } catch (InterruptedException e) {
+ logger.debug("EGate tiltUP error: {} ", e.toString());
+ }
+ }
+ break;
+
+ case SHUTTERTILT:
+ if (command.toFullString() == UP) {
+ localDominoswissHandler.pulseUp(id);
+ } else if (command.toFullString() == DOWN) {
+ localDominoswissHandler.pulseDown(id);
+ } else if (command.toFullString() == CHANNEL_STOP) {
+ localDominoswissHandler.stop(id);
+ } else {
+ logger.debug("Blind got command but nothing executed: {} and ChannelUID: {}",
+ command.toFullString(), channelUID.getIdWithoutGroup());
+ }
+
+ default:
+ break;
+ }
+ }
+
+ @Override
+ public void initialize() {
+ this.id = getConfig().as(BlindConfig.class).id;
+ Bridge bridge = getBridge();
+ if (bridge != null) {
+ dominoswissHandler = (EGateHandler) bridge.getHandler();
+ EGateHandler localDominoswissHandler = dominoswissHandler;
+ if (localDominoswissHandler != null) {
+ localDominoswissHandler.registerBlind(this.id, getThing().getUID());
+ try {
+ ThingStatus bridgeStatus = bridge.getStatus();
+ if (bridgeStatus == ThingStatus.ONLINE && getThing().getStatus() != ThingStatus.ONLINE) {
+ updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE);
+ localDominoswissHandler = (EGateHandler) bridge.getHandler();
+ } else if (bridgeStatus == ThingStatus.OFFLINE) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
+ }
+ } catch (Exception e) {
+ logger.debug("Could not update ThingStatus ", e);
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, e.toString());
+
+ }
+ }
+ }
+ }
+
+ /*
+ * Gets the ID of this Blind
+ */
+ public String getID() {
+ return this.id;
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2010-2021 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.dominoswiss.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.core.thing.ThingTypeUID;
+
+/**
+ * The {@link DominoswissBindingConstants} class defines common constants, which are
+ * used across the whole binding.
+ *
+ * @author Frieso Aeschbacher - Initial contribution
+ */
+@NonNullByDefault
+public class DominoswissBindingConstants {
+
+ private static final String BINDING_ID = "dominoswiss";
+
+ // List of all Thing Type UIDs
+ public static final ThingTypeUID DOMINOSWISSBLINDS_THING_TYPE = new ThingTypeUID(BINDING_ID, "blind");
+ public static final ThingTypeUID DOMINOSWISSEGATE_THING_TYPE = new ThingTypeUID(BINDING_ID, "egate");
+
+ // List of all Channel ids
+ public static final String CHANNEL_PULSEUP = "pulseUp";
+ public static final String CHANNEL_PULSEDOWN = "pulseDown";
+ public static final String CHANNEL_CONTINOUSUP = "continousUp";
+ public static final String CHANNEL_CONTINOUSDOWN = "continousDown";
+ public static final String CHANNEL_STOP = "STOP";
+ public static final String UP = "UP";
+ public static final String DOWN = "DOWN";
+ public static final String SHUTTER = "shutter";
+ public static final String TILTUP = "tiltUp";
+ public static final String TILTDOWN = "tiltDown";
+ public static final String SHUTTERTILT = "shutterTilt";
+
+ public static final String GETCONFIG = "getConfig";
+
+ public static final String CR = "\r";
+}
--- /dev/null
+/**
+ * Copyright (c) 2010-2021 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.dominoswiss.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link DominoswissConfiguration} class contains fields mapping thing configuration parameters.
+ *
+ * @author Frieso Aeschbacher - Initial contribution
+ */
+@NonNullByDefault
+public class DominoswissConfiguration {
+
+ /**
+ * Server ip address
+ */
+ public String ipAddress = "localhost";
+ /**
+ * Server web port for REST calls
+ */
+ public int port = 1318;
+
+ /**
+ * Language for TTS has to be fix to EN as only English commands are allowed
+ */
+ public final String language = "EN";
+}
--- /dev/null
+/**
+ * Copyright (c) 2010-2021 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.dominoswiss.internal;
+
+import static org.openhab.binding.dominoswiss.internal.DominoswissBindingConstants.*;
+
+import java.util.Set;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+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;
+
+/**
+ * The {@link DominoswissHandlerFactory} is responsible for creating things and thing
+ * handlers.
+ *
+ * @author Frieso Aeschbacher - Initial contribution
+ */
+@NonNullByDefault
+@Component(configurationPid = "binding.dominoswiss", service = ThingHandlerFactory.class)
+public class DominoswissHandlerFactory extends BaseThingHandlerFactory {
+
+ private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(DOMINOSWISSEGATE_THING_TYPE,
+ DOMINOSWISSBLINDS_THING_TYPE);
+
+ @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(DOMINOSWISSEGATE_THING_TYPE)) {
+ return new EGateHandler((Bridge) thing);
+ }
+
+ if (thingTypeUID.equals(DOMINOSWISSBLINDS_THING_TYPE)) {
+ return new BlindHandler(thing);
+ }
+ return null;
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2010-2021 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.dominoswiss.internal;
+
+import static org.openhab.binding.dominoswiss.internal.DominoswissBindingConstants.*;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.HashMap;
+import java.util.List;
+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.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.ThingUID;
+import org.openhab.core.thing.binding.BaseBridgeHandler;
+import org.openhab.core.types.Command;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@link EgateHandler} is responsible for handling commands, which are
+ * sent to one of the channels.
+ *
+ * @author Frieso Aeschbacher - Initial contribution
+ */
+@NonNullByDefault
+public class EGateHandler extends BaseBridgeHandler {
+
+ private final Logger logger = LoggerFactory.getLogger(EGateHandler.class);
+ private @Nullable Socket egateSocket;
+
+ private int port;
+ private @Nullable String host;
+ private static final int SOCKET_TIMEOUT_SEC = 250;
+ private final Object lock = new Object();
+ private @Nullable BufferedWriter writer;
+ private @Nullable BufferedReader reader;
+ private @Nullable Future<?> refreshJob;
+ private Map<String, ThingUID> registeredBlinds;
+ private @Nullable ScheduledFuture<?> pollingJob;
+
+ public EGateHandler(Bridge thing) {
+ super(thing);
+ registeredBlinds = new HashMap<String, ThingUID>();
+ }
+
+ @Override
+ public void handleCommand(ChannelUID channelUID, Command command) {
+ if (channelUID.getId().equals(GETCONFIG)) {
+ sendCommand("EthernetGet;\r");
+ }
+ }
+
+ @Override
+ public void initialize() {
+ DominoswissConfiguration config;
+ config = this.getConfigAs(DominoswissConfiguration.class);
+ host = config.ipAddress;
+ port = config.port;
+
+ if (host != null && port > 0) {
+ // Create a socket to eGate
+ try (Socket localEgateSocket = new Socket(host, port)) {
+ writer = new BufferedWriter(new OutputStreamWriter(localEgateSocket.getOutputStream()));
+ egateSocket = localEgateSocket;
+ } catch (IOException e) {
+ logger.debug("IOException in initialize: {} host {} port {}", e.toString(), host, port);
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.toString());
+ egateSocket = null;
+ }
+ pollingJob = scheduler.scheduleWithFixedDelay(this::pollingConfig, 0, 30, TimeUnit.SECONDS);
+ } else {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR,
+ "Cannot connect to dominoswiss eGate gateway. host IP address or port are not set.");
+ }
+ }
+
+ @Override
+ public void dispose() {
+ try {
+ Socket localEgateSocket = egateSocket;
+ if (localEgateSocket != null) {
+ localEgateSocket.close();
+ }
+ Future<?> localRefreshJob = refreshJob;
+ if (localRefreshJob != null) {
+ localRefreshJob.cancel(true);
+ }
+ BufferedReader localReader = reader;
+ if (localReader != null) {
+ localReader.close();
+ }
+
+ BufferedWriter localWriter = writer;
+ if (localWriter != null) {
+ localWriter.close();
+ }
+ ScheduledFuture<?> localPollingJob = pollingJob;
+ if (localPollingJob != null) {
+ localPollingJob.cancel(true);
+ localPollingJob = null;
+ }
+ logger.debug("EGate Handler connection closed, disposing");
+ } catch (IOException e) {
+ logger.debug("EGate Handler Error on dispose: {} ", e.toString());
+ }
+ }
+
+ public synchronized boolean isConnected() {
+ Socket localEGateSocket = egateSocket;
+ if (localEGateSocket == null) {
+ return false;
+ }
+
+ // NOTE: isConnected() returns true once a connection is made and will
+ // always return true even after the socket is closed
+ // http://stackoverflow.com/questions/10163358/
+ return localEGateSocket.isConnected() && !localEGateSocket.isClosed();
+ }
+
+ /**
+ * Possible Instructions are:
+ * FssTransmit 1 Kommandoabsetzung (Controller > eGate > Dominoswiss)
+ * FssReceive 2 Empfangenes Funkpaket (Dominoswiss > eGate > Controller)
+ *
+ * @throws InterruptedException
+ *
+ */
+
+ public void tiltUp(String id) throws InterruptedException {
+ for (int i = 0; i < 3; i++) {
+ pulseUp(id);
+ Thread.sleep(150); // sleep to not confuse the blinds
+
+ }
+ }
+
+ public void tiltDown(String id) throws InterruptedException {
+ for (int i = 0; i < 3; i++) {
+ pulseDown(id);
+ Thread.sleep(150);// sleep to not confuse the blinds
+ }
+ }
+
+ public void pulseUp(String id) {
+ sendCommand("Instruction=1;ID=" + id + ";Command=1;Priority=1;CheckNr=3415347;" + CR);
+ }
+
+ public void pulseDown(String id) {
+ sendCommand("Instruction=1;ID=" + id + ";Command=2;Priority=1;CheckNr=2764516;" + CR);
+ }
+
+ public void continuousUp(String id) {
+ sendCommand("Instruction=1;ID=" + id + ";Command=3;Priority=1;CheckNr=2867016;" + CR, 20000);
+ }
+
+ public void continuousDown(String id) {
+ sendCommand("Instruction=1;ID=" + id + ";Command=4;Priority=1;CheckNr=973898;" + CR, 20000);
+ }
+
+ public void stop(String id) {
+ sendCommand("Instruction=1;ID=" + id + ";Command=5;Priority=1;CheckNr=5408219;" + CR);
+ }
+
+ public void registerBlind(String id, ThingUID uid) {
+ logger.debug("Registring Blind id {} with thingUID {}", id, uid);
+ registeredBlinds.put(id, uid);
+ }
+
+ /**
+ * Send a command to the eGate Server.
+ */
+
+ private void sendCommand(String command) {
+ sendCommand(command, SOCKET_TIMEOUT_SEC);
+ }
+
+ private synchronized void sendCommand(String command, int timeout) {
+ logger.debug("EGate got command: {}", command);
+ Socket localEGateSocket = egateSocket;
+ BufferedWriter localWriter = writer;
+ if (localEGateSocket == null || localWriter == null) {
+ return;
+ }
+ if (!isConnected()) {
+ logger.debug("no connection to Dominoswiss eGate server when trying to send command, returning...");
+ return;
+ }
+
+ // Send plain string to eGate Server,
+ try {
+ localEGateSocket.setSoTimeout(SOCKET_TIMEOUT_SEC);
+ localWriter.write(command);
+ localWriter.flush();
+ } catch (IOException e) {
+ logger.debug("Error while sending command {} to Dominoswiss eGate Server {} ", command, e.toString());
+ }
+ }
+
+ private void pollingConfig() {
+ if (!isConnected()) {
+ Socket localEGateSocket = egateSocket;
+ BufferedWriter localWriter = writer;
+ if (localEGateSocket == null || localWriter == null) {
+ return;
+ }
+ synchronized (lock) {
+ try {
+ localEGateSocket.connect(new InetSocketAddress(host, port));
+ localEGateSocket.setSoTimeout(SOCKET_TIMEOUT_SEC);
+ localWriter.write("SilenceModeSet;Value=0;" + CR);
+ localWriter.flush();
+ } catch (IOException e) {
+ logger.debug("IOException in pollingConfig: {} host {} port {}", e.toString(), host, port);
+ try {
+ localEGateSocket.close();
+ egateSocket = null;
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.toString());
+ } catch (IOException e1) {
+ logger.debug("EGate Socket not closed {}", e1.toString());
+ }
+ egateSocket = null;
+ }
+ if (egateSocket != null) {
+ updateStatus(ThingStatus.ONLINE);
+ startAutomaticRefresh();
+ logger.debug("EGate Handler started automatic refresh, status: {} ",
+ getThing().getStatus().toString());
+ } else {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
+ }
+ }
+ }
+ }
+
+ private void startAutomaticRefresh() {
+ Runnable runnable = () -> {
+ try {
+
+ Socket localSocket = egateSocket;
+ if (localSocket == null) {
+ return;
+ }
+ BufferedReader localReader = reader;
+ if (localReader == null) {
+ reader = new BufferedReader(new InputStreamReader(localSocket.getInputStream()));
+ }
+ if (localReader != null && localReader.ready()) {
+ String input = localReader.readLine();
+ logger.debug("Reader got from EGATE: {}", input);
+ onData(input);
+ }
+ } catch (IOException e) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR,
+ "Error while reading command from Dominoswiss eGate Server " + e.toString());
+ }
+ };
+ refreshJob = scheduler.submit(runnable);
+ }
+
+ /**
+ * Finds and returns a child thing for a given UID of this bridge.
+ *
+ * @param uid uid of the child thing
+ * @return child thing with the given uid or null if thing was not found
+ */
+ public @Nullable Thing getThingByUID(ThingUID uid) {
+ Bridge bridge = getThing();
+
+ List<Thing> things = bridge.getThings();
+
+ for (Thing thing : things) {
+ if (thing.getUID().equals(uid)) {
+ return thing;
+ }
+ }
+
+ return null;
+ }
+
+ protected void onData(String input) {
+ // Instruction=2;ID=19;Command=1;Value=0;Priority=0;
+ Map<String, String> map = new HashMap<String, String>();
+ // split on ;
+ String[] parts = input.split(";");
+ if (parts.length >= 2) {
+ for (int i = 0; i < parts.length; i += 2) {
+ map.put(parts[i], parts[i + 1]);
+ }
+ }
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<binding:binding id="dominoswiss" 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>Dominoswiss Binding</name>
+ <description>The Dominoswiss Binding interacts with the Dominoswiss eGate G1 Gateway to control blinds</description>
+</binding:binding>
--- /dev/null
+# binding
+binding.dominoswiss.name = Dominoswiss
+binding.dominoswiss.description = Dominoswiss Binding zur Kontrolle der Jalousien
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<thing:thing-descriptions bindingId="dominoswiss"
+ 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-type id="egate">
+ <label>Dominoswiss EGate Server</label>
+ <description>This is a Dominoswiss EGate Server instance.</description>
+ <config-description>
+ <parameter name="ipAddress" type="text" required="true">
+ <label>IP or Host Name</label>
+ <context>network-address</context>
+ <description>The IP or host name of the Dominoswiss EGate Server (192.168.1.100, localhost)</description>
+ </parameter>
+ <parameter name="port" type="integer" required="true" min="1" max="65335">
+ <label>Web Port</label>
+ <description>Port interface of the Dominoswiss EGate Server, default 1318</description>
+ <default>1318</default>
+ </parameter>
+ </config-description>
+ </bridge-type>
+
+ <thing-type id="blind">
+ <supported-bridge-type-refs>
+ <bridge-type-ref id="egate"/>
+ </supported-bridge-type-refs>
+ <label>Blind</label>
+ <description>Provides various control commands for Dominoswiss receivers</description>
+ <channels>
+ <channel id="pulseUp" typeId="pulseUp"/>
+ <channel id="pulseDown" typeId="pulseDown"/>
+ <channel id="continuousUp" typeId="continuousUp"/>
+ <channel id="continuousDown" typeId="continuousDown"/>
+ <channel id="stop" typeId="stop"/>
+ <channel id="shutter" typeId="shutter"/>
+ <channel id="shutterTilt" typeId="shutterTilt"/>
+ <channel id="tiltUp" typeId="tiltUp"/>
+ <channel id="tiltDown" typeId="tiltDown"/>
+ </channels>
+ <properties>
+ <property name="vendor">Dominoswiss</property>
+ </properties>
+ <config-description>
+ <parameter name="id" type="text" required="true">
+ <label>ID Address</label>
+ <description>Blinds are identified by their ID address</description>
+ </parameter>
+ </config-description>
+ </thing-type>
+
+ <channel-type id="pulseUp">
+ <item-type>Rollershutter</item-type>
+ <label>Pulse Up</label>
+ <description>Send one pulse up</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="pulseDown">
+ <item-type>Rollershutter</item-type>
+ <label>Pulse Down</label>
+ <description>Send one pulse down</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="continuousUp">
+ <item-type>Rollershutter</item-type>
+ <label>Continuous Up</label>
+ <description>Send continuous up command to blind</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="continuousDown">
+ <item-type>Rollershutter</item-type>
+ <label>Continuous Down</label>
+ <description>Send continuous down command to blind</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="stop">
+ <item-type>Rollershutter</item-type>
+ <label>Stop</label>
+ <description>Send stop impulse to stop the blinds</description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="shutter">
+ <item-type>Rollershutter</item-type>
+ <label>Shutter</label>
+ <description>Handle the commands up/down/stop </description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="shutterTilt">
+ <item-type>Rollershutter</item-type>
+ <label>Shutter Tilt Up Down</label>
+ <description>Handle the commands tiltUp/tiltDown/stop </description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="tiltUp">
+ <item-type>Rollershutter</item-type>
+ <label>Tilt Up</label>
+ <description>Handle the command for 3 tilts up </description>
+ <state readOnly="true"/>
+ </channel-type>
+
+ <channel-type id="tiltDown">
+ <item-type>Rollershutter</item-type>
+ <label>Tilt Down</label>
+ <description>Handle the command for 3 tilts down </description>
+ <state readOnly="true"/>
+ </channel-type>
+
+</thing:thing-descriptions>
<module>org.openhab.binding.digitalstrom</module>
<module>org.openhab.binding.dlinksmarthome</module>
<module>org.openhab.binding.dmx</module>
+ <module>org.openhab.binding.dominoswiss</module>
<module>org.openhab.binding.doorbird</module>
<module>org.openhab.binding.draytonwiser</module>
<module>org.openhab.binding.dscalarm</module>