Ekey integration into openHAB3 (as ekey binding is deprecated and won't be available for OH3)

Unfortunately the Ekey binding was not ported from 1.x to 3.x for use with openHAB3, so I just stepped into that void and created a python script, which will listen to the UDP packages from the Ekey CV LAN, combine the MULTI protocol answers into a JSON, and update with via use of REST API an item of openHAB. Then I wrote some short rule for openHAB3, which updates the ekey items in openHAB.
Part of that was, that the “old” Ekey 1.x binding only supports RARE protocol (why that is, I don’t know) and the remoteopenHAB binding did not proof to be that stable from my view (see OH3 remote openHAB doesn't reconnect), so the “have an openHAB2 instance for your 1.x legacy bindings and use remoteopenHAB” didn’t work for me.

Prerequisites

  • a server, which runs python (2 or 3 doesn’t matter right now), could be your OH3 server of course
  • Ekey CV LAN (current URL on ekey.net)
  • your openHAB(3/2) REST API

The Python script
Once you run the script, it will listen continously on some UDP packets coming in on your defined UDP port, if found (it assumes, it is in MULTI format, no check for that yet!) it will take the payload, split it in a list, then transform it in a JSON, which it then uploads to your openHAB REST API.

#!/usr/bin/python
/*
 * Version 0.1.0
 * By Thomas Binder
 * openHAB Community: https://community.openhab.org/u/binderth
*/

import datetime, sys, socket, json, os, re        # standard packages

# CONFIGURATION
# openHAB REST
OH_HOST = '192.168.178.10'   # the IP-address of your openHAB server
OH_PORT = '8080'            # the port of your openHAB server (default is 8080)
OH_EKEYITEM = 'ekey_JSON'   # the item in openHAB, you send the JSON to

# UDP
UDP_PORT = 51000            # the UDP port you configured in the configuration program of CV LAN (default is 51000)
PAYLOAD_DELIMITER = "_"     # the delimiter you configured in the configuration program of CV LAN (default is '_')
EKEY_ATTRIBUTES = ["packettype", "userid", "username", "userstatus", "fingerid", "keyid", "serialfs", "namefs", "action", "inputid", "timestamp"]

print "listening on port: " + str(UDP_PORT)

# creating UDP-Socket
sock = socket.socket(	socket.AF_INET, # Internet
			socket.SOCK_DGRAM) # UDP
sock.bind(("", UDP_PORT))

# wait for socket data
while True:
    # receiving MULTI coded Ekey payload
    EKEY_MULTI, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
    EKEY_MULTI = re.sub('[^\u0000-\u007f]', '',  EKEY_MULTI)

    # current timestamp
    TIMESTAMP = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S")

    # split payload into a list and add the current timestamp
    EKEY_VALUES = EKEY_MULTI.split("_")
    EKEY_VALUES.append(str(TIMESTAMP))
    EKEY_LIST = dict(zip(EKEY_ATTRIBUTES, EKEY_VALUES))

    # convert list into JSON (and remove all non-ASCII characters)
    EKEY_JSON = json.dumps(EKEY_LIST)
    print "JSON: ", EKEY_JSON

    # Take JSON and update item with openHAB REST
    UPDATE_URL = 'http://' + OH_HOST + ':' + OH_PORT + '/rest/items/' + OH_EKEYITEM
    CURL_STR = "curl -X POST --header 'Content-Type: text/plain' --header 'Accept: application/json' -d '" + EKEY_JSON + "' '" + UPDATE_URL + "'"
    os.system(CURL_STR)

openHAB3 rule
after your “Ekey JSON” item got an update from the script, it will then again split the JSON into parts and update your Ekey Items (as MULTI has 10 attributes, you can have all of them into your openHAB instance plus the timestamp)

triggers:
  - id: "2"
    configuration:
      itemName: ekey_JSON
    type: core.ItemCommandTrigger
conditions: []
actions:
  - inputs: {}
    id: "1"
    configuration:
      type: application/javascript
      script: |
        var ekey = JSON.parse(items["ekey_JSON"]);              # parses the JSON-payload of the item 
        events.sendCommand("EkeyUserstatus", ekey.userstatus);  # the above update all items from the JSON-payload /MULTI
        events.sendCommand("EkeyUsername", ekey.username);
        events.sendCommand("EkeyUserid", ekey.userid);
        events.sendCommand("EkeyNamefs", ekey.namefs);
        events.sendCommand("EkeySerialfs", ekey.serialfs);
        events.sendCommand("EkeyLastaction", ekey.timestamp);
        events.sendCommand("EkeyKeyid", ekey.keyid);
        events.sendCommand("EkeyPackettype", ekey.packettype);
        events.sendCommand("EkeyInputid", ekey.inputid);
        events.sendCommand("EkeyFingerid", ekey.fingerid);
        events.sendCommand("EkeyAction", ekey.action);
    type: script.ScriptAction

after that, you can do your own rules and stuff with that information.

a bit more “techy”, see

1 Like

Hello binderth,

how do I create the “ekey_JSON” item in openHAB3?

Regards

that’s just an String-Item, you can create wherever you want. I used the semantic model in OH3 and put it in my category structure. It’s not necessary to have it in place somewhere special, just the naming must match the OH_EKEYITEM in the python script.

PS: all the other items “Ekeyxx” must be live also and you can use them with your intended logic.

Hi Thomas,
I used the “add item” in the items overview to create the “ekey_JSON” and other “ekeyxx” items.
But when running the Python script from a terminal, I got the error message that the “child process .py couldn’t be executed (file or directory not found)” :confused:
And the only path I found in your script is
’http://’ + OH_HOST + ‘:’ + OH_PORT + ‘/rest/items/’ + OH_EKEYITEM
In my case it is (using https and port 8443; script was executed on my OH3-server)
https://192.168.xxx.xxx:8443/rest/items/ekey_JSON
But there is neither a folder ‘rest’ on ‘/’ level or inside ‘/etc/openhab/’ nor is there a file named “ekey_JSON.item”…
I used installation from the repository via apt-get and I read somewhere, that the paths depends on installation method.
So can you tell me how to adjust your script?

Hi Ansgar,

I guess, you have to read a bit more on how openHAB works… :wink:
In short, what my script needs:

  • ready made items, which reflect the kind of information and/or actions you like to use with ekey in this case
  • so, the rules or other stuff related to how you cope with the information, which the python-script gives you has done within openHAB separately

What my script does:

  • listening on a UDP port for incoming packets
  • interpreting the payload
  • sending the payload to the REST-API of openHAB

So, regardless of the kind of installation of your openHAB installation, the REST-API takes the payload (which my script turned into a JSON) and then splitting the JSON attributes into the “Ekeyxxx” items with the sample rule I pasted above.
so, no you don’t have to do anything on openHABs side[1] to receive the payload - except adding the items -, you don’t need to search for “folders”, as there are none, it’s the REST-API my script uses.

[1] except in OH3, if you put restrictions on your API in place, so you need to authenticate your API-calls, then you need to adjust my script accordingly. But if you do that, you can easily change the python to cope with http-authentication

Hi Thomas et al!

Many thanks for creating this!!!
Currently upgrading from OH2 to OH3, facing some challenges because of six OH1 bindings still in use, ekey being one of them.
While the above looks like a really good workaround, I’m just wondering whether there are any plans to create a native ekey binding for OH3.
Does anybody know about respective plans, or, is it a definitive “deprecated”?

Many thanks and best regards
Achim

Hi Achim,

I don’t think, an native OH3-Binding is around the corner. I didn’t find anything on github and also here in the forum there’s not much going on around ekey.
But! my “workaround” actually works really well (except the occasional 503-errors my Nuki bridge is throwing out, which is annoying!).

Do you have nodered up and running? I switched from the python-listener listed here to a nodered-integration, which works also fine (not, because the python-listener didn’t work - it did! - but because I integrated loads of stuff via nodered now; mostly API-based information, which I transport via MQTT into openHAB).

Hi Thomas,

Many thanks again for taking care!

No, I’m not using Node-RED. My plan of action now is to install an independent OH3 on a separate Linux-Box, test all the open issues and their solutions/workarounds, and then migrate my existing OH2 installation. I don’t want to be without functionality for a longer period.

Will report back!

Cheers
Achim

As you wrote above, you have a few non-OH3 bindings? You can always have two openhab instances, and use remote openhab to have them talk to each other.

Agree!
But long-term solution should be to have everything on one box.

Just got my hands on a CV-Lan device. If I can get it to work with my Arte fingerprint scanner and Integra controller, I might have a look to get a real openHAB 3 binding…

2 Likes

Hi Thomas,
As you pointed out, for your Python script, the protocol must be MULTI.
Interesting effect on my side: Used to run RARE as a protocol and managed to analyze respective data traffic with Wireshark. Works flawlessly with the binding-ekey1 (1.14.0). Now when I switch to MULTI (or even HOME) via the “ekey_home_converter_LAN_config.exe”, everything goes silent, no detectable traffic anymore.
I’m running the “integra case type” with the standard control panel and a “converter UDP”.
Many thanks and best regards
Achim

Hi Achim,

hmm… could be, that your integra doesn’t support MULTI… which is odd, as I used to think only RARE isn’t supported by every device…
does HOME work with your device?

Hi Thomas,
Looks like MULTI only works with MULTI devices and not with HOME devices. Two different ranges of products. Tried to switch to HOME by changing the selection in the converter config tool, but the result did not seem to be something like string or ASCII. At least this was what your python script told me and what I could confirm with Wireshark.
Is there a need to change anything else than the converter?
Many thanks and best regards
Achim

Addendum:
Had another closer look. Apparently, after switching to HOME, getting a string like the following as part of the package
1_0001_3_xxxxxxxxxxxxxx_1_1
meaning there is something to evaluate. Obviously, the current Python script does not evaluate correctly, but leaves with an error, in this case “TypeError: cannot use a string pattern on a bytes-like object”.

Addendum 2:
Had to convert the captured byte object (PAYLOAD) into a string object with
EKEY_MULTI = PAYLOAD.decode(‘UTF-8’)
and just deleted the re.sub statement for removal on non-ASCII, but now getting a suitable JSON
JSON: {“packettype”: “1”, “userid”: “0001”, “fingerid”: “3”, “serialfs”: “xxxxxxxxxxxxxx”, “action”: “1”, “relais”: “1”, “timestamp”: “2021-03-25T13:50:55”}
Next up for real-life testing…

Hi all!

Thanks Thomas et al for all your help and support!
Managed to get it done with an ekey HOME (integra case type plus standard control panel) plus the UDP converter. Switched the protocol from RARE to HOME, because MULTI was not available in this installation.

Modified Thomas’ Python script top of this topic slightly

#!/usr/bin/python

import datetime, sys, socket, json, os, re        # standard packages

# CONFIGURATION
# openHAB REST
OH_HOST = '192.168.178.59'  # the IP-address of your openHAB server
OH_PORT = '8080'            # the port of your openHAB server (default is 8080)
OH_EKEYITEM = 'ekey_JSON'   # the item in openHAB, you send the JSON to

# UDP
UDP_PORT = 5001             # the UDP port you configured in the configuration program of CV LAN (default is 51000)
PAYLOAD_DELIMITER = "_"     # the delimiter you configured in the configuration program of CV LAN (default is '_')
EKEY_ATTRIBUTES = ["packettype", "userid", "fingerid", "serialfs", "action", "relais", "timestamp"]   # this is for HOME protocol

print ( "listening on port: " + str(UDP_PORT) )

# creating UDP-Socket
sock = socket.socket(   socket.AF_INET, # Internet
                        socket.SOCK_DGRAM) # UDP
sock.bind(("", UDP_PORT))

# wait for socket data
while True:
    # receiving HOME coded Ekey payload
    PAYLOAD, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
    print ( "PAYLOAD: ", PAYLOAD )
    EKEY_HOME = PAYLOAD.decode('UTF-8')     # need a string, not a binary
    print ( "EKEY_HOME: ", EKEY_HOME)

    # current timestamp
    TIMESTAMP = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S")

    # split payload into a list and add the current timestamp
    EKEY_VALUES = EKEY_HOME.split("_")
    EKEY_VALUES.append(str(TIMESTAMP))
    EKEY_LIST = dict(zip(EKEY_ATTRIBUTES, EKEY_VALUES))

    # convert list into JSON (and remove all non-ASCII characters)
    EKEY_JSON = json.dumps(EKEY_LIST)
    print ( "JSON: ", EKEY_JSON )

    # Take JSON and update item with openHAB REST
    UPDATE_URL = 'http://' + OH_HOST + ':' + OH_PORT + '/rest/items/' + OH_EKEYITEM
    CURL_STR = "curl -X POST --header 'Content-Type: text/plain' --header 'Accept: application/json' -d '" + EKEY_JSON + "' '" + UPDATE_URL + "'"
    os.system(CURL_STR)

and created a short rule

rule "ekey update"
when
   Item ekey_JSON changed
then
   val ekey_u = transform("JSONPATH","$.userid",ekey_JSON.state.toString)
   val ekey_f = transform("JSONPATH","$.fingerid",ekey_JSON.state.toString)
   val ekey_a = transform("JSONPATH","$.action",ekey_JSON.state.toString)
   UserID.postUpdate(ekey_u)
   FingerID.postUpdate(ekey_f)
   Action.postUpdate(ekey_a)
end

Works like a charm!
Still wondering how much effort it might be to translate the old binding (that should manage all three protocols: RARE, HOME, MULTI) into an OH3 compatible version. Never done something like this. Would be great, if Hans-Jörg could have a look into this!

Cheers
Achim

1 Like

hey! That’s cool! If you’d like you can file an pull request, so I can update the git-repository! :wink:

I shurely will, but have to find time to get my CV-LAN working…
Hopefully can start after Easter…

2 Likes

Hallo @hmerk ,
ich schätze sehr welche Arbeit die Community leistet. Deshalb bitte nicht falsch verstehen:
Gibt es eventuell schon ein Update zum Ekey Binding - dies hält mich aktuell leider davon ab auf OpenHAB 3 zu migrieren.

No worries, but first of all, this is an international community, so english please.

Unfortunately I did not find the time to start. Still have to get my cv lan to work.

But in the meantime, you could use the python script posted here, so no reason to not upgrade to openHAB 3.

Sorry @hmerk for writing in German
I will have a look in the meantime - thanks :+1:t2: