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. Praktische Anwendungen (Showcase)
  4. Bluetooth LE Türsensor mit Puck.js

NEWS

  • Weihnachtsangebot 2025! 🎄
    BluefoxB
    Bluefox
    13
    1
    356

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

  • Monatsrückblick – September 2025
    BluefoxB
    Bluefox
    14
    1
    2.3k

Bluetooth LE Türsensor mit Puck.js

Geplant Angeheftet Gesperrt Verschoben Praktische Anwendungen (Showcase)
2 Beiträge 1 Kommentatoren 1.1k Aufrufe
  • Ä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.
  • AlCalzoneA Offline
    AlCalzoneA Offline
    AlCalzone
    Developer
    schrieb am zuletzt editiert von
    #1

    Mein aktuelles Miniprojekt ist jetzt vollendet, daher wollte ich es mal vorstellen.

    Um die Beleuchtung in meiner Abstellkammer (die ich gerne mal vergesse auszuschalten) zu automatisieren, habe ich mir mit https://www.espruino.com/PuckJS und https://www.amazon.de/gp/product/B00F0BTTBU einen (fast) kabellosen Türsensor gebaut. Wie das ganze aussieht, sieht man hier:
    1097_img_0944.jpg

    Die Reed-Kontakte haben den Vorteil, dass sie sowohl NC (normal geschlossen) als auch NO (normal geöffnet) betrieben werden können. Bei Verwendung von NO ist der interne Kontakt geöffnet bei angelegtem Magneten, d.h. es fließt im Normalfall kein Strom.

    Das Kabel für NO (braun) ist am Puck an Pin D2 angeschlossen, das gemeinsame Kabel (weiß) an Pin D1.

    Der Code auf dem Puck wird nur ausgeführt, wenn ein Schaltvorgang erkannt wird, sodass er möglichst wenig Strom verbraucht (ca. 25µA im geschlossenen Zustand laut Hersteller).

    Über den Stromverbrauch im offenen Zustand habe ich noch keine Info. Evtl. sollte man hier die DAC-Funktion des Pins verwenden, um den Kontakt mit geringerer Spannung zu betreiben, oder den NC-Kontakt mitverwenden und im Code intelligent zwischen den Inputs wechseln.

    ! ````
    NRF.setScanResponse([
    //0x02,
    //0x01,0x05, // flags
    5, // length (including type byte)
    0x09, // name
    'T', 'u', 'e', 'r'
    ]);
    ! function send(value) {
    NRF.setAdvertising({
    0xEFA1: [value]
    }, {showName: false});
    }
    ! // set D2 to output, D1 to input with pulldown
    pinMode(D2, "output");
    digitalWrite(D2, 1);
    pinMode(D1, "input_pulldown");
    ! // watch the input for changes
    let status = null;
    setWatch(function(e) {
    if (e.state && status != "open") {
    // magnet open
    status = "open";
    console.log(status);
    digitalPulse(LED2, 1, 500);
    send(1);
    } else if (!e.state && status != "closed") {
    // magnet closed
    status = "closed";
    console.log(status);
    digitalPulse(LED1, 1, 500);
    send(0);
    }
    }, D1, {
    repeat: true,
    debounce: 150
    });

    
    Details zum Code im Spoiler:
    
    >! Der erste Block gibt dem Puck einen kurzen Namen und kann angepasst werden, sollte aber kurz bleiben, damit das Advertising noch funktioniert (die Datenmenge ist stark begrenzt).
    >! In der Funktion send wird der aktuelle Zustand des Kontakts (0 oder 1) auf dem Service 0xEFA1 bekanntgegeben. Die ID kann angepasst werden (sollte laut Spec eigentlich eine UUID sein, das ist mir zuhause aber egal), und muss im Script auf dem ioBroker ebenfalls eingetragen werden.
    >! Pin D2 wird als output festgelegt und auf den Status 1 gesetzt (d.h. hier liegen 3,3V an).
    >! Pin D1 ist ein input mit Pulldown-Widerstand, sodass bei geöffnetem Kontakt (Tür zu) der Sensorwert zu 0 definiert ist und nicht springt.
    >! Im Folgenden wird der Input-Pin überwacht und bei Änderungen kurz geblinkt (grün bei offener Tür, rot bei geschlossener) sowie die Bluetooth-Daten aktualisiert.
    
    Auf dem ioBroker läuft ein Skript, das per Bluetooth auf Advertising-Daten lauscht und diese als States anlegt:
    
    >! ````
    // Hier die BLE-Services eintragen, für die States angelegt werden sollen. 
    // Als HEX-strings, in Kleinbuchstaben und ohne führendes 0x
    const services = [
        "efa1"              // puck.js magnetometer proximity detection
    ];
    >! // =========================
    >! function updateState(stateId, value, ack) {
        const val = getState(stateId).val;
        if (val == null) {
            createState(stateId, value);
        } else if (val != value) {
            setState(stateId, value, ack);
        }
    }
    >! const noble = require("noble");
    >! const onDiscover = (p) => {
        if (!(p && p.advertisement && p.advertisement.serviceData)) return;
        const stateId_name = `BLE.${p.address}.name`;
        createState(`BLE.${p.address}.name`, p.advertisement.localName);
        for (let entry of p.advertisement.serviceData) {
            const uuid = entry.uuid;
            let data = entry.data;
            if (data.type === "Buffer") {
                data = Buffer.from(data.data);
            }
            if (data.length === 1) {
                // single byte
                data = data[0];
            } else { // not supported yet
                continue;
            }
    
            updateState(`BLE.${p.address}.${uuid}`, data, true);
        }
    };
    >! let isScanning = false;
    function startScanning() {
        if (isScanning) return;
        noble.on("discover", onDiscover);
        noble.startScanning(services, true);
        isScanning = true;
    }
    function stopScanning() {
        if (!isScanning) return;
        noble.removeAllListeners("discover");
        noble.stopScanning();
        isScanning = false;
    }
    >! noble.on("stateChange", (state) => {
        switch (state) {
            case "poweredOn":
                startScanning();
                break;
            case "poweredOff":
                stopScanning();
                break;
        }
    });
    if (noble.state === "poweredOn") startScanning();
    >! onStop((callback) => {
        stopScanning();
        noble.removeAllListeners("stateChange");
        if (callback) callback();
    }, 2000);
    

    Sollte auf dem Puck der Code des BLE-Service geändert worden sein, muss das hier bei services eingetragen werden.

    Warum `sudo` böse ist: https://forum.iobroker.net/post/17109

    1 Antwort Letzte Antwort
    0
    • AlCalzoneA Offline
      AlCalzoneA Offline
      AlCalzone
      Developer
      schrieb am zuletzt editiert von
      #2

      Kleines Update:

      Ich habe mich nochmal mit der Firmware und der Verkabelung beschäftigt.

      Neue Verkabelung:

      NC (grau) => D29 (output)

      NO (braun) => D2 (output)

      COM (weiß) => D1 (input)

      Um dauerhaften Stromfluss zu verhindern, liegt Spannung jetzt entweder an NC (D29) oder NO (D2) an. Der Pin wird so ausgewählt, dass kein Strom fließt.

      Wenn sich der Zustand des Magnetkontakts ändert, fließt kurzzeitig Strom. Der Puck reagiert das und vertauscht die Polung.

      Neue Firmware für den Puck:

      ! ````
      NRF.setScanResponse([
      //0x02,
      //0x01,0x05, // flags
      5, // length (including type byte)
      0x09, // name
      'T', 'u', 'e', 'r'
      ]);
      ! const advertisingData = {
      0xEFA1: [0], // magnet sensor
      0x180F: [Puck.getBatteryPercentage()], // battery
      };
      ! function send(value) {
      advertisingData[0xEFA1] = [value];
      NRF.setAdvertising(advertisingData, {showName: false});
      }
      ! // ^^^ BLUETOOTH ^^^
      // =================================
      // vvv SENSOR CODE vvv
      ! const pinNC = D29;
      const pinNO = D2;
      const pinCOM = D1;
      ! const HIGH = 1;
      const LOW = 0;
      ! let circuit = "NO";
      let rawState = null;
      let bluetoothState = null; // the state reported over bluetooth
      ! function writeNO() {
      digitalWrite(pinNO, HIGH);
      digitalWrite(pinNC, LOW);
      circuit = "NO";
      console.log("using NO circuit");
      }
      function writeNC() {
      digitalWrite(pinNC, HIGH);
      digitalWrite(pinNO, LOW);
      circuit = "NC";
      console.log("using NC circuit");
      }
      ! function parseState(valCOM) {
      valCOM = valCOM || digitalRead(pinCOM) === 1;
      if (circuit === "NO") {
      // when the NO circuit is used, valCOM is true when the door is open
      rawState = valCOM ? "open" : "closed";
      } else {
      // when the NC circuit is used, valCOM is true when the door is closed
      rawState = valCOM ? "closed" : "open";
      }
      ! return rawState;
      }
      ! function isConducting() {
      console.log(checking for conductance: circuit=${circuit}, rawState=${rawState});
      if (circuit === "NO" /* NO / && rawState === "open" / open /) return true;
      if (circuit === "NC" /
      NC / && rawState === "closed" / closed /) return true;
      return false;
      }
      ! function switchCircuit() {
      console.log("switching circuit");
      if (circuit === "NO") { // NO
      writeNC();
      } else { // NC
      writeNO();
      }
      }
      ! // set NC and NO pin to output, COM pin to input with pulldown
      pinMode(pinNC, "output");
      pinMode(pinNO, "output");
      pinMode(pinCOM, "input_pulldown");
      ! function onChange(e) {
      // parse the state depending on the current circuit;
      parseState(e.state);
      console.log("pin state changed: " + rawState);
      // switch circuit if neccessary
      if (isConducting()) switchCircuit();
      ! // do the switch stuff
      if (rawState == "open" && bluetoothState != "open") {
      // magnet open
      bluetoothState = "open";
      console.log(bluetoothState);
      digitalPulse(LED2, 1, 500);
      send(1);
      } else if (rawState == "closed" && bluetoothState != "closed") {
      // magnet closed
      bluetoothState = "closed";
      console.log(bluetoothState);
      digitalPulse(LED1, 1, 500);
      send(0);
      }
      }
      ! // watch the input for changes
      setWatch(onChange, pinCOM, {
      repeat: true,
      debounce: 150
      });
      // also update the battery level every hour
      setInterval(() => {
      advertisingData[0x180F] = [Puck.getBatteryPercentage()];
      send();
      }, 3600
      1000);
      ! // initially try to close the NO circuit
      writeNO();
      onChange({
      state: digitalRead(pinCOM) === 1
      });

      Warum `sudo` böse ist: https://forum.iobroker.net/post/17109

      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

      364

      Online

      32.5k

      Benutzer

      81.6k

      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