OpenHAB CULfw for Somfy RTS Rollershutters

RTS allows to have a gap of 100 between the counter of transmitter and receiver.
You probably will have that problem in the near future

do you know if both packages are required?

I’d guess you need transport-serial for openhab bindings

Hey Oliver,

many thanks for the script. I tried everything out and got the following error:
If the state of the rollingCode is e.g. ‘0x0001’:

2021-03-31 10:53:26.612 [INFO ] [.model.script.Shutter_BueroFlo.rules] - Rule started
2021-03-31 10:53:26.618 [INFO ] [.model.script.Shutter_BueroFlo.rules] - Thing: 'ShutterBueroFlo', Item: 'ShutterBueroFlo', Command: 'DOWN'
2021-03-31 10:53:26.622 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'Shutter_BueroFlo-1' failed: Could not cast 0x0001 to org.openhab.core.library.types.DecimalType; line 84, column 35, length 89 in Shutter_BueroFlo

If the state of the rollingCode is e.g. ‘0001’ (i thought maybe he doesn’t like the leading ‘0x’):

2021-03-31 10:56:09.423 [INFO ] [.model.script.Shutter_BueroFlo.rules] - Rule started
2021-03-31 10:56:09.430 [INFO ] [.model.script.Shutter_BueroFlo.rules] - Thing: 'ShutterBueroFlo', Item: 'ShutterBueroFlo', Command: 'DOWN'
2021-03-31 10:56:09.440 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'Shutter_BueroFlo-1' failed: Could not cast 0001 to org.openhab.core.library.types.DecimalType; line 84, column 35, length 89 in Shutter_BueroFlo

The referenced line in your rule is:

var String strPayLoad = "YsA1" + strRTSCode + "0" + strRollingCodeHex + strAddress + "\n"

My question is: How do I need to save the rollingCode state? I tried it in decimal values (1 and 101) as well and got the same error.

As short background:
I added a fifth item: The shutter itself, so that I could interact with it on my sitemap.

Rollershutter ShutterBueroFlo "Rolladen Büro Flo" <rollershutter> (gShutter_BueroFlo)

Of course I made sure, that all items are in the same group (gShutter_BueroFlo). And obviously the rule is triggered, as I can see in the logs.

Maybe it has something to do with the type of variable you store the rolling code in and after that parse it to the strPayLoad variable.
I found this link and that link that might help with the format of the rollingCode. Unfortanetly I am not expierienced enough in coding.

I would appreciate your help!

Hi Flo,
your Item hast to be of type number dimensionless.
what OH version are on?

maybe a misunderstandig. Please put all _control items into one group. not alle items belonging to buroflo.

All Shutter related items are in the group “gShutter_BueroFlo”. And the group seems to work.

I am on OH3 with openHabian 3.0.1 on a Rasperry Pi 4.
Which item do you mean? The rollershutter item (the actual rollershutter), or one of the others (calibration or rolling code)?

No, if you have 3 shutters then you need to assign 3 items to your group - only the ones that receive commands, in my example all Items with suffix control
Otherwise the script will be executed every time you change calibration or rolling code

Hi Flo,
what do you mean by this?

Hey Oliver,
Sorry for the late response. I meant, that I created a fith item (a rollershutter item) where I can send the commands UP and DOWN via the PaperUI.

Anyway, I deleted them after your response and set up everything like you said. all _control-items in one group, item type number:dimensionless…

He still seems to have a problem with the script:

2021-04-06 13:57:49.372 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'Shutter_BueroFlo-1' failed: Could not cast 0x0200 to org.openhab.core.library.types.DecimalType; line 84, column 35, length 89 in Shutter_BueroFlo

in the same referenced line I mentioned earlier… I tested the rollingCode out as string, number, number:dimensionless and everything failed.
What would help me is, if you could let me see the actual content of your shutter related items, so e.g. I have my four items _control, _rollingcode, _calibration and _address, and they look like this:

_control:

Number:Dimensionless ShutterBueroFlo_control "Command [%d]" (gShutter_BueroFlo)

(gShutter_BueroFlo) is the groupname where the _control-item is a member of (and noone else).

My _rollingCode file looks like this:

String ShutterBueroFlo_rollingCode "RollingCode [%s]"

My _calibration file looks like this:

Number ShutterBueroFlo_calibration "Calibration: [%d]%%"

And my _address file looks like this:

String ShutterBueroFlo_address "Address: [%s]"

