]> git.basschouten.com Git - openhab-addons.git/commitdiff
[ekey] initial contribution / oh1 migration (#10996)
authorHans-Jörg Merk <github@hmerk.de>
Tue, 12 Oct 2021 19:15:14 +0000 (21:15 +0200)
committerGitHub <noreply@github.com>
Tue, 12 Oct 2021 19:15:14 +0000 (21:15 +0200)
* [ekey] initial contribution / oh1 migration

Signed-off-by: Hans-Jörg Merk <github@hmerk.de>
19 files changed:
CODEOWNERS
bom/openhab-addons/pom.xml
bundles/org.openhab.binding.ekey/NOTICE [new file with mode: 0644]
bundles/org.openhab.binding.ekey/README.md [new file with mode: 0644]
bundles/org.openhab.binding.ekey/pom.xml [new file with mode: 0644]
bundles/org.openhab.binding.ekey/src/main/feature/feature.xml [new file with mode: 0644]
bundles/org.openhab.binding.ekey/src/main/java/org/openhab/binding/ekey/internal/EkeyBindingConstants.java [new file with mode: 0644]
bundles/org.openhab.binding.ekey/src/main/java/org/openhab/binding/ekey/internal/EkeyConfiguration.java [new file with mode: 0644]
bundles/org.openhab.binding.ekey/src/main/java/org/openhab/binding/ekey/internal/EkeyDynamicStateDescriptionProvider.java [new file with mode: 0644]
bundles/org.openhab.binding.ekey/src/main/java/org/openhab/binding/ekey/internal/EkeyHandlerFactory.java [new file with mode: 0644]
bundles/org.openhab.binding.ekey/src/main/java/org/openhab/binding/ekey/internal/api/EkeyPacketListener.java [new file with mode: 0644]
bundles/org.openhab.binding.ekey/src/main/java/org/openhab/binding/ekey/internal/api/EkeyUdpPacketReceiver.java [new file with mode: 0644]
bundles/org.openhab.binding.ekey/src/main/java/org/openhab/binding/ekey/internal/handler/EkeyHandler.java [new file with mode: 0644]
bundles/org.openhab.binding.ekey/src/main/resources/OH-INF/binding/binding.xml [new file with mode: 0644]
bundles/org.openhab.binding.ekey/src/main/resources/OH-INF/i18n/ekey.properties [new file with mode: 0644]
bundles/org.openhab.binding.ekey/src/main/resources/OH-INF/i18n/ekey_de.properties [new file with mode: 0644]
bundles/org.openhab.binding.ekey/src/main/resources/OH-INF/thing/dynamic-channels.xml [new file with mode: 0644]
bundles/org.openhab.binding.ekey/src/main/resources/OH-INF/thing/thing-types.xml [new file with mode: 0644]
bundles/pom.xml

index e95e3a802299a776673c33e41a3b85594509f220..d1e56d4ea753885ec4c4f245737eb7780425adf3 100644 (file)
@@ -74,6 +74,7 @@
 /bundles/org.openhab.binding.dwdunwetter/ @limdul79
 /bundles/org.openhab.binding.ecobee/ @mhilbush
 /bundles/org.openhab.binding.ecotouch/ @sibbi77
+/bundles/org.openhab.binding.ekey/ @hmerk
 /bundles/org.openhab.binding.elerotransmitterstick/ @vbier
 /bundles/org.openhab.binding.energenie/ @hmerk
 /bundles/org.openhab.binding.enigma2/ @gdolfen
index c86eafdcd7a819ffea3b0eeb3b88806725cc4efc..9e4a4b9d41cba2eb07a2fb3834d66bff17d955ec 100644 (file)
       <artifactId>org.openhab.binding.ecotouch</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.openhab.addons.bundles</groupId>
+      <artifactId>org.openhab.binding.ekey</artifactId>
+      <version>${project.version}</version>
+    </dependency>
     <dependency>
       <groupId>org.openhab.addons.bundles</groupId>
       <artifactId>org.openhab.binding.elerotransmitterstick</artifactId>
diff --git a/bundles/org.openhab.binding.ekey/NOTICE b/bundles/org.openhab.binding.ekey/NOTICE
new file mode 100644 (file)
index 0000000..38d625e
--- /dev/null
@@ -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
diff --git a/bundles/org.openhab.binding.ekey/README.md b/bundles/org.openhab.binding.ekey/README.md
new file mode 100644 (file)
index 0000000..5bb649b
--- /dev/null
@@ -0,0 +1,135 @@
+# ekey Binding\r
+\r
+This binding connects to [ekey](https://ekey.net/) converter UDP (CV-LAN) using the RARE/MULTI/HOME protocols.\r
+\r
+## Supported Things\r
+\r
+This binding only supports one thing type:\r
+\r
+| Thing       | Thing Type | Description                                 |\r
+|-------------|------------|---------------------------------------------|\r
+| cvlan | Thing      | Represents a single ekey converter UDP |\r
+\r
+## Thing Configuration\r
+\r
+The binding uses the following configuration parameters.\r
+\r
+| Parameter | Description                                                    |\r
+|-----------|----------------------------------------------------------------|\r
+| ipAddress | IPv4 address of the eKey udp converter.  A static IP address is recommended.|\r
+| port      | The port as configured during the UDP Converter configuration.  e.g. 56000 (Binding default)     |\r
+| protocol  | Can be RARE, MULTI or HOME depending on what the system supports. Binding defaults to RARE  |\r
+| delimiter | The delimiter is also defined on the ekey UDP converter - use the ekey configuration software to determine which delimiter is used or to change it.  Binding default is `_` (underscore)  |\r
+\r
+## Channels\r
+\r
+| Channel ID | Item Type | Protocol | Description                                                                                                                                                                                                                                           | Possible Values                      |\r
+|------------|-----------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------|\r
+| action     | Number    | R/M/H    | This indicates whether access was granted (value=0) or denied (value=-1).                                                                                                                                                                             | 0,-1 (136 and 137 with RARE protocol |\r
+| fingerId   | Number    | R/M/H    | This indicates the finger that was used by a person.                                                                                                                                                                                                  | 0-9,-1                               |\r
+| fsName     | String    | M        | This returns the 4-character-long name that was specified on the controller for the specific terminals.                                                                                                                                               |                                      |\r
+| fsSerial     | Number    | R/M/H        | This returns the serial number for the specific terminal.                                     |\r
+| inputId    | Number    | M        | This indicates which of the four digital inputs was triggered. Value is number of Input. "-1" indicates that no input was triggered.                                                                                                                  | 0-4,-1                               |\r
+| keyId      | Number    | M        | This indicates which of the four keys was used. See ekey documentation on "keys".                                                                                                                                                                     | 0-4,-1                               |\r
+| relayId    | Number    | R/H      | This indicates which relay has been switched.                                                                                                                                                                                                         | 0-3,-1                               |\r
+| termId     | Number    | R        | This provides the serial number of the packet source. The source can be a fingerprint terminal or the controller (in case of digital inputs). The Serial number has a length of 13. When using RARE mode, only the trailing 8 digits can be returned. |                                      |\r
+| userId     | Number    | R/M/H    | This indicates which user has been detected on the terminal. The value is the numerical order of the user as it was specified on the controller.                                                                                                      | 0-99,-1                              |\r
+| userName   | String    | M        | This returns the ten-character-long name of the person that has been recognized on the terminal. The name that is returned must have been previously specified on the controller.                                                                     |                                      |\r
+| userStatus | Number    | M        | This indicates the status of the user (-1=undefined, 1=enabled, 0= disabled)                                                                                                                                                                          | 0,1,-1                               |\r
+\r
+## Examples\r
+\r
+example.things\r
+\r
+```\r
+Thing ekey:cvlan:de3b8db06e "Ekey Udp Converter" @ "Control Panel" [ ipAddress="xxx.xxx.xxx.xxx", port="56000", protocol="RARE", delimiter="_" ]\r
+```\r
+\r
+rare.items\r
+\r
+```\r
+Number Action "Last action [MAP(ekey_action.map):%d]"                          { channel="ekey:cvlan:de3b8db06e:action" }\r
+Number FingerID "User used finger [MAP(ekey_finger.map):%d]"                   { channel="ekey:cvlan:de3b8db06e:fingerId" }\r
+Number RelayID "Last relay that has been swiched [%d]"                         { channel="ekey:cvlan:de3b8db06e:relayId" }\r
+Number Serialnumber "Serialnumber [%d]"                                        { channel="ekey:cvlan:de3b8db06e:fsSerial" }\r
+Number TerminalID "Last used terminal [MAP(ekey_terminal.map):%d]"             { channel="ekey:cvlan:de3b8db06e:termId" }\r
+Number UserID "Last user that accessed the house was [MAP(ekey_names.map):%d]" { channel="ekey:cvlan:de3b8db06e:userId" }\r
+```\r
+\r
+multi.items\r
+\r
+```\r
+Number Action "Last action [MAP(ekey_action.map):%d]"                          { channel="ekey:cvlan:de3b8db06e:action" }\r
+Number FingerID "User used finger [MAP(ekey_finger.map):%d]"                   { channel="ekey:cvlan:de3b8db06e:fingerId" }\r
+String FsName "Name of Scanner [%s]                                            { channel="ekey:cvlan:de3b8db06e:fsName" }\r
+Number FsSerial "Serialnumber [%d]"                                            { channel="ekey:cvlan:de3b8db06e:fsSerial" }\r
+Number InputID "Last input that has been triggered [%d]"                       { channel="ekey:cvlan:de3b8db06e:inputId" }\r
+Number KeyID  "Last key that has been used [%d]"                               { channel="ekey:cvlan:de3b8db06e:keyId" }\r
+Number UserID "Last user that accessed the house was [MAP(ekey_names.map):%d]" { channel="ekey:cvlan:de3b8db06e:userId" }\r
+String UserName " Name of Last user that accessed the house was : [%d]"        { channel="ekey:cvlan:de3b8db06e:userName" }\r
+Number UserStatus "Last user that accessed the house was [MAP(ekey_names.map):%d]" { channel="ekey:cvlan:de3b8db06e:userStatus" }\r
+```\r
+\r
+home.items\r
+\r
+```\r
+Number Action "Last action [MAP(ekey_action.map):%d]"                          { channel="ekey:cvlan:de3b8db06e:action" }\r
+Number FingerID "User used finger [MAP(ekey_finger.map):%d]"                   { channel="ekey:cvlan:de3b8db06e:fingerId" }\r
+Number RelayID "Last relay that has been swiched [%d]"                         { channel="ekey:cvlan:de3b8db06e:relayId" }\r
+Number Serialnumber "Serialnumber [%d]"                                        { channel="ekey:cvlan:de3b8db06e:fsSerial" }\r
+Number UserID "Last user that accessed the house was [MAP(ekey_names.map):%d]" { channel="ekey:cvlan:de3b8db06e:userId" }\r
+```\r
+\r
+transform/ekey_finger.map [This is just an example, as there is no strict rule what finger belongs to what number]\r
+\r
+```javascript\r
+0=leftlittle\r
+1=leftring\r
+2=leftmiddle\r
+3=leftindex\r
+4=leftthumb\r
+5=rightthumb\r
+6=rightindex\r
+7=rightmiddle\r
+8=rightring\r
+9=rightlittle\r
+-1=unknown\r
+```\r
+\r
+transform/ekey_names.map [NO spaces allowed]\r
+\r
+```javascript\r
+-1=Unspecified\r
+1=JohnDoe\r
+2=JaneDoe\r
+```\r
+\r
+transform/ekey_terminal.map\r
+\r
+```javascript\r
+80156839130911=Front\r
+80156839130914=Back\r
+```\r
+\r
+transform/ekey_multi_action.map\r
+\r
+```javascript\r
+0=granted\r
+-1=rejected\r
+1=timeoutA\r
+2=timeoutB\r
+3=inactive\r
+4=alwaysuser\r
+5=notcoupled\r
+6=digitalinput\r
+```\r
+\r
+transform/ekey_rare_action.map\r
+\r
+```javascript\r
+136=granted\r
+137=rejected\r
+```\r
+\r
+\r
+\r
diff --git a/bundles/org.openhab.binding.ekey/pom.xml b/bundles/org.openhab.binding.ekey/pom.xml
new file mode 100644 (file)
index 0000000..c7682fb
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+  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.ekey</artifactId>
+
+  <name>openHAB Add-ons :: Bundles :: Ekey Binding</name>
+
+</project>
diff --git a/bundles/org.openhab.binding.ekey/src/main/feature/feature.xml b/bundles/org.openhab.binding.ekey/src/main/feature/feature.xml
new file mode 100644 (file)
index 0000000..6281b97
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<features name="org.openhab.binding.ekey-${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-ekey" description="Ekey Binding" version="${project.version}">
+               <feature>openhab-runtime-base</feature>
+               <bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.ekey/${project.version}</bundle>
+       </feature>
+</features>
diff --git a/bundles/org.openhab.binding.ekey/src/main/java/org/openhab/binding/ekey/internal/EkeyBindingConstants.java b/bundles/org.openhab.binding.ekey/src/main/java/org/openhab/binding/ekey/internal/EkeyBindingConstants.java
new file mode 100644 (file)
index 0000000..4d18a92
--- /dev/null
@@ -0,0 +1,47 @@
+/**
+ * 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.ekey.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.core.thing.ThingTypeUID;
+
+/**
+ * The {@link EkeyBindingConstants} class defines common constants, which are
+ * used across the whole binding.
+ *
+ * @author Hans-Jörg Merk - Initial contribution
+ */
+@NonNullByDefault
+public class EkeyBindingConstants {
+
+    public static final String BINDING_ID = "ekey";
+
+    // List of all Thing Type UIDs
+    public static final ThingTypeUID THING_TYPE_CVLAN = new ThingTypeUID(BINDING_ID, "cvlan");
+
+    // List of all Channel ids
+    public static final String CHANNEL_TYPE_USERID = "userId";
+    public static final String CHANNEL_TYPE_USERNAME = "userName";
+    public static final String CHANNEL_TYPE_USERSTATUS = "userStatus";
+    public static final String CHANNEL_TYPE_FINGERID = "fingerId";
+    public static final String CHANNEL_TYPE_KEYID = "keyId";
+    public static final String CHANNEL_TYPE_FSSERIAL = "fsSerial";
+    public static final String CHANNEL_TYPE_FSNAME = "fsName";
+    public static final String CHANNEL_TYPE_ACTION = "action";
+    public static final String CHANNEL_TYPE_INPUTID = "inputId";
+    public static final String CHANNEL_TYPE_RELAYID = "relayId";
+    public static final String CHANNEL_TYPE_TERMID = "termId";
+    public static final String CHANNEL_TYPE_RESERVED = "relayId";
+    public static final String CHANNEL_TYPE_EVENT = "event";
+    public static final String CHANNEL_TYPE_TIMESTAMP = "timestamp";
+}
diff --git a/bundles/org.openhab.binding.ekey/src/main/java/org/openhab/binding/ekey/internal/EkeyConfiguration.java b/bundles/org.openhab.binding.ekey/src/main/java/org/openhab/binding/ekey/internal/EkeyConfiguration.java
new file mode 100644 (file)
index 0000000..ae7f029
--- /dev/null
@@ -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.ekey.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link EkeyConfiguration} class contains fields mapping thing configuration parameters.
+ *
+ * @author Hans-Jörg Merk - Initial contribution
+ */
+@NonNullByDefault
+public class EkeyConfiguration {
+
+    public String ipAddress = "";
+    public int port;
+    public String protocol = "";
+    public String delimiter = "";
+}
diff --git a/bundles/org.openhab.binding.ekey/src/main/java/org/openhab/binding/ekey/internal/EkeyDynamicStateDescriptionProvider.java b/bundles/org.openhab.binding.ekey/src/main/java/org/openhab/binding/ekey/internal/EkeyDynamicStateDescriptionProvider.java
new file mode 100644 (file)
index 0000000..b64f24f
--- /dev/null
@@ -0,0 +1,41 @@
+/**
+ * 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.ekey.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.core.events.EventPublisher;
+import org.openhab.core.thing.binding.BaseDynamicStateDescriptionProvider;
+import org.openhab.core.thing.i18n.ChannelTypeI18nLocalizationService;
+import org.openhab.core.thing.link.ItemChannelLinkRegistry;
+import org.openhab.core.thing.type.DynamicStateDescriptionProvider;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+
+/**
+ *
+ * @author Hans-Jörg Merk - Initial contribution
+ */
+@Component(service = { DynamicStateDescriptionProvider.class, EkeyDynamicStateDescriptionProvider.class })
+@NonNullByDefault
+public class EkeyDynamicStateDescriptionProvider extends BaseDynamicStateDescriptionProvider {
+
+    @Activate
+    public EkeyDynamicStateDescriptionProvider(final @Reference EventPublisher eventPublisher, //
+            final @Reference ItemChannelLinkRegistry itemChannelLinkRegistry, //
+            final @Reference ChannelTypeI18nLocalizationService channelTypeI18nLocalizationService) {
+        this.eventPublisher = eventPublisher;
+        this.itemChannelLinkRegistry = itemChannelLinkRegistry;
+        this.channelTypeI18nLocalizationService = channelTypeI18nLocalizationService;
+    }
+}
diff --git a/bundles/org.openhab.binding.ekey/src/main/java/org/openhab/binding/ekey/internal/EkeyHandlerFactory.java b/bundles/org.openhab.binding.ekey/src/main/java/org/openhab/binding/ekey/internal/EkeyHandlerFactory.java
new file mode 100644 (file)
index 0000000..832a6c0
--- /dev/null
@@ -0,0 +1,66 @@
+/**
+ * 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.ekey.internal;
+
+import static org.openhab.binding.ekey.internal.EkeyBindingConstants.THING_TYPE_CVLAN;
+
+import java.util.Set;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.binding.ekey.internal.handler.EkeyHandler;
+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.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+
+/**
+ * The {@link EkeyHandlerFactory} is responsible for creating things and thing
+ * handlers.
+ *
+ * @author Hans-Jörg Merk - Initial contribution
+ */
+@NonNullByDefault
+@Component(configurationPid = "binding.ekey", service = ThingHandlerFactory.class)
+public class EkeyHandlerFactory extends BaseThingHandlerFactory {
+
+    private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_CVLAN);
+
+    private final EkeyDynamicStateDescriptionProvider ekeyStateDescriptionProvider;
+
+    @Activate
+    public EkeyHandlerFactory(ComponentContext componentContext,
+            final @Reference EkeyDynamicStateDescriptionProvider dynamicStateDescriptionProvider) {
+        this.ekeyStateDescriptionProvider = dynamicStateDescriptionProvider;
+    }
+
+    @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 (THING_TYPE_CVLAN.equals(thingTypeUID)) {
+            return new EkeyHandler(thing, ekeyStateDescriptionProvider);
+        }
+        return null;
+    }
+}
diff --git a/bundles/org.openhab.binding.ekey/src/main/java/org/openhab/binding/ekey/internal/api/EkeyPacketListener.java b/bundles/org.openhab.binding.ekey/src/main/java/org/openhab/binding/ekey/internal/api/EkeyPacketListener.java
new file mode 100644 (file)
index 0000000..1aecf0a
--- /dev/null
@@ -0,0 +1,37 @@
+/**
+ * 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.ekey.internal.api;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.core.thing.ThingStatus;
+
+/**
+ * The {@link EkeyPacketListener} is in interface for a Ekey packet received consumer
+ *
+ * @author Hans-Jörg Merk - Initial contribution
+ */
+@NonNullByDefault
+public interface EkeyPacketListener {
+    /**
+     * This method will be called in case a message was received.
+     *
+     */
+    void messageReceived(byte[] message);
+
+    /**
+     * This method will be called in case the connection status has changed.
+     *
+     */
+    void connectionStatusChanged(ThingStatus status, byte @Nullable [] message);
+}
diff --git a/bundles/org.openhab.binding.ekey/src/main/java/org/openhab/binding/ekey/internal/api/EkeyUdpPacketReceiver.java b/bundles/org.openhab.binding.ekey/src/main/java/org/openhab/binding/ekey/internal/api/EkeyUdpPacketReceiver.java
new file mode 100644 (file)
index 0000000..5114ee2
--- /dev/null
@@ -0,0 +1,158 @@
+/**
+ * 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.ekey.internal.api;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.binding.ekey.internal.handler.EkeyHandler;
+import org.openhab.core.thing.ThingStatus;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This Class provides the DatagramSocket that listens for eKey packets on the network
+ * This will run in a thread and can be interrupted by calling <code>stopListener()<code>
+ * Before starting the thread initialization is required (mode, ip, port and deliminator)
+ *
+ * @author Hans-Jörg Merk - Initial contribution
+ */
+@NonNullByDefault
+public class EkeyUdpPacketReceiver {
+
+    private final Logger logger = LoggerFactory.getLogger(EkeyUdpPacketReceiver.class);
+
+    private final int buffersize = 1024;
+    private final String ipAddress;
+    private final int port;
+    private final String readerThreadName;
+
+    private @Nullable DatagramSocket socket;
+
+    private @Nullable EkeyPacketListener packetListener;
+
+    private boolean connected = false;
+
+    public EkeyUdpPacketReceiver(final String ipAddress, final int port, final String readerThreadName) {
+        this.ipAddress = ipAddress;
+        this.port = port;
+        this.readerThreadName = readerThreadName;
+    }
+
+    public void openConnection() throws IOException {
+        closeConnection();
+
+        EkeyPacketListener listener = this.packetListener;
+
+        socket = new DatagramSocket(port);
+
+        Thread udpListener = new Thread(new UDPListener());
+        udpListener.setName(readerThreadName);
+        udpListener.setDaemon(true);
+        udpListener.start();
+
+        setConnected(true);
+        if (listener != null) {
+            listener.connectionStatusChanged(ThingStatus.ONLINE, null);
+        }
+    }
+
+    public void closeConnection() {
+        setConnected(false);
+        try {
+            DatagramSocket localSocket = socket;
+            if (localSocket != null) {
+                localSocket.close();
+                localSocket = null;
+            }
+        } catch (Exception exception) {
+            logger.debug("closeConnection(): Error closing connection - {}", exception.getMessage());
+        }
+    }
+
+    private class UDPListener implements Runnable {
+
+        /**
+         * Run method. Runs the MessageListener thread
+         */
+        @Override
+        public void run() {
+            logger.debug("Starting ekey Packet Receiver");
+
+            DatagramSocket localSocket = socket;
+
+            if (localSocket == null) {
+                throw new IllegalStateException("Cannot access socket.");
+            }
+
+            byte[] lastPacket = null;
+            DatagramPacket packet = new DatagramPacket(new byte[buffersize], buffersize);
+            packet.setData(new byte[buffersize]);
+
+            while (isConnected()) {
+                try {
+                    logger.trace("Listen for incoming packet");
+                    localSocket.receive(packet);
+                    logger.trace("Packet received - {}", packet.getData());
+                } catch (IOException exception) {
+                    logger.debug("Exception during packet read - {}", exception.getMessage());
+                }
+                InetAddress sourceIp;
+                try {
+                    sourceIp = InetAddress.getByName(ipAddress);
+                    if (packet.getAddress().equals(sourceIp)) {
+                        lastPacket = packet.getData();
+                        readMessage(lastPacket);
+                    } else {
+                        logger.warn("Packet received from unknown source- {}", packet.getData());
+                    }
+                } catch (UnknownHostException e) {
+                    logger.debug("Exception during address conversion - {}", e.getMessage());
+                }
+            }
+        }
+    }
+
+    public void readMessage(byte[] message) {
+        EkeyPacketListener listener = this.packetListener;
+
+        if (listener != null && message.length != 0) {
+            listener.messageReceived(message);
+        }
+    }
+
+    public void addEkeyPacketListener(EkeyPacketListener listener) {
+        if (this.packetListener == null) {
+            this.packetListener = listener;
+        }
+    }
+
+    public void setConnected(boolean connected) {
+        this.connected = connected;
+    }
+
+    public boolean isConnected() {
+        return this.connected;
+    }
+
+    public void removeEkeyPacketListener(EkeyHandler ekeyHandler) {
+        if (this.packetListener != null) {
+            this.packetListener = null;
+        }
+    }
+}
diff --git a/bundles/org.openhab.binding.ekey/src/main/java/org/openhab/binding/ekey/internal/handler/EkeyHandler.java b/bundles/org.openhab.binding.ekey/src/main/java/org/openhab/binding/ekey/internal/handler/EkeyHandler.java
new file mode 100644 (file)
index 0000000..7bfc719
--- /dev/null
@@ -0,0 +1,364 @@
+/**
+ * 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.ekey.internal.handler;
+
+import static org.openhab.binding.ekey.internal.EkeyBindingConstants.*;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.binding.ekey.internal.EkeyConfiguration;
+import org.openhab.binding.ekey.internal.EkeyDynamicStateDescriptionProvider;
+import org.openhab.binding.ekey.internal.api.EkeyPacketListener;
+import org.openhab.binding.ekey.internal.api.EkeyUdpPacketReceiver;
+import org.openhab.core.library.types.DecimalType;
+import org.openhab.core.library.types.StringType;
+import org.openhab.core.thing.Channel;
+import org.openhab.core.thing.ChannelUID;
+import org.openhab.core.thing.Thing;
+import org.openhab.core.thing.ThingStatus;
+import org.openhab.core.thing.ThingStatusDetail;
+import org.openhab.core.thing.binding.BaseThingHandler;
+import org.openhab.core.thing.binding.builder.ChannelBuilder;
+import org.openhab.core.thing.binding.builder.ThingBuilder;
+import org.openhab.core.thing.type.ChannelKind;
+import org.openhab.core.thing.type.ChannelTypeUID;
+import org.openhab.core.types.Command;
+import org.openhab.core.types.State;
+import org.openhab.core.types.StateOption;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@link EkeyHandler} is responsible for handling commands, which are
+ * sent to one of the channels.
+ *
+ * @author Hans-Jörg Merk - Initial contribution
+ */
+@NonNullByDefault
+public class EkeyHandler extends BaseThingHandler implements EkeyPacketListener {
+
+    private final Logger logger = LoggerFactory.getLogger(EkeyHandler.class);
+
+    private final EkeyDynamicStateDescriptionProvider ekeyStateDescriptionProvider;
+
+    private EkeyConfiguration config = new EkeyConfiguration();
+    private @Nullable EkeyUdpPacketReceiver receiver;
+
+    public EkeyHandler(Thing thing, EkeyDynamicStateDescriptionProvider ekeyStateDescriptionProvider) {
+        super(thing);
+        this.ekeyStateDescriptionProvider = ekeyStateDescriptionProvider;
+    }
+
+    @Override
+    public void handleCommand(ChannelUID channelUID, Command command) {
+        // The binding does not handle any command
+    }
+
+    @Override
+    public void initialize() {
+        logger.debug("ekey handler initializing");
+        config = getConfigAs(EkeyConfiguration.class);
+
+        if (!config.ipAddress.isEmpty() && config.port != 0) {
+            updateStatus(ThingStatus.UNKNOWN);
+
+            scheduler.submit(() -> {
+                populateChannels(config.protocol);
+                String readerThreadName = "OH-binding-" + getThing().getUID().getAsString();
+
+                EkeyUdpPacketReceiver localReceiver = receiver = new EkeyUdpPacketReceiver(config.ipAddress,
+                        config.port, readerThreadName);
+                localReceiver.addEkeyPacketListener(this);
+                try {
+                    localReceiver.openConnection();
+                } catch (IOException e) {
+                    updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Cannot open connection)");
+                }
+                updateStatus(ThingStatus.ONLINE);
+            });
+        } else {
+            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "No IP address specified)");
+        }
+    }
+
+    @Override
+    public void dispose() {
+        EkeyUdpPacketReceiver localReceiver = this.receiver;
+
+        if (localReceiver != null) {
+            localReceiver.closeConnection();
+            localReceiver.removeEkeyPacketListener(this);
+        }
+        super.dispose();
+    }
+
+    @Override
+    public void messageReceived(byte[] message) {
+        logger.debug("messageReceived() : {}", message);
+        config = getConfigAs(EkeyConfiguration.class);
+        String delimiter = config.delimiter;
+
+        switch (config.protocol) {
+            case "RARE":
+                parseRare(message, delimiter);
+                break;
+            case "MULTI":
+                parseMulti(message, delimiter);
+                break;
+            case "HOME":
+                parseHome(message, delimiter);
+                break;
+        }
+    }
+
+    @Override
+    public void connectionStatusChanged(ThingStatus status, byte @Nullable [] message) {
+        if (message != null) {
+            this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, null);
+        }
+        this.updateStatus(status);
+    }
+
+    public void parseRare(byte[] message, String delimiter) {
+        logger.debug("parse RARE packet");
+        if (message.length >= 72) {
+            byte[] newMessage = Arrays.copyOf(message, 72);
+            String messageString = new String(newMessage);
+            long action = getIntValueFrom(newMessage, 4, 4);
+            long terminalid = getIntValueFrom(newMessage, 8, 4);
+            String terminalSerial = getStringValueFrom(newMessage, 12, 14);
+            long relayid = getIntValueFrom(newMessage, 26, 1);
+            long userid = getIntValueFrom(newMessage, 28, 4);
+            long fingerid = getIntValueFrom(newMessage, 32, 4);
+            int serial = reconstructFsSerial(terminalid);
+            if (logger.isTraceEnabled()) {
+                logger.trace("messageString received() : {}", messageString);
+                logger.trace("AKTION           : {}", action);
+                logger.trace("TERMINAL SERIAL  : {}", terminalSerial);
+                logger.trace("RESERVED         : {}", getStringValueFrom(newMessage, 27, 1));
+                logger.trace("RELAY ID         : {}", relayid);
+                logger.trace("USER ID          : {}", userid);
+                logger.trace("FINGER ID        : {}", fingerid);
+                logger.trace("EVENT            : {}", getStringValueFrom(newMessage, 36, 16));
+                logger.trace("FS SERIAL        : {}", serial);
+            }
+            updateState(CHANNEL_TYPE_ACTION, new DecimalType(action));
+            if (!terminalSerial.isEmpty()) {
+                updateState(CHANNEL_TYPE_TERMID, DecimalType.valueOf(terminalSerial));
+            } else {
+                updateState(CHANNEL_TYPE_TERMID, DecimalType.valueOf("-1"));
+            }
+            updateState(CHANNEL_TYPE_RESERVED, StringType.valueOf(getStringValueFrom(newMessage, 27, 1)));
+            updateState(CHANNEL_TYPE_RELAYID, new DecimalType(relayid));
+            updateState(CHANNEL_TYPE_USERID, new DecimalType(userid));
+            updateState(CHANNEL_TYPE_FINGERID, new DecimalType(fingerid));
+            updateState(CHANNEL_TYPE_EVENT, StringType.valueOf(getStringValueFrom(newMessage, 36, 16)));
+            updateState(CHANNEL_TYPE_FSSERIAL, new DecimalType(serial));
+
+        }
+    }
+
+    public void parseMulti(byte[] message, String delimiter) {
+        logger.debug("parse MULTI packet");
+        if (message.length >= 46) {
+            byte[] newMessage = Arrays.copyOf(message, 46);
+            String messageString = new String(newMessage);
+            String[] array = messageString.split(delimiter);
+            if (logger.isTraceEnabled()) {
+                logger.trace("messageString received() : {}", messageString);
+                logger.trace("USER ID     : {}", array[1]);
+                logger.trace("USER ID     : {}", array[1]);
+                logger.trace("USER NAME   : {}", array[2]);
+                logger.trace("USER STATUS : {}", array[3]);
+                logger.trace("FINGER ID   : {}", array[4]);
+                logger.trace("KEY ID      : {}", array[5]);
+                logger.trace("SERIENNR FS : {}", array[6]);
+                logger.trace("NAME FS     : {}", new String(array[7]).replace("-", ""));
+                logger.trace("AKTION      : {}", array[8]);
+                logger.trace("INPUT ID    : {}", array[9]);
+
+            }
+            if (!"-".equals(array[1])) {
+                updateState(CHANNEL_TYPE_USERID, DecimalType.valueOf((array[1])));
+            } else {
+                updateState(CHANNEL_TYPE_USERID, DecimalType.valueOf("-1"));
+            }
+            String userName = (array[2]).toString();
+            if (!userName.isEmpty()) {
+                userName = userName.replace("-", "");
+                userName = userName.replace(" ", "");
+                updateState(CHANNEL_TYPE_USERNAME, StringType.valueOf(userName));
+            }
+            if (!"-".equals(array[3])) {
+                updateState(CHANNEL_TYPE_USERSTATUS, DecimalType.valueOf((array[3])));
+            } else {
+                updateState(CHANNEL_TYPE_USERSTATUS, DecimalType.valueOf("-1"));
+            }
+            if (!"-".equals(array[4])) {
+                updateState(CHANNEL_TYPE_FINGERID, DecimalType.valueOf((array[4])));
+            } else {
+                updateState(CHANNEL_TYPE_FINGERID, DecimalType.valueOf("-1"));
+            }
+            if (!"-".equals(array[5])) {
+                updateState(CHANNEL_TYPE_KEYID, DecimalType.valueOf((array[5])));
+            } else {
+                updateState(CHANNEL_TYPE_KEYID, DecimalType.valueOf("-1"));
+            }
+            updateState(CHANNEL_TYPE_FSSERIAL, DecimalType.valueOf((array[6])));
+            updateState(CHANNEL_TYPE_FSNAME, new StringType(new String(array[7]).replace("-", "")));
+            updateState(CHANNEL_TYPE_ACTION, DecimalType.valueOf((array[8])));
+            if (!"-".equals(array[9])) {
+                updateState(CHANNEL_TYPE_INPUTID, DecimalType.valueOf((array[9])));
+            } else {
+                updateState(CHANNEL_TYPE_INPUTID, DecimalType.valueOf("-1"));
+            }
+        } else {
+            logger.trace("received packet is to short : {}", message);
+        }
+    }
+
+    public void parseHome(byte[] message, String delimiter) {
+        logger.debug("parse HOME packet");
+        if (message.length >= 27) {
+            byte[] newMessage = Arrays.copyOf(message, 27);
+            String messageString = new String(newMessage);
+            String[] array = messageString.split(delimiter);
+            if (logger.isTraceEnabled()) {
+                logger.trace("messageString received() : {}", messageString);
+                logger.trace("USER ID     : {}", array[1]);
+                logger.trace("FINGER ID   : {}", array[2]);
+                logger.trace("SERIENNR FS : {}", array[3]);
+                logger.trace("AKTION      : {}", array[4]);
+                logger.trace("RELAY ID    : {}", array[5]);
+            }
+            if (!"-".equals(array[1])) {
+                updateState(CHANNEL_TYPE_USERID, DecimalType.valueOf((array[1])));
+            } else {
+                updateState(CHANNEL_TYPE_USERID, DecimalType.valueOf("-1"));
+            }
+            if (!"-".equals(array[2])) {
+                updateState(CHANNEL_TYPE_FINGERID, DecimalType.valueOf((array[2])));
+            } else {
+                updateState(CHANNEL_TYPE_FINGERID, DecimalType.valueOf("-1"));
+            }
+            updateState(CHANNEL_TYPE_FSSERIAL, DecimalType.valueOf((array[3])));
+            updateState(CHANNEL_TYPE_ACTION, DecimalType.valueOf((array[4])));
+            if (!"-".equals(array[5])) {
+                State relayId = DecimalType.valueOf((array[5]));
+                updateState(CHANNEL_TYPE_RELAYID, relayId);
+            } else {
+                updateState(CHANNEL_TYPE_RELAYID, DecimalType.valueOf("-1"));
+            }
+        } else {
+            logger.trace("received packet is to short : {}", message);
+        }
+    }
+
+    public void addChannel(String channelId, String itemType, @Nullable final Collection<String> options) {
+        if (thing.getChannel(channelId) == null) {
+            logger.debug("Channel '{}' for UID to be added", channelId);
+            ThingBuilder thingBuilder = editThing();
+            final ChannelTypeUID channelTypeUID = new ChannelTypeUID(BINDING_ID, channelId);
+            Channel channel = ChannelBuilder.create(new ChannelUID(getThing().getUID(), channelId), itemType)
+                    .withType(channelTypeUID).withKind(ChannelKind.STATE).build();
+            thingBuilder.withChannel(channel);
+            updateThing(thingBuilder.build());
+        }
+        if (options != null) {
+            final List<StateOption> stateOptions = options.stream()
+                    .map(e -> new StateOption(e, e.substring(0, 1) + e.substring(1).toLowerCase()))
+                    .collect(Collectors.toList());
+            logger.debug("StateOptions : '{}'", stateOptions);
+            ekeyStateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), channelId), stateOptions);
+        }
+    }
+
+    public void populateChannels(String protocol) {
+        String channelId = "";
+        String itemType = "Number";
+
+        switch (protocol) {
+            case "HOME":
+                channelId = CHANNEL_TYPE_RELAYID;
+                addChannel(channelId, itemType, null);
+                break;
+            case "MULTI":
+                channelId = CHANNEL_TYPE_USERNAME;
+                addChannel(channelId, "String", null);
+                channelId = CHANNEL_TYPE_USERSTATUS;
+                addChannel(channelId, itemType, null);
+                channelId = CHANNEL_TYPE_KEYID;
+                addChannel(channelId, itemType, null);
+                channelId = CHANNEL_TYPE_FSNAME;
+                addChannel(channelId, "String", null);
+                channelId = CHANNEL_TYPE_INPUTID;
+                addChannel(channelId, itemType, null);
+                break;
+            case "RARE":
+                channelId = CHANNEL_TYPE_TERMID;
+                addChannel(channelId, itemType, null);
+                channelId = CHANNEL_TYPE_RELAYID;
+                addChannel(channelId, itemType, null);
+                channelId = CHANNEL_TYPE_RESERVED;
+                addChannel(channelId, "String", null);
+                channelId = CHANNEL_TYPE_EVENT;
+                addChannel(channelId, "String", null);
+                break;
+        }
+    }
+
+    private long getIntValueFrom(byte[] bytes, int start, int length) {
+        if (start + length > bytes.length) {
+            return -1;
+        }
+        long value = 0;
+        int bits = 0;
+        for (int i = start; i < start + length; i++) {
+            value |= (bytes[i] & 0xFF) << bits;
+            bits += 8;
+        }
+        return value;
+    }
+
+    private String getStringValueFrom(byte[] bytes, int start, int length) {
+        if (start + length > bytes.length) {
+            logger.debug("Could not get String from bytes");
+            return "";
+        }
+        StringBuffer value = new StringBuffer();
+        for (int i = start + length - 1; i >= start; i--) {
+            if (bytes[i] > (byte) ' ' && bytes[i] < (byte) '~') {
+                value.append((char) bytes[i]);
+            }
+        }
+        return value.toString();
+    }
+
+    private int reconstructFsSerial(long termID) {
+        long s = termID;
+        s ^= 0x70000000;
+        int ssss = (int) (s & 0xFFFF);
+        s >>= 16;
+        int yy = (int) s % 53;
+        int ww = (int) s / 53;
+        yy *= 1000000;
+        ww *= 10000;
+        return ww + yy + ssss;
+    }
+}
diff --git a/bundles/org.openhab.binding.ekey/src/main/resources/OH-INF/binding/binding.xml b/bundles/org.openhab.binding.ekey/src/main/resources/OH-INF/binding/binding.xml
new file mode 100644 (file)
index 0000000..ad2d0f0
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<binding:binding id="ekey" 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>Ekey Binding</name>
+       <description>This is the binding for connecting openHAB to Ekey fingerprint scanners.</description>
+
+</binding:binding>
diff --git a/bundles/org.openhab.binding.ekey/src/main/resources/OH-INF/i18n/ekey.properties b/bundles/org.openhab.binding.ekey/src/main/resources/OH-INF/i18n/ekey.properties
new file mode 100644 (file)
index 0000000..ee012eb
--- /dev/null
@@ -0,0 +1,46 @@
+# binding
+binding.ekey.name = Ekey Binding
+binding.ekey.description = This Binding integrates Ekey CV-LAN UDP adapters
+
+# thing types
+thing-type.ekey.label = CV-LAN
+thing-type.ekey.description = CV-LAN UDP adapter
+
+# thing type config description
+thing-type.config.ekey.ipAddress.label = IP Address
+thing-type.config.ekey.ipAddress.description = IPv4 address of the eKey udp converter. A static IP address is recommended.
+thing-type.config.ekey.port.label = Port
+thing-type.config.ekey.port.description = The port as configured during the UDP Converter configuration. e.g. 56000
+thing-type.config.ekey.protocol.label = Protocol
+thing-type.config.ekey.protocol.description = Can be RARE, MULTI or HOME depending on what the system supports
+thing-type.config.ekey.delimiter.label = Delimiter
+thing-type.config.ekey.delimiter.description = The delimiter is also defined on the ekey UDP converter - use the ekey configuration software to determine which delimiter is used or to change it. Another option is _ (underscore)
+
+# channel types
+channel-type.ekey.userId.label = User ID
+channel-type.ekey.userId.description = This indicates which user has been detected on the terminal. The value is the numerical order of the user as it was specified on the controller.
+channel-type.ekey.userName.label = Username
+channel-type.ekey.userName.description = Returns the ten-character-long name of the person that has been recognized on the terminal
+channel-type.ekey.userStatus.label = User status
+channel-type.ekey.userStatus.description = Indicates the status of the user (-1=undefined, 1=enabled, 0= disabled)
+channel-type.ekey.fingerId.label = Finger ID
+channel-type.ekey.fingerId.description = Indicates which finger has been detected on the terminal. (0-9,-1)
+channel-type.ekey.keyId.label = Key ID
+channel-type.ekey.keyId.description = Indicates which of the four keys was used. See ekey documentation on "keys".
+channel-type.ekey.fsSerial.label = Serialnumber
+channel-type.ekey.fsSerial.description = This returns the 4-character-long name that was specified on the controller for the specific terminals
+channel-type.ekey.fsName.label = Terminal Name
+channel-type.ekey.fsName.description = This returns the terminal name
+channel-type.ekey.action.label = Action
+channel-type.ekey.action.description = Indicates whether access was granted (value=0) or denied (value=-1). According to the ekey documentation there are six more values possible
+channel-type.ekey.inputId.label = Input ID
+channel-type.ekey.inputId.description = Indicates which of the four digital inputs was triggered. Value is number of Input. "-1" indicates that no input was triggered.
+channel-type.ekey.relayId.label = Relay ID
+channel-type.ekey.relayId.description = Indicates which relay has been switched.
+channel-type.ekey.termId.label = Terminal ID
+channel-type.ekey.termId.description = This provides the serial number of the packet source. The source can be a fingerprint terminal or the controller (in case of digital inputs). The Serial number has a length of 13. 
+channel-type.ekey.reserved.label = Reserved
+channel-type.ekey.reserved.description = Reserved
+channel-type.ekey.event.label = Event
+channel-type.ekey.event.description = Event
+
diff --git a/bundles/org.openhab.binding.ekey/src/main/resources/OH-INF/i18n/ekey_de.properties b/bundles/org.openhab.binding.ekey/src/main/resources/OH-INF/i18n/ekey_de.properties
new file mode 100644 (file)
index 0000000..0e3c029
--- /dev/null
@@ -0,0 +1,46 @@
+# binding
+binding.ekey.name = Ekey Binding
+binding.ekey.description = Dieses Binding integriert die ekey CV-LAN converter UDP.
+
+# thing types
+thing-type.ekey.label = CV-LAN
+thing-type.ekey.description = eKey CV-LAN converter UDP
+
+# thing type config description
+thing-type.config.ekey.ipAddress.label = IP-Adresse
+thing-type.config.ekey.ipAddress.description = IPv4 Adresse des eKey converter UDP. Eine statische IPv4 Adresse wird empfohlen.
+thing-type.config.ekey.port.label = Empfänger Port
+thing-type.config.ekey.port.description = Der während der Konfiguration des ekey converter UDP festgelegte Empfänger Port, z.B. 56000
+thing-type.config.ekey.protocol.label = Protokoll
+thing-type.config.ekey.protocol.description = Das vom ekey converter UDP verwendete Protokoll (RARE, MULTI oder HOME, abhängig vom verwendeten System).
+thing-type.config.ekey.delimiter.label = Abstandshalter
+thing-type.config.ekey.delimiter.description = Der im ekey converter UDP Protokoll verwendete Feldtrenner.
+
+# channel types
+channel-type.ekey.userId.label = Benutzer ID
+channel-type.ekey.userId.description = Zeigt an, welcher Benutzer vom Terminal erkannt wurde. Es handelt sich um den im Konverter festgelegten numerischen Wert (0-99).
+channel-type.ekey.userName.label = Benutzername
+channel-type.ekey.userName.description = Zeigt den 10-stelligen Benutzernamen des vom Terminal erkannten Benutzers.
+channel-type.ekey.userStatus.label = Benutzerstatus
+channel-type.ekey.userStatus.description = Zeigt den Status der vom Terminal erkannten Benutzers an (-1=nicht definiert, 1=nicht gesperrt, 0=gesperrt)
+channel-type.ekey.fingerId.label = Finger ID
+channel-type.ekey.fingerId.description = Zeigt den vom Terminal erkannten Finger an. (0-9,-)
+channel-type.ekey.keyId.label = Schlüssel ID
+channel-type.ekey.keyId.description = Zegt an, welcher der 4 Schlüssel verwendet wurde. Siehe ekey Dokumentation "Schlüssel".
+channel-type.ekey.fsSerial.label = Seriennummer
+channel-type.ekey.fsSerial.description = Zeiget die Seriennummer des Terminals.
+channel-type.ekey.fsName.label = Terminalname
+channel-type.ekey.fsName.description = Zeiget den im Kontrolle hinterlegten 4-stelligen Namen des Terminal.
+channel-type.ekey.action.label = Aktion
+channel-type.ekey.action.description = Zeigt an, ob die letzte Aktion erfolgreich war (Wert=0) oder abgewiesen wurde (Wert=-1). Nach der ekey Dokumentation sind weitere 6 Werte möglich.
+channel-type.ekey.inputId.label = Eingangs ID
+channel-type.ekey.inputId.description = Zeigt an, welcher der 4 digitalen Eingänge ausgelöst wurde. Der Wert entspricht dem Eingang "-1" bedeutet kein Eingang.
+channel-type.ekey.relayId.label = Relais ID
+channel-type.ekey.relayId.description = Zeigt an, welches der Relais geschaltet wurde. Der Wert entspricht dem Relais "-1" bedeutet kein Relais
+channel-type.ekey.termId.label = Terminal ID
+channel-type.ekey.termId.description = Zeigt die Seriennummer des Senders am. Sender kann ein Terminal oder Kontroller sein (Bei digitalen Eingängen). Die Seriennummer ist 13-stellig. 
+channel-type.ekey.reserved.label = Reserviert
+channel-type.ekey.reserved.description = Reserviert
+channel-type.ekey.event.label = Ereignis
+channel-type.ekey.event.description = Ereignis - Beschreibung nicht verfügbar.
+
diff --git a/bundles/org.openhab.binding.ekey/src/main/resources/OH-INF/thing/dynamic-channels.xml b/bundles/org.openhab.binding.ekey/src/main/resources/OH-INF/thing/dynamic-channels.xml
new file mode 100644 (file)
index 0000000..f19e9d9
--- /dev/null
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<thing:thing-descriptions bindingId="ekey"
+       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">
+
+       <channel-type id="userName">
+               <item-type>String</item-type>
+               <label>@text/channel-type.ekey.userName.label</label>
+               <description>@text/channel-type.ekey.userName.description</description>
+               <state readOnly="true"></state>
+       </channel-type>
+       <channel-type id="userStatus">
+               <item-type>Number</item-type>
+               <label>@text/channel-type.ekey.userStatus.label</label>
+               <description>@text/channel-type.ekey.userStatus.description</description>
+               <state readOnly="true"></state>
+       </channel-type>
+       <channel-type id="keyId">
+               <item-type>Number</item-type>
+               <label>@text/channel-type.ekey.keyId.label</label>
+               <description>@text/channel-type.ekey.keyId.description</description>
+               <state readOnly="true"></state>
+       </channel-type>
+       <channel-type id="fsName">
+               <item-type>String</item-type>
+               <label>@text/channel-type.ekey.fsName.label</label>
+               <description>@text/channel-type.ekey.fsName.description</description>
+               <state readOnly="true"></state>
+       </channel-type>
+       <channel-type id="inputId">
+               <item-type>Number</item-type>
+               <label>@text/channel-type.ekey.inputId.label</label>
+               <description>@text/channel-type.ekey.inputId.description</description>
+               <state readOnly="true"></state>
+       </channel-type>
+       <channel-type id="relayId">
+               <item-type>Number</item-type>
+               <label>@text/channel-type.ekey.relayId.label</label>
+               <description>@text/channel-type.ekey.relayId.description</description>
+               <state readOnly="true"></state>
+       </channel-type>
+       <channel-type id="termId">
+               <item-type>Number</item-type>
+               <label>@text/channel-type.ekey.termId.label</label>
+               <description>@text/channel-type.ekey.termId.description</description>
+               <state readOnly="true"></state>
+       </channel-type>
+       <channel-type id="reserved">
+               <item-type>String</item-type>
+               <label>@text/channel-type.ekey.reserved.label</label>
+               <description>@text/channel-type.ekey.reserved.description</description>
+               <state readOnly="true"></state>
+       </channel-type>
+       <channel-type id="event">
+               <item-type>String</item-type>
+               <label>@text/channel-type.ekey.event.label</label>
+               <description>@text/channel-type.ekey.event.description</description>
+               <state readOnly="true"></state>
+       </channel-type>
+
+</thing:thing-descriptions>
diff --git a/bundles/org.openhab.binding.ekey/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.ekey/src/main/resources/OH-INF/thing/thing-types.xml
new file mode 100644 (file)
index 0000000..04a2172
--- /dev/null
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<thing:thing-descriptions bindingId="ekey"
+       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">
+
+       <thing-type id="cvlan">
+               <label>@text/thing-type.ekey.label</label>
+               <description>@text/thing-type.ekey.description</description>
+
+               <channels>
+                       <channel id="userId" typeId="userId"/>
+                       <channel id="fingerId" typeId="fingerId"/>
+                       <channel id="fsSerial" typeId="fsSerial"/>
+                       <channel id="action" typeId="action"/>
+               </channels>
+
+               <config-description>
+                       <parameter name="ipAddress" type="text" required="true">
+                               <context>network-address</context>
+                               <label>@text/thing-type.config.ekey.ipAddress.label</label>
+                               <description>@text/thing-type.config.ekey.ipAddress.description</description>
+                       </parameter>
+                       <parameter name="port" type="integer" min="1" max="65535" required="false">
+                               <label>@text/thing-type.config.ekey.port.label</label>
+                               <description>@text/thing-type.config.ekey.port.description</description>
+                               <default>56000</default>
+                       </parameter>
+                       <parameter name="protocol" type="text" required="false">
+                               <label>@text/thing-type.config.ekey.protocol.label</label>
+                               <description>@text/thing-type.config.ekey.protocol.description</description>
+                               <default>RARE</default>
+                               <options>
+                                       <option value="RARE">RARE</option>
+                                       <option value="MULTI">MULTI</option>
+                                       <option value="HOME">HOME</option>
+                               </options>
+                       </parameter>
+                       <parameter name="delimiter" type="text" required="false">
+                               <label>@text/thing-type.config.ekey.delimiter.label</label>
+                               <description>@text/thing-type.config.ekey.delimiter.description</description>
+                               <default>_</default>
+                       </parameter>
+               </config-description>
+       </thing-type>
+
+       <channel-type id="userId">
+               <item-type>Number</item-type>
+               <label>@text/channel-type.ekey.userId.label</label>
+               <description>@text/channel-type.ekey.userId.description</description>
+               <state readOnly="true"></state>
+       </channel-type>
+       <channel-type id="fingerId">
+               <item-type>Number</item-type>
+               <label>@text/channel-type.ekey.fingerId.label</label>
+               <description>@text/channel-type.ekey.fingerId.description</description>
+               <state readOnly="true"></state>
+       </channel-type>
+       <channel-type id="fsSerial">
+               <item-type>Number</item-type>
+               <label>@text/channel-type.ekey.fsSerial.label</label>
+               <description>@text/channel-type.ekey.fsSerial.description</description>
+               <state readOnly="true"></state>
+       </channel-type>
+       <channel-type id="action">
+               <item-type>Number</item-type>
+               <label>@text/channel-type.ekey.action.label</label>
+               <description>@text/channel-type.ekey.action.description</description>
+               <state readOnly="true"></state>
+       </channel-type>
+</thing:thing-descriptions>
index 47e550dd4978e8cef9849a6692c9036711829770..2ac8d20aee5035f188c1ca64329af88f42427457 100644 (file)
     <module>org.openhab.binding.dwdunwetter</module>
     <module>org.openhab.binding.ecobee</module>
     <module>org.openhab.binding.ecotouch</module>
+    <module>org.openhab.binding.ekey</module>
     <module>org.openhab.binding.elerotransmitterstick</module>
     <module>org.openhab.binding.energenie</module>
     <module>org.openhab.binding.enigma2</module>