Set up EnOcean Hoppe SecuSignal FHFS-vw window handles (EEP F61000)

This tutorial will provide one possibility how to integrate Hoppe SecuSignal FHFS-vw window handles (EEP F61000) into your openHAB installation.

If you followed the instructions how to set up EnOcean via Homegear, your window handles are working properly. However, to use them in a comfortable way in OH2, you need to do some further adjustments in order to show the states properly on your sitemap or work with states in your rules.
While a regular contact item in openHAB knows two states (OPEN and CLOSED), a window handle does effectively have three states, that is CLOSED, OPEN, and AJAR (TILTED). Homegear does provide these three states, however, it sends these states to openHAB in the form of integers (0=CLOSED, 1=OPEN, and 2=AJAR). openHAB then internally transforms these states. Unfortunately, there’s something weird going on during this transformation. The incoming values in openHAB are UNDEFINED, CLOSED, and OPEN. The following table summarizes the states in Homegear and openHAB.

Real state window handle | Homegear | openHAB 2
closed | 0| UNDEFINED
open | 1 | CLOSED
ajar (tilted) | 2 | OPEN

When putting your window handles on your sitemap, you may want to define your devices as STRING items. That will allow you to show the appropriate states. In addition, you may want to use a <CONTACT> icon, as this icon (ironically) supports all three window handle states (in contrast to a CONTACT item). However, the state of an icon will be determined by the raw state of the item (in contrast to the label, see documentation). That means, we need to perform a ‘raw state transformation’. That part is a bit tricky (and a detailed discussion can be found here), but we could use some form of the proxy item design pattern described by @rlkoshak.

What we effectively need to do is to write a rule that takes these incorrect states of the original items, transforms them and assigns the new, correct states to proxy items. That means, in your items file you need to define two items:

  1. The real window handle with the correct EnOcean/HomeMatic channel
  2. A proxy item with a highly related name (that will make life easier further down the road)

Part of my windowHandle item file looks like shown below. The group definition and the label transformation will be described later. What you can see is that the real devices will be assigned a channel while the virtual devices naturally do not have any real channels. One word regarding my name convention: The “s” in “sFenster” stands for “sensor”, while the “v” in “vFenster” stands for “virtual”. This helps me to easily identify the functionality of an item when working with it within rule files.

// Real devices
Group:Contact:AND(CLOSED,OPEN) g_sFenster "Fenster"    <contact>
String ug_buero_sFenster    <contact>   (g_sFenster)    {channel='homematic:HG-F6-10-00:6e230a45:EOD01A93E7E:1#STATE'}
String eg_wz_sFenster1      <contact>   (g_sFenster)    {channel='homematic:HG-F6-10-00:6e230a45:EOD01A956AA:1#STATE'}
String eg_wz_sFenster2      <contact>   (g_sFenster)    {channel='homematic:HG-F6-10-00:6e230a45:EOD01A6E747:1#STATE'}

// Virtual devices
Group:Contact:AND(CLOSED,OPEN) g_vFenster "Fenster"    <contact>
String ug_buero_vFenster                "BĂŒro [MAP(EnOceanWindowHandle_label.map):%s]"          <contact>   (g_vFenster)
String eg_wz_vFenster1                  "Wohnzimmer 1 [MAP(EnOceanWindowHandle_label.map):%s]"  <contact>   (g_vFenster)
String eg_wz_vFenster2                  "Wohnzimmer 2 [MAP(EnOceanWindowHandle_label.map):%s]"  <contact>   (g_vFenster)  

Now, let’s turn our attention to the rules file. First we take a look at an individual window handle. Whenever a window handle receives an update, the raw state transformation needs to be done. For this to take place, we take advantage of the SWITCH command. You could use IF-THEN-ELSE, but in cases like this, I prefer SWITCH as it makes the code easier to read (and understand). Now, if the window handle item ug_buero_sFenster receives an update, its state will be analyzed and a transformed version will be assigned to the proxy device ug_buero_vFenster. Please note that all new states have to be put in quotation marks ("") due to the fact that we are working with STRING items. It’s the virtual device that you subsequently put on your sitemap where it will correctly signal via <contact> icon its three states: “Closed”, “Open”, and “Ajar”.