Now somehow the script seems to have a problem with the rollingCode. As I said earlier: I tried several itemtypes (number, number:dimensionless, string) and the two options “0x0200” and “0200”. But nothing worked. The script always says, that it could not cast “0x0200” or “0200” to the decimaltype-library from openHAB.
I really appreciate the help! thanks again!

excuse my. My docs are wrong. rollingCode has to be NUMBER.
don’t forget to set the state via REST API to a proper value

the overall idea behind this script is, that you can add as many rollershutters as you want without the need to have multiple copies of this script.
In case you have two more rollershutters, just add each _control item to your existing group gShutter_BueroFlo. Of course then it would make sense to rename the group to a more general name.

Hey Oliver,

thank you very much!! I got it working!! I can post my config next week, when I have more time. I needed to make little adjustments, because pyserial had a problem with the command. But this was a minor change. If anyone is interested in how to integrate it to Alexa I can post this as well.

thank you again! I am more than happy!

Hi Flo,
could you post the changes to the py script?

One more question to the nanoCul. Is this device working out of the box? Or do you have to change the Firmware or add specific drivers?

Hi Oliver,

mine worked out of the box.

Hey Oliver,

sorry for the wait. I had a lot to do… But, as promised, here my configuration including the connection to Amazon Alexa.

I mentioned my hardware (nanoCUL-Stick and openhabian 3 on a Rasperry Pi 4) earlier in this thread.

Let’s begin:
under /etc/openhab/rules the rule for the shutters:

import org.openhab.core.model.script.ScriptServiceUtil
/*
=======================================================================================================================
DESCRIPTION:
    Change the following data in this script: Group name, scriptName
    All devices have to be a member of the group.
    Syntax of item names:
     <itemName>_control                 (Type: STRING; valid commands: 0 or UP, STOP or MY, 100 or DOWN, PROG, NUMBER:dimensionless [1..99])
     <itemName>_rollingCode             (Type: STRING; persisted item, which stores the last rollingCode)
     <itemName>_calibration             (Type: NUMBER; persisted item, which stores the duration of a half cycle from 0% to 100% in seconds. Required to control the motor with a command like 60[%])
     <itemName>_address                 (Type: STRING; persisted item, which stores address of device)
    Make sure that Items for rollingcode, Calibration and Address are not NULL
    If there are problems, set debug variable in this script to true
    still to be done:
      more error checking, esp. if item is null
      check return string of python script
      or use serial binding
=======================================================================================================================

=======================================================================================================================
CHANGE VALUES ACCORDINGLY: */

var Boolean debug = true
val String fileName = "Shutter_BueroFlo.rules"
val String scriptCommand = "python3"
val String scriptName = "/etc/openhab/scripts/RTS.py"
var Timer tScript = null
rule "RTS BueroFlo"
//======================================================================================================================

when
    Member of gShutter_BueroFlo received command
then
    if (debug) logInfo(fileName,"Rule started")
    tScript?.cancel
    var String strThing = triggeringItem.name.toString().split("_").get(0)
    var String strItem = triggeringItem.name.toString()
    var String strCommand = receivedCommand.toString()
        if (debug) logInfo(fileName, "Thing: '{}', Item: '{}', Command: '{}'",strThing,strItem,strCommand)
    var String strRTSCode = ""
    var Integer intCommand = 0
    var Float fSeconds = 0.0

//find regular commands
    switch strCommand.toUpperCase {
        case "" : {
            logInfo(fileName,"Item: '{}' received empty command",strItem)
            return
        }
        case "MY", case "STOP" : strRTSCode = "1"
        case "UP" : strRTSCode = "2"
        case "DOWN" : strRTSCode = "4"
        case "PROG" : strRTSCode = "8"
//find number values in command
        default: {
                if (debug) logInfo(fileName,"No standard commands submitted")
            var strCommand2 = transform("REGEX", "\\D*(\\d+)\\D*", strCommand)
                if (debug) logInfo(fileName,"strCommand2: '{}'",strCommand2)
            if (strCommand2 !== null) {
                intCommand = Integer.parseInt(strCommand2)
                    if (debug) logInfo(fileName,"intCommand: '{}'",intCommand.toString())
                switch intCommand {
                    case 0 : strRTSCode = "2"
                    case 100 : strRTSCode = "4"
                    case intCommand > 100 : logInfo(fileName,"Item: '{}' received command '{}': not in range [0..100]",strItem,intCommand.toString())
//calculate time when motor has to stop
                    default: {
                        strRTSCode = "4"
                        var Float fCalibration = (ScriptServiceUtil.getItemRegistry.getItem(strThing+"_calibration").state as DecimalType).floatValue
                            if (debug) logInfo(fileName, "fCalibration: '{}'",fCalibration.toString())
                        fSeconds = intCommand.floatValue * fCalibration / 100
                            if (debug) logInfo(fileName, "fSeconds: '{}'",fSeconds.toString())
                    }
                }
            } else {
                logInfo(fileName,"Item: '{}' received unknown command '{}'",strItem,strCommand)
                return
            }
        }
    }

