ioBroker: Steuerung von Somfy Rollladen-Aktoren mittels Javascript und CUL-Adapter über das RTS-Protokoll

Seit ich eine Homematic CCU3 in Betrieb hatte, blieb die CCU2 mit alter Firmware auch noch am Leben um die Somfys per CUxD und CUL-Stick zu bewegen. Das ging leider nicht anders: Den CUL- Adapter für den ioBroker gibt es zwar schon eine Weile, ich konnte mich aber nicht aufraffen etwas zu coden.

Mein Skript basiert noch auf den „alten“ Voraussetzungen aus der Homematic-Welt.
Dort wurde mal per Definition festgelegt: Rollladen auf bedeutet einen Wert von 100, Rollladen zu = 0. (Das sind auch die Werte, die wir tatsächlich in der Visualisierung, oder in anderen Scripten setzen.)
Die Betrachtungsweise ist im Prinzip:
Offen = 100% Lichteinfall; Zu = 0% Lichteinfall.
Das kommt von den intelligenten Aktoren, welche Befehle wie „Setze die Behanghöhe auf 50%“ ausführen können weil sie sich alle dafür nötigen Faktoren bei der Ersteinrichtung und im Betrieb gemerkt haben. Mit den Somfy Rollladen-Aktoren – zumindest die, die ich kenne – geht das leider nicht, da müssen wir selbst entscheiden, wann die Stop-Taste gedrückt wird. Als die elektrischen Rollladen bei uns eingebaut wurden, war Smarthome nicht die Priorität, da war „Ich stehe auf, gehe an die Fernbedienung und drücke den Kopf“ schon ziemlicher Luxus 😉 Also arbeite ich mit dem (recht teuren) Kram, der da ist und versuche diesen etwas „smarter“ zu machen. Wenn es euch auch so geht, dann lest weiter.
Wenn ihr vor der Neu-Anschaffung steht und schon mit eurer Smarthome-Installation zugange seid:
Kauft gleich etwas, was euren Bedürfnissen entspricht.
So kann man z.B. aus einem Shelly2 eine Rollladen-Steuerung für relativ kleines Geld bauen, Anleitungen hierzu finden sich in verschiedenen Foren.


Was dem Script noch fehlt, ist eine komfortable Methode, sich bei den Aktoren bekannt zu machen. Aktuell müsst ihr das noch von Hand erledigen und ein sog. Roh-Telegramm zum Anlernen schicken. (Oder Ihr seid den gleichen Weg wie ich über die Homematic und CUxD gekommen, dann könnt Ihre eure bisherigen ID’s weiter verwenden)

Da sowohl die Welt auf GitHub (wo ich mein Script veröffentlicht habe), als auch ca. die Hälfte der ioBroker-Welt in englisch sind, wurde das Script von mir ebenfalls mit englischen Kommentaren versehen, daher auch dieser recht ausschweifende Beitrag in deutsch.

Technische Voraussetzungen :

  • CUL-Stick USB, bevorzugt eine 433MHz Variante (die Vorteile dieser Variante im speziellen Anwendungsfall erkläre ich im weiteren Verlauf)
  • Den (fertig installierten und funktionierenden) ioBroker
  • CUL-Adapter für unseren ioBroker
  • Script-Adapter für den ioBroker (auch funktionierend)
  • Somfy-Aktoren, die sich über das RTS-Protokoll fernbedienen lassen (Wenn ihr für ein Somfy-Gerät eine Fernbedienung habt, ist das schon mal ein guter Indikator)

Voraussetzungen vor der Tastatur:

Jede(r) die / der hier weiter macht, sollte zumindest wissen, was der ioBroker ist, was ein JavaScript ist, sicher im Umgang mit dem Rechner sein und die Fähigkeit mitbringen, sich ein wenig in die digitale Welt ein zu denken.
Sprich:
Diese Person hat schon mehr am Rechner gemacht, als einen Brief in der Textverarbeitung zu schreiben, oder eine Email zu versenden.
Dieser Beitrag ist keine Anleitung, welche jeden zum Erfolg führt.
Z.B. das Anlernen unserer „Fernbedienung“ an die Aktoren ist etwas fummelig und zeitkritisch, da u.A. innerhalb einer bestimmten Zeitspanne nach dem Aktivieren des Programmiermodus am Rollladen-Aktor das (nennen wir es mal so) Anlern-Telegramm geschickt werden muss.
Die Versierteren werden eventuell denken „Warum hat er das denn so gemacht, das geht doch viel eleganter“, diese Personen sind herzlich zur Verbesserung eingeladen 😉