rule "ug_buero_sFenster transformation"
when
    Item ug_buero_sFenster received update
then
    switch(ug_buero_sFenster.state) {
        case "Undefined": ug_buero_vFenster.postUpdate("CLOSED")
        case "Closed": ug_buero_vFenster.postUpdate("OPEN")
        case "Open": ug_buero_vFenster.postUpdate("AJAR")
    }
end

rule "eg_wz_sFenster1 transformation"
when
    Item eg_wz_sFenster1 received update
then
    switch(eg_wz_sFenster1.state) {
        case "Undefined": eg_wz_vFenster1.postUpdate("CLOSED")
        case "Closed": eg_wz_vFenster1.postUpdate("OPEN")
        case "Open": eg_wz_vFenster1.postUpdate("AJAR")
    }
end

rule "eg_wz_sFenster2 transformation"
when
    Item eg_wz_sFenster2 received update
then
    switch(eg_wz_sFenster2.state) {
        case "Undefined": eg_wz_vFenster2.postUpdate("CLOSED")
        case "Closed": eg_wz_vFenster2.postUpdate("OPEN")
        case "Open": eg_wz_vFenster2.postUpdate("AJAR")
    }
end

In a last step, let’s try to streamline our rules file. The disadvantage of the code above is that you have to code a rule for every window handle in your house. For illustration purposes I showed only three window handle rules. In reality, I have ten window handles, i.e. this would produce large amounts of redundant code. This makes the rules file less readable, and - more important - less maintenance-friendly. If you take a closer look at the individual rules, you will observe that the only differences are the item names. The intention for every rule is essentially the same.

Now, the group contact (which I defined at the very beginning of the items file) comes into play. This approach is again heavily based on another excellent design pattern described by @rlkoshak (Design Pattern: Working with Groups in Rules). I encourage every reader to take a look as I won’t repeat the concept here, but simply show how I transferred the approach to streamline my code. I just would like to mention that this concept requires some kind of persistence (such as mapdb), which I won’t describe here.

rule "sFenster transformation"
when
    Item ug_buero_sFenster changed or
    Item eg_wz_sFenster1 changed or
    Item eg_wz_sFenster2 changed or

then
    Thread::sleep(100) // give persistence time to catch up
    
    // Acquire the window that triggered the rule
    // - use filter remove the windows that are not saved to persitence yet (i.e. lastUpdate returns null)
    // - use sortBy to order the members by lastUpdate, the most recent will be last
    // - get the last updated Item, window contatcs are unlikely to change within 100 msec of each other so this approach works
    // If they are likely to change that close together this approach will fail

    val sFenster = g_sFenster.members.filter[s|s.lastUpdate("mapdb") != null].sortBy[lastUpdate("mapdb")].last as StringItem
    
    // Replace the part of the name ("_sFenster" vs "_vFenster")
    var vFenster = sFenster.name.replace("_sFenster","_vFenster")

    switch(sFenster.state) {
        case "Undefined": vFenster.postUpdate("CLOSED")
        case "Closed": vFenster.postUpdate("OPEN")
        case "Open": vFenster.postUpdate("AJAR")
    }
end

You may have noticed that I defined the group as being of type CONTACT, while the individual group items are of type STRING. It is my understanding that a group’s function (such as AND, OR etc.) only can take exactly two input parameter, such as ON and OFF in the case of a group switch or OPEN and CLOSED in the case of a group contact (as stated in the documentation). I defined the group contact in a way that it’s state will be OPEN if not ALLwindows are closed. That implies that the group contact won’t distinguish between OPEN and AJAR. However, in my point of view, this is not critical as AJAR is also a state that can be described as OPEN.

Here’s the relevant part of my sitemap. It shows the group state on the main page and its individual members on a subpage.

Text item=g_vFenster { 
    Frame {
        Default item=ug_buero_vFenster
        Default item=eg_wz_vFenster1
        Default item=eg_wz_vFenster2
    }
}

Last but not least, I’ll show my label transformation file, which translates the states into German. Information about label transformation can be found here.

EnOceanWindowHandle_label.map
-=N/A
NULL=N/A
CLOSED=geschlossen
OPEN=offen
AJAR=gekippt

Any suggestions for improvement? Just leave a comment


2 Likes