mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 07:02:02 +01:00
[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:
parent
ebf2a76311
commit
15b83cc40f
@ -70,6 +70,7 @@
|
||||
/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
|
||||
|
@ -341,6 +341,11 @@
|
||||
<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>
|
||||
|
13
bundles/org.openhab.binding.dominoswiss/NOTICE
Normal file
13
bundles/org.openhab.binding.dominoswiss/NOTICE
Normal 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
|
100
bundles/org.openhab.binding.dominoswiss/README.md
Normal file
100
bundles/org.openhab.binding.dominoswiss/README.md
Normal 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
|
||||
```
|
15
bundles/org.openhab.binding.dominoswiss/pom.xml
Normal file
15
bundles/org.openhab.binding.dominoswiss/pom.xml
Normal 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>
|
@ -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>
|
@ -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 = "";
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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";
|
||||
}
|
@ -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";
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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>
|
@ -0,0 +1,3 @@
|
||||
# binding
|
||||
binding.dominoswiss.name = Dominoswiss
|
||||
binding.dominoswiss.description = Dominoswiss Binding zur Kontrolle der Jalousien
|
@ -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>
|
@ -102,6 +102,7 @@
|
||||
<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>
|
||||
|
Loading…
Reference in New Issue
Block a user