Das RTS-Protokoll:

Das hauseigene RTS-Protokoll wird von Somfy – soweit ich mich erinnere – für alle Geräte verwendet, die sich fernbedienen lassen. Es sind einige Abhandlungen von wirklich intelligenten Menschen darüber im Netz veröffentlicht worden, die sich auch die Mühe gemacht haben, das ganze zu analysieren und mit Puls- / Pausenzeiten etc. auf den unteren Übertragungsschichten zu erklären.
Kurz zusammengefasst ist der interessante Teil für uns ein Daten-Telegramm, welches wir einfach versenden und hoffen, dass irgendwo innerhalb unserer Reichweite ein Gerät ist, das uns verstehen kann, verstehen will und im besten Fall auch unseren Befehl ausführt.
Für uns ist es nicht notwendig, das Protokoll zu 100% zu verstehen. Es reicht uns der Teil, den andere für uns aufbereitet haben.
Vereinfacht sieht das, was wir verschicken dann in etwa so aus, wie hier im Beispiel, die für uns lesbaren Informationen sind grundsätzlich hexadezimal (0-9, A-F) dargestellt
(Befehl um einen Rollladen zu schließen).:

A0402D60AFBC01
| | |   |
| | |   |--- Unsere ID-Nummer, mit der wir uns an einem Aktor                 | | |        angelernt / bekannt gemacht haben. Selbst festgelegt,
| | |        aber dann (quasi) nicht mehr änderbar.
| | |
| | |------- Der sog. Rolling Code, dieser wird nach jedem Befehl
| |          um 1 inkrementiert ("hoch gezählt"). Geht von 0000
| |          bis FFFF (dezimal: 65535). Was danach passiert: Keine
| |          Ahnung, wahrscheinlich fängt es wieder bei Null an.
| |
| |--------- Der Befehl zum Schließen ist 40 hex (0x40)
|
|----------- Der "Encryption Key"; Aus einer Doku entnommen und
             entsprechend interpretiert:
             Beginnt immer mit "A", die 2. Stelle ist ein Zähler für
             eine Art Verschlüsselung. Das Ganze funktioniert aber
             auch, wenn wir damit nichts tun. Deshalb fangen unsere
             Befehle immer mit "A0" an

Laut den einschlägigen Protokollanalysen soll das RTS-Protokoll – auch wenn man es zu 100% gemäß Spezifikation verwendet – nicht besonders sicher sein;
Demnach also für einen Experten mit entsprechender Ausstattung oder einen versierten Laien mit der von einem Experten geschriebenen Software und etwas Hardware
relativ leicht „knackbar“. So ist z.B. ein Aktor schon recht tolerant, wenn z.B. der Rolling Code minimal von dem abweicht, den er sich selbst gemerkt hat. Das bedeutet:
Wenn wir selbst mal merken, dass wir im RC (Rolling Code) etwas hinterher sind und der Rollladen deshalb nicht „fährt“, schicken wir einfach unseren Befehl so oft (wir inkrementieren den RC ja nach jedem Befehl) bis sich wieder etwas bewegt.
Sprich: Unser RC wieder „synchron“ zum Aktor ist.
Wenn wir zu viel auf dem Zähler haben (weil z.B. der Rollladen ein paar Tage außer Betrieb war, die Automation aber fleißig weiter gesendet hat): Kurz nachrechnen, wie viele Steuerbefehle geschickt worden sein könnten, den Zähler-Wert verringern und Befehle an diesen Rollladen schicken, bis es wieder geht 😉

