New openHab2 EnOcean binding

I don’t believe this (rather unusual) setup will work. In my view the main problem is that the ESP-software “sends Enocean packages 1-1 to tcp/wifi” whereas the biding just expects a serial interface, esp RFC2217 is “Telnet Com Port Control Option”.
So IF the ESP-software IS RFC2217 compliant/compatible it should work, but looking at the github site, the software is intended to be used differently with the associated node-red package.

You could ask the author of the ESP-software about RFC2217 compatibility.

Thank you Markus, I will investigate a bit in this direction. There seem to be RFC2217 implementations around for ESP8266 so I might be able to combine this.

What’s strange however is that the response to the VERSION Request seems to be handled correctly by the binding according to the logs

If you take a look into RFC2271 you’ll find some elements, which are needed to make good ole serial communications work (setting baud-rate, flow-control …). So it will send/receive some additional characters, which if sent 1-1 to the Enocean gateway, will confuse it and mangle the communication.

That is the pity with standards: if you only use it on one end, it will only “work” by accident.

That’s true, it might just be coincidence then…

I will have a closer look at the standard and the binding code. Do you happen to know where the RFC2271 specific message handling is implemented? So far most of the code I was going through was all about the ESP protocols. I will find it eventually, was just wondering if you could give me a hint

That stuff is not binding specific but is provided by OH on the framework-level. If you look in openhab-core you’ll find eg. org.openhab.core.io.transport.serial.rxtx.rfc2217.
That “addon” in core uses gnu.io.rfc2217

HTH
-Markus

1 Like

Apparently it is a lot of work to make my gateway understand RFC2217…

However I figured out a simpler way to do this by using socat and found a great way to set this up here in the community:

Maybe this can help others who try to set this up in a similar way.

Many thanks for this great binding!

I finally received my window sensor today and was able to add it fully functional to OpenHab much quicker than expected.

I use a Siegenia Senso Secure device. Even though it is super expensive I liked its features and I’m not planning to put them on every window (and I saved quite a bit of money by building my own gateway…). For configuration I setup a generic item that just transforms the whole message to a string item via the genericString channel:

(function(inputData) {

    var parts = inputData.split('|'),
        hexToBytes = function(hex) {
        for (var bytes = [], c = 0; c < hex.length; c += 2)
        bytes.push(parseInt(hex.substr(c, 2), 16));
        return bytes;
    };

    if(!parts || parts.length != 2)
        return null;

    var b = hexToBytes(parts[1]);
    switch(parts[0]){
        case "genericString":
            return "StringType" + "|" + b;
            break;

        case "genericRollershutter":
            break;

        case "genericDimmer":
            break;

        case "genericNumber":            
            break;

        case "genericColor":
            break;

        case "genericTeachInCMD":
            break;
    }

    return (inputData);
})(input)

I then implemented the message handling in a rule:

var messageBytes = newState.toString().split(",");

for (var i = 0; i < messageBytes.length; i++) {
  var messageType;
  switch (i) {
    case 0:
      // Message Type: 1 = Window Status, 2 = Alarm
      messageType = messageBytes[i];
      break;
    case 1:
      // Window Status or Burglary Alarm
      if(messageType == 1) {
        // Cut off first byte since it only indicates keepalive messages
        var windowState = messageBytes[i] & 127;
        if (windowState == 0) {
          // State: None
          break;
        }
        if (windowState < 4) {
          // Window is closed
          events.sendCommand('door_terrace_opening', "Geschlossen");
        } else if (windowState < 7) {
          events.sendCommand('door_terrace_opening', "Geöffnet");
        } else {
          events.sendCommand('door_terrace_opening', "Gekippt");
        }
        if (windowState == 1 || windowState == 4 || windowState == 7) {
          events.sendCommand('door_terrace_handle', "Geschlossen");
        } else if (windowState == 2 || windowState == 5 || windowState == 8) {
          events.sendCommand('door_terrace_handle', "Geöffnet");
        } else if (windowState == 3 || windowState == 6 || windowState == 9) {
          events.sendCommand('door_terrace_handle', "Gekippt");
        }
      } else {
        messageBytes[i] == 1 ? events.sendCommand('door_terrace_alarm', "ON") : events.sendCommand('door_terrace_alarm', "OFF");
      }
      break;
    // Bytes 2 - 5 are not interesting for us right now
    case 6:
      // Alarm messages are only 2 byte long so can be ignored here
      // First bit is the status
      if ((messageBytes[i] & 128) == 128) {
        events.sendCommand('door_terrace_battery_alarm', "ON");
      } else {
        events.sendCommand('door_terrace_battery_alarm', "OFF");
      }
      // Bits 2 - 8 are percentage values
      var batteryPercent = messageBytes[i] & 127;
        events.sendCommand('door_terrace_battery', batteryPercent);
      break;  
  }
}

