Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. ioBroker Allgemein
    4. IoBroker mit Warema WMS Web Control

    NEWS

    • [erledigt] 15. 05. Wartungsarbeiten am ioBroker Forum

    • ioBroker goes Matter ... Matter Adapter in Stable

    • Monatsrückblick - April 2025

    IoBroker mit Warema WMS Web Control

    This topic has been deleted. Only users with topic management privileges can see it.
    • S
      Silvana4 last edited by

      @Pman:

      Leider kann ich dir nicht wirklich weiterhelfen, aber ein paar Dinge kann ich zu WMS sagen, habe es auch hier.

      Die Mediolaunterstützung ist glaube ich noch nicht raus, ich glaube auch, dass dort WMS ohne Webcontrol unterstützt werden soll?! WMS läuft zumindest mit einem Funkprotokoll auf 2.4Ghz, was Mediola unterstützen sollte. Ich habe irgendwo gelesen, dass es sich um Zigbee handeln soll, aber ich glaube eher, dass es LWMesh ist (nur eine Vermutung), zumindest konnte ich aus dem Funkverkehr keine sinnvollen Zigbee Pakete abfangen.

      Sollte für den Conbee-Stick die angekündigte Wiresharkunterstützung kommen, werde ich nochmal untersuchen, was da bei WMS gefunkt wird, denke aber ohne den Masterkey von Warema ist da nichts möglich.

      Hatte das Webcontrol mal kurz hier und natürlich könnte man sich irgendwie ein Skript basteln, welches das Webinterface von Webcontrol missbraucht, um Befehle dorthin zu senden. Eine beschriebene API dafür gibt http://www.onlineaktienhandel.net/ aber nicht und auch die APP lief (glaube das hat sich mittlerweile geändert) nicht auf Android 7. Daher habe ich das Teil zurück gesendet und mich nicht weiter damit befasst. Ich habe mir dann eine weitere WMS-Fernbedienung geholt und steuere diese mit einem Homematic Empfänger. Ist schon sehr gebastelt, aber erfüllt seinen Zweck. `

      Danke für die Hilfe

      1 Reply Last reply Reply Quote 0
      • R
        radiorichter last edited by

        @ Pman, danke für die Antwort!

        puh… schwieriges Thema... hab mir jetzt aktuell für die Wohnung Homematic geholt (2 Schaltsteckdosen + 1 wandschalter + 1 Funkdimmer). Klappt alles soweit echt super und bin total zufrieden damit...

        Laut Internet sind jedoch die Rolloaktoren / Schaltaktoren von Homematic nicht wirklich langlebig... Da ich nicht alle paar Monate was austauschen will und von Warema eher gutes gehört habe, fände ich die Lösung natürlich auch klug.

        mh... Skript basteln... was würde das genau heißen, bzw wie aufwändig wäre dann so etwas? Danke schonmal!

        1 Reply Last reply Reply Quote 0
        • R
          radiorichter last edited by

          > Ich habe mir dann eine weitere WMS-Fernbedienung geholt und steuere diese mit einem Homematic Empfänger. Ist schon sehr gebastelt, aber erfüllt seinen Zweck.

          Hast du da ein Bild für mich wie du das gelöst hast? 😉 Wie viele WMS Komponenten kannst du dann damit ansteuern?

          Wäre dann also mit diesen Empfänger?

          https://www.elv.de/output/controller.as … ail2=48372

          mit dieser Fernbedienung?

          https://www.der-sonnenschutz-shop.de/wa … gJnC_D_BwE

          1 Reply Last reply Reply Quote 0
          • P
            Pman last edited by

            Genau die beiden Teile. Ich habe die Ausgänge des Homematic-Empfängers über Opto-Koppler mit den Tasten auf der Fernbedienung verbunden. Wie gesagt, sehr gebastelt und ich habe auch nicht viel Ahnung von den Schaltungen. Da es keinen Rückkanal gibt, muss die Logik der Fernbedienung in einem Skript nachgebildet werden. Das Skript und die FB starten auf Kanal 1, wobei ich nur Raffstore nutze, keine anderen Geräte. Durch mehrfachsenden der Raffstore-Taste wird der Kanal weitergeschaltet, das Skript speichert den aktuellen Kanal parallel in einem State. Zusätzlich habe ich die Tasten Hoch, Runter und Stop verbunden. Wobei man bei dem Homematic-Empfänger die An-Zeit senden kann, wodurch man auch kurzes und langes drücken erzeugen kann.

            Ich habe das Skript sogar um Laufzeiten erweitert und kann so die Raffstore auf bestimmte Positionen fahren. Allerdings natürlich nur, wenn das Skript den aktuellen Zustand kennt. Wenn ich zwischendruch mit einem anderen Sender die Position verändert habe, funktioniert es nicht mehr.

            Die Hardware und das Skript sind wirklich sehr speziell auf meine Situation angepasst, daher möchte ich daraus eigentlich keine Anleitung machen.

            1 Reply Last reply Reply Quote 0
            • R
              radiorichter last edited by

              danke, hat mir auf jeden Fall schon mal weitergeholfen 😉

              Bis zum Einzug ist ja noch ein wenig hin, evtl gibts bis dahin irgendwo eine nette Lösung, wenn nicht würd ich nochmal ein bisschen Wissen von dir abzwacken müssen 😉

              1 Reply Last reply Reply Quote 0
              • W
                willjoha last edited by

                Bin auch aktuell auf der Suche nach einer Lösung und versuche das Funk und/oder das WMS Stick Protokoll zu verstehen.

                Das WMS Funkprotokoll basiert zumindest auf IEEE 802.15.4. Die MAC Frames sind in Ordnung, Verschlüsselung des MAC Frames ist bei mir bisher noch nicht vorgekommen.

                Alle anderen Layer darüber scheinen allerdings proprietär zu sein. Ist weder Zigbee noch LwMesh obwohl BitCatcher sowie Wireshark dies zumindest vermuten.

                Die Bedeutung der nicht verschlüsselten Teile der proprietären Frames habe ich großteils schon herausbekommen. Hauptteil sind Sequenznummern sowie Quell- und Zieladressen. Aktuell gehe ich auch davon aus das nur ein Netzwerkschlüssel für das gesamte Netzwerk verwendet wird. Zumindest verwendet diesen WMS Studio für mein Netzwerk und WMS Toolkit hat diesen auch von meinem Handsender beim Einlernen des WMS Sticks zugeschickt bekommen.

                Wo wir schon beim WMS Stick wären. WMS Studio schickt zu Beginn den Netzwerkschlüssel sowie den Funkkanal und die PANID an den WMSStick.

                Der WMS Stick scheint danach die Verschlüsselung/Entschlüsselung selbst zu übernehmen. Teile der einzelnen Funk Frames fehlen im Seriellen Protokoll und zumindest die Broadcast Messages meiner Wetterstation habe ich mit dem WMS Stick noch nicht seriell Empfangen. EDIT: Broadcast Messages der Wetterstation kann ich nun Empfangen sieht wie folgt aus: {rABCDEF7080000200FFFFFF00FF0062FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF} Das r müsste für received stehen ABCDEF steht für die SNR der Wetterstation in Hex.

                Meine Hoffnung ist aktuell der WMS Stick selbst. Um die Verschlüsselung müsste man sich dann nicht kümmern, braucht keine spezielle Firmware auf einem Conbee oder vergleichbarem und sollte insgesamt stabiler laufen.

                1 Reply Last reply Reply Quote 0
                • R
                  radiorichter last edited by

                  Hi willjoha,

                  Danke für deinen Beitrag, leider verstehe ich davon rein gar nichts… sorry... :?

                  Ich denke man könnte das ganze auch über RF LINK lösen, 2.4Ghz würde ja gehen. Ich hab schon mal Kontakt mit dem Kollegen aufgenommen, der war nur der Meinung dass Ihm der Kauf einer solchen Fernbedienung zu teuer sein, um damit den "Code" auszulesen... Ob man dann damit jedoch den Status irgendwie Rückmelden kann ist fraglich...

                  Hier dazu die Antwort von William:
                  ` > Hello Dominik,

                  It does currently not work with RFLink.

                  I am sorry to say that I do not know any working solutions for the Warema WMS at 2.4Ghz.

                  Usually I try to purchase remotes like the WMS but I am afraid this one is very expensive.

                  If you know of a cheap remote then let me known.

                  Best Regards,

                  William oder eben die gleiche Lösung wie Pman: > Well.. the only other option that comes to mind is to use the io pins on the Arduino.

                  RFlink has support for i/o pins that you can solder directly to the pcb of the original remote control.

                  After that, RFLink will "push" the buttons for you.

                  This way of controlling within RFLink works exactly the same as using a generic switch set.. like Elro/Kaku etc.

                  The down side is that you can not use the remote on its own anymore.

                  This works for any remote control. even infra red remotes.. rflink simply pushes the buttons for you `

                  1 Reply Last reply Reply Quote 0
                  • W
                    willjoha last edited by

                    Kann schon mal passieren das ich zu technisch werde 😉 Am Ende der Nachricht ist dies auch diesmal der Fall.

                    Diesen "Code" auszulesen war mein erster Ansatz, da ich wie Pman die Hoffnung hatte das das von Warema eingesetzte Funkprotokoll nicht selbst implementiert ist und damit schon bekannt ist. Soweit ich das jetzt sagen kann ist es eine proprietäre Implementierung die auf aber zumindest auf IEEE 802.15.4 als unterste Schicht basiert.

                    Bei der Analyse bin ich aber darauf gestoßen das der Warema USB Stick die Ver- und Entschlüsselung bereits übernimmt und die Relevanten Teile der Funktelegramme per Serieller Schnittstelle bereitstellt.

                    Nachdem ich nun heute noch meinem WebControl vorgegaukelt habe das mein WMS Stick ein Raffstore ist habe ich zumindest die wichtigsten Teile des Seriellen Protokolls zusammen. Ich versuch es mal einigermaßen verständlich zu beschreiben. Damit sollte dann eine Implementierung für die jeweilige Smarthome Software möglich sein.

                    Benötigt wird dann neben der Software nur noch der Warema WMS Stick (USB Stick) für ca 55€.

                    <size size="150">Alles unten beschriebene ist nicht ausführlich getestet und nur durch Analysen ermittelt. Mit dem WMS Stick können die Geräte auch programmiert werden falsche Nachrichten können daher zu einer Beschädigung eurer Anlage führen. Verwendung daher auf eigene Risiko.</size>

                    Serielle Parameter:

                    Baudrate: 125000

                    Parity: None

                    Data bits: 8

                    Stop bits: 1

                    Nachrichten an und vom WMS Stick sind immer in geschweiften Klammern {} eingeschlossen, Linefeed/Return ist nicht nötig.

                    Die meisten Befehle die man an den USB Stick schickt werden mit "{a}" quittiert. Falls der Befehl nicht verstanden wird kommt ein "{f}" zurück.

                    WMS Stick Prüfen:

                    Ob man mit einem WMS Stick verbunden ist kann man mit folgender Sequenz: "{G}"

                    Der WMS Stick antwortet in diesem Fall nicht mit "{a}" sondern mit "{gWMS USB-Stick}"

                    Die Version des WMS Stick kann mit "{V}" abgefragt werden. in diesem Fall kommt ebenfalls kein "{a}" zurück sondern "{vVVVVVVVV }" wobei VVVVVVVV für die Versionsnummer steht.

                    Mit Netz verbinden:

                    Damit der WMS Stick mit euren Geräten im Netzwerk kommunizieren kann benötigt er den Netzwerkschlüssel den bekommt er mit folgendem Befehl:

                    "{K401KKKKKKKKKKKKKKKKKKKKKKKKKKKKKK}"

                    KKKKKKKKKKKKKKKKKKKKKKKKKKKKKK steht hierbei für den AES Schlüssel des Netzwerks. Der WMS Stick quittiert diesen Befehl mit "{a}"

                    Dieser Schlüssel kann auf zwei Wegen ermittelt werden. Option 1 durch mitlauschen der Seriellen Kommunikation zwischen WMS Studio und WMS Stick. Hierfür benötigt ihr aber euer Projekt mit dem die Anlage parametriert wurde. Option 2 WMS Stick per WMS Handsender ins Netzwerk einlernen. Die hierfür nötigen Befehle an den WMS Stick habe ich zwar schon einmal mitgetracet allerdings nicht dokumentiert da ich durch Option 1 schon den Schlüssel hatte. Kann das bei Gelegenheit noch nachholen.

                    Danach muss noch der Funkkanal und die PANID mitgeteilt werden:

                    "{M%CCPPPP}" wobei CC für den Funkkanal (Default: 17) und PPPP für die PANID steht. Das Prozentzeichen könnte noch durch eine Raute (#) ersetzt werden dann empfängt man allerdings keine Broadcasts. Befehlt wird ebenfalls mit "{a}" quittiert.

                    Jetzt seit ihr bereits mit dem Netz verbunden und solltet Broadcast Messages eurer Wetterstation beziehungsweise Zeitsignale eures WebControls oder der WMS Zentrale empfangen.

                    Wetterstations Broadcast:

                    "{rAAAAAA708000WWL1FFFFFFL2FFRRTTFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF}"

                    AAAAAA = SNR (Seriennummer) der Wetterstation in HEX.

                    7080 = Nachrichten Typ hier Wetter

                    WW = Wind, müsste in m/s sein.

                    L1 = Helligkeitswert 1

                    L2 = Helligkeitswert 2 (Wie aus Helligkeitswert 1 und Helligkeitswert 2 korrekt berechnet wird weiß ich noch nicht.)

                    RR = Niederschlag (00: Kein Regen C8: Regen)

                    TT = Temperatur * 10 muss also durch 10 geteilt werden. Wie Temperaturen über 25,4° und unter 0° dargestellt werden weiß ich noch nicht.

                    Datums/Zeit Broadcast:

                    "{rAAAAAA80200B080009YYNNDDHHMM0C060101}"

                    AAAAAA = SNR (Seriennummer) der WMS Zentrale/WebControl in HEX.

                    8020 = Nachrichten Typ hier Datum/Zeit

                    YY = Jahr 2 stellig in HEX

                    NN = Monat in HEX

                    DD = Tag in HEX

                    HH = Stunden in HEX

                    MM = Minuten in HEX

                    "{rAAAAAA80200B080009110A080C240C060101}" entspricht 08.10.2017 12:36

                    WMS Gerät winken lassen:

                    "{R06AAAAAA7050}" an WMS Stick schicken.

                    AAAAAA = SNR (Seriennummer) vom Gerät welches Winken soll in HEX.

                    7050 = Nachrichten Typ hier Winken

                    WMS Stick quittiert mit "{a}"

                    Status Zwischenstecker abfragen:

                    "{R06AAAAAA801001000005}" an WMS Stick schicken.

                    AAAAAA = SNR (Seriennummer) vom abzufragenden Zwischenstecker in HEX.

                    8010 = Nachrichten Typ hier Statusabfrage

                    WMS Stick quittiert mit "{a}"

                    Zwischenstecker schickt Status:

                    {rAAAAAA801101000003PPWWV1V200}

                    AAAAAA = SNR (Seriennummer) vom abgefragten Zwischenstecker in HEX.

                    8011 = Nachrichten Typ hier Statusantwort

                    PP = Position in % * 2 (HEX) muss daher durch 2 geteilt werden

                    WW = Winkel +127 in HEX. 127 entspricht daher 0°.

                    V1 = Position Volant 1. FF entspricht nicht vorhanden.

                    V2 = Position Volant 2. FF entspricht nicht vorhanden.

                    Kodierung von PP, WW, V1 und V2 entspricht der des WMS WebControl Protocols kann daher mit Hilfe des WebControl JavaScripts nachvollzogen werden.

                    Der WMS Handsender kann auch den Grund für den Letzten Fahrbefehl anzeigen (Wind, Niederschlag, Eis, …) ob und wie dies kodiert ist weiß ich noch nicht.

                    Zwischestecker auf Position fahren:

                    "{R06AAAAAA707003PPWWV1V2}"

                    AAAAAA = SNR (Seriennummer) vom abgefragten Zwischenstecker in HEX.

                    7070 = Nachrichten Typ hier Fahrbefehl

                    PP = Position in % * 2 (HEX) muss daher durch 2 geteilt werden

                    WW = Winkel +127 in HEX. 127 entspricht daher 0°.

                    V1 = Position Volant 1. FF entspricht nicht vorhanden.

                    V2 = Position Volant 2. FF entspricht nicht vorhanden.

                    PP, WW, V1, V2 wie unter "Status Zwischenstecker abfragen" beschrieben.

                    WMS Stick quittiert mit "{a}"

                    Zwischenstecker schickt Bestätigung:

                    {rAAAAAA70710010023F02C04DFFFF0C0DFFFF}

                    AAAAAA = SNR (Seriennummer) vom abgefragten Zwischenstecker in HEX.

                    7071 = Nachrichten Typ hier Bestätigung Fahrbefehl.

                    Genaue Zusammensetzung habe ich hier noch nicht analysiert. Am Ende scheinen zwei Position enthalten zu sein (2 x PPWWV1V2, C04DFFFF0C0DFFFF).

                    Nachdem der Handsender die Ursache anzeigen kann warum ein Fahrbefehl nicht ausgeführt wird wird dies auch noch enthalten sein.

                    R 1 Reply Last reply Reply Quote 0
                    • R
                      radiorichter last edited by

                      HI willjoha,

                      erstmal danke für deine Unterstützung. Glaub ich habs grob verstanden wie es ablaufen soll 😉

                      Wie sendest du dann die Befehle an den WMS Stick? Ich brauch sozusagen ein Programm das ein Funkprotokoll von IEEE 802.15.4 hat und folgendes schickt:
                      ` > Zwischestecker auf Position fahren:

                      "{R06AAAAAA707003PPWWV1V2}" `

                      Gibt es hierzu einen passenden Adapter im iobroker, der das kann? 😉

                      1 Reply Last reply Reply Quote 0
                      • P
                        Pman last edited by

                        @willjoha:

                        Serielle Parameter:

                        Baudrate: 125000

                        Parity: None

                        Data bits: 8

                        Stop bits: 1

                        Nachrichten an und vom WMS Stick sind immer in geschweiften Klammern {} eingeschlossen, Linefeed/Return ist nicht nötig.

                        Die meisten Befehle die man an den USB Stick schickt werden mit "{a}" quittiert. Falls der Befehl nicht verstanden wird kommt ein "{f}" zurück.

                        WMS Stick Prüfen:

                        Ob man mit einem WMS Stick verbunden ist kann man mit folgender Sequenz: "{G}"

                        Der WMS Stick antwortet in diesem Fall nicht mit "{a}" sondern mit "{gWMS USB-Stick}"

                        … `
                        MEGA! Danke für den Anfang. Jetzt müsste natürlich noch etwas geforscht werden.

                        Ich habe noch eine Frage: Kanal und PANID, finden die sich in der Projektdatei? Zumindest hätte man dann, wenn man diese Datei hat, alles nötige zur Hand.

                        Noch ein wichtiger Vorgang wäre das Auffinden (und Bestimmen) von Geräten (im Netz). Für alle weiteren Befehle muss man ja zunächst die Seriennummern kennen.

                        1 Reply Last reply Reply Quote 0
                        • W
                          willjoha last edited by

                          @radiorichter: Ehrlich gesagt hab ich mich mit ioBroker selbst noch überhaupt nicht beschäftigt. Nachdem es JavaScript basiert ist und ein Node-RED Adapter vorhanden ist sollte es damit schon gehen. Ich bediene den Stick aktuell über einen Node-RED flow.

                          @Pman: Kanal, PANID und Netzwerkschlüssel sind in der Projektdatei gespeichert. PANID und Netzwerkschlüssel allerdings nicht im Klartext. Hab deshalb gerade nochmal den einlern Vorgang aufgezeichnet. Der Funktioniert auch ohne Projektdatei, welche die wenigsten haben dürften.

                          Stick zum einlernen Vorbereiten:

                          {G}

                          {gWMS USB-Stick}

                          {M%17FFFF}

                          {a}

                          Rot wird an den WMS Stick geschickt, Blau schickt der WMS Stick zurück. Die hier sind aber ja von oben schon bekannt.

                          PANID wird hierfür auf FFFF gesetzt. WMS toolkit nutzt hier auch immer Funkkanal 17. Da mein Netzwerk ebenfalls auf Funkkanal 17 läuft kann ich nicht sagen wie es sich verhält wenn das WMS Netz nicht Funkkanal 17 nutzt. Warema Standard ist aber zumindest Funkkanal 17 und sollte bei 90% aller Anlagen so sein.

                          Mit Handsender nach neuen Geräten suchen:

                          Handsender aufwecken (beliebige Taste drücken), danach die Lerntaste im Batteriefach für 5 Sekunden drücken.

                          Handsender sucht nun nach neuen Geräten und schickt dabei folgende Nachrichten:

                          {rAAAAAA5060PPPP021100}

                          AAAAAA = SNR des Handsenders

                          5060 = Nachrichten Typ hier wahrscheinlich die Aufforderung den Funkkanal zu wechseln

                          PPPP = PANID des Netzwerks

                          11 = Wahrscheinlich der Funkkanal in HEX.

                          Vermutung das es sich hier um die Aufforderung zum Wechseln des Funkkanals handelt stützt sich darauf das diese Pakete dann von der Software mit dem Befehl zum Funkkanal und PANID einstellen beantwortet werden.

                          Wir müssen also dann folgendes an den WMS Stick schicken:

                          {M%17FFFF}

                          Zu beachten ist hier das der Funkkanal hier nicht in HEX kodiert ist und die PANID noch nicht übernommen wird. Diese Nachricht kann mehrfach kommen. WMS Stick quittiert wie immer mit {a}.

                          Danach folgt der eigentlich Scan:

                          {rAAAAAA7020PPPP02}

                          AAAAAA = SNR des Handsenders

                          7020 = Nachrichten Typ hier wahrscheinlich der Scan Befehl, könnte auch nur der Befehl zum abfragen der PANID sein.

                          PPPP = PANID des Netzwerks

                          Wir müssen darauf wie folgt antworten:

                          {R01AAAAAA7021FFFF02}

                          AAAAAA = SNR des Handsenders

                          7021 = Nachrichten Typ hier Antwort auf den Scan Befehl

                          FFFF = Da wir noch in keinem Netzwerk sind senden wir FFFF als PANID

                          02 = Wahrscheinlich der Geräte Typ. Dann wäre die 02 entweder der WMS Stick selbst oder die WMS toolkit Software.

                          WMS Stick quittiert das ganze wieder mit {a}. Allerdings wird dies ebenfalls vom Handsender selbst noch einmal quittiert was dann wie folgt aussieht:

                          {rAAAAAA50AC97AB}

                          AAAAAA = SNR des Handsenders

                          50AC = Nachrichten Typ hier Quittierung

                          97AB = Wechselt immer sind die letzten 2 Bytes in der Funknachricht wahrscheinlich Prüfsumme.

                          Diese Sequenz kann sich wie die vorherige ebenfalls wiederholen.

                          Jetzt sollten wir soweit sein das der Handsender alle Geräte gefunden hat. Im Bekannte werden mit einer Grünen LED angezeigt.

                          Unser WMS Stick sollte mit einer Roten LED angezeigt werden.

                          Mit den Pfeiltasten jetzt zur Roten LED navigieren und die Stop Taste drücken.

                          Der Handsender schickt wieder die Kanalwechsel Aufforderung wir reagieren wie oben, stellen den angegebenen Funkkanal ein bleiben aber bei der PANID FFFF.

                          Und schon schickt uns der Handsender den Netzwerkschlüssel:

                          {rAAAAAA5018PPPP0123456789ABCDEFFEDCBA9876543210FF11}

                          AAAAAA = SNR des Handsenders

                          5018 = Nachrichten Typ hier Netzwerkschlüssel/Aufforderung dem Netz beizutreten

                          PPPP = PANID des Netzwerks

                          0123456789ABCDEFFEDCBA9876543210 = Netzwerkschlüssel in umgekehrter Reihenfolge. WMS Stick erwartet in im {K401} Befehl in umgekehrter Reihenfolge also 1032547698BADCFEEFCDAB8967452301

                          11 = Müsste wieder der Funkkanal sein.

                          Wenn wir ordentlich sein wollen müssen wir diesen Befehl ebenfalls wie folgt quittieren:

                          {R21AAAAAA50AC}

                          AAAAAA = SNR des Handsenders

                          50AC = Wie oben Nachrichten Typ zum Quittieren.

                          Nach Geräten im Netzwerk suchen:

                          Eigentlich habe ich die Vorgehensweise wie man nach Geräten im Netzwerk sucht jetzt schon beschrieben.

                          Der Handsender macht nämlich nichts anderes. Die Befehle die wir an den WMS Stick schicken müssen sind allerdings minimal unterschiedlich.

                          Falls man auch nicht eingelernte Geräte finden will sollte man mit der Aufforderung zum Funkkanalwechsel beginnen.

                          Für alle möglichen Funkkanäle (11-26) führen wir folgende Sequenz aus:

                          {K4011032547698BADCFEEFCDAB8967452301}

                          {a}

                          {M#FFP1P1}

                          {a}

                          {R04FFFFFF5060P2P2021100}

                          {a}

                          1032547698BADCFEEFCDAB8967452301 = Netzwerkschlüssel von oben.

                          FF = Funkkanal dezimal (11-26)

                          P1P1 = PANID allerdings diesmal ebenfalls in umgekehrter Reihenfolge. Könnte aber auch ein Fehler im WMS Studio sein.

                          P2P2 = PANID in richtiger Reihenfolge.

                          {a} wie immer die Quittierung des WMS Sticks.

                          Danach folgt der eigentliche Scan Befehl, der reicht auch aus wenn ihr nur nach den Bekannten suchen wollt:

                          WMS Stick wieder auf euer Netzwerk einstellen, wie das geht hab ich ja schon im letzten Post geschrieben.

                          Wenn euer WMS Stick schon auf euer Netzwerk eingestellt ist müsst ihr dies hier glaub ich nicht wiederholen.

                          {R04FFFFFF7020PPPP02}

                          FFFFFF = Broadcast an alle

                          7020 = Scan Befehl wie oben.

                          PPPP = PANID eures Netzwerks.

                          Die Geräte antworten dann wie folgt:

                          {rAAAAAA7021PPPP63}

                          AAAAAA = SNR des Gerätes

                          7021 = Antwort auf Scan Befehl wie oben.

                          PPPP = PANID eures Netzwerks.

                          63 = Wie oben wahrscheinlich Gerätetyp.

                          Meine Vermutung zu den möglichen Gerätetypen:

                          63 = Wetterstation

                          06 = WebControl

                          02 = WMS Stick oder WMS toolkit Software

                          20 = WMS Zwischenstecker: In diesem Fall ist die Antwort 7021 deutlich länger (z.B. Raffstore {rAAAAAA7021PPPP208FFF0300000000000000000000020101FF04000000000000})

                          Jetzt sollte aber alles Nötige für eine ordentliche Smarthome Lösung zusammen sein 😉

                          1 Reply Last reply Reply Quote 0
                          • P
                            Pman last edited by

                            Wow super!

                            Um einen ordentlichen ioBroker Adapter zu erschaffen, wäre zunächst eine wms-node-api sinnvoll. Auf der API aufbauend wäre der Adapter dann nur noch Fleißarbeit.

                            Ich versuche mal deine Erkenntnisse gedanklich in Richtung API umzuformulieren:

                            Vorraussetzung: Zur Nutzung der API werden zumindest ein WMS-Stick, ein Handsender, sowie ein fertig installiertes WMS-Netzwerk benötigt.

                            Um an Kanal, PANID und KEY zu kommen, wird der STICK mit dem Handsender in das Netz eingelernt, dabei erhält er die drei nötigen Werte. Solange der API oder dem Stick diese Werte bekannt sind, muss dieser Vorgang nicht wiederholt werden.

                            Mit diesen drei Werten können wir den Stick initialisieren und im vorhandenen WMS-Netzwerk:

                            (a) Geräte erkennen und anlernen (ich würde es gerne bei ersterem belassen, um keine Dummheiten zu erlauben)

                            (b) Broadcasts mithorchen (bisher ZEIT und WETTER)

                            © Befehle an Geräte senden (bisher Zwischenschalter steuern)

                            1 Reply Last reply Reply Quote 0
                            • R
                              radiorichter last edited by

                              wenn ich euch bei irgendwas behilflich sein kann, gebt Bescheid. 🙂 denke aber das ich euch keine große Hilfe bin :roll:

                              1 Reply Last reply Reply Quote 0
                              • W
                                willjoha last edited by

                                Anlernen würde ich auch nicht unterstützen. Ist eh im Handsender implementiert und der ist ja Voraussetzung.

                                Hab nochmal ein paar Funktionen des WebControl angeschaut und meine Erkenntnisse noch mal etwas strukturierter zusammengefasst.

                                Damit sollte es auch etwas einfacher sein eine API zu definieren.

                                Neu hinzugekommen ist Grenzwerte lesen/schreiben und Automatikbetrieb Ein-/Ausschalten.

                                Beim Grenzwerte schreiben ist aufzupassen da hier auch der Wind- und Niederschlagsgrenzwert geändert werden kann. Dies kann bei falschen Werten zu Beschädigungen führen.

                                Befehl zum Zeitschaltuhr auslesen ist auch dabei. Wie dort das Paket genau aufgebaut ist hab ich nicht analysiert.

                                JavaScript hab ich schon etwas länger nichts mehr gemacht und in node.js müsste ich mich auch erst noch einarbeiten.

                                Ansonsten kann ich da auch noch weiter unterstützen.

                                Falls zum Protokoll ansonsten noch etwas gewünscht ist sagt einfach Bescheid.

                                General Message structure:
                                ==========================================================================
                                
                                | Start Byte | Stick Control Sequenze    | Payload (Optional) | End Byte |
                                --------------------------------------------------------------------------
                                |     {      |          1-6 Byte         |                    |     }    |
                                
                                Stick Control Sequenze (SCS):
                                --------------------------------------------------------------------------
                                Stick Control Sequenzes send to the WMS Stick will start with an
                                uppercase letter, Stick Control Sequenzes received from the USB-Stick
                                start with a lower case letter.
                                
                                G:  	Check if this is a WMS Stick
                                g: 		Response to G request. Payload will be "WMS USB-Stick" in this
                                        case.
                                
                                a:		Acknowledge for the last command send to the WMS Stick.
                                f:		An error occured with the last command send to the WMS Stick.
                                
                                r:		Received a WMS message
                                R01:	Send a WMS message
                                R04:	Send a WMS message
                                R06:	Send a WMS message
                                R21:	Send a WMS message
                                
                                K401:	Set Network AES Key 16 Byte HEX encoded --> 32 Byte
                                M:		Set wirless channel, PANID and Filter 
                                
                                WMS Message Structure:
                                ==========================================================================
                                
                                The WMS Message Structure described here is used as payload for all
                                messages with a Stick Control Sequenze starting with an r or R.
                                
                                | Dst/Src SNR  | Message Type | Parameter (Optional) | Payload (Optional)|
                                --------------------------------------------------------------------------
                                | 3 Byte HEX   | 2 Byte HEX   | 0 Byte or 4 Byte HEX |                   |
                                
                                Message Types and corresponding Parameters:
                                --------------------------------------------------------------------------
                                
                                50AC: Acknowledge
                                			Sending direction: 	 SCS=R21, No Parameter, No Payload
                                			Receiving direction: SCS=r  , No Parameter, 2 Byte HEX Payload
                                
                                5018: Join Network request
                                			Sending direction: 	 ???
                                			Receiving direction: SCS=r, No Parameter, below Payload
                                
                                			Payload Structure:
                                			| PANID      | Network Key | ???  | Channel?   |
                                			------------------------------------------------
                                			| 2 Byte HEX | 16 Byte HEX |  FF  | 1 Byte HEX |
                                
                                			The Network Key will be send in reverse order.
                                
                                5060: Switch Channel request
                                			Sending direction: 	 SCS=R04, No Parameter, below Payload
                                			Receiving direction: SCS=r  , No Parameter, below Payload
                                
                                			Payload Structure:
                                			| PANID      | ???  | Channel?   | ???  |
                                			-----------------------------------------
                                			| 2 Byte HEX |  02  | 1 Byte HEX |  00  |
                                
                                7020: Scan request
                                			Sending direction: 	 SCS=R04, No Parameter, below Payload
                                			Receiving direction: SCS=r  , No Parameter, below Payload
                                
                                			Payload Structure:
                                			| PANID      | ???  |
                                			---------------------
                                			| 2 Byte HEX |  02  |
                                
                                			Destination Address in sending direction can be FFFFFF
                                			(Broadcast).
                                
                                7021: Scan response
                                			Sending direction: 	 SCS=R01, No Parameter, below Payload
                                			Receiving direction: SCS=r  , No Parameter, below Payload
                                
                                			Payload Structure:
                                			| PANID      | Device Type? | Payload (Optional)
                                			-------------------------------------------------
                                			| 2 Byte HEX | 1 Byte HEX   |
                                
                                			Device Types:
                                			-------------------------------------------------------
                                			63 | Wetterstation						| No Payload
                                			06 | WebControl							| No Payload
                                			02 | WMS Stick or WMS toolkit Software	| No Payload
                                			20 | WMS Zwischenstecker				| With Payload
                                
                                7080: Weather Broadcast
                                			Sending direction: 	 ???
                                			Receiving direction: SCS=r  , No Parameter, below Payload
                                
                                			Payload Structure:
                                			| ??? | Wind m/s   | Lumen 1    | ???    | Lumen 2    | ??? | Rain       | Temperature | ???                                            |
                                			-----------------------------------------------------------------------------------------------------------------------------------------
                                			| 00  | 1 Byte HEX | 1 Byte HEX | FFFFFF | 1 Byte HEX | FF  | 1 Byte Hex | 1 Byte Hex  | FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF |
                                
                                			        | Possible Values
                                			----------------------------
                                			Lumen 1 | 00, 02-FF
                                			Lumen 2 | if Lumen 1 == 0: 00-FA
                                			        | else: FA
                                			Rain    | 00: No Rain
                                					| C8: Rain
                                		    Temp.   | 00-FF: Temperature in °Celsius * 10
                                					| Currently no Idea how negative Temperatures and Temperatures above 25.4°C are handled.
                                			Wind    | 00-19???
                                
                                7050: Beckon request
                                			Sending direction: 	 SCS=R06, No Parameter, No Payload
                                			Receiving direction: ???
                                
                                7070: Control request
                                			Sending direction: 	 SCS=R06, No Parameter, below Payload
                                			Receiving direction: SCS=r  , No Parameter, below Payload
                                
                                			Payload Structure:
                                			| ??? | Position   | Angle      | Valance 1  | Valance 2  |
                                			-----------------------------------------------------------
                                			| 03  | 1 Byte HEX | 1 Byte HEX | 1 Byte HEX | 1 Byte HEX |
                                
                                			          | Possible Values
                                			--------------------------------------------------------
                                			Position  | Position in % * 2 in HEX. C8 = 100%
                                			Angle     | Angle + 127 in HEX. 7F = 0°
                                			Valance 1 | FF: No Valance
                                					  | ???
                                			Valance 2 | FF: No Valance
                                					  | ???
                                
                                7071: Control response
                                			Sending direction: 	 ???
                                			Receiving direction: SCS=r  , No Parameter, Payload not analyzed yet.
                                
                                8010: WMS parameter get request
                                	01000005: Current Position WMS Motor
                                	26000046: Current clock timer settings
                                	0C000006: Current limits + automatic operation mode
                                			Sending direction: 	 SCS=R06, above Parameter, no Payload
                                			Receiving direction: SCS=r  , above Parameter, no Payload
                                
                                8011: WMS parameter get response
                                	01000003: Current Position WMS Motor
                                			Sending direction: 	 ???
                                			Receiving direction: SCS=r  , above Parameter, below Payload
                                
                                			Payload Structure:
                                			| Position   | Angle      | Valance 1  | Valance 2  | ??? |
                                			-----------------------------------------------------------
                                			| 1 Byte HEX | 1 Byte HEX | 1 Byte HEX | 1 Byte HEX | 00  |
                                
                                			          | Possible Values
                                			--------------------------------------------------------
                                			Position  | Position in % * 2 in HEX. C8 = 100%
                                			Angle     | Angle + 127 in HEX. 7F = 0°
                                			Valance 1 | FF: No Valance
                                					  | ???
                                			Valance 2 | FF: No Valance
                                					  | ???
                                
                                	26000046: Current clock timer settings
                                			Sending direction: 	 ???
                                			Receiving direction: SCS=r  , above Parameter, Payload not analyzed yet.
                                
                                	0C000006: Current limits + automatic operation mode
                                			Sending direction: 	 ???
                                			Receiving direction: SCS=r  , above Parameter, below Payload
                                
                                			Payload Structure:
                                			| Wind       | Rain       | Sun        | Dusk       | Op mode    | ??? |
                                			------------------------------------------------------------------------
                                			| 1 Byte HEX | 1 Byte HEX | 1 Byte HEX | 1 Byte HEX | 1 Byte HEX | 0F  |
                                
                                			        | Possible Values
                                			--------------------------------------------------------
                                			Wind    | 00: Off
                                					| 01: 5 m/s
                                					| 02: 6 m/s
                                					| 03: 7 m/s
                                					| 04: 8 m/s
                                					| 05: 9 m/s
                                					| 06: 10 m/s
                                					| 07: 11 m/s
                                					| 08: 12 m/s
                                					| 09: 13 m/s
                                			Rain    | 00: Off
                                					| 01: On
                                			Sun     | 00: Off
                                					| 01: 10 klx
                                					| 02: 15 klx
                                					| 03: 20 klx
                                					| 04: 25 klx
                                					| 05: 30 klx
                                					| 06: 35 klx
                                					| 07: 40 klx
                                					| 08: 45 klx
                                					| 09: 50 klx
                                			Dusk    | 00: Off
                                					| 01: 16 lx
                                					| 02: 16-46 lx
                                					| 03: 46 lx
                                					| 04: 46-80 lx
                                					| 05: 80 lx
                                					| 06: 80-150 lx
                                					| 07: 150 lx
                                					| 08: 150-400 lx
                                					| 09: 400 lx
                                			Op Mode | 00: Off
                                					| 01: On
                                
                                8020: WMS parameter set request
                                	0B080009:	Set Current Date/Time
                                			Sending direction: 	 ???
                                			Receiving direction: SCS=r  , above Parameter, below Payload
                                
                                			Payload Structure:
                                			| Year       | Month      | Day        | Hour       | Minute     | ???        | Day of Week? | ???  |
                                			---------------------------------------------------------------------------------------------------- 
                                			| 1 Byte HEX | 1 Byte HEX | 1 Byte HEX | 1 Byte HEX | 1 Byte HEX | 1 Byte Hex | 1 Byte HEX   | 0101 |
                                
                                			            | Possible Values
                                			--------------------------------------------------------																   
                                			Day of Week | 00: Monday
                                						| 01: Tuesday
                                						| 02: Wednesday
                                						| 03: Thursday
                                						| 04: Friday
                                						| 05: Saturday
                                						| 06: Sunday
                                
                                	0D000004:	Set limits
                                			Sending direction: 	 SCS=R06, above Parameter, below Payload
                                			Receiving direction: SCS=r  , above Parameter, below Payload
                                
                                			Payload Structure:
                                			| Wind       | Rain       | Sun        | Dusk       |
                                			-----------------------------------------------------
                                			| 1 Byte HEX | 1 Byte HEX | 1 Byte HEX | 1 Byte HEX |
                                
                                			        | Possible Values
                                			--------------------------------------------------------
                                			Wind    | 00: Off
                                					| 01: 5 m/s
                                					| 02: 6 m/s
                                					| 03: 7 m/s
                                					| 04: 8 m/s
                                					| 05: 9 m/s
                                					| 06: 10 m/s
                                					| 07: 11 m/s
                                					| 08: 12 m/s
                                					| 09: 13 m/s
                                			Rain    | 00: Off
                                					| 01: On
                                			Sun     | 00: Off
                                					| 01: 10 klx
                                					| 02: 15 klx
                                					| 03: 20 klx
                                					| 04: 25 klx
                                					| 05: 30 klx
                                					| 06: 35 klx
                                					| 07: 40 klx
                                					| 08: 45 klx
                                					| 09: 50 klx
                                			Dusk    | 00: Off
                                					| 01: 16 lx
                                					| 02: 16-46 lx
                                					| 03: 46 lx
                                					| 04: 46-80 lx
                                					| 05: 80 lx
                                					| 06: 80-150 lx
                                					| 07: 150 lx
                                					| 08: 150-400 lx
                                					| 09: 400 lx
                                
                                	0D040001:   Set automatic operation on/off
                                			Sending direction: 	 SCS=R06, above Parameter, below Payload
                                			Receiving direction: SCS=r  , above Parameter, below Payload
                                
                                			Payload Structure:
                                			| Op mode    |
                                			--------------
                                			| 1 Byte HEX |
                                
                                			Possible Values: 00: Off, 01: On
                                
                                
                                1 Reply Last reply Reply Quote 0
                                • P
                                  Pman last edited by

                                  Super so weit, ich versuche nun grade einen decoder für die einkommenden Packete zu schreiben, also eine Umwandlung in einer besser weiterzuverarbeitendes Javascript Objekt. PANID und KEY werden eingehen in der Payload anscheinend in umgekehrter Reihenfolge (little-endian) geschickt. Nun kommen einige wenige Werte auch evtl mit mehr als einem Byte (lumen? temp?), könnte es sein, dass auch diese Werte in umgekehrte Reihenfolge eingehen?

                                  Hier der (unfertige) Decoder:

                                  //example:
                                  var packet = decodeWMS('r1234567020341202');
                                  console.log(JSON.stringify(packet));
                                  
                                  function decodeWMS(packet) {
                                      var obj = {};
                                      switch (packet.substr(0, 1)) {
                                          case 'g':
                                              obj.type = 'stickType';
                                              obj.payload = {name: packet.substr(1)};
                                              break;
                                          case 'v':
                                              obj.type = 'stickVersion';
                                              obj.payload = {version: packet.substr(1)};
                                              break;
                                          case 'f':
                                              obj.type = 'error';
                                              break;
                                          case 'a':
                                              obj.type = 'ack';
                                              break;
                                          case 'r':
                                              obj.type = 'message';
                                              obj.payload = decodeWMSMessage(packet.substr(1));
                                              break;
                                          default:
                                              obj.type = 'unknown';
                                              obj.payload = packet.substr(1);
                                      }
                                      return obj;
                                  }
                                  
                                  function decodeWMSMessage(message) {
                                      var obj = {};
                                      obj.src = message.substr(0, 6);
                                      var type = message.substr(6, 4);
                                      var payload = message.substr(10);
                                      switch (type) {
                                          case '5018':
                                              obj.type = 'joinNetworkRequest';
                                              obj.messagePayload = {
                                                  panId: payload.substr(0, 4).match(/../g).reverse().join(""),
                                                  networkKey: payload.substr(4, 32).match(/../g).reverse().join(""),
                                                  unknown: payload.substr(36, 2),
                                                  channel: parseInt(payload.substr(38, 2), 16)
                                              };
                                              break;
                                          case '5060':
                                              obj.type = 'switchChannelRequest';
                                              obj.messagePayload = {
                                                  panId: payload.substr(0, 4).match(/../g).reverse().join(""),
                                                  deviceType: payload.substr(4, 2),
                                                  channel: parseInt(payload.substr(6, 2), 16)
                                              };
                                              break;
                                          case '50AC':
                                              obj.type = 'ack';
                                              obj.messagePayload = {
                                                  unknown: payload.substr(0, 4)
                                              };
                                              break;
                                          case '7020':
                                              obj.type = 'scanRequest';
                                              obj.messagePayload = {
                                                  panId: payload.substr(0, 4).match(/../g).reverse().join(""),
                                                  deviceType: payload.substr(4, 2)
                                              };
                                              break;
                                          case '7021':
                                              obj.type = 'scanResponse';
                                              obj.messagePayload = {
                                                  panId: payload.substr(0, 4).match(/../g).reverse().join(""),
                                                  deviceType: payload.substr(4, 2) //63: wetterstation, 06: webcontrol, 02: stick/software, 20: zwischenstecker
                                              };
                                              break;
                                          case '7080':
                                              obj.type = 'weatherBroadcast';
                                              obj.messagePayload = {
                                                  unknown_1: payload.substr(0, 2),
                                                  wind: parseInt(payload.substr(2, 2), 16),
                                                  lumen_1: payload.substr(4, 2),
                                                  unknown_2: payload.substr(6, 6),
                                                  lumen_2: payload.substr(12, 2),
                                                  unknown_3: payload.substr(14, 2),
                                                  rain: payload.substr(16, 2) === 'C8',
                                                  temp: parseInt(payload.substr(18, 2), 16) / 10,
                                                  unknown_4: payload.substr(20)
                                              };
                                              break;
                                          case '7050':
                                              obj.type = 'beckonRequest';
                                              break;
                                          case '7070':
                                              obj.type = 'controlRequest';
                                              obj.messagePayload = {
                                                  unknown: payload.substr(0, 2),
                                                  position: parseInt(payload.substr(2, 2), 16) / 2,
                                                  angle: parseInt(payload.substr(4, 2), 16) - 127,
                                                  valance_1: payload.substr(6, 2),
                                                  valance_2: payload.substr(8, 2)
                                              };
                                              break;
                                          case '7071':
                                              obj.type = 'controlResponse';
                                              obj.messagePayload = payload;
                                              break;
                                          case '8010':
                                              obj.type = 'parameterGetRequest';
                                              obj.messagePayload = {
                                                  parameter: payload.substr(0) //01000005: position, 26000046: clock timer settings, 0C000006: auto modes & limits
                                              };
                                              break;
                                          case '8011':
                                              obj.type = 'parameterGetResponse';
                                              obj.messagePayload = {
                                                  parameter: payload.substr(0, 8)
                                              };
                                              switch (obj.messagePayload.parameter) {
                                                  case '01000003': //position
                                                      obj.messagePayload.position = parseInt(payload.substr(8, 2), 16) / 2;
                                                      obj.messagePayload.angle = parseInt(payload.substr(10, 2), 16) - 127;
                                                      obj.messagePayload.valance_1 = payload.substr(12, 2);
                                                      obj.messagePayload.valance_2 = payload.substr(14, 2);
                                                      break;
                                                  case '0C000006': //auto modes & limits
                                                      obj.messagePayload.auto_wind = payload.substr(8, 2) !== '00' ? parseInt(payload.substr(4, 1), 16) + 4 : 0; //0 = off
                                                      obj.messagePayload.auto_rain = payload.substr(10, 2) === '01';
                                                      obj.messagePayload.auto_sun = payload.substr(12, 2) !== '00' ? parseInt(payload.substr(4, 1), 16) * 5 + 5 : 0; //0 = off
                                                      obj.messagePayload.auto_dusk = payload.substr(14, 2) !== '00' ? parseInt(payload.substr(4, 1), 16) : 0; //0 = off
                                                      obj.messagePayload.auto_op = payload.substr(16, 2) === '01';
                                                      break;
                                                  case '26000046':
                                                  default:
                                                      obj.messagePayload.unknown = payload.substr(8);
                                              }
                                              break;
                                          case '8020':
                                              obj.type = 'parameterSetRequest';
                                              //@todo
                                              break;
                                          default:
                                              obj.type = 'unknown';
                                              obj.messagePayload = payload;
                                      }
                                      return obj;
                                  }
                                  
                                  1 Reply Last reply Reply Quote 0
                                  • W
                                    willjoha last edited by

                                    Na so unfertig ist der doch gar nicht.

                                    Ja die PANID ist im little-endian Format im MAC Frame und auch der WMS Stick erwartet ihn eigentlich immer im little-endian Format.

                                    Ich hab bei den Analysen nur von der WMS Studio Software beim Scan die PANID big-endian bekommen, geh daher immer noch davon aus das das ein Fehler in der WMS Studio Software ist.

                                    Ich würde daher im Decoder auch die PANID nicht umdrehen brauchen Sie ja eh little-endian.

                                    Edit: Temperatur könnte noch little-endian sein. Dann werden positive Temperaturen allerdings als negative Zahlen geschickt. Lumen hab ich meine Vermutung zur Berechnung eingebaut, ist ganz sicher nicht little-endian.

                                    Ansonsten hab ich deinen Decoder mal in meinen node-red Flow gehängt und etwas getestet.

                                    Hab folgende Messages getestet:

                                    • G

                                    • V

                                    • 50AC

                                    • 7020

                                    • 7021

                                      Wollen wir hier bei den Zwischensteckern die noch unbekannte Payload mit ins Objekt packen?

                                    • 7080

                                      Hab hier mal meine aktuelle Lumen Berechnung eingebaut. Muss noch über die Grenzwerte prüfen ob das so hin kommt.

                                      Könnte auch insgesamt nochmal mit 2 multipliziert werden müssen. Sollte aber schon näherungsweise hinkommen.

                                    • 7071

                                    • 8011

                                      • 01000005
                                      Positions request kommt manchmal auch mit der angefragten Parameter Nummer zurück.
                                      
                                      • 0C000006

                                        substr aufrufe korrigiert

                                    • 8020

                                      DateTime implementiert das unbekannte Feld zwischen minute und day of week sind die Sekunden. WebControl schickt es ziemlich genau einmal pro Minute…

                                    Hier noch der Decoder mit meinen Änderungen:

                                    function decodeWMS(packet) {
                                        packet = packet.replace(/^{|}$/g, '');
                                        var obj = {};
                                        switch (packet.substr(0, 1)) {
                                            case 'g':
                                                obj.type = 'stickType';
                                                obj.payload = {name: packet.substr(1)};
                                                break;
                                            case 'v':
                                                obj.type = 'stickVersion';
                                                obj.payload = {version: packet.substr(1)};
                                                break;
                                            case 'f':
                                                obj.type = 'error';
                                                break;
                                            case 'a':
                                                obj.type = 'ack';
                                                break;
                                            case 'r':
                                                obj.type = 'message';
                                                obj.payload = decodeWMSMessage(packet.substr(1));
                                                break;
                                            default:
                                                obj.type = 'unknown';
                                                obj.payload = packet.substr(1);
                                        }
                                        return obj;
                                    }
                                    
                                    function decodeWMSMessage(message) {
                                        var obj = {};
                                        obj.src = message.substr(0, 6);
                                        var type = message.substr(6, 4);
                                        var payload = message.substr(10);
                                        switch (type) {
                                            case '5018':
                                                obj.type = 'joinNetworkRequest';
                                                obj.messagePayload = {
                                                    panId: payload.substr(0, 4),
                                                    networkKey: payload.substr(4, 32).match(/../g).reverse().join(""),
                                                    unknown: payload.substr(36, 2),
                                                    channel: parseInt(payload.substr(38, 2), 16)
                                                };
                                                break;
                                            case '5060':
                                                obj.type = 'switchChannelRequest';
                                                obj.messagePayload = {
                                                    panId: payload.substr(0, 4),
                                                    deviceType: payload.substr(4, 2),
                                                    channel: parseInt(payload.substr(6, 2), 16)
                                                };
                                                break;
                                            case '50AC':
                                                obj.type = 'ack';
                                                obj.messagePayload = {
                                                    unknown: payload.substr(0, 4)
                                                };
                                                break;
                                            case '7020':
                                                obj.type = 'scanRequest';
                                                obj.messagePayload = {
                                                    panId: payload.substr(0, 4),
                                                    deviceType: payload.substr(4, 2)
                                                };
                                                break;
                                            case '7021':
                                                obj.type = 'scanResponse';
                                                obj.messagePayload = {
                                                    panId: payload.substr(0, 4),
                                                    deviceType: payload.substr(4, 2) //63: wetterstation, 06: webcontrol, 02: stick/software, 20: zwischenstecker
                                                };
                                                break;
                                            case '7080':
                                                obj.type = 'weatherBroadcast';
                                                obj.messagePayload = {
                                                    unknown_1: payload.substr(0, 2),
                                                    wind: parseInt(payload.substr(2, 2), 16),
                                                    lumen_1: payload.substr(4, 2),
                                                    unknown_2: payload.substr(6, 6),
                                                    lumen_2: payload.substr(12, 2),
                                                    unknown_3: payload.substr(14, 2),
                                                    rain: payload.substr(16, 2) === 'C8',
                                                    temp: parseInt(payload.substr(18, 2), 16) / 10,
                                                    unknown_4: payload.substr(20),
                                                    lumen: payload.substr(4, 2) === '00' ? parseInt(payload.substr(12, 2), 16) * 2 : parseInt(payload.substr(4, 2), 16) * parseInt(payload.substr(12, 2), 16)
                                                };
                                                break;
                                            case '7050':
                                                obj.type = 'beckonRequest';
                                                break;
                                            case '7070':
                                                obj.type = 'controlRequest';
                                                obj.messagePayload = {
                                                    unknown: payload.substr(0, 2),
                                                    position: parseInt(payload.substr(2, 2), 16) / 2,
                                                    angle: parseInt(payload.substr(4, 2), 16) - 127,
                                                    valance_1: payload.substr(6, 2),
                                                    valance_2: payload.substr(8, 2)
                                                };
                                                break;
                                            case '7071':
                                                obj.type = 'controlResponse';
                                                obj.messagePayload = payload;
                                                break;
                                            case '8010':
                                                obj.type = 'parameterGetRequest';
                                                obj.messagePayload = {
                                                    parameter: payload.substr(0) //01000005: position, 26000046: clock timer settings, 0C000006: auto modes & limits
                                                };
                                                break;
                                            case '8011':
                                                obj.type = 'parameterGetResponse';
                                                obj.messagePayload = {
                                                    parameter: payload.substr(0, 8)
                                                };
                                                switch (obj.messagePayload.parameter) {
                                                    case '01000003': //position
                                                    case '01000005': //position
                                                        obj.messagePayload.position = parseInt(payload.substr(8, 2), 16) / 2;
                                                        obj.messagePayload.angle = parseInt(payload.substr(10, 2), 16) - 127;
                                                        obj.messagePayload.valance_1 = payload.substr(12, 2);
                                                        obj.messagePayload.valance_2 = payload.substr(14, 2);
                                                        break;
                                                    case '0C000006': //auto modes & limits
                                                        obj.messagePayload.auto_wind = payload.substr(8, 2) !== '00' ? parseInt(payload.substr(8, 2), 16) + 4 : 0; //0 = off
                                                        obj.messagePayload.auto_rain = payload.substr(10, 2) === '01';
                                                        obj.messagePayload.auto_sun = payload.substr(12, 2) !== '00' ? parseInt(payload.substr(12, 2), 16) * 5 + 5 : 0; //0 = off
                                                        obj.messagePayload.auto_dusk = payload.substr(14, 2) !== '00' ? parseInt(payload.substr(14, 2), 16) : 0; //0 = off
                                                        obj.messagePayload.auto_op = payload.substr(16, 2) === '01';
                                                        break;
                                                    case '26000046':
                                                        obj.messagePayload.unknown = payload.substr(8);
                                                        break;
                                                    default:
                                                        obj.messagePayload.unknown = payload.substr(8);
                                                }
                                                break;
                                            case '8020':
                                                obj.type = 'parameterSetRequest';
                                                obj.messagePayload = {
                                                    parameter: payload.substr(0, 8)
                                                };
                                                switch (obj.messagePayload.parameter) {
                                                    case '0B080009':
                                                        obj.messagePayload.year = parseInt(payload.substr(8, 2), 16);
                                                        obj.messagePayload.month = parseInt(payload.substr(10, 2), 16);
                                                        obj.messagePayload.day = parseInt(payload.substr(12, 2), 16);
                                                        obj.messagePayload.hour = parseInt(payload.substr(14, 2), 16);
                                                        obj.messagePayload.minute = parseInt(payload.substr(16, 2), 16);
                                                        obj.messagePayload.second = parseInt(payload.substr(18, 2), 16);
                                                        obj.messagePayload.day_of_week = parseInt(payload.substr(20, 2), 16);
                                                        obj.messagePayload.unknown_2 = payload.substr(22);
                                                        break;
                                                    default:
                                                        obj.messagePayload.unknown = payload.substr(8);
                                                }
                                                //@todo
                                                break;
                                            default:
                                                obj.type = 'unknown';
                                                obj.messagePayload = payload;
                                        }
                                        return obj;
                                    }
                                    
                                    msg.payload = decodeWMS(msg.payload);
                                    return msg;
                                    
                                    1 Reply Last reply Reply Quote 0
                                    • P
                                      Pman last edited by

                                      @willjoha:

                                      7021

                                      Wollen wir hier bei den Zwischensteckern die noch unbekannte Payload mit ins Objekt packen? `
                                      Auf jeden Fall, ist mir wohl durch die Lappen gegangen. Alle anderen unknowns sind ja auch drin, dann kann man die bei neuen Erkenntnissen einfach ersetzen.

                                      lumen_1 und lumen_2 können auch rausfliegen, wenn du diese beide weiterverarbeiten konntest.

                                      Ich werde morgen noch als Gegenstück einen Encoder basteln, damit man relativ einfach Packet zum senden erstellen kann.

                                      1 Reply Last reply Reply Quote 0
                                      • P
                                        Pman last edited by

                                        Hier nochmal eine leicht angepasste Version des Decoders, mit deinen Änderungen.

                                        Ich bin bei den Automatik-Modi zurück zu den Tatsächlichen Werten (0-9) gegangen. Ich denke damit kann man erstmal besser arbeiten. Wenn wir später eine Umrechnung (wie in den Tabellen von Warema) benötigen, dann machen wir das besser in einer anderen Funktion.

                                        Anmerkung: die Funktion bezieht sich bei mir nur auf den Inhalt des Packets, ohne die Delimiter ({}). Ich nutze die Funktion im Moment zum testen mit https://www.npmjs.com/package/serialport und dort wird mir der Delimiter ohnehin abgeschnitten.

                                        function decodeWMS(packet) {
                                            var obj = {};
                                            switch (packet.substr(0, 1)) {
                                                case 'g':
                                                    obj.type = 'stickType';
                                                    obj.payload = {name: packet.substr(1)};
                                                    break;
                                                case 'v':
                                                    obj.type = 'stickVersion';
                                                    obj.payload = {version: packet.substr(1)};
                                                    break;
                                                case 'f':
                                                    obj.type = 'error';
                                                    break;
                                                case 'a':
                                                    obj.type = 'ack';
                                                    break;
                                                case 'r':
                                                    obj.type = 'message';
                                                    obj.payload = decodeWMSMessage(packet.substr(1));
                                                    break;
                                                default:
                                                    obj.type = 'unknown';
                                                    obj.payload = packet.substr(1);
                                            }
                                            return obj;
                                        }
                                        
                                        function decodeWMSMessage(message) {
                                            var obj = {};
                                            obj.src = message.substr(0, 6);
                                            var type = message.substr(6, 4);
                                            var payload = message.substr(10);
                                            switch (type) {
                                                case '5018':
                                                    obj.type = 'joinNetworkRequest';
                                                    obj.messagePayload = {
                                                        panId: payload.substr(0, 4),
                                                        networkKey: payload.substr(4, 32).match(/../g).reverse().join(""),
                                                        unknown: payload.substr(36, 2),
                                                        channel: parseInt(payload.substr(38, 2), 16)
                                                    };
                                                    break;
                                                case '5060':
                                                    obj.type = 'switchChannelRequest';
                                                    obj.messagePayload = {
                                                        panId: payload.substr(0, 4),
                                                        deviceType: payload.substr(4, 2),
                                                        channel: parseInt(payload.substr(6, 2), 16)
                                                    };
                                                    break;
                                                case '50AC':
                                                    obj.type = 'ack';
                                                    obj.messagePayload = {
                                                        unknown: payload.substr(0, 4)
                                                    };
                                                    break;
                                                case '7020':
                                                    obj.type = 'scanRequest';
                                                    obj.messagePayload = {
                                                        panId: payload.substr(0, 4),
                                                        deviceType: payload.substr(4, 2)
                                                    };
                                                    break;
                                                case '7021':
                                                    obj.type = 'scanResponse';
                                                    obj.messagePayload = {
                                                        panId: payload.substr(0, 4),
                                                        deviceType: payload.substr(4, 2), //63: wetterstation, 06: webcontrol, 02: stick/software, 20: zwischenstecker
                                                        unknown: payload.substr(6) //optional
                                                    };
                                                    break;
                                                case '7080':
                                                    obj.type = 'weatherBroadcast';
                                                    obj.messagePayload = {
                                                        unknown_1: payload.substr(0, 2),
                                                        wind: parseInt(payload.substr(2, 2), 16),
                                                        lumen: payload.substr(4, 2) === '00' ? parseInt(payload.substr(12, 2), 16) * 2 : parseInt(payload.substr(4, 2), 16) * parseInt(payload.substr(12, 2), 16),
                                                        unknown_2: payload.substr(6, 6),
                                                        unknown_3: payload.substr(14, 2),
                                                        rain: payload.substr(16, 2) === 'C8',
                                                        temp: parseInt(payload.substr(18, 2), 16) / 10,
                                                        unknown_4: payload.substr(20)
                                                    };
                                                    break;
                                                case '7050':
                                                    obj.type = 'beckonRequest';
                                                    break;
                                                case '7070':
                                                    obj.type = 'controlRequest';
                                                    obj.messagePayload = {
                                                        unknown: payload.substr(0, 2),
                                                        position: parseInt(payload.substr(2, 2), 16) / 2,
                                                        angle: parseInt(payload.substr(4, 2), 16) - 127,
                                                        valance_1: payload.substr(6, 2),
                                                        valance_2: payload.substr(8, 2)
                                                    };
                                                    break;
                                                case '7071':
                                                    obj.type = 'controlResponse';
                                                    obj.messagePayload = payload;
                                                    break;
                                                case '8010':
                                                    obj.type = 'parameterGetRequest';
                                                    obj.messagePayload = {
                                                        parameter: payload.substr(0) //01000005: position, 26000046: clock timer settings, 0C000006: auto modes & limits
                                                    };
                                                    break;
                                                case '8011':
                                                    obj.type = 'parameterGetResponse';
                                                    obj.messagePayload = {
                                                        parameter: payload.substr(0, 8)
                                                    };
                                                    switch (obj.messagePayload.parameter) {
                                                        case '01000003': //position
                                                        case '01000005': //position
                                                            obj.messagePayload.type = 'position';
                                                            obj.messagePayload.position = parseInt(payload.substr(8, 2), 16) / 2;
                                                            obj.messagePayload.angle = parseInt(payload.substr(10, 2), 16) - 127;
                                                            obj.messagePayload.valance_1 = payload.substr(12, 2);
                                                            obj.messagePayload.valance_2 = payload.substr(14, 2);
                                                            break;
                                                        case '0C000006': //auto modes & limits
                                                            obj.messagePayload.type = 'autoSettings';
                                                            obj.messagePayload.wind = parseInt(payload.substr(8, 2), 16);
                                                            obj.messagePayload.rain = parseInt(payload.substr(10, 2), 16);
                                                            obj.messagePayload.sun = parseInt(payload.substr(12, 2), 16);
                                                            obj.messagePayload.dusk = parseInt(payload.substr(14, 2), 16);
                                                            obj.messagePayload.op = parseInt(payload.substr(16, 2), 16);
                                                            break;
                                                        case '26000046':
                                                            obj.messagePayload.type = 'clock';
                                                            obj.messagePayload.unknown = payload.substr(8);
                                                            break;
                                                        default:
                                                            obj.messagePayload.type = 'unknown';
                                                            obj.messagePayload.unknown = payload.substr(8);
                                                    }
                                                    break;
                                                case '8020':
                                                    obj.type = 'parameterSetRequest';
                                                    obj.messagePayload = {
                                                        parameter: payload.substr(0, 8)
                                                    };
                                                    switch (obj.messagePayload.parameter) {
                                                        case '0B080009':
                                                            obj.messagePayload.type = 'clock';
                                                            obj.messagePayload.year = parseInt(payload.substr(8, 2), 16);
                                                            obj.messagePayload.month = parseInt(payload.substr(10, 2), 16);
                                                            obj.messagePayload.day = parseInt(payload.substr(12, 2), 16);
                                                            obj.messagePayload.hour = parseInt(payload.substr(14, 2), 16);
                                                            obj.messagePayload.minute = parseInt(payload.substr(16, 2), 16);
                                                            obj.messagePayload.second = parseInt(payload.substr(18, 2), 16);
                                                            obj.messagePayload.day_of_week = parseInt(payload.substr(20, 2), 16);
                                                            obj.messagePayload.unknown = payload.substr(22);
                                                            break;
                                                        default:
                                                            obj.messagePayload.type = 'unknown';
                                                            obj.messagePayload.unknown = payload.substr(8);
                                                    }
                                                    break;
                                                default:
                                                    obj.type = 'unknown';
                                                    obj.messagePayload = payload;
                                            }
                                            return obj;
                                        }
                                        
                                        1 Reply Last reply Reply Quote 0
                                        • P
                                          Pman last edited by

                                          Und hier der Encoder, allerdings kaum getestet.

                                          Benutzung:

                                          encodeWMS(type, parameter), wobei type z.B controlRequest und parameter dann '{dst: 'ABCDEF', position: 100, angle:0}'.

                                          encodeWMS('controlRequest', {dst: 'ABCDEF', position: 100, angle:0});
                                          
                                          

                                          Wenn type unbekannt ist, oder nicht alle nötigen Parameter angegeben sind, wird false zurückgegeben. Ansonsten wird der String zum Senden an den Stick zurückgegeben, ohne Delimiter ({}).

                                          function encodeWMS(type, parameter) {
                                              if (!parameter) parameter = {};
                                              switch (type) {
                                                  case 'switchChannel':
                                                      if (isNaN(parameter.channel)) return false;
                                                      return '{M%' + parameter.channel + 'FFFF}';
                                                      break;
                                                  case 'ack':
                                                      if (!parameter.dst) return false;
                                                      return '{R21' + parameter.dst + '50AC}';
                                                      break;
                                                  case 'switchChannelRequest': //channel 17 fixed
                                                      if (!parameter.panId) return false;
                                                      return '{R04FFFFFF5060' + parameter.panId + '021100}'; // dst or FFFFFF???
                                                      break;
                                                  case 'scanRequest':
                                                      return '{R04FFFFFF7020' + parameter.panId + '02}';
                                                      break;
                                                  case 'scanResponse':
                                                      if (!parameter.panId || !parameter.dst) return false;
                                                      return '{R01' + parameter.dst + '7021' + parameter.panId + '02}'; //fixed to deviceType 02 for now
                                                      break;
                                                  case 'beckonRequest':
                                                      if (!parameter.dst) return false;
                                                      return '{R06' + parameter.dst + '7050}';
                                                      break;
                                                  case 'controlRequest':
                                                      if (!parameter.dst || isNaN(parameter.position) || isNaN(parameter.angle)) return false;
                                                      return '{R06' + parameter.dst + '7070' + '03'
                                                          + ('0' + (Math.min(Math.max(parameter.position, 0), 100) * 2).toString(16)).substr(-2).toUpperCase()
                                                          + ('0' + (Math.min(Math.max(parameter.angle, 0), 90) + 127).toString(16)).substr(-2).toUpperCase()
                                                          + 'FFFF}'; //no idea how valance works
                                                      break;
                                                  case 'parameterGetRequest':
                                                      if (!parameter.dst || !parameter.parameter) return false;
                                                      return '{R06' + parameter.dst + '8010' + parameter.parameter + '}';
                                                      break;
                                                  case 'parameterGetRequestPosition':
                                                      if (!parameter.dst) return false;
                                                      return '{R06' + parameter.dst + '8010' + '01000005}';
                                                      break;
                                                  case 'parameterGetRequestClock':
                                                      if (!parameter.dst) return false;
                                                      return '{R06' + parameter.dst + '8010' + '26000046}';
                                                      break;
                                                  case 'parameterGetRequestAutoSettings':
                                                      if (!parameter.dst) return false;
                                                      return '{R06' + parameter.dst + '8010' + '0C000006}';
                                                      break;
                                                  case 'parameterSetRequestAutoSettings':
                                                      if (!parameter.dst || !parameter.parameter
                                                          || isNaN(parameter.wind) || isNaN(parameter.rain)
                                                          || isNaN(parameter.sun) || isNaN(parameter.dusk))
                                                          return false;
                                                      return '{R06' + parameter.dst + '8020' + '0D000004'
                                                          + ('0' + Math.min(Math.max(parameter.wind, 0), 9).toString(16)).substr(-2).toUpperCase()
                                                          + ('0' + Math.min(Math.max(parameter.rain, 0), 9).toString(16)).substr(-2).toUpperCase()
                                                          + ('0' + Math.min(Math.max(parameter.sun, 0), 9).toString(16)).substr(-2).toUpperCase()
                                                          + ('0' + Math.min(Math.max(parameter.dusk, 0), 9).toString(16)).substr(-2).toUpperCase()
                                                          + (parameter.op ? '01' : '00')
                                                          + '}';
                                                      break;
                                                  case 'parameterSetRequestAutoAll':
                                                      if (!parameter.dst) return false;
                                                      return '{R06' + parameter.dst + '8020' + '0D040001' + (parameter.op ? '01' : '00') + '}';
                                                      break;
                                                  default: //unkown message type
                                                      return false;
                                                      break;
                                              }
                                          }
                                          
                                          1 Reply Last reply Reply Quote 0
                                          • W
                                            willjoha last edited by

                                            Hab mal alles in eine Klasse gepackt. Die ist bei weitem noch nicht fertig und da kann einiges drin sein was man eigentlich so nicht macht. Wie gesagt hab ewig nichts mit JavaScript gemacht und mir das heute soweit nur angelesen.

                                            Im Decoder hab ich heute noch den joinNetworkRequest und scanRequest erfolgreich getestet.

                                            Der Temperaturfühler der Wetterstation ist sehr träge. Fön und Eiswürfel haben nicht wirklich was gebracht.

                                            Encoder hab ich noch nichts großartig angeschaut.

                                            'use strict';
                                            const SerialPort = require('serialport');
                                            const Delimiter = SerialPort.parsers.Delimiter;
                                            
                                            const EventEmitter = require('events');
                                            
                                            class wms extends EventEmitter
                                            {
                                            
                                            constructor()
                                            {
                                            	super();
                                            	this.isOpen = false;
                                            	this.queue = [];
                                            }
                                            
                                            	decodeWMS(packet) {
                                            		var obj = {};
                                            		switch (packet.substr(0, 1)) {
                                            			case 'g':
                                            				obj.type = 'stickType';
                                            				obj.payload = {name: packet.substr(1)};
                                            				break;
                                            			case 'v':
                                            				obj.type = 'stickVersion';
                                            				obj.payload = {version: packet.substr(1)};
                                            				break;
                                            			case 'f':
                                            				obj.type = 'error';
                                            				break;
                                            			case 'a':
                                            				obj.type = 'ack';
                                            				break;
                                            			case 'r':
                                            				obj.type = 'message';
                                            				obj.payload = this.decodeWMSMessage(packet.substr(1));
                                            				break;
                                            			default:
                                            				obj.type = 'unknown';
                                            				obj.payload = packet.substr(1);
                                            		}
                                            		return obj;
                                            	};
                                            
                                            	decodeWMSMessage(message) {
                                            		var obj = {};
                                            		obj.src = message.substr(0, 6);
                                            		var type = message.substr(6, 4);
                                            		var payload = message.substr(10);
                                            		switch (type) {
                                            			case '5018':
                                            				obj.type = 'joinNetworkRequest';
                                            				obj.messagePayload = {
                                            					panId: payload.substr(0, 4),
                                            					networkKey: payload.substr(4, 32).match(/../g).reverse().join(""),
                                            					unknown: payload.substr(36, 2),
                                            					channel: parseInt(payload.substr(38, 2), 16)
                                            				};
                                            				break;
                                            			case '5060':
                                            				obj.type = 'switchChannelRequest';
                                            				obj.messagePayload = {
                                            					panId: payload.substr(0, 4),
                                            					deviceType: payload.substr(4, 2),
                                            					channel: parseInt(payload.substr(6, 2), 16)
                                            				};
                                            				break;
                                            			case '50AC':
                                            				obj.type = 'ack';
                                            				obj.messagePayload = {
                                            					unknown: payload.substr(0, 4)
                                            				};
                                            				break;
                                            			case '7020':
                                            				obj.type = 'scanRequest';
                                            				obj.messagePayload = {
                                            					panId: payload.substr(0, 4),
                                            					deviceType: payload.substr(4, 2)
                                            				};
                                            				break;
                                            			case '7021':
                                            				obj.type = 'scanResponse';
                                            				obj.messagePayload = {
                                            					panId: payload.substr(0, 4),
                                            					deviceType: payload.substr(4, 2), //63: wetterstation, 06: webcontrol, 02: stick/software, 20: zwischenstecker
                                            					unknown: payload.substr(6) //optional
                                            				};
                                            				break;
                                            			case '7080':
                                            				obj.type = 'weatherBroadcast';
                                            				obj.messagePayload = {
                                            					unknown_1: payload.substr(0, 2),
                                            					wind: parseInt(payload.substr(2, 2), 16),
                                            					lumen: payload.substr(4, 2) === '00' ? parseInt(payload.substr(12, 2), 16) * 2 : parseInt(payload.substr(4, 2), 16) * parseInt(payload.substr(12, 2), 16),
                                            					unknown_2: payload.substr(6, 6),
                                            					unknown_3: payload.substr(14, 2),
                                            					rain: payload.substr(16, 2) === 'C8',
                                            					temp: parseInt(payload.substr(18, 2), 16) / 10,
                                            					unknown_4: payload.substr(20)
                                            				};
                                            				break;
                                            			case '7050':
                                            				obj.type = 'beckonRequest';
                                            				break;
                                            			case '7070':
                                            				obj.type = 'controlRequest';
                                            				obj.messagePayload = {
                                            					unknown: payload.substr(0, 2),
                                            					position: parseInt(payload.substr(2, 2), 16) / 2,
                                            					angle: parseInt(payload.substr(4, 2), 16) - 127,
                                            					valance_1: payload.substr(6, 2),
                                            					valance_2: payload.substr(8, 2)
                                            				};
                                            				break;
                                            			case '7071':
                                            				obj.type = 'controlResponse';
                                            				obj.messagePayload = payload;
                                            				break;
                                            			case '8010':
                                            				obj.type = 'parameterGetRequest';
                                            				obj.messagePayload = {
                                            					parameter: payload.substr(0) //01000005: position, 26000046: clock timer settings, 0C000006: auto modes & limits
                                            				};
                                            				break;
                                            			case '8011':
                                            				obj.type = 'parameterGetResponse';
                                            				obj.messagePayload = {
                                            					parameter: payload.substr(0, 8)
                                            				};
                                            				switch (obj.messagePayload.parameter) {
                                            					case '01000003': //position
                                            					case '01000005': //position
                                            						obj.messagePayload.type = 'position';
                                            						obj.messagePayload.position = parseInt(payload.substr(8, 2), 16) / 2;
                                            						obj.messagePayload.angle = parseInt(payload.substr(10, 2), 16) - 127;
                                            						obj.messagePayload.valance_1 = payload.substr(12, 2);
                                            						obj.messagePayload.valance_2 = payload.substr(14, 2);
                                            						break;
                                            					case '0C000006': //auto modes & limits
                                            						obj.messagePayload.type = 'autoSettings';
                                            						obj.messagePayload.wind = parseInt(payload.substr(8, 2), 16);
                                            						obj.messagePayload.rain = parseInt(payload.substr(10, 2), 16);
                                            						obj.messagePayload.sun = parseInt(payload.substr(12, 2), 16);
                                            						obj.messagePayload.dusk = parseInt(payload.substr(14, 2), 16);
                                            						obj.messagePayload.op = parseInt(payload.substr(16, 2), 16);
                                            						break;
                                            					case '26000046':
                                            						obj.messagePayload.type = 'clock';
                                            						obj.messagePayload.unknown = payload.substr(8);
                                            						break;
                                            					default:
                                            						obj.messagePayload.type = 'unknown';
                                            						obj.messagePayload.unknown = payload.substr(8);
                                            				}
                                            				break;
                                            			case '8020':
                                            				obj.type = 'parameterSetRequest';
                                            				obj.messagePayload = {
                                            					parameter: payload.substr(0, 8)
                                            				};
                                            				switch (obj.messagePayload.parameter) {
                                            					case '0B080009':
                                            						obj.messagePayload.type = 'clock';
                                            						obj.messagePayload.year = parseInt(payload.substr(8, 2), 16);
                                            						obj.messagePayload.month = parseInt(payload.substr(10, 2), 16);
                                            						obj.messagePayload.day = parseInt(payload.substr(12, 2), 16);
                                            						obj.messagePayload.hour = parseInt(payload.substr(14, 2), 16);
                                            						obj.messagePayload.minute = parseInt(payload.substr(16, 2), 16);
                                            						obj.messagePayload.second = parseInt(payload.substr(18, 2), 16);
                                            						obj.messagePayload.day_of_week = parseInt(payload.substr(20, 2), 16);
                                            						obj.messagePayload.unknown = payload.substr(22);
                                            						break;
                                            					default:
                                            						obj.messagePayload.type = 'unknown';
                                            						obj.messagePayload.unknown = payload.substr(8);
                                            				}
                                            				break;
                                            			default:
                                            				obj.type = 'unknown';
                                            				obj.messagePayload = payload;
                                            		}
                                            		return obj;
                                            	};
                                            
                                            	encodeWMS(type, parameter) {
                                            		if (!parameter) parameter = {};
                                            		switch (type) {
                                            			case 'switchChannel':
                                            				if (isNaN(parameter.channel)) return false;
                                            				return '{M%' + parameter.channel + 'FFFF}';
                                            				break;
                                            			case 'ack':
                                            				if (!parameter.dst) return false;
                                            				return '{R21' + parameter.dst + '50AC}';
                                            				break;
                                            			case 'switchChannelRequest': //channel 17 fixed
                                            				if (!parameter.panId) return false;
                                            				return '{R04FFFFFF5060' + parameter.panId + '021100}'; // dst or FFFFFF???
                                            				break;
                                            			case 'scanRequest':
                                            				return '{R04FFFFFF7020' + parameter.panId + '02}';
                                            				break;
                                            			case 'scanResponse':
                                            				if (!parameter.panId || !parameter.dst) return false;
                                            				return '{R01' + parameter.dst + '7021' + parameter.panId + '02}'; //fixed to deviceType 02 for now
                                            				break;
                                            			case 'beckonRequest':
                                            				if (!parameter.dst) return false;
                                            				return '{R06' + parameter.dst + '7050}';
                                            				break;
                                            			case 'controlRequest':
                                            				if (!parameter.dst || isNaN(parameter.position) || isNaN(parameter.angle)) return false;
                                            				return '{R06' + parameter.dst + '7070' + '03'
                                            					+ ('0' + (Math.min(Math.max(parameter.position, 0), 100) * 2).toString(16)).substr(-2).toUpperCase()
                                            					+ ('0' + (Math.min(Math.max(parameter.angle, 0), 90) + 127).toString(16)).substr(-2).toUpperCase()
                                            					+ 'FFFF}'; //no idea how valance works
                                            				break;
                                            			case 'parameterGetRequest':
                                            				if (!parameter.dst || !parameter.parameter) return false;
                                            				return '{R06' + parameter.dst + '8010' + parameter.parameter + '}';
                                            				break;
                                            			case 'parameterGetRequestPosition':
                                            				if (!parameter.dst) return false;
                                            				return '{R06' + parameter.dst + '8010' + '01000005}';
                                            				break;
                                            			case 'parameterGetRequestClock':
                                            				if (!parameter.dst) return false;
                                            				return '{R06' + parameter.dst + '8010' + '26000046}';
                                            				break;
                                            			case 'parameterGetRequestAutoSettings':
                                            				if (!parameter.dst) return false;
                                            				return '{R06' + parameter.dst + '8010' + '0C000006}';
                                            				break;
                                            			case 'parameterSetRequestAutoSettings':
                                            				if (!parameter.dst || !parameter.parameter
                                            					|| isNaN(parameter.wind) || isNaN(parameter.rain)
                                            					|| isNaN(parameter.sun) || isNaN(parameter.dusk))
                                            					return false;
                                            				return '{R06' + parameter.dst + '8020' + '0D000004'
                                            					+ ('0' + Math.min(Math.max(parameter.wind, 0), 9).toString(16)).substr(-2).toUpperCase()
                                            					+ ('0' + Math.min(Math.max(parameter.rain, 0), 9).toString(16)).substr(-2).toUpperCase()
                                            					+ ('0' + Math.min(Math.max(parameter.sun, 0), 9).toString(16)).substr(-2).toUpperCase()
                                            					+ ('0' + Math.min(Math.max(parameter.dusk, 0), 9).toString(16)).substr(-2).toUpperCase()
                                            					+ (parameter.op ? '01' : '00')
                                            					+ '}';
                                            				break;
                                            			case 'parameterSetRequestAutoAll':
                                            				if (!parameter.dst) return false;
                                            				return '{R06' + parameter.dst + '8020' + '0D040001' + (parameter.op ? '01' : '00') + '}';
                                            				break;
                                            			default: //unkown message type
                                            				return false;
                                            				break;
                                            		}
                                            	}
                                            
                                            	onData(data)
                                            	{
                                            		var message = this.decodeWMS(data.toString('ascii',1));
                                            
                                            		switch(message.type)
                                            		{
                                            			case 'stickType':
                                            				var next = this.getExpectedMessage('stickType');
                                            				if(next != undefined)
                                            				{
                                            					next.resolve(message);
                                            				}
                                            				break;
                                            			case 'stickVersion':
                                            				var next = this.getExpectedMessage('stickVersion');
                                            				if(next != undefined)
                                            				{
                                            					next.resolve(message.payload.version);
                                            				}
                                            				break;
                                            			case 'error':
                                            			case 'ack':
                                            				var next = this.getExpectedMessage('ack');
                                            				if(next != undefined)
                                            				{
                                            					if(message.type === 'ack') {
                                            						next.resolve();
                                            					} else {
                                            						next.reject(new Error('WMS Stick rejected the command'));
                                            					}
                                            				}
                                            				break;
                                            			case 'message':
                                            				switch(message.payload.type)
                                            				{
                                            					case 'weatherBroadcast':
                                            						this.emit('weatherBroadcast', message);
                                            						break;
                                            					case 'parameterGetResponse':
                                            						var next = this.getExpectedMessage('message', {'src': message.payload.src, 'msgType': message.payload.type, 'parameterType': message.payload.messagePayload.type});
                                            						if(next != undefined)
                                            						{
                                            							next.resolve(message);
                                            						}
                                            						break;
                                            				}
                                            				break;
                                            			default: this.emit('unknown', message);
                                            		}
                                            	};
                                            
                                            	open(path) {
                                            		var promise = new Promise( (resolve, reject) => {
                                            			this.port = new SerialPort(path, {baudRate: 125000}, (error) => {
                                            				if(error)
                                            				{
                                            					reject(error);
                                            					return;
                                            				}
                                            				this.parser = this.port.pipe(new Delimiter( {delimiter: '}'}));
                                            				this.parser.on('data', (data) => {this.onData(data)} );
                                            				resolve();
                                            			});
                                            		});
                                            
                                            		return promise.then(() => {
                                            			return this.getStickType();
                                            		}, (error) => {
                                            			this.isOpen = false;
                                            			return Promise.reject(error);
                                            		}).then((wms) => {
                                            			this.isOpen = true;
                                            			return Promise.resolve();
                                            		}, (error) => {
                                            			this.isOpen = false;
                                            			return Promise.reject(error);
                                            		});
                                            
                                            	};
                                            
                                            	close() {
                                            		this.port.drain(() => {
                                            			this.port.close();
                                            			this.isOpen = false;
                                            		});
                                            	}
                                            
                                            	getExpectedMessage(type, parameter)
                                            	{
                                            		if(this.queue[type] == undefined)
                                            		{
                                            			this.queue[type] = [];
                                            		}
                                            		if(type !== 'message') {
                                            			return(this.queue[type].shift());
                                            		} else {
                                            			if(this.queue[type][parameter.src] == undefined)
                                            			{
                                            				this.queue[type][parameter.src] = [];
                                            			}
                                            			if(this.queue[type][parameter.src][parameter.msgType] == undefined)
                                            			{
                                            				this.queue[type][parameter.src][parameter.msgType] = [];
                                            			}
                                            			if(parameter.msgType === 'parameterGetResponse')
                                            			{
                                            				if(this.queue[type][parameter.src][parameter.msgType][parameter.parameterType] == undefined)
                                            				{
                                            					this.queue[type][parameter.src][parameter.msgType][parameter.parameterType] = [];
                                            				}
                                            				return this.queue[type][parameter.src][parameter.msgType][parameter.parameterType].shift();
                                            			} else {
                                            				return this.queue[type][parameter.src][parameter.msgType].shift();
                                            			}
                                            		}
                                            	}
                                            
                                            	addExpectedMessage(type, ms, parameter) {
                                            		let promise = new Promise( (resolve, reject) => {
                                            			if(this.queue[type] == undefined)
                                            			{
                                            				this.queue[type] = [];
                                            			}
                                            			if(type !== 'message')
                                            			{
                                            				this.queue[type].push({'resolve': resolve, 'reject': reject, 'parameter': parameter});
                                            			} else {
                                            				if(this.queue[type][parameter.src] == undefined)
                                            				{
                                            					this.queue[type][parameter.src] = [];
                                            				}
                                            				if(this.queue[type][parameter.src][parameter.msgType] == undefined)
                                            				{
                                            					this.queue[type][parameter.src][parameter.msgType] = [];
                                            				}
                                            				if(parameter.msgType === 'parameterGetResponse')
                                            				{
                                            					if(this.queue[type][parameter.src][parameter.msgType][parameter.parameterType] == undefined)
                                            					{
                                            						this.queue[type][parameter.src][parameter.msgType][parameter.parameterType] = [];
                                            					}
                                            					this.queue[type][parameter.src][parameter.msgType][parameter.parameterType].push({'resolve': resolve, 'reject': reject, 'parameter': parameter});
                                            				} else {
                                            					this.queue[type][parameter.src][parameter.msgType].push({'resolve': resolve, 'reject': reject, 'parameter': parameter});
                                            				}
                                            			}
                                            		});
                                            		let timeout = new Promise((resolve, reject) => {
                                            			let id = setTimeout(() => {
                                            				clearTimeout(id);
                                            				this.getExpectedMessage(type, parameter);
                                            				reject('Message ' + type + ' timedout in ' + ms + ' ms')
                                            			}, ms)
                                            		});
                                            
                                            		return Promise.race([
                                            			promise,
                                            			timeout
                                            		]);
                                            	}
                                            
                                            	getStickType() {
                                            		let promise = this.addExpectedMessage('stickType', 100);
                                            		this.port.write('{G}');
                                            		return promise;
                                            	}
                                            
                                            	getStickVersion() {
                                            		let promise = this.addExpectedMessage('stickVersion', 100);
                                            		this.port.write('{V}');
                                            		return promise;
                                            	}
                                            
                                            	getPosition(dst) {
                                            		let promises = [];
                                            		promises.push(this.addExpectedMessage('ack', 100));
                                            		promises.push(this.addExpectedMessage('message', 200, {'src': dst, 'msgType': 'parameterGetResponse', 'parameterType': 'position'}));
                                            		this.port.write(this.encodeWMS('parameterGetRequestPosition', {'dst': dst}));
                                            		return Promise.all(promises);
                                            	}
                                            
                                            	static list()
                                            	{
                                            		return SerialPort.list().
                                            			then( (ports) => {
                                            				var portPromises = [];
                                            				ports.forEach( (port) => {
                                            					portPromises.push(new Promise( (resolve, reject) => {
                                            						let tempWMS = new wms();
                                            						tempWMS.open(port.comName).then( () => {
                                            							tempWMS.close();
                                            							resolve({'comName': port.comName, 'isWMSStick': true});
                                            						}, (error) => {
                                            							tempWMS.close();
                                            							resolve({'comName': port.comName, 'isWMSStick': false})
                                            						});
                                            					}));
                                            
                                            				});
                                            				return Promise.all(portPromises);
                                            			}, (error) =>{
                                            				return Promise.rejected(error);
                                            			});
                                            	};
                                            
                                            };
                                            
                                            const myWMS = new wms();
                                            
                                            wms.list().then((lst) => {
                                            	console.log(lst);
                                            
                                            	setTimeout(function () {	
                                            		myWMS.open('COM3').then(() => {
                                            			myWMS.getStickVersion().then(console.log, console.error);
                                            			myWMS.getPosition('AAAAAA').then(console.log, console.error);
                                            		}, console.error);
                                            		myWMS.on('weatherBroadcast', (msg) => {console.log(msg)});
                                            	}, 10000);	
                                            
                                            }, console.error);
                                            
                                            
                                            1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post

                                            Support us

                                            ioBroker
                                            Community Adapters
                                            Donate
                                            FAQ Cloud / IOT
                                            HowTo: Node.js-Update
                                            HowTo: Backup/Restore
                                            Downloads
                                            BLOG

                                            570
                                            Online

                                            31.6k
                                            Users

                                            79.5k
                                            Topics

                                            1.3m
                                            Posts

                                            26
                                            121
                                            26462
                                            Loading More Posts
                                            • Oldest to Newest
                                            • Newest to Oldest
                                            • Most Votes
                                            Reply
                                            • Reply as topic
                                            Log in to reply
                                            Community
                                            Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
                                            The ioBroker Community 2014-2023
                                            logo