!! Im Tool alles kleinschreiben. HA mag keine großen Buchstaben!!
!! Sonst wird nichts funktionieren !!
1. MQTT installieren
Einstellungen - Geräte und Dienste - Integration - Integration hinzufügen - MQTT - MQTT - Das offizielle Mosquitto Mqtt Broker Add-on verwenden
Integration - MQTT - hinzufügen.
2. File Editor installieren
Einstellungen - Addons - AddOnStore - FileEditor - installieren
Addons - FileEditor - In Seitenleiste anzeigen - starten
3. zigbee2mqtt installieren
Einstellungen - Addons - AddOnStore - oben rechts ⋮ - Repositories - https://github.com/zigbee2mqtt/hassio-zigbee2mqtt
F5 drücken
Zigbee2MQTT - installieren
In Seitenleiste anzeigen - starten - links Zigbee2MQTT - Stick einrichten. MQTT Einstellungen so lassen.
4. Ordner erstellen (wo die configuration.yaml ist). Also ganz "vorne". Da kommt "www" und "room" hin
File editor - + new Folder - "www" (/homeassistant/www)
+ new Folder - "room" (/homeassistant/room)
4.1 Dateien erstellen.
Ordner www öffnen und "New file" - room-visual-card.js
- class RoomVisualCard extends HTMLElement {
- setConfig(config) {
- if (!config.room) throw new Error("Bitte 'room' angeben (z. B. arbeitszimmer).");
- this._config = config;
- if (!this.shadowRoot) this.attachShadow({ mode: "open" });
- this._build();
- }
- getCardSize() { return 5; }
- _build() {
- const root = this.shadowRoot;
- root.innerHTML = `
- <ha-card>
- <style>
- .wrap { padding: 8px; }
- .canvas { position: relative; background:#f0f0f0; border:1px solid #ccc;
- min-width:100px; min-height:100px; }
- .dot { position:absolute; width:10px; height:10px; border-radius:50%;
- transform:translate(-50%,-50%); }
- .s1{ background:red; } .s2{ background:green; } .s3{ background:blue; }
- .zone{ position:absolute; border:2px dashed; pointer-events:none; opacity:.15; }
- .label{ position:absolute; left:3px; top:3px; font-size:12px; color:#000; }
- </style>
- <div class="wrap">
- <div id="canvas" class="canvas"></div>
- </div>
- </ha-card>
- `;
- this._canvas = root.getElementById("canvas");
- // Dots anlegen (immer 3 Slots)
- this._dots = [1,2,3].map(i => {
- const d = document.createElement("div");
- d.className = `dot s${i}`;
- d.id = `dot${i}`;
- this._canvas.appendChild(d);
- return d;
- });
- // Zonen anlegen (aus config.zones [{id, color, name?}] )
- this._zones = {};
- (this._config.zones || []).forEach(z => {
- const div = document.createElement("div");
- div.className = "zone";
- div.style.borderColor = z.color || "orange";
- div.style.background = z.color || "orange";
- // Label
- const span = document.createElement("span");
- span.className = "label";
- span.textContent = z.name || z.id;
- div.appendChild(span);
- div.id = `zone_${z.id}`;
- this._canvas.appendChild(div);
- this._zones[z.id] = div;
- });
- }
- set hass(hass) {
- this._hass = hass;
- if (!this._config) return;
- const room = this._config.room;
- // Raumgröße (cm == px)
- const w = this._num(`input_number.${room}_raumx`);
- const h = this._num(`input_number.${room}_raumy`);
- if (w && h) {
- this._canvas.style.width = Math.round(w) + "px";
- this._canvas.style.height = Math.round(h) + "px";
- }
- // Punkte (Slot 1..3) positionieren
- [1,2,3].forEach((i, idx) => {
- const x = this._num(`sensor.${room}_slot${i}_welt_x`);
- const y = this._num(`sensor.${room}_slot${i}_welt_y`);
- const el = this._dots[idx];
- if (!el) return;
- if ([x,y,h].some(v => v == null)) { el.style.display="none"; return; }
- el.style.display = "block";
- el.style.left = Math.round(x) + "px";
- el.style.top = Math.round(h - y) + "px"; // unten->oben
- });
- // Zonen (per input_number.<room>_<id>_{x1,x2,y1,y2})
- (this._config.zones || []).forEach(z => {
- const el = this._zones[z.id];
- if (!el) return;
- const x1 = this._num(`input_number.${room}_${z.id}_x1`);
- const x2 = this._num(`input_number.${room}_${z.id}_x2`);
- const y1 = this._num(`input_number.${room}_${z.id}_y1`);
- const y2 = this._num(`input_number.${room}_${z.id}_y2`);
- if ([x1,x2,y1,y2,h].some(v => v == null)) { el.style.display="none"; return; }
- el.style.display = "block";
- const left = Math.min(x1, x2);
- const top = h - Math.max(y1, y2);
- el.style.left = Math.round(left) + "px";
- el.style.top = Math.round(top) + "px";
- el.style.width = Math.round(Math.abs(x2 - x1)) + "px";
- el.style.height = Math.round(Math.abs(y2 - y1)) + "px";
- });
- }
- _num(entityId) {
- const s = this._hass?.states?.[entityId]?.state;
- const v = parseFloat(s);
- return Number.isFinite(v) ? v : null;
- }
- }
- console.info('%croom-visual-card loaded', 'color: green; font-weight: bold');
- if (!customElements.get('room-visual-card')) {
- customElements.define('room-visual-card', RoomVisualCard);
- } else {
- console.warn('room-visual-card was already defined');
- }
4.2. /homeassistant/configuration.yaml bearbeiten
File Editor - ganz am anfang die configuration.yaml bearbeiten
5. Bewegungsmelder in Z2M erkennbar machen
File Editor - /homeassistant/zigbee2mqtt - Ordner external_converters erstellen
Dort Datei LD2450_erforscht.js erstellen.
- 'use strict';
- // --- Converter für LD2450 ---------------------------------------------
- const fzLD2450 = {
- cluster: 'genAnalogInput',
- type: ['attributeReport', 'readResponse'],
- convert: (model, msg) => {
- const ep = msg.endpoint.ID;
- const val = msg.data.presentValue;
- if (ep === 25) return { slot1_brightness: Math.round(val * 1000) / 1000 };
- if (ep === 26) return { slot1_temperature: Math.round(val * 10) / 10 };
- if (ep === 27) return { slot1_pressure: Math.round(val * 10) / 10 };
- switch (ep) {
- case 1: return { slot1_distance: val };
- case 6: return { slot1_x: val };
- case 7: return { slot1_y: val };
- case 9: return { slot2_distance: val };
- case 14: return { slot2_x: val };
- case 15: return { slot2_y: val };
- case 17: return { slot3_distance: val };
- case 22: return { slot3_x: val };
- case 23: return { slot3_y: val };
- }
- },
- };
- const exposes = require('zigbee-herdsman-converters/lib/exposes');
- const ea = exposes.access; // Kurz-Alias
- const eNumeric = exposes.numeric; // Fabrik-Funktion
- module.exports = [{
- zigbeeModel: ['LD2450'],
- fingerprint: [{ manufacturerName: 'erforscht', modelID: 'LD2450' }],
- model: 'LD2450_erforscht',
- vendor: 'erforscht',
- description: 'LD2450 12 endpoints',
- meta: { multiEndpoint: true },
- configure: async (device, coordinator) => {
- const used = [1,6,7,9,14,15,17,22,23,25,26,27];
- for (const ep of used) {
- const endpoint = device.getEndpoint(ep);
- if (!endpoint) continue;
- try { await endpoint.bind('genAnalogInput', coordinator); } catch (_) {}
- // schnelleres Reporting und einheitlicher Schwellwert wie in der iobroker-Vorlage
- await endpoint.configureReporting('genAnalogInput', [{
- attribute: 0x0055, // presentValue
- minimumReportInterval: 1, // frühestens alle 1 s (vorher 5 s)
- maximumReportInterval: 3600, // spätestens alle 1 h
- reportableChange: 0.01, // 1 cm / 0.01 lx / 0.01 °C / 0.01 hPa
- }]);
- }
- },
- fromZigbee: [fzLD2450],
- toZigbee: [],
- exposes: [
- eNumeric('slot1_distance', ea.STATE).withUnit('m') .withValueMin(0) .withValueMax(6),
- eNumeric('slot1_x', ea.STATE).withUnit('m') .withValueMin(-6) .withValueMax(6),
- eNumeric('slot1_y', ea.STATE).withUnit('m') .withValueMin(-6) .withValueMax(6),
- eNumeric('slot1_brightness', ea.STATE).withUnit('lx') .withValueMin(0) .withValueMax(100000),
- eNumeric('slot1_temperature', ea.STATE).withUnit('°C') .withValueMin(-40).withValueMax(85),
- eNumeric('slot1_pressure', ea.STATE).withUnit('hPa') .withValueMin(300).withValueMax(1100),
- // ergänzt: Grenzen wie in der iobroker-Version
- eNumeric('slot2_distance', ea.STATE).withUnit('m') .withValueMin(0) .withValueMax(6),
- eNumeric('slot2_x', ea.STATE).withUnit('m') .withValueMin(-6) .withValueMax(6),
- eNumeric('slot2_y', ea.STATE).withUnit('m') .withValueMin(-6) .withValueMax(6),
- eNumeric('slot3_distance', ea.STATE).withUnit('m') .withValueMin(0) .withValueMax(6),
- eNumeric('slot3_x', ea.STATE).withUnit('m') .withValueMin(-6) .withValueMax(6),
- eNumeric('slot3_y', ea.STATE).withUnit('m') .withValueMin(-6) .withValueMax(6),
- ],
- }];
6. Bewegungsmelder integrieren
Einstellung - Addons - Zigbee2MQTT - Neu Starten
Bewegungsmelder Updaten. ->
Zigbee2MQTT - Anlernen
Nach Integration vom BW dort auf das gelbe Kästchen klicken (neu konfigurieren). Dann kontrollieren. Auf den BW klicken - Details.
7. Zonen erstellen !!!WICHTIG!!! ALLES Kleinschreiben im Tool und generell IMMER in HA!!! Bei Missachtung funktioniert es nicht!!!
Die Datei herunterladen, entpacken und starten. Eventuell Windows Warnungen zulassen. --> create_ha_yaml.zip
Oder direkt hier erstellen im Form >klick_mich<
Sensor-Pfad sensor.xxxx nimmt man aus Entwicklerwerkzeug - Zustände. Dort sieht man den Sensor.
z.B. sensor.0x588c81fffe36a1dc_slot1_distance
Dann ist der Pfad es bis zum ersten Unterstrich. Nicht den Unterstrich mitnehmen. In dem Fall "sensor.0x588c81fffe36a1dc"
Es wird eine xxx.yaml erzeugt und eine xxx_visual_card.txt
in "room" kann man weitere Ordner erstellen. Ich würde z.b. den Ordner "arbeitszimmer" erstellen. Dort die yaml reinkopieren:
File editor - room - Order erstellen "arbeitszimmer" - Upload File - "arbeitszimmer.yaml" auswählen und uploaden.
8. Visuelle Ansicht
Einstellung - Dashboards - Dashboard hinzufügen
Neues Dashboard von Grund auf - Titel z.B. "Visualisierung"
öffnen - oben rechts "Bleistift" - in der Mitte "Abschnitt erstellen" - "Neuer Abschnitt +"
Ganz runterscrollen "Manuell" - den Text löschen "type: ""
Die xxx_visual_card.txt öffnen. Alles kopieren und dann einfügen. Speichern. Oben rechts "Fertig"
9. neu Starten
Entwicklerwerkzeuge - YAML - Konnfiguration Prüfen - Neu Starten - Home Assistant neu starten - neu starten
Visualisierung sieht man jetzt denn Raum. Fals nicht, 1x F5 drücken.
Fertig
10. Weitere Bewegungsmelder
Bei weiteren Bewegungsmelder: Anlernen - Wieder die beiden Dateien erstellen durch das Tool. Die yaml in "room" rein. Dann wieder wie in der
8. Visuelle Ansicht
einen neuen Abschnitt machen und den Inhalt der txt Datei einfügen. Oder weitere Dashboard hinzufügen. Freie Wahl.