I don’t acutally know if the alarm is working properly, I hit the window a couple of times but that was apparently not enough. I guess I’ll find out when the kids are playing soccer in the garden :rofl:

If this is of interest for anyone: the alarm does work (just had to hit the door a bit harder). However there does not seem to be a reset message after the end of the alarm as I expected. However I think it is actually better to reset the alarm manually should it ever go off so it does not go unnoticed.

One question: The binding seems to have problems to reconnect to a serial port of it disappears and is readded. I always have to restart OH for the bridge to come back up. Is this a known issue or does anyone know of a workaround?

Regarding your question: I can share your experience of having problems to reconnect. Sometimes it works just fine, sometimes I have to restart OH.

I actually found a workaround a while ago: I create a virtual serial device as a proxy via socat and use this virtual device in openHAB. This way socat is handling reconnections. This works very well for me.

So you are using socat on the very same device OpenHAB is running on?

udev ==> ttyUSB0 ==> socat ==> ttyUSB_socat ==> openhab

?

Yes socat is running on the same host, however my setup is a bit different because my gateway is not connected directly to the openHAB machine but via TCP. However this should work with a connected usb device as well. So I have:

TCP Gateway → Socat (TCP socket to tty0) → Second Socat (tty0 to tty1) → openHAB uses tty1

The second Socat creates a pair of virtual serial devices that are “always connected” so openHAB won’t have to deal with reconnects. The first Socat instance writes all data received from the socket to tty0 and vice versa.

I can even unplug the gateway and plug it back in later without openHAB noticing that it was offline.

Can you please share the command line for the second socat?

In my case I am using a serial connection provided via USB. However, sometimes the USB device stops working, so I have to reset the USB device. This again sometimes changes the device’s name from ttyUSB0 to ttyUSB2 and vice versa. I cover this by having appropriate UDEV rules, always linking the device to ttyFGW14. However, OH sometimes has a hard time resuming the communication.

Today’s attempts by implementing a socat from ttyFGW14 to ttySOCAT_FGW14 didn’t bring any improvements - disconnects still will be discovered by OH, reconnect rarely works, only a restart of the OH service seems to be helpful.

Sure this is the code I use:

#!/bin/bash
# https://community.openhab.org/t/cant-use-forwarded-socat-serial-port-in-lgtvserial-binding-ioexception/97965
# https://community.openhab.org/t/forwarding-of-serial-and-usb-ports-over-the-network-to-openhab/46597

# use while loop to restart socat on connection end
while /bin/true; do
    socat -d -d -s -T 1200 -lf /openhab/userdata/logs/socat_proxy.log pty,link=/dev/ttyNET0,raw,user=openhab,group=openhab,mode=777 pty,link=/dev/ttyNET1,raw,echo=0
    sleep 1
done &> /dev/null &

In the comments you find references to the threads where I got the idea from. You probably don’t need the -T 1200, it was working for me so I did not try to remove this.

Edit: For completeness this is the first socat command:

#!/bin/bash
# https://community.openhab.org/t/cant-use-forwarded-socat-serial-port-in-lgtvserial-binding-ioexception/97965
# https://community.openhab.org/t/forwarding-of-serial-and-usb-ports-over-the-network-to-openhab/46597

# use while loop to restart socat on connection end
sleep 5
while /bin/true; do
    socat -d -d -s -T 600 -lf /openhab/userdata/logs/socat.log /dev/ttyNET1,raw tcp:10.9.50.202:9999,connect-timeout=30,forever,intervall=10
    sleep 1
done &> /dev/null &

Thanks for your help!
By this, I learned that my chain needs to look like this:
udev ==> ttyUSB0 (file) ==> socat ==> ttyUSB_socatA (pty) => socat => ttyUSB_socatB (pty) ==> openhab

Finally I was able to reset ttyUSB0 without having OH notice this. However: it still didn’t work.

So I think I’ll stick with my current solution: taking a heartbeat and perform increasing action if this is missing:

  • reset the usb device
  • reset the usb device and restart OH
  • restart the whole VM

Seems to work :slight_smile:

Hm… Too bad to hear that it didn’t work for you :unamused:

Hi @fruggy83

