From 40148f21f02516bd73c1a714ac66e4d3dac84c73 Mon Sep 17 00:00:00 2001 From: n-b-dy Date: Sat, 11 Jan 2025 23:20:29 +0100 Subject: [PATCH] chore: release v0.0.3 - Added states for objects with high byte 0x03 with reading and writing - Recreate device objects on adapter restart - Simplified methods for writing fan data based on subscribed states - Added a first unit test for the parsing of numbers. --- README.md | 3 +- build/lib/DataHelpers.js | 54 ++++++++ build/lib/DataHelpers.js.map | 7 + build/lib/ModelData.js | 16 ++- build/lib/ModelData.js.map | 4 +- build/main.js | 76 ++++++----- build/main.js.map | 4 +- io-package.json | 245 +++++++++++++++++++---------------- package-lock.json | 4 +- package.json | 2 +- 10 files changed, 264 insertions(+), 151 deletions(-) create mode 100644 build/lib/DataHelpers.js create mode 100644 build/lib/DataHelpers.js.map diff --git a/README.md b/README.md index a193cfc..dd75038 100644 --- a/README.md +++ b/README.md @@ -63,8 +63,7 @@ This channel contains system data about the hardware and firmware as well as run - Implement missing data points (like time schedule, writing of network data & cloud control) ## Changelog - -### **WORK IN PROGRESS** +### 0.0.3 (2025-01-11) - Added states for objects with high byte 0x03 with reading and writing - Recreate device objects on adapter restart diff --git a/build/lib/DataHelpers.js b/build/lib/DataHelpers.js new file mode 100644 index 0000000..f21df35 --- /dev/null +++ b/build/lib/DataHelpers.js @@ -0,0 +1,54 @@ +"use strict"; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var DataHelpers_exports = {}; +__export(DataHelpers_exports, { + DataHelpers: () => DataHelpers +}); +module.exports = __toCommonJS(DataHelpers_exports); +class DataHelpers { + /** + * Parses the provided ioBroker StateValue to a number. This works either for provided numbers or strings. + * A string is at first parsed as it is. If this does not work, the first space is used to split the string + * and the first part is expected to be a number. In case no space is found, the first characters are parsed + * to a number (any one until the first non-numeric char appers). + * @param value The ioBroker StateValue which is converted to a number. + * @returns The parsed number or NaN in case it could not be parsed. + */ + static ParseInputNumber(value, log) { + if (typeof value !== "number" && typeof value !== "string") { + log == null ? void 0 : log.warn(`The value is not from type number or string, but ${typeof value}`); + return NaN; + } + let nValue = Number(value); + if (typeof value === "string") { + nValue = parseInt(value); + if (isNaN(nValue)) + nValue = parseInt(String(value).substring(0, String(value).indexOf(" "))); + if (isNaN(nValue)) { + log == null ? void 0 : log.warn(`Unable to parse the number from the input value: ${value}`); + } + } + return nValue; + } +} +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + DataHelpers +}); +//# sourceMappingURL=DataHelpers.js.map diff --git a/build/lib/DataHelpers.js.map b/build/lib/DataHelpers.js.map new file mode 100644 index 0000000..a86349b --- /dev/null +++ b/build/lib/DataHelpers.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../../src/lib/DataHelpers.ts"], + "sourcesContent": ["export class DataHelpers {\n /**\n * Parses the provided ioBroker StateValue to a number. This works either for provided numbers or strings.\n * A string is at first parsed as it is. If this does not work, the first space is used to split the string\n * and the first part is expected to be a number. In case no space is found, the first characters are parsed\n * to a number (any one until the first non-numeric char appers).\n * @param value The ioBroker StateValue which is converted to a number.\n * @returns The parsed number or NaN in case it could not be parsed.\n */\n public static ParseInputNumber(value: ioBroker.StateValue, log: ioBroker.Logger | undefined): number {\n if (typeof value !== \"number\" && typeof value !== \"string\") {\n log?.warn(`The value is not from type number or string, but ${typeof value}`);\n return NaN;\n }\n\n let nValue = Number(value);\n\n if (typeof value === \"string\") {\n nValue = parseInt(value);\n\n // Give it a second try, if it was not parsable -> check for the first space as separating character\n if (isNaN(nValue)) nValue = parseInt(String(value).substring(0, String(value).indexOf(\" \")));\n\n if (isNaN(nValue)) {\n log?.warn(`Unable to parse the number from the input value: ${value}`);\n }\n }\n\n return nValue;\n }\n}\n"], + "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,MAAM,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASrB,OAAc,iBAAiB,OAA4B,KAA0C;AACjG,QAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAU;AACxD,iCAAK,KAAK,oDAAoD,OAAO,KAAK;AAC1E,aAAO;AAAA,IACX;AAEA,QAAI,SAAS,OAAO,KAAK;AAEzB,QAAI,OAAO,UAAU,UAAU;AAC3B,eAAS,SAAS,KAAK;AAGvB,UAAI,MAAM,MAAM;AAAG,iBAAS,SAAS,OAAO,KAAK,EAAE,UAAU,GAAG,OAAO,KAAK,EAAE,QAAQ,GAAG,CAAC,CAAC;AAE3F,UAAI,MAAM,MAAM,GAAG;AACf,mCAAK,KAAK,oDAAoD,KAAK;AAAA,MACvE;AAAA,IACJ;AAEA,WAAO;AAAA,EACX;AACJ;", + "names": [] +} diff --git a/build/lib/ModelData.js b/build/lib/ModelData.js index 97a6669..fb61e84 100644 --- a/build/lib/ModelData.js +++ b/build/lib/ModelData.js @@ -21,7 +21,8 @@ __export(ModelData_exports, { DataToSend: () => DataToSend, ParsedData: () => ParsedData, ParsingStatus: () => ParsingStatus, - ReceivedData: () => ReceivedData + ReceivedData: () => ReceivedData, + WriteDataModel: () => WriteDataModel }); module.exports = __toCommonJS(ModelData_exports); class DataToSend { @@ -59,11 +60,22 @@ class ReceivedData { strIdentifer; value; } +class WriteDataModel { + constructor(strFanId, fanData, value) { + this.strFanId = strFanId; + this.fanData = fanData; + this.value = value; + } + strFanId; + fanData; + value; +} // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { DataToSend, ParsedData, ParsingStatus, - ReceivedData + ReceivedData, + WriteDataModel }); //# sourceMappingURL=ModelData.js.map diff --git a/build/lib/ModelData.js.map b/build/lib/ModelData.js.map index 07bb15c..ac15f31 100644 --- a/build/lib/ModelData.js.map +++ b/build/lib/ModelData.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../../src/lib/ModelData.ts"], - "sourcesContent": ["export class DataToSend {\n public constructor(data: Buffer, ipAddress: string) {\n this.data = data;\n this.ipAddress = ipAddress;\n }\n\n public data: Buffer;\n public ipAddress: string;\n}\n\nexport enum ParsingStatus {\n Ok = 1,\n WrongHeader,\n WrongVersion,\n WrongIdSize,\n ChecksumError,\n Undefined,\n}\n\nexport class ParsedData {\n constructor() {\n this.strFanId = \"\";\n this.status = ParsingStatus.Undefined;\n this.receivedData = [];\n }\n\n strFanId: string;\n status: ParsingStatus;\n receivedData: ReceivedData[];\n}\n\nexport class ReceivedData {\n constructor(identifer: string = \"\", value: ioBroker.StateValue = null) {\n this.strIdentifer = identifer;\n this.value = value;\n }\n\n strIdentifer: string;\n value: ioBroker.StateValue;\n}\n"], - "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,MAAM,WAAW;AAAA,EACb,YAAY,MAAc,WAAmB;AAChD,SAAK,OAAO;AACZ,SAAK,YAAY;AAAA,EACrB;AAAA,EAEO;AAAA,EACA;AACX;AAEO,IAAK,gBAAL,kBAAKA,mBAAL;AACH,EAAAA,8BAAA,QAAK,KAAL;AACA,EAAAA,8BAAA;AACA,EAAAA,8BAAA;AACA,EAAAA,8BAAA;AACA,EAAAA,8BAAA;AACA,EAAAA,8BAAA;AANQ,SAAAA;AAAA,GAAA;AASL,MAAM,WAAW;AAAA,EACpB,cAAc;AACV,SAAK,WAAW;AAChB,SAAK,SAAS;AACd,SAAK,eAAe,CAAC;AAAA,EACzB;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AACJ;AAEO,MAAM,aAAa;AAAA,EACtB,YAAY,YAAoB,IAAI,QAA6B,MAAM;AACnE,SAAK,eAAe;AACpB,SAAK,QAAQ;AAAA,EACjB;AAAA,EAEA;AAAA,EACA;AACJ;", + "sourcesContent": ["export class DataToSend {\n public constructor(data: Buffer, ipAddress: string) {\n this.data = data;\n this.ipAddress = ipAddress;\n }\n\n public data: Buffer;\n public ipAddress: string;\n}\n\nexport enum ParsingStatus {\n Ok = 1,\n WrongHeader,\n WrongVersion,\n WrongIdSize,\n ChecksumError,\n Undefined,\n}\n\nexport class ParsedData {\n constructor() {\n this.strFanId = \"\";\n this.status = ParsingStatus.Undefined;\n this.receivedData = [];\n }\n\n strFanId: string;\n status: ParsingStatus;\n receivedData: ReceivedData[];\n}\n\nexport class ReceivedData {\n constructor(identifer: string = \"\", value: ioBroker.StateValue = null) {\n this.strIdentifer = identifer;\n this.value = value;\n }\n\n strIdentifer: string;\n value: ioBroker.StateValue;\n}\n\nexport type FanRemoteEndpoint = { strIpAddress: string; strPassword: string };\n\nexport class WriteDataModel {\n constructor(strFanId: string, fanData: FanRemoteEndpoint, value: ioBroker.StateValue) {\n this.strFanId = strFanId;\n this.fanData = fanData;\n this.value = value;\n }\n\n strFanId: string;\n fanData: FanRemoteEndpoint;\n value: ioBroker.StateValue;\n}\n"], + "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,MAAM,WAAW;AAAA,EACb,YAAY,MAAc,WAAmB;AAChD,SAAK,OAAO;AACZ,SAAK,YAAY;AAAA,EACrB;AAAA,EAEO;AAAA,EACA;AACX;AAEO,IAAK,gBAAL,kBAAKA,mBAAL;AACH,EAAAA,8BAAA,QAAK,KAAL;AACA,EAAAA,8BAAA;AACA,EAAAA,8BAAA;AACA,EAAAA,8BAAA;AACA,EAAAA,8BAAA;AACA,EAAAA,8BAAA;AANQ,SAAAA;AAAA,GAAA;AASL,MAAM,WAAW;AAAA,EACpB,cAAc;AACV,SAAK,WAAW;AAChB,SAAK,SAAS;AACd,SAAK,eAAe,CAAC;AAAA,EACzB;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AACJ;AAEO,MAAM,aAAa;AAAA,EACtB,YAAY,YAAoB,IAAI,QAA6B,MAAM;AACnE,SAAK,eAAe;AACpB,SAAK,QAAQ;AAAA,EACjB;AAAA,EAEA;AAAA,EACA;AACJ;AAIO,MAAM,eAAe;AAAA,EACxB,YAAY,UAAkB,SAA4B,OAA4B;AAClF,SAAK,WAAW;AAChB,SAAK,UAAU;AACf,SAAK,QAAQ;AAAA,EACjB;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AACJ;", "names": ["ParsingStatus"] } diff --git a/build/main.js b/build/main.js index a602779..f7a4e36 100644 --- a/build/main.js +++ b/build/main.js @@ -26,6 +26,7 @@ var DateTime = __toESM(require("date-and-time")); var udp = __toESM(require("dgram")); var NTP = __toESM(require("ntp-time")); var import_queue_fifo = __toESM(require("queue-fifo")); +var import_DataHelpers = require("./lib/DataHelpers"); var import_ModelData = require("./lib/ModelData"); var Oxxify = __toESM(require("./lib/OxxifyProtocol")); class OxxifyFanControl extends utils.Adapter { @@ -166,7 +167,10 @@ class OxxifyFanControl extends utils.Adapter { } } /** - * Is called if a subscribed state changes + * Is called if a subscribed state changes. Here the subscribed states are dispatched for the + * dedicated actions regarding the fans. + * @param strStateIdentifier The state which has changed. + * @param state The new value including meta data from ioBroker. */ onStateChange(strStateIdentifier, state) { if (state) { @@ -176,7 +180,7 @@ class OxxifyFanControl extends utils.Adapter { if (strFanId) { const fanData = this.GetFanDataFromConfig(strFanId); if (fanData) { - const data = new WriteDataModel(strFanId, fanData, state.val); + const data = new import_ModelData.WriteDataModel(strFanId, fanData, state.val); switch (strStateIdentifier.split(".").pop()) { case "boostModeFollowUpTime": this.WriteNumberFanData(data, this.oxxify.WriteBoostModeFollowUpTime.bind(this.oxxify)); @@ -252,6 +256,10 @@ class OxxifyFanControl extends utils.Adapter { this.log.info(`state ${strStateIdentifier} deleted`); } } + /** + * Method to build up the protocol frame to read all data from the fans according to the protocol. + * @param bIncludeConstData True contains the const data like the firmware and the version, false excludes them. + */ ReadAllFanData(bIncludeConstData) { this.config.fans.forEach((element) => { this.oxxify.StartNewFrame(element.id, element.password); @@ -294,6 +302,12 @@ class OxxifyFanControl extends utils.Adapter { this.sendQuene.enqueue(new import_ModelData.DataToSend(packet, element.ipaddr)); }); } + /** + * Parses the fan id from the ioBroker identifer. This fan id has 16 hexadecimal + * characters and is added from the end user by the fan configuration. + * @param strId The identifier from ioBroker for the state, that has changed. + * @returns The fan id if found or undefined. + */ ParseFanId(strId) { const strFanIdRegex = "[0-9A-Fa-f]{16}"; const match = strId.match(strFanIdRegex); @@ -302,14 +316,24 @@ class OxxifyFanControl extends utils.Adapter { } return void 0; } + /** + * Fetchs the configured fan data based on the provided identifier. + * @param strFanId The fan identifier, for which the configuration data is requested. + * @returns The fan config data if found, otherwise undefined. + */ GetFanDataFromConfig(strFanId) { const data = this.config.fans.find((f) => f.id == strFanId); if (data == void 0) return void 0; return { strIpAddress: data.ipaddr, strPassword: data.password }; } + /** + * Generic function to create a protocol frame to write a numeric value to the fan. + * @param data The data to write with necessary fan data as well. + * @param writeNumberMethod The function from the OxxifyProtocol class, which adds the data to write. + */ WriteNumberFanData(data, writeNumberMethod) { - const nValue = this.ParseInputNumber(data.value); + const nValue = import_DataHelpers.DataHelpers.ParseInputNumber(data.value, this.log); if (isNaN(nValue)) return; this.oxxify.StartNewFrame(data.strFanId, data.fanData.strPassword); @@ -318,6 +342,11 @@ class OxxifyFanControl extends utils.Adapter { const packet = this.oxxify.ProtocolPacket; this.sendQuene.enqueue(new import_ModelData.DataToSend(packet, data.fanData.strIpAddress)); } + /** + * Generic function to create a protocol frame to write a string value to the fan. + * @param data The data to write with necessary fan data as well. + * @param writeNumberMethod The function from the OxxifyProtocol class, which adds the data to write. + */ WriteStringFanData(data, writeStringMethod) { this.oxxify.StartNewFrame(data.strFanId, data.fanData.strPassword); writeStringMethod(String(data.value)); @@ -325,6 +354,11 @@ class OxxifyFanControl extends utils.Adapter { const packet = this.oxxify.ProtocolPacket; this.sendQuene.enqueue(new import_ModelData.DataToSend(packet, data.fanData.strIpAddress)); } + /** + * Generic function to create a protocol frame to write a bool value to the fan. + * @param data The data to write with necessary fan data as well. + * @param writeNumberMethod The function from the OxxifyProtocol class, which adds the data to write. + */ WriteBoolFanData(data, writeStringMethod) { if (typeof data.value !== "boolean") { this.log.warn(`The value is not from type boolean.`); @@ -336,6 +370,11 @@ class OxxifyFanControl extends utils.Adapter { const packet = this.oxxify.ProtocolPacket; this.sendQuene.enqueue(new import_ModelData.DataToSend(packet, data.fanData.strIpAddress)); } + /** + * Generic function to create a protocol frame to trigger a funtion at the fan. like reseting stuff. + * @param writeNumberMethod The function from the OxxifyProtocol class, triggers the function. + * @returns void + */ WriteVoidFanData(data, writeVoidMethod) { this.oxxify.StartNewFrame(data.strFanId, data.fanData.strPassword); writeVoidMethod(); @@ -343,6 +382,11 @@ class OxxifyFanControl extends utils.Adapter { const packet = this.oxxify.ProtocolPacket; this.sendQuene.enqueue(new import_ModelData.DataToSend(packet, data.fanData.strIpAddress)); } + /** + * Fetchs the current time from the configured NTP server and writes the date and time to the provided fan. + * @param strFanId The fan id, for which the time sync is processed. + * @param fanData The related fan data to create the protocol frame. + */ SyncRtcClock(strFanId, fanData) { this.ntpClient.syncTime().then((value) => { const dateTime = DateTime.parse(value.time.toISOString(), "YYYY-MM-DD[T]HH:mm:ss.SSS[Z]", true); @@ -369,22 +413,6 @@ class OxxifyFanControl extends utils.Adapter { this.log.error(reason); }); } - ParseInputNumber(value) { - if (typeof value !== "number" && typeof value !== "string") { - this.log.warn(`The value is not from type number or string, but ${typeof value}`); - return NaN; - } - let nValue = Number(value); - if (typeof value === "string") { - nValue = parseInt(value); - if (isNaN(nValue)) - nValue = parseInt(String(value).substring(0, String(value).indexOf(" "))); - if (isNaN(nValue)) { - this.log.warn(`Unable to parse the number from the input value: ${value}`); - } - } - return nValue; - } //#region Protected data members udpServer; oxxify = new Oxxify.OxxifyProtocol(); @@ -399,14 +427,4 @@ if (require.main !== module) { } else { (() => new OxxifyFanControl())(); } -class WriteDataModel { - constructor(strFanId, fanData, value) { - this.strFanId = strFanId; - this.fanData = fanData; - this.value = value; - } - strFanId; - fanData; - value; -} //# sourceMappingURL=main.js.map diff --git a/build/main.js.map b/build/main.js.map index b35dbdb..b70cd26 100644 --- a/build/main.js.map +++ b/build/main.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/main.ts"], - "sourcesContent": ["/*\n * Created with @iobroker/create-adapter v2.6.5\n */\n\n// The adapter-core module gives you access to the core ioBroker functions\n// you need to create an adapter\nimport * as utils from \"@iobroker/adapter-core\";\n\n// Load your modules here, e.g.:\n// import * as fs from \"fs\";\nimport * as DateTime from \"date-and-time\";\nimport * as udp from \"dgram\";\nimport * as NTP from \"ntp-time\";\nimport Queue from \"queue-fifo\";\nimport { DataToSend, ReceivedData } from \"./lib/ModelData\";\nimport * as Oxxify from \"./lib/OxxifyProtocol\";\n\ntype FanRemoteEndpoint = { strIpAddress: string; strPassword: string };\n\nclass OxxifyFanControl extends utils.Adapter {\n public constructor(options: Partial = {}) {\n super({\n ...options,\n name: \"oxxify-fan-control\",\n });\n this.on(\"ready\", this.onReady.bind(this));\n this.on(\"stateChange\", this.onStateChange.bind(this));\n this.on(\"unload\", this.onUnload.bind(this));\n\n this.udpServer = udp.createSocket(\"udp4\");\n }\n\n /**\n * Is called when databases are connected and adapter received configuration.\n */\n private async onReady(): Promise {\n // Initialize your adapter here\n\n // Reset the connection indicator during startup\n await this.setState(\"info.connection\", false, true);\n\n this.log.debug(`NTP-Server: ${this.config.ntpServer}`);\n this.log.debug(`Fan data polling invervall: ${this.config.pollingInterval} seconds`);\n\n this.ntpClient = new NTP.Client(this.config.ntpServer);\n\n if (typeof this.config.fans == \"undefined\" || this.config.fans.length == 0) {\n this.log.error(\"Please set at least one vent in the adapter configuration!\");\n return;\n }\n\n // Remove any old objects and recreate them on adapter start\n if (this.supportsFeature && this.supportsFeature(\"ADAPTER_DEL_OBJECT_RECURSIVE\")) {\n await this.delObjectAsync(\"devices\", { recursive: true });\n }\n\n await this.extendObject(\"devices\", {\n type: \"channel\",\n common: {\n name: {\n en: \"Devices\",\n de: \"Ger\u00E4te\",\n ru: \"\u0423\u0441\u0442\u0440\u043E\u0439\u0441\u0442\u0432\u0430\",\n pt: \"Dispositivos\",\n nl: \"Apparaten\",\n fr: \"Dispositifs\",\n it: \"Dispositivi\",\n es: \"Dispositivos\",\n pl: \"Urz\u0105dzenia\",\n uk: \"\u041F\u0440\u0438\u0441\u0442\u0440\u043E\u0457\",\n \"zh-cn\": \"Devices\",\n },\n role: undefined,\n },\n native: {},\n });\n\n const dataDictionary = this.oxxify.DataDictionary;\n\n this.config.fans.forEach(async (element) => {\n this.log.debug('Fan configured: \"' + element.name + '\": ' + element.id + \" - \" + element.ipaddr);\n\n await this.extendObject(\"devices.\" + element.id, {\n type: \"channel\",\n common: {\n name: element.name,\n role: undefined,\n },\n });\n\n dataDictionary.forEach(async (value: Oxxify.FanData) => {\n await this.extendObject(\"devices.\" + element.id + \".\" + value.strIdentifer, {\n type: \"state\",\n common: {\n name: value.name,\n role: value.strRole,\n read: true,\n write: value.bIsWritable,\n type: value.strType,\n unit: value.strUnit,\n min: value.minValue,\n max: value.maxValue,\n },\n });\n });\n });\n\n // In order to get state updates, you need to subscribe to them. The following line adds a subscription for our variable we have created above.\n // You can also add a subscription for multiple states. The following line watches all states starting with \"lights.\"\n // this.subscribeStates(\"lights.*\");\n // Or, if you really must, you can also watch all states. Don\"t do this if you don\"t need to. Otherwise this will cause a lot of unnecessary load on the system:\n this.subscribeStates(\"devices.*.fan.*\");\n this.subscribeStates(\"devices.*.sensors.state*\");\n this.subscribeStates(\"devices.*.sensors.target*\");\n this.subscribeStates(\"devices.*.system.triggerRtcTimeSync\");\n this.subscribeStates(\"devices.*.system.resetAlarms\");\n\n // emits when any error occurs\n this.udpServer.on(\"error\", (error) => {\n this.log.error(\"Error: \" + error);\n this.udpServer.close();\n });\n\n // emits on new datagram msg\n this.udpServer.on(\"message\", async (msg, info) => {\n // Reset the connection indicator during startup\n await this.setState(\"info.connection\", true, true);\n\n this.log.silly(\n `Received ${msg.length} bytes from ${info.address}:${info.port} - Data: ${msg.toString(\"hex\")}`,\n );\n const data = this.oxxify.ParseResponseData(msg);\n\n if (data.receivedData.length > 0) {\n data.receivedData.forEach(async (value: ReceivedData) => {\n await this.setState(\"devices.\" + data.strFanId + \".\" + value.strIdentifer, value.value, true);\n });\n }\n });\n\n this.udpServer.bind(4001);\n\n // emits when socket is ready and listening for datagram msgs\n this.udpServer.on(\"listening\", async () => {\n const address = this.udpServer.address();\n const port = address.port;\n const family = address.family;\n const ipaddr = address.address;\n this.log.debug(\"Server is listening at: \" + ipaddr + \":\" + port + \" (\" + family + \")\");\n\n this.ReadAllFanData(true);\n });\n\n //emits after the socket is closed using socket.close();\n this.udpServer.on(\"close\", () => {\n this.log.warn(\"Socket is closed\");\n });\n\n this.queneInterval = this.setInterval(() => {\n if (this.sendQuene.isEmpty() == false) {\n const sendData = this.sendQuene.dequeue();\n\n if (sendData != null) {\n this.log.silly(\n \"Sending \" + sendData.data.toString(\"hex\") + \" to \" + sendData.ipAddress + \":\" + 4000,\n );\n this.udpServer.send(sendData.data, 4000, sendData.ipAddress, (err) => {\n if (err != null) this.log.error(err.message);\n });\n }\n }\n }, 25);\n\n this.pollingInterval = this.setInterval(() => {\n this.ReadAllFanData(false);\n }, this.config.pollingInterval * 1000);\n }\n\n /**\n * Is called when adapter shuts down - callback has to be called under any circumstances!\n */\n private onUnload(callback: () => void): void {\n try {\n // Here you must clear all timeouts or intervals that may still be active\n // clearTimeout(timeout1);\n // clearTimeout(timeout2);\n // ...\n this.clearInterval(this.queneInterval);\n this.clearInterval(this.pollingInterval);\n\n this.udpServer.close();\n\n callback();\n } catch (e: any) {\n this.log.error(e.toString());\n callback();\n }\n }\n\n /**\n * Is called if a subscribed state changes\n */\n private onStateChange(strStateIdentifier: string, state: ioBroker.State | null | undefined): void {\n if (state) {\n // The state was changed\n this.log.silly(`state ${strStateIdentifier} changed: ${state.val} (ack = ${state.ack})`);\n\n if (state.ack == false) {\n const strFanId = this.ParseFanId(strStateIdentifier);\n\n if (strFanId) {\n const fanData = this.GetFanDataFromConfig(strFanId);\n\n if (fanData) {\n const data = new WriteDataModel(strFanId, fanData, state.val);\n\n switch (strStateIdentifier.split(\".\").pop()) {\n case \"boostModeFollowUpTime\":\n this.WriteNumberFanData(data, this.oxxify.WriteBoostModeFollowUpTime.bind(this.oxxify));\n break;\n\n case \"fanOperatingMode\":\n this.WriteNumberFanData(data, this.oxxify.WriteOperatingMode.bind(this.oxxify));\n break;\n\n case \"fanSpeedMode\":\n this.WriteNumberFanData(data, this.oxxify.WriteFanSpeedMode.bind(this.oxxify));\n break;\n\n case \"fanState\":\n this.WriteBoolFanData(data, this.oxxify.WriteFanState.bind(this.oxxify));\n break;\n\n case \"manualFanSpeed\":\n this.WriteNumberFanData(data, this.oxxify.WriteManualFanSpeed.bind(this.oxxify));\n break;\n\n case \"nightModeTimerSetpoint\":\n this.WriteStringFanData(\n data,\n this.oxxify.WriteNightModeTimerSetPoint.bind(this.oxxify),\n );\n break;\n\n case \"partyModeTimerSetpoint\":\n this.WriteStringFanData(\n data,\n this.oxxify.WritePartyModeTimerSetPoint.bind(this.oxxify),\n );\n break;\n\n case \"resetFilterExchangeCountdown\":\n this.WriteVoidFanData(\n data,\n this.oxxify.WriteResetFilterExchangeCountdown.bind(this.oxxify),\n );\n break;\n\n case \"timeControlledMode\":\n this.WriteBoolFanData(data, this.oxxify.WriteTimeControlledMode.bind(this.oxxify));\n break;\n\n case \"timerMode\":\n this.WriteNumberFanData(data, this.oxxify.WriteTimerMode.bind(this.oxxify));\n break;\n\n case \"stateAnalogVoltageSensor\":\n this.WriteBoolFanData(\n data,\n this.oxxify.WriteAnalogVoltageSensorState.bind(this.oxxify),\n );\n break;\n\n case \"stateHumiditySensor\":\n this.WriteBoolFanData(data, this.oxxify.WriteHumiditySensorState.bind(this.oxxify));\n break;\n\n case \"stateRelaisSensor\":\n this.WriteBoolFanData(data, this.oxxify.WriteRelaisSensorState.bind(this.oxxify));\n break;\n\n case \"targetAnalogVoltageValue\":\n this.WriteNumberFanData(\n data,\n this.oxxify.WriteTargetAnalogVoltageValue.bind(this.oxxify),\n );\n break;\n\n case \"targetHumidityValue\":\n this.WriteNumberFanData(data, this.oxxify.WriteTargetHumidityValue.bind(this.oxxify));\n break;\n\n case \"resetAlarms\":\n this.WriteVoidFanData(data, this.oxxify.WriteResetAlarmState.bind(this.oxxify));\n break;\n\n case \"triggerRtcTimeSync\":\n this.SyncRtcClock(strFanId, fanData);\n break;\n }\n }\n }\n }\n } else {\n // The state was deleted\n this.log.info(`state ${strStateIdentifier} deleted`);\n }\n }\n\n private ReadAllFanData(bIncludeConstData: boolean): void {\n this.config.fans.forEach((element) => {\n this.oxxify.StartNewFrame(element.id, element.password);\n this.oxxify.ReadFanState();\n this.oxxify.ReadFanSpeedMode();\n this.oxxify.ReadOperatingMode();\n this.oxxify.ReadOperatingTime();\n this.oxxify.ReadBoostState();\n this.oxxify.ReadBoostModeFollowUpTime();\n this.oxxify.ReadRtcBattery();\n this.oxxify.ReadAnalogVoltageSensorState();\n this.oxxify.ReadAlarmState();\n this.oxxify.ReadCloudServerEnabled();\n this.oxxify.ReadHumiditySensorState();\n this.oxxify.ReadRelaisSensorState();\n this.oxxify.ReadCurrentAnalogVoltage();\n this.oxxify.ReadCurrentHumidity();\n this.oxxify.ReadCurrentRelaisState();\n this.oxxify.ReadManualFanSpeed();\n this.oxxify.ReadFan1Speed();\n this.oxxify.ReadFan2Speed();\n this.oxxify.ReadFilterExchangeCountdown();\n this.oxxify.ReadFilterExchangeNecessary();\n this.oxxify.ReadWifiData();\n this.oxxify.ReadTimerModeValues();\n this.oxxify.ReadTargetAnalogVoltageValue();\n this.oxxify.ReadTargetHumidityValue();\n this.oxxify.ReadTimeControlledMode();\n this.oxxify.ReadRtcDateTime();\n if (bIncludeConstData) {\n this.oxxify.ReadFanType();\n this.oxxify.ReadFirmware();\n }\n this.oxxify.ReadNightModeTimerSetPoint();\n this.oxxify.ReadPartyModeTimerSetPoint();\n this.oxxify.ReadHumiditySensorOverSetPoint();\n this.oxxify.ReadAnalogVoltageSensorOverSetPoint();\n this.oxxify.FinishFrame();\n\n const packet = this.oxxify.ProtocolPacket;\n this.sendQuene.enqueue(new DataToSend(packet, element.ipaddr));\n });\n }\n\n private ParseFanId(strId: string): string | undefined {\n const strFanIdRegex = \"[0-9A-Fa-f]{16}\";\n const match = strId.match(strFanIdRegex);\n\n if (match) {\n return match.toString();\n }\n\n return undefined;\n }\n\n private GetFanDataFromConfig(strFanId: string): FanRemoteEndpoint | undefined {\n const data = this.config.fans.find((f) => f.id == strFanId);\n\n if (data == undefined) return undefined;\n\n return { strIpAddress: data.ipaddr, strPassword: data.password };\n }\n\n private WriteNumberFanData(data: WriteDataModel, writeNumberMethod: (nValue: number) => void): void {\n const nValue = this.ParseInputNumber(data.value);\n\n if (isNaN(nValue)) return;\n\n this.oxxify.StartNewFrame(data.strFanId, data.fanData.strPassword);\n writeNumberMethod(nValue);\n this.oxxify.FinishFrame();\n\n const packet = this.oxxify.ProtocolPacket;\n this.sendQuene.enqueue(new DataToSend(packet, data.fanData.strIpAddress));\n }\n\n private WriteStringFanData(data: WriteDataModel, writeStringMethod: (strValue: string) => void): void {\n this.oxxify.StartNewFrame(data.strFanId, data.fanData.strPassword);\n writeStringMethod(String(data.value));\n this.oxxify.FinishFrame();\n\n const packet = this.oxxify.ProtocolPacket;\n this.sendQuene.enqueue(new DataToSend(packet, data.fanData.strIpAddress));\n }\n\n private WriteBoolFanData(data: WriteDataModel, writeStringMethod: (bValue: boolean) => void): void {\n if (typeof data.value !== \"boolean\") {\n this.log.warn(`The value is not from type boolean.`);\n return;\n }\n\n this.oxxify.StartNewFrame(data.strFanId, data.fanData.strPassword);\n writeStringMethod(Boolean(data.value));\n this.oxxify.FinishFrame();\n\n const packet = this.oxxify.ProtocolPacket;\n this.sendQuene.enqueue(new DataToSend(packet, data.fanData.strIpAddress));\n }\n\n private WriteVoidFanData(data: WriteDataModel, writeVoidMethod: () => void): void {\n this.oxxify.StartNewFrame(data.strFanId, data.fanData.strPassword);\n writeVoidMethod();\n this.oxxify.FinishFrame();\n\n const packet = this.oxxify.ProtocolPacket;\n this.sendQuene.enqueue(new DataToSend(packet, data.fanData.strIpAddress));\n }\n\n private SyncRtcClock(strFanId: string, fanData: FanRemoteEndpoint): void {\n this.ntpClient\n .syncTime()\n .then((value: NTP.NTPPacket) => {\n const dateTime = DateTime.parse(value.time.toISOString(), \"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]\", true);\n this.log.debug(\"Received local time via ntp: \" + dateTime.toLocaleString());\n\n this.oxxify.StartNewFrame(strFanId, fanData.strPassword);\n this.oxxify.WriteRtcDateTime(dateTime);\n this.oxxify.FinishFrame();\n\n const packet = this.oxxify.ProtocolPacket;\n\n // Immediately send the data, as any delay would make the time sync invalid\n this.udpServer.send(packet, 4000, fanData.strIpAddress, (err) => {\n if (err != null) {\n this.log.error(err.message);\n } else {\n // Retrigger a reading of the data, as a RTC write does not immediately return the right values\n this.oxxify.StartNewFrame(strFanId, fanData.strPassword);\n this.oxxify.ReadRtcDateTime();\n this.oxxify.FinishFrame();\n\n const packet = this.oxxify.ProtocolPacket;\n const timeout = this.setTimeout(() => {\n this.sendQuene.enqueue(new DataToSend(packet, fanData.strIpAddress));\n this.clearTimeout(timeout);\n }, 1000);\n }\n });\n })\n .catch((reason: any) => {\n this.log.error(reason);\n });\n }\n\n private ParseInputNumber(value: ioBroker.StateValue): number {\n if (typeof value !== \"number\" && typeof value !== \"string\") {\n this.log.warn(`The value is not from type number or string, but ${typeof value}`);\n return NaN;\n }\n\n let nValue = Number(value);\n\n if (typeof value === \"string\") {\n nValue = parseInt(value);\n\n // Give it a second try, if it was not parsable -> check for the first space as separating character\n if (isNaN(nValue)) nValue = parseInt(String(value).substring(0, String(value).indexOf(\" \")));\n\n if (isNaN(nValue)) {\n this.log.warn(`Unable to parse the number from the input value: ${value}`);\n }\n }\n\n return nValue;\n }\n\n //#region Protected data members\n\n udpServer: udp.Socket;\n oxxify: Oxxify.OxxifyProtocol = new Oxxify.OxxifyProtocol();\n sendQuene: Queue = new Queue();\n queneInterval: ioBroker.Interval | undefined;\n pollingInterval: ioBroker.Interval | undefined;\n ntpClient: NTP.Client = new NTP.Client();\n\n //#endregion\n}\n\nif (require.main !== module) {\n // Export the constructor in compact mode\n module.exports = (options: Partial | undefined) => new OxxifyFanControl(options);\n} else {\n // otherwise start the instance directly\n (() => new OxxifyFanControl())();\n}\n\nclass WriteDataModel {\n constructor(strFanId: string, fanData: FanRemoteEndpoint, value: ioBroker.StateValue) {\n this.strFanId = strFanId;\n this.fanData = fanData;\n this.value = value;\n }\n strFanId: string;\n fanData: FanRemoteEndpoint;\n value: ioBroker.StateValue;\n}\n"], - "mappings": "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", + "sourcesContent": ["/*\n * Created with @iobroker/create-adapter v2.6.5\n */\n\n// The adapter-core module gives you access to the core ioBroker functions\n// you need to create an adapter\nimport * as utils from \"@iobroker/adapter-core\";\n\n// Load your modules here, e.g.:\n// import * as fs from \"fs\";\nimport * as DateTime from \"date-and-time\";\nimport * as udp from \"dgram\";\nimport * as NTP from \"ntp-time\";\nimport Queue from \"queue-fifo\";\nimport { DataHelpers } from \"./lib/DataHelpers\";\nimport { DataToSend, FanRemoteEndpoint, ReceivedData, WriteDataModel } from \"./lib/ModelData\";\nimport * as Oxxify from \"./lib/OxxifyProtocol\";\n\n/**\n * The main class for this adapter.\n */\nclass OxxifyFanControl extends utils.Adapter {\n public constructor(options: Partial = {}) {\n super({\n ...options,\n name: \"oxxify-fan-control\",\n });\n this.on(\"ready\", this.onReady.bind(this));\n this.on(\"stateChange\", this.onStateChange.bind(this));\n this.on(\"unload\", this.onUnload.bind(this));\n\n this.udpServer = udp.createSocket(\"udp4\");\n }\n\n /**\n * Is called when databases are connected and adapter received configuration.\n */\n private async onReady(): Promise {\n // Reset the connection indicator during startup\n await this.setState(\"info.connection\", false, true);\n\n this.log.debug(`NTP-Server: ${this.config.ntpServer}`);\n this.log.debug(`Fan data polling invervall: ${this.config.pollingInterval} seconds`);\n\n this.ntpClient = new NTP.Client(this.config.ntpServer);\n\n if (typeof this.config.fans == \"undefined\" || this.config.fans.length == 0) {\n this.log.error(\"Please set at least one vent in the adapter configuration!\");\n return;\n }\n\n // Remove any old objects and recreate them on adapter start\n if (this.supportsFeature && this.supportsFeature(\"ADAPTER_DEL_OBJECT_RECURSIVE\")) {\n await this.delObjectAsync(\"devices\", { recursive: true });\n }\n\n await this.extendObject(\"devices\", {\n type: \"channel\",\n common: {\n name: {\n en: \"Devices\",\n de: \"Ger\u00E4te\",\n ru: \"\u0423\u0441\u0442\u0440\u043E\u0439\u0441\u0442\u0432\u0430\",\n pt: \"Dispositivos\",\n nl: \"Apparaten\",\n fr: \"Dispositifs\",\n it: \"Dispositivi\",\n es: \"Dispositivos\",\n pl: \"Urz\u0105dzenia\",\n uk: \"\u041F\u0440\u0438\u0441\u0442\u0440\u043E\u0457\",\n \"zh-cn\": \"Devices\",\n },\n role: undefined,\n },\n native: {},\n });\n\n const dataDictionary = this.oxxify.DataDictionary;\n\n this.config.fans.forEach(async (element) => {\n this.log.debug('Fan configured: \"' + element.name + '\": ' + element.id + \" - \" + element.ipaddr);\n\n await this.extendObject(\"devices.\" + element.id, {\n type: \"channel\",\n common: {\n name: element.name,\n role: undefined,\n },\n });\n\n dataDictionary.forEach(async (value: Oxxify.FanData) => {\n await this.extendObject(\"devices.\" + element.id + \".\" + value.strIdentifer, {\n type: \"state\",\n common: {\n name: value.name,\n role: value.strRole,\n read: true,\n write: value.bIsWritable,\n type: value.strType,\n unit: value.strUnit,\n min: value.minValue,\n max: value.maxValue,\n },\n });\n });\n });\n\n // In order to get state updates, you need to subscribe to them. The following line adds a subscription for our variable we have created above.\n this.subscribeStates(\"devices.*.fan.*\");\n this.subscribeStates(\"devices.*.sensors.state*\");\n this.subscribeStates(\"devices.*.sensors.target*\");\n this.subscribeStates(\"devices.*.system.triggerRtcTimeSync\");\n this.subscribeStates(\"devices.*.system.resetAlarms\");\n\n // Emits when any error occurs\n this.udpServer.on(\"error\", (error) => {\n this.log.error(\"Error: \" + error);\n this.udpServer.close();\n });\n\n // Emits on new datagram msg\n this.udpServer.on(\"message\", async (msg, info) => {\n // Reset the connection indicator during startup\n await this.setState(\"info.connection\", true, true);\n\n this.log.silly(\n `Received ${msg.length} bytes from ${info.address}:${info.port} - Data: ${msg.toString(\"hex\")}`,\n );\n const data = this.oxxify.ParseResponseData(msg);\n\n if (data.receivedData.length > 0) {\n data.receivedData.forEach(async (value: ReceivedData) => {\n await this.setState(\"devices.\" + data.strFanId + \".\" + value.strIdentifer, value.value, true);\n });\n }\n });\n\n this.udpServer.bind(4001);\n\n // emits when socket is ready and listening for datagram msgs\n this.udpServer.on(\"listening\", async () => {\n const address = this.udpServer.address();\n const port = address.port;\n const family = address.family;\n const ipaddr = address.address;\n this.log.debug(\"Server is listening at: \" + ipaddr + \":\" + port + \" (\" + family + \")\");\n\n this.ReadAllFanData(true);\n });\n\n //emits after the socket is closed using socket.close();\n this.udpServer.on(\"close\", () => {\n this.log.warn(\"Socket is closed\");\n });\n\n this.queneInterval = this.setInterval(() => {\n if (this.sendQuene.isEmpty() == false) {\n const sendData = this.sendQuene.dequeue();\n\n if (sendData != null) {\n this.log.silly(\n \"Sending \" + sendData.data.toString(\"hex\") + \" to \" + sendData.ipAddress + \":\" + 4000,\n );\n this.udpServer.send(sendData.data, 4000, sendData.ipAddress, (err) => {\n if (err != null) this.log.error(err.message);\n });\n }\n }\n }, 25);\n\n this.pollingInterval = this.setInterval(() => {\n this.ReadAllFanData(false);\n }, this.config.pollingInterval * 1000);\n }\n\n /**\n * Is called when adapter shuts down - callback has to be called under any circumstances!\n */\n private onUnload(callback: () => void): void {\n try {\n // Here you must clear all timeouts or intervals that may still be active\n // clearTimeout(timeout1);\n // clearTimeout(timeout2);\n // ...\n this.clearInterval(this.queneInterval);\n this.clearInterval(this.pollingInterval);\n\n this.udpServer.close();\n\n callback();\n } catch (e: any) {\n this.log.error(e.toString());\n callback();\n }\n }\n\n /**\n * Is called if a subscribed state changes. Here the subscribed states are dispatched for the\n * dedicated actions regarding the fans.\n * @param strStateIdentifier The state which has changed.\n * @param state The new value including meta data from ioBroker.\n */\n private onStateChange(strStateIdentifier: string, state: ioBroker.State | null | undefined): void {\n if (state) {\n // The state was changed\n this.log.silly(`state ${strStateIdentifier} changed: ${state.val} (ack = ${state.ack})`);\n\n if (state.ack == false) {\n const strFanId = this.ParseFanId(strStateIdentifier);\n\n if (strFanId) {\n const fanData = this.GetFanDataFromConfig(strFanId);\n\n if (fanData) {\n const data = new WriteDataModel(strFanId, fanData, state.val);\n\n switch (strStateIdentifier.split(\".\").pop()) {\n case \"boostModeFollowUpTime\":\n this.WriteNumberFanData(data, this.oxxify.WriteBoostModeFollowUpTime.bind(this.oxxify));\n break;\n\n case \"fanOperatingMode\":\n this.WriteNumberFanData(data, this.oxxify.WriteOperatingMode.bind(this.oxxify));\n break;\n\n case \"fanSpeedMode\":\n this.WriteNumberFanData(data, this.oxxify.WriteFanSpeedMode.bind(this.oxxify));\n break;\n\n case \"fanState\":\n this.WriteBoolFanData(data, this.oxxify.WriteFanState.bind(this.oxxify));\n break;\n\n case \"manualFanSpeed\":\n this.WriteNumberFanData(data, this.oxxify.WriteManualFanSpeed.bind(this.oxxify));\n break;\n\n case \"nightModeTimerSetpoint\":\n this.WriteStringFanData(\n data,\n this.oxxify.WriteNightModeTimerSetPoint.bind(this.oxxify),\n );\n break;\n\n case \"partyModeTimerSetpoint\":\n this.WriteStringFanData(\n data,\n this.oxxify.WritePartyModeTimerSetPoint.bind(this.oxxify),\n );\n break;\n\n case \"resetFilterExchangeCountdown\":\n this.WriteVoidFanData(\n data,\n this.oxxify.WriteResetFilterExchangeCountdown.bind(this.oxxify),\n );\n break;\n\n case \"timeControlledMode\":\n this.WriteBoolFanData(data, this.oxxify.WriteTimeControlledMode.bind(this.oxxify));\n break;\n\n case \"timerMode\":\n this.WriteNumberFanData(data, this.oxxify.WriteTimerMode.bind(this.oxxify));\n break;\n\n case \"stateAnalogVoltageSensor\":\n this.WriteBoolFanData(\n data,\n this.oxxify.WriteAnalogVoltageSensorState.bind(this.oxxify),\n );\n break;\n\n case \"stateHumiditySensor\":\n this.WriteBoolFanData(data, this.oxxify.WriteHumiditySensorState.bind(this.oxxify));\n break;\n\n case \"stateRelaisSensor\":\n this.WriteBoolFanData(data, this.oxxify.WriteRelaisSensorState.bind(this.oxxify));\n break;\n\n case \"targetAnalogVoltageValue\":\n this.WriteNumberFanData(\n data,\n this.oxxify.WriteTargetAnalogVoltageValue.bind(this.oxxify),\n );\n break;\n\n case \"targetHumidityValue\":\n this.WriteNumberFanData(data, this.oxxify.WriteTargetHumidityValue.bind(this.oxxify));\n break;\n\n case \"resetAlarms\":\n this.WriteVoidFanData(data, this.oxxify.WriteResetAlarmState.bind(this.oxxify));\n break;\n\n case \"triggerRtcTimeSync\":\n this.SyncRtcClock(strFanId, fanData);\n break;\n }\n }\n }\n }\n } else {\n // The state was deleted\n this.log.info(`state ${strStateIdentifier} deleted`);\n }\n }\n\n /**\n * Method to build up the protocol frame to read all data from the fans according to the protocol.\n * @param bIncludeConstData True contains the const data like the firmware and the version, false excludes them.\n */\n private ReadAllFanData(bIncludeConstData: boolean): void {\n this.config.fans.forEach((element) => {\n this.oxxify.StartNewFrame(element.id, element.password);\n this.oxxify.ReadFanState();\n this.oxxify.ReadFanSpeedMode();\n this.oxxify.ReadOperatingMode();\n this.oxxify.ReadOperatingTime();\n this.oxxify.ReadBoostState();\n this.oxxify.ReadBoostModeFollowUpTime();\n this.oxxify.ReadRtcBattery();\n this.oxxify.ReadAnalogVoltageSensorState();\n this.oxxify.ReadAlarmState();\n this.oxxify.ReadCloudServerEnabled();\n this.oxxify.ReadHumiditySensorState();\n this.oxxify.ReadRelaisSensorState();\n this.oxxify.ReadCurrentAnalogVoltage();\n this.oxxify.ReadCurrentHumidity();\n this.oxxify.ReadCurrentRelaisState();\n this.oxxify.ReadManualFanSpeed();\n this.oxxify.ReadFan1Speed();\n this.oxxify.ReadFan2Speed();\n this.oxxify.ReadFilterExchangeCountdown();\n this.oxxify.ReadFilterExchangeNecessary();\n this.oxxify.ReadWifiData();\n this.oxxify.ReadTimerModeValues();\n this.oxxify.ReadTargetAnalogVoltageValue();\n this.oxxify.ReadTargetHumidityValue();\n this.oxxify.ReadTimeControlledMode();\n this.oxxify.ReadRtcDateTime();\n if (bIncludeConstData) {\n this.oxxify.ReadFanType();\n this.oxxify.ReadFirmware();\n }\n this.oxxify.ReadNightModeTimerSetPoint();\n this.oxxify.ReadPartyModeTimerSetPoint();\n this.oxxify.ReadHumiditySensorOverSetPoint();\n this.oxxify.ReadAnalogVoltageSensorOverSetPoint();\n this.oxxify.FinishFrame();\n\n const packet = this.oxxify.ProtocolPacket;\n this.sendQuene.enqueue(new DataToSend(packet, element.ipaddr));\n });\n }\n\n /**\n * Parses the fan id from the ioBroker identifer. This fan id has 16 hexadecimal\n * characters and is added from the end user by the fan configuration.\n * @param strId The identifier from ioBroker for the state, that has changed.\n * @returns The fan id if found or undefined.\n */\n private ParseFanId(strId: string): string | undefined {\n const strFanIdRegex = \"[0-9A-Fa-f]{16}\";\n const match = strId.match(strFanIdRegex);\n\n if (match) {\n return match.toString();\n }\n\n return undefined;\n }\n\n /**\n * Fetchs the configured fan data based on the provided identifier.\n * @param strFanId The fan identifier, for which the configuration data is requested.\n * @returns The fan config data if found, otherwise undefined.\n */\n private GetFanDataFromConfig(strFanId: string): FanRemoteEndpoint | undefined {\n const data = this.config.fans.find((f) => f.id == strFanId);\n\n if (data == undefined) return undefined;\n\n return { strIpAddress: data.ipaddr, strPassword: data.password };\n }\n\n /**\n * Generic function to create a protocol frame to write a numeric value to the fan.\n * @param data The data to write with necessary fan data as well.\n * @param writeNumberMethod The function from the OxxifyProtocol class, which adds the data to write.\n */\n private WriteNumberFanData(data: WriteDataModel, writeNumberMethod: (nValue: number) => void): void {\n const nValue = DataHelpers.ParseInputNumber(data.value, this.log);\n\n if (isNaN(nValue)) return;\n\n this.oxxify.StartNewFrame(data.strFanId, data.fanData.strPassword);\n writeNumberMethod(nValue);\n this.oxxify.FinishFrame();\n\n const packet = this.oxxify.ProtocolPacket;\n this.sendQuene.enqueue(new DataToSend(packet, data.fanData.strIpAddress));\n }\n\n /**\n * Generic function to create a protocol frame to write a string value to the fan.\n * @param data The data to write with necessary fan data as well.\n * @param writeNumberMethod The function from the OxxifyProtocol class, which adds the data to write.\n */\n private WriteStringFanData(data: WriteDataModel, writeStringMethod: (strValue: string) => void): void {\n this.oxxify.StartNewFrame(data.strFanId, data.fanData.strPassword);\n writeStringMethod(String(data.value));\n this.oxxify.FinishFrame();\n\n const packet = this.oxxify.ProtocolPacket;\n this.sendQuene.enqueue(new DataToSend(packet, data.fanData.strIpAddress));\n }\n\n /**\n * Generic function to create a protocol frame to write a bool value to the fan.\n * @param data The data to write with necessary fan data as well.\n * @param writeNumberMethod The function from the OxxifyProtocol class, which adds the data to write.\n */\n private WriteBoolFanData(data: WriteDataModel, writeStringMethod: (bValue: boolean) => void): void {\n if (typeof data.value !== \"boolean\") {\n this.log.warn(`The value is not from type boolean.`);\n return;\n }\n\n this.oxxify.StartNewFrame(data.strFanId, data.fanData.strPassword);\n writeStringMethod(Boolean(data.value));\n this.oxxify.FinishFrame();\n\n const packet = this.oxxify.ProtocolPacket;\n this.sendQuene.enqueue(new DataToSend(packet, data.fanData.strIpAddress));\n }\n\n /**\n * Generic function to create a protocol frame to trigger a funtion at the fan. like reseting stuff.\n * @param writeNumberMethod The function from the OxxifyProtocol class, triggers the function.\n * @returns void\n */\n private WriteVoidFanData(data: WriteDataModel, writeVoidMethod: () => void): void {\n this.oxxify.StartNewFrame(data.strFanId, data.fanData.strPassword);\n writeVoidMethod();\n this.oxxify.FinishFrame();\n\n const packet = this.oxxify.ProtocolPacket;\n this.sendQuene.enqueue(new DataToSend(packet, data.fanData.strIpAddress));\n }\n\n /**\n * Fetchs the current time from the configured NTP server and writes the date and time to the provided fan.\n * @param strFanId The fan id, for which the time sync is processed.\n * @param fanData The related fan data to create the protocol frame.\n */\n private SyncRtcClock(strFanId: string, fanData: FanRemoteEndpoint): void {\n this.ntpClient\n .syncTime()\n .then((value: NTP.NTPPacket) => {\n const dateTime = DateTime.parse(value.time.toISOString(), \"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]\", true);\n this.log.debug(\"Received local time via ntp: \" + dateTime.toLocaleString());\n this.oxxify.StartNewFrame(strFanId, fanData.strPassword);\n this.oxxify.WriteRtcDateTime(dateTime);\n this.oxxify.FinishFrame();\n\n const packet = this.oxxify.ProtocolPacket;\n\n // Immediately send the data, as any delay would make the time sync invalid\n this.udpServer.send(packet, 4000, fanData.strIpAddress, (err) => {\n if (err != null) {\n this.log.error(err.message);\n } else {\n // Retrigger a reading of the data, as a RTC write does not immediately return the right values\n this.oxxify.StartNewFrame(strFanId, fanData.strPassword);\n this.oxxify.ReadRtcDateTime();\n this.oxxify.FinishFrame();\n\n const packet = this.oxxify.ProtocolPacket;\n const timeout = this.setTimeout(() => {\n this.sendQuene.enqueue(new DataToSend(packet, fanData.strIpAddress));\n this.clearTimeout(timeout);\n }, 1000);\n }\n });\n })\n .catch((reason: any) => {\n this.log.error(reason);\n });\n }\n\n //#region Protected data members\n\n udpServer: udp.Socket;\n oxxify: Oxxify.OxxifyProtocol = new Oxxify.OxxifyProtocol();\n sendQuene: Queue = new Queue();\n queneInterval: ioBroker.Interval | undefined;\n pollingInterval: ioBroker.Interval | undefined;\n ntpClient: NTP.Client = new NTP.Client();\n\n //#endregion\n}\n\nif (require.main !== module) {\n // Export the constructor in compact mode\n module.exports = (options: Partial | undefined) => new OxxifyFanControl(options);\n} else {\n // otherwise start the instance directly\n (() => new OxxifyFanControl())();\n}\n"], + "mappings": "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", "names": ["packet", "Queue"] } diff --git a/io-package.json b/io-package.json index 2719439..95e67c4 100644 --- a/io-package.json +++ b/io-package.json @@ -1,116 +1,139 @@ { - "common": { - "name": "oxxify-fan-control", - "version": "0.0.2", - "news": { - "0.0.2": { - "en": "initial release", - "de": "erstausstrahlung", - "ru": "первоначальный выпуск", - "pt": "lançamento inicial", - "nl": "eerste release", - "fr": "libération initiale", - "it": "rilascio iniziale", - "es": "liberación inicial", - "pl": "początkowe zwolnienie", - "uk": "початковий реліз", - "zh-cn": "初步释放" - } - }, - "titleLang": { - "en": "Oxxify Fan Control", - "de": "Oxxify-Lüftersteuerung", - "ru": "Управление вентилятором Oxxify", - "pt": "Controle de ventilador Oxxify", - "nl": "Oxxify-ventilatorbediening", - "fr": "Contrôle du ventilateur Oxxify", - "it": "Controllo della ventola Oxxify", - "es": "Control del ventilador Oxxify", - "pl": "Sterowanie wentylatorem Oxxify", - "uk": "Контроль вентиляторів Oxxify", - "zh-cn": "Oxxify 风扇控制" - }, - "desc": { - "en": "Integrate your Oxxify Fans into your Smart Home.", - "de": "Integrieren Sie Ihre Oxxify-Lüfter in Ihr Smart Home.", - "ru": "Интегрируйте вентиляторы Oxxify в свой умный дом.", - "pt": "Integre seus fãs Oxxify em sua casa inteligente.", - "nl": "Integreer je Oxxify Fans in je Smart Home.", - "fr": "Intégrez vos ventilateurs Oxxify dans votre maison intelligente.", - "it": "Integra i tuoi fan Oxxify nella tua casa intelligente.", - "es": "Integra tus Fans Oxxify en tu Hogar Inteligente.", - "pl": "Zintegruj swoich fanów Oxxify ze swoim inteligentnym domem.", - "uk": "Інтегруйте вентилятори Oxxify у свій розумний дім.", - "zh-cn": "将您的 Oxxify 风扇集成到您的智能家居中。" - }, - "authors": ["N-b-dy "], - "keywords": ["oxxify", "fan", "ventilation"], - "licenseInformation": { - "type": "free", - "license": "GPL-3.0-or-later" - }, - "platform": "Javascript/Node.js", - "icon": "oxxify-fan-control.png", - "enabled": true, - "extIcon": "https://raw.githubusercontent.com/N-b-dy/ioBroker.oxxify-fan-control/main/admin/oxxify-fan-control.png", - "readme": "https://github.com/N-b-dy/ioBroker.oxxify-fan-control/blob/main/README.md", - "loglevel": "info", - "tier": 3, - "mode": "daemon", - "type": "climate-control", - "compact": true, - "connectionType": "local", - "dataSource": "poll", - "adminUI": { - "config": "json" - }, - "dependencies": [ - { - "js-controller": ">=6.0.11" - } - ], - "globalDependencies": [ - { - "admin": ">=7.1.3" - } - ] + "common": { + "name": "oxxify-fan-control", + "version": "0.0.3", + "news": { + "0.0.3": { + "en": "- Added states for objects with high byte 0x03 with reading and writing\n- Recreate device objects on adapter restart\n- Simplified methods for writing fan data based on subscribed states\n- Added a first unit test for the parsing of numbers.\n\n", + "de": "- Hinzugefügt Zustände für Objekte mit hohem Byte 0x03 mit Lesen und Schreiben\n- Geräteobjekte auf Adapter neu starten\n- Vereinfachte Methoden zum Schreiben von Fandaten basierend auf abonnierten Zuständen\n- Es wurde ein erster Einzeltest für die Parsierung von Zahlen hinzugefügt.\n\n", + "ru": "- Добавленные состояния для объектов с высоким байтом 0x03 с чтением и написанием\n- Восстановление объектов устройства при перезагрузке адаптера\n- Упрощенные методы для написания фан-данных на основе подписанных государств\n- Добавлено первое единичное испытание для выравнивания чисел.\n\n", + "pt": "- estados adicionados para objetos com alto byte 0x03 com leitura e escrita\n- Recriar objetos de dispositivo no reinício do adaptador\n- Métodos simplificados para escrever dados de fãs com base em estados subscritos\n- Adicionado um primeiro teste de unidade para a análise de números.\n\n", + "nl": "- Toegevoegd toestanden voor objecten met hoge byte 0x03 met lezen en schrijven\n- Apparaatobjecten op adapter herstarten\n- Vereenvoudigde methoden voor het schrijven van fangegevens op basis van de ingeschreven staten\n- Een eerste test toegevoegd voor het verwerken van getallen.\n\n", + "fr": "- Ajout d'états pour les objets avec haut octet 0x03 avec lecture et écriture\n- Recréer les objets du périphérique lors du redémarrage de l'adaptateur\n- Méthodes simplifiées pour l'écriture des données des ventilateurs basées sur les états souscrits\n- Ajout d'un premier test unitaire pour l'analyse des nombres.\n\n", + "it": "- Aggiunti stati per oggetti con byte 0x03 alto con lettura e scrittura\n- Riattivare gli oggetti del dispositivo sul riavvio dell'adattatore\n- Metodi semplificati per la scrittura dei dati dei fan in base agli stati iscritti\n- Aggiunto un primo test unitario per la parsing dei numeri.\n\n", + "es": "- Estados añadidos para objetos con alto byte 0x03 con lectura y escritura\n- Recrear objetos de dispositivo en el reinicio del adaptador\n- Métodos simplificados para escribir datos de fans basados en estados suscritos\n- Se agregó una primera prueba de unidad para el perfeccionamiento de números.\n\n", + "pl": "- Dodano stany dla obiektów o wysokim bajcie 0x03 z czytaniem i pisaniem\n- Regeneracja obiektów urządzenia przy ponownym uruchomieniu adaptera\n- Uproszczone metody zapisu danych fanów na podstawie subskrybowanych stanów\n- Dodano pierwszy test jednostkowy na parsowanie liczb.\n\n", + "uk": "- Додано стани для об'єктів з високим байтом 0x03 з читанням та письмовим записом\n- Відтворити об'єкти пристроїв на перезавантаженні адаптера\n- Спрощені методи написання даних вентилятора на основі підписаних штатів\n- Додано тест першого блоку для парсингу чисел.\n\n", + "zh-cn": "- 对有读写功能的高字节0x03的对象添加状态\n- 在适配器重新启动时重建设备对象\n- 简化根据订阅状态编写风扇数据的方法\n- 增加了第一个数字解析单元测试.\n\n" + }, + "0.0.2": { + "en": "initial release", + "de": "erstausstrahlung", + "ru": "первоначальный выпуск", + "pt": "lançamento inicial", + "nl": "eerste release", + "fr": "libération initiale", + "it": "rilascio iniziale", + "es": "liberación inicial", + "pl": "początkowe zwolnienie", + "uk": "початковий реліз", + "zh-cn": "初步释放" + } }, - "native": { - "pollingInterval": 5, - "ntpServer": "0.de.pool.ntp.org", - "fans": [ - { - "name": "fan1", - "id": "1234567890123456", - "ipaddr": "192.168.1.1", - "password": "topsecret" - } - ] + "titleLang": { + "en": "Oxxify Fan Control", + "de": "Oxxify-Lüftersteuerung", + "ru": "Управление вентилятором Oxxify", + "pt": "Controle de ventilador Oxxify", + "nl": "Oxxify-ventilatorbediening", + "fr": "Contrôle du ventilateur Oxxify", + "it": "Controllo della ventola Oxxify", + "es": "Control del ventilador Oxxify", + "pl": "Sterowanie wentylatorem Oxxify", + "uk": "Контроль вентиляторів Oxxify", + "zh-cn": "Oxxify 风扇控制" }, - "protectedNative": ["fans.password"], - "encryptedNative": ["fans.password"], - "objects": [], - "instanceObjects": [ - { - "_id": "info", - "type": "channel", - "common": { - "name": "Information" - }, - "native": {} - }, - { - "_id": "info.connection", - "type": "state", - "common": { - "role": "indicator.connected", - "name": "Device or service connected", - "type": "boolean", - "read": true, - "write": false, - "def": false - }, - "native": {} - } + "desc": { + "en": "Integrate your Oxxify Fans into your Smart Home.", + "de": "Integrieren Sie Ihre Oxxify-Lüfter in Ihr Smart Home.", + "ru": "Интегрируйте вентиляторы Oxxify в свой умный дом.", + "pt": "Integre seus fãs Oxxify em sua casa inteligente.", + "nl": "Integreer je Oxxify Fans in je Smart Home.", + "fr": "Intégrez vos ventilateurs Oxxify dans votre maison intelligente.", + "it": "Integra i tuoi fan Oxxify nella tua casa intelligente.", + "es": "Integra tus Fans Oxxify en tu Hogar Inteligente.", + "pl": "Zintegruj swoich fanów Oxxify ze swoim inteligentnym domem.", + "uk": "Інтегруйте вентилятори Oxxify у свій розумний дім.", + "zh-cn": "将您的 Oxxify 风扇集成到您的智能家居中。" + }, + "authors": [ + "N-b-dy " + ], + "keywords": [ + "oxxify", + "fan", + "ventilation" + ], + "licenseInformation": { + "type": "free", + "license": "GPL-3.0-or-later" + }, + "platform": "Javascript/Node.js", + "icon": "oxxify-fan-control.png", + "enabled": true, + "extIcon": "https://raw.githubusercontent.com/N-b-dy/ioBroker.oxxify-fan-control/main/admin/oxxify-fan-control.png", + "readme": "https://github.com/N-b-dy/ioBroker.oxxify-fan-control/blob/main/README.md", + "loglevel": "info", + "tier": 3, + "mode": "daemon", + "type": "climate-control", + "compact": true, + "connectionType": "local", + "dataSource": "poll", + "adminUI": { + "config": "json" + }, + "dependencies": [ + { + "js-controller": ">=6.0.11" + } + ], + "globalDependencies": [ + { + "admin": ">=7.1.3" + } ] + }, + "native": { + "pollingInterval": 5, + "ntpServer": "0.de.pool.ntp.org", + "fans": [ + { + "name": "fan1", + "id": "1234567890123456", + "ipaddr": "192.168.1.1", + "password": "topsecret" + } + ] + }, + "protectedNative": [ + "fans.password" + ], + "encryptedNative": [ + "fans.password" + ], + "objects": [], + "instanceObjects": [ + { + "_id": "info", + "type": "channel", + "common": { + "name": "Information" + }, + "native": {} + }, + { + "_id": "info.connection", + "type": "state", + "common": { + "role": "indicator.connected", + "name": "Device or service connected", + "type": "boolean", + "read": true, + "write": false, + "def": false + }, + "native": {} + } + ] } diff --git a/package-lock.json b/package-lock.json index 1871df6..1043cb5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "iobroker.oxxify-fan-control", - "version": "0.0.2", + "version": "0.0.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "iobroker.oxxify-fan-control", - "version": "0.0.2", + "version": "0.0.3", "license": "GPL-3.0-or-later", "dependencies": { "@iobroker/adapter-core": "^3.2.2", diff --git a/package.json b/package.json index af86433..00a91e0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "iobroker.oxxify-fan-control", - "version": "0.0.2", + "version": "0.0.3", "description": "Integrate your Oxxify Fans into your Smart Home.", "author": { "name": "N-b-dy",