Zur Sicherheit ist also auch ohne eigenes Script zu sagen, dass wir sobald ein Somfy RTS Gerät mit Fernbedienung betrieben wird, u.A. abwägen müssen:

  • Wie hoch ist die Wahrscheinlichkeit, dass eine Fremde Person sich die Mühe macht, den Funkverkehr von unserer Fernbedienung im 433MHz Bereich mit zu schneiden und zu dechiffrieren? (Relativ gering) Z. Zt. erscheint der Aufwand für Dritte IMHO noch zu hoch. Für viele Einbrecher gilt die Devise: Schnell rein, schnell raus, unauffällig sein.
    Das lässt sich schlecht mit tagelangem Herumstehen in einer Wohngegend mit aufmerksamen Nachbarn (wie bei uns) vereinbaren.
  • Macht sich eine Person im Fall der Fälle nicht eher mit der schnellen Lösung ans Werk und nimmt relativ grobes Werkzeug, statt Laptop? (Wahrscheinlich)
  • Würde ein tatsächlicher Schaden entstehen, wenn jemand fremdes lediglich die Rollladen hoch und runter fährt? (Mal von dem Schrecken abgesehen …)

CUL-Stick und Mini-Exkurs „Funk“:

Wie bereits eingangs erwähnt, verwende ich einen 433MHz Stick.
In den Smarthome-Foren wurde zu der Zeit, als ich begonnen habe, mich mit den Somfys zu beschäftigen, zwar berichtet, dass man einen 868MHz Stick dazu überreden kann, für den nächsten Befehl auf einer Frequenz nahe 433MHz zu senden.
ABER, das war nichts für mich, weil:

  • Noch eine weitere mögliche Fehlerquelle, die ich ausschließen wollte
  • Die Kollegen auch berichteten, dass man eine geringere Funk-Reichweite hat, da der HF-Chip außerhalb seiner Spezifikation betreiben wird. (Je nach Bauweise und Beschaffenheit eines Gebäude, sowie der Platzierung des am weitesten entfernten Empfängers, braucht man jeden einzelnen Zentimeter Reichweite 😉

Also wurde es ein Sender von https://www.busware.de, der nur auf 433MHz funkt mit einer dazu passenden abgesetzten 433MHz-Antenne (nicht so ein ultra-kurzes Stummelchen).
Zum Thema „Firmware auf den Stick bruzzeln“ finden diejenigen, die bis hier gelesen haben, unter Garantie ausreichend Informationen im Netz. Von daher gibt es an dieser Stelle keine weitere Anleitung zur Firmware, das wäre einen separaten Beitrag wert.
Achtung: Soweit ich das noch im Gedächtnis habe, gibt es Firmware-Versionen, welche das Senden von Roh (engl.: Raw) -Telegrammen nicht implementiert haben.
(Aber dafür andere Funktionen; Der Flash-Speicher des Sticks ist nicht unendlich groß)

Hinweis zur Funk-Technik allgemein:

Achtet darauf, dass eine Antenne immer auf die Frequenz abgestimmt ist,
auf der Ihr (im Gros aller Fälle) arbeitet.
Eine falsche Antenne funktioniert zwar in der Regel auch irgendwie, aber:

  • kann zu Reichweiten-Einbußen führen, mit denen wir den letzten Empfänger nicht mehr erreichen
  • Führt auf jeden Fall zu einem schlechteren Wirkungsgrad unseres Senders und somit mehr Wärme-Entwicklung im HF-Teil des Senders.
  • Könnte im schlechtesten Fall auch zum Hitze-Tod des Senders führen, was mir persönlich jedoch relativ unwahrscheinlich erscheint, da wir mit sehr geringen Leistungen arbeiten.
    Die Bauteile sind allerdings auch sehr klein….

Stark vereinfacht beträgt die Wellenlänge am Beispiel 433MHz rund 69cm, was bedeutet, dass die optimale Antenne als Vollwellenstrahler theoretisch eben 69cm lang sein müsste. Es gibt verschiedene Möglichkeiten eine Antenne auf einen Sender/Empfänger anzupassen, u.A. durch eine Spule am Fuß der Antenne, bzw. am Ausgang des HF-Teils (Stichwort: Elektrische Länge).
Auf jeden Fall muss die Länge einer Antenne einem geraden ganzzahligen Teiler der Wellenlänge entsprechen. Man spricht hier von Viertelwellen- (z.B. Lambda / 4), Halbwellen-, oder auch von Dreiviertelwellen-Strahlern. Man sollte also darauf achten, welche Antenne der Hersteller eine Gerätes empfiehlt. Auf der sicheren Seite ist man, wenn die Antenne gleich passend mit angeboten wird. Dann braucht man nicht rechnen und recherchieren.

Für Interessierte:
https://de.wikipedia.org/wiki/Groundplane-Antenne

https://de.wikipedia.org/wiki/Dipolantenne

Das Script:

Den bisher fertig entwickelten Teil des Scripts findet Ihr auf gitHub:
https://github.com/brkai/ioBroker-script-somfyCUL

Leider ist es nicht so, dass man einfach wie bei einem Computer-Spiel mal schnell installiert und i.d.R. dann sofort loslegen kann. Man muss auch selbst Hand anlegen und zumindest einigermaßen wissen was man tut. (Ich weiß es oft auch nur einigermaßen 😉 )

Im Script gibt es auf jeden Fall noch Potential für Verbesserungen, aufgrund meiner täglichen Aufgabenstellungen im Berufsleben ist es schon etwas her, dass ich beim Coden mit den echten Könnern mithalten konnte. Ich bitte hier um Nachsicht. Eventuell findet sich ja jemand unter den Lesenden, die/der mit mir zusammen den Code noch etwas optimiert?

Die Sektion „Description and hints“ im Script ist ausführlich, aber (zur Erinnerung) in englisch verfasst. Auch gibt es Tipps im Script selbst. Einer sei hier Explizit hervorgehoben:

Das Script legt sich beim ersten Start seine „Speicherplätze“ im Objekt-Baum automatisch an.

Wenn Ihr, aus welchen Gründen auch immer, den kompletten Bereich
„javascript.0.SomfyCUL“ löschen wollt/müsst:
Kopiert euch die RollingCode-Werte für die Einzelnen Rollläden
(Sektion: javascript.0.SomfyCUL.PhysicalShutters.RollingCodeXX)
vorher in eine Text-Datei, damit Ihr sie dann wieder im ioBroker von Hand eintragen könnt. Ansonsten müsst Ihr eine neue ID vergeben und das Script bei jedem Rollladen neu anlernen!!!

So weit, wie es mir möglich erschien habe ich nur wenige Stellen „eingebaut“ an denen etwas zwingend geändert werden muss um es auf eure Situation anzupassen. Diese im folgenden beschrieben:

// Instance of CUL-Adapter we want to talk to:
var culAd = 'cul.0';

In der Regel kann das so bleiben, wenn man zum Experimentieren aber eine 2. oder 3. Instanz des CUL-Adapters im ioBroker (abwechselnd) am Laufen hat, oder gar mehrere CUL-Sticks für verschiedene Aufgaben an der selben Maschine betreibt: Dann muss man hier die Instanz festlegen.

// Number of command-representations for VIS an logical shutter-groups
// Max: 99 otherwise we have to modify the rest of the script. I didn't really think too much before typing my code ;-)
var LogicalShuttersCount = 16;

Die Gesamt-Zahl der logischen Gruppen (Wenn mehrere Rollladen „gleichzeitig“ fahren sollen) und der einzelnen Rollladen. Wer mehr als 99 definieren möchte, muss dann auch an anderen Stellen im Script Anpassungen vornehmen. Ich denke aber, dass 99 ausreichend sind 😉 Die logischen Gruppen und Definitionen sind unsere Repräsentation für u.A. die Visualisierungs-Oberfläche. Sie sind auch mit den Steuerungs-Befehlen (.Level und .Stop) ausgestattet.

// Number of physical devices in the house
// Max: also 99
var PhysicalShuttersCount = 10;

Die Anzahl der tatsächlich vorhandenen / zu steuernden Rollläden….

// The part of the ID hex-value that is fix.
// If we have to connect our CUL to the Somfy's at new, we change it here
// For now 2 flexible hex-digits at the end will be enough ;-)
// The resulting ID will then be 'FABBxx' if you define 'FABB' here.
var MyRemoteIDFixedPrefix = 'A000';

Hier legen wir einen „Präfix“ für unsere Kennungen fest. Es ist dringend zu empfehlen die „A000“ in eine andere Hex-Folge (0-9, A-F) zu ändern. Mit der Kennung (Der Präfix hier plus 2 weitere „dynamische“ Stellen) identifizieren wir uns am Somfy-Empfänger.

// Quick and dirty: Define each logical shutter/blind here.
// We already have created the states before and have to fill them wth data:
retDummy = fsetLogicalSutterValues('00', "[00]", "Represents the first physical shutter");
retDummy = fsetLogicalSutterValues('01', "[01]", "Represents the second physical shutter");
:
:
:
retDummy = fsetLogicalSutterValues('09', "[09]", "Represents the last physical shutter");
retDummy = fsetLogicalSutterValues('10', "[00, 01, 02]", "The first group of shutters");
:
:
:
retDummy = fsetLogicalSutterValues('14', "[03, 04, 08, 09]", "Another Group");
retDummy = fsetLogicalSutterValues('15', "[00, 01, 02, 03, 04, 05, 06, 07, 08, 09]", "All shutters");

An dieser Stelle legen wir fest, welcher „virtuelle“ Rollladen (den wir z.B. in unserer Visualisierungs-Oberfläche ansprechen) welchen einzelnen, bzw. welche Gruppe von physikalisch vorhandenen Rollläden letztendlich ansteuert. Bitte beachtet: Wir fangen immer bei 0 (Zahl Null) an zu zählen. Der vordere Teil ist immer gleich; Hier steht der Rückgabe-Wert und der Funktions-Name des Funktions-Aufrufs
„retDummy = fsetLogicalSutterValues“.
Den Parameter-Teil muss ich etwas mehr auslegen:

Parameter-Teil der Funktion fsetLogicalSutterValues:
('10', "[00, 01, 02]", "Frei-Text zur Benamselung");
  |      |              |
  |      |              |--- 3. Parameter:
  |      |                   Eine frei befüllbare Zeichenfolge.
  |      |                   Wird zum einen dafür verwendet,
  |      |                   damit wir uns in 100 Jahren wieder daran
  |      |                   erinnern, was wir mal festgelegt haben.
  |      |                   Und ist auch gut brauchbar zum Debuggen ;-)
  |      |
  |      |------- 2. Parameter:
  |               Eine Zeichenfolge, die ein sog. Array definiert.
  |               Jeder Wert innerhalb der eckigen Klammern ist ein
  |               "echter" Rollladen. Auch wenn wir nur einen
  |               ansteuern wollen, brauchen wir die eckigen Klammern!
  |
  |------ 1. Parameter:
          Eine Zeichenfolge, die unseren logischen Rollladen
          identifiziert. An besten auch wirklich fortlaufend abarbeiten,
          sonst besteht die Gefahr, durcheinander zu kommen.
          Warum eine Zeichenfolge (Text) mit nur einer Zahl darin?
          ... weil wir unsere "Speicherplätze im Objektbaum aus
          mehreren Zeichenfolgen zusammen setzen und es so
          einfacher haben.

