Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. Hardware
    4. MQTT Bluetooth BLE Anwesenheitserkennung mit ESP32

    NEWS

    • ioBroker@Smart Living Forum Solingen, 14.06. - Agenda added

    • ioBroker goes Matter ... Matter Adapter in Stable

    • Monatsrückblick - April 2025

    MQTT Bluetooth BLE Anwesenheitserkennung mit ESP32

    This topic has been deleted. Only users with topic management privileges can see it.
    • G
      GiuseppeS @Utze86 last edited by

      @utze86
      Android Smartphones und auch meine Pixel Watch können mit Hilfe von Apps iBeacon simulieren und somit BLE advertisements senden. Aber die MAC ist leider nicht konstant, das lässt das Betriebssystem nicht zu. Ähnlich ist es ja auch bei Apple Geräten. Was aber zumindest bei den Android Apps konstant bleibt, das ist die UUID, die mitgesendet wird. Espresense bildet seine Gerätenamen auch entweder mit MAC oder den UUID. Mi Band sendet immer mit selber MAC, somit brauchst du das das mit der UUID nicht.

      1 Reply Last reply Reply Quote 0
      • G
        GiuseppeS last edited by GiuseppeS

        Aus dem ganzen BLE code vom Beispielskript ist eigentlich nur das notwendig:

        function scanCB(ev, res) {
            if (ev === BLE.Scanner.SCAN_RESULT) {
                
                let StaticMAC = { "addr": res.addr.slice(0,-2), "rssi": res.rssi };
                
                //print( JSON.stringify(StaticMAC));
                Shelly.emitEvent( "ShellyScanresult", StaticMAC);
            }
        }
        
        BLE.Scanner.Start({ duration_ms: -1}, scanCB);
        

        Über die Websocket Verbindung wird dann MAC und RSSI ausgegeben. Ich wollte eben den Outbound server von Shelly in iobroker einbinden. Dabei ist mir aber aufgefallen, dass das letzte ALexa Update einige meiner Skripte zerschossen hat. Bedeutet, die Websocket Seite von iobroker aus steht noch nicht.

        Habe übrigens die Scan-Aktivitäten vom Shelly mit meinem Mi Band 6 getestet (habe ich ja noch daheim). Das Band wurde kontinuierlich alle 9 Sekunden empfangen. ESPresense empfängt alle 5 Sekunden. Evtl müsste man an den Scaneinstellungen vom Shelly optimieren. Aktuell steht es auf Infinite Scan, hätte eigentlich das Optimum sein sollen...

        1 Reply Last reply Reply Quote 0
        • G
          GiuseppeS last edited by

          Habe noch etwas weiter getestet:

          Das war nun als Skript zuletzt im Shelly im Einsatz gewesen:

          function scanCB(ev, res) {
              if (ev === BLE.Scanner.SCAN_RESULT) {
                  let mac = res.addr.slice(0,-2);
                  
                  //if ( mac === "e8:61:51:5f:f0:2e"){
                    let StaticMAC = { "addr": res.addr.slice(0,-2), "rssi": res.rssi };
                    //print( JSON.stringify(StaticMAC));
                    Shelly.emitEvent( "ShellyScanresult", StaticMAC);
                  //}
              }
          }
          
          BLE.Scanner.Start({ duration_ms: -1}, scanCB);
          

          Hatte mit der if-Bedingung einen Filter auf meine MiBand MAC verwendet.

          Im Shelly muss bei "Settings/Connectivity/Outbound Websocket" die IP von iobroker mit Port 8085 eingegeben werden. Bei mir sah das so aus:
          394012e7-3e79-478e-921f-c5b1abd7a42c-image.png

          Mein iobroker Skript:

          const {WebSocketServer, WebSocket} = require('ws');
          
          const port = 8085;
          const DEBUG = true;
          
          /**
           * Simple object check.
           * @param item
           * @returns {boolean}
           */
          function isObject(item) {
              return (item && typeof item === 'object' && !Array.isArray(item));
          }
          
          /**
           * Deep merge two objects.
           * @param target
           * @param ...sources
           */
          function mergeDeep(target, ...sources) {
              if (!sources.length) return target;
              const source = sources.shift();
          
              if (isObject(target) && isObject(source)) {
                  for (const key in source) {
                      if (isObject(source[key])) {
                          if (!target[key]) Object.assign(target, { [key]: {} });
                          mergeDeep(target[key], source[key]);
                      } else {
                          Object.assign(target, { [key]: source[key] });
                      }
                  }
              }
          
              return mergeDeep(target, ...sources);
          }
          
          /**
           * Shelly Outbound WebSocket
           */
          class ShellyOWS {
              handlers = {};
              _idx = 0;
              httpServer = null;
              _clients = {};
              _statuses = {};
              _config = {};
              _requests = {};
              ws = null;
          
              /**
               * Init ShellyOWS with an existing httpServer
               *
               * @param {http.Server} httpServer
               */
              constructor(httpServer) {
                  this.httpServer = httpServer;
          
                  this.init();
              }
          
              /**
               * Internal method that is called in constructor to initialize
               *
               * @private
               */
              init() {
                  this.ws = new WebSocketServer({server: this.httpServer});
                  this.ws.on('connection', async (webSocket, request, client) => {
                      if (DEBUG) {
                          console.warn('New connection: ', request.socket.remoteAddress);
                      }
          
                      webSocket.on('message', async (message) => {
                          message = JSON.parse(message.toString());
          
                          this._clients[message.src] = webSocket;
                          webSocket.clientId = message.src;
          
                          let [model, deviceId] = message.src.split("-");
          
                          if (message.method) {
                              let method = message.method;
                              let params = message.params;
                              // console.log('New message', message, model, deviceId, method, params);
          
                              if (method === "NotifyFullStatus") {
                                  this._statuses[message.src] = params;
                                  let allConfig = await this.call(message.src, "Shelly.getconfig");
                                  // console.error("allConfig", allConfig);
                                  this._config[message.src] = allConfig;
                              }
                              else if (method === "NotifyStatus") {
                                  this._statuses[message.src] = mergeDeep(this._statuses[message.src] || {}, params);
                              }
                              else if (method === "NotifyEvent") {
                                  for (let event of params.events) {
                                      if (event.event === "config_changed") {
                                          let config = await this.call(message.src, event.component + ".getconfig");
                                          // console.error("updated config:", config);
                                          this._config[message.src][event.component] = config;
                                      }
                                  }
                              }
          
          
                              // proceed to call handlers
                              if (this.handlers[method]) {
                                  this._callHandler(method, message.src, params, webSocket);
                              }
                          }
                          else if (message.result) {
                              if (message.id && this._requests[message.id]) {
                                  this._requests[message.id](message.result);
                              }
                              // TODO: log error/warning?
                          }
                      });
          
                      await this.call(webSocket, "shelly.getdeviceinfo");
          
                      // console.error("new connection", request.socket.remoteAddress);
                  });
                  this.ws.on('close', (webSocket) => {
                      this._callHandler("OWS::Disconnected", webSocket.clientId, undefined, webSocket);
                      delete this._clients[webSocket.clientId];
                  })
              }
          
              /**
               * Internal.
               *
               * @param {string} method
               * @param {string} id
               * @param {Object} params
               * @param {WebSocket} webSocket
               * @private
               */
              _callHandler(method, id, params, webSocket) {
                  if (this.handlers[method]) {
                      let [model, deviceId] = id.split("-");
          
                      for (let k of Object.keys(this.handlers[method])) {
                          let cb = this.handlers[method][k];
          
                          try {
                              cb.call(this, id, params, webSocket, model, deviceId);
                          } catch (ex) {
                              console.error("Handler", method, 'thrown error:', ex);
                          }
                      }
                  }
              }
          
              /**
               * Add new handler
               *
               * @param {string} method
               * @param {Function} cb
               * @returns {number} ID of the handler, that can be used later with `removeHandler`
               */
              addHandler(method, cb) {
                  let id = this._idx++;
                  if (!this.handlers[method]) {
                      this.handlers[method] = {};
                  }
                  this.handlers[method][id] = cb;
                  return id;
              }
          
              /**
               * Remove handler
               *
               * @param {string} method
               * @param {number} id
               */
              removeHandler(method, id) {
                  delete this.handlers[method][id];
              }
          
              /**
               * Call a RPC on a target device id OR webSocket directly
               *
               * @param {string|WebSocket} deviceIdOrWebSocket
               * @param {string} method
               * @param {Object} params
               * @returns {Promise<never>|Promise<unknown>}
               */
              call(deviceIdOrWebSocket, method, params) {
                  let webSocket = deviceIdOrWebSocket instanceof WebSocket ?
                      deviceIdOrWebSocket : this._clients[deviceIdOrWebSocket];
          
                  if (!webSocket) {
                      // console.error(this._clients);
                      return Promise.reject(404);
                  }
          
                  return new Promise((res, rej) => {
                      let id = this._idx++;
                      this._requests[id] = (response) => {
                          res(response);
                      };
                      // todo: timeout
          
                      let req = {"jsonrpc":"2.0", "id": id, "src":"wsserver", "method": method};
                      if (params) {
                          req['params'] = params;
                      }
                      // console.debug("Calling:", deviceId, req);
                      webSocket.send(JSON.stringify(req));
                  });
              }
          
              /**
               * Return current (in-memory cached) device status
               *
               * @param {string} clientId
               * @returns {*|{}}
               */
              getState(clientId) {
                 return this._statuses[clientId] || {};
              }
          
              /**
               * Return current (in-memory cached) device config
               *
               * @param {string} clientId
               * @returns {*|{}}
               */
              getConfig(clientId) {
                  return this._config[clientId] || {};
              }
          
              /**
               * Update config (also updates local cache)
               *
               * @param {string} clientId
               * @param {string} component
               * @param {Object} config
               * @returns {Promise<*>}
               */
              async setConfig(clientId, component, config) {
                  // Since response is returned before the notification, we need to sync our local config first, so that immediate
                  // access to config would return the updated data.
                  //
                  // If you don't want that to happen, feel free to .call Component.SetConfig directly.
          
                  component = component.toLowerCase();
          
                  await this.call(clientId, component + ".setconfig", {'config': config});
          
                  this._config[clientId][component] = mergeDeep(this._config[clientId][component] || {}, config);
                  return this._config[clientId][component];
              }
          
              /**
               * Return ids of all clients currently connected.
               *
               * @returns {string[]}
               */
              getClients() {
                  return Object.keys(this._clients);
              }
          }
          
          
          /**
           * ########################################################################################################################
           * ########################################################################################################################
           * ########################################################################################################################
           *  Merge from Server and Script  from page: https://github.com/ALLTERCO/shelly-outbound-websockets
           * ########################################################################################################################
           * ########################################################################################################################
           * ########################################################################################################################
           */
          
          /**
           * Example on how to use events from 1 device and then toggle other devices.
           */
          
          
          const http = require('http')
          
          console.log('WS server starting at port ' + port);
          
          const httpServer = http.createServer()
          
          let shellyOws = new ShellyOWS(httpServer);
          
          
          let idHandler = shellyOws.addHandler("NotifyEvent", async (clientId, params) => {
              console.log( params)
          });
          
          
          httpServer.listen( port);
          
          
          
          
          function closeWS() {
          
              //cl( shellyOws.getClients() );
          
              console.log("Close http server connection.");
              shellyOws.removeHandler( "NotifyEvent", idHandler);
              
              httpServer.close();
          }
          onStop(closeWS, 1000);
          
          

          Ich muss noch herausfinden, wie ich die Verbindung in iobroker zu 100% trenne. Kam jetzt noch nicht dazu. Wenn du das Skript stoppst musst du aktuell die Instanz neu starten, damit der Shelly merkt, dass da keine Gegenseite zuhört. Daher würde ich aktuell eine zusätzliche Instanz zum Testen empfehlen.

          U 1 Reply Last reply Reply Quote 0
          • U
            Utze86 @GiuseppeS last edited by

            @giuseppes ja cool, danke! Werde ich testen sobald es geht. Leider bin ich diese Woche wieder unterwegs, daher muss das leider wieder bis zum Wochende warten 😞

            G 1 Reply Last reply Reply Quote 0
            • G
              GiuseppeS @Utze86 last edited by

              @utze86
              Habe unter der Woche auch immer weniger Zeit. Aber heute wollte ich zumindest das saubere Beenden des Skripts schaffen. Das klappt jetzt. Werde, sobald möglich, dass automatische Erstellen der States hinzufügen. Dann ist es für den ersten Beta-Test ausreichend. Ich bin weiterhin nicht überzeugt, ob die original Firmware "so gut" scannt, wie es Tasmota macht.

              U 1 Reply Last reply Reply Quote 0
              • U
                Utze86 @GiuseppeS last edited by

                @giuseppes So ich hatte am Wochenende mal wieder etwas Zeit zum testen. Was Tasmota angeht habe ich mich durch mehrere Intervalle durchprobiert.

                Erkenntnis: Es lassen sich auch Intervalle mit halben Sekunden abfragen. Jede Sekunde abfragen liefert bei mir bisher das beste Ergebnis. Im Durchschnitt erhalte ich alle 2,5 Sekunden ein Signal von meinem Mi Band 4, oftmals auch jede Sekunde. Zumindest gibt dies die Konsole des Shelly wieder.

                Anschließend habe ich die Shelly Beta Firmware getestet um zu gucken mit welcher Firmware ich das bessere Ergebnis erziele. Die BLE Auswertung am Shelly funktioniert schonmal super. Auch mit deinem Skript werden die Werte im iobroker ausgelesen. Allerdings ist mir nicht klar, ob und in welchen Datenpunkt die RSSI Werte im iobroker geschrieben werden. Hast du hier eine Idee? Mit den Werten würde ich dann die weitere Verarbeitung in Blockly durchführen wollen. Weiter hat mich etwas stutzig gemacht, dass die MAC Adressen die ausgelesen werden nur 10 Stellig sind, zumindest laut Log. Sollten die Adressen nicht 12 Stellig sein? Mein Mi Band konnte ich so leider nicht auf anhieb finden, allerdings war der Akku des Armbands fast leer, eventuell hat es daher nicht gesendet. Ich müsste das in den nächsten Tagen nochmal prüfen.

                Wenn das ganze funktioniert werde ich ziemlich gut abschätzen können welche Firmware für mich das bessere Ergebnis liefert. Ich hoffe ebenfalls, dass ich auf die Shelly Firmware zurückgreifen kann. Das würde einiges einfacher machen.

                Wie kommst du mit dem Skript voran? Gibt es bereits Neuigkeiten?

                VG Utze

                G 2 Replies Last reply Reply Quote 0
                • G
                  GiuseppeS @Utze86 last edited by

                  @utze86
                  Das Shelly Skript ist nach aktuellem Stand nicht mehr aktuell. Mit der Shelly beta2 hat sich die Struktur geändert, u.a. wurde die MAC angepasst, deshalb fehlen nun zwei Stellen.

                  Tasmota hatte mit meinen letzten Tests definitiv bessere Scan Ergebnisse. Deine Werte von 2-3 Sekunden sind schon richtig top. Ich musste aber heute meinen verbauten Tasmota Shelly ausbauen. Der Schaltzustand von meinem detached Schalter wurde sehr spät erkannt / übertragen. Daher tendiere ich nun noch mehr zur Shelly Firmware. Hier sollte aber der finale Stand abgewartet werden, sonst skripted man mehrfach.
                  In meinem ioBroker Skript für Shelly (websocket server) ist noch kein Schreiben in States integriert. Müsste ich ergänzen. Allerdings hatte ich zuletzt meine paar freien Stunden in eine Wegmessung meines elektrisch verstellbaren Schreibtisches investiert. Habe ich heute abgeschlossen und werde mich wieder um dieses Thema kümmern 😉

                  1 Reply Last reply Reply Quote 0
                  • G
                    GiuseppeS @Utze86 last edited by GiuseppeS

                    @utze86

                    Habe nun das Skript überarbeitet, sodass die RSSI Werte in States geschrieben werden. Anbei die aktuellen Stände:

                    Skript Shelly:

                    function scanCB(ev, res) {
                        if (ev === BLE.Scanner.SCAN_RESULT) {
                            let mac = res.addr;
                            let rssi = res.rssi;
                            let macType = res.addr_type;
                            
                            //print( JSON.stringify( res));
                            
                            if ( macType < 3){
                              let JsonMsg = { "addr": mac, "rssi": rssi };
                              //print(JSON.stringify( JsonMsg) );
                              Shelly.emitEvent( "ShellyScanresult", JsonMsg);
                            }
                        }
                    }
                    
                    BLE.Scanner.Start({ duration_ms: -1}, scanCB);
                    

                    Skript iobroker:

                    const {WebSocketServer, WebSocket} = require('ws');
                    
                    const port = 8085;
                    
                    const DEBUG = false;
                    
                    /**
                     * Simple object check.
                     * @param item
                     * @returns {boolean}
                     */
                    function isObject(item) {
                        return (item && typeof item === 'object' && !Array.isArray(item));
                    }
                    
                    /**
                     * Deep merge two objects.
                     * @param target
                     * @param ...sources
                     */
                    function mergeDeep(target, ...sources) {
                        if (!sources.length) return target;
                        const source = sources.shift();
                    
                        if (isObject(target) && isObject(source)) {
                            for (const key in source) {
                                if (isObject(source[key])) {
                                    if (!target[key]) Object.assign(target, { [key]: {} });
                                    mergeDeep(target[key], source[key]);
                                } else {
                                    Object.assign(target, { [key]: source[key] });
                                }
                            }
                        }
                    
                        return mergeDeep(target, ...sources);
                    }
                    
                    /**
                     * Shelly Outbound WebSocket
                     */
                    class ShellyOWS {
                        handlers = {};
                        _idx = 0;
                        httpServer = null;
                        _clients = {};
                        _statuses = {};
                        _config = {};
                        _requests = {};
                        ws = null;
                        sockets = [];
                    
                        /**
                         * Init ShellyOWS with an existing httpServer
                         *
                         * @param {http.Server} httpServer
                         */
                        constructor(httpServer) {
                            this.httpServer = httpServer;
                    
                            this.init();
                        }
                    
                        /**
                         * Internal method that is called in constructor to initialize
                         *
                         * @private
                         */
                        init() {
                            this.ws = new WebSocketServer({server: this.httpServer});
                            this.ws.on('connection', async (webSocket, request, client) => {
                                if (DEBUG) console.log('New device connected!');
                                
                                this.sockets.push( webSocket); // Added to force close ioBroker
                                webSocket.on('message', async (message) => {
                                    message = JSON.parse(message.toString());
                    
                                    this._clients[message.src] = webSocket;
                                    webSocket.clientId = message.src;
                    
                                    let [model, deviceId] = message.src.split("-");
                    
                                    if (message.method) {
                                        let method = message.method;
                                        let params = message.params;
                                        // console.log('New message', message, model, deviceId, method, params);
                    
                                        if (method === "NotifyFullStatus") {
                                            this._statuses[message.src] = params;
                                            let allConfig = await this.call(message.src, "Shelly.getconfig");
                                            // console.error("allConfig", allConfig);
                                            this._config[message.src] = allConfig;
                                        }
                                        else if (method === "NotifyStatus") {
                                            this._statuses[message.src] = mergeDeep(this._statuses[message.src] || {}, params);
                                        }
                                        else if (method === "NotifyEvent") {
                                            for (let event of params.events) {
                                                if (event.event === "config_changed") {
                                                    let config = await this.call(message.src, event.component + ".getconfig");
                                                    // console.error("updated config:", config);
                                                    this._config[message.src][event.component] = config;
                                                }
                                            }
                                        }
                    
                    
                                        // proceed to call handlers
                                        if (this.handlers[method]) {
                                            this._callHandler(method, message.src, params, webSocket);
                                        }
                                    }
                                    else if (message.result) {
                                        if (message.id && this._requests[message.id]) {
                                            this._requests[message.id](message.result);
                                        }
                                        // TODO: log error/warning?
                                    }
                                });
                    
                                await this.call(webSocket, "shelly.getdeviceinfo");
                    
                                // console.error("new connection", request.socket.remoteAddress);
                            });
                            this.ws.on('close', (webSocket) => {
                                this._callHandler("OWS::Disconnected", webSocket.clientId, undefined, webSocket);
                                cld("Disconnected");
                                delete this._clients[webSocket.clientId];
                            })
                        }
                    
                        /**
                         * Internal.
                         *
                         * @param {string} method
                         * @param {string} id
                         * @param {Object} params
                         * @param {WebSocket} webSocket
                         * @private
                         */
                        _callHandler(method, id, params, webSocket) {
                            if (this.handlers[method]) {
                                let [model, deviceId] = id.split("-");
                    
                                for (let k of Object.keys(this.handlers[method])) {
                                    let cb = this.handlers[method][k];
                    
                                    try {
                                        cb.call(this, id, params, webSocket, model, deviceId);
                                    } catch (ex) {
                                        console.error("Handler", method, 'thrown error:', ex);
                                    }
                                }
                            }
                        }
                    
                        /**
                         * Add new handler
                         *
                         * @param {string} method
                         * @param {Function} cb
                         * @returns {number} ID of the handler, that can be used later with `removeHandler`
                         */
                        addHandler(method, cb) {
                            let id = this._idx++;
                            if (!this.handlers[method]) {
                                this.handlers[method] = {};
                            }
                            this.handlers[method][id] = cb;
                            return id;
                        }
                    
                        /**
                         * Remove handler
                         *
                         * @param {string} method
                         * @param {number} id
                         */
                        removeHandler(method, id) {
                            delete this.handlers[method][id];
                        }
                    
                        /**
                         * Call a RPC on a target device id OR webSocket directly
                         *
                         * @param {string|WebSocket} deviceIdOrWebSocket
                         * @param {string} method
                         * @param {Object} params
                         * @returns {Promise<never>|Promise<unknown>}
                         */
                        call(deviceIdOrWebSocket, method, params) {
                            let webSocket = deviceIdOrWebSocket instanceof WebSocket ?
                                deviceIdOrWebSocket : this._clients[deviceIdOrWebSocket];
                    
                            if (!webSocket) {
                                // console.error(this._clients);
                                return Promise.reject(404);
                            }
                    
                            return new Promise((res, rej) => {
                                let id = this._idx++;
                                this._requests[id] = (response) => {
                                    res(response);
                                };
                                // todo: timeout
                    
                                let req = {"jsonrpc":"2.0", "id": id, "src":"wsserver", "method": method};
                                if (params) {
                                    req['params'] = params;
                                }
                                // console.debug("Calling:", deviceId, req);
                                webSocket.send(JSON.stringify(req));
                            });
                        }
                    
                        /**
                         * Return current (in-memory cached) device status
                         *
                         * @param {string} clientId
                         * @returns {*|{}}
                         */
                        getState(clientId) {
                           return this._statuses[clientId] || {};
                        }
                    
                        /**
                         * Return current (in-memory cached) device config
                         *
                         * @param {string} clientId
                         * @returns {*|{}}
                         */
                        getConfig(clientId) {
                            return this._config[clientId] || {};
                        }
                    
                        /**
                         * Update config (also updates local cache)
                         *
                         * @param {string} clientId
                         * @param {string} component
                         * @param {Object} config
                         * @returns {Promise<*>}
                         */
                        async setConfig(clientId, component, config) {
                            // Since response is returned before the notification, we need to sync our local config first, so that immediate
                            // access to config would return the updated data.
                            //
                            // If you don't want that to happen, feel free to .call Component.SetConfig directly.
                    
                            component = component.toLowerCase();
                    
                            await this.call(clientId, component + ".setconfig", {'config': config});
                    
                            this._config[clientId][component] = mergeDeep(this._config[clientId][component] || {}, config);
                            return this._config[clientId][component];
                        }
                    
                        /**
                         * Return ids of all clients currently connected.
                         *
                         * @returns {string[]}
                         */
                        getClients() {
                            return Object.keys(this._clients);
                        }
                    }
                    
                    
                    /**
                     * #########################################################################################################################
                     * ############ Merge from Server and Script  from page: https://github.com/ALLTERCO/shelly-outbound-websockets ############
                     * #########################################################################################################################
                     */
                    
                    
                    const http = require('http')
                    
                    console.log('WS server starting at port ' + port);
                    
                    const httpServer = http.createServer()
                    
                    let shellyOws = new ShellyOWS(httpServer);
                    
                    
                    let idHandler = shellyOws.addHandler("NotifyEvent", async (clientId, params) => {
                        if (DEBUG) console.log( clientId + " | " + JSON.stringify( params) );
                    
                        if ( params.events[0].event !== "ShellyScanresult") return 
                    
                        let val = params.events[0].data.rssi;
                    
                        let StateDef = {
                            id: `ShellyWebserver.ScanEvent.${params.events[0].data.addr}.${clientId}`,
                            initial: val,
                            forceCreation: false,
                            common: { role: "state", read: true, write: false, name: "RSSI", type: "number" },
                            native: {}
                        }
                    
                    
                        if ( existsState( `javascript.${instance}.${StateDef.id}`) ){
                            setState( StateDef.id, val);
                        } else {
                            createState(StateDef.id, StateDef.initial, StateDef.forceCreation, StateDef.common, StateDef.native);
                        }
                    
                    });
                    
                    httpServer.listen( port);
                    
                    
                    
                    
                    
                    function closeWS() {
                        console.log("Close http server connection.");
                        shellyOws.removeHandler( "NotifyEvent", idHandler);
                        shellyOws.sockets.forEach( socket => {
                            socket.close()
                        });
                        httpServer.close();
                    }
                    onStop(closeWS, 1000);
                    
                    

                    Ich muss ernüchternd feststellen, dass mein MiBand 6 gerade gar nicht mehr vom Shelly erkannt wird. Zuletzt wurde es erkannt, wenn auch nur alle 10 - 15 Sekunden. Da hatte ich aber noch versucht meine Pixel Watch über iBeacon zu erkennen (erfolglos). Nun hatte ich den Test mit dem MiBand machen wollen, wird nicht angezeigt. Aber grundsätzlich funktioniert das Skript.

                    Die Struktur der States schaut wie folgt aus:

                    javascript.INSTANZ*.ShellyWebserver.ScanEvent.MAC*.SHELLYDEVICE*

                    INSTANZ: Entspricht Instanz des Skripts in ioBroker
                    MAC: Gefundene Mac Adresse während des Scans
                    SHELLYDEVICE: Jeder Shelly schreibt seinen RSSI Wert unter seinem eigenen State

                    1189cb1f-3c71-4e28-a8e9-2176b0e6d025-image.png

                    Ich werde, nach jetzigem Stand, das Scannen mit der aktuellen original Shelly Firmware nicht mehr weiter verfolgen. Habe das Gefühl dass das Thema bei Shelly nicht ausgereift ist. Vor allem wird meine MiBand nicht konsequent gefunden. Was ich absolut nicht verstehen kann. Über den Android Scanner meines Handys oder über Espresense funktioniert es einwandfrei.

                    Ich werde mich wahrscheinlich in Tasmota nochmals versuchen. Zuletzt hatte die Schaltererkennung evtl. nicht funktioniert, weil mein Shelly einer aktuelleren Hardware entspricht.

                    U 1 Reply Last reply Reply Quote 1
                    • U
                      Utze86 @GiuseppeS last edited by

                      @giuseppes Danke für die Skripte. Leider kann ich auch keine positive Rückmeldung geben. Mit der Shelly Firmware erhalte ich im Durchschnitt nur alle 7-8 Sekunden ein Signal von meinem Mi Band. Das Ergebnis ist also wesentlich schlechter als die Auswertung über Tasmota. Ich werde im nächsten Schritt ein paar Shellys mit Tasmota flashen und mich um die Umsetzung der Anwesenheitserkennung kümmern.

                      G 1 Reply Last reply Reply Quote 1
                      • G
                        GiuseppeS @Utze86 last edited by

                        @utze86
                        Tasmota wäre aktuell auch meine erste Wahl. Werde im Testaufbau aber noch prüfen müssen, wieso die Schaltereingänge im detached Modus teilweise so spät erkannt werden. Benötige ich für zwei Fälle.

                        U 1 Reply Last reply Reply Quote 0
                        • stolly82
                          stolly82 last edited by stolly82

                          @giuseppes

                          Wie bekommen ich den Websocket im JavaScript Adapter zum laufen?

                          20:55:37.971	info	javascript.1 (30342) Start javascript script.js.Rules.Allgemein.Lokalisierung.Indoor_-_Shelly
                          20:55:38.124	info	javascript.1 (30342) script.js.Rules.Allgemein.Lokalisierung.Indoor_-_Shelly: WS server starting at port 8085
                          20:55:38.132	info	javascript.1 (30342) script.js.Rules.Allgemein.Lokalisierung.Indoor_-_Shelly: registered 0 subscriptions and 0 schedules
                          20:55:38.176	error	javascript.1 (30342) script.js.Rules.Allgemein.Lokalisierung.Indoor_-_Shelly: TypeError: WebSocketServer is not a constructor
                          20:55:38.179	error	javascript.1 (30342) at ShellyOWS.init (script.js.Rules.Allgemein.Lokalisierung.Indoor_-_Shelly:70:19)
                          20:55:38.181	error	javascript.1 (30342) at new ShellyOWS (script.js.Rules.Allgemein.Lokalisierung.Indoor_-_Shelly:61:14)
                          20:55:38.183	error	javascript.1 (30342) at script.js.Rules.Allgemein.Lokalisierung.Indoor_-_Shelly:282:17
                          20:55:38.184	error	javascript.1 (30342) at script.js.Rules.Allgemein.Lokalisierung.Indoor_-_Shelly:324:3
                          

                          e20d8ed0-01bb-4506-8b9d-4943b4bafe00-image.png
                          Zusätzliche NPM Module ws oder websocket läuft leider nicht 😞

                          G 2 Replies Last reply Reply Quote 0
                          • G
                            GiuseppeS @stolly82 last edited by

                            @stolly82
                            Woher weißt du, dass der Server nicht richtig läuft? Ich sehe keine Fehlermeldungen. Port 8085 sollte frei sein, dieser wird vom Server verwendet.

                            Hast du den Shelly auch korrekt auf den Server eingerichtet?

                            1 Reply Last reply Reply Quote 0
                            • G
                              GiuseppeS @stolly82 last edited by

                              @stolly82
                              Nur ws ist als Modul notwendig

                              1 Reply Last reply Reply Quote 0
                              • U
                                Utze86 @GiuseppeS last edited by Utze86

                                @giuseppes Nochmal eine kleine Rückmeldung zum Shelly. Ich habe das Skript nochmal mit der aktuellen stable Firmware von Shelly getestet. Diesen letzten Test wollte ich dann noch nochmal durchführen als ich gesehen habe, dass es ein Update gibt. Hier habe ich allerdings ein ähnliches Problem wie du: Das Mi Band wird komischer Weise gar nicht mehr erkannt. Keine Ahnung ob es am BLE in Kombi mit dem Band und dem Shelly liegt. Andere Geräte werden teils mehrfach die Sekunde erkannt. Der Trend geht also weiter zu Tasmota.

                                Hast du eigentlich inzwischen eine Möglichkeit gefunden die Shelly Firmware wieder zurück auf den Shelly zu bekommen wenn dort einmal Tasmota installiert wurde? Bisher konnte ich online keine original Firmware finden. Die Firmware von einem anderen Shelly runter ziehen fällt aktuell leider Flach da mein USB/Serial Adapter scheinbar den Geist aufgegeben hat. Aber ich habe gesehen, dass die Shellys sich inzwischen OTA mit verschiedenen Firmwaren flashen lassen. Was natürlich mega praktisch ist, vorallem wenn die Dinger bereits verbaut sind. Also falls du eine originale Firmware hast wäre es cool wenn du sie mir zur Verfügung stellen könntest.

                                EDIT: OTA geht natürlich nicht von Original FW zu Tasmota 😞

                                G 1 Reply Last reply Reply Quote 0
                                • G
                                  GiuseppeS @Utze86 last edited by

                                  @utze86
                                  Habe selbst noch keine original Firmware finden können, daher ist ein Flashen zurück auf original auch für mich nicht möglich. Über die Möglichkeit, die Firmware von einem anderem Gerät zu ziehen, hatte ich noch gar nicht nachgedacht.
                                  Ich habe übrigens meine Pixel Watch verkauft und mir die Amazfit GTS 4 Mini geholt. Diese sendet, wie das Mi Band, konstant Advertisements. Aber auch diese wird vom Shelly nicht gefunden, egal ob original Firmware oder Tasmota. Daher habe ich nun meine zwei Test-Shelly auf Facebook zum Verkauf angeboten. Ich überlege nun original esp32 mit espresense zu verwenden. Ich hatte versucht espresense für die Shelly zu kompilieren, funktionierte anscheinend, aber irgendwas führt dann zu einem kritischen Fehler und der Shelly bootet. Hatte schon einen Schaltereingang zu Testzwecken im espresense Code integriert... überlege nun worauf ich mich konzentrieren soll. Zeit ist ein begrenztes Gut.
                                  Werde mich mal schlau machen, wie ich Firmware von einem Shelly downloaden kann und melde mich wenn erfolgreich.

                                  U 2 Replies Last reply Reply Quote 0
                                  • U
                                    Utze86 @GiuseppeS last edited by Utze86

                                    @giuseppes

                                    Das klingt ja sehr ernüchternd. Sobald das bei mir mit dem flashen wieder funktioniert. Probiere ich nochmal die Variante mit Tasmota. Aber ist halt blöd zu wissen, dass wenn ich das Mi Band irgendwann durch ein anderes Armband tausche ich eventuell wieder Probleme mit dem Scannen bekomme. Der Wechsel zu "richtigen" ESP`s mir Espresence wäre wahrscheinlich die effektivste Lösung würde mich aber wieder vor das Problem stellen keine Unterputzlösung zu haben. Eventuell müsste ich mir hier nochmal Gedanken machen. Ich mache es davon abhängig wie es final mit Tasmota läuft. Allerdings würde ich auch langsam ganz gerne mal was umsetzen und nicht immer nur testen, wie du schon sagst die Zeit ist immer begrenzt...

                                    Dein Angebot bei Facebook habe ich gestern übrigens verfolgt 🙂

                                    Bezüglich zurückflashen der Firmware bin ich übrigens vor einiger Zeit auf dieses Video gestoßen. Möglicherweise funktioniert es über den gleichen weg mit den Shellys Gen. 2, müsste man mal testen. Ich persönlich kenne mich nicht wirklich mit Python aus, scheint mir jetzt aber auch nicht all zu komplex zu sein wenn man die Anleitung nutzt.

                                    https://haus-automatisierung.com/projekt/2018/10/25/projekt-esp-firmware-klonen.html

                                    G 1 Reply Last reply Reply Quote 0
                                    • G
                                      GiuseppeS @Utze86 last edited by

                                      @utze86
                                      Original Firmware:
                                      Hatte heute die Firmware von einem Shelly gezogen und auf einem Tasmotized Shelly geflashed, hatte geklappt. Durch verschiedene Tests habe ich die Firmware aber unbrauchbar gemacht. Morgen lade ich die wieder und melde mich.

                                      Scanner:
                                      Auch mein mi band wurde zum Teil von Tasmota nicht erkannt und phasenweise, wenn es erkannt wurde, kamen die rssi mal nach 2s, mal nach 15s.
                                      Das mit espresense (crash) hatte mich so geärgert, dass ich keine Lust mehr darauf hatte. Hatte heute zwei Einstellungen korrigiert und trotzdem =crash.
                                      Aber die Komplexität von espresense benötige ich nicht, ebenso ist tasmota eigentlich zu viel. Daher schreibe ich jetzt etwas von Grund auf neu.
                                      Habe die bluetooth Bibliothek im shelly ohne crash getestet: Uhr wird sogar sekündlich (!!!) gefunden. Hoffe, dass es sich nicht verschlechtert, wenn die Wifi Verbindung dazu kommt.

                                      Nächsten Schritte:

                                      • Erkennung der Schaltereingänge
                                      • Schalten der Relais
                                      • Übertragung der Werte über mqtt. Hier muss ich schauen, was alles übertragen wird. Es wäre sonst sehr viel. Zunächst nur MAC + RSSI + Status Eingänge
                                      • Schalten der Relais über mqtt
                                      • wenn noch Zeit und Motivation übrig: OTA Update ermöglichen

                                      Meine minimal Idee für die Umsetzung hinsichtlich Shelly: die Statis der Schalter-Eingänge werden immer über mqtt übermittelt. Somit kann die Intelligenz (Schalter, Taster, mit Relay verknüpft, Rollladen oder Licht, etc.) vollständig über ioBroker umgesetzt werden.

                                      U 1 Reply Last reply Reply Quote 0
                                      • U
                                        Utze86 @GiuseppeS last edited by

                                        @giuseppes
                                        Hört sich mal wieder vielversprechend an ich bin gespannt was du berichtest. Morgen müsste mein neuer Controller zum flashen kommen. Dann teste ich mich nochmal parallel mit Tasmota und werde mal ein paar Shellys verbauen. Bin gespannt wie stabil das dann auch läuft. Nach deinem letzten Post bin ich da etwas skeptisch, dass das dauerhaft und stabil läuft.

                                        1 Reply Last reply Reply Quote 0
                                        • U
                                          Utze86 last edited by

                                          @GiuseppeS

                                          Wie laufen deine Versuche mit der bluetooth Bibliothek? Bist du schon weiter?

                                          Ich habe inzwischen zwei Shellys mit Tasmota verbaut und die Signale vom MiBand kommen nach wie vor recht regelmäßig an. Neben dem Mi Band versuche ich grade noch ein weiteres BLE Gerät zu tracken. Hierzu nehme ich ein Gigaset BLE Beacon. Beide Geräte werden vom Shelly zuverlässig empfangen und im Tasmota Main Menu angezeigt. Allerdings habe ich das Problem, dass beide RSSI Werte in nur einen Datenpunkt IBEACON_RSSI im iobroker geschrieben werden. Das heißt ich kann bei meiner Auswertung im iobroker nicht mehr differenzieren ob das Signal vom Mi Band oder vom BLE Tag kommt. Hast du eine Idee wie ich es gelöst bekomme, dass Tasmota zwei Datenpunkte an den iobroker sendet, also bspw. IBEACON_RSSI_MiBand und IBEACON_RSSI_GigasetBeacon? Zur Auswertung nutze ich den Sonoff Adapter aber eventuell gibt es ja eine andere Möglichkeit.

                                          Die zwei Geräte bekommt man übrigens einfach gescannt und gefiltert wenn man in der Tasmota-Konsole die Regel für zwei Geräte hintereinander weg eingibt, danke für den Tipp:
                                          Rule2 ON System#Boot DO BLEAlias MACadresse1=Name1 MACAdresse2=Name2 endon

                                          G 1 Reply Last reply Reply Quote 0
                                          • G
                                            GiuseppeS @Utze86 last edited by

                                            @utze86
                                            Wenn der Gigaset Tag immer mit der selben MAC sendet, kannst Du das so machen. Spätestens, wenn das Smartphone über iBeacon Simulator hinzukommt, klappt das Filtern nicht mehr, da dann die UUID verwendet werden müsste, Tasmota aber nur mac filtern kann. Zumindest habe ich nichts anderes gefunden.
                                            Leider funktioniert der Sonoff Adapter nicht optimal mit den Scanner Werten. Du kannst alternativ den MQTT Client Adapter testen. Dann müsstest du alles über MQTT selbst steuern.

                                            Zu meiner Implementierung für den Shelly

                                            Bisher umgesetzt:

                                            • BLE Scanner für eine hinterlegte MAC. Werte kommen meist alle 1-2 Sekunden. Manchmal dauert es 3-4s.
                                            • Erkennen der Schaltereingänge
                                            • Schalten der Ausgänge
                                            • Modus für Licht und Rollladen umschaltbar
                                            • Rollladen über Positionsvorgabe steuerbar (bisher einfache Kalibrierung über manuelle Zeitmessung)
                                            • OTA Updates möglich über PlatformIO

                                            Bisher fest codiert, nicht optimal für Endanwender:

                                            • WLAN und MQTT Server Konfiguration
                                            • Konfiguration der Ein- und Ausgänge
                                            • Filter für eine MAC

                                            Geplant (in dieser Reihenfolge)

                                            • Konfiguration der Ein- und Ausgänge über MQTT
                                            • Filter erweitern auf mehrere MAC und über MQTT
                                            • Filter erweitern auf iBeacon UUIDs
                                            • Auf Github inkl Doku veröffentlichen
                                            • Leistungsmessung für Shelly 2PM integrieren und darüber automatische Kalibrierung der Rollläden
                                            • Leistungsmessung für Shelly 1PM

                                            Die Leistungsmessungen sind absolut optional, wenn ich Langeweile haben sollte.

                                            Einzig Wifi und Mqtt werde ich wahrscheinlich nicht zeitnah über WebUI implementieren können, da ich kein funktionierendes Beispiel habe. Bedeutet, jeder Endanwender muss selbst über PlatformIO kompilieren.

                                            Es wurden zuletzt Shelly Plus 2PM mit DualCore gesichtet. Wenn ich eins davon in die Finger bekomme, würde ich versuchen, die Shelly Funktionalität in Espresense zu integrieren.

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

                                            Support us

                                            ioBroker
                                            Community Adapters
                                            Donate

                                            884
                                            Online

                                            31.6k
                                            Users

                                            79.5k
                                            Topics

                                            1.3m
                                            Posts

                                            26
                                            242
                                            34327
                                            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