After using the enocean binding for a couple of months I can say that it works great for most of the time, however I still see some problems from time to time that may be related to race conditions between the bridge coming online and child things getting initialized.

During my nightly backups I stop OH for a couple of seconds/minutes and recreate the container afterwards causing the binding to reinitialize the bridge and child things. Most of the time everything works fine but sometimes (estimated 10% of restarts) I discover that the child things either don’t come back online after the reboot (maybe 90% of the failed reboots) or pretend to be online but don’t receive any updates after that even though they are online (last received message remains at the time when the reboot takes place). I cannot remember I ever had the bridge in an offline state after a reboot so I assume that bridge reconnections are working just fine.

Could the first problem be related to the connectorTask of the EnoceanBridgeHandler waiting for the bridge to come online while child things are already trying to get initialized? Please note that I really have no clue at all how the core implementation of thing initialization works so I might be completely on the wrong track here… However my reconnection issues are quite real so I suspect some multithreading problems here… Maybe there are other users out there who can help to get to the bottom of this. If you need more input from my side I’m also happy to help :slightly_smiling_face: :+1:

HI @DrRSatzteil

thanks a lot for these hints and your work on the binding :+1:

I have not realized such problems in my environments. However I am not restarting my prod env in a such regular basis and my dev env has not many things. So I am maybe not really representativ :slight_smile:

I have just a few questions.
Problem 1: child things do not come back online

  • Which status do your things have in this case? Still “Bridge offline” or any configuration error?
  • What happens if you disable and re-enable such a thing through the gui?
  • Do you really see any received message in this case?

Problem 2: child things just pretend to be only

  • Is this the case for all things or just a few?
  • Which log messages do you get? First the bridge should go online, then the things should go online (initializeThing thing id bridge status ONLINE), afterwards you should see a “Listener added: (EnOceanId as long)”.
  • What happens if you receive a message for such a thing? If you see “ESP Packet payload xxx for ID received” the ThingHandler has received the message from the bridge and is online.

Best regards
Daniel

Hi @fruggy83

I can’t answer all questions right away. I will check the log files when this happens again.

The things say „Bridge offline“. When I disable and reenable them through the gui they immediately work perfectly fine. But I only see received messages after I reenabled the things, when they are still in Bridge offline state I don’t get any messages. To be more precise: I do not get any updates on item level, I would also need to check the logs to see if there’s something happening on the binding level.

I would need to wait for this rather rare case to check the logs in detail. However I can answer your first question: it’s usually only the case for a single device, all other devices are working fine.

Ok today it happened again (Case 1):

The affected thing remains in state “ERROR: BRIDGE” and in the details it says: Status: OFFLINE - BRIDGE_OFFLINE.

And the good news is that I actually see an exception in the logs:

2021-10-18 03:15:05.588 [ERROR] [core.thing.internal.ThingManagerImpl] - Exception occurred during notification about bridge status change on thing 'enocean:windowSashHandleSensor:160542a4f3:058A42A4': null
java.util.ConcurrentModificationException: null
	at java.util.HashMap.computeIfAbsent(HashMap.java:1134) ~[?:?]
	at org.openhab.binding.enocean.internal.transceiver.EnOceanTransceiver.addPacketListener(EnOceanTransceiver.java:378) ~[?:?]
	at org.openhab.binding.enocean.internal.handler.EnOceanBridgeHandler.addPacketListener(EnOceanBridgeHandler.java:383) ~[?:?]
	at org.openhab.binding.enocean.internal.handler.EnOceanBridgeHandler.addPacketListener(EnOceanBridgeHandler.java:378) ~[?:?]
	at org.openhab.binding.enocean.internal.handler.EnOceanBaseSensorHandler.validateConfig(EnOceanBaseSensorHandler.java:105) ~[?:?]
	at org.openhab.binding.enocean.internal.handler.EnOceanBaseThingHandler.initializeThing(EnOceanBaseThingHandler.java:99) ~[?:?]
	at org.openhab.binding.enocean.internal.handler.EnOceanBaseThingHandler.bridgeStatusChanged(EnOceanBaseThingHandler.java:259) ~[?:?]
	at org.openhab.core.thing.internal.ThingManagerImpl$5.run(ThingManagerImpl.java:964) [bundleFile:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) [?:?]
	at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) [?:?]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
	at java.lang.Thread.run(Thread.java:829) [?:?]

So maybe a ConcurrentHashMap should be used for the listeners. This will probably get worse the more sensors are in place.

Created PR https://github.com/openhab/openhab-addons/pull/11408