[KW 50 / 25] : Was habt ihr diese Woche im Smart Home geplant / umgesetzt?

Nuki Smart Lock Go (2025)

  • Schließzylinder gewechselt

    • beim alten Zylinder konnten nicht gleichzeitig innen und außen Schlüssel stecken
  • Nuki installiert und mit der Handy-APP in Betrieb genommen.

  • Die Einrichtung bzw. MQTT-Integration in HA hat mir 2 Stolpersteine in den Weg gelegt.

    1. Da Matter bei mir (noch) keine Rolle spielt, wollte ich es mit MQTT einrichten. Ich bin es gewohnt, bei MQTT - Verbindungen die Port-Nummer :1883 anzugeben. Die wollte Nuki aber gar nicht wissen. Die Fehlermeldung der Handy-APP war zu allgemein, um es direkt zu erkennen.
    2. Für MQTT Benutzer und Passwort habe ich ein vorhandenes Konto verwendet. Das Passwort hat sehr viele Stellen. Nuki erlaubt aber nur 32. Da ich es mit Drag-and-Drop eingefügt habe, ist mir nicht aufgefallen, dass es abgeschnitten wird. Hat 'ne Weile gedauert, bis ich gemerkt habe was los ist. Ob es in der Anleitung steht, weiß ich nicht. Außer QR-Codes lese ich meistens nix. :innocent:
      In der App wird allerdings darauf hingewiesen, ein neues Konto zu verwenden, allerdings aus Sicherheitsgründen und nicht wegen der Stellenzahl.
  • Wie mein finales Setup mit Hilfe von Home Assistant und Node-RED aussehen wird, habe ich noch nicht zu Ende gedacht. Erstmal die Basics abklären.

  • Das Geofencing mit dem Auto-Unlock habe ich nicht aktiviert, da ich (fast) immer durch die Garage ins Haus komme.

  • Was mit HA schon gut funkioniert:

    • NFC-Tag in HA konfiguriert, automatisiert und neben die Haustür geklebt.

      • das klappt erfreulich gut. Handy entsperren, dran halten - Tür geht auf.
    • Morsetaster eingerichtet:

      • Das Keypad von Nuki war mir als Fallback-Lösung, falls man kein Handy in der Tasche hat, zu teuer.
      • Dafür habe ich einen Aufputz-Installationstaster aus meiner Heimwerkerkiste mit einem Aqara-Fenstersensor (7,-€ im 10er-Pack bei ALI) ausgerüstet und an unverfänglicher Stelle im Vorbau angebracht.
      • Mit diesem Taster kann man einen Morsecode eingeben.
      • zB. -…- (1 x lang, 3 x kurz, 1 x lang)
      • Da keiner weiß, wofür der Taster eigentlich da ist und auch den Code nicht kennt, halte ich die Sicherheit für ausreichend.
      • Das Timing der Kurz- Langimpulse ist in weiten Bereichen anpassbar und eigentlich intuitiv erlernbar.
      • Die Automation wurde in Node-RED programmiert.
      • den Sequenz-Prüfer für den Morsecode habe ich von der „Künstlichen Inkontinenz“ entwickeln lassen.
/**
 * Konfigurationsparameter
 */
const TARGET_CODE = '-...-'; // Zielcode: 1x Lang, 3x Kurz, 1x Lang
const BASE_UNIT = 400; // Basiseinheit in ms
const MAX_DURATION_DOT = BASE_UNIT * 2; // = 800ms. Alles unter diesem Wert ist ein Punkt (.).
const MAX_INACTIVITY_TIME = 3000; // Code wird nach 3 Sekunden Inaktivität gelöscht

// --- Context-Variablen ---
let startTime = context.get('startTime') || 0;
let currentCode = context.get('currentCode') || '';
let resetTimer = context.get('resetTimer') || null;

// 1. Eingangsdaten prüfen
if (typeof msg.payload !== 'string' || (msg.payload !== 'on' && msg.payload !== 'off')) {
    return null;
}

// HOLT DEN ZUSTAND DIREKT VOM PAYLOAD
const newState = msg.payload; 

// 2. Timer-Logik für Inaktivität (Code-Zurücksetzung)
if (resetTimer) {
    clearTimeout(resetTimer);
}
resetTimer = setTimeout(() => {
    if (currentCode.length > 0) {
        node.warn(`Code ${currentCode} durch Inaktivität zurückgesetzt.`);
        context.set('currentCode', '');
    }
    context.set('resetTimer', null);
}, MAX_INACTIVITY_TIME);
context.set('resetTimer', resetTimer);

// --- TASTER GEDRÜCKT (START der Messung: Wechsel auf 'off') ---
if (newState === 'off') {
    startTime = Date.now();
    context.set('startTime', startTime);
    node.status({ fill: "green", shape: "dot", text: "Warte auf Loslassen... (OFF erkannt)" });
    return null;
}

// --- TASTER LOSGELASSEN (ENDE der Messung: Wechsel auf 'on') ---
else if (newState === 'on' && startTime > 0) {
    const duration = Date.now() - startTime;
    startTime = 0; // Messung abgeschlossen
    
    let symbol = '';
    
    // Klassifizierung:
    if (duration < MAX_DURATION_DOT) {
        symbol = '.'; // Kurz = Punkt
    } else {
        symbol = '-'; // Lang = Strich
    }

    // 3. Sequenzprüfung
    const nextCharIndex = currentCode.length;
    
    if (TARGET_CODE[nextCharIndex] === symbol) {
        // Das Symbol ist korrekt für diese Position
        currentCode += symbol;
        
        if (currentCode === TARGET_CODE) {
            // **ERFOLG** - Gesamter Code eingegeben
            node.status({ fill: "blue", shape: "dot", text: `CODE ERKANNT: ${currentCode}` });
            currentCode = ''; // Code zurücksetzen für nächste Eingabe
            context.set('currentCode', currentCode);
            context.set('startTime', startTime);
            msg.payload = "SUCCESS";
            return msg;
        }
        
        // Teil-Erfolg, weiter warten
        node.status({ fill: "yellow", shape: "dot", text: `Aktuell: ${currentCode}` });
        
    } else {
        // Falsches Symbol an dieser Stelle: Code zurücksetzen
        node.status({ fill: "red", shape: "dot", text: `FEHLER. Erwartet: ${TARGET_CODE[nextCharIndex]}, Erhalten: ${symbol}` });
        node.warn(`Code ${currentCode} fehlerhaft. Wird zurückgesetzt.`);
        currentCode = '';
    }
    
    // 4. Kontext speichern
    context.set('startTime', startTime);
    context.set('currentCode', currentCode);
    return null;
}

// Andere Zustände ignorieren
return null;
1 „Gefällt mir“