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

    • Wir empfehlen: Node.js 22.x

    • Neuer Blog: Fotos und Eindrücke aus Solingen

    • ioBroker goes Matter ... Matter Adapter in Stable

    IoBroker mit Warema WMS Web Control

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

      @henry9843
      Es funktioniert!
      Vielen Dank!!!!!!!!
      Ihr rettet mir mein Wochenende!

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

        Habe das Update nun auch hinter mir und hinterlasse hier nochmal meine aktuelle Version des Skripts.

        //updated for serialport 10.x
        
        const { SerialPort } = require('serialport');
        const { ReadlineParser } = require('@serialport/parser-readline')
        const namespace = '0_userdata.0.Custom.WMS';
        log('namespace: ' + namespace);
        
        //config
        const PATH = "/dev/ttyWMS";
        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 = 10;  //how often to scan for devices (seconds)
        var scanDevicesMax = 3; //stop scanning after discovering all devices
        //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 initially
            timers.scanInit = setTimeout(function () {
                wmsScan();
            }, 5000);
            //scan again every scanInterval seconds
            timers.scan = setInterval(function () {
                wmsScan();
            }, scanInterval * 1000);
        }
        
        //connect to serial port
        
        const port = new SerialPort({
            path: PATH,
            baudRate: 125000,
            parity: 'none',
            dataBits: 8,
            stopBits: 1,
            autoOpen: false,
        });
        
        //create parser with '}' as delemiter
        const parser = port.pipe(new ReadlineParser({ delimiter: '}' }))
        
        // handle serial port errors
        port.on('error', function () {
            log('serial port error!', 'warn');
            closePort().then((msg) => {
                log(msg, 'info');
            }).catch((err) => {
                log(err, 'warn');
            });
        });
        
        //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) => {
                return writeAndWaitFor(encodeWMS('switchChannelRequest', {
                    panId: PANID
                }), 'a', true);
            }).then((line) => {
                init();
            }).catch((err) => {
                log(err, 'warn');
                closePort().then((msg) => {
                    log(msg, 'info');
                }).catch((err) => {
                    log(err, 'warn');
                });
            });
        }).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', 'info');
                clearInterval(timers.scan);
                if (port && port.isOpen) {
                    // close connection
                    port.close(() => {
                        resolve('port closed')
                    });
                } else {
                    reject('no port was opened');
                }
            });
        }
        
        //on script stop close port
        onStop(() => {
            clearInterval(timers.scan);
            //@todo clear all timers;
            closePort().then((msg) => {
                log(msg, 'info');
            }).catch((err) => {
                log(err, 'warn');
            });
        
        }, 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('received: ' + JSON.stringify(obj), 'debug');
            //process object
            setTimeout( () => processWMS(obj), 10);
        }
        
        //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;
                let listener = (line) => {
                    log('listener received message: "' + wmsTrim(line) + '" / expected: "' + expect + '"', 'debug');
                    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);
            });
        }
        
        var portReady = true;
        var sendInterval;
        function enqueue(data) {
            if (typeof data === 'string'){
                writeQueue.push(data);
            } 
            clearInterval(sendInterval);
            sendInterval = setInterval(sendData, 50);
        }
        function sendData() {
            if (writeQueue.length === 0 && portReady) {
                clearInterval(sendInterval);
                return;
            }
            if (portReady) {
                portReady = false;
                var sendData = writeQueue.shift();
                log('sending ' + sendData, 'debug');
                port.write(sendData);
                port.drain((err) => {
                    portReady = true;
                });
            }
        }
        
        /* 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, 00: Handsender
                        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) {
            log('encoding: ' + type + ' with parameters ' + JSON.stringify(parameter), 'debug');
            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 || !parameter.deviceType) return false;
                    return '{R01' + parameter.dst + '7021' + parameter.panId + parameter.deviceType + (parameter.payload ? parameter.payload : '') + '}'; //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, deviceType: '20', payload: '8FFF03000000000000000000000201010000000000000000'}), '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') {
                        let src = '' + obj.payload.src.trim();
                        if (knownDevices[src] === true) {
                            //log('skipping device: ' + src);
                            return;   
                        };
                        knownDevices[src] = true;
                        log('device type 20 found: ' + src);
        
                        scanDevicesMax--;
                        if (scanDevicesMax === 0) {  
                            clearInterval(timers.scan);
                            log ('stop scanning for devices');
                        }
        
                        
                        //log('creating state: ' + namespace + '.Raffstore.' + src + '.position');
                        createState(namespace + '.Raffstore.' + src + '.position', 0, {
                            type: 'number',
                            min: 0,
                            max: 100,
                            unit: '%'
                        });
                        //log('creating state: ' + namespace + '.Raffstore.' + src + '.angle');
                        createState(namespace + '.Raffstore.' + src + '.angle', 0, {
                            type: 'number',
                            min: 0,
                            max: 90,
                            unit: '°'
                        }, function () {
                            var deviceId = 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(() => {
                                    clearInterval(timers[deviceId + 'parameterGetRequestPosition']);
                                    var lastValueAngle = -1;
                                    var lastValuePosition = -1;
                                    var noChange = 0;
                                    writeAndWaitFor(encodeWMS('parameterGetRequestPosition', {dst: src}), 'a');
                                    timers[deviceId + 'parameterGetRequestPosition'] = setInterval(function () {
                                        //get parameter periodically until no change is detected
                                        log(getState(deviceId + '.position').val + ':' + lastValuePosition + ' | ' + getState(deviceId + '.angle').val + ':' + lastValueAngle, 'info')
                                        if (getState(deviceId + '.position').val === lastValuePosition && getState(deviceId + '.angle').val === lastValueAngle) {
                                            noChange++;
                                            if (noChange === 2) {
                                                clearInterval(timers[deviceId + 'parameterGetRequestPosition']);
                                            }
                                        } else {
                                            noChange = 0;
                                        }
                                        lastValuePosition = getState(deviceId + '.position').val;
                                        lastValueAngle = getState(deviceId + '.angle').val;
                                        writeAndWaitFor(encodeWMS('parameterGetRequestPosition', {dst: src}), 'a');
                                    },  5000 + Math.random() * 1000);
                                    //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(() => {
                                    clearInterval(timers[deviceId + 'parameterGetRequestPosition']);
                                    var lastValueAngle = -1;
                                    var lastValuePosition = -1;
                                    var noChange = 0;
                                    writeAndWaitFor(encodeWMS('parameterGetRequestPosition', {dst: src}), 'a');
                                    timers[deviceId + 'parameterGetRequestPosition'] = setInterval(function () {
                                        //get parameter periodically until no change is detected
                                        log(getState(deviceId + '.position').val + ':' + lastValuePosition + ' | ' + getState(deviceId + '.angle').val + ':' + lastValueAngle, 'info');
                                        if (getState(deviceId + '.position').val === lastValuePosition && getState(deviceId + '.angle').val === lastValueAngle) {
                                            noChange++;
                                            if (noChange === 2) {
                                                clearInterval(timers[deviceId + 'parameterGetRequestPosition']);
                                            }
                                        } else {
                                            noChange = 0;
                                        }
                                        lastValuePosition = getState(deviceId + '.position').val;
                                        lastValueAngle = getState(deviceId + '.angle').val;
                                        writeAndWaitFor(encodeWMS('parameterGetRequestPosition', {dst: src}), 'a');
                                    },  3500 + Math.random() * 1000);
                                    //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(namespace + '.Raffstore.' + obj.payload.src + '.position', obj.payload.messagePayload.position, true, 100, true);
                            setStateDelayed(namespace + '.Raffstore.' + obj.payload.src + '.angle', obj.payload.messagePayload.angle, true, 100, true);
                        default:
                            break;
                    }
                    break;
                case 'weatherBroadcast':
                    log('received weatherBroadcast', 'debug');
                    let src = '' + obj.payload.src.trim();
                    createState(namespace + '.Wetter.' + src + '.temp', 0, {
                        type: 'number',
                        unit: '°C',
                        write: false
                    }, function () {
                        setStateDelayed(namespace + '.Wetter.' + src + '.temp', obj.payload.messagePayload.temp, true, 100, true);
                    });
                    createState(namespace + '.Wetter.' + src + '.wind', 0, {
                        type: 'number',
                        min: 0,
                        unit: 'm/s',
                        write: false
                    }, function () {
                        setStateDelayed(namespace + '.Wetter.' + src + '.wind', obj.payload.messagePayload.wind, true, 100, true);
                    });
                    createState(namespace + '.Wetter.' + src + '.lux', 0, {
                        type: 'number',
                        min: 0,
                        unit: 'lux',
                        write: false
                    }, function () {
                        setStateDelayed(namespace + '.Wetter.' + src + '.lux', obj.payload.messagePayload.lumen, true, 100, true);
                    });
                    createState(namespace + '.Wetter.' + src + '.rain', false, {
                        type: 'boolean',
                        write: false
                    }, function () {
                        setStateDelayed(namespace + '.Wetter.' + src + '.rain', obj.payload.messagePayload.rain, true, 100, true);
                    });
                    break;
                case 'beckonRequest':
                    writeAndWaitFor(encodeWMS('ack', {dst: obj.payload.src}), 'a');
                    break;
                case 'controlRequest':
                    writeAndWaitFor(encodeWMS('ack', {dst: obj.payload.src}), 'a');
                    break;      
                default:
                    break;
            }
        }
        
        //scan for devices
        function wmsScan() {  
            log('scanning for devices');
            writeAndWaitFor(encodeWMS('scanRequest', {panId: PANID}), 'a');   
        }
        
        
        
        1 Reply Last reply Reply Quote 0
        • T
          Toby 1 last edited by

          Hallo zusammen,

          Vielen Dank euch allen für's Reverse-Engineering, Coding und Testing!

          Wer von euch hat schonmal über den WMS-Stick die Wetterdaten aus einer Wetterstation ausgelesen? Welche genaue Wetterstation verwendet ihr da?
          Klappt das mit der WMS Wetterstation eco oder plus oder welche sollte ich am Besten anschaffen?

          Vielen Dank und viele Grüße,
          Toby

          1 Reply Last reply Reply Quote 0
          • Marco Santarelli
            Marco Santarelli last edited by Marco Santarelli

            Hello, is the maintaner of warema-wms-venetian-blinds on NPM reading this thread? While I know I can see it and reverse-engineer it from the node_modules folder, Is it possible for this person to put the code on GitHub, so that we can collaborate on it?

            I have Warema blinds and a weather station at home, as well as the WMS stick and a webcontrol pro, and I became fairly proficient with WMS Studio, so I can help test the integrations and provide bugfixes!

            1 Reply Last reply Reply Quote 0
            • Marc Berg
              Marc Berg Most Active last edited by

              @marco-santarelli sagte in IoBroker mit Warema WMS Web Control:

              Hello, is the maintaner of warema-wms-venetian-blinds on NPM reading this thread? While I know I can see it and reverse-engineer it from the node_modules folder, Is it possible for this person to put the code on GitHub, so that we can collaborate on it?

              I have Warema blinds and a weather station at home, as well as the WMS stick and a webcontrol pro, and I became fairly proficient with WMS Studio, so I can help test the integrations and provide bugfixes!

              Hi Marco, did you get any response? I am also interested in further development.

              Marco Santarelli 1 Reply Last reply Reply Quote 0
              • Marco Santarelli
                Marco Santarelli @Marc Berg last edited by

                @marc-berg No response, i reverse-engineered the code from the npm package and modified it myself. You can see how I use it at https://github.com/santam85/addon-warema-wms/tree/main

                Marc Berg 1 Reply Last reply Reply Quote 0
                • Marc Berg
                  Marc Berg Most Active @Marco Santarelli last edited by

                  @marco-santarelli

                  Yes, that's how I did it too. A fork of your repo and some customisations for my devices. I'm happy with that now.

                  https://github.com/Marc-Berg/wms2mqtt

                  P 1 Reply Last reply Reply Quote 0
                  • T
                    tweefo last edited by

                    Had been using Tombox' adapter working with the Webcontrol pro for a while. However it suddenly stopped working some time ago. Does someone still have it running with pro?

                    1 Reply Last reply Reply Quote 0
                    • P
                      PatrickR @Marc Berg last edited by

                      @marc-berg
                      Entschuldige bitte mein Anfängerfrage

                      Dein "wms2mqtt" auf Github, sollte dies auch auf HA laufen?
                      Ich frage, weil ich die Fehlermeldung beim hinzufügen erhalte, dass es kein gültiges Repository wäre,
                      was ggf. an der fehlenden "repository.json" liegt.

                      Danke schon mal
                      Patrick

                      Marc Berg 1 Reply Last reply Reply Quote 0
                      • Marc Berg
                        Marc Berg Most Active @PatrickR last edited by

                        @patrickr sagte in IoBroker mit Warema WMS Web Control:

                        Dein "wms2mqtt" auf Github, sollte dies auch auf HA laufen?

                        Mein Ziel war es, das Image um meine zusätzlichen Gerätetypen zu erweitern und unter einer Docker Umgebung laufen zu lassen. Deshalb habe ich alle HA-Funktionalitäten entfernt, um den Code schlank zu halten.

                        Wenn dir die Geräte reichen, die @Marco-Santarelli drin hat, solltest du sein Image nehmen.

                        P 1 Reply Last reply Reply Quote 0
                        • P
                          PatrickR @Marc Berg last edited by PatrickR

                          @marc-berg
                          Danke für Deine schnelle RM.

                          Ich hab auch 63, 2A, daher bin ich auf Dein Resp gestossen.

                          Hab gerade erst die Chat-Funktion gefunden (what a shame)
                          Ich chatte Dich mal an, vermutlich interessiert meine Frage die wenigsten da HA.

                          Patrick

                          Marc Berg 1 Reply Last reply Reply Quote 0
                          • Marc Berg
                            Marc Berg Most Active @PatrickR last edited by

                            @patrickr sagte in IoBroker mit Warema WMS Web Control:

                            vermutlich interessiert meine Frage die wenigsten da HA.

                            Um ganz ehrlich zu sein: Mich interessiert HA auch nicht. Deshalb kann ich diesbezüglich auch keinen Support leisten.

                            Wenn du dir selbst was zusammenstricken möchtest, dann musst du neben der index.js auch die Module unter addon-warema-wms/warema-bridge/srv/warema-wms-venetian-blinds anpassen, denn diese übernehmen die eigentliche Kommunikation mit dem WMS Netzwerk. Wegen der von mir entfernen HA-Funktionalität kannst du die Dateien aber nicht 1:1 ersetzen.

                            P 1 Reply Last reply Reply Quote 0
                            • P
                              PatrickR @Marc Berg last edited by

                              @marc-berg Vielen Dank

                              P 1 Reply Last reply Reply Quote 0
                              • P
                                PatrickR @PatrickR last edited by

                                @Marc-Berg
                                Hallo Marc,
                                ich mußte bzgl. Wetterstation Pro
                                bei mir im wms-util.js noch einen Wert ändern.

                                Das wäre bei Dir
                                wms2mqtt/warema-bridge/srv/warema-wms-venetian-blinds/wms-util.js
                                Zeile 272
                                params.temp = parseInt(payload.substr(18, 2), 16) / 2 - 35;

                                Ich muß 40 abziehen, um die korrekten Werte zu erhalten.
                                Vergleich mit WMS Stick und WMS studio pro.

                                Gruß
                                Patrick

                                PS: Sieh bitte auch meinen Kommentar zum " Squash deduplication #6"
                                Und vielen Dank für das "Implement comprehensive weather data deduplication"

                                Marc Berg 1 Reply Last reply Reply Quote 0
                                • Marc Berg
                                  Marc Berg Most Active @PatrickR last edited by

                                  @patrickr sagte in IoBroker mit Warema WMS Web Control:

                                  Das wäre bei Dir
                                  wms2mqtt/warema-bridge/srv/warema-wms-venetian-blinds/wms-util.js
                                  Zeile 272
                                  params.temp = parseInt(payload.substr(18, 2), 16) / 2 - 35;

                                  Ich muß 40 abziehen, um die korrekten Werte zu erhalten.

                                  Da hast du Recht, das passt nicht. Habe ich aber auch nur aus der original Library übernommen. Ich verwende die Temperatur der Wetterstation nicht, da bei starker Sonneneinstrahlung gern mal Mondwerte ankommen. Auch in der Warema App wird die Temperatur nicht direkt angezeigt, dem Hersteller ist wohl auch klar, dass man darauf nichts geben kann. Passe ich aber trotzdem bei Gelegenheit mal an.

                                  Und vielen Dank für das "Implement comprehensive weather data deduplication"

                                  Ich dachte erst, es sei ein Fehler im Code, aber die Wetterstation sendet wirklich ständig doppelt und dreifach. Wahrscheinlich kann ich noch viel mehr Duplikate rausfiltern, auch das schaue ich mir nochmal an.

                                  P 1 Reply Last reply Reply Quote 0
                                  • P
                                    PatrickR @Marc Berg last edited by

                                    @marc-berg sagte in IoBroker mit Warema WMS Web Control:
                                    Wo noch ein allgemeines Problem liegt, ist bei den Jalousien, der maximale Winkel welcher wie in meinem Fall auf 80° steht.

                                    Und bei der Umrechnung in % muss ich genau diesen maximal Wert als 100% hernehmen, ansonsten verwende ich einen falschen Wert.

                                    So ging es mir anfänglich.

                                    Da dieser Maximalwert für jeden Actuator unterschiedlich sein kann,
                                    gibt es für unterschiedliche Werte auch unterschiedliche Winkelwerte die 100% bedeuten.

                                    Man müßte eigentlich für jeden Actuator den maxWert als Berechnungsbasis ablegen und diesen in der Konfiguration übergeben (alles machbar aber mit Aufwand).

                                    Was anderes noch.
                                    Es gibt bestimmt eine Botschaft um im WMS-Mesh-System die Geräte auf "Abwesend" zu setzen.
                                    Ist Dir da etwas bekannt?

                                    Danke.
                                    Patrick

                                    Marc Berg 1 Reply Last reply Reply Quote 0
                                    • Marc Berg
                                      Marc Berg Most Active @PatrickR last edited by

                                      @patrickr sagte in IoBroker mit Warema WMS Web Control:

                                      Wo noch ein allgemeines Problem liegt, ist bei den Jalousien, der maximale Winkel welcher wie in meinem Fall auf 80° steht.
                                      Und bei der Umrechnung in % muss ich genau diesen maximal Wert als 100% hernehmen, ansonsten verwende ich einen falschen Wert.

                                      Da ich keine Jalousien von Warema besitze, kann ich das nicht nachstellen.

                                      Es gibt bestimmt eine Botschaft um im WMS-Mesh-System die Geräte auf "Abwesend" zu setzen.
                                      Ist Dir da etwas bekannt?

                                      Nein, keine Ahnung.

                                      P 1 Reply Last reply Reply Quote 0
                                      • P
                                        PatrickR @Marc Berg last edited by

                                        @marc-berg
                                        ich hab noch für mich eine Anpassung bzgl. Polling gemacht.
                                        Wenn ein neues Weather broadcast empfangen wird, wird der
                                        der Intervall-Zähler für "Weather polling function" retriggert.

                                        ///////////// index.js : Info

                                        //Neu: Info
                                        let weatherInterval;

                                        //Neu: Info
                                        function retriggerWeatherPolling() {
                                        if (weatherInterval) {
                                        clearInterval(weatherInterval);
                                        }
                                        weatherInterval = setInterval(pollWeatherData, pollingInterval);
                                        log.fkt_log_info('046:Restarted weather data polling every ' + pollingInterval + ' ms');
                                        }

                                        //Änderung : Info
                                        // Start weather polling with configurable interval
                                        weatherInterval = setInterval(pollWeatherData, pollingInterval);
                                        log.fkt_log_info('045:Started weather data polling every ' + pollingInterval + ' ms');

                                        //Neu: Info
                                        //function callback(err, msg)
                                        /////case 'wms-vb-rcv-weather-broadcast':
                                        ///////if (!cachedWeather || cachedWeather.hash !== weatherHash || (currentTime - cachedWeather.timestamp) > minTimeDiff) {
                                        /////////if (typeof client !== 'undefined' && client.connected) {
                                        retriggerWeatherPolling();

                                        Gruß
                                        Patrick

                                        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

                                        817
                                        Online

                                        32.0k
                                        Users

                                        80.4k
                                        Topics

                                        1.3m
                                        Posts

                                        26
                                        126
                                        32183
                                        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