//prepare serial data payload for python script
//Syntax: Ys + EncryptionKey=A1 + Command + 0 + RollingCode + Address
    var Integer intRollingCode = (ScriptServiceUtil.getItemRegistry.getItem(strThing + "_rollingCode").state as DecimalType).intValue
        if (debug) logInfo(fileName, "intRollingCode: '{}'",intRollingCode.toString())
    var String strRollingCodeHex = String::format("%04X", intRollingCode)
    var String strAddress = ScriptServiceUtil.getItemRegistry.getItem(strThing + "_address").state.toString()
        if (debug) logInfo(fileName, "PAYLOAD: strRTSCode: '{}', strRollingCodeHex: '{}', strAddress: '{}'",strRTSCode,strRollingCodeHex,strAddress)
    var String strPayLoad = "YsA1" + strRTSCode + "0" + strRollingCodeHex + strAddress + "\n"
        if (debug) logInfo(fileName, "PAYLOAD STRING: '{}'",strPayLoad)
    var result = executeCommandLine(Duration.ofSeconds(2),scriptCommand, scriptName, strPayLoad)
        logInfo(fileName, "Python script result: {}",result)
    ScriptServiceUtil.getItemRegistry.getItem(strThing + "_rollingCode").postUpdate(intRollingCode + 1)

//send STOP after fSeconds if command is number from 1 to 99
    if (fSeconds > 0.0) {
        strRTSCode = "1"
        strRollingCodeHex = String::format("%04X", intRollingCode +1)
        strPayLoad = "YsA1" + strRTSCode + "0" + strRollingCodeHex + strAddress + "\n"
            if (debug) logInfo(fileName, "PAYLOAD STRING timer triggered: '{}'",strPayLoad)
        tScript = createTimer(now.plusSeconds(fSeconds.longValue), [ |
            var result = executeCommandLine(Duration.ofSeconds(2),scriptCommand, scriptName, strPayLoad)
                logInfo(fileName, "Python script result timer triggered: {}",result)
            ScriptServiceUtil.getItemRegistry.getItem(strThing + "_rollingCode").postUpdate(intRollingCode + 2)
        ])
    }
end

under /etc/openhab/scripts the RTS-Python script, where I needed to change the coding of the Payload (notice the line with ser.write):

#!/usr/bin/python3
# cudos go to chacha
# Install pyserial from https://pythonhosted.org/pyserial/pyserial.html#installation
# add 'stty -F /dev/ttyUSB0 -hupcl' to file /etc/rc.local
import serial
import sys

payLoad = sys.argv[1]
print("Python script received payload " + payLoad)
ser = serial.Serial('/dev/ttyUSB0', 38400, timeout=.1)
        #or: ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)
ser.write(payLoad.encode())
ser.close()

under /etc/openhab/items the next following items:
the _address.items-Item:

String ShutterBueroFlo_address "Address: [%s]"

the _calibration.items-Item:

Number ShutterBueroFlo_calibration "Calibration: [%d]%%"

the _control.items-Item:

Number:Dimensionless ShutterBueroFlo_control "Command [%d]"

the _rollingCode.items-Item:

Number ShutterBueroFlo_rollingCode "RollingCode [%s]"

Additionally I added a Rollershutter item, which is in the group of gShutter_BueroFlo. This triggeres the rule, mentioned above. More importantly I use this item for the connection to Alexa, but I will come to that later in the post. So here the Rollershutter item:

Rollershutter ShutterBueroFlo "Rolladen Flo Office" <rollershutter> (gShutter_BueroFlo)

As Oliver explained, we need a persistence for the rollingCode-item, so we need to change/update/create the file /etc/openhab/persistence/rrd4j.persist and add this line/lines:

Items {
  gShutter_BueroFlo* : strategy =  restoreOnStartup
}

To be able to control the shutters, I need to put them in my openhab-sitemap unter /etc/openhab/sitemaps:

