From 8a3f7e72bb6d045912bd5cba43b800186ee94538 Mon Sep 17 00:00:00 2001 From: Adrian Jagielak Date: Wed, 23 Jul 2025 20:25:01 +0200 Subject: [PATCH] Add demo mode --- futurehome/config.yaml | 8 +- .../rootfs/etc/services.d/futurehome/run | 1 + futurehome/src/admin.ts | 10 +- futurehome/src/client.ts | 22 +- futurehome/src/fimp/fimp.ts | 24 +- futurehome/src/ha/globals.ts | 6 +- futurehome/src/index.ts | 30 +- futurehome/src/mqtt/demo_client.ts | 95 + futurehome/src/mqtt/demo_data/device.json | 2105 +++++++++++++++++ futurehome/src/mqtt/demo_data/state.json | 1141 +++++++++ futurehome/src/mqtt/interface.ts | 29 + futurehome/src/mqtt/real_client.ts | 57 + 12 files changed, 3477 insertions(+), 51 deletions(-) create mode 100644 futurehome/src/mqtt/demo_client.ts create mode 100644 futurehome/src/mqtt/demo_data/device.json create mode 100644 futurehome/src/mqtt/demo_data/state.json create mode 100644 futurehome/src/mqtt/interface.ts create mode 100644 futurehome/src/mqtt/real_client.ts diff --git a/futurehome/config.yaml b/futurehome/config.yaml index 266f5ca..b1870cd 100644 --- a/futurehome/config.yaml +++ b/futurehome/config.yaml @@ -1,6 +1,6 @@ # https://developers.home-assistant.io/docs/add-ons/configuration#add-on-config name: Futurehome -version: "0.0.15" +version: "0.0.16" slug: futurehome description: Local Futurehome Smarthub integration url: "https://github.com/adrianjagielak/home-assistant-futurehome" @@ -19,10 +19,12 @@ options: hub_ip: "" username: "" password: "" + demo_mode: false schema: hub_ip: "str?" - username: "str" - password: "str" + username: "str?" + password: "str?" + demo_mode: "bool?" image: "ghcr.io/adrianjagielak/{arch}-home-assistant-futurehome" diff --git a/futurehome/rootfs/etc/services.d/futurehome/run b/futurehome/rootfs/etc/services.d/futurehome/run index eb868cc..cfd6ab8 100755 --- a/futurehome/rootfs/etc/services.d/futurehome/run +++ b/futurehome/rootfs/etc/services.d/futurehome/run @@ -8,6 +8,7 @@ set -e export FH_HUB_IP=$(bashio::config 'hub_ip') export FH_USERNAME=$(bashio::config 'username') export FH_PASSWORD=$(bashio::config 'password') +export DEMO_MODE=$(bashio::config 'demo_mode') export MQTT_HOST=$(bashio::services mqtt "host") export MQTT_PORT=$(bashio::services mqtt "port") diff --git a/futurehome/src/admin.ts b/futurehome/src/admin.ts index bfd285d..c5e4545 100644 --- a/futurehome/src/admin.ts +++ b/futurehome/src/admin.ts @@ -1,9 +1,9 @@ -import { MqttClient } from "mqtt"; import { v4 as uuidv4 } from "uuid"; +import { IMqttClient } from "./mqtt/interface"; export function exposeSmarthubTools( - ha: MqttClient, - fimp: MqttClient, + ha: IMqttClient, + fimp: IMqttClient, hubAddr = "pt:j1/mt:cmd/rt:app/rn:zb/ad:1" ) { const base = "homeassistant/switch/fh_zb_pairing"; @@ -22,7 +22,7 @@ export function exposeSmarthubTools( stat_t: `${base}/state`, device, }), - { retain: true } + { retain: true, qos: 2 } ); // // keep last known state locally @@ -35,7 +35,7 @@ export function exposeSmarthubTools( // // optimistic update so the UI flips instantly // pairingOn = turnOn; - ha.publish(`${base}/state`, turnOn ? "ON" : "OFF", { retain: true }); + ha.publish(`${base}/state`, turnOn ? "ON" : "OFF", { retain: true, qos: 2 }); // placeholder FIMP message – adjust to real API if different fimp.publish( diff --git a/futurehome/src/client.ts b/futurehome/src/client.ts index ad7b27a..8212fca 100644 --- a/futurehome/src/client.ts +++ b/futurehome/src/client.ts @@ -1,21 +1,23 @@ -import mqtt, { MqttClient } from "mqtt"; +import { DemoFimpMqttClient } from "./mqtt/demo_client"; +import { IMqttClient } from "./mqtt/interface"; +import { RealMqttClient } from "./mqtt/real_client"; -export function connectHub(opts: { hubIp: string; username: string; password: string; }): Promise { - const url = `mqtt://${opts.hubIp || "futurehome-smarthub.local"}`; - return makeClient(url, 1884, opts.username, opts.password); +export function connectHub(opts: { hubIp: string; username: string; password: string; demo: boolean; }): Promise { const url = `mqtt://${opts.hubIp || "futurehome-smarthub.local"}`; + return makeClient(url, 1884, opts.username, opts.password, opts.demo); } -export async function connectHA(opts: { mqttHost: string; mqttPort: number; mqttUsername: string; mqttPassword: string; }): Promise<{ ha: MqttClient; retainedMessages: RetainedMessage[] }> { +export async function connectHA(opts: { mqttHost: string; mqttPort: number; mqttUsername: string; mqttPassword: string; }): Promise<{ ha: IMqttClient; retainedMessages: RetainedMessage[] }> { const url = `mqtt://${opts.mqttHost}`; - let ha = await makeClient(url, opts.mqttPort, opts.mqttUsername, opts.mqttPassword); + let ha = await makeClient(url, opts.mqttPort, opts.mqttUsername, opts.mqttPassword, false); let retainedMessages = await waitForHARetainedMessages(ha) return { ha, retainedMessages }; } -function makeClient(url: string, port: number, username: string, password: string): Promise { +function makeClient(url: string, port: number, username: string, password: string, demo: boolean): Promise { return new Promise((resolve, reject) => { - const client = mqtt.connect(url, { port, username, password, protocolVersion: 4 }); + const client = demo ? new DemoFimpMqttClient() : new RealMqttClient(); + client.connect(url, { port, username, password, protocolVersion: 4 }); client.once("connect", () => resolve(client)); client.once("error", reject); }); @@ -24,7 +26,7 @@ function makeClient(url: string, port: number, username: string, password: strin type RetainedMessage = { topic: string; message: string }; async function waitForHARetainedMessages( - client: MqttClient, + client: IMqttClient, timeoutMs = 3000 ): Promise { const topicPattern = /^homeassistant\/device\/futurehome.*$/; @@ -32,7 +34,7 @@ async function waitForHARetainedMessages( return new Promise((resolve, reject) => { const retainedMessages: RetainedMessage[] = []; - const messageHandler = (topic: string, message: Buffer, packet: any) => { + const messageHandler = (topic: string, message: Buffer, packet: { retain?: boolean }) => { if (packet.retain && topicPattern.test(topic)) { retainedMessages.push({ topic, message: message.toString() }); } diff --git a/futurehome/src/fimp/fimp.ts b/futurehome/src/fimp/fimp.ts index cfe271d..61b8407 100644 --- a/futurehome/src/fimp/fimp.ts +++ b/futurehome/src/fimp/fimp.ts @@ -1,10 +1,10 @@ -import { MqttClient } from "mqtt/*"; import { v4 as uuidv4 } from "uuid"; import { log } from "../logger"; +import { IMqttClient } from "../mqtt/interface"; -let fimp: MqttClient | undefined = undefined; +let fimp: IMqttClient | undefined = undefined; -export function setFimp(client: MqttClient) { +export function setFimp(client: IMqttClient) { fimp = client; } @@ -57,14 +57,6 @@ export async function sendFimpMsg({ }, ); - // For example for "cmd.foo.set" we would expect to get "evt.foo.report" back (plus the service name must match). - let possibleResponseType: string | null = null; - if (cmd.split('.').length === 3) { - possibleResponseType = cmd.split('.').map( - (part, index, array) => index === 0 ? 'evt' : (index === array.length - 1 ? 'report' : part), - ).join('.'); - } - return new Promise((resolve, reject) => { const timeout = setTimeout(() => { fimp?.removeListener('message', onResponse); @@ -112,16 +104,6 @@ export async function sendFimpMsg({ return; } - // TODO(adrianjagielak): is this needed? - // if (possibleResponseType != null && msg.type === possibleResponseType && msg.serv === parameters.service) { - // log.debug(`Received FIMP response for message ${uid} (matched using possible response type "${possibleResponseType}").`); - // - // clearTimeout(timeout); - // effectiveMqttClient.removeListener('message', onResponse); - // resolve(msg); - // return; - // } - const hasValidType = msg.type != null && msg.type.startsWith('evt.'); const reqCmdParts = cmd.split('.'); const resCmdParts = msg.type?.split('.') ?? []; diff --git a/futurehome/src/ha/globals.ts b/futurehome/src/ha/globals.ts index 605c046..3cd71f2 100644 --- a/futurehome/src/ha/globals.ts +++ b/futurehome/src/ha/globals.ts @@ -1,9 +1,9 @@ -import { MqttClient } from "mqtt/*"; +import { IMqttClient } from "../mqtt/interface"; import { CommandHandlers } from "./publish_device"; -export let ha: MqttClient | undefined = undefined; +export let ha: IMqttClient | undefined = undefined; -export function setHa(client: MqttClient) { +export function setHa(client: IMqttClient) { ha = client; } diff --git a/futurehome/src/index.ts b/futurehome/src/index.ts index f4ca18d..82eed36 100644 --- a/futurehome/src/index.ts +++ b/futurehome/src/index.ts @@ -11,24 +11,33 @@ import { VinculumPd7Device } from "./fimp/vinculum_pd7_device"; import { haUpdateAvailability } from "./ha/update_availability"; (async () => { - const hubIp = process.env.FH_HUB_IP || ""; - const hubUsername = process.env.FH_USERNAME || ""; - const hubPassword = process.env.FH_PASSWORD || ""; + const hubIp = process.env.FH_HUB_IP || ''; + const hubUsername = process.env.FH_USERNAME || ''; + const hubPassword = process.env.FH_PASSWORD || ''; + const demoMode = (process.env.DEMO_MODE || '').toLowerCase().includes('true'); - const mqttHost = process.env.MQTT_HOST || ""; - const mqttPort = Number(process.env.MQTT_PORT || "1883"); - const mqttUsername = process.env.MQTT_USER || ""; - const mqttPassword = process.env.MQTT_PWD || ""; + const mqttHost = process.env.MQTT_HOST || ''; + const mqttPort = Number(process.env.MQTT_PORT || '1883'); + const mqttUsername = process.env.MQTT_USER || ''; + const mqttPassword = process.env.MQTT_PWD || ''; - // 1) Connect to HA broker (for discovery + state) + // 1) Connect to HA broker (for discovery + state + availability + commands) log.info("Connecting to HA broker..."); const { ha, retainedMessages } = await connectHA({ mqttHost, mqttPort, mqttUsername, mqttPassword, }); setHa(ha); log.info("Connected to HA broker"); + if (!demoMode && (!hubUsername || !hubPassword)) { + log.info("Empty username or password in non-demo mode. Removing all Futurehome devices from Home Assistant..."); + retainedMessages.forEach((retainedMessage) => { + ha?.publish(retainedMessage.topic, '', { retain: true, qos: 2 }); + }); + return; + } + // 2) Connect to Futurehome hub (FIMP traffic) log.info("Connecting to Futurehome hub..."); - const fimp = await connectHub({ hubIp, username: hubUsername, password: hubPassword }); + const fimp = await connectHub({ hubIp, username: hubUsername, password: hubPassword, demo: demoMode }); fimp.subscribe("#"); setFimp(fimp); log.info("Connected to Futurehome hub"); @@ -39,6 +48,7 @@ import { haUpdateAvailability } from "./ha/update_availability"; cmd: 'cmd.pd7.request', val: { cmd: "get", component: null, param: { components: ['house'] } }, val_t: 'object', + timeoutMs: 30000, }); let hubId = house.val.param.house.hubId; @@ -48,6 +58,7 @@ import { haUpdateAvailability } from "./ha/update_availability"; cmd: 'cmd.pd7.request', val: { cmd: "get", component: null, param: { components: ['device'] } }, val_t: 'object', + timeoutMs: 30000, }); const haConfig = retainedMessages.filter(msg => msg.topic.endsWith("/config")); @@ -160,6 +171,7 @@ import { haUpdateAvailability } from "./ha/update_availability"; cmd: 'cmd.pd7.request', val: { cmd: "get", component: null, param: { components: ['state'] } }, val_t: 'object', + timeoutMs: 30000, }); ha.on('message', (topic, buf) => { diff --git a/futurehome/src/mqtt/demo_client.ts b/futurehome/src/mqtt/demo_client.ts new file mode 100644 index 0000000..6526f20 --- /dev/null +++ b/futurehome/src/mqtt/demo_client.ts @@ -0,0 +1,95 @@ +import { OnErrorCallback, OnMessageCallback } from 'mqtt/*'; +import { IMqttClient } from './interface'; +import { Buffer } from 'buffer'; +import { FimpResponse } from '../fimp/fimp'; +import demo_data__state from './demo_data/state.json'; +import demo_data__device from './demo_data/device.json'; + +export class DemoFimpMqttClient implements IMqttClient { + private messageHandlers = new Set(); + private errorHandlers = new Set(); + private onceConnectHandlers: (() => void)[] = []; + private onceErrorHandlers: OnErrorCallback[] = []; + + connect(url: string, options: { + port: number; + username: string; + password: string; + protocolVersion: 4; + }): void { + setTimeout(() => { + this.onceConnectHandlers.forEach((h) => h()); + }, 100); + } + + subscribe(topicObject: string, opts?: { qos: 0 | 1 | 2 }, callback?: (err: Error | null) => void): void; + subscribe(topic: string, opts?: any, callback?: any): void { } + + publish(topic: string, value: string, options: { + retain?: boolean; + qos: 0 | 1 | 2; + }): void { + setTimeout(() => { + const msg = JSON.parse(value) + + const sendResponse = (response: FimpResponse) => { + response.corid = response.corid ?? msg.uid; + const buffer = Buffer.from(JSON.stringify(response)); + for (const handler of this.messageHandlers) { + handler(topic, buffer, { retain: false } as any); + } + } + + if (msg.serv == 'vinculum' && msg.type == 'cmd.pd7.request' && msg.val?.param?.components?.includes('house')) { + sendResponse({ type: 'evt.pd7.response', val: { param: { house: { hubId: '000000004c38b232' } } } }) + } else if (msg.serv == 'vinculum' && msg.type == 'cmd.pd7.request' && msg.val?.param?.components?.includes('device')) { + sendResponse({ type: 'evt.pd7.response', val: { param: { device: demo_data__device } } }); + } else if (msg.serv == 'vinculum' && msg.type == 'cmd.pd7.request' && msg.val?.param?.components?.includes('state')) { + sendResponse({ type: 'evt.pd7.response', val: { param: { state: { devices: demo_data__state } } } }) + } + }, 100); + } + + on(event: 'message', handler: OnMessageCallback): void; + on(event: 'error', handler: OnErrorCallback): void; + on(event: any, handler: any): void { + if (event === 'message') { + this.messageHandlers.add(handler); + } else if (event === 'error') { + this.errorHandlers.add(handler); + } + } + + off(event: 'message', handler: OnMessageCallback): void; + off(event: 'error', handler: OnErrorCallback): void; + off(event: any, handler: any): void { + if (event === 'message') { + this.messageHandlers.delete(handler); + } else if (event === 'error') { + this.errorHandlers.delete(handler); + } + } + + removeListener(event: 'message', handler: OnMessageCallback): void { + this.off(event, handler); + } + + once(event: 'connect', handler: () => void): void; + once(event: 'error', handler: OnErrorCallback): void; + once(event: any, handler: any): void { + if (event === 'connect') { + this.onceConnectHandlers.push(handler); + } else if (event === 'error') { + this.onceErrorHandlers.push(handler); + } + } + + simulateError(message: string) { + const err = new Error(message); + for (const handler of this.errorHandlers) { + handler(err); + } + this.onceErrorHandlers.forEach((h) => h(err)); + this.onceErrorHandlers = []; + } +} \ No newline at end of file diff --git a/futurehome/src/mqtt/demo_data/device.json b/futurehome/src/mqtt/demo_data/device.json new file mode 100644 index 0000000..f084753 --- /dev/null +++ b/futurehome/src/mqtt/demo_data/device.json @@ -0,0 +1,2105 @@ +[ + { + "client": { + "name": "Boiler 3 cycles" + }, + "fimp": { + "adapter": "flow", + "address": "XFhAkhMmXNwCt4M", + "group": "1" + }, + "functionality": "appliance", + "id": 26, + "lrn": true, + "model": "flow_XFhAkhMmXNwCt4M", + "modelAlias": "Stop after", + "param": { + "power": "off", + "timestamp": null + }, + "problem": false, + "room": 7, + "services": { + "out_bin_switch": { + "addr": "/rt:dev/rn:flow/ad:1/sv:out_bin_switch/ad:XFhAkhMmXNwCt4M_0", + "enabled": true, + "intf": [ + "cmd.binary.set" + ], + "props": {} + } + }, + "supports": [ + "clear", + "poll" + ], + "thing": 26, + "type": { + "subtype": null, + "supported": { + "appliance": [], + "blinds": [], + "boiler": [], + "fan": [], + "heater": [], + "light": [], + "siren": [], + "water_valve": [] + }, + "type": "appliance" + } + }, + { + "client": { + "name": "Heatit - Z-TRM3 ch_0" + }, + "fimp": { + "adapter": "zwave-ad", + "address": "8", + "group": "ch_0" + }, + "functionality": null, + "id": 165, + "lrn": true, + "model": "zw_411_3_515", + "modelAlias": "Heatit - Z-TRM3", + "param": { + "energy": 1594.5, + "supportedThermostatModes": [ + "off", + "heat" + ], + "targetTemperature": 21, + "thermostatMode": "heat", + "timestamp": "2025-06-16 22:13:38 +0200", + "wattage": null, + "zwaveConfigParameters": [] + }, + "problem": false, + "room": null, + "services": { + "dev_sys": { + "addr": "/rt:dev/rn:zw/ad:1/sv:dev_sys/ad:8_0", + "enabled": true, + "intf": [ + "cmd.config.get_report", + "cmd.config.set", + "cmd.group.add_members", + "cmd.group.delete_members", + "cmd.group.get_members", + "cmd.ping.send", + "evt.config.report", + "evt.group.members_report", + "evt.ping.report" + ], + "props": { + "is_secure": false, + "is_unsecure": true + } + }, + "meter_elec": { + "addr": "/rt:dev/rn:zw/ad:1/sv:meter_elec/ad:8_0", + "enabled": true, + "intf": [ + "cmd.meter.get_report", + "evt.meter.report" + ], + "props": { + "is_secure": false, + "is_unsecure": true, + "sup_export_units": [], + "sup_units": [ + "kWh", + "W", + "V" + ] + } + }, + "thermostat": { + "addr": "/rt:dev/rn:zw/ad:1/sv:thermostat/ad:8_0", + "enabled": true, + "intf": [ + "cmd.mode.get_report", + "cmd.mode.set", + "cmd.setpoint.get_report", + "cmd.setpoint.set", + "evt.mode.report", + "evt.setpoint.report" + ], + "props": { + "is_secure": false, + "is_unsecure": true, + "sup_modes": [ + "off", + "heat" + ], + "sup_setpoints": [ + "heat" + ], + "sup_temperatures": { + "heat": { + "max": 35, + "min": 5 + } + } + } + }, + "version": { + "addr": "/rt:dev/rn:zw/ad:1/sv:version/ad:8_0", + "enabled": true, + "intf": [ + "cmd.version.get_report", + "evt.version.report" + ], + "props": { + "is_secure": false, + "is_unsecure": true + } + } + }, + "supports": [ + "clear", + "poll" + ], + "thing": 125, + "type": { + "subtype": null, + "supported": { + "thermostat": [] + }, + "type": "thermostat" + } + }, + { + "client": { + "name": "Heatit - Z-TRM3 ch_1" + }, + "fimp": { + "adapter": "zwave-ad", + "address": "8", + "group": "ch_1" + }, + "functionality": null, + "id": 166, + "lrn": true, + "model": "zw_411_3_515", + "modelAlias": "Heatit - Z-TRM3", + "param": { + "energy": 3714.10009765625, + "supportedThermostatModes": [ + "off", + "heat" + ], + "targetTemperature": 14, + "thermostatMode": "heat", + "timestamp": "2025-07-23 19:50:36 +0200", + "wattage": 0.419999986886978 + }, + "problem": false, + "room": 1, + "services": { + "dev_sys": { + "addr": "/rt:dev/rn:zw/ad:1/sv:dev_sys/ad:8_1", + "enabled": true, + "intf": [ + "cmd.group.add_members", + "cmd.group.delete_members", + "cmd.group.get_members", + "evt.group.members_report" + ], + "props": { + "is_secure": false, + "is_unsecure": true + } + }, + "meter_elec": { + "addr": "/rt:dev/rn:zw/ad:1/sv:meter_elec/ad:8_1", + "enabled": true, + "intf": [ + "cmd.meter.get_report", + "evt.meter.report" + ], + "props": { + "is_secure": false, + "is_unsecure": true, + "sup_export_units": [], + "sup_units": [ + "kWh", + "W", + "V" + ] + } + }, + "thermostat": { + "addr": "/rt:dev/rn:zw/ad:1/sv:thermostat/ad:8_1", + "enabled": true, + "intf": [ + "cmd.mode.get_report", + "cmd.mode.set", + "cmd.setpoint.get_report", + "cmd.setpoint.set", + "evt.mode.report", + "evt.setpoint.report" + ], + "props": { + "is_secure": false, + "is_unsecure": true, + "sup_modes": [ + "off", + "heat" + ], + "sup_setpoints": [ + "heat" + ], + "sup_temperatures": { + "heat": { + "max": 35, + "min": 5 + } + } + } + } + }, + "supports": [ + "clear", + "poll" + ], + "thing": 125, + "type": { + "subtype": null, + "supported": { + "thermostat": [] + }, + "type": "thermostat" + } + }, + { + "client": { + "name": "Heatit - Z-TRM3 ch_2" + }, + "fimp": { + "adapter": "zwave-ad", + "address": "8", + "group": "ch_2" + }, + "functionality": null, + "id": 167, + "lrn": true, + "model": "zw_411_3_515", + "modelAlias": "Heatit - Z-TRM3", + "param": { + "temperature": 30.7999992370605, + "timestamp": "2025-07-23 19:50:36 +0200" + }, + "problem": false, + "room": null, + "services": { + "basic": { + "addr": "/rt:dev/rn:zw/ad:1/sv:basic/ad:8_2", + "enabled": true, + "intf": [ + "cmd.lvl.get_report", + "cmd.lvl.set", + "evt.lvl.report" + ], + "props": { + "is_secure": false, + "is_unsecure": true + } + }, + "dev_sys": { + "addr": "/rt:dev/rn:zw/ad:1/sv:dev_sys/ad:8_2", + "enabled": true, + "intf": [ + "cmd.group.add_members", + "cmd.group.delete_members", + "cmd.group.get_members", + "evt.group.members_report" + ], + "props": { + "is_secure": false, + "is_unsecure": true + } + }, + "sensor_temp": { + "addr": "/rt:dev/rn:zw/ad:1/sv:sensor_temp/ad:8_2", + "enabled": true, + "intf": [ + "cmd.sensor.get_report", + "evt.sensor.report" + ], + "props": { + "is_secure": false, + "is_unsecure": true, + "sup_units": [ + "C" + ] + } + } + }, + "supports": [ + "clear", + "poll" + ], + "thing": 125, + "type": { + "subtype": null, + "supported": { + "sensor": [] + }, + "type": "sensor" + } + }, + { + "client": { + "name": "Heatit - Z-TRM3 ch_3" + }, + "fimp": { + "adapter": "zwave-ad", + "address": "8", + "group": "ch_3" + }, + "functionality": null, + "id": 168, + "lrn": true, + "model": "zw_411_3_515", + "modelAlias": "Heatit - Z-TRM3", + "param": { + "temperature": 0, + "timestamp": "2025-07-06 16:29:06 +0200" + }, + "problem": false, + "room": null, + "services": { + "basic": { + "addr": "/rt:dev/rn:zw/ad:1/sv:basic/ad:8_3", + "enabled": true, + "intf": [ + "cmd.lvl.get_report", + "cmd.lvl.set", + "evt.lvl.report" + ], + "props": { + "is_secure": false, + "is_unsecure": true + } + }, + "dev_sys": { + "addr": "/rt:dev/rn:zw/ad:1/sv:dev_sys/ad:8_3", + "enabled": true, + "intf": [ + "cmd.group.add_members", + "cmd.group.delete_members", + "cmd.group.get_members", + "evt.group.members_report" + ], + "props": { + "is_secure": false, + "is_unsecure": true + } + }, + "sensor_temp": { + "addr": "/rt:dev/rn:zw/ad:1/sv:sensor_temp/ad:8_3", + "enabled": true, + "intf": [ + "cmd.sensor.get_report", + "evt.sensor.report" + ], + "props": { + "is_secure": false, + "is_unsecure": true, + "sup_units": [ + "C" + ] + } + } + }, + "supports": [ + "clear", + "poll" + ], + "thing": 125, + "type": { + "subtype": null, + "supported": { + "sensor": [] + }, + "type": "sensor" + } + }, + { + "client": { + "name": "Heatit - Z-TRM3 ch_4" + }, + "fimp": { + "adapter": "zwave-ad", + "address": "8", + "group": "ch_4" + }, + "functionality": null, + "id": 169, + "lrn": true, + "model": "zw_411_3_515", + "modelAlias": "Heatit - Z-TRM3", + "param": { + "temperature": 29.1000003814697, + "timestamp": "2025-07-23 19:50:36 +0200" + }, + "problem": false, + "room": 1, + "services": { + "basic": { + "addr": "/rt:dev/rn:zw/ad:1/sv:basic/ad:8_4", + "enabled": true, + "intf": [ + "cmd.lvl.get_report", + "cmd.lvl.set", + "evt.lvl.report" + ], + "props": { + "is_secure": false, + "is_unsecure": true + } + }, + "dev_sys": { + "addr": "/rt:dev/rn:zw/ad:1/sv:dev_sys/ad:8_4", + "enabled": true, + "intf": [ + "cmd.group.add_members", + "cmd.group.delete_members", + "cmd.group.get_members", + "evt.group.members_report" + ], + "props": { + "is_secure": false, + "is_unsecure": true + } + }, + "sensor_temp": { + "addr": "/rt:dev/rn:zw/ad:1/sv:sensor_temp/ad:8_4", + "enabled": true, + "intf": [ + "cmd.sensor.get_report", + "evt.sensor.report" + ], + "props": { + "is_secure": false, + "is_unsecure": true, + "sup_units": [ + "C" + ], + "thing_role": "main" + } + } + }, + "supports": [ + "clear", + "poll" + ], + "thing": 125, + "type": { + "subtype": null, + "supported": { + "sensor": [] + }, + "type": "sensor" + } + }, + { + "client": { + "name": "Boiler" + }, + "fimp": { + "adapter": "zwave-ad", + "address": "9", + "group": "ch_0" + }, + "functionality": "appliance", + "id": 177, + "lrn": true, + "model": "zw_134_3_78", + "param": { + "energy": 2506.001953125, + "power": "off", + "temperature": 25.4899997711182, + "timestamp": "2025-07-23 19:50:00 +0200", + "wattage": 0, + "zwaveConfigParameters": [] + }, + "problem": false, + "room": 7, + "services": { + "basic": { + "addr": "/rt:dev/rn:zw/ad:1/sv:basic/ad:9_0", + "enabled": true, + "intf": [ + "cmd.lvl.get_report", + "cmd.lvl.set", + "evt.lvl.report" + ], + "props": { + "is_secure": true, + "is_unsecure": true + } + }, + "dev_sys": { + "addr": "/rt:dev/rn:zw/ad:1/sv:dev_sys/ad:9_0", + "enabled": true, + "intf": [ + "cmd.config.get_report", + "cmd.config.set", + "cmd.group.add_members", + "cmd.group.delete_members", + "cmd.group.get_members", + "cmd.ping.send", + "evt.config.report", + "evt.group.members_report", + "evt.ping.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + }, + "meter_elec": { + "addr": "/rt:dev/rn:zw/ad:1/sv:meter_elec/ad:9_0", + "enabled": true, + "intf": [ + "cmd.meter.get_report", + "cmd.meter.reset", + "evt.meter.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false, + "sup_units": [ + "kWh", + "W", + "V", + "A" + ] + } + }, + "out_bin_switch": { + "addr": "/rt:dev/rn:zw/ad:1/sv:out_bin_switch/ad:9_0", + "enabled": true, + "intf": [ + "cmd.binary.get_report", + "cmd.binary.set", + "evt.binary.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + }, + "scene_ctrl": { + "addr": "/rt:dev/rn:zw/ad:1/sv:scene_ctrl/ad:9_0", + "enabled": true, + "intf": [ + "cmd.scene.get_report", + "cmd.scene.set", + "evt.scene.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false, + "sup_scenes": null + } + }, + "sensor_temp": { + "addr": "/rt:dev/rn:zw/ad:1/sv:sensor_temp/ad:9_0", + "enabled": true, + "intf": [ + "cmd.sensor.get_report", + "evt.sensor.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false, + "sup_units": [ + "C", + "F" + ], + "thing_role": "main" + } + }, + "version": { + "addr": "/rt:dev/rn:zw/ad:1/sv:version/ad:9_0", + "enabled": true, + "intf": [ + "cmd.version.get_report", + "evt.version.report" + ], + "props": { + "is_secure": true, + "is_unsecure": true + } + } + }, + "supports": [ + "clear", + "poll" + ], + "thing": 131, + "type": { + "subtype": null, + "supported": { + "appliance": [], + "blinds": [], + "boiler": [], + "fan": [], + "heater": [], + "light": [], + "siren": [], + "water_valve": [] + }, + "type": "appliance" + } + }, + { + "client": { + "name": "Start boiler 3h" + }, + "fimp": { + "adapter": "flow", + "address": "tfnGPTUArLR0Vzs", + "group": "1" + }, + "functionality": null, + "id": 178, + "lrn": true, + "model": "flow_tfnGPTUArLR0Vzs", + "modelAlias": "Start boiler 1.5h", + "param": { + "timestamp": null + }, + "problem": false, + "room": 4, + "services": {}, + "supports": [ + "clear" + ], + "thing": 132, + "type": { + "subtype": null, + "supported": {}, + "type": null + } + }, + { + "client": { + "name": "LOM001" + }, + "fimp": { + "adapter": "zigbee", + "address": "2", + "group": "ch_11" + }, + "functionality": "appliance", + "id": 180, + "lrn": true, + "model": null, + "modelAlias": "LOM001", + "param": { + "dimValue": 1, + "power": "on", + "timestamp": "2025-07-23 19:38:58 +0200" + }, + "problem": false, + "room": 1, + "services": { + "association": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:association/ad:2_11", + "enabled": true, + "intf": [], + "props": { + "in_services": [ + "out_bin_switch", + "out_lvl_switch" + ], + "is_secure": true, + "is_unsecure": false + } + }, + "indicator_ctrl": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:indicator_ctrl/ad:2_11", + "enabled": true, + "intf": [ + "cmd.indicator.set_visual_element" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + }, + "out_bin_switch": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:out_bin_switch/ad:2_11", + "enabled": true, + "intf": [ + "cmd.binary.get_report", + "cmd.binary.set", + "evt.binary.report" + ], + "props": {} + }, + "out_lvl_switch": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:out_lvl_switch/ad:2_11", + "enabled": true, + "intf": [ + "cmd.lvl.get_report", + "cmd.lvl.set", + "cmd.lvl.start", + "cmd.lvl.stop", + "evt.lvl.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false, + "max_lvl": 254, + "min_lvl": 0 + } + } + }, + "supports": [ + "clear", + "poll" + ], + "thing": 134, + "type": { + "subtype": null, + "supported": { + "appliance": [], + "blinds": [], + "fan": [], + "heater": [], + "light": [] + }, + "type": "appliance" + } + }, + { + "client": { + "name": "TRADFRI SHORTCUT Button" + }, + "fimp": { + "adapter": "zigbee", + "address": "4", + "group": "ch_1" + }, + "functionality": null, + "id": 182, + "lrn": true, + "model": null, + "modelAlias": "TRADFRI SHORTCUT Button", + "param": { + "batteryLevel": "ok", + "batteryPercentage": 50, + "timestamp": "2022-07-15 03:05:46 +0200" + }, + "problem": false, + "room": 4, + "services": { + "association": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:association/ad:4_1", + "enabled": true, + "intf": [ + "cmd.association.add", + "cmd.association.delete", + "cmd.association.delete_all", + "cmd.association.get_report", + "evt.association.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false, + "out_services": [ + "out_bin_switch", + "out_lvl_switch" + ] + } + }, + "battery": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:battery/ad:4_1", + "enabled": true, + "intf": [ + "evt.lvl.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + }, + "indicator_ctrl": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:indicator_ctrl/ad:4_1", + "enabled": true, + "intf": [ + "cmd.indicator.set_visual_element" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + }, + "scene_ctrl": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:scene_ctrl/ad:4_1", + "enabled": true, + "intf": [ + "evt.scene.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + } + }, + "supports": [ + "clear", + "poll" + ], + "thing": 136, + "type": { + "subtype": "scene", + "supported": { + "input": [ + "scene" + ] + }, + "type": "input" + } + }, + { + "client": { + "name": "TRADFRI on/off switch" + }, + "fimp": { + "adapter": "zigbee", + "address": "6", + "group": "ch_1" + }, + "functionality": null, + "id": 188, + "lrn": true, + "model": "zb - IKEA of Sweden - TRADFRI on/off switch", + "modelAlias": "TRADFRI on/off switch", + "param": { + "batteryLevel": "low", + "batteryPercentage": 8, + "timestamp": "2022-05-17 21:50:11 +0200" + }, + "problem": false, + "room": 1, + "services": { + "association": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:association/ad:6_1", + "enabled": true, + "intf": [ + "cmd.association.add", + "cmd.association.delete", + "cmd.association.delete_all", + "cmd.association.get_report", + "evt.association.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false, + "out_services": [ + "out_bin_switch", + "out_lvl_switch" + ] + } + }, + "battery": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:battery/ad:6_1", + "enabled": true, + "intf": [ + "evt.lvl.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + }, + "indicator_ctrl": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:indicator_ctrl/ad:6_1", + "enabled": true, + "intf": [ + "cmd.indicator.set_visual_element" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + }, + "scene_ctrl": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:scene_ctrl/ad:6_1", + "enabled": true, + "intf": [ + "evt.scene.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + } + }, + "supports": [ + "clear", + "poll" + ], + "thing": 142, + "type": { + "subtype": "scene", + "supported": { + "input": [ + "scene" + ] + }, + "type": "input" + } + }, + { + "client": { + "name": "TRADFRI bulb E27 CWS opal 600lm" + }, + "fimp": { + "adapter": "zigbee", + "address": "3", + "group": "ch_1" + }, + "functionality": "lighting", + "id": 190, + "lrn": true, + "model": "zb - IKEA of Sweden - TRADFRI bulb E27 CWS opal 600lm", + "modelAlias": "TRADFRI bulb E27 CWS opal 600lm", + "param": { + "color": [ + 0, + 0, + 0, + 0, + 0 + ], + "dimValue": 100, + "power": "off", + "timestamp": "2023-03-19 16:44:21 +0100" + }, + "problem": false, + "room": 1, + "services": { + "association": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:association/ad:3_1", + "enabled": true, + "intf": [], + "props": { + "in_services": [ + "color", + "out_bin_switch", + "out_lvl_switch" + ], + "is_secure": true, + "is_unsecure": false + } + }, + "color_ctrl": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:color_ctrl/ad:3_1", + "enabled": true, + "intf": [ + "cmd.color.get_report", + "cmd.color.set", + "evt.color.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false, + "sup_components": [ + "red", + "green", + "blue" + ] + } + }, + "indicator_ctrl": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:indicator_ctrl/ad:3_1", + "enabled": true, + "intf": [ + "cmd.indicator.set_visual_element" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + }, + "out_bin_switch": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:out_bin_switch/ad:3_1", + "enabled": true, + "intf": [ + "cmd.binary.get_report", + "cmd.binary.set", + "evt.binary.report" + ], + "props": {} + }, + "out_lvl_switch": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:out_lvl_switch/ad:3_1", + "enabled": true, + "intf": [ + "cmd.lvl.get_report", + "cmd.lvl.set", + "cmd.lvl.start", + "cmd.lvl.stop", + "evt.lvl.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false, + "max_lvl": 254, + "min_lvl": 0 + } + }, + "virtual_meter_elec": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:virtual_meter_elec/ad:3_1", + "enabled": true, + "intf": [ + "cmd.config.get_interval", + "cmd.config.set_interval", + "cmd.meter.add", + "cmd.meter.get_report", + "cmd.meter.remove", + "evt.config.interval_report", + "evt.meter.report" + ], + "props": { + "sup_modes": [ + "off", + "on" + ], + "sup_units": [ + "W" + ] + } + } + }, + "supports": [ + "clear", + "poll" + ], + "thing": 144, + "type": { + "subtype": null, + "supported": { + "light": [] + }, + "type": "light" + } + }, + { + "client": { + "name": "Connecte Thermostat" + }, + "fimp": { + "adapter": "zigbee", + "address": "9", + "group": "ch_1" + }, + "functionality": null, + "id": 193, + "lrn": true, + "model": "zb - _TZE200_4hbx5cvx - TS0601", + "modelAlias": "Connecte Thermostat", + "param": { + "targetTemperature": 17, + "temperature": 21, + "timestamp": "2022-02-23 00:06:14 +0100" + }, + "problem": false, + "room": null, + "services": { + "indicator_ctrl": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:indicator_ctrl/ad:9_1", + "enabled": true, + "intf": [ + "cmd.indicator.set_visual_element" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + }, + "sensor_temp": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:sensor_temp/ad:9_1", + "enabled": true, + "intf": [ + "cmd.sensor.get_report", + "evt.sensor.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false, + "sup_units": [ + "C" + ], + "thing_role": "main" + } + }, + "thermostat": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:thermostat/ad:9_1", + "enabled": true, + "intf": [ + "cmd.setpoint.get_report", + "cmd.setpoint.set", + "evt.setpoint.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false, + "sup_modes": [], + "sup_setpoints": [ + "heat" + ] + } + } + }, + "supports": [ + "clear", + "poll" + ], + "thing": 147, + "type": { + "subtype": null, + "supported": { + "thermostat": [] + }, + "type": "thermostat" + } + }, + { + "client": { + "name": "TS0121" + }, + "fimp": { + "adapter": "zigbee", + "address": "7", + "group": "ch_1" + }, + "functionality": "lighting", + "id": 196, + "lrn": true, + "model": "zb - _TZ3000_fqoynhku - TS0121", + "modelAlias": "TS0121", + "param": { + "power": "off", + "timestamp": "2022-06-11 20:09:09 +0200" + }, + "problem": false, + "room": null, + "services": { + "indicator_ctrl": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:indicator_ctrl/ad:7_1", + "enabled": true, + "intf": [ + "cmd.indicator.set_visual_element" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + }, + "meter_elec": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:meter_elec/ad:7_1", + "enabled": true, + "intf": [ + "cmd.meter.get_report", + "cmd.meter_ext.get_report", + "evt.meter.report", + "evt.meter_ext.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + }, + "out_bin_switch": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:out_bin_switch/ad:7_1", + "enabled": true, + "intf": [ + "cmd.binary.get_report", + "cmd.binary.set", + "evt.binary.report" + ], + "props": {} + } + }, + "supports": [ + "clear", + "poll" + ], + "thing": 150, + "type": { + "subtype": null, + "supported": { + "appliance": [], + "blinds": [], + "boiler": [], + "fan": [], + "heater": [], + "light": [], + "siren": [], + "water_valve": [] + }, + "type": "light" + } + }, + { + "client": { + "name": "lumi.plug.maeu01" + }, + "fimp": { + "adapter": "zigbee", + "address": "5", + "group": "ch_1" + }, + "functionality": "lighting", + "id": 197, + "lrn": true, + "model": "zb - LUMI - lumi.plug.maeu01", + "modelAlias": "lumi.plug.maeu01", + "param": { + "power": "off", + "timestamp": "2022-06-02 01:41:04 +0200" + }, + "problem": false, + "room": null, + "services": { + "indicator_ctrl": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:indicator_ctrl/ad:5_1", + "enabled": true, + "intf": [ + "cmd.indicator.set_visual_element" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + }, + "meter_elec": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:meter_elec/ad:5_1", + "enabled": true, + "intf": [ + "cmd.meter.get_report", + "cmd.meter_ext.get_report", + "evt.meter.report", + "evt.meter_ext.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + }, + "out_bin_switch": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:out_bin_switch/ad:5_1", + "enabled": true, + "intf": [ + "cmd.binary.get_report", + "cmd.binary.set", + "evt.binary.report" + ], + "props": {} + } + }, + "supports": [ + "clear", + "poll" + ], + "thing": 151, + "type": { + "subtype": null, + "supported": { + "appliance": [], + "blinds": [], + "boiler": [], + "fan": [], + "heater": [], + "light": [], + "siren": [], + "water_valve": [] + }, + "type": "light" + } + }, + { + "client": { + "name": "4512701" + }, + "fimp": { + "adapter": "zigbee", + "address": "12", + "group": "ch_1" + }, + "functionality": null, + "id": 199, + "lrn": true, + "model": "zb - NAMRON AS - 4512701", + "modelAlias": "4512701", + "param": { + "batteryLevel": "ok", + "batteryPercentage": 18, + "timestamp": "2025-04-26 03:31:18 +0200" + }, + "problem": false, + "room": null, + "services": { + "association": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:association/ad:12_1", + "enabled": true, + "intf": [ + "cmd.association.add", + "cmd.association.delete", + "cmd.association.delete_all", + "cmd.association.get_report", + "evt.association.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false, + "out_services": [ + "color", + "out_bin_switch", + "out_lvl_switch" + ] + } + }, + "battery": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:battery/ad:12_1", + "enabled": true, + "intf": [ + "evt.lvl.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + }, + "indicator_ctrl": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:indicator_ctrl/ad:12_1", + "enabled": true, + "intf": [ + "cmd.indicator.set_visual_element" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + }, + "scene_ctrl": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:scene_ctrl/ad:12_1", + "enabled": true, + "intf": [ + "evt.scene.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + } + }, + "supports": [ + "clear", + "poll" + ], + "thing": 153, + "type": { + "subtype": "scene", + "supported": { + "input": [ + "scene" + ] + }, + "type": "input" + } + }, + { + "client": { + "name": "4512719" + }, + "fimp": { + "adapter": "zigbee", + "address": "14", + "group": "ch_1" + }, + "functionality": null, + "id": 201, + "lrn": true, + "model": "zb - NAMRON AS - 4512719", + "modelAlias": "4512719", + "param": { + "batteryLevel": "ok", + "batteryPercentage": 37, + "timestamp": "2023-01-04 16:16:36 +0100" + }, + "problem": false, + "room": null, + "services": { + "association": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:association/ad:14_1", + "enabled": true, + "intf": [ + "cmd.association.add", + "cmd.association.delete", + "cmd.association.delete_all", + "cmd.association.get_report", + "evt.association.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false, + "out_services": [ + "color", + "out_bin_switch", + "out_lvl_switch" + ] + } + }, + "battery": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:battery/ad:14_1", + "enabled": true, + "intf": [ + "evt.lvl.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + }, + "indicator_ctrl": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:indicator_ctrl/ad:14_1", + "enabled": true, + "intf": [ + "cmd.indicator.set_visual_element" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + }, + "scene_ctrl": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:scene_ctrl/ad:14_1", + "enabled": true, + "intf": [ + "evt.scene.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + } + }, + "supports": [ + "clear", + "poll" + ], + "thing": 155, + "type": { + "subtype": "scene", + "supported": { + "input": [ + "scene" + ] + }, + "type": "input" + } + }, + { + "client": { + "name": "HAN sensor" + }, + "fimp": { + "adapter": "zigbee", + "address": "10", + "group": "ch_2" + }, + "functionality": null, + "id": 204, + "lrn": true, + "model": "zb - Develco Products A/S - EMIZB-132", + "modelAlias": "HAN sensor", + "param": { + "energy": 45071.297, + "timestamp": "2025-07-23 19:50:51 +0200", + "wattage": 164 + }, + "problem": false, + "room": 6, + "services": { + "indicator_ctrl": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:indicator_ctrl/ad:10_2", + "enabled": true, + "intf": [ + "cmd.indicator.set_visual_element" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + }, + "meter_elec": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:meter_elec/ad:10_2", + "enabled": true, + "intf": [ + "cmd.meter.get_export_report", + "cmd.meter.get_report", + "cmd.meter_ext.get_report", + "evt.meter.export_report", + "evt.meter.report", + "evt.meter_ext.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false, + "sup_extended_vals": [ + "i1", + "p_import_react", + "u1", + "p_export_react" + ], + "sup_units": [ + "kWh", + "W" + ] + } + }, + "ota": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:ota/ad:10_2", + "enabled": true, + "intf": [ + "evt.ota_end.report", + "evt.ota_progress.report", + "evt.ota_start.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + } + }, + "supports": [ + "clear", + "poll" + ], + "thing": 158, + "type": { + "subtype": "main_elec", + "supported": { + "meter": [ + "main_elec" + ] + }, + "type": "meter" + } + }, + { + "client": { + "name": "HAN sensor" + }, + "fimp": { + "adapter": "zigbee", + "address": "11", + "group": "ch_2" + }, + "functionality": null, + "id": 205, + "lrn": true, + "model": "zb - frient A/S - EMIZB-132", + "modelAlias": "EMIZB-132", + "param": { + "energy": 37030.806, + "timestamp": "2022-11-02 00:02:29 +0100", + "wattage": 3320 + }, + "problem": false, + "room": 6, + "services": { + "indicator_ctrl": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:indicator_ctrl/ad:11_2", + "enabled": true, + "intf": [ + "cmd.indicator.set_visual_element" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + }, + "meter_elec": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:meter_elec/ad:11_2", + "enabled": true, + "intf": [ + "cmd.meter.get_export_report", + "cmd.meter.get_report", + "cmd.meter_ext.get_report", + "cmd.meter_metadata.get_report", + "evt.meter.export_report", + "evt.meter.report", + "evt.meter_ext.report", + "evt.meter_metadata.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false, + "serial_number": "6970631401991295", + "sup_extended_vals": [], + "sup_units": [ + "kWh", + "W" + ] + } + }, + "ota": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:ota/ad:11_2", + "enabled": true, + "intf": [ + "evt.ota_end.report", + "evt.ota_progress.report", + "evt.ota_start.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + } + }, + "supports": [ + "clear", + "poll" + ], + "thing": 160, + "type": { + "subtype": null, + "supported": { + "meter": [ + "main_elec" + ] + }, + "type": null + } + }, + { + "client": { + "name": "TRADFRI remote control" + }, + "fimp": { + "adapter": "zigbee", + "address": "8", + "group": "ch_1" + }, + "functionality": null, + "id": 206, + "lrn": true, + "model": "zb - IKEA of Sweden - TRADFRI remote control", + "modelAlias": "TRADFRI remote control", + "param": { + "batteryLevel": "ok", + "batteryPercentage": 37, + "timestamp": "2024-02-07 16:47:05 +0100" + }, + "problem": false, + "room": 1, + "services": { + "association": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:association/ad:8_1", + "enabled": true, + "intf": [ + "cmd.association.add", + "cmd.association.delete", + "cmd.association.delete_all", + "cmd.association.get_report", + "evt.association.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false, + "out_services": [ + "out_bin_switch", + "out_lvl_switch" + ] + } + }, + "battery": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:battery/ad:8_1", + "enabled": true, + "intf": [ + "evt.lvl.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + }, + "indicator_ctrl": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:indicator_ctrl/ad:8_1", + "enabled": true, + "intf": [ + "cmd.indicator.set_visual_element" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + }, + "scene_ctrl": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:scene_ctrl/ad:8_1", + "enabled": true, + "intf": [ + "evt.scene.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + } + }, + "supports": [ + "clear", + "poll" + ], + "thing": 161, + "type": { + "subtype": "scene", + "supported": { + "input": [ + "scene" + ] + }, + "type": "input" + } + }, + { + "client": { + "name": "Restart router" + }, + "fimp": { + "adapter": "flow", + "address": "oYinQN8bgwxeDt9", + "group": "ch_0" + }, + "functionality": "appliance", + "id": 208, + "lrn": true, + "model": "flow_oYinQN8bgwxeDt9", + "modelAlias": "Restart router", + "param": { + "power": "off", + "timestamp": null + }, + "problem": false, + "room": 1, + "services": { + "out_bin_switch": { + "addr": "/rt:dev/rn:flow/ad:1/sv:out_bin_switch/ad:oYinQN8bgwxeDt9_0", + "enabled": true, + "intf": [ + "cmd.binary.set" + ], + "props": {} + } + }, + "supports": [ + "clear", + "poll" + ], + "thing": 165, + "type": { + "subtype": null, + "supported": { + "appliance": [], + "blinds": [], + "boiler": [], + "fan": [], + "heater": [], + "light": [], + "siren": [], + "water_valve": [] + }, + "type": "appliance" + } + }, + { + "client": { + "name": "Boiler 5 cycles" + }, + "fimp": { + "adapter": "flow", + "address": "1bPIbg2So4l3Y6h", + "group": "7" + }, + "functionality": "appliance", + "id": 209, + "lrn": true, + "model": "flow_1bPIbg2So4l3Y6h", + "modelAlias": "Boiler 5 cycles", + "param": { + "power": "off", + "timestamp": null + }, + "problem": false, + "room": 7, + "services": { + "out_bin_switch": { + "addr": "/rt:dev/rn:flow/ad:1/sv:out_bin_switch/ad:tfnGPTUArLR0Vzs_0", + "enabled": true, + "intf": [ + "cmd.binary.set" + ], + "props": {} + } + }, + "supports": [ + "clear", + "poll" + ], + "thing": 166, + "type": { + "subtype": null, + "supported": { + "appliance": [], + "blinds": [], + "boiler": [], + "fan": [], + "heater": [], + "light": [], + "siren": [], + "water_valve": [] + }, + "type": "appliance" + } + }, + { + "client": { + "name": "HAN sensor gen1" + }, + "fimp": { + "adapter": "zigbee", + "address": "1", + "group": "ch_1" + }, + "functionality": null, + "id": 210, + "lrn": true, + "model": "zb - Datek - Meter Reader", + "modelAlias": "HAN sensor gen1", + "param": { + "energy": 0, + "temperature": 14.55, + "timestamp": "2024-03-08 19:58:08 +0100", + "wattage": 0 + }, + "problem": false, + "room": null, + "services": { + "indicator_ctrl": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:indicator_ctrl/ad:1_1", + "enabled": true, + "intf": [ + "cmd.indicator.set_visual_element" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + }, + "meter_elec": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:meter_elec/ad:1_1", + "enabled": true, + "intf": [ + "cmd.meter.get_export_report", + "cmd.meter.get_report", + "cmd.meter_ext.get_report", + "cmd.meter_metadata.get_report", + "evt.meter.export_report", + "evt.meter.report", + "evt.meter_ext.report", + "evt.meter_metadata.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false, + "serial_number": "6970631401991295", + "sup_extended_vals": [ + "u1", + "i1", + "p_import_react", + "p_export_react" + ], + "sup_units": [ + "kWh", + "W" + ] + } + }, + "ota": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:ota/ad:1_1", + "enabled": true, + "intf": [ + "evt.ota_end.report", + "evt.ota_progress.report", + "evt.ota_start.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + }, + "sensor_temp": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:sensor_temp/ad:1_1", + "enabled": true, + "intf": [ + "evt.sensor.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false, + "sup_units": [ + "C" + ], + "thing_role": "main" + } + } + }, + "supports": [ + "clear", + "poll" + ], + "thing": 167, + "type": { + "subtype": null, + "supported": { + "meter": [ + "main_elec" + ] + }, + "type": "meter" + } + }, + { + "client": { + "name": "Develco smart plug" + }, + "fimp": { + "adapter": "zigbee", + "address": "13", + "group": "ch_2" + }, + "functionality": "appliance", + "id": 211, + "lrn": true, + "model": "zb - Develco Products A/S - SPLZB-131", + "modelAlias": "Develco smart plug", + "param": { + "energy": 0.855, + "power": "off", + "timestamp": "2025-07-23 19:35:16 +0200", + "wattage": 0 + }, + "problem": false, + "room": 9, + "services": { + "association": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:association/ad:13_2", + "enabled": true, + "intf": [], + "props": { + "in_services": [ + "out_bin_switch" + ], + "is_secure": true, + "is_unsecure": false + } + }, + "indicator_ctrl": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:indicator_ctrl/ad:13_2", + "enabled": true, + "intf": [ + "cmd.indicator.set_visual_element" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + }, + "meter_elec": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:meter_elec/ad:13_2", + "enabled": true, + "intf": [ + "cmd.meter.get_export_report", + "cmd.meter.get_report", + "cmd.meter_ext.get_report", + "cmd.meter_metadata.get_report", + "evt.meter.export_report", + "evt.meter.report", + "evt.meter_ext.report", + "evt.meter_metadata.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false, + "serial_number": "0015BC002F004932", + "sup_extended_vals": [ + "p_import_react", + "freq", + "u1", + "i1", + "p_import", + "p_export_react", + "p_export" + ], + "sup_units": [ + "kWh", + "W" + ] + } + }, + "ota": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:ota/ad:13_2", + "enabled": true, + "intf": [ + "evt.ota_end.report", + "evt.ota_progress.report", + "evt.ota_start.report" + ], + "props": { + "is_secure": true, + "is_unsecure": false + } + }, + "out_bin_switch": { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:out_bin_switch/ad:13_2", + "enabled": true, + "intf": [ + "cmd.binary.get_report", + "cmd.binary.set", + "evt.binary.report" + ], + "props": {} + } + }, + "supports": [ + "clear", + "poll" + ], + "thing": 168, + "type": { + "subtype": null, + "supported": { + "appliance": [], + "blinds": [], + "boiler": [], + "fan": [], + "heater": [], + "light": [], + "siren": [], + "water_valve": [] + }, + "type": "appliance" + } + } +] diff --git a/futurehome/src/mqtt/demo_data/state.json b/futurehome/src/mqtt/demo_data/state.json new file mode 100644 index 0000000..3b0c046 --- /dev/null +++ b/futurehome/src/mqtt/demo_data/state.json @@ -0,0 +1,1141 @@ +[ + { + "id": 26, + "services": [] + }, + { + "id": 165, + "services": [ + { + "addr": "/rt:dev/rn:zw/ad:1/sv:thermostat/ad:8_0", + "attributes": [ + { + "name": "setpoint", + "values": [ + { + "ts": "2021-11-15 21:30:00 +0100", + "val": { + "temp": "21.000000", + "type": "heat", + "unit": "C" + }, + "val_t": "str_map" + } + ] + }, + { + "name": "mode", + "values": [ + { + "ts": "2021-11-15 20:31:03 +0100", + "val": "heat", + "val_t": "string" + } + ] + } + ], + "name": "thermostat" + }, + { + "addr": "/rt:dev/rn:zw/ad:1/sv:dev_sys/ad:8_0", + "attributes": [ + { + "name": "state", + "values": [ + { + "ts": "2025-06-16 22:13:38 +0200", + "val": "UP", + "val_t": "string" + } + ] + } + ], + "name": "dev_sys" + }, + { + "addr": "/rt:dev/rn:zw/ad:1/sv:meter_elec/ad:8_0", + "attributes": [ + { + "name": "meter", + "values": [ + { + "props": { + "unit": "kWh" + }, + "ts": "2021-11-15 20:31:03 +0100", + "val": 1594.5, + "val_t": "float" + } + ] + } + ], + "name": "meter_elec" + } + ] + }, + { + "id": 166, + "services": [ + { + "addr": "/rt:dev/rn:zw/ad:1/sv:thermostat/ad:8_1", + "attributes": [ + { + "name": "setpoint", + "values": [ + { + "ts": "2025-07-22 23:00:00 +0200", + "val": { + "temp": "14.00", + "type": "heat", + "unit": "C" + }, + "val_t": "str_map" + } + ] + }, + { + "name": "mode", + "values": [ + { + "ts": "2025-07-20 23:00:00 +0200", + "val": "heat", + "val_t": "string" + } + ] + } + ], + "name": "thermostat" + }, + { + "addr": "/rt:dev/rn:zw/ad:1/sv:meter_elec/ad:8_1", + "attributes": [ + { + "name": "meter", + "values": [ + { + "props": { + "unit": "pulse_c" + }, + "ts": "2025-06-19 20:54:34 +0200", + "val": 0.300000011920929, + "val_t": "float" + }, + { + "props": { + "unit": "kWh" + }, + "ts": "2025-07-23 19:50:36 +0200", + "val": 3714.10009765625, + "val_t": "float" + }, + { + "props": { + "unit": "V" + }, + "ts": "2025-07-23 19:50:36 +0200", + "val": 235.600006103516, + "val_t": "float" + }, + { + "props": { + "unit": "W" + }, + "ts": "2025-07-23 19:50:36 +0200", + "val": 0.419999986886978, + "val_t": "float" + } + ] + } + ], + "name": "meter_elec" + }, + { + "addr": "/rt:dev/rn:zw/ad:1/sv:basic/ad:8_1", + "attributes": [ + { + "name": "lvl", + "values": [ + { + "ts": "2025-05-30 22:58:10 +0200", + "val": 255, + "val_t": "int" + } + ] + } + ], + "name": "basic" + }, + { + "addr": "/rt:dev/rn:zw/ad:1/sv:dev_sys/ad:8_1", + "attributes": [ + { + "name": "error", + "values": [ + { + "props": { + "msg": "TRANSMIT_COMPLETE_NOROUTE", + "src": "nodeId=8_1;service=thermostat" + }, + "ts": "2024-02-25 16:20:51 +0100", + "val": "TX_ERROR", + "val_t": "string" + } + ] + } + ], + "name": "dev_sys" + } + ] + }, + { + "id": 167, + "services": [ + { + "addr": "/rt:dev/rn:zw/ad:1/sv:sensor_temp/ad:8_2", + "attributes": [ + { + "name": "sensor", + "values": [ + { + "props": { + "unit": "C" + }, + "ts": "2025-07-23 19:50:36 +0200", + "val": 30.7999992370605, + "val_t": "float" + } + ] + } + ], + "name": "sensor_temp" + } + ] + }, + { + "id": 168, + "services": [ + { + "addr": "/rt:dev/rn:zw/ad:1/sv:sensor_temp/ad:8_3", + "attributes": [ + { + "name": "sensor", + "values": [ + { + "props": { + "unit": "C" + }, + "ts": "2025-07-06 16:29:06 +0200", + "val": 0, + "val_t": "float" + } + ] + } + ], + "name": "sensor_temp" + } + ] + }, + { + "id": 169, + "services": [ + { + "addr": "/rt:dev/rn:zw/ad:1/sv:sensor_temp/ad:8_4", + "attributes": [ + { + "name": "sensor", + "values": [ + { + "props": { + "unit": "C" + }, + "ts": "2025-07-23 19:50:36 +0200", + "val": 29.1000003814697, + "val_t": "float" + } + ] + } + ], + "name": "sensor_temp" + } + ] + }, + { + "id": 177, + "services": [ + { + "addr": "/rt:dev/rn:zw/ad:1/sv:sensor_temp/ad:9_0", + "attributes": [ + { + "name": "sensor", + "values": [ + { + "props": { + "unit": "C" + }, + "ts": "2021-12-20 02:20:02 +0100", + "val": 25.4899997711182, + "val_t": "float" + } + ] + } + ], + "name": "sensor_temp" + }, + { + "addr": "/rt:dev/rn:zw/ad:1/sv:out_bin_switch/ad:9_0", + "attributes": [ + { + "name": "binary", + "values": [ + { + "ts": "2025-07-19 06:50:25 +0200", + "val": false, + "val_t": "bool" + } + ] + } + ], + "name": "out_bin_switch" + }, + { + "addr": "/rt:dev/rn:zw/ad:1/sv:dev_sys/ad:9_0", + "attributes": [ + { + "name": "state", + "values": [ + { + "ts": "2024-03-08 04:10:23 +0100", + "val": "UP", + "val_t": "string" + } + ] + }, + { + "name": "error", + "values": [ + { + "props": { + "msg": "TRANSMIT_COMPLETE_NO_ACK", + "src": "nodeId=9_0;service=out_bin_switch" + }, + "ts": "2024-03-08 04:08:27 +0100", + "val": "TX_ERROR", + "val_t": "string" + } + ] + } + ], + "name": "dev_sys" + }, + { + "addr": "/rt:dev/rn:zw/ad:1/sv:meter_elec/ad:9_0", + "attributes": [ + { + "name": "meter", + "values": [ + { + "props": { + "delta_t": "120", + "prv_data": "2506.001953", + "unit": "kWh" + }, + "ts": "2025-07-23 19:50:00 +0200", + "val": 2506.001953125, + "val_t": "float" + }, + { + "props": { + "unit": "W" + }, + "ts": "2025-07-22 05:12:19 +0200", + "val": 0, + "val_t": "float" + } + ] + } + ], + "name": "meter_elec" + } + ] + }, + { + "id": 178, + "services": [] + }, + { + "id": 180, + "services": [ + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:out_lvl_switch/ad:2_11", + "attributes": [ + { + "name": "lvl", + "values": [ + { + "ts": "2022-11-07 00:11:17 +0100", + "val": 1, + "val_t": "int" + } + ] + }, + { + "name": "binary", + "values": [ + { + "ts": "2022-05-23 02:22:03 +0200", + "val": true, + "val_t": "bool" + } + ] + } + ], + "name": "out_lvl_switch" + }, + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:out_bin_switch/ad:2_11", + "attributes": [ + { + "name": "binary", + "values": [ + { + "ts": "2025-07-23 19:38:58 +0200", + "val": true, + "val_t": "bool" + } + ] + } + ], + "name": "out_bin_switch" + } + ] + }, + { + "id": 182, + "services": [ + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:scene_ctrl/ad:4_1", + "attributes": [ + { + "name": "scene", + "values": [ + { + "ts": "2022-07-15 03:05:46 +0200", + "val": "on", + "val_t": "string" + } + ] + } + ], + "name": "scene_ctrl" + }, + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:battery/ad:4_1", + "attributes": [ + { + "name": "lvl", + "values": [ + { + "ts": "2022-01-20 23:11:45 +0100", + "val": 50, + "val_t": "int" + } + ] + } + ], + "name": "battery" + } + ] + }, + { + "id": 188, + "services": [ + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:scene_ctrl/ad:6_1", + "attributes": [ + { + "name": "scene", + "values": [ + { + "ts": "2022-05-05 00:01:50 +0200", + "val": "off", + "val_t": "string" + } + ] + } + ], + "name": "scene_ctrl" + }, + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:association/ad:6_1", + "attributes": [ + { + "name": "association", + "values": [ + { + "ts": "2022-02-19 16:19:10 +0100", + "val": { + "members": [ + "3_1" + ] + }, + "val_t": "object" + } + ] + } + ], + "name": "association" + }, + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:battery/ad:6_1", + "attributes": [ + { + "name": "lvl", + "values": [ + { + "ts": "2022-05-17 21:50:11 +0200", + "val": 8, + "val_t": "int" + } + ] + } + ], + "name": "battery" + } + ] + }, + { + "id": 190, + "services": [ + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:out_lvl_switch/ad:3_1", + "attributes": [ + { + "name": "lvl", + "values": [ + { + "ts": "2023-01-15 20:44:21 +0100", + "val": 254, + "val_t": "int" + } + ] + }, + { + "name": "binary", + "values": [ + { + "ts": "2023-01-15 20:44:21 +0100", + "val": true, + "val_t": "bool" + } + ] + } + ], + "name": "out_lvl_switch" + }, + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:color_ctrl/ad:3_1", + "attributes": [ + { + "name": "color", + "values": [ + { + "ts": "2023-01-05 00:31:31 +0100", + "val": { + "blue": 0, + "green": 0, + "red": 0 + }, + "val_t": "int_map" + } + ] + } + ], + "name": "color_ctrl" + }, + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:out_bin_switch/ad:3_1", + "attributes": [ + { + "name": "binary", + "values": [ + { + "ts": "2023-03-19 16:44:21 +0100", + "val": false, + "val_t": "bool" + } + ] + } + ], + "name": "out_bin_switch" + } + ] + }, + { + "id": 193, + "services": [ + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:thermostat/ad:9_1", + "attributes": [ + { + "name": "state", + "values": [ + { + "ts": "2022-02-23 00:06:14 +0100", + "val": "Idle", + "val_t": "string" + } + ] + }, + { + "name": "mode", + "values": [ + { + "ts": "2022-02-23 00:06:13 +0100", + "val": "Manual", + "val_t": "string" + } + ] + }, + { + "name": "setpoint", + "values": [ + { + "ts": "2022-02-23 00:06:13 +0100", + "val": { + "temp": "17", + "type": "heat", + "unit": "C" + }, + "val_t": "str_map" + } + ] + } + ], + "name": "thermostat" + }, + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:sensor_temp/ad:9_1", + "attributes": [ + { + "name": "sensor", + "values": [ + { + "props": { + "unit": "C" + }, + "ts": "2022-02-23 00:06:13 +0100", + "val": 21, + "val_t": "float" + } + ] + } + ], + "name": "sensor_temp" + } + ] + }, + { + "id": 196, + "services": [ + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:out_bin_switch/ad:7_1", + "attributes": [ + { + "name": "binary", + "values": [ + { + "ts": "2022-06-02 01:30:25 +0200", + "val": false, + "val_t": "bool" + } + ] + } + ], + "name": "out_bin_switch" + }, + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:meter_elec/ad:7_1", + "attributes": [ + { + "name": "meter_ext", + "values": [ + { + "ts": "2022-06-11 20:09:09 +0200", + "val": { + "i1": 0, + "p_import": 0, + "u1": 236 + }, + "val_t": "float_map" + } + ] + }, + { + "name": "meter", + "values": [ + { + "props": { + "unit": "kWh" + }, + "ts": "2022-06-02 01:36:00 +0200", + "val": 0.168, + "val_t": "float" + } + ] + } + ], + "name": "meter_elec" + } + ] + }, + { + "id": 197, + "services": [ + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:out_bin_switch/ad:5_1", + "attributes": [ + { + "name": "binary", + "values": [ + { + "ts": "2022-06-02 01:33:01 +0200", + "val": false, + "val_t": "bool" + } + ] + } + ], + "name": "out_bin_switch" + }, + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:meter_elec/ad:5_1", + "attributes": [ + { + "name": "meter_ext", + "values": [ + { + "ts": "2022-06-02 01:33:01 +0200", + "val": { + "p_import": 0 + }, + "val_t": "float_map" + } + ] + }, + { + "name": "meter", + "values": [ + { + "props": { + "unit": "kWh" + }, + "ts": "2022-06-02 01:41:04 +0200", + "val": 0.053, + "val_t": "float" + } + ] + } + ], + "name": "meter_elec" + } + ] + }, + { + "id": 199, + "services": [ + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:scene_ctrl/ad:12_1", + "attributes": [ + { + "name": "scene", + "values": [ + { + "ts": "2025-04-22 21:05:49 +0200", + "val": "stop", + "val_t": "string" + } + ] + } + ], + "name": "scene_ctrl" + }, + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:association/ad:12_1", + "attributes": [ + { + "name": "association", + "values": [ + { + "ts": "2022-07-02 15:14:43 +0200", + "val": { + "members": [] + }, + "val_t": "object" + } + ] + } + ], + "name": "association" + }, + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:battery/ad:12_1", + "attributes": [ + { + "name": "lvl", + "values": [ + { + "ts": "2025-04-26 03:31:18 +0200", + "val": 18, + "val_t": "int" + } + ] + } + ], + "name": "battery" + } + ] + }, + { + "id": 201, + "services": [ + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:scene_ctrl/ad:14_1", + "attributes": [ + { + "name": "scene", + "values": [ + { + "ts": "2022-07-02 15:52:33 +0200", + "val": "stop", + "val_t": "string" + } + ] + } + ], + "name": "scene_ctrl" + }, + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:association/ad:14_1", + "attributes": [ + { + "name": "association", + "values": [ + { + "ts": "2022-07-02 15:49:21 +0200", + "val": { + "members": [] + }, + "val_t": "object" + } + ] + } + ], + "name": "association" + }, + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:battery/ad:14_1", + "attributes": [ + { + "name": "lvl", + "values": [ + { + "ts": "2023-01-04 16:16:36 +0100", + "val": 37, + "val_t": "int" + } + ] + } + ], + "name": "battery" + } + ] + }, + { + "id": 204, + "services": [ + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:meter_elec/ad:10_2", + "attributes": [ + { + "name": "meter_ext", + "values": [ + { + "ts": "2025-07-23 19:50:45 +0200", + "val": { + "i1": 0.753, + "p_export_react": 0, + "p_import_react": 13, + "u1": 234.8 + }, + "val_t": "float_map" + } + ] + }, + { + "name": "meter", + "values": [ + { + "props": { + "unit": "kWh" + }, + "ts": "2025-07-23 19:50:51 +0200", + "val": 45071.297, + "val_t": "float" + }, + { + "props": { + "unit": "W" + }, + "ts": "2025-07-23 19:50:51 +0200", + "val": 164, + "val_t": "float" + } + ] + } + ], + "name": "meter_elec" + } + ] + }, + { + "id": 205, + "services": [ + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:meter_elec/ad:11_2", + "attributes": [ + { + "name": "meter_ext", + "values": [ + { + "ts": "2022-11-02 00:02:21 +0100", + "val": { + "i1": 6.551, + "p_export_react": 417, + "p_import_react": 0, + "u1": 237.2 + }, + "val_t": "float_map" + } + ] + }, + { + "name": "meter", + "values": [ + { + "props": { + "unit": "kWh" + }, + "ts": "2022-11-02 00:00:11 +0100", + "val": 37030.806, + "val_t": "float" + }, + { + "props": { + "unit": "W" + }, + "ts": "2022-11-02 00:02:29 +0100", + "val": 3320, + "val_t": "float" + } + ] + } + ], + "name": "meter_elec" + } + ] + }, + { + "id": 206, + "services": [ + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:scene_ctrl/ad:8_1", + "attributes": [ + { + "name": "scene", + "values": [ + { + "ts": "2023-01-15 20:44:23 +0100", + "val": "step down", + "val_t": "string" + } + ] + } + ], + "name": "scene_ctrl" + }, + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:association/ad:8_1", + "attributes": [ + { + "name": "association", + "values": [ + { + "ts": "2023-01-05 00:31:29 +0100", + "val": { + "members": [ + "3_1" + ] + }, + "val_t": "object" + } + ] + } + ], + "name": "association" + }, + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:battery/ad:8_1", + "attributes": [ + { + "name": "lvl", + "values": [ + { + "ts": "2024-02-07 16:47:05 +0100", + "val": 37, + "val_t": "int" + } + ] + } + ], + "name": "battery" + } + ] + }, + { + "id": 208, + "services": [] + }, + { + "id": 209, + "services": [] + }, + { + "id": 210, + "services": [ + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:sensor_temp/ad:1_1", + "attributes": [ + { + "name": "sensor", + "values": [ + { + "props": { + "unit": "C" + }, + "ts": "2024-03-08 19:11:58 +0100", + "val": 14.55, + "val_t": "float" + } + ] + } + ], + "name": "sensor_temp" + }, + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:meter_elec/ad:1_1", + "attributes": [ + { + "name": "meter_ext", + "values": [ + { + "ts": "2024-03-08 19:42:28 +0100", + "val": { + "i1": 1.779, + "p_export_react": 0.001, + "p_import_react": 0, + "u1": 235 + }, + "val_t": "float_map" + } + ] + }, + { + "name": "meter", + "values": [ + { + "props": { + "unit": "kWh" + }, + "ts": "2024-03-08 19:41:32 +0100", + "val": 0, + "val_t": "float" + }, + { + "props": { + "unit": "W" + }, + "ts": "2024-03-08 19:58:08 +0100", + "val": 0, + "val_t": "float" + } + ] + } + ], + "name": "meter_elec" + } + ] + }, + { + "id": 211, + "services": [ + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:out_bin_switch/ad:13_2", + "attributes": [ + { + "name": "binary", + "values": [ + { + "ts": "2025-07-23 19:21:49 +0200", + "val": false, + "val_t": "bool" + } + ] + } + ], + "name": "out_bin_switch" + }, + { + "addr": "/rt:dev/rn:zigbee/ad:1/sv:meter_elec/ad:13_2", + "attributes": [ + { + "name": "meter_ext", + "values": [ + { + "ts": "2025-07-23 19:35:16 +0200", + "val": { + "i1": 0, + "p_export": 0, + "p_import": 0, + "u1": 234.13 + }, + "val_t": "float_map" + } + ] + }, + { + "name": "meter", + "values": [ + { + "props": { + "unit": "kWh" + }, + "ts": "2025-07-23 19:21:49 +0200", + "val": 0.855, + "val_t": "float" + }, + { + "props": { + "unit": "W" + }, + "ts": "2025-07-23 19:21:49 +0200", + "val": 0, + "val_t": "float" + } + ] + } + ], + "name": "meter_elec" + } + ] + } +] diff --git a/futurehome/src/mqtt/interface.ts b/futurehome/src/mqtt/interface.ts new file mode 100644 index 0000000..22f78ef --- /dev/null +++ b/futurehome/src/mqtt/interface.ts @@ -0,0 +1,29 @@ +import { IPublishPacket, OnErrorCallback, OnMessageCallback } from "mqtt/*"; + +export interface IMqttClient { + connect(url: string, options: { + port: number; + username: string; + password: string; + protocolVersion: 4; + }): void; + + subscribe(topic: string): void; + subscribe(topicObject: string, opts?: { qos: 0 | 1 | 2 }, callback?: (err: Error | null) => void): void; + + publish(topic: string, value: string, options: { + retain?: boolean; + qos: 0 | 1 | 2; + }): void; + + on(event: 'message', handler: OnMessageCallback): void; + on(event: 'error', handler: OnErrorCallback): void; + + off(event: 'message', handler: OnMessageCallback): void; + off(event: 'error', handler: OnErrorCallback): void; + + removeListener(event: 'message', handler: (topic: string, payload: Buffer, packet: IPublishPacket) => void): void; + + once(event: 'connect', handler: () => void): void; + once(event: 'error', handler: OnErrorCallback): void; +} \ No newline at end of file diff --git a/futurehome/src/mqtt/real_client.ts b/futurehome/src/mqtt/real_client.ts new file mode 100644 index 0000000..5bc05f4 --- /dev/null +++ b/futurehome/src/mqtt/real_client.ts @@ -0,0 +1,57 @@ +import { connect, IPublishPacket, MqttClient, OnErrorCallback, OnMessageCallback } from 'mqtt'; +import { IMqttClient } from './interface'; + +export class RealMqttClient implements IMqttClient { + private client: MqttClient; + + constructor() { + this.client = {} as MqttClient; // gets initialized in connect() + } + + connect(url: string, options: { + port: number; + username: string; + password: string; + protocolVersion: 4; + }): void { + this.client = connect(url, options); + } + + subscribe(topicObject: string, opts?: { qos: 0 | 1 | 2 }, callback?: (err: Error | null) => void): void; + subscribe(topic: string, opts?: any, callback?: any): void { + if (opts) { + this.client.subscribe(topic, opts, callback); + } else { + this.client.subscribe(topic); + } + } + + publish(topic: string, value: string, options: { + retain?: boolean; + qos: 0 | 1 | 2; + }): void { + this.client.publish(topic, value, options); + } + + on(event: 'message', handler: OnMessageCallback): void; + on(event: 'error', handler: OnErrorCallback): void; + on(event: any, handler: any): void { + this.client.on(event, handler); + } + + off(event: 'message', handler: OnMessageCallback): void; + off(event: 'error', handler: OnErrorCallback): void; + off(event: any, handler: any): void { + this.client.off(event, handler); + } + + removeListener(event: 'message', handler: OnMessageCallback): void { + this.client.removeListener(event, handler); + } + + once(event: 'connect', handler: () => void): void; + once(event: 'error', handler: OnErrorCallback): void; + once(event: any, handler: any): void { + this.client.once(event, handler); + } +}