[dominoswiss] Initial contribution (#11585)

* Added Dominoswiss to CODEOWNERS and POMs

Signed-off-by: Frieso Aeschbacher <frieso.aeschbacher@gmail.com>

* Intitial contribution of Dominoswiss Binding

Signed-off-by: Frieso Aeschbacher <frieso.aeschbacher@gmail.com>

* Typo in pom.xml

Signed-off-by: Frieso Aeschbacher <frieso.aeschbacher@gmail.com>

* Fixed inputs from fwolter

Signed-off-by: Frieso Aeschbacher <frieso.aeschbacher@gmail.com>

* Fixed inputs from fwolter

Signed-off-by: Frieso Aeschbacher <frieso.aeschbacher@gmail.com>

* Fixed localWriter Issue

Signed-off-by: Frieso Aeschbacher <frieso.aeschbacher@gmail.com>

* Update bom/openhab-addons/pom.xml

Signed-off-by: Fabian Wolter <github@fabian-wolter.de>

Co-authored-by: Fabian Wolter <github@fabian-wolter.de>
This commit is contained in:
Frieso Aeschbacher 2021-12-11 13:05:41 +01:00 committed by GitHub
parent ebf2a76311
commit 15b83cc40f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 947 additions and 0 deletions

View File

@ -70,6 +70,7 @@
/bundles/org.openhab.binding.digitalstrom/ @MichaelOchel @msiegele /bundles/org.openhab.binding.digitalstrom/ @MichaelOchel @msiegele
/bundles/org.openhab.binding.dlinksmarthome/ @MikeJMajor /bundles/org.openhab.binding.dlinksmarthome/ @MikeJMajor
/bundles/org.openhab.binding.dmx/ @openhab/add-ons-maintainers /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.doorbird/ @mhilbush
/bundles/org.openhab.binding.draytonwiser/ @andrew-schofield /bundles/org.openhab.binding.draytonwiser/ @andrew-schofield
/bundles/org.openhab.binding.dscalarm/ @RSStephens /bundles/org.openhab.binding.dscalarm/ @RSStephens

View File

@ -341,6 +341,11 @@
<artifactId>org.openhab.binding.dmx</artifactId> <artifactId>org.openhab.binding.dmx</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.dominoswiss</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.openhab.addons.bundles</groupId> <groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.doorbird</artifactId> <artifactId>org.openhab.binding.doorbird</artifactId>

View File

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

View File

@ -0,0 +1,100 @@
# 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
```

View File

@ -0,0 +1,15 @@
<?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>

View File

@ -0,0 +1,9 @@
<?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>

View File

@ -0,0 +1,29 @@
/**
* 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 = "";
}

View File

@ -0,0 +1,186 @@
/**
* 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;
}
}

View File

@ -0,0 +1,49 @@
/**
* 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";
}

View File

@ -0,0 +1,38 @@
/**
* 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";
}

View File

@ -0,0 +1,60 @@
/**
* 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;
}
}

View File

@ -0,0 +1,316 @@
/**
* 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]);
}
}
}
}

View File

@ -0,0 +1,8 @@
<?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>

View File

@ -0,0 +1,3 @@
# binding
binding.dominoswiss.name = Dominoswiss
binding.dominoswiss.description = Dominoswiss Binding zur Kontrolle der Jalousien

View File

@ -0,0 +1,114 @@
<?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>

View File

@ -102,6 +102,7 @@
<module>org.openhab.binding.digitalstrom</module> <module>org.openhab.binding.digitalstrom</module>
<module>org.openhab.binding.dlinksmarthome</module> <module>org.openhab.binding.dlinksmarthome</module>
<module>org.openhab.binding.dmx</module> <module>org.openhab.binding.dmx</module>
<module>org.openhab.binding.dominoswiss</module>
<module>org.openhab.binding.doorbird</module> <module>org.openhab.binding.doorbird</module>
<module>org.openhab.binding.draytonwiser</module> <module>org.openhab.binding.draytonwiser</module>
<module>org.openhab.binding.dscalarm</module> <module>org.openhab.binding.dscalarm</module>