Group item=BueroFlo label="Büro Flo" icon=office
                {
                        Switch item=ShutterBueroFlo icon=rollershutter label="Rolladen Büro Flo"
                        Slider item=ShutterBueroFlo_calibration icon=rollershutter label="Stand Rolladen Büro Flo"
                        Group item=BueroFlo_rolladeninfo label="Rolladeninfo"
                        {
                                Text item=ShutterBueroFlo_control icon=network label="Command Code [%s]"
                                Text item=ShutterBueroFlo_address icon=rollershutter label="Adresse [%s]"
                                Text item=ShutterBueroFlo_calibration icon=rollershutter label="Stand [%d]%%"
                                Text item=ShutterBueroFlo_rollingCode icon=rollershutter label="RollingCode [%s]"
                        }
                }

For troubleshooting reasons I also wanted to see the control-, address-, calibration- and rollingCode-items. So you can ignore the part after “Rolladeninfo”. The main items here are the switch and slider item for the control of the rollershutters.

Now, to implement Alexa in this whole setup (thanks again to all of you):
The first requirement to use Alexa is the openHAB Cloud Connector, see here.
The second requirement is the integration from openHAB Cloud to your Amazon Account. I found a very good step-by-step-guide here.

For Alexa to work, we need to make a change in the rollershutter item and add a few things:

Rollershutter ShutterBueroFlo "Rolladen Flo Office" <rollershutter> (gShutter_BueroFlo) {alexa="RangeController.rangeValue" [category="EXTERIOR_BLIND", friendlyNames="@Setting.Opening", supportedRange="0:100:10", unitOfMeasure="Percent", actionMappings="Close=0,Open=100,Lower=(-10),Raise=(+10)", stateMappings="Closed=0,Open=1:100"]}

After that it should pop up as a device in your Alexa App, when you scan for new devices in your Alexa App. Mappings and assignments in the Alexa App are up to you.

After that you can control the Rollershutters via your voice. So far - depending on the language - these commands work after saying “Alexa %Name of Rollershutter device%” in my configuration “Alexa Rolladen Büro Flo”:

"UP", "100", "OPEN", "AUF" -> for opening the shutter
"CLOSE", "0", "SHUT", "DOWN", "RUNTER" -> for closing the shutter

Of course you can configure your “own” commands by adding a scene(?) for Alexa, where you put in the actual command and map it to a saying like “Good night” (for closing the rollershutters). But I did not implement it until now. AND this is another topic and has nothing to do with this thread.

Oliver, sorry for the long post, you only wanted to know about the “.encode”-command in the python script, but I thought, that maybe someome could benefit from this post.

best regards to all and thank you again for this amazing script! :slight_smile:
Flo

Hi Flo,
thanks for the feedback that the python script needs to be changed. I still had no time to test as the nanocul is not working.

there is still some misunderstanding and you can make it easier as follows:

Number:Dimensionless ShutterBueroFlo_control "Command [%d]"

this is the item which triggers the rule and sends the command code to the rule. there is no need to have an additional switch item to trigger the rule.
not sure about the sitemap syntax, but in OH2 you could use the following:

Switch	item=ShutterBueroFlo_control	label="Rolladen Büro Flo"		icon="blinds"		mappings=[UP="Hoch", STOP="Stop", DOWN="Runter", 50="Halb runterfahren"]

with a tap on one of these four buttons you send the command to the rule.

Please also change the _control item to type STRING
If you do these changes, remove ALL items from your group EXCEPT _control item. the group item is not intended to group various items related to one physical thing. it is a container whose members are ALL “_control” items across several rollershutters

Could somebody please help me out?
The nanocul was succesfully paired with a somfy rollershutter and was acknowledged with moving the rollershutter up and down but UP or DOWN commands are not accepted.

Hy
I’m new to Openhab and wanted to know if there is already a solution to bind Somfy rts blinds with a nanocul to openhab 3 (windows version).
thanks in advance

Hey, is anyone still interested in getting a OH3 compatible version of @Daniel_Weisser 's somfycul binding?
As his code was available on github, I forked it, made the minimal necessary changes and got it working on my OH3.2 setup on my Raspi4. If you’re interested I could either publish the jar on GitHub for you guys to download or maybe even release it as an “official” binding (but that would require additional work to fulfill OH developer guidelines for bindings).
Haven’t really looked at the python scripts you guys came up with in the meantime. They also sound like a great idea.

I don’t know if @Daniel_Weisser still checks this forum. Or maybe he is just on a very long vacation… :wink:

2 Likes