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

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

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. Hardware
  4. MQTT Bluetooth BLE Anwesenheitserkennung mit ESP32

NEWS

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

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

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

MQTT Bluetooth BLE Anwesenheitserkennung mit ESP32

Geplant Angeheftet Gesperrt Verschoben Hardware
242 Beiträge 26 Kommentatoren 45.8k Aufrufe 32 Watching
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • S Spezialtrick

    @giuseppes

    Dann setze ich erstmal drei ESP auf und warte auf dein Skript. :)

    G Offline
    G Offline
    GiuseppeS
    schrieb am zuletzt editiert von
    #71

    @spezialtrick

    Anbei das Skript für Triangulation:

    const mathjs = require("mathjs");
    
    
    /**
      * Berechnet triangulierten Punkt inkl. Unschärfe-Radius
      *
      * Basis-Gleichung lautet:
      * (x - x_i)² + (y - y_i)² = (r_i + ur)²,
      * mit i = 1,2,3 und ur = Unschärferadius
      * -> x² + x_i² - 2x_i*x + y² + y_i² - 2y_i*y = r_i² + u² + 2r_i*u
      *
      * Angelehnt an Lösungsweg: https://stackoverflow.com/a/56294794
      * Änderung: statt "= (r_i * k)² wird "= (r_i + ur)²" verwendet!
      *
      * @param {Object} p1 First point and radius: [ x, y, r ]
      * @param {Object} p2 Second point and radius: [ x, y, r ]
      * @param {Object} p3 Third point and radius: [ x, y, r ]
      * @return {Object} tril. Point and error-radius { x, y, ur }
      */
    function trilaterate (p1, p2, p3) {
    
        function sqr (a) {return a*a};
        function sqrt (a) {return mathjs.sqrt(a)};
    
        function solvePQ (p,q) {
            let d = sqr(p)/4 - q;
            if (d >= 0){
                let x1 = -p/2 + sqrt(d);
                let x2 = -p/2 - sqrt(d);
                return [x1, x2]
            } else {
                return []
            }
        }
    
        let x1 = p1[0], y1 = p1[1], r1 = p1[2],
            x2 = p2[0], y2 = p2[1], r2 = p2[2],
            x3 = p3[0], y3 = p3[1], r3 = p3[2];
    
        // Gl. a_i: x² + x_i² - 2x_i*x + y² + y_i² - 2y_i*y = r_i² + u² + 2r_i*u
        // Gl. a_1 - Gl. a_2 und Gl. a_1 - Gl.a_3 eliminiert x²/y² und ergibt ein LGS
        // A * X = C + B * u >>> X = A^-1 * C + A^-1 * B * u
    
        let A = [
            [ 2*(x2 - x1), 2*(y2 - y1) ],
            [ 2*(x3 - x1), 2*(y3 - y1) ]
        ];
    
        let C = [
            sqr(r1) - sqr(r2) - sqr(x1) + sqr(x2) - sqr(y1) + sqr(y2),
            sqr(r1) - sqr(r3) - sqr(x1) + sqr(x3) - sqr(y1) + sqr(y3)
        ];
    
        let B = [ 2*(r1 - r2), 2*(r1 - r3) ];
    
        let A_inv = mathjs.inv(A);
        let A_invC = mathjs.multiply(A_inv, C);
        let A_invB = mathjs.multiply(A_inv, B);
    
        // x = A_invC[0] + A_invB[0] * u, und y = A_invC[1] + A_invB[1] * u
        // x = c1 + c2 * u, und y = c3 + c4 * u in Gl. a_1
    
        let c1 = A_invC[0];
        let c2 = A_invB[0];
        let c3 = A_invC[1];
        let c4 = A_invB[1];
        
        let quot = sqr(c2) + sqr(c4) - 1;
        let p = (2*c1*c2 - 2*x1*c2 + 2*c3*c4 - 2*y1*c4 - 2*r1) / quot;
        let q = (sqr(c1) + sqr(x1) - 2*x1*c1 + sqr(c3) + sqr(y1) - 2*y1*c3 - sqr(r1)) / quot;
    
        let arrU = solvePQ(p,q);
    
        if (arrU == []) return "ur konnte nicht berechnet werden!";
    
        let u = arrU[0]; // Bisherige Tests: arrU[0] scheint immer zu passen?
        let x = c1 + c2 * u;
        let y = c3 + c4 * u;
    
        return { x: x.toFixed(2), y: y.toFixed(2), ur: u.toFixed(2) }
        
    }
    
    console.log(trilaterate( [0,0,7], [10,0,7], [5,8.66,7] ))
    
    

    Übergabe in die Funktion "trilaterate()" sind die drei Punkte mit X, Y und Radius. Radius ist der in cm oder m umgerechnete RSSI Wert. Die Umrechnung findest Du im unteren Skript mit "getDist()". Wichtig ist natürlich, dass immer dieselben Einheiten verwendet werden ;-)
    Übrigens musst Du innerhalb der Javascript Instanz das Modul mathjs eingeben. Das wird hier für vereinfachte Matrizen-Rechnungen verwendet.

    Womit ich zuletzt experimentiert hatte, war das Anzeigen der RSSI Werte (umgerechnet in cm) über html. Weil ich nur ein esp32 hatte (+ BLE vom PC), habe ich so nutzbare Filtermöglichkeiten getestet.
    Für das bessere Verständnis:
    "rssiComp" = RSSI Wert meines PCs = Sensor 1
    "rssiWemos" = RSSI Wert meines ESP32 = Sensor 2

    Im folgenden Skript werden die Positionen der beiden Sensoren + deren RSSI-in-cm Werten zu meiner BLE Uhr angezeigt

    
    createState("VIS.bleScan.Drawing");
    
    let idType = "Avg"; // Kf oder Raw
    
    // return in cm
    function getDist(rssi, txPower){
        let n = 2;
        let exponent = (txPower - rssi) / (10 * n);
        return Math.pow(10, exponent)*100;
    }
    
    let rssiComp, rssiWemos;
    
    on({id: new RegExp('javascript\.1\.VIS\.bleScan.\Pino\..*'), change: "any"}, function (obj) {
        let value = obj.state.val;
        let id = obj.id.split(".").pop();
    
        if (id == idType + "Wemos") rssiWemos = value;
        if (id == idType + "Comp") rssiComp = value;
        
        let html = '<svg width="410" height="900"> '
                 + '<rect x="10" y="10" width="225" height="500" style="fill:none;stroke:white;stroke-width:5" />'
                 + '<circle cx="220" cy="70" r="5" stroke="white" stroke-width="5" fill=white />' /*Comp*/
                 + '<text x="200" y="100" fill="red">' + rssiComp + '</text>' /*Comp*/
                 + '<circle cx="220" cy="70" r="' + getDist(rssiComp, -69)/2 + '" stroke="green" stroke-width="4" fill=none />' /*Comp*/
                 + '<circle cx="100" cy="410" r="5" stroke="white" stroke-width="5" fill=white />' /*Wemos*/
                 + '<text x="80" y="440" fill="red">' + rssiWemos + '</text>' /*Wemos*/
                 + '<circle cx="100" cy="410" r="' + getDist(rssiWemos, -69)/2 + '" stroke="green" stroke-width="4" fill=none />' /*Wemos*/
                 + '</svg>'
        
        setState("javascript." + instance + ".VIS.bleScan.Drawing", html);
    });
    

    So sahen meine Test-States aus:
    374aba7d-eb59-4090-9739-063b4b475a6e-image.png

    1 Antwort Letzte Antwort
    0
    • S Spezialtrick

      @giuseppes

      Dann setze ich erstmal drei ESP auf und warte auf dein Skript. :)

      G Offline
      G Offline
      GiuseppeS
      schrieb am zuletzt editiert von
      #72

      @spezialtrick
      Natürlich kannst Du beide Skripte in ein einziges Skript zusammnführen. Ich hatte zu dem Zeitpunkt die beiden Tests unabhängig voneinander durchgeführt, daher getrennt aufgeführt...

      1 Antwort Letzte Antwort
      0
      • E Offline
        E Offline
        exitus
        schrieb am zuletzt editiert von
        #73

        Hallo klappt es auch mit iphone kann ich das Bluetooth signal vom iphone auch dafür benutzen???

        G 1 Antwort Letzte Antwort
        0
        • E exitus

          Hallo klappt es auch mit iphone kann ich das Bluetooth signal vom iphone auch dafür benutzen???

          G Offline
          G Offline
          GiuseppeS
          schrieb am zuletzt editiert von
          #74

          @exitus
          Sowie ich das beim iPhone meiner Freundin erkennen konnte, sendete das iPhone nur ble Advertisements während es entsperrt war. Nicht dauerhaft. Bei Androiden gibt es Apps, um es dauerhaft zu aktivieren.

          E 1 Antwort Letzte Antwort
          0
          • G GiuseppeS

            @exitus
            Sowie ich das beim iPhone meiner Freundin erkennen konnte, sendete das iPhone nur ble Advertisements während es entsperrt war. Nicht dauerhaft. Bei Androiden gibt es Apps, um es dauerhaft zu aktivieren.

            E Offline
            E Offline
            exitus
            schrieb am zuletzt editiert von
            #75

            @giuseppes warum es hier klappt ???
            https://www.youtube.com/watch?v=ShyqG8DjkrU&t=65s

            G 1 Antwort Letzte Antwort
            0
            • E exitus

              @giuseppes warum es hier klappt ???
              https://www.youtube.com/watch?v=ShyqG8DjkrU&t=65s

              G Offline
              G Offline
              GiuseppeS
              schrieb am zuletzt editiert von GiuseppeS
              #76

              @exitus
              Habe mir gerade die Zeit genommen und in Video reingeschaut. Im Video geht es Bluetooth allgemein und nicht ble. So löse ich übrigens auch daheim das allgemeine Thema Anwesenheit. Mit dem Bluetooth vom PC, das funktioniert auch mit iPhones.
              In diesem Thread geht es um BLE, hierfür werden Geräte benötigt, die dauerhaft BLE Advertisements senden. Und soweit ich weiß, senden iPhones nur bis die ihren Funk allgemein schlafen legen. Deshalb ist beim iPhones auch die Anwesenheit per WLAN ping nur eingeschränkt möglich.

              1 Antwort Letzte Antwort
              0
              • G Offline
                G Offline
                GiuseppeS
                schrieb am zuletzt editiert von GiuseppeS
                #77

                Ich denke, dass dieses Projekt die richtige Adresse für alle Interessenten ist:

                https://espresense.com/

                Hier wird anscheinend alles geboten, um mehrere esp32 zu verwenden und daraus die eigene Position zu ermitteln.

                EDIT:
                Anscheinend ist espresense nur eine angenehme Art die ESPs zu flashen. Natürlich inkl einiger Vorteile dieser Firmware: statt MAC wird ein Fingerprint gesendet. Unkomplizierte Art der Konfiguration über Weboberfläche. Trilateration und Darstellung ist trotzdem zu erledigen. Wenn ich mit meinem FireTV Projekt durch bin, werde ich hier was versuchen...

                S 1 Antwort Letzte Antwort
                0
                • G GiuseppeS

                  Ich denke, dass dieses Projekt die richtige Adresse für alle Interessenten ist:

                  https://espresense.com/

                  Hier wird anscheinend alles geboten, um mehrere esp32 zu verwenden und daraus die eigene Position zu ermitteln.

                  EDIT:
                  Anscheinend ist espresense nur eine angenehme Art die ESPs zu flashen. Natürlich inkl einiger Vorteile dieser Firmware: statt MAC wird ein Fingerprint gesendet. Unkomplizierte Art der Konfiguration über Weboberfläche. Trilateration und Darstellung ist trotzdem zu erledigen. Wenn ich mit meinem FireTV Projekt durch bin, werde ich hier was versuchen...

                  S Offline
                  S Offline
                  Spezialtrick
                  schrieb am zuletzt editiert von
                  #78

                  @giuseppes Bist du schon zum Testen gekommen? :)

                  G 1 Antwort Letzte Antwort
                  0
                  • S Spezialtrick

                    @giuseppes Bist du schon zum Testen gekommen? :)

                    G Offline
                    G Offline
                    GiuseppeS
                    schrieb am zuletzt editiert von
                    #79

                    @spezialtrick
                    Ja, allerdings mit der Erkenntnis, dass die esp32 ab ca. 4-6 absolut ungenau sind. Kann später mein Skript hochladen. Hatte es schon ziemlich generisch programmiert. Hatte zu Testzwecken folgendes umgesetzt:

                    • Erstellen von Räumen in svg
                    • Darstellung der Radien der esp32

                    Es wird ein Datenpunkt erstellt und aktualisiert. So kann man sich ein Bild davon machen, wie genau die esp32 einen orten können.

                    Wollte schauen wie die Genauigkeit ist, bevor ich bzgl Trilateration etc weiter mach. Habe dann abgebrochen, d.h. Trilateration habe ich nicht integriert.

                    1 Antwort Letzte Antwort
                    0
                    • S Offline
                      S Offline
                      Spezialtrick
                      schrieb am zuletzt editiert von
                      #80

                      @giuseppes Danke für die kurzfristige Antwort!

                      War deine Erkenntnis, dass esp32 ab ca. 4-6m Entfernung ungenau werden oder wenn man 4-6 ESPs nutzt, Ungenauigkeiten auftreten?

                      G 1 Antwort Letzte Antwort
                      0
                      • M Offline
                        M Offline
                        Muchul
                        schrieb am zuletzt editiert von
                        #81

                        Hat schon jemand das Appdaemon app eingesetzt?
                        https://github.com/ESPresense/ad-espresense-ips

                        1 Antwort Letzte Antwort
                        0
                        • S Spezialtrick

                          @giuseppes Danke für die kurzfristige Antwort!

                          War deine Erkenntnis, dass esp32 ab ca. 4-6m Entfernung ungenau werden oder wenn man 4-6 ESPs nutzt, Ungenauigkeiten auftreten?

                          G Offline
                          G Offline
                          GiuseppeS
                          schrieb am zuletzt editiert von
                          #82

                          @spezialtrick
                          Ab ca 3m wird es immer ungenauer, sodass das Signal ab gut 4m eigentlich nicht mehr brauchbar ist. Dann würde die räumliche Zuordnung nicht mehr funktionieren. Alternativ müsste man entsprechend viele esp32 verteilen. Aber in meinen 90qm müssten es dann schon mindestens 7 Stück sein.

                          @Muchul
                          Diese sogenannte App ist ein python script zugeschnitten auf Homeassistant. Die Triangulation ist zwar in einer separaten Unterfunktion, aber die Berechnung wird mit Hilfe weniger mathematischer Aufrufe aus python Bibliotheken durchgeführt. Ich habe nach Alternativen für JS gesucht aber bin nicht fündig geworden.
                          Grundsätzlich halte ich es aber eh für genauer, nur die nächstgelegenen 3 esp32 zu verwenden statt alle und ein best-fit zu berechnen. Schließlich nahm in meinem Test mit zunehmender Distanz die Genauigkeit massiv ab. Triangulation mit nur drei Punkten auf der Ebene habe ich schon.

                          M 1 Antwort Letzte Antwort
                          0
                          • G GiuseppeS

                            @spezialtrick
                            Ab ca 3m wird es immer ungenauer, sodass das Signal ab gut 4m eigentlich nicht mehr brauchbar ist. Dann würde die räumliche Zuordnung nicht mehr funktionieren. Alternativ müsste man entsprechend viele esp32 verteilen. Aber in meinen 90qm müssten es dann schon mindestens 7 Stück sein.

                            @Muchul
                            Diese sogenannte App ist ein python script zugeschnitten auf Homeassistant. Die Triangulation ist zwar in einer separaten Unterfunktion, aber die Berechnung wird mit Hilfe weniger mathematischer Aufrufe aus python Bibliotheken durchgeführt. Ich habe nach Alternativen für JS gesucht aber bin nicht fündig geworden.
                            Grundsätzlich halte ich es aber eh für genauer, nur die nächstgelegenen 3 esp32 zu verwenden statt alle und ein best-fit zu berechnen. Schließlich nahm in meinem Test mit zunehmender Distanz die Genauigkeit massiv ab. Triangulation mit nur drei Punkten auf der Ebene habe ich schon.

                            M Offline
                            M Offline
                            Muchul
                            schrieb am zuletzt editiert von
                            #83

                            @giuseppes
                            Ich suche noch nach einer Möglichkeit, auf einer Karte anzuzeigen, wo der BLE Tag liegt.
                            Ich habe 100qm und 6 Räume. Ich wäre auch geneigt bis zu 10 esp32 Laufen zu lassen, aber Mangels Programmierkenntnisse wird es wohl schwierig.

                            G 1 Antwort Letzte Antwort
                            0
                            • M Muchul

                              @giuseppes
                              Ich suche noch nach einer Möglichkeit, auf einer Karte anzuzeigen, wo der BLE Tag liegt.
                              Ich habe 100qm und 6 Räume. Ich wäre auch geneigt bis zu 10 esp32 Laufen zu lassen, aber Mangels Programmierkenntnisse wird es wohl schwierig.

                              G Offline
                              G Offline
                              GiuseppeS
                              schrieb am zuletzt editiert von
                              #84

                              @muchul
                              Ich sags mal so: wenn ihr aus der Genauigkeit einen Nutzen ziehen könnt, kann ich das Skript noch ergänzen. Lade erstmal das hoch was ich habe. Wenn ihr mit euren Tests zufrieden seid, ergänze ich es anschließend. Wollte keine Energie mehr reinstecken, weil ich es selbst höchstwahrscheinlich nicht nutzen werde. Es gibt leider keine tolle Möglichkeit esp32 versteckt zu installieren.

                              M 1 Antwort Letzte Antwort
                              0
                              • G GiuseppeS

                                @muchul
                                Ich sags mal so: wenn ihr aus der Genauigkeit einen Nutzen ziehen könnt, kann ich das Skript noch ergänzen. Lade erstmal das hoch was ich habe. Wenn ihr mit euren Tests zufrieden seid, ergänze ich es anschließend. Wollte keine Energie mehr reinstecken, weil ich es selbst höchstwahrscheinlich nicht nutzen werde. Es gibt leider keine tolle Möglichkeit esp32 versteckt zu installieren.

                                M Offline
                                M Offline
                                Muchul
                                schrieb am zuletzt editiert von
                                #85

                                @giuseppes
                                Ich habe sie in kleine 6x10 cm Gehäuse gepackt, auf einer Platine mit Netzteil gelötet und in die Ecken der Zimmer gelegt, meistens steht da eh was rum, so dass die nicht zu sehen sind.

                                1 Antwort Letzte Antwort
                                0
                                • G Offline
                                  G Offline
                                  GiuseppeS
                                  schrieb am zuletzt editiert von GiuseppeS
                                  #86

                                  Anbei das Skript für die Anzeige der Scanner innerhalb eurer Räumlichkeiten. Ich habe testweise zwei Scanner wieder laufen lassen. Ich selbst bin in diesem Bild im selben Raum wie der Scanner "gast1". Der Ring vom gast1 Scanner erwischt mich ziemlich gut. Aber man sieht dass der weiter entfernte Scanner nicht ganz hinkommt. Ich bin ca. 7 Meter vom wohnz1 Scanner entfernt. Angezeigt werden 4,8m. Manchmal ist der RAW Wert vom Scanner besser, aber dieser schwankt halt doch stärker. War auch schon im Wohnzimmer gestanden und die Ringe beobachtet... Naja... Wenn wirklich Räume detektiert werden sollen, dann ist es hier eher ein Schätzen. Dann genau so gut in jede Ecke eines Raumes ein esp hingelegt werden und auswerten welche der esp's den geringsten Wert anzeigt, natürlich ohne Überschneidungen und immer in die äßeren Raum-Ecken.

                                  e6903e90-8760-4adb-947e-a7a0460854bd-image.png

                                  
                                  
                                  let svgScale = 0.4;
                                  
                                  /**
                                   * ##########################################################################################
                                   * Define your rooms. Coordinates starts at upper left corner...
                                   * 
                                   * Property key "color" is optional, e.g. { name: "Kueche", x: 0, y: 0, w: 360, h: 200, color: "red"},
                                   * Key "name" must contain only letters! No whitespaces and any special characters are allowed!
                                   * ##########################################################################################
                                   */
                                  
                                  let defaultColorRooms = "blue";
                                  let RoomDef = [
                                      { name: "Kueche",       x:   0, y:   0, w: 360, h: 200},
                                      { name: "Gaestezimmer", x:   0, y: 220, w: 360, h: 280},
                                      { name: "Badezimmer",   x:   0, y: 520, w: 360, h: 220},
                                      { name: "Essbereich",   x: 380, y:   0, w: 230, h: 230},
                                      { name: "Wohnzimmer",   x: 380, y: 230, w: 230, h: 230},
                                      { name: "Wohnzimmer",   x: 610, y:   0, w: 370, h: 460},
                                      { name: "Flur",         x: 380, y: 460, w: 380, h: 200},
                                      { name: "Flur",         x: 380, y: 660, w: 150, h: 110},
                                      { name: "GastWC",       x: 550, y: 680, w: 150, h:  90},
                                      { name: "Schlafzimmer", x: 780, y: 480, w: 350, h: 400}
                                  ];
                                  
                                  
                                  
                                  /**
                                   * ##########################################################################################
                                   * Define your scanner. Coordinates starts at upper left corner...
                                   * 
                                   * Property key "color" is optional, e.g. gast1: { x: 260, y: 230, color: "red"},
                                   * Key name must be same as configured in presense scanner!
                                   * ##########################################################################################
                                   */
                                  
                                  let defaultColorScanner = "white";
                                  let defaultRadiusScanner = 10;
                                  // Property key "color" is optional
                                  let ScannerDef = {
                                      gast1: { x: 260, y: 230},
                                      wohnz1:   { x: 980, y: 430}
                                  };
                                  
                                  
                                  
                                  /**
                                   * ##########################################################################################
                                   * Define your beacons. Coordinates starts at upper left corner...
                                   * 
                                   * ##########################################################################################
                                   */
                                  
                                  let defaultColorBeacon = "red";
                                  let BeaconDef = {
                                      MiBand: "mqtt-client.0.espresense.devices.mifit:c1090a022232",
                                      One8Pro: "mqtt-client.0.espresense.devices.iBeacon:5a7a3358-247b-4e68-9d6e-6ced93ff93f1-0-0",
                                      Iphone: "mqtt-client.0.espresense.devices.apple:iphone13-3"
                                  };
                                  
                                  
                                  
                                  
                                  
                                  
                                  
                                  let praefixStates = `javascript.${instance}.IndoorPositioning.`;
                                  
                                  function dbglog(){
                                      return false
                                  }
                                  
                                  let InstArrRooms = [];
                                  let InstJsScanner = {};
                                  let InstArrBeacons = [];
                                  
                                  
                                  function pushStates( JsStates, cb) {
                                      let actStateName, State;
                                      let create = () => {
                                          createState( State.id, State.common, State.native, () => {
                                              setTimeout( ()=>{ 
                                                  if ( getState( State.id).val === null) setState( State.id, State.initial, true);
                                                  delete ownJsStates[ actStateName];
                                                  pushStates( ownJsStates, cb);
                                              }, 200)
                                          });
                                      }
                                      let ownJsStates = JSON.parse( JSON.stringify( JsStates));
                                      if ( Object.keys( ownJsStates).length === 0){
                                          cb && cb();
                                      } else {
                                          let ArrStateNames = Object.keys( ownJsStates);
                                          actStateName = ArrStateNames[0]
                                          State = ownJsStates[ actStateName];
                                          let exists = existsState( State.id);
                                          // Workaround needed if REDIS is used! createState() with initial value not possible!
                                          if ( exists && State.forceCreation){
                                              deleteState( State.id, ()=>{
                                                  create();
                                              });
                                          } else {
                                              create();
                                          }
                                      }
                                  }
                                  
                                  
                                  class Room {
                                      
                                      constructor( name, x, y, w, h, fill = defaultColorRooms) {
                                          this.name = name;
                                          this.x = x;
                                          this.y = y;
                                          this.w = w;
                                          this.h = h;
                                          this.fill = fill;
                                          this.svg = `<rect x="${this.x*svgScale}" y="${this.y*svgScale}" width="${this.w*svgScale}" height="${this.h*svgScale}" style="fill:none; stroke:${this.fill}; stroke-width:2" />`;
                                          // filled rect: `<rect x="${this.x}" y="${this.y}" width="${this.w}" height="${this.h}" style="fill:${this.fill}" />`
                                      }
                                  
                                      isInRoom( x, y){ return ( x >= this.x && x <= (this.x + this.w) && y >= this.y && y <= (this.y + this.h) ) }
                                  }
                                  
                                  
                                  class Scanner {
                                      constructor( name, x, y, fill = defaultColorScanner) {
                                          this.name = name;
                                          this.x = x;
                                          this.y = y;
                                          this.r = defaultRadiusScanner;
                                          this.fill = fill;
                                          this.svg = `
                                              <circle cx="${this.x*svgScale}" cy="${this.y*svgScale}" r="${this.r*svgScale}" fill=${this.fill} />
                                              <text x="${(this.x+this.r+5)*svgScale}" y="${(this.y+5)*svgScale}" stroke="${this.fill}" stroke-width="1" fill=none>${this.name}</text>
                                          `;
                                      }
                                  
                                      getCircle( r){
                                          return `<circle cx="${this.x*svgScale}" cy="${this.y*svgScale}" r="${r*svgScale}" stroke="${this.fill}" stroke-width="2" fill=none />`
                                      }
                                  }
                                  
                                  
                                  class Beacon {
                                      constructor( name, mqttId, svgBasic) {
                                          this.name = name;
                                          this.mqttId = mqttId;
                                          this.StateDef;
                                          this.svgBasic = svgBasic;
                                          this.svgScannerCircles = "";
                                          this.svgBeaconCircle = "";
                                  
                                          this.praefixStates = `${praefixStates}${this.name}.`;
                                          this.DetectedScanner = [];
                                          this._init();
                                      }
                                  
                                      _init(){
                                          this.StateDef = {
                                              VIS_HTML: {
                                                  id: "VIS_HTML",
                                                  initial: "",
                                                  forceCreation: false,
                                                  common: { role: "state", read: true, write: false, name: "IndoorPositioning.VIS_HTML", type: "string" },
                                                  native: {}
                                              },
                                              ROOM_DEFAULT: {  /** Copy for each defined Room */
                                                  id: "Rooms.",
                                                  initial: false,
                                                  forceCreation: false,
                                                  common: { role: "state", read: true, write: false, name: "Room Presence", type: "boolean" },
                                                  native: {}
                                              }
                                          };
                                  
                                          // Get all Rooom Names
                                          RoomDef.forEach( Room => {
                                              if ( !this.StateDef.hasOwnProperty( Room.name) ){
                                                  this.StateDef[ Room.name] = JSON.parse( JSON.stringify( this.StateDef[ "ROOM_DEFAULT"] ) ); // Copy ROOMS-DEFAULT to new Room state
                                                  this.StateDef[ Room.name].id = this.StateDef[ Room.name].id + Room.name;
                                              }
                                          });
                                          delete this.StateDef[ "ROOM_DEFAULT"];
                                  
                                          // Extend all IDs with own praefixStates
                                          Object.keys( this.StateDef).forEach( ele => {
                                              let completeID = `${this.praefixStates}${ this.StateDef[ ele].id}`;
                                              this.StateDef[ ele].id = completeID;
                                          });
                                  
                                          pushStates( this.StateDef, () => {
                                              if (dbglog()) console.log( `States created for Beacon "${this.name}"`);
                                              this._writeSVG();
                                              $( this.mqttId + ".*").each( (id, i) => { if ( id !== "undefined") this.DetectedScanner.push( id) });
                                              this._subscribeScanners();
                                          });
                                      }
                                  
                                      _subscribeScanners(){
                                          on({id: this.DetectedScanner, change: "ne"}, ( obj) => {
                                              this._processScans();
                                          });
                                      }
                                  
                                      _processScans(){
                                          // Get range circles from each scanner
                                          let ScanResults = {};
                                          this.svgScannerCircles = "";
                                          this.DetectedScanner.forEach( id => {
                                              let scannerName = id.split(".").pop();
                                              if ( ScannerDef.hasOwnProperty( scannerName) ) {
                                                  ScanResults[ scannerName] = JSON.parse( getState( id).val).distance * 100;
                                                  //ScanResults[ scannerName] = JSON.parse( getState( id).val).raw * 100;
                                                  this.svgScannerCircles = this.svgScannerCircles + InstJsScanner[ scannerName].getCircle( ScanResults[ scannerName]);
                                              } else {
                                                  console.log( `Scanner "${scannerName}" found in MQTT states "${this.mqttId}" but not defined in variable "ScannerDef". Define Scanner with X/Y coordinates and restart script!`)
                                              }
                                          });
                                  
                                          this._writeSVG();
                                          
                                          
                                      }
                                  
                                      _getRoomPresences( x, y){
                                          let presence = [];
                                          InstArrRooms.forEach( Room => {
                                              if (dbglog()) console.log( "Checking for Room: " + Room.name);
                                              if ( Room.isInRoom( x, y) && presence.indexOf( Room.name) !== -1 ) presence.push( Room.name);
                                          });
                                          return presence
                                      }
                                  
                                      _writeSVG(){
                                          let svg =  this.svgBasic + this.svgScannerCircles + this.svgBeaconCircle + "</svg>";
                                          this._write( "VIS_HTML", svg);
                                      }
                                  
                                      _write( jsKey, value, ack = true) {
                                          if (dbglog()) console.log(`Write state: ${this.StateDef[ jsKey].id} = ${ ( value === "" ? '' : value)} (ack = ${ack})`);
                                          setState( this.StateDef[ jsKey].id, value, ack);
                                      }
                                  }
                                  
                                  
                                  
                                  
                                  
                                  
                                  
                                  function main(){
                                  
                                      // Instantiate Rooms
                                      RoomDef.forEach( JsRoom => {
                                          if ( JsRoom.hasOwnProperty( "color") ) InstArrRooms.push( new Room( JsRoom.name, JsRoom.x, JsRoom.y, JsRoom.w, JsRoom.h, JsRoom.color) );
                                          else InstArrRooms.push( new Room( JsRoom.name, JsRoom.x, JsRoom.y, JsRoom.w, JsRoom.h) );
                                      });
                                      
                                      // Instantiate Scanner
                                      Object.keys( ScannerDef).forEach( scanner => {
                                          let Obj = ScannerDef[ scanner];
                                          if ( Obj.hasOwnProperty( "color") ) InstJsScanner[ scanner] = new Scanner( scanner, Obj.x, Obj.y, Obj.color);
                                          else InstJsScanner[ scanner] = new Scanner( scanner, Obj.x, Obj.y, Obj.color);
                                      })
                                  
                                      // Get Rooms SVG
                                      let svgH = 0;
                                      let svgW = 0;
                                      let svgRooms = "";
                                      InstArrRooms.forEach( Room => {
                                          if ( Room.x + Room.w > svgW) svgW = Room.x + Room.w;
                                          if ( Room.y + Room.h > svgH) svgH = Room.y + Room.h;
                                          svgRooms = svgRooms + Room.svg;
                                      });
                                  
                                      // Get Scanners SVG
                                      let svgScanner = "";
                                      Object.keys( InstJsScanner).forEach( Scanner => {
                                          svgScanner = svgScanner + InstJsScanner[ Scanner].svg;
                                      })
                                  
                                  
                                      let svgBasic = `
                                          <svg width="${svgW}" height="${svgH}" >
                                          ${svgRooms}
                                          ${svgScanner}
                                      `;
                                      // </svg> will be added when writing to state...
                                  
                                      Object.keys( BeaconDef).forEach( key => {
                                          InstArrBeacons.push( new Beacon( key, BeaconDef[ key], svgBasic ) )
                                      });
                                  
                                  }
                                  main();
                                  
                                  

                                  Erläuterungen zu euren EInstellungen:

                                  • svgScale
                                    Skalierung des SVG in eurer VIS

                                  • RoomDef
                                    Eure Räume mit den absolut Koordinaten in X und Y + deren Breite (w) und Höhe (h). Wichtig ist, dass ihr den Maßstab in cm verwendet. Ich habe für die Definition nur Räume als Rechtecke angenommen. Deshalb ist es möglich, Räume mit dem selben Namen zu unterteilen. Ich habe das bei mir im Beispiel mit "Flur" gemacht. Dieser ist eher L-förmig. Außerdem habe ich den Essbereich aus dem Wohnzimmer rausgeschnitten, daher so viele Aufteilungen.

                                  • ScannerDef
                                    Hier die einzelnen Scanner mit deren original Namen (espsense Namen!) inkl. deren Position angeben.

                                  • BeaconDef
                                    Hier die einzelnen Beacons o.ä. angeben mit den zugehörigen ioBroker IDs.

                                  Ich verwende den ioBroker mqtt-client Adapter. Hier muss natürlich "espresense/#" in die Subscribtions, damit der mqtt client auch auf die Daten der Scanner hört.

                                  Wenn ihr das Skript startet, werden für jeden einzelnen Beacon States erstellt. In meinem Beispiel sendet das MiBand gerade aktiv die BLE advertisements, daher habe ich diesen State in die VIS mit einem html Widget angezeigt.

                                  d4eb1359-d5dc-4de4-9b5d-a582f3f17f9e-image.png

                                  Die State-Gruppe "Rooms" war eine Vorbereitung für den nächsten Programmierschritt, wenn Triangulation implementiert wäre. Ist hier also noch ohne Funktion.

                                  1 Antwort Letzte Antwort
                                  0
                                  • G Offline
                                    G Offline
                                    GiuseppeS
                                    schrieb am zuletzt editiert von GiuseppeS
                                    #87

                                    Habe nun die Position eines Scanners verändert. Man sieht auch hier, dass eine minimale Abweichung schon dazu führt, dass ich nun ungefähr am Esstisch zu vermuten bin, statt im Gästezimmer...

                                    a92aded4-4eab-4823-ad1c-9d2178a8de88-image.png

                                    Meine Hoffnung basiert weiterhin auf UWB und deren Unterstützung mit Arduino-Hardware. Diese Code Basis könnte ich ja weiterhin nutzen, nur die Quelle der Scanner wäre ein anderer State. Es gibt bereits Scanner Hardware zu kaufen, alber die Sender sind das Problem. Diese Scanner funktionieren bisher nur untereinander, nicht mit AirTags o.ä.

                                    P.S.: Falls ihr keinen Grundriss der Wohnung habt, könnt ihr (wenn vorhanden) die Karte vom Roborock Staubsauger verwenden. Hatte sie so skaliert, dass es gut mit dem Umrechnen passt. Dann muss nicht alles händisch abgemessen werden.

                                    P.P.S.: Macht eure Versuche und schaut ob ihr mit den Daten der ESPs etwas anfangen könnt. Achtet auch ruhig darauf, wenn ihr schon mehrere verteilt habt, ob euer Standpunkt durch mehrere ESPs besser berechnet werden könnte. Dann würde ich das Thema Triangulation weiterführen bzw. im Forum nach einer JS Möglichkeit fragen, wie man "least-squares circle fit" umsetzen könnte. Ich bin aktuell nicht sehr optimistisch...

                                    M 1 Antwort Letzte Antwort
                                    0
                                    • M Offline
                                      M Offline
                                      Muchul
                                      schrieb am zuletzt editiert von Muchul
                                      #88

                                      Ich werde am Wochenende versuchen das Script zum laufen zu bringen und Berichten.

                                      1 Antwort Letzte Antwort
                                      0
                                      • M Offline
                                        M Offline
                                        Muchul
                                        schrieb am zuletzt editiert von
                                        #89

                                        Hallo @GiuseppeS

                                        soweit denke ich läuft das Script, jedenfalls gibt es keine Fehlermeldungen:

                                        Mein angepasstest Script:

                                        let svgScale = 0.4;
                                        
                                        /**
                                         * ##########################################################################################
                                         * Define your rooms. Coordinates starts at upper left corner...
                                         * 
                                         * Property key "color" is optional, e.g. { name: "Kueche", x: 0, y: 0, w: 360, h: 200, color: "red"},
                                         * Key "name" must contain only letters! No whitespaces and any special characters are allowed!
                                         * ##########################################################################################
                                         */
                                        
                                        let defaultColorRooms = "blue";
                                        let RoomDef = [
                                            { name: "Wohnzimmer",       x:   0, y:   0, w: 400, h: 584},
                                            { name: "Arbeitszimmer",    x: 441, y: 184, w: 250, h: 400},
                                            { name: "Umkleide",         x: 701, y: 184, w: 250, h: 400},
                                            { name: "Balkon",           x: 498, y:   0, w: 514, h: 156},
                                            { name: "Kabuff",           x: 832, y: 606, w: 120, h: 112},
                                            { name: "Flur",             x: 222, y: 606, w: 597, h: 112},
                                            { name: "Schlafzimmer",     x: 596, y: 736, w: 355, h: 449},
                                            { name: "Badezimmer",       x: 418, y: 736, w: 160, h: 449},
                                            { name: "GaesteWC",         x: 222, y: 736, w: 173, h: 132},
                                            { name: "Eingang",          x:   0, y: 606, w: 196, h: 265},
                                            { name: "Küche",            x:   0, y: 891, w: 390, h: 297}
                                        ];
                                        
                                        
                                        /**
                                         * ##########################################################################################
                                         * Define your scanner. Coordinates starts at upper left corner...
                                         * 
                                         * Property key "color" is optional, e.g. gast1: { x: 260, y: 230, color: "red"},
                                         * Key name must be same as configured in presense scanner!
                                         * ##########################################################################################
                                         */
                                        
                                        let defaultColorScanner = "white";
                                        let defaultRadiusScanner = 10;
                                        // Property key "color" is optional
                                        let ScannerDef = {
                                            kueche:       { x: 300, y: 1150},
                                        	wohnzimmer:    { x: 300, y: 300},
                                        	schlafzimmer:  { x: 900, y: 1140}, 
                                            umkleide:      { x: 900, y: 185}
                                        };
                                        
                                        /**
                                         * ##########################################################################################
                                         * Define your beacons. Coordinates starts at upper left corner...
                                         * 
                                         * ##########################################################################################
                                         */
                                        
                                        let defaultColorBeacon = "red";
                                        let BeaconDef = {
                                            SenerMiB: "mqtt-client.0.espresense.devices.mifit:dd498fe71f99",
                                            PerihanMiB:"mqtt-client.0.espresense.devices.mifit:c7e3c409ee00",
                                            SaziyeMiB: "mqtt-client.0.espresense.devices.mifit:e04c3be8e749"
                                        };
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        let praefixStates = `javascript.${instance}.IndoorPositioning.`;
                                        
                                        function dbglog(){
                                            return false
                                        }
                                        
                                        let InstArrRooms = [];
                                        let InstJsScanner = {};
                                        let InstArrBeacons = [];
                                        
                                        
                                        function pushStates( JsStates, cb) {
                                            let actStateName, State;
                                            let create = () => {
                                                createState( State.id, State.common, State.native, () => {
                                                    setTimeout( ()=>{ 
                                                        if ( getState( State.id).val === null) setState( State.id, State.initial, true);
                                                        delete ownJsStates[ actStateName];
                                                        pushStates( ownJsStates, cb);
                                                    }, 200)
                                                });
                                            }
                                            let ownJsStates = JSON.parse( JSON.stringify( JsStates));
                                            if ( Object.keys( ownJsStates).length === 0){
                                                cb && cb();
                                            } else {
                                                let ArrStateNames = Object.keys( ownJsStates);
                                                actStateName = ArrStateNames[0]
                                                State = ownJsStates[ actStateName];
                                                let exists = existsState( State.id);
                                                // Workaround needed if REDIS is used! createState() with initial value not possible!
                                                if ( exists && State.forceCreation){
                                                    deleteState( State.id, ()=>{
                                                        create();
                                                    });
                                                } else {
                                                    create();
                                                }
                                            }
                                        }
                                        
                                        
                                        class Room {
                                            
                                            constructor( name, x, y, w, h, fill = defaultColorRooms) {
                                                this.name = name;
                                                this.x = x;
                                                this.y = y;
                                                this.w = w;
                                                this.h = h;
                                                this.fill = fill;
                                                this.svg = `<rect x="${this.x*svgScale}" y="${this.y*svgScale}" width="${this.w*svgScale}" height="${this.h*svgScale}" style="fill:none; stroke:${this.fill}; stroke-width:2" />`;
                                                // filled rect: `<rect x="${this.x}" y="${this.y}" width="${this.w}" height="${this.h}" style="fill:${this.fill}" />`
                                            }
                                        
                                            isInRoom( x, y){ return ( x >= this.x && x <= (this.x + this.w) && y >= this.y && y <= (this.y + this.h) ) }
                                        }
                                        
                                        
                                        class Scanner {
                                            constructor( name, x, y, fill = defaultColorScanner) {
                                                this.name = name;
                                                this.x = x;
                                                this.y = y;
                                                this.r = defaultRadiusScanner;
                                                this.fill = fill;
                                                this.svg = `
                                                    <circle cx="${this.x*svgScale}" cy="${this.y*svgScale}" r="${this.r*svgScale}" fill=${this.fill} />
                                                    <text x="${(this.x+this.r+5)*svgScale}" y="${(this.y+5)*svgScale}" stroke="${this.fill}" stroke-width="1" fill=none>${this.name}</text>
                                                `;
                                            }
                                        
                                            getCircle( r){
                                                return `<circle cx="${this.x*svgScale}" cy="${this.y*svgScale}" r="${r*svgScale}" stroke="${this.fill}" stroke-width="2" fill=none />`
                                            }
                                        }
                                        
                                        
                                        class Beacon {
                                            constructor( name, mqttId, svgBasic) {
                                                this.name = name;
                                                this.mqttId = mqttId;
                                                this.StateDef;
                                                this.svgBasic = svgBasic;
                                                this.svgScannerCircles = "";
                                                this.svgBeaconCircle = "";
                                        
                                                this.praefixStates = `${praefixStates}${this.name}.`;
                                                this.DetectedScanner = [];
                                                this._init();
                                            }
                                        
                                            _init(){
                                                this.StateDef = {
                                                    VIS_HTML: {
                                                        id: "VIS_HTML",
                                                        initial: "",
                                                        forceCreation: false,
                                                        common: { role: "state", read: true, write: false, name: "IndoorPositioning.VIS_HTML", type: "string" },
                                                        native: {}
                                                    },
                                                    ROOM_DEFAULT: {  /** Copy for each defined Room */
                                                        id: "Rooms.",
                                                        initial: false,
                                                        forceCreation: false,
                                                        common: { role: "state", read: true, write: false, name: "Room Presence", type: "boolean" },
                                                        native: {}
                                                    }
                                                };
                                        
                                                // Get all Rooom Names
                                                RoomDef.forEach( Room => {
                                                    if ( !this.StateDef.hasOwnProperty( Room.name) ){
                                                        this.StateDef[ Room.name] = JSON.parse( JSON.stringify( this.StateDef[ "ROOM_DEFAULT"] ) ); // Copy ROOMS-DEFAULT to new Room state
                                                        this.StateDef[ Room.name].id = this.StateDef[ Room.name].id + Room.name;
                                                    }
                                                });
                                                delete this.StateDef[ "ROOM_DEFAULT"];
                                        
                                                // Extend all IDs with own praefixStates
                                                Object.keys( this.StateDef).forEach( ele => {
                                                    let completeID = `${this.praefixStates}${ this.StateDef[ ele].id}`;
                                                    this.StateDef[ ele].id = completeID;
                                                });
                                        
                                                pushStates( this.StateDef, () => {
                                                    if (dbglog()) console.log( `States created for Beacon "${this.name}"`);
                                                    this._writeSVG();
                                                    $( this.mqttId + ".*").each( (id, i) => { if ( id !== "undefined") this.DetectedScanner.push( id) });
                                                    this._subscribeScanners();
                                                });
                                            }
                                        
                                            _subscribeScanners(){
                                                on({id: this.DetectedScanner, change: "ne"}, ( obj) => {
                                                    this._processScans();
                                                });
                                            }
                                        
                                            _processScans(){
                                                // Get range circles from each scanner
                                                let ScanResults = {};
                                                this.svgScannerCircles = "";
                                                this.DetectedScanner.forEach( id => {
                                                    let scannerName = id.split(".").pop();
                                                    if ( ScannerDef.hasOwnProperty( scannerName) ) {
                                                        ScanResults[ scannerName] = JSON.parse( getState( id).val).distance * 100;
                                                        //ScanResults[ scannerName] = JSON.parse( getState( id).val).raw * 100;
                                                        this.svgScannerCircles = this.svgScannerCircles + InstJsScanner[ scannerName].getCircle( ScanResults[ scannerName]);
                                                    } else {
                                                        console.log( `Scanner "${scannerName}" found in MQTT states "${this.mqttId}" but not defined in variable "ScannerDef". Define Scanner with X/Y coordinates and restart script!`)
                                                    }
                                                });
                                        
                                                this._writeSVG();
                                                
                                                
                                            }
                                        
                                            _getRoomPresences( x, y){
                                                let presence = [];
                                                InstArrRooms.forEach( Room => {
                                                    if (dbglog()) console.log( "Checking for Room: " + Room.name);
                                                    if ( Room.isInRoom( x, y) && presence.indexOf( Room.name) !== -1 ) presence.push( Room.name);
                                                });
                                                return presence
                                            }
                                        
                                            _writeSVG(){
                                                let svg =  this.svgBasic + this.svgScannerCircles + this.svgBeaconCircle + "</svg>";
                                                this._write( "VIS_HTML", svg);
                                            }
                                        
                                            _write( jsKey, value, ack = true) {
                                                if (dbglog()) console.log(`Write state: ${this.StateDef[ jsKey].id} = ${ ( value === "" ? '' : value)} (ack = ${ack})`);
                                                setState( this.StateDef[ jsKey].id, value, ack);
                                            }
                                        }
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        function main(){
                                        
                                            // Instantiate Rooms
                                            RoomDef.forEach( JsRoom => {
                                                if ( JsRoom.hasOwnProperty( "color") ) InstArrRooms.push( new Room( JsRoom.name, JsRoom.x, JsRoom.y, JsRoom.w, JsRoom.h, JsRoom.color) );
                                                else InstArrRooms.push( new Room( JsRoom.name, JsRoom.x, JsRoom.y, JsRoom.w, JsRoom.h) );
                                            });
                                            
                                            // Instantiate Scanner
                                            Object.keys( ScannerDef).forEach( scanner => {
                                                let Obj = ScannerDef[ scanner];
                                                if ( Obj.hasOwnProperty( "color") ) InstJsScanner[ scanner] = new Scanner( scanner, Obj.x, Obj.y, Obj.color);
                                                else InstJsScanner[ scanner] = new Scanner( scanner, Obj.x, Obj.y, Obj.color);
                                            })
                                        
                                            // Get Rooms SVG
                                            let svgH = 0;
                                            let svgW = 0;
                                            let svgRooms = "";
                                            InstArrRooms.forEach( Room => {
                                                if ( Room.x + Room.w > svgW) svgW = Room.x + Room.w;
                                                if ( Room.y + Room.h > svgH) svgH = Room.y + Room.h;
                                                svgRooms = svgRooms + Room.svg;
                                            });
                                        
                                            // Get Scanners SVG
                                            let svgScanner = "";
                                            Object.keys( InstJsScanner).forEach( Scanner => {
                                                svgScanner = svgScanner + InstJsScanner[ Scanner].svg;
                                            })
                                        
                                        
                                            let svgBasic = `
                                                <svg width="${svgW}" height="${svgH}" >
                                                ${svgRooms}
                                                ${svgScanner}
                                            `;
                                            // </svg> will be added when writing to state...
                                        
                                            Object.keys( BeaconDef).forEach( key => {
                                                InstArrBeacons.push( new Beacon( key, BeaconDef[ key], svgBasic ) )
                                            });
                                        
                                        }
                                        main();
                                        
                                        

                                        Es wurden auch Datenpunkte angelegt:

                                        f303c55c-a572-44b6-82e9-4907bedfc0b9-image.png

                                        Habe erst mal den ganzen Morgen mit dem Grundriss verbracht :-)

                                        Hätte zwei Fragen, falls du mich supporten magst:

                                        1. ist das normal das da in der Zeile Room Presence false steht, bzw. wofür ist das? ich sitze hier gerade im Wonzimmer, und der Scanner meldet ja das er mich sieht:
                                          a67774f5-741e-4b7a-8e7a-7a263fc272b8-image.png

                                        Bin leider völlig unbedarft was das VIS angeht, kannst du mir bitte beschreiben, wie ich das in der VIS angezeigt bekomme?

                                        G 1 Antwort Letzte Antwort
                                        0
                                        • M Muchul

                                          Hallo @GiuseppeS

                                          soweit denke ich läuft das Script, jedenfalls gibt es keine Fehlermeldungen:

                                          Mein angepasstest Script:

                                          let svgScale = 0.4;
                                          
                                          /**
                                           * ##########################################################################################
                                           * Define your rooms. Coordinates starts at upper left corner...
                                           * 
                                           * Property key "color" is optional, e.g. { name: "Kueche", x: 0, y: 0, w: 360, h: 200, color: "red"},
                                           * Key "name" must contain only letters! No whitespaces and any special characters are allowed!
                                           * ##########################################################################################
                                           */
                                          
                                          let defaultColorRooms = "blue";
                                          let RoomDef = [
                                              { name: "Wohnzimmer",       x:   0, y:   0, w: 400, h: 584},
                                              { name: "Arbeitszimmer",    x: 441, y: 184, w: 250, h: 400},
                                              { name: "Umkleide",         x: 701, y: 184, w: 250, h: 400},
                                              { name: "Balkon",           x: 498, y:   0, w: 514, h: 156},
                                              { name: "Kabuff",           x: 832, y: 606, w: 120, h: 112},
                                              { name: "Flur",             x: 222, y: 606, w: 597, h: 112},
                                              { name: "Schlafzimmer",     x: 596, y: 736, w: 355, h: 449},
                                              { name: "Badezimmer",       x: 418, y: 736, w: 160, h: 449},
                                              { name: "GaesteWC",         x: 222, y: 736, w: 173, h: 132},
                                              { name: "Eingang",          x:   0, y: 606, w: 196, h: 265},
                                              { name: "Küche",            x:   0, y: 891, w: 390, h: 297}
                                          ];
                                          
                                          
                                          /**
                                           * ##########################################################################################
                                           * Define your scanner. Coordinates starts at upper left corner...
                                           * 
                                           * Property key "color" is optional, e.g. gast1: { x: 260, y: 230, color: "red"},
                                           * Key name must be same as configured in presense scanner!
                                           * ##########################################################################################
                                           */
                                          
                                          let defaultColorScanner = "white";
                                          let defaultRadiusScanner = 10;
                                          // Property key "color" is optional
                                          let ScannerDef = {
                                              kueche:       { x: 300, y: 1150},
                                          	wohnzimmer:    { x: 300, y: 300},
                                          	schlafzimmer:  { x: 900, y: 1140}, 
                                              umkleide:      { x: 900, y: 185}
                                          };
                                          
                                          /**
                                           * ##########################################################################################
                                           * Define your beacons. Coordinates starts at upper left corner...
                                           * 
                                           * ##########################################################################################
                                           */
                                          
                                          let defaultColorBeacon = "red";
                                          let BeaconDef = {
                                              SenerMiB: "mqtt-client.0.espresense.devices.mifit:dd498fe71f99",
                                              PerihanMiB:"mqtt-client.0.espresense.devices.mifit:c7e3c409ee00",
                                              SaziyeMiB: "mqtt-client.0.espresense.devices.mifit:e04c3be8e749"
                                          };
                                          
                                          
                                          
                                          
                                          
                                          
                                          
                                          let praefixStates = `javascript.${instance}.IndoorPositioning.`;
                                          
                                          function dbglog(){
                                              return false
                                          }
                                          
                                          let InstArrRooms = [];
                                          let InstJsScanner = {};
                                          let InstArrBeacons = [];
                                          
                                          
                                          function pushStates( JsStates, cb) {
                                              let actStateName, State;
                                              let create = () => {
                                                  createState( State.id, State.common, State.native, () => {
                                                      setTimeout( ()=>{ 
                                                          if ( getState( State.id).val === null) setState( State.id, State.initial, true);
                                                          delete ownJsStates[ actStateName];
                                                          pushStates( ownJsStates, cb);
                                                      }, 200)
                                                  });
                                              }
                                              let ownJsStates = JSON.parse( JSON.stringify( JsStates));
                                              if ( Object.keys( ownJsStates).length === 0){
                                                  cb && cb();
                                              } else {
                                                  let ArrStateNames = Object.keys( ownJsStates);
                                                  actStateName = ArrStateNames[0]
                                                  State = ownJsStates[ actStateName];
                                                  let exists = existsState( State.id);
                                                  // Workaround needed if REDIS is used! createState() with initial value not possible!
                                                  if ( exists && State.forceCreation){
                                                      deleteState( State.id, ()=>{
                                                          create();
                                                      });
                                                  } else {
                                                      create();
                                                  }
                                              }
                                          }
                                          
                                          
                                          class Room {
                                              
                                              constructor( name, x, y, w, h, fill = defaultColorRooms) {
                                                  this.name = name;
                                                  this.x = x;
                                                  this.y = y;
                                                  this.w = w;
                                                  this.h = h;
                                                  this.fill = fill;
                                                  this.svg = `<rect x="${this.x*svgScale}" y="${this.y*svgScale}" width="${this.w*svgScale}" height="${this.h*svgScale}" style="fill:none; stroke:${this.fill}; stroke-width:2" />`;
                                                  // filled rect: `<rect x="${this.x}" y="${this.y}" width="${this.w}" height="${this.h}" style="fill:${this.fill}" />`
                                              }
                                          
                                              isInRoom( x, y){ return ( x >= this.x && x <= (this.x + this.w) && y >= this.y && y <= (this.y + this.h) ) }
                                          }
                                          
                                          
                                          class Scanner {
                                              constructor( name, x, y, fill = defaultColorScanner) {
                                                  this.name = name;
                                                  this.x = x;
                                                  this.y = y;
                                                  this.r = defaultRadiusScanner;
                                                  this.fill = fill;
                                                  this.svg = `
                                                      <circle cx="${this.x*svgScale}" cy="${this.y*svgScale}" r="${this.r*svgScale}" fill=${this.fill} />
                                                      <text x="${(this.x+this.r+5)*svgScale}" y="${(this.y+5)*svgScale}" stroke="${this.fill}" stroke-width="1" fill=none>${this.name}</text>
                                                  `;
                                              }
                                          
                                              getCircle( r){
                                                  return `<circle cx="${this.x*svgScale}" cy="${this.y*svgScale}" r="${r*svgScale}" stroke="${this.fill}" stroke-width="2" fill=none />`
                                              }
                                          }
                                          
                                          
                                          class Beacon {
                                              constructor( name, mqttId, svgBasic) {
                                                  this.name = name;
                                                  this.mqttId = mqttId;
                                                  this.StateDef;
                                                  this.svgBasic = svgBasic;
                                                  this.svgScannerCircles = "";
                                                  this.svgBeaconCircle = "";
                                          
                                                  this.praefixStates = `${praefixStates}${this.name}.`;
                                                  this.DetectedScanner = [];
                                                  this._init();
                                              }
                                          
                                              _init(){
                                                  this.StateDef = {
                                                      VIS_HTML: {
                                                          id: "VIS_HTML",
                                                          initial: "",
                                                          forceCreation: false,
                                                          common: { role: "state", read: true, write: false, name: "IndoorPositioning.VIS_HTML", type: "string" },
                                                          native: {}
                                                      },
                                                      ROOM_DEFAULT: {  /** Copy for each defined Room */
                                                          id: "Rooms.",
                                                          initial: false,
                                                          forceCreation: false,
                                                          common: { role: "state", read: true, write: false, name: "Room Presence", type: "boolean" },
                                                          native: {}
                                                      }
                                                  };
                                          
                                                  // Get all Rooom Names
                                                  RoomDef.forEach( Room => {
                                                      if ( !this.StateDef.hasOwnProperty( Room.name) ){
                                                          this.StateDef[ Room.name] = JSON.parse( JSON.stringify( this.StateDef[ "ROOM_DEFAULT"] ) ); // Copy ROOMS-DEFAULT to new Room state
                                                          this.StateDef[ Room.name].id = this.StateDef[ Room.name].id + Room.name;
                                                      }
                                                  });
                                                  delete this.StateDef[ "ROOM_DEFAULT"];
                                          
                                                  // Extend all IDs with own praefixStates
                                                  Object.keys( this.StateDef).forEach( ele => {
                                                      let completeID = `${this.praefixStates}${ this.StateDef[ ele].id}`;
                                                      this.StateDef[ ele].id = completeID;
                                                  });
                                          
                                                  pushStates( this.StateDef, () => {
                                                      if (dbglog()) console.log( `States created for Beacon "${this.name}"`);
                                                      this._writeSVG();
                                                      $( this.mqttId + ".*").each( (id, i) => { if ( id !== "undefined") this.DetectedScanner.push( id) });
                                                      this._subscribeScanners();
                                                  });
                                              }
                                          
                                              _subscribeScanners(){
                                                  on({id: this.DetectedScanner, change: "ne"}, ( obj) => {
                                                      this._processScans();
                                                  });
                                              }
                                          
                                              _processScans(){
                                                  // Get range circles from each scanner
                                                  let ScanResults = {};
                                                  this.svgScannerCircles = "";
                                                  this.DetectedScanner.forEach( id => {
                                                      let scannerName = id.split(".").pop();
                                                      if ( ScannerDef.hasOwnProperty( scannerName) ) {
                                                          ScanResults[ scannerName] = JSON.parse( getState( id).val).distance * 100;
                                                          //ScanResults[ scannerName] = JSON.parse( getState( id).val).raw * 100;
                                                          this.svgScannerCircles = this.svgScannerCircles + InstJsScanner[ scannerName].getCircle( ScanResults[ scannerName]);
                                                      } else {
                                                          console.log( `Scanner "${scannerName}" found in MQTT states "${this.mqttId}" but not defined in variable "ScannerDef". Define Scanner with X/Y coordinates and restart script!`)
                                                      }
                                                  });
                                          
                                                  this._writeSVG();
                                                  
                                                  
                                              }
                                          
                                              _getRoomPresences( x, y){
                                                  let presence = [];
                                                  InstArrRooms.forEach( Room => {
                                                      if (dbglog()) console.log( "Checking for Room: " + Room.name);
                                                      if ( Room.isInRoom( x, y) && presence.indexOf( Room.name) !== -1 ) presence.push( Room.name);
                                                  });
                                                  return presence
                                              }
                                          
                                              _writeSVG(){
                                                  let svg =  this.svgBasic + this.svgScannerCircles + this.svgBeaconCircle + "</svg>";
                                                  this._write( "VIS_HTML", svg);
                                              }
                                          
                                              _write( jsKey, value, ack = true) {
                                                  if (dbglog()) console.log(`Write state: ${this.StateDef[ jsKey].id} = ${ ( value === "" ? '' : value)} (ack = ${ack})`);
                                                  setState( this.StateDef[ jsKey].id, value, ack);
                                              }
                                          }
                                          
                                          
                                          
                                          
                                          
                                          
                                          
                                          function main(){
                                          
                                              // Instantiate Rooms
                                              RoomDef.forEach( JsRoom => {
                                                  if ( JsRoom.hasOwnProperty( "color") ) InstArrRooms.push( new Room( JsRoom.name, JsRoom.x, JsRoom.y, JsRoom.w, JsRoom.h, JsRoom.color) );
                                                  else InstArrRooms.push( new Room( JsRoom.name, JsRoom.x, JsRoom.y, JsRoom.w, JsRoom.h) );
                                              });
                                              
                                              // Instantiate Scanner
                                              Object.keys( ScannerDef).forEach( scanner => {
                                                  let Obj = ScannerDef[ scanner];
                                                  if ( Obj.hasOwnProperty( "color") ) InstJsScanner[ scanner] = new Scanner( scanner, Obj.x, Obj.y, Obj.color);
                                                  else InstJsScanner[ scanner] = new Scanner( scanner, Obj.x, Obj.y, Obj.color);
                                              })
                                          
                                              // Get Rooms SVG
                                              let svgH = 0;
                                              let svgW = 0;
                                              let svgRooms = "";
                                              InstArrRooms.forEach( Room => {
                                                  if ( Room.x + Room.w > svgW) svgW = Room.x + Room.w;
                                                  if ( Room.y + Room.h > svgH) svgH = Room.y + Room.h;
                                                  svgRooms = svgRooms + Room.svg;
                                              });
                                          
                                              // Get Scanners SVG
                                              let svgScanner = "";
                                              Object.keys( InstJsScanner).forEach( Scanner => {
                                                  svgScanner = svgScanner + InstJsScanner[ Scanner].svg;
                                              })
                                          
                                          
                                              let svgBasic = `
                                                  <svg width="${svgW}" height="${svgH}" >
                                                  ${svgRooms}
                                                  ${svgScanner}
                                              `;
                                              // </svg> will be added when writing to state...
                                          
                                              Object.keys( BeaconDef).forEach( key => {
                                                  InstArrBeacons.push( new Beacon( key, BeaconDef[ key], svgBasic ) )
                                              });
                                          
                                          }
                                          main();
                                          
                                          

                                          Es wurden auch Datenpunkte angelegt:

                                          f303c55c-a572-44b6-82e9-4907bedfc0b9-image.png

                                          Habe erst mal den ganzen Morgen mit dem Grundriss verbracht :-)

                                          Hätte zwei Fragen, falls du mich supporten magst:

                                          1. ist das normal das da in der Zeile Room Presence false steht, bzw. wofür ist das? ich sitze hier gerade im Wonzimmer, und der Scanner meldet ja das er mich sieht:
                                            a67774f5-741e-4b7a-8e7a-7a263fc272b8-image.png

                                          Bin leider völlig unbedarft was das VIS angeht, kannst du mir bitte beschreiben, wie ich das in der VIS angezeigt bekomme?

                                          G Offline
                                          G Offline
                                          GiuseppeS
                                          schrieb am zuletzt editiert von
                                          #90

                                          @muchul
                                          Ja, das Thema Grundriss nimmt zunächst viel Zeit in Anspruch, allerdings ist mir kein einfacheres Verfahren bekannt. Leider.

                                          Die Datenpunkte unter Rooms müssten für jeden Raum erstellt werden. Dies war nur eine Vorbereitung und ist aktuell ohne Funktion. Es wird aktuell immer false angezeigt. Wenn die Triangulation integriert ist, sollte hier der Raum auf true gehen, wo sich das entsprechende Beacon befindet. Eigentlich sollten bei dir alle Räume hier sichtbar sein, nicht nur Wohnzimmer.

                                          Zur VIS:
                                          Direkt unter dem Beacon sollte ein Objekt mit dem Namen "VIS_HTML" existieren. Wenn du dieses Objekt nicht siehst, einmal die Seite im Browser komplett neu laden.
                                          In der VIS positionierst du ein html Widget. Empfehle hier einfach ein neues view zu erstellen und hier das neue HTML widget hinzuzufügen. Im html Code gibst du den VIS_HTML Datenpunkt innerhalb geschweifter Klammern an, z.B.:
                                          {javascript.1.IndoorPositioning.MiFit.VIS_HTML}

                                          Du kannst dieses view direkt unabhängig von der restlichen VIS anzeigen lassen, indem Du oben rechts beim VIS Editor auf das Play-Symbol klickst.
                                          Wenn Du alles korrekt konfiguriert hast, sollte eine Anzeige wie bei mir im Beispiel erscheinen

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


                                          Support us

                                          ioBroker
                                          Community Adapters
                                          Donate

                                          864

                                          Online

                                          32.4k

                                          Benutzer

                                          81.5k

                                          Themen

                                          1.3m

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

                                          • Du hast noch kein Konto? Registrieren

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