UNPKG

@ngreatorex/homie-device

Version:
181 lines 7.49 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DefaultConfiguration = void 0; const lodash_1 = __importDefault(require("lodash")); const mqtt_1 = __importDefault(require("mqtt")); const framework_1 = require("./framework"); const HomieNode_1 = __importDefault(require("./HomieNode")); const pkgJson = require("../package.json"); const homieVersion = "3.0.1"; const homieImplName = `nodejs:${pkgJson.name}`; const homieImplVersion = pkgJson.version; const DefaultStatsInterval = 60; exports.DefaultConfiguration = { friendlyName: "unknown", ip: null, mac: null, mqtt: { base_topic: "homie", client: { host: "localhost", password: undefined, port: 1883, username: undefined, }, connectionFactory: mqtt_1.default.connect, }, name: "", settings: {}, statsInterval: DefaultStatsInterval, }; class HomieDevice extends framework_1.HomieTopologyRoot { constructor(config) { super(HomieDevice.interval$(config)); this.interval$ = null; this.node = (config) => { super.assertConfigurable(); this.logger.debug(`Registering new node "${config.friendlyName}" (${config.name})`); return this.nodes$[config.name] = new HomieNode_1.default(this, config); }; this.setup = () => { var _a, _b, _c; const opts = lodash_1.default.merge({}, (_a = this.config.mqtt) === null || _a === void 0 ? void 0 : _a.client, { will: { payload: "lost", qos: 0, retain: true, topic: `${(_b = this.config.mqtt) === null || _b === void 0 ? void 0 : _b.base_topic}/${this.name}/$state`, }, }); if (!this.config.mqtt || typeof ((_c = this.config.mqtt) === null || _c === void 0 ? void 0 : _c.connectionFactory) !== "function") { throw new Error("No mqtt.connectionFactory is configured. This really shouldn't happen."); } this.mqttClient$ = this.client = this.config.mqtt.connectionFactory(opts); this.mqttClient$.on("connect", this.onConnect); this.mqttClient$.on("close", this.onDisconnect); this.mqttClient$.on("offline", this.onOffline); this.mqttClient$.on("error", this.onError); this.mqttClient$.on("message", (topic, payload) => { this.onMessage(topic, payload ? payload.toString() : null); }); this.subscribe(`${this.name}/#`); this.mqttClient$.subscribe(`${this.config.mqtt.base_topic}$broadcast/#`); this.logger.info(`Homie device ${this.config.friendlyName} (${this.config.name}) connected`); }; this.end = () => { if (this.mqttClient$ === null) { throw new Error("client has not been initialized"); } this.publishAttribute("state", "disconnected"); this.mqttClient$.end(); }; this.onConnect = () => { this.logger.verbose("Connected... creating standard publications and subscriptions"); const nodes = []; lodash_1.default.each(this.nodes$, (node) => { const text = node.isRange ? `${node.name}[]` : node.name; nodes.push(text); node.onConnect(); }); this.publishAttributes({ "fw/name": this.config.firmwareName, "fw/version": this.config.firmwareVersion, "homie": homieVersion, "implementation": homieImplName, "implementation/version": homieImplVersion, "localip": this.config.ip, "mac": this.config.mac, "name": this.friendlyName, "nodes": nodes.join(","), "state": "init", "stats": "interval,uptime", }); this.onStatsInterval(); this.interval$ = setInterval(() => { this.onStatsInterval(); }, this.statsInterval$ * 1000); super.onConnect(); this.publishAttribute("state", "ready"); }; this.onDisconnect = () => { super.onDisconnect(); if (this.interval$ != null) { clearInterval(this.interval$); } this.interval$ = null; lodash_1.default.each(this.nodes$, (node) => { node.onDisconnect(); }); }; this.onOffline = () => { super.onOffline(); lodash_1.default.each(this.nodes$, (node) => { node.onOffline(); }); }; this.onError = (err) => { super.onError(err); lodash_1.default.each(this.nodes$, (node) => { node.onError(err); }); }; this.onMessage = (topic, msg) => { const parts = topic.split("/"); const deviceTopic = parts.slice(2).join("/"); this.logger.debug(`received message: parts=${topic}, deviceTopic=${deviceTopic}`); if (parts[1] === "$broadcast") { this.logger.debug(`emitting broadcast for ${deviceTopic}: ${msg}`); this.emit("broadcast", deviceTopic, msg); return; } this.logger.debug(`emitting broadcast for ${deviceTopic}: ${msg}`); this.emit("message", deviceTopic, msg); this.emit(`message:${deviceTopic}`, msg); if (parts[1] === this.name && parts[4] === "set") { let nodeName = parts[2]; const propName = parts[3]; const value = msg; const range = { isRange: false, index: 0 }; if (nodeName.includes("_")) { range.isRange = true; const nodeParts = nodeName.split("_"); nodeName = nodeParts[0]; range.index = parseInt(nodeParts[1], 10); } const node = this.nodes$[nodeName]; if (node && node.isRange === range.isRange) { const prop = node.getProperty(propName); if (prop) { prop.invokeSetter(range, value); } } } }; this.startTime$ = Date.now(); this.nodes$ = {}; this.statsInterval$ = this.config.statsInterval || DefaultStatsInterval; this.mqttClient$ = null; } static interval$(config) { if (lodash_1.default.isString(config)) { config = { name: config, friendlyName: config }; } return lodash_1.default.merge({}, exports.DefaultConfiguration, config); } onStatsInterval() { super.onStatsInterval(); const uptime = (Date.now() - this.startTime$) / 1000; this.publishStats({ interval: this.statsInterval$, uptime: lodash_1.default.round(uptime, 0), }); lodash_1.default.each(this.nodes$, (node) => { node.onStatsInterval(); }); } } exports.default = HomieDevice; //# sourceMappingURL=HomieDevice.js.map