Skip to content

Commit 1aae8a4

Browse files
paphkoNemer_Daud
authored andcommitted
[anel] Initial contribution of the Anel NET-PwrCtrl binding for OH3 (openhab#10952)
* Initial contribution of the Anel NET-PwrCtrl binding for OH3. Signed-off-by: Patrick Koenemann <[email protected]> * Adjustments based on code review. Signed-off-by: Patrick Koenemann <[email protected]> * Further adjustments according to second review. Signed-off-by: Patrick Koenemann <[email protected]> * Checkstyle warnings revmoed. Signed-off-by: Patrick Koenemann <[email protected]>
1 parent 15dd90f commit 1aae8a4

26 files changed

+3163
-0
lines changed

CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
/bundles/org.openhab.binding.ambientweather/ @mhilbush
2424
/bundles/org.openhab.binding.amplipi/ @kaikreuzer
2525
/bundles/org.openhab.binding.androiddebugbridge/ @GiviMAD
26+
/bundles/org.openhab.binding.anel/ @paphko
2627
/bundles/org.openhab.binding.astro/ @gerrieg
2728
/bundles/org.openhab.binding.atlona/ @tmrobert8
2829
/bundles/org.openhab.binding.autelis/ @digitaldan

bom/openhab-addons/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@
106106
<artifactId>org.openhab.binding.androiddebugbridge</artifactId>
107107
<version>${project.version}</version>
108108
</dependency>
109+
<dependency>
110+
<groupId>org.openhab.addons.bundles</groupId>
111+
<artifactId>org.openhab.binding.anel</artifactId>
112+
<version>${project.version}</version>
113+
</dependency>
109114
<dependency>
110115
<groupId>org.openhab.addons.bundles</groupId>
111116
<artifactId>org.openhab.binding.astro</artifactId>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
This content is produced and maintained by the openHAB project.
2+
3+
* Project home: https://www.openhab.org
4+
5+
== Declared Project Licenses
6+
7+
This program and the accompanying materials are made available under the terms
8+
of the Eclipse Public License 2.0 which is available at
9+
https://www.eclipse.org/legal/epl-2.0/.
10+
11+
== Source Code
12+
13+
https://github.com/openhab/openhab-addons
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
# Anel NET-PwrCtrl Binding
2+
3+
Monitor and control Anel NET-PwrCtrl devices.
4+
5+
NET-PwrCtrl devices are power sockets / relays that can be configured via browser but they can also be controlled over the network, e.g. with an Android or iPhone app - and also with openHAB via this binding.
6+
Some NET-PwrCtrl devices also have 8 I/O ports which can either be used to directly switch the sockets / relays, or they can be used as general input / output switches in openHAB.
7+
8+
9+
## Supported Things
10+
11+
There are three kinds of devices ([overview on manufacturer's homepage](https://en.anel.eu/?src=/produkte/produkte.htm)):
12+
13+
| [Anel NET-PwrCtrl HUT](https://en.anel.eu/?src=/produkte/hut_2/hut_2.htm) <br/> <sub>( _advanced-firmware_ )</sub> | [Anel NET-PwrCtrl IO](https://en.anel.eu/?src=/produkte/io/io.htm) <br/> <sub>( _advanced-firmware_ )</sub> | [Anel NET-PwrCtrl HOME](https://de.anel.eu/?src=produkte/home/home.htm) <br/> <sub>( _home_ )</sub> <br/> (only German version) |
14+
| --- | --- | --- |
15+
| [![Anel NET-PwrCtrl HUT 2](https://de.anel.eu/image/leisten/HUT2LV-P_500.jpg)](https://de.anel.eu/?src=produkte/hut_2/hut_2.htm) | [![Anel NET-PwrCtrl IO](https://de.anel.eu/image/leisten/IO-Stecker.png)](https://de.anel.eu/?src=produkte/io/io.htm) | [![Anel NET-PwrCtrl HOME](https://de.anel.eu/image/leisten/HOME-DE-500.gif)](https://de.anel.eu/?src=produkte/home/home.htm) |
16+
17+
Thing type IDs:
18+
19+
* *home*: The smallest device, the _HOME_, is the only one with only three power sockets and only available in Germany.
20+
* *simple-firmware*: The _PRO_ and _REDUNDANT_ have eight power sockets and a similar (simplified) firmware as the _HOME_.
21+
* *advanced-firmware*: All others (_ADV_, _IO_, and the different _HUT_ variants) have eight power sockets / relays, eight IO ports, and an advanced firmware.
22+
23+
An [additional sensor](https://en.anel.eu/?src=/produkte/sensor_1/sensor_1.htm) may be used for monitoring temperature, humidity, and brightness.
24+
The sensor can be attached to a _HUT_ device via an Ethernet cable (max length is 50m).
25+
26+
27+
## Discovery
28+
29+
Devices can be discovered automatically if their UDP ports are configured as follows:
30+
31+
* 75 / 77 (default)
32+
* 750 / 770
33+
* 7500 / 7700
34+
* 7750 / 7770
35+
36+
If a device is found for a specific port (excluding the default port), the subsequent port is also scanned, e.g. 7500/7700 &rarr; 7501/7701 &rarr; 7502/7702 &rarr; etc.
37+
38+
Depending on the network switch and router devices, discovery may or may not work on wireless networks.
39+
It should work reliably though on local wired networks.
40+
41+
42+
## Thing Configuration
43+
44+
Each Thing requires the following configuration parameters.
45+
46+
| Parameter | Type | Default | Required | Description |
47+
|-----------------------|---------|-------------|----------|-------------|
48+
| Hostname / IP address | String | net-control | yes | Hostname or IP address of the device |
49+
| Send Port | Integer | 75 | yes | UDP port to send data to the device (in the anel web UI, it's the receive port!) |
50+
| Receive Port | Integer | 77 | yes | UDP port to receive data from the device (in the anel web UI, it's the send port!) |
51+
| User | String | user7 | yes | User to access the device (make sure it has rights to change relay / IO states!) |
52+
| Password | String | anel | yes | Password of the given user |
53+
54+
For multiple devices, please use exclusive UDP ports for each device.
55+
Ports above 1024 are recommended because they are outside the range of system ports.
56+
57+
Possible entries in your thing file could be (thing types _home_, _simple-firmware_, and _advanced-firmware_ are explained above in _Supported Things_):
58+
59+
```
60+
anel:home:mydevice1 [hostname="192.168.0.101", udpSendPort=7500, udpReceivePort=7700, user="user7", password="anel"]
61+
anel:simple-firmware:mydevice2 [hostname="192.168.0.102", udpSendPort=7501, udpReceivePort=7701, user="user7", password="anel"]
62+
anel:advanced-firmware:mydevice3 [hostname="192.168.0.103", udpSendPort=7502, udpReceivePort=7702, user="user7", password="anel"]
63+
anel:advanced-firmware:mydevice4 [hostname="192.168.0.104", udpSendPort=7503, udpReceivePort=7703, user="user7", password="anel"]
64+
```
65+
66+
67+
## Channels
68+
69+
Depending on the thing type, the following channels are available.
70+
71+
| Channel ID | Item Type | Supported Things | Read Only | Description |
72+
|--------------------|--------------------|-------------------|-----------|-------------|
73+
| prop#name | String | all | yes | Name of the device |
74+
| prop#temperature | Number:Temperature | simple / advanced | yes | Temperature of the integrated sensor |
75+
| sensor#temperature | Number:Temperature | advanced | yes | Temperature of the optional external sensor |
76+
| sensor#humidity | Number | advanced | yes | Humidity of the optional external sensor |
77+
| sensor#brightness | Number | advanced | yes | Brightness of the optional external sensor |
78+
| r1#name | String | all | yes | Name of relay / socket 1 |
79+
| r2#name | String | all | yes | Name of relay / socket 2 |
80+
| r3#name | String | all | yes | Name of relay / socket 3 |
81+
| r4#name | String | simple / advanced | yes | Name of relay / socket 4 |
82+
| r5#name | String | simple / advanced | yes | Name of relay / socket 5 |
83+
| r6#name | String | simple / advanced | yes | Name of relay / socket 6 |
84+
| r7#name | String | simple / advanced | yes | Name of relay / socket 7 |
85+
| r8#name | String | simple / advanced | yes | Name of relay / socket 8 |
86+
| r1#state | Switch | all | no * | State of relay / socket 1 |
87+
| r2#state | Switch | all | no * | State of relay / socket 2 |
88+
| r3#state | Switch | all | no * | State of relay / socket 3 |
89+
| r4#state | Switch | simple / advanced | no * | State of relay / socket 4 |
90+
| r5#state | Switch | simple / advanced | no * | State of relay / socket 5 |
91+
| r6#state | Switch | simple / advanced | no * | State of relay / socket 6 |
92+
| r7#state | Switch | simple / advanced | no * | State of relay / socket 7 |
93+
| r8#state | Switch | simple / advanced | no * | State of relay / socket 8 |
94+
| r1#locked | Switch | all | yes | Whether or not relay / socket 1 is locked |
95+
| r2#locked | Switch | all | yes | Whether or not relay / socket 2 is locked |
96+
| r3#locked | Switch | all | yes | Whether or not relay / socket 3 is locked |
97+
| r4#locked | Switch | simple / advanced | yes | Whether or not relay / socket 4 is locked |
98+
| r5#locked | Switch | simple / advanced | yes | Whether or not relay / socket 5 is locked |
99+
| r6#locked | Switch | simple / advanced | yes | Whether or not relay / socket 6 is locked |
100+
| r7#locked | Switch | simple / advanced | yes | Whether or not relay / socket 7 is locked |
101+
| r8#locked | Switch | simple / advanced | yes | Whether or not relay / socket 8 is locked |
102+
| io1#name | String | advanced | yes | Name of IO port 1 |
103+
| io2#name | String | advanced | yes | Name of IO port 2 |
104+
| io3#name | String | advanced | yes | Name of IO port 3 |
105+
| io4#name | String | advanced | yes | Name of IO port 4 |
106+
| io5#name | String | advanced | yes | Name of IO port 5 |
107+
| io6#name | String | advanced | yes | Name of IO port 6 |
108+
| io7#name | String | advanced | yes | Name of IO port 7 |
109+
| io8#name | String | advanced | yes | Name of IO port 8 |
110+
| io1#state | Switch | advanced | no ** | State of IO port 1 |
111+
| io2#state | Switch | advanced | no ** | State of IO port 2 |
112+
| io3#state | Switch | advanced | no ** | State of IO port 3 |
113+
| io4#state | Switch | advanced | no ** | State of IO port 4 |
114+
| io5#state | Switch | advanced | no ** | State of IO port 5 |
115+
| io6#state | Switch | advanced | no ** | State of IO port 6 |
116+
| io7#state | Switch | advanced | no ** | State of IO port 7 |
117+
| io8#state | Switch | advanced | no ** | State of IO port 8 |
118+
| io1#mode | Switch | advanced | yes | Mode of port 1: _ON_ = input, _OFF_ = output |
119+
| io2#mode | Switch | advanced | yes | Mode of port 2: _ON_ = input, _OFF_ = output |
120+
| io3#mode | Switch | advanced | yes | Mode of port 3: _ON_ = input, _OFF_ = output |
121+
| io4#mode | Switch | advanced | yes | Mode of port 4: _ON_ = input, _OFF_ = output |
122+
| io5#mode | Switch | advanced | yes | Mode of port 5: _ON_ = input, _OFF_ = output |
123+
| io6#mode | Switch | advanced | yes | Mode of port 6: _ON_ = input, _OFF_ = output |
124+
| io7#mode | Switch | advanced | yes | Mode of port 7: _ON_ = input, _OFF_ = output |
125+
| io8#mode | Switch | advanced | yes | Mode of port 8: _ON_ = input, _OFF_ = output |
126+
127+
\* Relay / socket state is read-only if it is locked; otherwise it is changeable.<br/>
128+
\** IO port state is read-only if its mode is _input_, it is changeable if its mode is _output_.
129+
130+
131+
## Full Example
132+
133+
`.things` file:
134+
135+
```
136+
Thing anel:advanced-firmware:anel1 "Anel1" [hostname="192.168.0.100", udpSendPort=7500, udpReceivePort=7700, user="user7", password="anel"]
137+
```
138+
139+
`.items` file:
140+
141+
```
142+
// device properties
143+
String anel1name "Anel1 Name" {channel="anel:advanced-firmware:anel1:prop#name"}
144+
Number:Temperature anel1temperature "Anel1 Temperature" {channel="anel:advanced-firmware:anel1:prop#temperature"}
145+
146+
// external sensor properties
147+
Number:Temperature anel1sensorTemperature "Anel1 Sensor Temperature" {channel="anel:advanced-firmware:anel1:sensor#temperature"}
148+
Number anel1sensorHumidity "Anel1 Sensor Humidity" {channel="anel:advanced-firmware:anel1:sensor#humidity"}
149+
Number anel1sensorBrightness "Anel1 Sensor Brightness" {channel="anel:advanced-firmware:anel1:sensor#brightness"}
150+
151+
// relay names and states
152+
String anel1relay1name "Anel1 Relay1 name" {channel="anel:advanced-firmware:anel1:r1#name"}
153+
Switch anel1relay1locked "Anel1 Relay1 locked" {channel="anel:advanced-firmware:anel1:r1#locked"}
154+
Switch anel1relay1state "Anel1 Relay1" {channel="anel:advanced-firmware:anel1:r1#state"}
155+
Switch anel1relay2state "Anel1 Relay2" {channel="anel:advanced-firmware:anel1:r2#state"}
156+
Switch anel1relay3state "Anel1 Relay3" {channel="anel:advanced-firmware:anel1:r3#state"}
157+
Switch anel1relay4state "Anel1 Relay4" {channel="anel:advanced-firmware:anel1:r4#state"}
158+
Switch anel1relay5state "Light Bedroom" {channel="anel:advanced-firmware:anel1:r5#state"}
159+
Switch anel1relay6state "Doorbell" {channel="anel:advanced-firmware:anel1:r6#state"}
160+
Switch anel1relay7state "Socket TV" {channel="anel:advanced-firmware:anel1:r7#state"}
161+
Switch anel1relay8state "Socket Terrace" {channel="anel:advanced-firmware:anel1:r8#state"}
162+
163+
// IO port names and states
164+
String anel1io1name "Anel1 IO1 name" {channel="anel:advanced-firmware:anel1:io1#name"}
165+
Switch anel1io1mode "Anel1 IO1 mode" {channel="anel:advanced-firmware:anel1:io1#mode"}
166+
Switch anel1io1state "Anel1 IO1" {channel="anel:advanced-firmware:anel1:io1#state"}
167+
Switch anel1io2state "Anel1 IO2" {channel="anel:advanced-firmware:anel1:io2#state"}
168+
Switch anel1io3state "Anel1 IO3" {channel="anel:advanced-firmware:anel1:io3#state"}
169+
Switch anel1io4state "Anel1 IO4" {channel="anel:advanced-firmware:anel1:io4#state"}
170+
Switch anel1io5state "Switch Bedroom" {channel="anel:advanced-firmware:anel1:io5#state"}
171+
Switch anel1io6state "Doorbell" {channel="anel:advanced-firmware:anel1:io6#state"}
172+
Switch anel1io7state "Switch Office" {channel="anel:advanced-firmware:anel1:io7#state"}
173+
Switch anel1io8state "Reed Contact Door" {channel="anel:advanced-firmware:anel1:io8#state"}
174+
```
175+
176+
`.sitemap` file:
177+
178+
```
179+
sitemap anel label="Anel NET-PwrCtrl" {
180+
Frame label="Device and Sensor" {
181+
Text item=anel1name label="Anel1 Name"
182+
Text item=anel1temperature label="Anel1 Temperature [%.1f °C]"
183+
Text item=anel1sensorTemperature label="Anel1 Sensor Temperature [%.1f °C]"
184+
Text item=anel1sensorHumidity label="Anel1 Sensor Humidity [%.1f]"
185+
Text item=anel1sensorBrightness label="Anel1 Sensor Brightness [%.1f]"
186+
}
187+
Frame label="Relays" {
188+
Text item=anel1relay1name label="Relay 1 name" labelcolor=[anel1relay1locked==ON="green",anel1relay1locked==OFF="maroon"]
189+
Switch item=anel1relay1state
190+
Switch item=anel1relay2state
191+
Switch item=anel1relay3state
192+
Switch item=anel1relay4state
193+
Switch item=anel1relay5state
194+
Switch item=anel1relay6state
195+
Switch item=anel1relay7state
196+
Switch item=anel1relay8state
197+
}
198+
Frame label="IO Ports" {
199+
Text item=anel1io1name label="IO 1 name" labelcolor=[anel1io1mode==OFF="green",anel1io1mode==ON="maroon"]
200+
Switch item=anel1io1state
201+
Switch item=anel1io2state
202+
Switch item=anel1io3state
203+
Switch item=anel1io4state
204+
Switch item=anel1io5state
205+
Switch item=anel1io6state
206+
Switch item=anel1io7state
207+
Switch item=anel1io8state
208+
}
209+
}
210+
```
211+
212+
The relay / IO port names are rarely useful because you probably set similar (static) labels for the state items.<br/>
213+
The locked state / IO mode is also rarely relevant in practice, because it typically doesn't change.
214+
215+
`.rules` file:
216+
217+
```
218+
rule "doorbell only at daytime"
219+
when Item anel1io6state changed then
220+
if (now.getHoursOfDay >= 6 && now.getHoursOfDay <= 22) {
221+
anel1relay6state.sendCommand(if (anel1io6state.state != ON) ON else OFF)
222+
}
223+
someNotificationItem.sendCommand("Someone just rang the doorbell")
224+
end
225+
```
226+
227+
228+
## Reference Documentation
229+
230+
The UDP protocol of Anel devices is explained [here](https://forum.anel.eu/viewtopic.php?f=16&t=207).
231+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<parent>
8+
<groupId>org.openhab.addons.bundles</groupId>
9+
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
10+
<version>3.2.0-SNAPSHOT</version>
11+
</parent>
12+
13+
<artifactId>org.openhab.binding.anel</artifactId>
14+
15+
<name>openHAB Add-ons :: Bundles :: Anel Binding</name>
16+
17+
</project>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<features name="org.openhab.binding.anel-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
3+
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
4+
5+
<feature name="openhab-binding-anel" description="Anel Binding" version="${project.version}">
6+
<feature>openhab-runtime-base</feature>
7+
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.anel/${project.version}</bundle>
8+
</feature>
9+
</features>
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/**
2+
* Copyright (c) 2010-2021 Contributors to the openHAB project
3+
*
4+
* See the NOTICE file(s) distributed with this work for additional
5+
* information.
6+
*
7+
* This program and the accompanying materials are made available under the
8+
* terms of the Eclipse Public License 2.0 which is available at
9+
* http://www.eclipse.org/legal/epl-2.0
10+
*
11+
* SPDX-License-Identifier: EPL-2.0
12+
*/
13+
package org.openhab.binding.anel.internal;
14+
15+
import org.eclipse.jdt.annotation.NonNullByDefault;
16+
import org.eclipse.jdt.annotation.Nullable;
17+
18+
/**
19+
* The {@link AnelConfiguration} class contains fields mapping thing configuration parameters.
20+
*
21+
* @author Patrick Koenemann - Initial contribution
22+
*/
23+
@NonNullByDefault
24+
public class AnelConfiguration {
25+
26+
public @Nullable String hostname;
27+
public @Nullable String user;
28+
public @Nullable String password;
29+
/** Port to send data from openhab to device. */
30+
public int udpSendPort = IAnelConstants.DEFAULT_SEND_PORT;
31+
/** Openhab receives messages via this port from device. */
32+
public int udpReceivePort = IAnelConstants.DEFAULT_RECEIVE_PORT;
33+
34+
public AnelConfiguration() {
35+
}
36+
37+
public AnelConfiguration(@Nullable String hostname, @Nullable String user, @Nullable String password, int sendPort,
38+
int receivePort) {
39+
this.hostname = hostname;
40+
this.user = user;
41+
this.password = password;
42+
this.udpSendPort = sendPort;
43+
this.udpReceivePort = receivePort;
44+
}
45+
46+
@Override
47+
public String toString() {
48+
final StringBuilder builder = new StringBuilder();
49+
builder.append(getClass().getSimpleName());
50+
builder.append("[hostname=");
51+
builder.append(hostname);
52+
builder.append(",user=");
53+
builder.append(user);
54+
builder.append(",password=");
55+
builder.append(mask(password));
56+
builder.append(",udpSendPort=");
57+
builder.append(udpSendPort);
58+
builder.append(",udpReceivePort=");
59+
builder.append(udpReceivePort);
60+
builder.append("]");
61+
return builder.toString();
62+
}
63+
64+
private @Nullable String mask(@Nullable String string) {
65+
return string == null ? null : string.replaceAll(".", "X");
66+
}
67+
}

0 commit comments

Comments
 (0)