🧩Skripte: JavaScript und Blockly
Die Logik im Smart Home steckt meist im JavaScript-Adapter (javascript.0). Er führt JavaScript, TypeScript und Blockly aus. Blockly ist eine grafische Oberfläche, die im Hintergrund ebenfalls JavaScript erzeugt – hier siehst du beides nebeneinander.
🧪Drei Beispiele
Meldet der Bewegungsmelder im Flur Bewegung und ist es dunkel (< 50 lux), geht das Flurlicht an und nach 2 Minuten wieder aus.
var lichtTimer;
on({ id: 'hm-rpc.0.MUSTER0003.1.MOTION' /* Bewegung Flur */, change: 'ne' }, async (obj) => {
let value = obj.state.val;
let oldValue = obj.oldState.val;
if (value == true && getState('hm-rpc.0.MUSTER0003.1.ILLUMINATION').val < 50) {
setState('shelly.0.shellyplus1#0a1b2c3d4e02#1.Relay0.Switch' /* Deckenlampe Flur */, true);
(() => { if (lichtTimer) { clearTimeout(lichtTimer); lichtTimer = null; }})();
lichtTimer = setTimeout(async () => {
lichtTimer = null;
setState('shelly.0.shellyplus1#0a1b2c3d4e02#1.Relay0.Switch' /* Deckenlampe Flur */, false);
console.log('Flurlicht nach 2 Minuten aus');
}, 120000);
}
});
// Licht bei Bewegung – JavaScript-Adapter (javascript.0)
const BEWEGUNG = 'hm-rpc.0.MUSTER0003.1.MOTION';
const HELLIGKEIT = 'hm-rpc.0.MUSTER0003.1.ILLUMINATION';
const LAMPE = 'shelly.0.shellyplus1#0a1b2c3d4e02#1.Relay0.Switch';
let timer = null;
on({ id: BEWEGUNG, change: 'ne' }, (obj) => {
if (obj.state.val !== true) return; // nur „Bewegung erkannt“
if (getState(HELLIGKEIT).val >= 50) return; // hell genug → nichts tun
setState(LAMPE, true); // Befehl: ack = false
if (timer) clearTimeout(timer); // Nachlauf neu starten
timer = setTimeout(() => {
setState(LAMPE, false);
timer = null;
log('Flurlicht nach 2 Minuten aus');
}, 2 * 60 * 1000);
});true. Mit 'ne' (not equal) wird das ignoriert – das Licht geht nach 2 Minuten aus, obwohl noch jemand da ist. Mit 'any' startet jede Meldung den Nachlauf neu. Probiere es im Simulator aus.📚Die wichtigsten Funktionen
on / subscribe
Abonniert Änderungen. change: 'ne' (Wert anders), 'any' (jede Aktualisierung), 'gt', 'lt' … Weitere Filter: val, ack, q, oldVal …
on({ id: 'hm-rpc.0.MUSTER0003.1.MOTION', change: 'ne' }, (obj) => {
log(obj.id + ': ' + obj.oldState.val + ' → ' + obj.state.val);
});
// Kurzform: on('ID', cb) → change ist dann 'ne'
// Objektform ohne change → 'any'setState
Schreibt einen Wert. Drittes Argument ist ack – für Geräte weglassen (Befehl), für eigene Datenpunkte true.
setState('shelly.0.…Relay0.Switch', true); // Befehl (ack = false)
setState('0_userdata.0.Nachtmodus', true, true); // Tatsache (ack = true)
setState('0_userdata.0.Nachtmodus', { val: true, ack: true });getState
Liest den aktuellen State mit val, ack, ts, lc, from. Existiert er nicht, kommt { val: null, notExist: true } und eine Warnung.
const t = getState('zigbee.0.00158d0000000b01.temperature');
log(t.val + ' °C, geändert: ' + new Date(t.lc).toLocaleString());schedule
Zeitplan im Cron-Format (5 Felder, mit Sekunden 6) oder astronomisch (sunrise, sunset …).
schedule('0 22 * * *', () => { /* täglich 22:00 */ });
schedule('*/3 * * * * *', () => { /* alle 3 Sekunden (6 Felder) */ });
schedule({ astro: 'sunset', shift: 30 }, () => { /* 30 min nach Sonnenuntergang */ });setTimeout / clearTimeout
Wie in normalem JavaScript. Beim Stoppen eines Skripts räumt der Adapter laufende Timer und Abos auf.
let t = setTimeout(() => setState(LAMPE, false), 2 * 60 * 1000); clearTimeout(t);
createState / sendTo / $-Selektor
Eigene Datenpunkte anlegen, Nachrichten an andere Instanzen schicken, viele States über Enums auf einmal ansprechen.
createState('0_userdata.0.Zaehler', 0, { type: 'number', role: 'value' });
sendTo('history.0', 'getHistory', { id, options }, (res) => { … });
$('state(functions=Licht)(rooms=Wohnzimmer)').setState(false);🧠Wie ein Skript intern abläuft
States-DB javascript.0
┌────────────┐ stateChange ┌─────────────────────────────┐
│ MOTION │ ──────────▶ │ für jedes Abo: passt der │
│ val: true │ │ Filter? (id, change, ack, q)│
└────────────┘ │ └ ja → Callback ausführen │
▲ │ setState(LAMPE, true) │
│ └──────────────┬──────────────┘
│ setState(LAMPE, true), ack:false │
└───────────────────────────────────┘
danach: Adapter shelly.0 schaltet und bestätigt (ack:true)script) unter script.js.…, mit dem Quelltext in common.source. Bei Blockly-Skripten hängen die Blöcke zusätzlich als kodiertes XML am Quelltext.change: 'any' eines States hört und denselben State schreibt, ruft sich selbst immer wieder auf. Abhilfe: 'ne', ein ack-Filter oder ein anderer Ziel-State.0_userdata.0 – dort bleiben sie auch erhalten, wenn der JavaScript-Adapter neu installiert wird.