@victronenergy/mfd-modules 11.1.6 → 11.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/Modules/Mqtt/Mqtt.store.d.ts.map +1 -1
- package/dist/src/Modules/Mqtt/Mqtt.store.js +16 -1
- package/dist/src/Modules/Mqtt/Mqtt.store.js.map +1 -1
- package/dist/src/Modules/SwitchingPane/SwitchingDevice.provider.d.ts.map +1 -1
- package/dist/src/Modules/SwitchingPane/SwitchingDevice.provider.js +14 -17
- package/dist/src/Modules/SwitchingPane/SwitchingDevice.provider.js.map +1 -1
- package/dist/src/Modules/SwitchingPane/SwitchingPane.provider.d.ts.map +1 -1
- package/dist/src/Modules/SwitchingPane/SwitchingPane.provider.js +14 -7
- package/dist/src/Modules/SwitchingPane/SwitchingPane.provider.js.map +1 -1
- package/dist/src/Modules/Tanks/Tanks.provider.d.ts.map +1 -1
- package/dist/src/Modules/Tanks/Tanks.provider.js +14 -17
- package/dist/src/Modules/Tanks/Tanks.provider.js.map +1 -1
- package/dist/src/Modules/Temperatures/Temperatures.provider.d.ts.map +1 -1
- package/dist/src/Modules/Temperatures/Temperatures.provider.js +14 -17
- package/dist/src/Modules/Temperatures/Temperatures.provider.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Mqtt.store.d.ts","sourceRoot":"/","sources":["src/Modules/Mqtt/Mqtt.store.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,qBAAqB,EAAE,UAAU,EAAE,MAAM,MAAM,CAAA;AACxD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAU,MAAM,EAAE,MAAM,SAAS,CAAA;AAQ7E,qBAAa,SAAS;IACpB,MAAM,CAAC,EAAE,UAAU,GAAG,IAAI,CAAA;IAC1B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAA;IAC/B,MAAM,EAAE,MAAM,CAAoB;IAClC,QAAQ,EAAE,YAAY,CAAK;IAC3B,YAAY,EAAE,YAAY,CAAK;IAC/B,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAoB;IACjD,QAAQ,EAAE,QAAQ,CAAA;IAClB,QAAQ,EAAE,MAAM,CAA0C;IAC1D,mBAAmB,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,GAAG,SAAS,CAAA;IAC/D,WAAW,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,GAAG,SAAS,CAAA;IACtD,2BAA2B,EAAE,MAAM,CAAI;IACvC,mBAAmB,EAAE,MAAM,EAAE,CAAK;IAClC,mBAAmB,EAAE,OAAO,CAAQ;IAEpC;;;;;;;;;;;;;;;;OAgBG;IACH,gBAAgB,WACL,MAAM,iBAMhB;IAED;;;;;;;;;;;;;;;;;;UAkBM;IACN,gBAAgB,YACJ,MAAM;;MAsBjB;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,kBAAkB,cACJ,MAAM,
|
|
1
|
+
{"version":3,"file":"Mqtt.store.d.ts","sourceRoot":"/","sources":["src/Modules/Mqtt/Mqtt.store.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,qBAAqB,EAAE,UAAU,EAAE,MAAM,MAAM,CAAA;AACxD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAU,MAAM,EAAE,MAAM,SAAS,CAAA;AAQ7E,qBAAa,SAAS;IACpB,MAAM,CAAC,EAAE,UAAU,GAAG,IAAI,CAAA;IAC1B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAA;IAC/B,MAAM,EAAE,MAAM,CAAoB;IAClC,QAAQ,EAAE,YAAY,CAAK;IAC3B,YAAY,EAAE,YAAY,CAAK;IAC/B,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAoB;IACjD,QAAQ,EAAE,QAAQ,CAAA;IAClB,QAAQ,EAAE,MAAM,CAA0C;IAC1D,mBAAmB,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,GAAG,SAAS,CAAA;IAC/D,WAAW,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,GAAG,SAAS,CAAA;IACtD,2BAA2B,EAAE,MAAM,CAAI;IACvC,mBAAmB,EAAE,MAAM,EAAE,CAAK;IAClC,mBAAmB,EAAE,OAAO,CAAQ;IAEpC;;;;;;;;;;;;;;;;OAgBG;IACH,gBAAgB,WACL,MAAM,iBAMhB;IAED;;;;;;;;;;;;;;;;;;UAkBM;IACN,gBAAgB,YACJ,MAAM;;MAsBjB;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,kBAAkB,cACJ,MAAM,SAyBnB;;IAqBD,IAAI,WAAW,YAEd;IAED,gBAAgB,GAAI,QAAQ,MAAM,UAqBjC;IAED,qBAAqB;IASrB,UAAU,GAAI,OAAO,MAAM,EAAE,SAAS;QAAE,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,UAUlE;IAED,mBAAmB,aAGlB;IAED,oBAAoB,aAQnB;IAED,2BAA2B,GAAI,SAAS,MAAM,UAW7C;IAED,gBAAgB,aAKf;IAED,iBAAiB,aAKhB;IAED,WAAW,GAAI,UAAU,MAAM,UAO9B;IAED,SAAS,CAAC,MAAM,EAAE,MAAM;IAIxB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO;IAIvC,IAAI,GACF,UAAU,MAAM,EAChB,MAAM,MAAM,YAAc,EAC1B,MAAM,MAAM,GAAG,IAAI,EACnB,OAAM,MAAyB,EAC/B,SAAQ,OAAe,EACvB,WAAW,MAAM,UAqGlB;IAED,oBAAoB,aA4BnB;IAED,uBAAuB,aAOtB;IAED,iBAAiB,aAOhB;IAED,mBAAmB,aAMlB;IAED,mBAAmB,aAMlB;IAED,OAAO,GAAI,OAAO,MAAM,EAAE,MAAM,MAAM,GAAG,MAAM,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,EAAE,UAAU,qBAAqB,UAWjG;CACF;AA2CD,wBAAgB,OAAO,cAEtB"}
|
|
@@ -185,7 +185,10 @@ export class MqttStore {
|
|
|
185
185
|
// trace()
|
|
186
186
|
if (wildcard === undefined || wildcard === "" || wildcard === null)
|
|
187
187
|
return {};
|
|
188
|
-
|
|
188
|
+
// Anchored single-level match: MQTT `+` matches exactly one topic level (no `/`),
|
|
189
|
+
// so a value change deep under a tree (e.g. `switch/0/.../Dimming`) no longer
|
|
190
|
+
// satisfies a shallow wildcard (`switch/+`) the way the old unanchored regex did.
|
|
191
|
+
const topicRegex = getWildcardRegex(wildcard);
|
|
189
192
|
return Object.fromEntries(Object.keys(this.messages)
|
|
190
193
|
.filter((topic) => topic.match(topicRegex))
|
|
191
194
|
.map((topic) => [topic, this.messages[topic]])
|
|
@@ -539,6 +542,18 @@ export class MqttStore {
|
|
|
539
542
|
}
|
|
540
543
|
}
|
|
541
544
|
const SUPPRESSED_KEEPALIVE_OPTIONS = JSON.stringify({ "keepalive-options": ["suppress-republish"] });
|
|
545
|
+
// Compiled wildcard regexes are cached: the same handful of wildcards recompute
|
|
546
|
+
// on every value flush, so we avoid rebuilding the RegExp each time.
|
|
547
|
+
const wildcardRegexCache = new Map();
|
|
548
|
+
function getWildcardRegex(wildcard) {
|
|
549
|
+
let regex = wildcardRegexCache.get(wildcard);
|
|
550
|
+
if (!regex) {
|
|
551
|
+
// `+` -> one level (no slash); anchor so the match is the whole topic, not a prefix
|
|
552
|
+
regex = new RegExp("^" + wildcard.replace(/\+/g, "[^/]+") + "$");
|
|
553
|
+
wildcardRegexCache.set(wildcard, regex);
|
|
554
|
+
}
|
|
555
|
+
return regex;
|
|
556
|
+
}
|
|
542
557
|
/**
|
|
543
558
|
* Compute mean by providing existing mean, number of samples, and new sample.
|
|
544
559
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Mqtt.store.js","sourceRoot":"/","sources":["src/Modules/Mqtt/Mqtt.store.ts"],"names":[],"mappings":"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","sourcesContent":["import { comparer, makeAutoObservable, runInAction } from \"mobx\"\nimport { computedFn } from \"mobx-utils\"\nimport * as mqtt from \"mqtt\"\nimport { IClientPublishOptions, MqttClient } from \"mqtt\"\nimport { MqttMessage, MqttMessages, PortalId, STATUS, Topics } from \"../Mqtt\"\nimport Logger from \"../../utils/logger\"\nimport { getMessageJson } from \"../../utils/util\"\nimport { useMemo } from \"react\"\nimport { assign } from \"lodash-es\"\n\nlet store: MqttStore\n\nexport class MqttStore {\n client?: MqttClient | null\n error?: object | null | boolean\n status: string = STATUS.CONNECTING\n messages: MqttMessages = {}\n messageQueue: MqttMessages = {}\n topicsSubscribed: Set<string> = new Set<string>()\n portalId: PortalId\n uniqueId: string = Math.random().toString(16).substr(2, 8)\n keepAliveHandlerRef: ReturnType<typeof setInterval> | undefined\n queueWorker: ReturnType<typeof setTimeout> | undefined\n meanQueueWorkerPassDuration: number = 0\n urgentTopicPrefixes: string[] = []\n initialLoadComplete: boolean = false\n\n /**\n * Returns the current cached message for a given MQTT topic.\n *\n * React Components using this method will re-render when their specific\n * topic's message changes.\n *\n * Using comparer.identity will trigger the re-renders any time\n * a message arrives for the given topic. We rely on the fact\n * that MQTT will only re-send a message when the value changes,\n * or on a full keep alive.\n *\n * Note: Receiving the same message for a given topic will cause re-renders,\n * as we do not check structural identity of the message.\n *\n * @param topic - The MQTT topic to retrieve the message for\n * @returns The message object for the topic, or undefined if topic is not provided or not found\n */\n messageFromTopic = computedFn(\n (topic?: string) => {\n // Logger.log(`DEBUG: messageFromTopic: ${JSON.stringify(topic)}`)\n // trace()\n return topic ? this.messages[topic] : undefined\n },\n { name: \"Mqtt.store.messageFromTopic\", equals: comparer.identity }\n )\n\n /**\n * Returns the current cached messages for a given set of MQTT topics.\n *\n * This is a memoized computed function - each set of topics has its own cached value.\n *\n * React Components using this method will re-render when\n * any of the messages for specified topics change.\n *\n * Using comparer.identity will trigger the re-renders any time\n * a message arrives for any of the specified topics. We rely on the fact\n * that MQTT will only re-send a message when the value changes,\n * or on a full keep alive.\n\n * Note: Receiving the same message for a given topic will cause re-renders,\n * as we do not check structural identity of the message.\n *\n * @param topics - The MQTT topics to retrieve the messages for\n * @returns The messages objects for the given topics, or empty dictionary if topics not found\n */\n messagesByTopics = computedFn(\n (topics?: Topics) => {\n // Logger.log(`DEBUG: messagesByTopics: ${JSON.stringify(topics)}`)\n // trace()\n if (!topics) {\n return {}\n }\n\n const result: { [key: string]: MqttMessage | MqttMessage[] } = {}\n\n Object.entries(topics).forEach(([label, topic]) => {\n if (Array.isArray(topic)) {\n result[label] = topic.map((t) => this.messageFromTopic(t))\n } else if (topic === undefined) {\n result[label] = undefined\n } else {\n result[label] = this.messageFromTopic(topic)\n }\n })\n\n return result\n },\n { name: \"Mqtt.store.messagesByTopics\", equals: comparer.identity }\n )\n\n /**\n * Returns the current cached messages for MQTT topics specified via regex.\n *\n * React Components using this method will re-render when\n * values of any of the matched topics change. The components also re-render\n * when new MQTT topics are received and match needs to be checked.\n *\n * Using comparer.identity will trigger the re-renders any time\n * a message arrives for any of the matched topics. We rely on the fact\n * that MQTT will only re-send a message when the value changes,\n * or on a full keep alive.\n *\n * Note: Receiving the same message for a given topic will cause re-renders,\n * as we do not check structural identity of the message.\n *\n * @param wildcard - The MQTT wildcard to retrieve the message for\n * @returns The messages objects for the given topics, or empty dictionary if topics not found\n */\n messagesByWildcard = computedFn(\n (wildcard?: string) => {\n // Logger.log(`DEBUG: messagesByWildcard: ${JSON.stringify(wildcard)}`)\n // trace()\n if (wildcard === undefined || wildcard === \"\" || wildcard === null) return {}\n\n const topicRegex = new RegExp(wildcard.replace(/\\+/g, \"\\\\w*\")) // + in mqtt is anything -> .*\n\n return Object.fromEntries(\n Object.keys(this.messages)\n .filter((topic) => topic.match(topicRegex))\n .map((topic) => [topic, this.messages[topic]])\n // Filter out empty results\n .filter(\n ([_key, message]) =>\n message !== undefined &&\n message !== null &&\n (!Array.isArray(message) ||\n (message.length !== 0 && !message.every((v) => v === undefined || v === null)))\n )\n )\n },\n { name: \"Mqtt.store.messagesByWildcard\", equals: comparer.identity }\n )\n\n constructor() {\n makeAutoObservable(this, {\n messageQueue: false,\n urgentTopicPrefixes: false,\n initialLoadComplete: false,\n completeInitialLoad: false,\n setupKeepaliveTimer: false,\n clearKeepaliveTimer: false,\n sendFullKeepalive: false,\n sendSuppressedKeepalive: false,\n setupQueueWorker: false,\n removeQueueWorker: false,\n scheduleNextQueueWorkerPass: false,\n subscribeToTopic: false,\n subscribeToAllTopics: false,\n clearSubscribedTopics: false,\n })\n }\n\n get isConnected() {\n return this.status === STATUS.CONNECTED\n }\n\n subscribeToTopic = (topic?: string) => {\n if (!topic) return\n if (topic.includes(\"undefined\")) return\n\n if (!this.topicsSubscribed.has(topic)) {\n Logger.log(`Subscribing to ${topic}`)\n this.client?.subscribe(topic, (err, granted) => {\n if (err) {\n Logger.error(err)\n return\n }\n\n if (granted !== undefined && granted[0]) {\n Logger.log(`Subscribed to ${granted[0].topic} with Qos ${granted[0].qos}`)\n } else {\n Logger.log(`Subscribed to ${topic} with Qos unknown`)\n }\n })\n\n this.topicsSubscribed.add(topic)\n }\n }\n\n clearSubscribedTopics() {\n this.topicsSubscribed.clear()\n this.urgentTopicPrefixes = []\n this.initialLoadComplete = false\n runInAction(() => {\n this.portalId = undefined\n })\n }\n\n addMessage = (topic: string, message: { value: string | undefined }) => {\n // Logger.log(`DEBUG: addMessage: topic: ${topic}, urgentPrefixes: ${JSON.stringify(this.urgentTopicPrefixes)}`)\n if (this.initialLoadComplete && this.urgentTopicPrefixes.some((prefix) => topic.startsWith(prefix))) {\n // NOTE: If topic starts with one of the urgent prefixes, deliver it immediately\n this.messages[topic] = message.value\n } else {\n // NOTE: Otherwise store message to the queue, and move messages from the queue\n // NOTE: to the React components that are MobX observers periodically and in batches\n this.messageQueue[topic] = message.value\n }\n }\n\n completeInitialLoad = () => {\n this.addMessagesFromQueue()\n this.initialLoadComplete = true\n }\n\n addMessagesFromQueue = () => {\n // keys() avoids materializing all values just to check emptiness\n if (Object.keys(this.messageQueue).length > 0) {\n // Logger.log(`DEBUG: addMessagesFromQueue: in queue: ${JSON.stringify(Object.values(this.messageQueue).length)}`)\n assign(this.messages, this.messageQueue)\n // Logger.log(`DEBUG: addMessagesFromQueue: to process: ${JSON.stringify(Object.values(this.messages).length)}`)\n this.messageQueue = {}\n }\n }\n\n scheduleNextQueueWorkerPass = (timeout: number) => {\n this.queueWorker = setTimeout(() => {\n const started = performance.now()\n this.addMessagesFromQueue()\n const ended = performance.now()\n this.meanQueueWorkerPassDuration = addToMean(this.meanQueueWorkerPassDuration, 10, ended - started)\n // Schedule next update after 1 - 3 seconds\n // depending on how fast we were able to process the incoming messages\n const newTimeout = Math.max(1000, Math.min(this.meanQueueWorkerPassDuration * 50, 3000))\n this.scheduleNextQueueWorkerPass(newTimeout)\n }, timeout)\n }\n\n setupQueueWorker = () => {\n this.removeQueueWorker()\n\n this.meanQueueWorkerPassDuration = 20 // ms\n this.scheduleNextQueueWorkerPass(1000) // ms\n }\n\n removeQueueWorker = () => {\n if (this.queueWorker) {\n clearTimeout(this.queueWorker)\n }\n this.queueWorker = undefined\n }\n\n setPortalId = (portalId: string) => {\n this.portalId = portalId\n this.urgentTopicPrefixes = [\n `N/${portalId}/switch/`,\n `N/${portalId}/system/0/SwitchableOutput`,\n `N/${portalId}/settings/0/Settings/Gui2/Switchpane/Preset/`,\n ]\n }\n\n setStatus(status: string) {\n this.status = status\n }\n\n setError(error: object | null | boolean) {\n this.error = error\n }\n\n boot = (\n protocol: string,\n host: string = \"localhost\",\n port: number | null,\n path: string = \"websocket-mqtt\",\n remote: boolean = false,\n portalId?: string\n ) => {\n Logger.log(\"MQTT booting\")\n\n let client = this.client\n\n if (client) {\n client.end(true)\n this.client = undefined\n this.portalId = undefined\n this.topicsSubscribed.clear()\n this.urgentTopicPrefixes = []\n this.initialLoadComplete = false\n }\n\n let url\n if (remote) {\n if (!host) {\n return\n }\n // remote connection to VRM broker always uses MQTTS over 443\n url = `mqtts://${host}:443`\n } else {\n // local connection derives websocket protocol from web app protocol\n const wsproto = protocol === \"https:\" ? \"wss:\" : \"ws:\"\n if (port) {\n url = `${wsproto}//${host}:${port}/${path}`\n } else {\n url = `${wsproto}//${host}/${path}`\n }\n }\n\n Logger.log(`MQTT connecting to ${url}`)\n client = mqtt.connect(url, { resubscribe: false })\n\n this.client = client\n this.portalId = portalId\n\n client.on(\"error\", (error) => {\n Logger.log(\"MQTT error\")\n runInAction(() => {\n this.setError(error)\n this.setStatus(STATUS.DISCONNECTED)\n })\n this.removeQueueWorker()\n this.clearKeepaliveTimer()\n this.clearSubscribedTopics()\n })\n\n client.on(\"offline\", () => {\n Logger.log(\"MQTT offline\")\n runInAction(() => {\n this.setError(true)\n this.setStatus(STATUS.OFFLINE)\n })\n this.removeQueueWorker()\n this.clearKeepaliveTimer()\n this.clearSubscribedTopics()\n })\n\n client.on(\"connect\", () => {\n Logger.log(\"MQTT connected\")\n runInAction(() => {\n this.setError(null)\n this.setStatus(STATUS.CONNECTED)\n // Never use wildcard when connecting remotely\n this.subscribeToTopic(`N/${remote ? portalId : \"+\"}/system/0/Serial`)\n this.setupKeepaliveTimer()\n })\n })\n\n client.on(\"message\", (topic, message) => {\n // Logger.log(`DEBUG: Message received: ${topic} - ${message.toString()}`)\n\n const str = message.toString()\n if (str === \"\") return\n\n const parsed = getMessageJson(str)\n\n if (topic.endsWith(\"/system/0/Serial\") && !this.portalId) {\n if (this.portalId !== parsed.value && parsed.value !== undefined) {\n this.setPortalId(parsed.value)\n }\n\n runInAction(() => this.subscribeToAllTopics())\n }\n if (!this.initialLoadComplete && topic.endsWith(\"full_publish_completed\")) {\n const uniqueId = (parsed[\"full-publish-completed-echo\"] as string) || \"\"\n Logger.log(\n `Received full_publish_completed for ${this.portalId} with full-publish-completed-echo: '${uniqueId}'`\n )\n if (uniqueId === this.uniqueId) {\n this.completeInitialLoad()\n this.setupQueueWorker()\n }\n }\n\n this.addMessage(topic, parsed)\n })\n\n Logger.log(\"MQTT booted\")\n }\n\n subscribeToAllTopics = () => {\n const topics = [\n `N/${this.portalId}/settings/#`,\n `N/${this.portalId}/system/#`,\n `N/${this.portalId}/vebus/#`,\n `N/${this.portalId}/alternator/#`,\n `N/${this.portalId}/battery/#`,\n `N/${this.portalId}/charger/#`,\n `N/${this.portalId}/dcsource/#`,\n `N/${this.portalId}/generator/#`,\n `N/${this.portalId}/genset/#`,\n `N/${this.portalId}/dcgenset/#`,\n `N/${this.portalId}/inverter/#`,\n `N/${this.portalId}/tank/#`,\n `N/${this.portalId}/temperature/#`,\n `N/${this.portalId}/switch/#`,\n `N/${this.portalId}/full_publish_completed`,\n ]\n\n this.client?.subscribe(topics, (err) => {\n if (err) {\n Logger.error(err)\n return\n }\n\n // When we received all topics we send a full keepalive.\n this.sendFullKeepalive()\n })\n }\n\n sendSuppressedKeepalive = () => {\n if (this.portalId) {\n const topic = `R/${this.portalId}/keepalive`\n\n Logger.log(`Sending keepalive for ${this.portalId} with ${SUPPRESSED_KEEPALIVE_OPTIONS}`)\n this.client?.publish(topic, SUPPRESSED_KEEPALIVE_OPTIONS)\n }\n }\n\n sendFullKeepalive = () => {\n if (this.portalId) {\n const topic = `R/${this.portalId}/keepalive`\n\n Logger.log(`Sending first keepalive for ${this.portalId} with full-publish-completed-echo: '${this.uniqueId}'`)\n this.client?.publish(topic, `{ \"keepalive-options\" : [ {\"full-publish-completed-echo\": \"${this.uniqueId}\" } ] }`)\n }\n }\n\n setupKeepaliveTimer = () => {\n this.clearKeepaliveTimer()\n\n this.keepAliveHandlerRef = setInterval(this.sendSuppressedKeepalive, 30000)\n\n this.sendFullKeepalive()\n }\n\n clearKeepaliveTimer = () => {\n const ref = this.keepAliveHandlerRef\n if (ref) {\n clearInterval(ref)\n }\n this.keepAliveHandlerRef = undefined\n }\n\n publish = (topic: string, data: string | number | { raw: string }, options?: IClientPublishOptions) => {\n if (this.status !== STATUS.CONNECTED || !this.client) {\n Logger.log(\"Could not publish value, not connected to MQTT broker\")\n return\n }\n const message =\n typeof data === \"object\" && data !== null && \"raw\" in data ? data.raw : JSON.stringify({ value: data })\n\n Logger.log(`Publishing to ${topic}: ${message}`)\n\n this.client?.publish(topic, message, options ?? {})\n }\n}\n\nconst SUPPRESSED_KEEPALIVE_OPTIONS = JSON.stringify({ \"keepalive-options\": [\"suppress-republish\"] })\n\n/**\n * Compute mean by providing existing mean, number of samples, and new sample.\n *\n * @param {number} mean current mean\n * @param {number} n number of sampled values\n * @param {number} newValue the sample\n * @returns {number} the new mean\n *\n * @example\n * addToMean(14, 5, 53); // => 20.5\n */\nfunction addToMean(mean: number, n: number, newValue: number): number {\n return mean + (newValue - mean) / (n + 1)\n}\n\nfunction initializeStore() {\n const _store = store ?? new MqttStore()\n // For SSG and SSR always create a new store\n if (typeof window === \"undefined\") return _store\n // Create the store once in the client\n if (!store) store = _store\n\n return _store\n}\n\nexport function useMqtt() {\n return useMemo(() => initializeStore(), [])\n}\n"]}
|
|
1
|
+
{"version":3,"file":"Mqtt.store.js","sourceRoot":"/","sources":["src/Modules/Mqtt/Mqtt.store.ts"],"names":[],"mappings":"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","sourcesContent":["import { comparer, makeAutoObservable, runInAction } from \"mobx\"\nimport { computedFn } from \"mobx-utils\"\nimport * as mqtt from \"mqtt\"\nimport { IClientPublishOptions, MqttClient } from \"mqtt\"\nimport { MqttMessage, MqttMessages, PortalId, STATUS, Topics } from \"../Mqtt\"\nimport Logger from \"../../utils/logger\"\nimport { getMessageJson } from \"../../utils/util\"\nimport { useMemo } from \"react\"\nimport { assign } from \"lodash-es\"\n\nlet store: MqttStore\n\nexport class MqttStore {\n client?: MqttClient | null\n error?: object | null | boolean\n status: string = STATUS.CONNECTING\n messages: MqttMessages = {}\n messageQueue: MqttMessages = {}\n topicsSubscribed: Set<string> = new Set<string>()\n portalId: PortalId\n uniqueId: string = Math.random().toString(16).substr(2, 8)\n keepAliveHandlerRef: ReturnType<typeof setInterval> | undefined\n queueWorker: ReturnType<typeof setTimeout> | undefined\n meanQueueWorkerPassDuration: number = 0\n urgentTopicPrefixes: string[] = []\n initialLoadComplete: boolean = false\n\n /**\n * Returns the current cached message for a given MQTT topic.\n *\n * React Components using this method will re-render when their specific\n * topic's message changes.\n *\n * Using comparer.identity will trigger the re-renders any time\n * a message arrives for the given topic. We rely on the fact\n * that MQTT will only re-send a message when the value changes,\n * or on a full keep alive.\n *\n * Note: Receiving the same message for a given topic will cause re-renders,\n * as we do not check structural identity of the message.\n *\n * @param topic - The MQTT topic to retrieve the message for\n * @returns The message object for the topic, or undefined if topic is not provided or not found\n */\n messageFromTopic = computedFn(\n (topic?: string) => {\n // Logger.log(`DEBUG: messageFromTopic: ${JSON.stringify(topic)}`)\n // trace()\n return topic ? this.messages[topic] : undefined\n },\n { name: \"Mqtt.store.messageFromTopic\", equals: comparer.identity }\n )\n\n /**\n * Returns the current cached messages for a given set of MQTT topics.\n *\n * This is a memoized computed function - each set of topics has its own cached value.\n *\n * React Components using this method will re-render when\n * any of the messages for specified topics change.\n *\n * Using comparer.identity will trigger the re-renders any time\n * a message arrives for any of the specified topics. We rely on the fact\n * that MQTT will only re-send a message when the value changes,\n * or on a full keep alive.\n\n * Note: Receiving the same message for a given topic will cause re-renders,\n * as we do not check structural identity of the message.\n *\n * @param topics - The MQTT topics to retrieve the messages for\n * @returns The messages objects for the given topics, or empty dictionary if topics not found\n */\n messagesByTopics = computedFn(\n (topics?: Topics) => {\n // Logger.log(`DEBUG: messagesByTopics: ${JSON.stringify(topics)}`)\n // trace()\n if (!topics) {\n return {}\n }\n\n const result: { [key: string]: MqttMessage | MqttMessage[] } = {}\n\n Object.entries(topics).forEach(([label, topic]) => {\n if (Array.isArray(topic)) {\n result[label] = topic.map((t) => this.messageFromTopic(t))\n } else if (topic === undefined) {\n result[label] = undefined\n } else {\n result[label] = this.messageFromTopic(topic)\n }\n })\n\n return result\n },\n { name: \"Mqtt.store.messagesByTopics\", equals: comparer.identity }\n )\n\n /**\n * Returns the current cached messages for MQTT topics specified via regex.\n *\n * React Components using this method will re-render when\n * values of any of the matched topics change. The components also re-render\n * when new MQTT topics are received and match needs to be checked.\n *\n * Using comparer.identity will trigger the re-renders any time\n * a message arrives for any of the matched topics. We rely on the fact\n * that MQTT will only re-send a message when the value changes,\n * or on a full keep alive.\n *\n * Note: Receiving the same message for a given topic will cause re-renders,\n * as we do not check structural identity of the message.\n *\n * @param wildcard - The MQTT wildcard to retrieve the message for\n * @returns The messages objects for the given topics, or empty dictionary if topics not found\n */\n messagesByWildcard = computedFn(\n (wildcard?: string) => {\n // Logger.log(`DEBUG: messagesByWildcard: ${JSON.stringify(wildcard)}`)\n // trace()\n if (wildcard === undefined || wildcard === \"\" || wildcard === null) return {}\n\n // Anchored single-level match: MQTT `+` matches exactly one topic level (no `/`),\n // so a value change deep under a tree (e.g. `switch/0/.../Dimming`) no longer\n // satisfies a shallow wildcard (`switch/+`) the way the old unanchored regex did.\n const topicRegex = getWildcardRegex(wildcard)\n\n return Object.fromEntries(\n Object.keys(this.messages)\n .filter((topic) => topic.match(topicRegex))\n .map((topic) => [topic, this.messages[topic]])\n // Filter out empty results\n .filter(\n ([_key, message]) =>\n message !== undefined &&\n message !== null &&\n (!Array.isArray(message) ||\n (message.length !== 0 && !message.every((v) => v === undefined || v === null)))\n )\n )\n },\n { name: \"Mqtt.store.messagesByWildcard\", equals: comparer.identity }\n )\n\n constructor() {\n makeAutoObservable(this, {\n messageQueue: false,\n urgentTopicPrefixes: false,\n initialLoadComplete: false,\n completeInitialLoad: false,\n setupKeepaliveTimer: false,\n clearKeepaliveTimer: false,\n sendFullKeepalive: false,\n sendSuppressedKeepalive: false,\n setupQueueWorker: false,\n removeQueueWorker: false,\n scheduleNextQueueWorkerPass: false,\n subscribeToTopic: false,\n subscribeToAllTopics: false,\n clearSubscribedTopics: false,\n })\n }\n\n get isConnected() {\n return this.status === STATUS.CONNECTED\n }\n\n subscribeToTopic = (topic?: string) => {\n if (!topic) return\n if (topic.includes(\"undefined\")) return\n\n if (!this.topicsSubscribed.has(topic)) {\n Logger.log(`Subscribing to ${topic}`)\n this.client?.subscribe(topic, (err, granted) => {\n if (err) {\n Logger.error(err)\n return\n }\n\n if (granted !== undefined && granted[0]) {\n Logger.log(`Subscribed to ${granted[0].topic} with Qos ${granted[0].qos}`)\n } else {\n Logger.log(`Subscribed to ${topic} with Qos unknown`)\n }\n })\n\n this.topicsSubscribed.add(topic)\n }\n }\n\n clearSubscribedTopics() {\n this.topicsSubscribed.clear()\n this.urgentTopicPrefixes = []\n this.initialLoadComplete = false\n runInAction(() => {\n this.portalId = undefined\n })\n }\n\n addMessage = (topic: string, message: { value: string | undefined }) => {\n // Logger.log(`DEBUG: addMessage: topic: ${topic}, urgentPrefixes: ${JSON.stringify(this.urgentTopicPrefixes)}`)\n if (this.initialLoadComplete && this.urgentTopicPrefixes.some((prefix) => topic.startsWith(prefix))) {\n // NOTE: If topic starts with one of the urgent prefixes, deliver it immediately\n this.messages[topic] = message.value\n } else {\n // NOTE: Otherwise store message to the queue, and move messages from the queue\n // NOTE: to the React components that are MobX observers periodically and in batches\n this.messageQueue[topic] = message.value\n }\n }\n\n completeInitialLoad = () => {\n this.addMessagesFromQueue()\n this.initialLoadComplete = true\n }\n\n addMessagesFromQueue = () => {\n // keys() avoids materializing all values just to check emptiness\n if (Object.keys(this.messageQueue).length > 0) {\n // Logger.log(`DEBUG: addMessagesFromQueue: in queue: ${JSON.stringify(Object.values(this.messageQueue).length)}`)\n assign(this.messages, this.messageQueue)\n // Logger.log(`DEBUG: addMessagesFromQueue: to process: ${JSON.stringify(Object.values(this.messages).length)}`)\n this.messageQueue = {}\n }\n }\n\n scheduleNextQueueWorkerPass = (timeout: number) => {\n this.queueWorker = setTimeout(() => {\n const started = performance.now()\n this.addMessagesFromQueue()\n const ended = performance.now()\n this.meanQueueWorkerPassDuration = addToMean(this.meanQueueWorkerPassDuration, 10, ended - started)\n // Schedule next update after 1 - 3 seconds\n // depending on how fast we were able to process the incoming messages\n const newTimeout = Math.max(1000, Math.min(this.meanQueueWorkerPassDuration * 50, 3000))\n this.scheduleNextQueueWorkerPass(newTimeout)\n }, timeout)\n }\n\n setupQueueWorker = () => {\n this.removeQueueWorker()\n\n this.meanQueueWorkerPassDuration = 20 // ms\n this.scheduleNextQueueWorkerPass(1000) // ms\n }\n\n removeQueueWorker = () => {\n if (this.queueWorker) {\n clearTimeout(this.queueWorker)\n }\n this.queueWorker = undefined\n }\n\n setPortalId = (portalId: string) => {\n this.portalId = portalId\n this.urgentTopicPrefixes = [\n `N/${portalId}/switch/`,\n `N/${portalId}/system/0/SwitchableOutput`,\n `N/${portalId}/settings/0/Settings/Gui2/Switchpane/Preset/`,\n ]\n }\n\n setStatus(status: string) {\n this.status = status\n }\n\n setError(error: object | null | boolean) {\n this.error = error\n }\n\n boot = (\n protocol: string,\n host: string = \"localhost\",\n port: number | null,\n path: string = \"websocket-mqtt\",\n remote: boolean = false,\n portalId?: string\n ) => {\n Logger.log(\"MQTT booting\")\n\n let client = this.client\n\n if (client) {\n client.end(true)\n this.client = undefined\n this.portalId = undefined\n this.topicsSubscribed.clear()\n this.urgentTopicPrefixes = []\n this.initialLoadComplete = false\n }\n\n let url\n if (remote) {\n if (!host) {\n return\n }\n // remote connection to VRM broker always uses MQTTS over 443\n url = `mqtts://${host}:443`\n } else {\n // local connection derives websocket protocol from web app protocol\n const wsproto = protocol === \"https:\" ? \"wss:\" : \"ws:\"\n if (port) {\n url = `${wsproto}//${host}:${port}/${path}`\n } else {\n url = `${wsproto}//${host}/${path}`\n }\n }\n\n Logger.log(`MQTT connecting to ${url}`)\n client = mqtt.connect(url, { resubscribe: false })\n\n this.client = client\n this.portalId = portalId\n\n client.on(\"error\", (error) => {\n Logger.log(\"MQTT error\")\n runInAction(() => {\n this.setError(error)\n this.setStatus(STATUS.DISCONNECTED)\n })\n this.removeQueueWorker()\n this.clearKeepaliveTimer()\n this.clearSubscribedTopics()\n })\n\n client.on(\"offline\", () => {\n Logger.log(\"MQTT offline\")\n runInAction(() => {\n this.setError(true)\n this.setStatus(STATUS.OFFLINE)\n })\n this.removeQueueWorker()\n this.clearKeepaliveTimer()\n this.clearSubscribedTopics()\n })\n\n client.on(\"connect\", () => {\n Logger.log(\"MQTT connected\")\n runInAction(() => {\n this.setError(null)\n this.setStatus(STATUS.CONNECTED)\n // Never use wildcard when connecting remotely\n this.subscribeToTopic(`N/${remote ? portalId : \"+\"}/system/0/Serial`)\n this.setupKeepaliveTimer()\n })\n })\n\n client.on(\"message\", (topic, message) => {\n // Logger.log(`DEBUG: Message received: ${topic} - ${message.toString()}`)\n\n const str = message.toString()\n if (str === \"\") return\n\n const parsed = getMessageJson(str)\n\n if (topic.endsWith(\"/system/0/Serial\") && !this.portalId) {\n if (this.portalId !== parsed.value && parsed.value !== undefined) {\n this.setPortalId(parsed.value)\n }\n\n runInAction(() => this.subscribeToAllTopics())\n }\n if (!this.initialLoadComplete && topic.endsWith(\"full_publish_completed\")) {\n const uniqueId = (parsed[\"full-publish-completed-echo\"] as string) || \"\"\n Logger.log(\n `Received full_publish_completed for ${this.portalId} with full-publish-completed-echo: '${uniqueId}'`\n )\n if (uniqueId === this.uniqueId) {\n this.completeInitialLoad()\n this.setupQueueWorker()\n }\n }\n\n this.addMessage(topic, parsed)\n })\n\n Logger.log(\"MQTT booted\")\n }\n\n subscribeToAllTopics = () => {\n const topics = [\n `N/${this.portalId}/settings/#`,\n `N/${this.portalId}/system/#`,\n `N/${this.portalId}/vebus/#`,\n `N/${this.portalId}/alternator/#`,\n `N/${this.portalId}/battery/#`,\n `N/${this.portalId}/charger/#`,\n `N/${this.portalId}/dcsource/#`,\n `N/${this.portalId}/generator/#`,\n `N/${this.portalId}/genset/#`,\n `N/${this.portalId}/dcgenset/#`,\n `N/${this.portalId}/inverter/#`,\n `N/${this.portalId}/tank/#`,\n `N/${this.portalId}/temperature/#`,\n `N/${this.portalId}/switch/#`,\n `N/${this.portalId}/full_publish_completed`,\n ]\n\n this.client?.subscribe(topics, (err) => {\n if (err) {\n Logger.error(err)\n return\n }\n\n // When we received all topics we send a full keepalive.\n this.sendFullKeepalive()\n })\n }\n\n sendSuppressedKeepalive = () => {\n if (this.portalId) {\n const topic = `R/${this.portalId}/keepalive`\n\n Logger.log(`Sending keepalive for ${this.portalId} with ${SUPPRESSED_KEEPALIVE_OPTIONS}`)\n this.client?.publish(topic, SUPPRESSED_KEEPALIVE_OPTIONS)\n }\n }\n\n sendFullKeepalive = () => {\n if (this.portalId) {\n const topic = `R/${this.portalId}/keepalive`\n\n Logger.log(`Sending first keepalive for ${this.portalId} with full-publish-completed-echo: '${this.uniqueId}'`)\n this.client?.publish(topic, `{ \"keepalive-options\" : [ {\"full-publish-completed-echo\": \"${this.uniqueId}\" } ] }`)\n }\n }\n\n setupKeepaliveTimer = () => {\n this.clearKeepaliveTimer()\n\n this.keepAliveHandlerRef = setInterval(this.sendSuppressedKeepalive, 30000)\n\n this.sendFullKeepalive()\n }\n\n clearKeepaliveTimer = () => {\n const ref = this.keepAliveHandlerRef\n if (ref) {\n clearInterval(ref)\n }\n this.keepAliveHandlerRef = undefined\n }\n\n publish = (topic: string, data: string | number | { raw: string }, options?: IClientPublishOptions) => {\n if (this.status !== STATUS.CONNECTED || !this.client) {\n Logger.log(\"Could not publish value, not connected to MQTT broker\")\n return\n }\n const message =\n typeof data === \"object\" && data !== null && \"raw\" in data ? data.raw : JSON.stringify({ value: data })\n\n Logger.log(`Publishing to ${topic}: ${message}`)\n\n this.client?.publish(topic, message, options ?? {})\n }\n}\n\nconst SUPPRESSED_KEEPALIVE_OPTIONS = JSON.stringify({ \"keepalive-options\": [\"suppress-republish\"] })\n\n// Compiled wildcard regexes are cached: the same handful of wildcards recompute\n// on every value flush, so we avoid rebuilding the RegExp each time.\nconst wildcardRegexCache = new Map<string, RegExp>()\n\nfunction getWildcardRegex(wildcard: string): RegExp {\n let regex = wildcardRegexCache.get(wildcard)\n if (!regex) {\n // `+` -> one level (no slash); anchor so the match is the whole topic, not a prefix\n regex = new RegExp(\"^\" + wildcard.replace(/\\+/g, \"[^/]+\") + \"$\")\n wildcardRegexCache.set(wildcard, regex)\n }\n return regex\n}\n\n/**\n * Compute mean by providing existing mean, number of samples, and new sample.\n *\n * @param {number} mean current mean\n * @param {number} n number of sampled values\n * @param {number} newValue the sample\n * @returns {number} the new mean\n *\n * @example\n * addToMean(14, 5, 53); // => 20.5\n */\nfunction addToMean(mean: number, n: number, newValue: number): number {\n return mean + (newValue - mean) / (n + 1)\n}\n\nfunction initializeStore() {\n const _store = store ?? new MqttStore()\n // For SSG and SSR always create a new store\n if (typeof window === \"undefined\") return _store\n // Create the store once in the client\n if (!store) store = _store\n\n return _store\n}\n\nexport function useMqtt() {\n return useMemo(() => initializeStore(), [])\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SwitchingDevice.provider.d.ts","sourceRoot":"/","sources":["src/Modules/SwitchingPane/SwitchingDevice.provider.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAA2B,MAAM,SAAS,CAAA;AAEnE,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAIzF,MAAM,MAAM,yBAAyB,GAAG,MAAM,CAAA;AAE9C,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,iBAAiB,EAAE,qBAAqB,EAAE,CAAA;CAC3C;AAED,MAAM,WAAW,qBAAsB,SAAQ,MAAM;IACnD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,eAAO,MAAM,6BAA6B,GACxC,UAAU,QAAQ,EAClB,MAAM,oBAAoB,EAC1B,YAAY,yBAAyB;;;;CAKrC,CAAA;AAEF,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,yBAAyB,GAAG,oBAAoB,CAK9F;AAED,wBAAgB,mBAAmB,
|
|
1
|
+
{"version":3,"file":"SwitchingDevice.provider.d.ts","sourceRoot":"/","sources":["src/Modules/SwitchingPane/SwitchingDevice.provider.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAA2B,MAAM,SAAS,CAAA;AAEnE,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAIzF,MAAM,MAAM,yBAAyB,GAAG,MAAM,CAAA;AAE9C,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,iBAAiB,EAAE,qBAAqB,EAAE,CAAA;CAC3C;AAED,MAAM,WAAW,qBAAsB,SAAQ,MAAM;IACnD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,eAAO,MAAM,6BAA6B,GACxC,UAAU,QAAQ,EAClB,MAAM,oBAAoB,EAC1B,YAAY,yBAAyB;;;;CAKrC,CAAA;AAEF,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,yBAAyB,GAAG,oBAAoB,CAK9F;AAED,wBAAgB,mBAAmB,6DAwClC"}
|
|
@@ -2,7 +2,7 @@ import { useEffect, useMemo } from "react";
|
|
|
2
2
|
import { useMqtt, useTopicsState } from "../Mqtt";
|
|
3
3
|
import Logger from "../../utils/logger";
|
|
4
4
|
import { useSwitchingDevicesStore } from "./SwitchingDevices.store";
|
|
5
|
-
import {
|
|
5
|
+
import { untracked } from "mobx";
|
|
6
6
|
export const getSwitchingDeviceStateTopics = (portalId, tree, instanceId) => ({
|
|
7
7
|
productName: `N/${portalId}/${tree}/${instanceId}/ProductName`,
|
|
8
8
|
customName: `N/${portalId}/${tree}/${instanceId}/CustomName`,
|
|
@@ -23,24 +23,21 @@ export function useSwitchingDevices() {
|
|
|
23
23
|
const messagesForSwitchingDevices = mqtt.messagesByWildcard(topics.devices);
|
|
24
24
|
// Examine MQTT to find all available switching devices
|
|
25
25
|
useEffect(() => {
|
|
26
|
-
if (!messagesForSwitchingDevices || Object.
|
|
26
|
+
if (!messagesForSwitchingDevices || Object.keys(messagesForSwitchingDevices).length === 0) {
|
|
27
27
|
Logger.log("Waiting for switching devices...");
|
|
28
|
+
return;
|
|
28
29
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
switchingDevicesStore.setDevices(newDevices);
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
return () => dispose();
|
|
30
|
+
const deviceInstances = Object.values(messagesForSwitchingDevices);
|
|
31
|
+
// NOTE: the store is typed as instance ids but holds device state snapshots at runtime
|
|
32
|
+
const oldDevices = switchingDevicesStore.devices;
|
|
33
|
+
const instanceSet = new Set(deviceInstances);
|
|
34
|
+
if (oldDevices.length !== deviceInstances.length ||
|
|
35
|
+
!oldDevices.every((device) => instanceSet.has(device.instance))) {
|
|
36
|
+
Logger.log(`New switching devices instances: ${JSON.stringify(deviceInstances)}`);
|
|
37
|
+
// NOTE: snapshot device state untracked — per-device values are observed live via useSwitchingDevice,
|
|
38
|
+
// NOTE: the store list only needs refreshing when the set of devices changes
|
|
39
|
+
const newDevices = untracked(() => deviceInstances.map((deviceId) => mqtt.messagesByTopics(getSwitchingDeviceStateTopics(mqtt.portalId, "switch", deviceId))));
|
|
40
|
+
switchingDevicesStore.setDevices(newDevices);
|
|
44
41
|
}
|
|
45
42
|
}, [messagesForSwitchingDevices, mqtt, switchingDevicesStore]);
|
|
46
43
|
return switchingDevicesStore;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SwitchingDevice.provider.js","sourceRoot":"/","sources":["src/Modules/SwitchingPane/SwitchingDevice.provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAC1C,OAAO,EAAoB,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AACnE,OAAO,MAAM,MAAM,oBAAoB,CAAA;AAEvC,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAA;AACnE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"SwitchingDevice.provider.js","sourceRoot":"/","sources":["src/Modules/SwitchingPane/SwitchingDevice.provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { useEffect, useMemo } from \"react\"\nimport { PortalId, Topics, useMqtt, useTopicsState } from \"../Mqtt\"\nimport Logger from \"../../utils/logger\"\nimport { SwitchableOutputState, SwitchableOutputTree } from \"./SwitchableOutput.provider\"\nimport { useSwitchingDevicesStore } from \"./SwitchingDevices.store\"\nimport { untracked } from \"mobx\"\n\nexport type SwitchingDeviceInstanceId = number\n\nexport interface SwitchingDeviceState {\n productName: string\n customName: string\n instance: number\n switchableOutputs: SwitchableOutputState[]\n}\n\nexport interface SwitchingDeviceTopics extends Topics {\n productName?: string\n customName?: string\n instance?: string\n}\n\nexport const getSwitchingDeviceStateTopics = (\n portalId: PortalId,\n tree: SwitchableOutputTree,\n instanceId: SwitchingDeviceInstanceId\n) => ({\n productName: `N/${portalId}/${tree}/${instanceId}/ProductName`,\n customName: `N/${portalId}/${tree}/${instanceId}/CustomName`,\n instance: `N/${portalId}/${tree}/${instanceId}/DeviceInstance`,\n})\n\nexport function useSwitchingDevice(instanceId: SwitchingDeviceInstanceId): SwitchingDeviceState {\n const { portalId } = useMqtt()\n const topics = useMemo(() => getSwitchingDeviceStateTopics(portalId, \"switch\", instanceId), [portalId, instanceId])\n\n return useTopicsState<SwitchingDeviceState>(topics)\n}\n\nexport function useSwitchingDevices() {\n const switchingDevicesStore = useSwitchingDevicesStore()\n\n const getTopics = (portalId: PortalId) => ({\n devices: `N/${portalId}/switch/+/DeviceInstance`,\n })\n\n const mqtt = useMqtt()\n const topics = useMemo(() => getTopics(mqtt.portalId), [mqtt.portalId])\n\n const messagesForSwitchingDevices = mqtt.messagesByWildcard(topics.devices)\n\n // Examine MQTT to find all available switching devices\n useEffect(() => {\n if (!messagesForSwitchingDevices || Object.keys(messagesForSwitchingDevices).length === 0) {\n Logger.log(\"Waiting for switching devices...\")\n return\n }\n\n const deviceInstances = Object.values(messagesForSwitchingDevices) as SwitchingDeviceInstanceId[]\n // NOTE: the store is typed as instance ids but holds device state snapshots at runtime\n const oldDevices = switchingDevicesStore.devices as unknown as SwitchingDeviceState[]\n const instanceSet = new Set(deviceInstances)\n if (\n oldDevices.length !== deviceInstances.length ||\n !oldDevices.every((device) => instanceSet.has(device.instance))\n ) {\n Logger.log(`New switching devices instances: ${JSON.stringify(deviceInstances)}`)\n // NOTE: snapshot device state untracked — per-device values are observed live via useSwitchingDevice,\n // NOTE: the store list only needs refreshing when the set of devices changes\n const newDevices = untracked(() =>\n deviceInstances.map((deviceId) =>\n mqtt.messagesByTopics(getSwitchingDeviceStateTopics(mqtt.portalId, \"switch\", deviceId))\n )\n ) as unknown as SwitchingDeviceInstanceId[]\n switchingDevicesStore.setDevices(newDevices)\n }\n }, [messagesForSwitchingDevices, mqtt, switchingDevicesStore])\n\n return switchingDevicesStore\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SwitchingPane.provider.d.ts","sourceRoot":"/","sources":["src/Modules/SwitchingPane/SwitchingPane.provider.ts"],"names":[],"mappings":"AAKA,OAAO,EAAiC,yBAAyB,EAAE,MAAM,4BAA4B,CAAA;AACrG,OAAO,EAIL,kBAAkB,EAKnB,MAAM,6BAA6B,CAAA;AACpC,OAAO,EAA8B,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAYpF,eAAO,MAAM,gBAAgB,GAAI,yBAAyB,MAAM,
|
|
1
|
+
{"version":3,"file":"SwitchingPane.provider.d.ts","sourceRoot":"/","sources":["src/Modules/SwitchingPane/SwitchingPane.provider.ts"],"names":[],"mappings":"AAKA,OAAO,EAAiC,yBAAyB,EAAE,MAAM,4BAA4B,CAAA;AACrG,OAAO,EAIL,kBAAkB,EAKnB,MAAM,6BAA6B,CAAA;AACpC,OAAO,EAA8B,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAYpF,eAAO,MAAM,gBAAgB,GAAI,yBAAyB,MAAM,uDA8Q/D,CAAA;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,MAAM;;cAQ8B,yBAAyB;cACjC,kBAAkB;EAEhG;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM;;cAQ0B,yBAAyB;aAC5B,cAAc;EAEzF;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,OAAO,CAGtD"}
|
|
@@ -15,12 +15,18 @@ export const useSwitchingPane = (gxDeviceRelaysGroupName) => {
|
|
|
15
15
|
systemOutputs: `N/${mqtt.portalId}/system/+/SwitchableOutput/+/Settings/+`,
|
|
16
16
|
switchOutputs: `N/${mqtt.portalId}/switch/+/SwitchableOutput/+/Settings/+`,
|
|
17
17
|
genericInputs: `N/${mqtt.portalId}/switch/+/GenericInput/+/Settings/+`,
|
|
18
|
-
|
|
18
|
+
// NOTE: deliberately precise (not `switch/+`) so that high-frequency operational
|
|
19
|
+
// NOTE: values (State, Dimming, Status, ...) do not invalidate the grouping below
|
|
20
|
+
switchingDeviceInstances: `N/${mqtt.portalId}/switch/+/DeviceInstance`,
|
|
21
|
+
switchingDeviceCustomNames: `N/${mqtt.portalId}/switch/+/CustomName`,
|
|
22
|
+
switchingDeviceProductNames: `N/${mqtt.portalId}/switch/+/ProductName`,
|
|
19
23
|
}), [mqtt.portalId]);
|
|
20
24
|
const messagesForSystemOutputs = mqtt.messagesByWildcard(topics.systemOutputs);
|
|
21
25
|
const messagesForSwitchOutputs = mqtt.messagesByWildcard(topics.switchOutputs);
|
|
22
26
|
const messagesForInputs = mqtt.messagesByWildcard(topics.genericInputs);
|
|
23
|
-
const
|
|
27
|
+
const messagesForSwitchingDeviceInstances = mqtt.messagesByWildcard(topics.switchingDeviceInstances);
|
|
28
|
+
const messagesForSwitchingDeviceCustomNames = mqtt.messagesByWildcard(topics.switchingDeviceCustomNames);
|
|
29
|
+
const messagesForSwitchingDeviceProductNames = mqtt.messagesByWildcard(topics.switchingDeviceProductNames);
|
|
24
30
|
useEffect(() => {
|
|
25
31
|
if (!hasMessages(messagesForSystemOutputs) &&
|
|
26
32
|
!hasMessages(messagesForSwitchOutputs) &&
|
|
@@ -45,12 +51,11 @@ export const useSwitchingPane = (gxDeviceRelaysGroupName) => {
|
|
|
45
51
|
const genericInputTypes = inputGroupTopics.map((t) => Number(messagesForInputs[`${t.slice(0, -"/Group".length)}/Type`]));
|
|
46
52
|
const genericInputNames = inputGroupTopics.map((t) => messagesForInputs[`${t.slice(0, -"/Group".length)}/CustomName`]);
|
|
47
53
|
const genericInputVisibilityFlags = inputGroupTopics.map((t) => Number(messagesForInputs[`${t.slice(0, -"/Group".length)}/ShowUIInput`]));
|
|
48
|
-
const switchingDevices = Object.keys(
|
|
49
|
-
.filter((k) => k.endsWith("/DeviceInstance"))
|
|
50
|
-
.sort();
|
|
54
|
+
const switchingDevices = Object.keys(messagesForSwitchingDeviceInstances).sort();
|
|
51
55
|
const switchingDeviceNames = switchingDevices.map((t) => {
|
|
52
56
|
const prefix = t.slice(0, -"/DeviceInstance".length);
|
|
53
|
-
return
|
|
57
|
+
return (messagesForSwitchingDeviceCustomNames[`${prefix}/CustomName`] ||
|
|
58
|
+
messagesForSwitchingDeviceProductNames[`${prefix}/ProductName`]);
|
|
54
59
|
});
|
|
55
60
|
// --- Phase B: comparison guard, batched in a single action ---
|
|
56
61
|
runInAction(() => {
|
|
@@ -194,7 +199,9 @@ export const useSwitchingPane = (gxDeviceRelaysGroupName) => {
|
|
|
194
199
|
messagesForSystemOutputs,
|
|
195
200
|
messagesForSwitchOutputs,
|
|
196
201
|
messagesForInputs,
|
|
197
|
-
|
|
202
|
+
messagesForSwitchingDeviceInstances,
|
|
203
|
+
messagesForSwitchingDeviceCustomNames,
|
|
204
|
+
messagesForSwitchingDeviceProductNames,
|
|
198
205
|
gxDeviceRelaysGroupName,
|
|
199
206
|
mqtt,
|
|
200
207
|
store,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SwitchingPane.provider.js","sourceRoot":"/","sources":["src/Modules/SwitchingPane/SwitchingPane.provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { runInAction, untracked } from \"mobx\"\nimport Logger from \"../../utils/logger\"\nimport { useMqtt } from \"../Mqtt\"\nimport { useMemo, useEffect } from \"react\"\nimport { useSwitchingPaneStore } from \"./SwitchingPane.store\"\nimport { getSwitchingDeviceStateTopics, SwitchingDeviceInstanceId } from \"./SwitchingDevice.provider\"\nimport {\n getSwitchingPaneItemNameForDisplay,\n getSwitchableOutputStateTopics,\n SWITCHABLE_OUTPUT_TREES,\n SwitchableOutputId,\n SwitchableOutputState,\n SwitchableOutputTree,\n GenericInputState,\n SwitchingPaneItem,\n} from \"./SwitchableOutput.provider\"\nimport { getGenericInputStateTopics, GenericInputId } from \"./GenericInput.provider\"\nimport {\n GenericInputType,\n remapGenericInputType,\n SwitchableOutputType,\n SwitchableOutputVisibility,\n SWITCHABLE_OUTPUT_FUNCTION,\n SWITCHABLE_OUTPUT_VISIBILITY,\n} from \"../../utils/constants\"\n\nconst hasMessages = (messages: Record<string, string> | undefined) => messages && Object.keys(messages).length > 0\n\nexport const useSwitchingPane = (gxDeviceRelaysGroupName: string) => {\n const store = useSwitchingPaneStore()\n const mqtt = useMqtt()\n\n const topics = useMemo(\n () => ({\n systemOutputs: `N/${mqtt.portalId}/system/+/SwitchableOutput/+/Settings/+`,\n switchOutputs: `N/${mqtt.portalId}/switch/+/SwitchableOutput/+/Settings/+`,\n genericInputs: `N/${mqtt.portalId}/switch/+/GenericInput/+/Settings/+`,\n switchingDevices: `N/${mqtt.portalId}/switch/+`,\n }),\n [mqtt.portalId]\n )\n\n const messagesForSystemOutputs = mqtt.messagesByWildcard(topics.systemOutputs)\n const messagesForSwitchOutputs = mqtt.messagesByWildcard(topics.switchOutputs)\n const messagesForInputs = mqtt.messagesByWildcard(topics.genericInputs)\n const messagesForSwitchingDevices = mqtt.messagesByWildcard(topics.switchingDevices)\n\n useEffect(() => {\n if (\n !hasMessages(messagesForSystemOutputs) &&\n !hasMessages(messagesForSwitchOutputs) &&\n !hasMessages(messagesForInputs)\n ) {\n Logger.log(\"Waiting for switchable outputs or generic inputs...\")\n return\n }\n\n // --- Phase A: Extract comparison arrays from wildcard messages (cheap) ---\n\n const messagesForOutputs = { ...messagesForSystemOutputs, ...messagesForSwitchOutputs }\n\n const outputGroupTopics = Object.keys(messagesForOutputs)\n .filter((k) => k.endsWith(\"/Settings/Group\"))\n .sort()\n\n const customGroupAssignments = outputGroupTopics.map((t) => messagesForOutputs[t])\n const outputTypes = outputGroupTopics.map(\n (t) => Number(messagesForOutputs[`${t.slice(0, -\"/Group\".length)}/Type`]) as SwitchableOutputType\n )\n const outputNames = outputGroupTopics.map((t) => messagesForOutputs[`${t.slice(0, -\"/Group\".length)}/CustomName`])\n const outputVisibilityFlags = outputGroupTopics.map(\n (t) => Number(messagesForOutputs[`${t.slice(0, -\"/Group\".length)}/ShowUIControl`]) as SwitchableOutputVisibility\n )\n const outputFunctions = outputGroupTopics.map((t) =>\n Number(messagesForOutputs[`${t.slice(0, -\"/Group\".length)}/Function`])\n )\n\n const inputGroupTopics = Object.keys(messagesForInputs)\n .filter((k) => k.endsWith(\"/Settings/Group\"))\n .sort()\n\n const genericInputGroupAssignments = inputGroupTopics.map((t) => messagesForInputs[t])\n const genericInputTypes = inputGroupTopics.map(\n (t) => Number(messagesForInputs[`${t.slice(0, -\"/Group\".length)}/Type`]) as GenericInputType\n )\n const genericInputNames = inputGroupTopics.map(\n (t) => messagesForInputs[`${t.slice(0, -\"/Group\".length)}/CustomName`]\n )\n const genericInputVisibilityFlags = inputGroupTopics.map(\n (t) => Number(messagesForInputs[`${t.slice(0, -\"/Group\".length)}/ShowUIInput`]) as SwitchableOutputVisibility\n )\n\n const switchingDevices = Object.keys(messagesForSwitchingDevices)\n .filter((k) => k.endsWith(\"/DeviceInstance\"))\n .sort()\n const switchingDeviceNames = switchingDevices.map((t) => {\n const prefix = t.slice(0, -\"/DeviceInstance\".length)\n return messagesForSwitchingDevices[`${prefix}/CustomName`] || messagesForSwitchingDevices[`${prefix}/ProductName`]\n })\n\n // --- Phase B: comparison guard, batched in a single action ---\n\n runInAction(() => {\n const groupAssignmentsChanged = !arraysEqual(store.customGroupAssignments, customGroupAssignments)\n if (groupAssignmentsChanged) store.setCustomGroupAssignments(customGroupAssignments)\n\n const outputTypesChanged = !arraysEqual(store.outputTypes, outputTypes)\n if (outputTypesChanged) store.setOutputTypes(outputTypes)\n\n const outputNamesChanged = !arraysEqual(store.outputNames, outputNames)\n if (outputNamesChanged) store.setOutputNames(outputNames)\n\n const outputVisibilityFlagsChanged = !arraysEqual(store.outputVisibilityFlags, outputVisibilityFlags)\n if (outputVisibilityFlagsChanged) store.setOutputVisibilityFlags(outputVisibilityFlags)\n\n const outputFunctionsChanged = !arraysEqual(store.outputFunctions, outputFunctions)\n if (outputFunctionsChanged) store.setOutputFunctions(outputFunctions)\n\n const switchingDevicesChanged = !arraysEqual(store.switchingDevices, switchingDevices)\n if (switchingDevicesChanged) store.setSwitchingDevices(switchingDevices)\n\n const switchingDeviceNamesChanged = !arraysEqual(store.switchingDeviceNames, switchingDeviceNames)\n if (switchingDeviceNamesChanged) store.setSwitchingDeviceNames(switchingDeviceNames)\n\n const giGroupAssignmentsChanged = !arraysEqual(store.genericInputGroupAssignments, genericInputGroupAssignments)\n if (giGroupAssignmentsChanged) store.setGenericInputGroupAssignments(genericInputGroupAssignments)\n\n const giTypesChanged = !arraysEqual(store.genericInputTypes, genericInputTypes)\n if (giTypesChanged) store.setGenericInputTypes(genericInputTypes)\n\n const giNamesChanged = !arraysEqual(store.genericInputNames, genericInputNames)\n if (giNamesChanged) store.setGenericInputNames(genericInputNames)\n\n const giVisibilityFlagsChanged = !arraysEqual(store.genericInputVisibilityFlags, genericInputVisibilityFlags)\n if (giVisibilityFlagsChanged) store.setGenericInputVisibilityFlags(genericInputVisibilityFlags)\n\n const isInitialLoad =\n store.customGroupAssignments.length === 0 &&\n store.outputTypes.length === 0 &&\n store.switchingDevices.length === 0 &&\n store.genericInputGroupAssignments.length === 0\n\n if (!isInitialLoad) {\n if (groupAssignmentsChanged) Logger.log(`Switchable outputs group assignments changed, recomputing...`)\n if (outputTypesChanged) Logger.log(`Switchable outputs types changed, recomputing...`)\n if (outputNamesChanged) Logger.log(`Switchable outputs names changed, recomputing...`)\n if (outputVisibilityFlagsChanged) Logger.log(`Switchable outputs visibility flags changed, recomputing...`)\n if (outputFunctionsChanged) Logger.log(`Switchable outputs functions changed, recomputing...`)\n if (switchingDevicesChanged) Logger.log(`Switching devices changed, recomputing...`)\n if (switchingDeviceNamesChanged) Logger.log(`Switching device names changed, recomputing...`)\n if (giGroupAssignmentsChanged) Logger.log(`Generic input group assignments changed, recomputing...`)\n if (giTypesChanged) Logger.log(`Generic input types changed, recomputing...`)\n if (giNamesChanged) Logger.log(`Generic input names changed, recomputing...`)\n if (giVisibilityFlagsChanged) Logger.log(`Generic input visibility flags changed, recomputing...`)\n }\n\n if (\n groupAssignmentsChanged ||\n outputTypesChanged ||\n outputNamesChanged ||\n outputVisibilityFlagsChanged ||\n outputFunctionsChanged ||\n switchingDevicesChanged ||\n switchingDeviceNamesChanged ||\n giGroupAssignmentsChanged ||\n giTypesChanged ||\n giNamesChanged ||\n giVisibilityFlagsChanged\n ) {\n const items: { groupName: string; item: SwitchingPaneItem }[] = []\n\n for (const topic of outputGroupTopics) {\n const info = extractSwitchableOutputInfo(topic)\n\n const { deviceName, output } = untracked(() => {\n const device = mqtt.messagesByTopics(\n getSwitchingDeviceStateTopics(mqtt.portalId, info.tree, info.deviceId)\n ) as unknown as Record<string, string>\n const out = mqtt.messagesByTopics(\n getSwitchableOutputStateTopics(mqtt.portalId, info.tree, info.deviceId, info.outputId)\n ) as unknown as SwitchableOutputState\n return {\n deviceName: device.customName || device.productName || gxDeviceRelaysGroupName,\n output: out,\n }\n })\n\n if (\n !(\n output.showUIControl & SWITCHABLE_OUTPUT_VISIBILITY.VISIBLE ||\n output.showUIControl & SWITCHABLE_OUTPUT_VISIBILITY.VISIBLE_LOCAL_UI\n )\n ) {\n continue\n }\n\n // GX system relays: only show when Function is Manual (matching gui-v2)\n if (\n info.tree === \"system\" &&\n output.function != null &&\n output.function !== SWITCHABLE_OUTPUT_FUNCTION.MANUAL\n ) {\n continue\n }\n\n const customGroup = (messagesForOutputs[topic] ?? \"\").trim()\n\n items.push({\n groupName: customGroup === \"\" ? deviceName : customGroup,\n item: {\n ...output,\n kind: \"switchableOutput\",\n tree: info.tree,\n deviceId: info.deviceId,\n outputId: info.outputId,\n parentDeviceName: deviceName as string,\n },\n })\n }\n\n for (const topic of inputGroupTopics) {\n const info = extractGenericInputInfo(topic)\n\n const { deviceName, input } = untracked(() => {\n const device = mqtt.messagesByTopics(\n getSwitchingDeviceStateTopics(mqtt.portalId, info.tree, info.deviceId)\n ) as unknown as Record<string, string>\n const inp = mqtt.messagesByTopics(\n getGenericInputStateTopics(mqtt.portalId, info.tree, info.deviceId, info.inputId)\n ) as unknown as GenericInputState\n return {\n deviceName: device.customName || device.productName || gxDeviceRelaysGroupName,\n input: inp,\n }\n })\n\n if (\n !(\n input.showUIControl & SWITCHABLE_OUTPUT_VISIBILITY.VISIBLE ||\n input.showUIControl & SWITCHABLE_OUTPUT_VISIBILITY.VISIBLE_LOCAL_UI\n )\n ) {\n continue\n }\n\n const customGroup = (messagesForInputs[topic] ?? \"\").trim()\n\n items.push({\n groupName: customGroup === \"\" ? deviceName : customGroup,\n item: {\n ...input,\n kind: \"genericInput\",\n tree: info.tree,\n deviceId: info.deviceId,\n outputId: info.inputId,\n parentDeviceName: deviceName as string,\n type: remapGenericInputType(input.type as number),\n },\n })\n }\n\n const groups: { [key: string]: SwitchingPaneItem[] } = {}\n for (const { groupName, item } of items) {\n ;(groups[groupName] ||= []).push(item)\n }\n\n for (const arr of Object.values(groups)) {\n arr.sort((a, b) => {\n const aName = getSwitchingPaneItemNameForDisplay(a, a.parentDeviceName)\n const bName = getSwitchingPaneItemNameForDisplay(b, b.parentDeviceName)\n return aName.localeCompare(bName)\n })\n }\n\n Logger.log(`New switching pane groups: ${JSON.stringify(Object.keys(groups))}`)\n store.setGroups(groups)\n }\n })\n }, [\n messagesForSystemOutputs,\n messagesForSwitchOutputs,\n messagesForInputs,\n messagesForSwitchingDevices,\n gxDeviceRelaysGroupName,\n mqtt,\n store,\n ])\n\n return store\n}\n\nexport function extractSwitchableOutputInfo(topic: string) {\n const pattern = new RegExp(`/(${SWITCHABLE_OUTPUT_TREES.join(\"|\")})/`)\n const match = topic.match(pattern)\n const switchStart = match ? match.index! + match[0].length : -1\n const outputStart = topic.indexOf(\"/SwitchableOutput/\") + 18\n\n return {\n tree: (match?.[1] as SwitchableOutputTree) ?? null,\n deviceId: Number(topic.substring(switchStart, topic.indexOf(\"/\", switchStart))) as SwitchingDeviceInstanceId,\n outputId: topic.substring(outputStart, topic.indexOf(\"/\", outputStart)) as SwitchableOutputId,\n }\n}\n\nexport function extractGenericInputInfo(topic: string) {\n const pattern = new RegExp(`/(${SWITCHABLE_OUTPUT_TREES.join(\"|\")})/`)\n const match = topic.match(pattern)\n const treeEnd = match ? match.index! + match[0].length : -1\n const inputStart = topic.indexOf(\"/GenericInput/\") + 14\n\n return {\n tree: (match?.[1] as SwitchableOutputTree) ?? null,\n deviceId: Number(topic.substring(treeEnd, topic.indexOf(\"/\", treeEnd))) as SwitchingDeviceInstanceId,\n inputId: topic.substring(inputStart, topic.indexOf(\"/\", inputStart)) as GenericInputId,\n }\n}\n\nexport function arraysEqual<T>(a: T[], b: T[]): boolean {\n if (a.length !== b.length) return false\n return a.every((element, index) => Object.is(element, b[index]))\n}\n"]}
|
|
1
|
+
{"version":3,"file":"SwitchingPane.provider.js","sourceRoot":"/","sources":["src/Modules/SwitchingPane/SwitchingPane.provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { runInAction, untracked } from \"mobx\"\nimport Logger from \"../../utils/logger\"\nimport { useMqtt } from \"../Mqtt\"\nimport { useMemo, useEffect } from \"react\"\nimport { useSwitchingPaneStore } from \"./SwitchingPane.store\"\nimport { getSwitchingDeviceStateTopics, SwitchingDeviceInstanceId } from \"./SwitchingDevice.provider\"\nimport {\n getSwitchingPaneItemNameForDisplay,\n getSwitchableOutputStateTopics,\n SWITCHABLE_OUTPUT_TREES,\n SwitchableOutputId,\n SwitchableOutputState,\n SwitchableOutputTree,\n GenericInputState,\n SwitchingPaneItem,\n} from \"./SwitchableOutput.provider\"\nimport { getGenericInputStateTopics, GenericInputId } from \"./GenericInput.provider\"\nimport {\n GenericInputType,\n remapGenericInputType,\n SwitchableOutputType,\n SwitchableOutputVisibility,\n SWITCHABLE_OUTPUT_FUNCTION,\n SWITCHABLE_OUTPUT_VISIBILITY,\n} from \"../../utils/constants\"\n\nconst hasMessages = (messages: Record<string, string> | undefined) => messages && Object.keys(messages).length > 0\n\nexport const useSwitchingPane = (gxDeviceRelaysGroupName: string) => {\n const store = useSwitchingPaneStore()\n const mqtt = useMqtt()\n\n const topics = useMemo(\n () => ({\n systemOutputs: `N/${mqtt.portalId}/system/+/SwitchableOutput/+/Settings/+`,\n switchOutputs: `N/${mqtt.portalId}/switch/+/SwitchableOutput/+/Settings/+`,\n genericInputs: `N/${mqtt.portalId}/switch/+/GenericInput/+/Settings/+`,\n // NOTE: deliberately precise (not `switch/+`) so that high-frequency operational\n // NOTE: values (State, Dimming, Status, ...) do not invalidate the grouping below\n switchingDeviceInstances: `N/${mqtt.portalId}/switch/+/DeviceInstance`,\n switchingDeviceCustomNames: `N/${mqtt.portalId}/switch/+/CustomName`,\n switchingDeviceProductNames: `N/${mqtt.portalId}/switch/+/ProductName`,\n }),\n [mqtt.portalId]\n )\n\n const messagesForSystemOutputs = mqtt.messagesByWildcard(topics.systemOutputs)\n const messagesForSwitchOutputs = mqtt.messagesByWildcard(topics.switchOutputs)\n const messagesForInputs = mqtt.messagesByWildcard(topics.genericInputs)\n const messagesForSwitchingDeviceInstances = mqtt.messagesByWildcard(topics.switchingDeviceInstances)\n const messagesForSwitchingDeviceCustomNames = mqtt.messagesByWildcard(topics.switchingDeviceCustomNames)\n const messagesForSwitchingDeviceProductNames = mqtt.messagesByWildcard(topics.switchingDeviceProductNames)\n\n useEffect(() => {\n if (\n !hasMessages(messagesForSystemOutputs) &&\n !hasMessages(messagesForSwitchOutputs) &&\n !hasMessages(messagesForInputs)\n ) {\n Logger.log(\"Waiting for switchable outputs or generic inputs...\")\n return\n }\n\n // --- Phase A: Extract comparison arrays from wildcard messages (cheap) ---\n\n const messagesForOutputs = { ...messagesForSystemOutputs, ...messagesForSwitchOutputs }\n\n const outputGroupTopics = Object.keys(messagesForOutputs)\n .filter((k) => k.endsWith(\"/Settings/Group\"))\n .sort()\n\n const customGroupAssignments = outputGroupTopics.map((t) => messagesForOutputs[t])\n const outputTypes = outputGroupTopics.map(\n (t) => Number(messagesForOutputs[`${t.slice(0, -\"/Group\".length)}/Type`]) as SwitchableOutputType\n )\n const outputNames = outputGroupTopics.map((t) => messagesForOutputs[`${t.slice(0, -\"/Group\".length)}/CustomName`])\n const outputVisibilityFlags = outputGroupTopics.map(\n (t) => Number(messagesForOutputs[`${t.slice(0, -\"/Group\".length)}/ShowUIControl`]) as SwitchableOutputVisibility\n )\n const outputFunctions = outputGroupTopics.map((t) =>\n Number(messagesForOutputs[`${t.slice(0, -\"/Group\".length)}/Function`])\n )\n\n const inputGroupTopics = Object.keys(messagesForInputs)\n .filter((k) => k.endsWith(\"/Settings/Group\"))\n .sort()\n\n const genericInputGroupAssignments = inputGroupTopics.map((t) => messagesForInputs[t])\n const genericInputTypes = inputGroupTopics.map(\n (t) => Number(messagesForInputs[`${t.slice(0, -\"/Group\".length)}/Type`]) as GenericInputType\n )\n const genericInputNames = inputGroupTopics.map(\n (t) => messagesForInputs[`${t.slice(0, -\"/Group\".length)}/CustomName`]\n )\n const genericInputVisibilityFlags = inputGroupTopics.map(\n (t) => Number(messagesForInputs[`${t.slice(0, -\"/Group\".length)}/ShowUIInput`]) as SwitchableOutputVisibility\n )\n\n const switchingDevices = Object.keys(messagesForSwitchingDeviceInstances).sort()\n const switchingDeviceNames = switchingDevices.map((t) => {\n const prefix = t.slice(0, -\"/DeviceInstance\".length)\n return (\n messagesForSwitchingDeviceCustomNames[`${prefix}/CustomName`] ||\n messagesForSwitchingDeviceProductNames[`${prefix}/ProductName`]\n )\n })\n\n // --- Phase B: comparison guard, batched in a single action ---\n\n runInAction(() => {\n const groupAssignmentsChanged = !arraysEqual(store.customGroupAssignments, customGroupAssignments)\n if (groupAssignmentsChanged) store.setCustomGroupAssignments(customGroupAssignments)\n\n const outputTypesChanged = !arraysEqual(store.outputTypes, outputTypes)\n if (outputTypesChanged) store.setOutputTypes(outputTypes)\n\n const outputNamesChanged = !arraysEqual(store.outputNames, outputNames)\n if (outputNamesChanged) store.setOutputNames(outputNames)\n\n const outputVisibilityFlagsChanged = !arraysEqual(store.outputVisibilityFlags, outputVisibilityFlags)\n if (outputVisibilityFlagsChanged) store.setOutputVisibilityFlags(outputVisibilityFlags)\n\n const outputFunctionsChanged = !arraysEqual(store.outputFunctions, outputFunctions)\n if (outputFunctionsChanged) store.setOutputFunctions(outputFunctions)\n\n const switchingDevicesChanged = !arraysEqual(store.switchingDevices, switchingDevices)\n if (switchingDevicesChanged) store.setSwitchingDevices(switchingDevices)\n\n const switchingDeviceNamesChanged = !arraysEqual(store.switchingDeviceNames, switchingDeviceNames)\n if (switchingDeviceNamesChanged) store.setSwitchingDeviceNames(switchingDeviceNames)\n\n const giGroupAssignmentsChanged = !arraysEqual(store.genericInputGroupAssignments, genericInputGroupAssignments)\n if (giGroupAssignmentsChanged) store.setGenericInputGroupAssignments(genericInputGroupAssignments)\n\n const giTypesChanged = !arraysEqual(store.genericInputTypes, genericInputTypes)\n if (giTypesChanged) store.setGenericInputTypes(genericInputTypes)\n\n const giNamesChanged = !arraysEqual(store.genericInputNames, genericInputNames)\n if (giNamesChanged) store.setGenericInputNames(genericInputNames)\n\n const giVisibilityFlagsChanged = !arraysEqual(store.genericInputVisibilityFlags, genericInputVisibilityFlags)\n if (giVisibilityFlagsChanged) store.setGenericInputVisibilityFlags(genericInputVisibilityFlags)\n\n const isInitialLoad =\n store.customGroupAssignments.length === 0 &&\n store.outputTypes.length === 0 &&\n store.switchingDevices.length === 0 &&\n store.genericInputGroupAssignments.length === 0\n\n if (!isInitialLoad) {\n if (groupAssignmentsChanged) Logger.log(`Switchable outputs group assignments changed, recomputing...`)\n if (outputTypesChanged) Logger.log(`Switchable outputs types changed, recomputing...`)\n if (outputNamesChanged) Logger.log(`Switchable outputs names changed, recomputing...`)\n if (outputVisibilityFlagsChanged) Logger.log(`Switchable outputs visibility flags changed, recomputing...`)\n if (outputFunctionsChanged) Logger.log(`Switchable outputs functions changed, recomputing...`)\n if (switchingDevicesChanged) Logger.log(`Switching devices changed, recomputing...`)\n if (switchingDeviceNamesChanged) Logger.log(`Switching device names changed, recomputing...`)\n if (giGroupAssignmentsChanged) Logger.log(`Generic input group assignments changed, recomputing...`)\n if (giTypesChanged) Logger.log(`Generic input types changed, recomputing...`)\n if (giNamesChanged) Logger.log(`Generic input names changed, recomputing...`)\n if (giVisibilityFlagsChanged) Logger.log(`Generic input visibility flags changed, recomputing...`)\n }\n\n if (\n groupAssignmentsChanged ||\n outputTypesChanged ||\n outputNamesChanged ||\n outputVisibilityFlagsChanged ||\n outputFunctionsChanged ||\n switchingDevicesChanged ||\n switchingDeviceNamesChanged ||\n giGroupAssignmentsChanged ||\n giTypesChanged ||\n giNamesChanged ||\n giVisibilityFlagsChanged\n ) {\n const items: { groupName: string; item: SwitchingPaneItem }[] = []\n\n for (const topic of outputGroupTopics) {\n const info = extractSwitchableOutputInfo(topic)\n\n const { deviceName, output } = untracked(() => {\n const device = mqtt.messagesByTopics(\n getSwitchingDeviceStateTopics(mqtt.portalId, info.tree, info.deviceId)\n ) as unknown as Record<string, string>\n const out = mqtt.messagesByTopics(\n getSwitchableOutputStateTopics(mqtt.portalId, info.tree, info.deviceId, info.outputId)\n ) as unknown as SwitchableOutputState\n return {\n deviceName: device.customName || device.productName || gxDeviceRelaysGroupName,\n output: out,\n }\n })\n\n if (\n !(\n output.showUIControl & SWITCHABLE_OUTPUT_VISIBILITY.VISIBLE ||\n output.showUIControl & SWITCHABLE_OUTPUT_VISIBILITY.VISIBLE_LOCAL_UI\n )\n ) {\n continue\n }\n\n // GX system relays: only show when Function is Manual (matching gui-v2)\n if (\n info.tree === \"system\" &&\n output.function != null &&\n output.function !== SWITCHABLE_OUTPUT_FUNCTION.MANUAL\n ) {\n continue\n }\n\n const customGroup = (messagesForOutputs[topic] ?? \"\").trim()\n\n items.push({\n groupName: customGroup === \"\" ? deviceName : customGroup,\n item: {\n ...output,\n kind: \"switchableOutput\",\n tree: info.tree,\n deviceId: info.deviceId,\n outputId: info.outputId,\n parentDeviceName: deviceName as string,\n },\n })\n }\n\n for (const topic of inputGroupTopics) {\n const info = extractGenericInputInfo(topic)\n\n const { deviceName, input } = untracked(() => {\n const device = mqtt.messagesByTopics(\n getSwitchingDeviceStateTopics(mqtt.portalId, info.tree, info.deviceId)\n ) as unknown as Record<string, string>\n const inp = mqtt.messagesByTopics(\n getGenericInputStateTopics(mqtt.portalId, info.tree, info.deviceId, info.inputId)\n ) as unknown as GenericInputState\n return {\n deviceName: device.customName || device.productName || gxDeviceRelaysGroupName,\n input: inp,\n }\n })\n\n if (\n !(\n input.showUIControl & SWITCHABLE_OUTPUT_VISIBILITY.VISIBLE ||\n input.showUIControl & SWITCHABLE_OUTPUT_VISIBILITY.VISIBLE_LOCAL_UI\n )\n ) {\n continue\n }\n\n const customGroup = (messagesForInputs[topic] ?? \"\").trim()\n\n items.push({\n groupName: customGroup === \"\" ? deviceName : customGroup,\n item: {\n ...input,\n kind: \"genericInput\",\n tree: info.tree,\n deviceId: info.deviceId,\n outputId: info.inputId,\n parentDeviceName: deviceName as string,\n type: remapGenericInputType(input.type as number),\n },\n })\n }\n\n const groups: { [key: string]: SwitchingPaneItem[] } = {}\n for (const { groupName, item } of items) {\n ;(groups[groupName] ||= []).push(item)\n }\n\n for (const arr of Object.values(groups)) {\n arr.sort((a, b) => {\n const aName = getSwitchingPaneItemNameForDisplay(a, a.parentDeviceName)\n const bName = getSwitchingPaneItemNameForDisplay(b, b.parentDeviceName)\n return aName.localeCompare(bName)\n })\n }\n\n Logger.log(`New switching pane groups: ${JSON.stringify(Object.keys(groups))}`)\n store.setGroups(groups)\n }\n })\n }, [\n messagesForSystemOutputs,\n messagesForSwitchOutputs,\n messagesForInputs,\n messagesForSwitchingDeviceInstances,\n messagesForSwitchingDeviceCustomNames,\n messagesForSwitchingDeviceProductNames,\n gxDeviceRelaysGroupName,\n mqtt,\n store,\n ])\n\n return store\n}\n\nexport function extractSwitchableOutputInfo(topic: string) {\n const pattern = new RegExp(`/(${SWITCHABLE_OUTPUT_TREES.join(\"|\")})/`)\n const match = topic.match(pattern)\n const switchStart = match ? match.index! + match[0].length : -1\n const outputStart = topic.indexOf(\"/SwitchableOutput/\") + 18\n\n return {\n tree: (match?.[1] as SwitchableOutputTree) ?? null,\n deviceId: Number(topic.substring(switchStart, topic.indexOf(\"/\", switchStart))) as SwitchingDeviceInstanceId,\n outputId: topic.substring(outputStart, topic.indexOf(\"/\", outputStart)) as SwitchableOutputId,\n }\n}\n\nexport function extractGenericInputInfo(topic: string) {\n const pattern = new RegExp(`/(${SWITCHABLE_OUTPUT_TREES.join(\"|\")})/`)\n const match = topic.match(pattern)\n const treeEnd = match ? match.index! + match[0].length : -1\n const inputStart = topic.indexOf(\"/GenericInput/\") + 14\n\n return {\n tree: (match?.[1] as SwitchableOutputTree) ?? null,\n deviceId: Number(topic.substring(treeEnd, topic.indexOf(\"/\", treeEnd))) as SwitchingDeviceInstanceId,\n inputId: topic.substring(inputStart, topic.indexOf(\"/\", inputStart)) as GenericInputId,\n }\n}\n\nexport function arraysEqual<T>(a: T[], b: T[]): boolean {\n if (a.length !== b.length) return false\n return a.every((element, index) => Object.is(element, b[index]))\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tanks.provider.d.ts","sourceRoot":"/","sources":["src/Modules/Tanks/Tanks.provider.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,QAAQ,
|
|
1
|
+
{"version":3,"file":"Tanks.provider.d.ts","sourceRoot":"/","sources":["src/Modules/Tanks/Tanks.provider.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,QAAQ,0CAuCpB,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { untracked } from "mobx";
|
|
2
2
|
import Logger from "../../utils/logger";
|
|
3
3
|
import { useMqtt } from "../Mqtt";
|
|
4
4
|
import { getTankStateTopics } from "./Tank.provider";
|
|
@@ -13,24 +13,21 @@ export const useTanks = () => {
|
|
|
13
13
|
const topics = useMemo(() => getTopics(mqtt.portalId), [mqtt.portalId]);
|
|
14
14
|
const messages = mqtt.messagesByWildcard(topics.tanks);
|
|
15
15
|
useEffect(() => {
|
|
16
|
-
if (!messages || Object.
|
|
16
|
+
if (!messages || Object.keys(messages).length === 0) {
|
|
17
17
|
// Logger.log("Waiting for tanks...")
|
|
18
|
+
return;
|
|
18
19
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
tanksStore.setTanks(newTanks);
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
return () => dispose();
|
|
20
|
+
const deviceInstances = Object.values(messages);
|
|
21
|
+
const oldTanks = tanksStore.tanks;
|
|
22
|
+
const instanceSet = new Set(deviceInstances);
|
|
23
|
+
if (!oldTanks ||
|
|
24
|
+
oldTanks.length !== deviceInstances.length ||
|
|
25
|
+
!oldTanks.every((tank) => instanceSet.has(tank.instance))) {
|
|
26
|
+
Logger.log(`New tanks instances: ${JSON.stringify(deviceInstances)}`);
|
|
27
|
+
// NOTE: snapshot tank state untracked — per-tank values are observed live via useTank,
|
|
28
|
+
// NOTE: the store list only needs refreshing when the set of tanks changes
|
|
29
|
+
const newTanks = untracked(() => deviceInstances.map((tankInstanceId) => mqtt.messagesByTopics(getTankStateTopics(mqtt.portalId, tankInstanceId))));
|
|
30
|
+
tanksStore.setTanks(newTanks);
|
|
34
31
|
}
|
|
35
32
|
}, [messages, mqtt, tanksStore]);
|
|
36
33
|
return tanksStore;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tanks.provider.js","sourceRoot":"/","sources":["src/Modules/Tanks/Tanks.provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"Tanks.provider.js","sourceRoot":"/","sources":["src/Modules/Tanks/Tanks.provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAA;AAChC,OAAO,MAAM,MAAM,oBAAoB,CAAA;AACvC,OAAO,EAAY,OAAO,EAAE,MAAM,SAAS,CAAA;AAC3C,OAAO,EAAE,kBAAkB,EAA6B,MAAM,iBAAiB,CAAA;AAC/E,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAE1C,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAG,EAAE;IAC3B,MAAM,UAAU,GAAG,aAAa,EAAE,CAAA;IAElC,MAAM,SAAS,GAAG,CAAC,QAAkB,EAAE,EAAE,CAAC,CAAC;QACzC,KAAK,EAAE,KAAK,QAAQ,wBAAwB;KAC7C,CAAC,CAAA;IAEF,MAAM,IAAI,GAAG,OAAO,EAAE,CAAA;IACtB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAA;IAEvE,MAAM,QAAQ,GAAG,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAEtD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACpD,qCAAqC;YACrC,OAAM;QACR,CAAC;QAED,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAqB,CAAA;QACnE,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAA;QACjC,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,CAAA;QAC5C,IACE,CAAC,QAAQ;YACT,QAAQ,CAAC,MAAM,KAAK,eAAe,CAAC,MAAM;YAC1C,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EACzD,CAAC;YACD,MAAM,CAAC,GAAG,CAAC,wBAAwB,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,EAAE,CAAC,CAAA;YACrE,uFAAuF;YACvF,2EAA2E;YAC3E,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,EAAE,CAC9B,eAAe,CAAC,GAAG,CAAC,CAAC,cAAc,EAAE,EAAE,CACrC,IAAI,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC,CACzE,CACwB,CAAA;YAC3B,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;QAC/B,CAAC;IACH,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAA;IAEhC,OAAO,UAAU,CAAA;AACnB,CAAC,CAAA","sourcesContent":["import { untracked } from \"mobx\"\nimport Logger from \"../../utils/logger\"\nimport { PortalId, useMqtt } from \"../Mqtt\"\nimport { getTankStateTopics, TankInstanceId, TankState } from \"./Tank.provider\"\nimport { useTanksStore } from \"./Tanks.store\"\nimport { useMemo, useEffect } from \"react\"\n\nexport const useTanks = () => {\n const tanksStore = useTanksStore()\n\n const getTopics = (portalId: PortalId) => ({\n tanks: `N/${portalId}/tank/+/DeviceInstance`,\n })\n\n const mqtt = useMqtt()\n const topics = useMemo(() => getTopics(mqtt.portalId), [mqtt.portalId])\n\n const messages = mqtt.messagesByWildcard(topics.tanks)\n\n useEffect(() => {\n if (!messages || Object.keys(messages).length === 0) {\n // Logger.log(\"Waiting for tanks...\")\n return\n }\n\n const deviceInstances = Object.values(messages) as TankInstanceId[]\n const oldTanks = tanksStore.tanks\n const instanceSet = new Set(deviceInstances)\n if (\n !oldTanks ||\n oldTanks.length !== deviceInstances.length ||\n !oldTanks.every((tank) => instanceSet.has(tank.instance))\n ) {\n Logger.log(`New tanks instances: ${JSON.stringify(deviceInstances)}`)\n // NOTE: snapshot tank state untracked — per-tank values are observed live via useTank,\n // NOTE: the store list only needs refreshing when the set of tanks changes\n const newTanks = untracked(() =>\n deviceInstances.map((tankInstanceId) =>\n mqtt.messagesByTopics(getTankStateTopics(mqtt.portalId, tankInstanceId))\n )\n ) as unknown as TankState[]\n tanksStore.setTanks(newTanks)\n }\n }, [messages, mqtt, tanksStore])\n\n return tanksStore\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Temperatures.provider.d.ts","sourceRoot":"/","sources":["src/Modules/Temperatures/Temperatures.provider.ts"],"names":[],"mappings":"AAOA,wBAAgB,eAAe,
|
|
1
|
+
{"version":3,"file":"Temperatures.provider.d.ts","sourceRoot":"/","sources":["src/Modules/Temperatures/Temperatures.provider.ts"],"names":[],"mappings":"AAOA,wBAAgB,eAAe,qDAuC9B"}
|
|
@@ -3,7 +3,7 @@ import { useMqtt } from "../Mqtt";
|
|
|
3
3
|
import { useTemperaturesStore } from "./Temperatures.store";
|
|
4
4
|
import Logger from "../../utils/logger";
|
|
5
5
|
import { getTemperatureStateTopics } from "./Temperature.provider";
|
|
6
|
-
import {
|
|
6
|
+
import { untracked } from "mobx";
|
|
7
7
|
export function useTemperatures() {
|
|
8
8
|
const temperaturesStore = useTemperaturesStore();
|
|
9
9
|
const mqtt = useMqtt();
|
|
@@ -13,24 +13,21 @@ export function useTemperatures() {
|
|
|
13
13
|
const topics = useMemo(() => getTopics(mqtt.portalId), [mqtt.portalId]);
|
|
14
14
|
const messages = mqtt.messagesByWildcard(topics.temperatureInstances);
|
|
15
15
|
useEffect(() => {
|
|
16
|
-
if (!messages || Object.
|
|
16
|
+
if (!messages || Object.keys(messages).length === 0) {
|
|
17
17
|
// Logger.log("Waiting for temperatures...");
|
|
18
|
+
return;
|
|
18
19
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
temperaturesStore.setTemperatures(newTemperatures);
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
return () => dispose();
|
|
20
|
+
const deviceInstances = Object.values(messages);
|
|
21
|
+
const oldTemperatures = temperaturesStore.temperatures;
|
|
22
|
+
const instanceSet = new Set(deviceInstances);
|
|
23
|
+
if (!oldTemperatures ||
|
|
24
|
+
oldTemperatures.length !== deviceInstances.length ||
|
|
25
|
+
!oldTemperatures.every((temperature) => instanceSet.has(temperature.instance))) {
|
|
26
|
+
Logger.log(`New temperatures instances: ${JSON.stringify(deviceInstances)}`);
|
|
27
|
+
// NOTE: snapshot temperature state untracked — per-sensor values are observed live via useTemperature,
|
|
28
|
+
// NOTE: the store list only needs refreshing when the set of sensors changes
|
|
29
|
+
const newTemperatures = untracked(() => deviceInstances.map((temperatureInstanceId) => mqtt.messagesByTopics(getTemperatureStateTopics(mqtt.portalId, temperatureInstanceId))));
|
|
30
|
+
temperaturesStore.setTemperatures(newTemperatures);
|
|
34
31
|
}
|
|
35
32
|
}, [messages, mqtt, temperaturesStore]);
|
|
36
33
|
return temperaturesStore;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Temperatures.provider.js","sourceRoot":"/","sources":["src/Modules/Temperatures/Temperatures.provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAC1C,OAAO,EAAY,OAAO,EAAE,MAAM,SAAS,CAAA;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AAC3D,OAAO,MAAM,MAAM,oBAAoB,CAAA;AACvC,OAAO,EAAE,yBAAyB,EAA2C,MAAM,wBAAwB,CAAA;AAC3G,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"Temperatures.provider.js","sourceRoot":"/","sources":["src/Modules/Temperatures/Temperatures.provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAC1C,OAAO,EAAY,OAAO,EAAE,MAAM,SAAS,CAAA;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AAC3D,OAAO,MAAM,MAAM,oBAAoB,CAAA;AACvC,OAAO,EAAE,yBAAyB,EAA2C,MAAM,wBAAwB,CAAA;AAC3G,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAA;AAEhC,MAAM,UAAU,eAAe;IAC7B,MAAM,iBAAiB,GAAG,oBAAoB,EAAE,CAAA;IAChD,MAAM,IAAI,GAAG,OAAO,EAAE,CAAA;IAEtB,MAAM,SAAS,GAAG,CAAC,QAAkB,EAAE,EAAE,CAAC,CAAC;QACzC,oBAAoB,EAAE,KAAK,QAAQ,+BAA+B;KACnE,CAAC,CAAA;IAEF,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAA;IAEvE,MAAM,QAAQ,GAAG,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAA;IAErE,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACpD,6CAA6C;YAC7C,OAAM;QACR,CAAC;QAED,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAA4B,CAAA;QAC1E,MAAM,eAAe,GAAG,iBAAiB,CAAC,YAAY,CAAA;QACtD,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,CAAA;QAC5C,IACE,CAAC,eAAe;YAChB,eAAe,CAAC,MAAM,KAAK,eAAe,CAAC,MAAM;YACjD,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,EAC9E,CAAC;YACD,MAAM,CAAC,GAAG,CAAC,+BAA+B,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,EAAE,CAAC,CAAA;YAC5E,uGAAuG;YACvG,6EAA6E;YAC7E,MAAM,eAAe,GAAG,SAAS,CAAC,GAAG,EAAE,CACrC,eAAe,CAAC,GAAG,CAAC,CAAC,qBAAqB,EAAE,EAAE,CAC5C,IAAI,CAAC,gBAAgB,CAAC,yBAAyB,CAAC,IAAI,CAAC,QAAQ,EAAE,qBAAqB,CAAC,CAAC,CACvF,CAC+B,CAAA;YAClC,iBAAiB,CAAC,eAAe,CAAC,eAAe,CAAC,CAAA;QACpD,CAAC;IACH,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAA;IAEvC,OAAO,iBAAiB,CAAA;AAC1B,CAAC","sourcesContent":["import { useEffect, useMemo } from \"react\"\nimport { PortalId, useMqtt } from \"../Mqtt\"\nimport { useTemperaturesStore } from \"./Temperatures.store\"\nimport Logger from \"../../utils/logger\"\nimport { getTemperatureStateTopics, TemperatureInstanceId, TemperatureState } from \"./Temperature.provider\"\nimport { untracked } from \"mobx\"\n\nexport function useTemperatures() {\n const temperaturesStore = useTemperaturesStore()\n const mqtt = useMqtt()\n\n const getTopics = (portalId: PortalId) => ({\n temperatureInstances: `N/${portalId}/temperature/+/DeviceInstance`,\n })\n\n const topics = useMemo(() => getTopics(mqtt.portalId), [mqtt.portalId])\n\n const messages = mqtt.messagesByWildcard(topics.temperatureInstances)\n\n useEffect(() => {\n if (!messages || Object.keys(messages).length === 0) {\n // Logger.log(\"Waiting for temperatures...\");\n return\n }\n\n const deviceInstances = Object.values(messages) as TemperatureInstanceId[]\n const oldTemperatures = temperaturesStore.temperatures\n const instanceSet = new Set(deviceInstances)\n if (\n !oldTemperatures ||\n oldTemperatures.length !== deviceInstances.length ||\n !oldTemperatures.every((temperature) => instanceSet.has(temperature.instance))\n ) {\n Logger.log(`New temperatures instances: ${JSON.stringify(deviceInstances)}`)\n // NOTE: snapshot temperature state untracked — per-sensor values are observed live via useTemperature,\n // NOTE: the store list only needs refreshing when the set of sensors changes\n const newTemperatures = untracked(() =>\n deviceInstances.map((temperatureInstanceId) =>\n mqtt.messagesByTopics(getTemperatureStateTopics(mqtt.portalId, temperatureInstanceId))\n )\n ) as unknown as TemperatureState[]\n temperaturesStore.setTemperatures(newTemperatures)\n }\n }, [messages, mqtt, temperaturesStore])\n\n return temperaturesStore\n}\n"]}
|