Skip to content
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Standard: (Kein Skin)
  • Kein Skin
Einklappen
ioBroker Logo

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. ioBroker Allgemein
  4. IoBroker mit Warema WMS Web Control

NEWS

  • UPDATE 31.10.: Amazon Alexa - ioBroker Skill läuft aus ?
    apollon77A
    apollon77
    48
    3
    8.7k

  • Monatsrückblick – September 2025
    BluefoxB
    Bluefox
    13
    1
    2.1k

  • Neues Video "KI im Smart Home" - ioBroker plus n8n
    BluefoxB
    Bluefox
    16
    1
    3.0k

IoBroker mit Warema WMS Web Control

Geplant Angeheftet Gesperrt Verschoben ioBroker Allgemein
127 Beiträge 26 Kommentatoren 39.1k Aufrufe 18 Watching
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • W Offline
    W Offline
    willjoha
    schrieb am zuletzt editiert von
    #14

    @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 Antwort Letzte Antwort
    0
    • P Offline
      P Offline
      Pman
      schrieb am zuletzt editiert von
      #15

      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 Antwort Letzte Antwort
      0
      • R Offline
        R Offline
        radiorichter
        schrieb am zuletzt editiert von
        #16

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

        1 Antwort Letzte Antwort
        0
        • W Offline
          W Offline
          willjoha
          schrieb am zuletzt editiert von
          #17

          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 Antwort Letzte Antwort
          0
          • P Offline
            P Offline
            Pman
            schrieb am zuletzt editiert von
            #18

            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 Antwort Letzte Antwort
            0
            • W Offline
              W Offline
              willjoha
              schrieb am zuletzt editiert von
              #19

              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 Antwort Letzte Antwort
              0
              • P Offline
                P Offline
                Pman
                schrieb am zuletzt editiert von
                #20

                @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 Antwort Letzte Antwort
                0
                • P Offline
                  P Offline
                  Pman
                  schrieb am zuletzt editiert von
                  #21

                  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 Antwort Letzte Antwort
                  0
                  • P Offline
                    P Offline
                    Pman
                    schrieb am zuletzt editiert von
                    #22

                    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 Antwort Letzte Antwort
                    0
                    • W Offline
                      W Offline
                      willjoha
                      schrieb am zuletzt editiert von
                      #23

                      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 Antwort Letzte Antwort
                      0
                      • P Offline
                        P Offline
                        Pman
                        schrieb am zuletzt editiert von
                        #24

                        Die Klasse werde ich mir mal angucken.

                        Ich habe kleinere Verbesserungen an Decode und Encoder vorgenommen.

                        Weiterhin habe ich in den technischen Daten für meine Wetterstation PLUS gefunden, dass der Messbereich Helligkeit im Bereich 0-100klx und bei Dämmerung im Bereich 0-500lx liegt. Das wären das wohl genau die beiden Fälle, welche du unterscheidest, wobei ich bei klx den Wert noch mal 2 nehmen musste. Heute bei Sonne hat sich der Wert nämlich bei 50klx an die Wand gefahren (C8FFFFFFFAF).

                        Temperatur kommt auch noch nicht wirklich hin, da muss die Formel eine andere sein. Das Ergebnis sollte laut den technischen Daten zwischen -25°C und 60°C liegen. Wobei auch hier evtl. gar nicht der ganze Wertebereich (00-FF) genutzt wird. Eine sehr einfache Rechnung, welche aber für meine bisherigen Messungen mit einem anderen Außenthermometer übereinstimmen wäre: WERT / 2 - 35.

                        Wind könnte WERT / 10 sein (0-25m/s).

                        Technische Daten:

                        https://www.warema.de/Produkte/Steuerun … n_plus.php

                        Hier nochmal die aktualisierten Funktionen:

                        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) / 10,
                                        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) * 2,
                                        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) / 2 - 35,
                                        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;
                        }
                        
                        function encodeWMS(type, parameter) {
                            if (!parameter) parameter = {};
                            switch (type) {
                                case 'setKey':
                                    if (!parameter.key) return false;
                                    return '{K401' + parameter.key + '}';
                                    break;
                                case 'setScanMode':
                                    if (isNaN(parameter.channel) || !parameter.panId) return false;
                                    return '{M#' + parameter.channel + parameter.panId.match(/../g).reverse().join("") + '}';
                                    break;
                                case 'switchChannel':
                                    if (isNaN(parameter.channel) || !parameter.panId) return false;
                                    return '{M%' + parameter.channel + parameter.panId + '}';
                                    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 Antwort Letzte Antwort
                        0
                        • W Offline
                          W Offline
                          willjoha
                          schrieb am zuletzt editiert von
                          #25

                          Ja, Formel für die Temperatur könnte hinkommen. Hab jetzt auch noch mal mit einem anderen Thermometer geprüft.

                          Wie ich meine erste eingebaut habe waren es um die 10° hätte dann hingehauen ;)

                          Für Wind gehe ich davon aus das keine Umrechnung nötig ist. Für Regen haben sie es auch nicht gemacht,

                          da kommen genau die 200 die auch in der Dokumentation stehen.

                          1 Antwort Letzte Antwort
                          0
                          • P Offline
                            P Offline
                            Pman
                            schrieb am zuletzt editiert von
                            #26

                            Temperatur fällt im moment ab und nach meiner Formel weiterhin alles synchron mit dem anderen Thermometer, natürlich nicht aufs zehntel Grad genau.

                            Wind durch 10 wäre tatsächlich zu wenig, andersrum kommt es mir ohne aber auch zu viel vor. 5-6m/s bei quasi Windstille. Kann natürlich auch sein, dass der Sensor bei sehr wenig Wind nicht gut funktioniert, die Wetterstation Plus hat keinen mechanischen Sensor dafür.

                            1 Antwort Letzte Antwort
                            0
                            • P Offline
                              P Offline
                              Pman
                              schrieb am zuletzt editiert von
                              #27

                              So ich hatte nun ein wenig Zeit und habe mir mal ein komplettes Skript für ioBroker.javascript gebastelt um alles zu testen.

                              So weit funktioniert alles, allerdings ist mir aufgefallen, dass Kanäle noch komplett fehlen.

                              Daher wollte ich mal nachfragen, ob du dazu irgendwelche Infos hast?

                              Ich nehme an zum auslesen und setzen von Kanalzugehörigkeiten eines Gerätes wird einen weiteren Parameter geben.

                              Die Frage ist, wie man an einen Kanal sendet, evtl. per Broadcast?

                              1 Antwort Letzte Antwort
                              0
                              • W Offline
                                W Offline
                                willjoha
                                schrieb am zuletzt editiert von
                                #28

                                Bin in den letzten Tagen auch nicht zu viel gekommen. Wollte noch die Messwerte der Wetterstation mit dem Handsender überprüfen allerdings war der Wind nie Stark genug und ich immer zu Spät um die Lumen noch ordentlich zu prüfen…

                                Ansonsten verstehe ich mittlerweile ein paar Byte der Control Response.

                                Hast du in deinem Script meine Klasse verwendet oder etwas eigenes geschrieben?

                                Zum Thema Kanäle: Da bin ich mir ziemlich sicher das diese nur im Handsender bzw WebControl existieren. Wenn der Handsender an einen Kanal mit 4 Aktoren einen Befehl schickt leuchtet die sende LED genau 4 mal. Bei einem WebControl Kanal mit 2 Aktoren hab ich da entsprechend dann auch 2 Nachrichten an die einzelnen Aktoren mit dem ConBee mit geschnitten. Um ganz sicher zu sein könnten wir einem Handsender beim einlernen des Sticks mal vorgaukeln der Stick sei ein Zwischenstecker. Dann könnten wir den Stick im Handsender einem Kanal zuordnen. Bin mir ziemlich sicher das der Stick in diesem Fall nicht mitgeteilt bekommt auf welchen Kanal er programmiert wurde.

                                1 Antwort Letzte Antwort
                                0
                                • P Offline
                                  P Offline
                                  Pman
                                  schrieb am zuletzt editiert von
                                  #29

                                  Das mit den Kanälen klingt plausibel. Ich denke mittlerweile, der Windwert funktioniert wie von die beschrieben, bei Temperatur kommt meine Formel zumindest ungefähr hin. Es könnte natürlich eine richtigere Formel (mit sehr ähnlichen) Ergebnissen geben.

                                  Ich habe für das Skript zum testen einfach die Funktionen zusammengewüftelt, müsste aber leicht auf deine Klasse übertragbar sein bzw. die relevanten Funktionen einfach in eine Klasse übertragbar sein. Ich poste das Skript dir hier einfach mal.

                                  Die Funktionalität steckt im Prinzip komplett in processWMS, wo auf die ankommenden Packete entsprechend reagiert wird. In dieser Funktion wird dann natürlich auch massiv gebrauch von der ioBroker-API gemacht, also Datenpunkte erstellt und verändert usw..

                                  Verwendung des Skripts:

                                  Mit den default-Werten für PANID und KEY müsste sich das Skript im Anlernmodus befinden, kann also über Handsender eingelernt werden, KEY und PANID werden dabei im log ausgegeben.

                                  Sobald PANID und KEY im Skript hinterlegt werden, wird der Stick damit versorgt und fragt beim Start (und in regelmäßigen Abständen) Raffstore und Wetterstationen ab, speichert die Werte in Datenpunkten und reagiert umgekehrt auf Änderungen in den Datenpunkten 'level' und 'angle'.

                                  var namespace = 'WMS';
                                  var SerialPort = require('serialport');
                                  
                                  //config
                                  const PATH = "/dev/ttyUSB0";
                                  const CHANNEL = 17;
                                  const PANID = "FFFF"; //inclusion mode: FFFF
                                  const KEY = "00112233445566778899AABBCCDDEEFF"; //inclusion mode: "00112233445566778899AABBCCDDEEFF"
                                  var positionInterval = 60; //how often current position is requested (seconds)
                                  var scanInterval = 600;  //how often to scan for devices (seconds)
                                  //listPorts();  //uncomment to list all available serial ports
                                  
                                  /* do not edit below! */
                                  //globals
                                  var knownDevices = {}; //stores known devices
                                  var lastData = ''; //contains last packet
                                  var writeQueue = []; //stores data to be sent to serial port
                                  var timers = {};
                                  
                                  /* open serial port and setup parser */
                                  function init() {
                                      //scan 3 times
                                      setTimeout(function () {
                                          wmsScan();
                                      }, 5000);
                                      setTimeout(function () {
                                          wmsScan();
                                      }, 10000);
                                      setTimeout(function () {
                                          wmsScan();
                                      }, 30000);
                                      //scan again every scanInterval seconds
                                      setInterval(function () {
                                          wmsScan();
                                      }, scanInterval * 1000);
                                  }
                                  
                                  //connect to serial port
                                  const port = new SerialPort(PATH, {
                                      baudRate: 125000,
                                      parity: 'none',
                                      dataBits: 8,
                                      stopBits: 1,
                                      autoOpen: false,
                                  });
                                  //create parser with '}' as delemiter
                                  const parser = port.pipe(new SerialPort.parsers.Readline({delimiter: '}'}));
                                  
                                  // handle serial port errors
                                  port.on('error', function () {
                                      log('serial port error!', 'warn');
                                      closePort();
                                  });
                                  
                                  //parse incomming packets
                                  parser.on('data', parseData);
                                  
                                  //open serial port
                                  portOpen().then((msg) => {
                                      log(msg);
                                      writeAndWaitFor('{G}', 'gWMS USB-Stick', true).then((line) => {
                                          return writeAndWaitFor('{V}', 'v', true);
                                      }).then((line) => {
                                          log('Stick Version: ' + line);
                                          return writeAndWaitFor(encodeWMS('setKey', {key: KEY}), 'a', true);
                                      }).then((line) => {
                                          return writeAndWaitFor(encodeWMS('switchChannel', {
                                              channel: CHANNEL,
                                              panId: PANID
                                          }), 'a', true);
                                      }).then((line) => {
                                          init();
                                      }).catch((err) => {
                                          log(err, 'warn');
                                          closePort();
                                      });
                                  }).catch((err) => {
                                      log(err, 'warn');
                                  });
                                  
                                  /* serialport helper functions */
                                  
                                  //opens port with promise
                                  function portOpen() {
                                      return new Promise((resolve, reject) => {
                                          port.open((err) => {
                                              err ? reject(err) : resolve('port opened');
                                          })
                                      });
                                  }
                                  
                                  //close port if open
                                  function closePort() {
                                      return new Promise((resolve, reject) => {
                                          log('closing open serial ports', 'warn');
                                          if (port && port.isOpen) {
                                              // close connection
                                              port.close(() => {
                                                  resolve('port closed')
                                              });
                                          } else {
                                              reject('no port was opened');
                                          }
                                      });
                                  }
                                  
                                  //on script stop close port
                                  onStop(closePort, 2000);
                                  
                                  //handle incomming data
                                  function parseData(data) {
                                      //trim data
                                      data = wmsTrim(data);
                                      //do nothing, if packet is received twice
                                      if (lastData === data) return
                                      lastData = data;
                                      log('received message: ' + data, 'debug');
                                      //decode data into object
                                      var obj = decodeWMS(data);
                                      log(JSON.stringify(obj), 'debug');
                                      //process object
                                      processWMS(obj);
                                  }
                                  
                                  //list available serial ports
                                  function listPorts() {
                                      SerialPort.list().then((ports) => {
                                          log('Serial Ports: ' + JSON.stringify(ports));
                                      }).catch((err) => {
                                          log('error listing ports: ' + JSON.stringify(err));
                                      });
                                  }
                                  
                                  //write to serial port and wait for answer
                                  function writeAndWaitFor(data, expect, rejectOnTimeout, timeout) {
                                      return new Promise((resolve, reject) => {
                                          if (isNaN(timeout)) timeout = 5000;
                                          log('sending ' + data, 'debug');
                                          listener = (line) => {
                                              if (wmsTrim(line).substr(0, expect.length) === expect) {
                                                  log('received expected answer: ' + expect, 'debug');
                                                  parser.removeListener('data', listener);
                                                  resolve(wmsTrim(line));
                                              } else {
                                                  log('received unexpected answer (still waiting): ' + wmsTrim(line).substr(0, expect.length) + '!=' + expect, 'debug');
                                              }
                                          };
                                          parser.on('data', listener);
                                          enqueue(data);
                                          //remove listener after 5 seconds
                                          setTimeout(() => {
                                              parser.removeListener('data', listener);
                                              rejectOnTimeout ? reject(expect) : resolve(false);
                                          }, timeout);
                                      });
                                  }
                                  
                                  function enqueue(data) {
                                      if (typeof data === 'string') writeQueue.push(data);
                                      if (writeQueue.length === 1) {
                                          port.write(writeQueue.shift());
                                          port.drain((err) => {
                                              if (writeQueue.length) enqueue();
                                          });
                                      }
                                  }
                                  
                                  /* WMS helper functions */
                                  
                                  //trim wms string
                                  function wmsTrim(data) {
                                      return data.trim().substr(1);
                                  }
                                  
                                  //decode wms strings into an object
                                  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;
                                  }
                                  
                                  //decode wms messages into an object
                                  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) * 2,
                                                  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) / 2 - 35,
                                                  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;
                                  }
                                  
                                  //create wms strings
                                  function encodeWMS(type, parameter) {
                                      if (!parameter) parameter = {};
                                      switch (type) {
                                          case 'setKey':
                                              if (!parameter.key) return false;
                                              return '{K401' + parameter.key + '}';
                                              break;
                                          case 'setScanMode':
                                              if (isNaN(parameter.channel) || !parameter.panId) return false;
                                              return '{M#' + parameter.channel + parameter.panId.match(/../g).reverse().join("") + '}';
                                              break;
                                          case 'switchChannel':
                                              if (isNaN(parameter.channel) || !parameter.panId) return false;
                                              return '{M%' + parameter.channel + parameter.panId + '}';
                                              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;
                                      }
                                  }
                                  
                                  //process packets
                                  function processWMS(obj) {
                                      //log(JSON.stringify(obj));
                                      if (obj.type !== 'message') return;
                                      switch (obj.payload.type) {
                                          case 'switchChannelRequest':
                                              log('received switchChannelRequest, switching channel to ' + obj.payload.messagePayload.channel, 'debug');
                                              writeAndWaitFor(encodeWMS('switchChannel', {
                                                  channel: obj.payload.messagePayload.channel,
                                                  panId: PANID
                                              }), 'a');
                                              break;
                                          case 'scanRequest':
                                              // send scanResponse
                                              log('received scanRequest, sending scanResponse', 'debug');
                                              writeAndWaitFor(encodeWMS('scanResponse', {dst: obj.payload.src, panId: PANID}), 'a');
                                              break;
                                          case 'joinNetworkRequest':
                                              log('received joinNetworkRequest:', 'debug');
                                              log('KEY: ' + obj.payload.messagePayload.networkKey);
                                              log('CHANNEL: ' + obj.payload.messagePayload.channel);
                                              log('PANID: ' + obj.payload.messagePayload.panId);
                                              writeAndWaitFor(encodeWMS('ack', {dst: obj.payload.src}), 'a');
                                              break;
                                          case 'scanResponse':
                                              log('received scanResponse', 'debug');
                                              log('TYPE: ' + obj.payload.messagePayload.deviceType, 'debug');
                                              log('SNR:' + obj.payload.src, 'debug');
                                              if (obj.payload.messagePayload.deviceType === '20') {
                                                  createState(this.namespace + '.Raffstore.' + obj.payload.src + '.position', 0, false, {
                                                      type: 'number',
                                                      min: 0,
                                                      max: 100,
                                                      unit: '%'
                                                  });
                                                  createState(this.namespace + '.Raffstore.' + obj.payload.src + '.angle', 0, false, {
                                                      type: 'number',
                                                      min: 0,
                                                      max: 90,
                                                      unit: '°'
                                                  }, function () {
                                                      if (knownDevices[obj.payload.src]) return;
                                                      knownDevices[obj.payload.src] = true;
                                                      var src = obj.payload.src;
                                                      log('device type 20 found: ' + src);
                                                      var deviceId = 'javascript.' + instance + '.' + this.namespace + '.Raffstore.' + src;
                                                      on({id: deviceId + '.position', change: 'ne', ack: false}, function (obj) {
                                                          //send parameter
                                                          writeAndWaitFor(
                                                              encodeWMS('controlRequest', {
                                                                  dst: src,
                                                                  position: obj.state.val,
                                                                  angle: getState(deviceId + '.angle').val
                                                              }),
                                                              'r' + src + '7071'
                                                          ).then(() => {
                                                              var lastValue = getState(deviceId + '.position').val;
                                                              writeAndWaitFor(encodeWMS('parameterGetRequestPosition', {dst: src}), 'a');
                                                              var timer = setInterval(function () {
                                                                  //get parameter periodicaly until no change is detected
                                                                  log(getState(deviceId + '.position').val + ':' + lastValue, 'debug')
                                                                  if (getState(deviceId + '.position').val === lastValue)
                                                                      clearInterval(timer);
                                                                  lastValue = getState(deviceId + '.position').val;
                                                                  writeAndWaitFor(encodeWMS('parameterGetRequestPosition', {dst: src}), 'a');
                                                              },  3500);
                                                              //setState(deviceId + '.position', getState(deviceId + '.position').val, true);
                                                          });
                                                      });
                                                      on({id: deviceId + '.angle', change: 'ne', ack: false}, function (obj) {
                                                          //send parameter
                                                          writeAndWaitFor(encodeWMS('controlRequest', {
                                                                  dst: src,
                                                                  position: getState(deviceId + '.position').val,
                                                                  angle: obj.state.val
                                                              }),
                                                              'r' + src + '7071'
                                                          ).then(() => {
                                                              var lastValue = getState(deviceId + '.angle').val;
                                                              writeAndWaitFor(encodeWMS('parameterGetRequestPosition', {dst: src}), 'a');
                                                              var timer = setInterval(function () {
                                                                  //get parameter periodicaly until no change is detected
                                                                  log(getState(deviceId + '.angle').val + ':' + lastValue, 'debug')
                                                                  if (getState(deviceId + '.angle').val === lastValue)
                                                                      clearInterval(timer);
                                                                  lastValue = getState(deviceId + '.angle').val;
                                                                  writeAndWaitFor(encodeWMS('parameterGetRequestPosition', {dst: src}), 'a');
                                                              },  3500);
                                                              //setState(deviceId + '.angle', getState(deviceId + '.angle').val, true);
                                                          });
                                                      });
                                                      setTimeout(function () {
                                                          //get parameter once
                                                          writeAndWaitFor(encodeWMS('parameterGetRequestPosition', {dst: src}), 'a');
                                                      }, 5000 + Math.random() * 5000);
                                                      setInterval(function () {
                                                          //get parameter periodicaly
                                                          writeAndWaitFor(encodeWMS('parameterGetRequestPosition', {dst: src}), 'a');
                                                      }, positionInterval * 1000 + Math.random() * 5000);
                                                  });
                                              }
                                              break;
                                          case 'parameterGetResponse':
                                              log('received parameterGetResponse', 'debug');
                                              switch (obj.payload.messagePayload.type) {
                                                  case 'position':
                                                      setStateDelayed(this.namespace + '.Raffstore.' + obj.payload.src + '.position', obj.payload.messagePayload.position, true, 100, true);
                                                      setStateDelayed(this.namespace + '.Raffstore.' + obj.payload.src + '.angle', obj.payload.messagePayload.angle, true, 100, true);
                                                  default:
                                                      break;
                                              }
                                              break;
                                          case 'weatherBroadcast':
                                              log('received weatherBroadcast', 'debug');
                                              createState(this.namespace + '.Wetter.' + obj.payload.src + '.temp', 0, false, {
                                                  type: 'number',
                                                  unit: '°C',
                                                  write: false
                                              }, function () {
                                                  setStateDelayed(this.namespace + '.Wetter.' + obj.payload.src + '.temp', obj.payload.messagePayload.temp, true, 100, true);
                                              });
                                              createState(this.namespace + '.Wetter.' + obj.payload.src + '.wind', 0, false, {
                                                  type: 'number',
                                                  min: 0,
                                                  unit: 'm/s',
                                                  write: false
                                              }, function () {
                                                  setStateDelayed(this.namespace + '.Wetter.' + obj.payload.src + '.wind', obj.payload.messagePayload.wind, true, 100, true);
                                              });
                                              createState(this.namespace + '.Wetter.' + obj.payload.src + '.lux', 0, false, {
                                                  type: 'number',
                                                  min: 0,
                                                  unit: 'lux',
                                                  write: false
                                              }, function () {
                                                  setStateDelayed(this.namespace + '.Wetter.' + obj.payload.src + '.lux', obj.payload.messagePayload.lumen, true, 100, true);
                                              });
                                              createState(this.namespace + '.Wetter.' + obj.payload.src + '.rain', false, false, {
                                                  type: 'boolean',
                                                  write: false
                                              }, function () {
                                                  setStateDelayed(this.namespace + '.Wetter.' + obj.payload.src + '.rain', obj.payload.messagePayload.rain, true, 100, true);
                                              });
                                              break;
                                          default:
                                              break;
                                      }
                                  }
                                  
                                  //scan for devices
                                  function wmsScan() {
                                      writeAndWaitFor(encodeWMS('scanRequest', {panId: PANID}), 'a');
                                  }
                                  
                                  
                                  1 Antwort Letzte Antwort
                                  0
                                  • P Offline
                                    P Offline
                                    Pman
                                    schrieb am zuletzt editiert von
                                    #30

                                    Wie sieht es eigtl. mit dem STOP-Befehl aus? Hast du da etwas?

                                    1 Antwort Letzte Antwort
                                    0
                                    • L Offline
                                      L Offline
                                      LaBamba
                                      schrieb am zuletzt editiert von
                                      #31

                                      Wirklich schade, dass anscheinend dieses Thema Warema Raffstoresteuerung nicht mehr weiterverfolgt wird und ein offizieller Adapter für den ioBroker geschaffen wird. Leider habe ich wenig Ahnung von der Programmierung aber ich kenne mindest 10 Leute die sich auch freuen würden.

                                      1 Antwort Letzte Antwort
                                      0
                                      • R Offline
                                        R Offline
                                        radiorichter
                                        schrieb am zuletzt editiert von
                                        #32

                                        @LaBamba:

                                        Wirklich schade, dass anscheinend dieses Thema Warema Raffstoresteuerung nicht mehr weiterverfolgt wird und ein offizieller Adapter für den ioBroker geschaffen wird. Leider habe ich wenig Ahnung von der Programmierung aber ich kenne mindest 10 Leute die sich auch freuen würden. ` Geht mir leider genau so. Wäre auch dazu bereit mitzuhelfen wo ich nur kann ;) oder auch Spenden wenn's sein muss :)

                                        Gesendet von meinem HUAWEI VNS-L21 mit Tapatalk

                                        1 Antwort Letzte Antwort
                                        0
                                        • P Offline
                                          P Offline
                                          Pman
                                          schrieb am zuletzt editiert von
                                          #33

                                          Leider keine Zeit, das Skript ist aber so lauffähig!

                                          1 Antwort Letzte Antwort
                                          0
                                          Antworten
                                          • In einem neuen Thema antworten
                                          Anmelden zum Antworten
                                          • Älteste zuerst
                                          • Neuste zuerst
                                          • Meiste Stimmen


                                          Support us

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

                                          434

                                          Online

                                          32.4k

                                          Benutzer

                                          81.5k

                                          Themen

                                          1.3m

                                          Beiträge
                                          Community
                                          Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
                                          ioBroker Community 2014-2025
                                          logo
                                          • Anmelden

                                          • Du hast noch kein Konto? Registrieren

                                          • Anmelden oder registrieren, um zu suchen
                                          • Erster Beitrag
                                            Letzter Beitrag
                                          0
                                          • Home
                                          • Aktuell
                                          • Tags
                                          • Ungelesen 0
                                          • Kategorien
                                          • Unreplied
                                          • Beliebt
                                          • GitHub
                                          • Docu
                                          • Hilfe