An einer Stelle ist nur im schlechtesten Fall etwas in der Funktion „fSendRawSomfy“ zu ändern:

var stRepeat = "Yr1";

Diese Zeile legt die Anzahl der Wiederholungen fest, wie oft der CUL-Stick einen Befehl in die Luft feuert. Im Standard sind es (glaube ich) 2 oder 3 Wiederholungen. Als ich auf der CCU vor X Jahren mit dem Script vom Homematic-Forum experimentiert habe, wollten meine Rollläden erst gar nicht funktionieren. Bis ich aus Zufall festgestellt habe dass es die Wiederholungen waren, die stören:
Meine Somfy-Aktoren reagieren ausschließlich, wenn ein und der selbe Befehl auch nur ein einziges Mal innerhalb einer Zeitspanne < 1 Sekunde (… nie genau gemessen, ist auch relativ uninteressant) empfangen wird. Bei anderen Anwendern des Homematic-Script
(https://homematic-forum.de/forum/viewtopic.php?f=37&t=21879) waren mehr als 1 Wiederholungen nötig, damit etwas passierte.

Anlernen an die Aktoren:

Momentan ist es noch recht unkomfortabel, unsere Script-Fernbedienung an die einzelnen Aktoren anzulernen. Unsere Kennung legen wir ja anhand eines fersten Präfinx und einer frotlaufenden Hex-Zahl fest. Dafür haben wir u.A. den Wert „PhysicalShuttersCount“ festgelegt. Wenn also unser Script das erste Mal gelaufen ist. (Natürlich mit den richtig eingestellten Werten!), können wir uns unsere ID’s au dem Objektbaum heraus kopieren, oder selbst zusammen bauen.
Mit dem im Beispiel verwendeten Präfix und PhysicalShuttersCount = 11
wären unsere ID;s z.B.:

„A00000“ für den ersten Rollladen, den wir anlernen wollen. (Wir beginnen bei 0 😉 )
„A00009“ für den 10. Rollladen
„A0000A“ für den 11. Rollladen

…. und so weiter.

Mein Vorschlag zum Anlernen ist, ein separates Script zu schreiben, schon alle Raw-Befehle vorzubereiten und diejenigen auszukommentieren, die man für den einzelnen Aktor nicht braucht. (Man könnte auch eine separate Visualisierung-Seite mit allen anzulernenden Aktoren machen, die man vom Smartphone aus aufrufen kann; Und dann bequem vor dem Rollladen stehen bleiben. Das soll aber hier nicht erklärt werden. Man kann auch mit dem Laptop durchs Haus laufen, oder wenn die Wege nicht zu lange sind zurück zum Desktop-Rechner laufen.) Eventuell muss noch die Widerholungs-Einstellung jedes Mal vorher an den Stick gesendet werden, sprich am Anfang des Script steht:

sendTo("cul.0", "sendraw", {"command": "Yr1"});

Das Telegramm zum Anlernen ist nach unserer Protokollbeschreibung immer:

„A0“ + PROG-Befehl + RollingCode + UnsereKennung

Der RollingCode mit einer frischen Kennung beginnt immer bei 0:

sendTo("cul.0", "sendraw", {"command": "YsA0800000A00000"});
//sendTo("cul.0", "sendraw", {"command": "YsA0800000A00001"});
//sendTo("cul.0", "sendraw", {"command": "YsA0800000A00002"});

... und so weiter

Diese Schritte sind jetzt für jeden Rollladen zu wiederholen:

  • Die richtige Zeile Einkommentieren und darauf achten, dass alle anderen Auskommentiert sind
  • Script speichern
  • Den Aktor am Fenster in den Anlern-Modus versetzen. (Wie das geht steht im Handbuch, kann bei verschiedenen Somfy-Aktoren auch minimal voneinander abweichen.
  • Script 1x starten und wieder beenden.
    Wenn Ihr mit dem Laptop oder dem Tablet vor dem Fenster steht:
    Der Aktor lässt zur Bestätigung den Motor kurz „klacken“. (Mir unbekannte Modelle könnten auch eine LED blinken lassen…)
  • Fertig, auf zum nächsten Fenster 😉

Abschließende Anmerkungen:

  • Wenn man sich sie Script-Funktion „fCommandToHexCode“ anschaut, stellt man fest:
    „Da fehlt ja die Möglichkeit Prozent-Werte zu setzen!“
    Ja, die fehlt, weil Somfy das nicht unterstützt. Manche Geräte verstehen die „MY-Funktion“ und fahren, wenn sie den Befehl „10h“ bekommen etwa in die Mitte.
  • Wir können unserem logischen Rollladen (Bedenke: Visualisierung) als Level auch z.B. „open“ und „close“ mit auf den Weg geben. Schaut in die Funktion „fCommandToHexCode“.
    Das sollte selbsterklärend sein.
  • Wir könnten auch ein und die selbe Kennung an mehreren Aktoren gleichzeitig anlernen
    (So macht man das u.A. mit der Original-Fernbedienung). Dann würden die Rollläden tatsächlich gleichzeitig fahren und nicht – wie bei „meiner“ Methode der Gruppierung – jeweils mit ein paar Millisekunden Zeitverzögerung. Die Gruppierung im Script ist aber wesentlich flexibler.
  • Die Links sind diesmal im Text verteilt 😛

Happy coding!!!