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

Zum Thema Aussperrschutz habe ich mir mal Folgendes eingerichtet:

  • Über unserem Außenwasserhahn habe ich in einen AP-Taster einen Aqara-Fensterkontakt eingebaut
    • damit wird normalerweise das Sonoff Wasserventil im Keller geschaltet
  • diesen Taster habe ich für eine weitere Automation verwendet
    • das Nuki an unserer Eingangstür kann mit unseren Handys geöffnet werden
    • da war es nur eine Frage der Zeit, wann mal die Tür zuschlägt und alle Handys im Haus liegen.
    • ein Keypad wollte ich nicht installieren
    • somit habe ich den Taster des Außenwasserhahns als „Morse-Taster“ zweckentfremdet.
    • in Node-RED habe ich einen Flow eingerichtet, welcher den Morsecode empfängt und verarbeitet.

  • wenn der Taster 1x lang - 3x kurz - 1x lang betätigt wird, schließt das Nuki die Tür auf.

  • da keiner weiß, was der Taster kann und auch den Code nicht kennt, ist die Missbrauchsgefahr relativ gering. Und ihr wisst nicht wo ich wohne, außerdem habe ich den Code für diesen Beitrag geändert. :innocent:

  • erfolglose Hack-Versuche werden an mein Handy gesendet und die Außenkamers zeichnet den ganzen Spaß auf.

EDIT: Aufgrund der vielen „Likes“ hier der Code für den Sequenz-Prüfer Function-Node

/**
 * 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;
11 „Gefällt mir“