Navigation

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

    NEWS

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

    • ioBroker goes Matter ... Matter Adapter in Stable

    • Monatsrückblick - April 2025

    IoBroker mit Warema WMS Web Control

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

      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 Reply Last reply Reply Quote 0
      • W
        willjoha last edited by

        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 Reply Last reply Reply Quote 0
        • P
          Pman last edited by

          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 Reply Last reply Reply Quote 0
          • P
            Pman last edited by

            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 Reply Last reply Reply Quote 0
            • W
              willjoha last edited by

              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 Reply Last reply Reply Quote 0
              • P
                Pman last edited by

                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 Reply Last reply Reply Quote 0
                • P
                  Pman last edited by

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

                  1 Reply Last reply Reply Quote 0
                  • L
                    LaBamba last edited by

                    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 Reply Last reply Reply Quote 0
                    • R
                      radiorichter last edited by

                      @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 Reply Last reply Reply Quote 0
                      • P
                        Pman last edited by

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

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

                          kein Thema, aber auf jeden Fall vielen Dank für das Skript. Bei mir wird es erst im Sommer soweit sein, wird dann schon klappen 😉

                          1 Reply Last reply Reply Quote 0
                          • L
                            LaBamba last edited by

                            Pman trotzdem super, dass du es so weit schon geschrieben hast. Vielleicht findet sich ja ein anderer der die Fähigkeiten hat dieses Skript in einen Adapter umzusetzen. Würde mich mega freuen!

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

                              @LaBamba:

                              Pman trotzdem super, dass du es so weit schon geschrieben hast. Vielleicht findet sich ja ein anderer der die Fähigkeiten hat dieses Skript in einen Adapter umzusetzen. Würde mich mega freuen! `
                              Adapter wäre natürlich super und bequem, aber unterm Strich hast du genau das gleiche mit dem Skript, was ein Adapter machen würde. Also keine falsche Scheu! Wenn das Skript jemand nutzen möchte helfe ich gerne bei der Ersteinrichtung, falls es Probleme gibt.

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

                                Pman, wärst du so nett und würdest uns einfach kurz zusammenfassen was man genau machen muss? Eine ganz kleine step by step Anleitung. Das ich beide scripte brauche, hab ich bereits verstanden, aber diese einfach in den iobroker reinpacken wird ja nicht reichen oder?

                                Eilt bei mir eh nicht wirklich, aber dafür wär ich / wir dir mega dankbar 😄

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

                                  Du benötigst den Javascript-Adapter und einen WMS-Stick.

                                  Kurze Anleitung:

                                  1. Falls nicht vorhanden den Javascript-Adapter installieren

                                  2. Im Javascript Adapter bei "zusätzliche NPM-Module" "serialport" eintragen, dann sollte der Adapter neu starten und das serialport-Packet installieren, was ggf. etwas dauert.

                                  3. Im Admin im Skripte-Tab Ein neues Skript (Javascript!) erstellen und das unten angefügte Skript einfügen, dabei die "//" vor "listPorts();" weg machen, damit beim ersten Start des Skripts die Seriellen Ports im LOG aufgelistet werden. Das Skript nun starten. Im Normalfall sollte der WMS-Stick auf einem Raspi wie bei mir unter /dev/ttyUSB0 zu finden sein, ansonsten muss man dies anpassen im Skript. Nachdem der Pfad zum WMS-Stick bekannt ist und eingetragen wurde "listPorts();" wieder auskommentieren. Das Skript neustarten.

                                  4. CHANNEL, PANID und KEY müssen nun bestimmt werden, dazu ist eine WMS-Zentrale oder WMS-Fernbedienung nötig. Einfach wie in der jeweiligen Anleitung beschrieben ein neues Gerät in das Netzwerk aufnehmen, dabei sollte der WMS-Stick gefunden werden. Sobald man diesen in das Netzwerk aufnimmt werden im LOG des Skriptes die drei Werte angezeigt.

                                  5. CHANNEL, PANID und KEY in das Skript eintrage und Skript neustarten.

                                  6. Unter javascript.0.WMS sollten nun für alle gefunden Geräte (Motoren, Wetterstationen usw.) Datenpunkte angelegt werden, die Nutzung sollte halbwegs selbsterlärend sein (level, 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 Reply Last reply Reply Quote 0
                                  • E
                                    Eberhart last edited by

                                    @Pman:

                                    … `

                                    Wow.Hammer, was du hier abgeliefert hast. Vielen lieben Dank dafür. Ich hab mich schon eine Weile lang geärgert, dass ich auf das proprietäre WMS gesetzt habe. Nun habe ich aber keinen Zweifel mehr, dass ich meine Raffstoren in die Heimautomatisierung integrieren kann.

                                    Eine Frage habe ich aber noch zum Key: ich habe mein WMS Netz mittels WMS Stick und WMS Studio erstellt. Dadurch habe ich ja eine Projektdatei (.bin), in der alle Komponenten gespeichert sind.

                                    Müsste es nicht so sein, dass der Key und PANID usw. in dieser Datei gespeichert sind? Vielleicht könnte man die aus der Datei extrahieren, so dass die Notwendigkeit entfällt, ein neues Gerät mit der Fernbedienung hinzuzufügen. Ich habe nämlich keine weiteren Geräte mehr..

                                    Was meinst du dazu? Und nochmals, vielen Dank!

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

                                      @Eberhart:

                                      Eine Frage habe ich aber noch zum Key: ich habe mein WMS Netz mittels WMS Stick und WMS Studio erstellt. Dadurch habe ich ja eine Projektdatei (.bin), in der alle Komponenten gespeichert sind.

                                      Müsste es nicht so sein, dass der Key und PANID usw. in dieser Datei gespeichert sind? Vielleicht könnte man die aus der Datei extrahieren, so dass die Notwendigkeit entfällt, ein neues Gerät mit der Fernbedienung hinzuzufügen. Ich habe nämlich keine weiteren Geräte mehr.. `

                                      Das kann gut ein, mit den Projektdateien habe ich mich bisher nicht beschäftigt. Ich denke das mit dem Hinzufügen ist noch nicht ganz klar geworden, du fügst tatsächlich den Stick zum Netzwerk hinzu, kein anderes Gerät. Der Adapter sorgt dafür, dass der Stick so antwortet, als sei er ein Gerät, welches hinzugefügt werden soll und erhält dadurch von der Fernbedienung/Zentrale die nötigen Infos.

                                      1 Reply Last reply Reply Quote 0
                                      • E
                                        Eberhart last edited by

                                        @Pman:

                                        @Eberhart:

                                        Eine Frage habe ich aber noch zum Key: ich habe mein WMS Netz mittels WMS Stick und WMS Studio erstellt. Dadurch habe ich ja eine Projektdatei (.bin), in der alle Komponenten gespeichert sind.

                                        Müsste es nicht so sein, dass der Key und PANID usw. in dieser Datei gespeichert sind? Vielleicht könnte man die aus der Datei extrahieren, so dass die Notwendigkeit entfällt, ein neues Gerät mit der Fernbedienung hinzuzufügen. Ich habe nämlich keine weiteren Geräte mehr.. `

                                        Das kann gut ein, mit den Projektdateien habe ich mich bisher nicht beschäftigt. Ich denke das mit dem Hinzufügen ist noch nicht ganz klar geworden, du fügst tatsächlich den Stick zum Netzwerk hinzu, kein anderes Gerät. Der Adapter sorgt dafür, dass der Stick so antwortet, als sei er ein Gerät, welches hinzugefügt werden soll und erhält dadurch von der Fernbedienung/Zentrale die nötigen Infos. `

                                        Und das geht mir jeder Fernbedienung? Ich habe aktuell eine Fernbedienung im Netz, es ist die mit den vielen Tasten, 1002767.

                                        Heißt das, wenn ich das Prozedere so durchführe, wie du es beschrieben hast, bleibt mein bestehendes WMS Netz erhalten, nur dass eben iobroker mittels WMS Stick als zusätzlicher Teilnehmer des Netzes agiert?

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

                                          Genau so ist es, in der Anleitung zur Fernbedienung steht, wie man Geräte hinzufügen und entfernen kann.

                                          1 Reply Last reply Reply Quote 0
                                          • E
                                            Eberhart last edited by

                                            Besten Dank. Ich werde mal alles einrichten und schauen ob es funktioniert.

                                            1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post

                                            Support us

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

                                            682
                                            Online

                                            31.6k
                                            Users

                                            79.5k
                                            Topics

                                            1.3m
                                            Posts

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