@victronenergy/mfd-modules 9.4.0 → 9.5.0

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.
@@ -12,10 +12,65 @@ export declare class MqttStore {
12
12
  keepAliveHandlerRef: any;
13
13
  queueWorker: any;
14
14
  meanQueueWorkerPassDuration: number;
15
+ urgentTopicPrefixes: string[];
16
+ /**
17
+ * Returns the current cached message for a given MQTT topic.
18
+ *
19
+ * React Components using this method will re-render when their specific
20
+ * topic's message changes.
21
+ *
22
+ * Using comparer.identity will trigger the re-renders any time
23
+ * a message arrives for the given topic. We rely on the fact
24
+ * that MQTT will only re-send a message when the value changes,
25
+ * or on a full keep alive.
26
+ *
27
+ * Note: Receiving the same message for a given topic will cause re-renders,
28
+ * as we do not check structural identity of the message.
29
+ *
30
+ * @param topic - The MQTT topic to retrieve the message for
31
+ * @returns The message object for the topic, or undefined if topic is not provided or not found
32
+ */
15
33
  messageFromTopic: (topic?: string) => MqttMessage;
34
+ /**
35
+ * Returns the current cached messages for a given set of MQTT topics.
36
+ *
37
+ * This is a memoized computed function - each set of topics has its own cached value.
38
+ *
39
+ * React Components using this method will re-render when
40
+ * any of the messages for specified topics change.
41
+ *
42
+ * Using comparer.identity will trigger the re-renders any time
43
+ * a message arrives for any of the specified topics. We rely on the fact
44
+ * that MQTT will only re-send a message when the value changes,
45
+ * or on a full keep alive.
46
+
47
+ * Note: Receiving the same message for a given topic will cause re-renders,
48
+ * as we do not check structural identity of the message.
49
+ *
50
+ * @param topics - The MQTT topics to retrieve the messages for
51
+ * @returns The messages objects for the given topics, or empty dictionary if topics not found
52
+ */
16
53
  messagesByTopics: (topics?: Topics) => {
17
54
  [key: string]: MqttMessage | MqttMessage[];
18
55
  };
56
+ /**
57
+ * Returns the current cached messages for MQTT topics specified via regex.
58
+ *
59
+ * React Components using this method will re-render when
60
+ * values of any of the matched topics change. The components also re-render
61
+ * when new MQTT topics are received and match needs to be checked.
62
+ *
63
+ * Using comparer.identity will trigger the re-renders any time
64
+ * a message arrives for any of the matched topics. We rely on the fact
65
+ * that MQTT will only re-send a message when the value changes,
66
+ * or on a full keep alive.
67
+ *
68
+ * Note: Receiving the same message for a given topic will cause re-renders,
69
+ * as we do not check structural identity of the message.
70
+ *
71
+ * @param wildcard - The MQTT wildcard to retrieve the message for
72
+ * @returns The messages objects for the given topics, or empty dictionary if topics not found
73
+ */
19
74
  messagesByWildcard: (wildcard?: string) => any;
20
75
  constructor();
21
76
  get isConnected(): boolean;
@@ -23,8 +78,8 @@ export declare class MqttStore {
23
78
  clearSubscribedTopics(): void;
24
79
  addMessage: (topic: string, message: {
25
80
  value: string | null;
26
- }) => Promise<void>;
27
- addMessagesFromQueue: () => Promise<void>;
81
+ }) => void;
82
+ addMessagesFromQueue: () => void;
28
83
  scheduleNextQueueWorkerPass: (timeout: number) => void;
29
84
  setupQueueWorker: () => void;
30
85
  removeQueueWorker: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"Mqtt.store.d.ts","sourceRoot":"/","sources":["src/Modules/Mqtt/Mqtt.store.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,qBAAqB,EAAE,UAAU,EAAC,MAAM,MAAM,CAAA;AACtD,OAAO,EAAC,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAU,MAAM,EAAC,MAAM,SAAS,CAAA;AAQ3E,qBAAa,SAAS;IAClB,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,GAAG,CAAA;IACxB,WAAW,EAAE,GAAG,CAAA;IAChB,2BAA2B,EAAE,MAAM,CAAI;IAMvC,gBAAgB,WAAuB,MAAM,iBAIyB;IAMtE,gBAAgB,YAAwB,MAAM;;MAoBwB;IAYtE,kBAAkB,cAA0B,MAAM,SAiBsB;;IAkBxE,IAAI,WAAW,YAEd;IAED,gBAAgB,GAAI,QAAQ,MAAM,UAmBjC;IAED,qBAAqB;IAKrB,UAAU,GAAU,OAAO,MAAM,EAAE,SAAS;QAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,mBAEnE;IAED,oBAAoB,sBAOnB;IAED,2BAA2B,GAAI,SAAS,MAAM,UAW7C;IAED,gBAAgB,aAKf;IAED,iBAAiB,aAKhB;IAED,WAAW,GAAI,UAAU,MAAM,UAE9B;IAED,SAAS,CAAC,MAAM,EAAE,MAAM;IAIxB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO;IAIvC,IAAI,GACA,UAAU,MAAM,EAChB,MAAM,MAAM,YAAc,EAC1B,MAAM,MAAM,GAAG,IAAI,EACnB,OAAM,MAAyB,EAC/B,SAAQ,OAAe,EACvB,WAAW,MAAM,UAgGpB;IAED,oBAAoB,aA4BnB;IAED,uBAAuB,aAStB;IAED,iBAAiB,aAQhB;IAED,mBAAmB,aAMlB;IAED,mBAAmB,aAMlB;IAED,OAAO,GAAI,OAAO,MAAM,EAAE,MAAM,MAAM,GAAG,MAAM,EAAE,UAAU,qBAAqB,UAS/E;CACJ;AA2BD,wBAAgB,OAAO,cAEtB"}
1
+ {"version":3,"file":"Mqtt.store.d.ts","sourceRoot":"/","sources":["src/Modules/Mqtt/Mqtt.store.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,qBAAqB,EAAE,UAAU,EAAC,MAAM,MAAM,CAAA;AACtD,OAAO,EAAC,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAU,MAAM,EAAC,MAAM,SAAS,CAAA;AAQ3E,qBAAa,SAAS;IAClB,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,GAAG,CAAA;IACxB,WAAW,EAAE,GAAG,CAAA;IAChB,2BAA2B,EAAE,MAAM,CAAI;IACvC,mBAAmB,EAAE,MAAM,EAAE,CAAK;IAElC;;;;;;;;;;;;;;;;QAgBI;IACJ,gBAAgB,WAAuB,MAAM,iBAIyB;IAEtE;;;;;;;;;;;;;;;;;;QAkBI;IACJ,gBAAgB,YAAwB,MAAM;;MAoBwB;IAEtE;;;;;;;;;;;;;;;;;QAiBI;IACJ,kBAAkB,cAA0B,MAAM,SAiBsB;;IAmBxE,IAAI,WAAW,YAEd;IAED,gBAAgB,GAAI,QAAQ,MAAM,UAmBjC;IAED,qBAAqB;IAMrB,UAAU,GAAI,OAAO,MAAM,EAAE,SAAS;QAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,UAW7D;IAED,oBAAoB,aAOnB;IAED,2BAA2B,GAAI,SAAS,MAAM,UAW7C;IAED,gBAAgB,aAKf;IAED,iBAAiB,aAKhB;IAED,WAAW,GAAI,UAAU,MAAM,UAK9B;IAED,SAAS,CAAC,MAAM,EAAE,MAAM;IAIxB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO;IAIvC,IAAI,GACA,UAAU,MAAM,EAChB,MAAM,MAAM,YAAc,EAC1B,MAAM,MAAM,GAAG,IAAI,EACnB,OAAM,MAAyB,EAC/B,SAAQ,OAAe,EACvB,WAAW,MAAM,UAkGpB;IAED,oBAAoB,aA4BnB;IAED,uBAAuB,aAStB;IAED,iBAAiB,aAQhB;IAED,mBAAmB,aAMlB;IAED,mBAAmB,aAMlB;IAED,OAAO,GAAI,OAAO,MAAM,EAAE,MAAM,MAAM,GAAG,MAAM,EAAE,UAAU,qBAAqB,UAS/E;CACJ;AA2BD,wBAAgB,OAAO,cAEtB"}
@@ -1,39 +1,3 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- var __generator = (this && this.__generator) || function (thisArg, body) {
11
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
12
- return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13
- function verb(n) { return function (v) { return step([n, v]); }; }
14
- function step(op) {
15
- if (f) throw new TypeError("Generator is already executing.");
16
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
17
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
18
- if (y = 0, t) op = [op[0] & 2, t.value];
19
- switch (op[0]) {
20
- case 0: case 1: t = op; break;
21
- case 4: _.label++; return { value: op[1], done: false };
22
- case 5: _.label++; y = op[1]; op = [0]; continue;
23
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
24
- default:
25
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29
- if (t[2]) _.ops.pop();
30
- _.trys.pop(); continue;
31
- }
32
- op = body.call(thisArg, _);
33
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35
- }
36
- };
37
1
  import { comparer, makeAutoObservable, runInAction } from "mobx";
38
2
  import { computedFn } from "mobx-utils";
39
3
  import * as mqtt from "mqtt";
@@ -112,10 +76,29 @@ var MqttStore = /** @class */ (function () {
112
76
  writable: true,
113
77
  value: 0
114
78
  });
115
- // Use comparer.identity to check the message we get for given topic.
116
- // Will cause re-render when new message for given topic arrives.
117
- // We rely on the fact that MQTT will only re-send a message when it
118
- // changes, and on full keep alive only.
79
+ Object.defineProperty(this, "urgentTopicPrefixes", {
80
+ enumerable: true,
81
+ configurable: true,
82
+ writable: true,
83
+ value: []
84
+ });
85
+ /**
86
+ * Returns the current cached message for a given MQTT topic.
87
+ *
88
+ * React Components using this method will re-render when their specific
89
+ * topic's message changes.
90
+ *
91
+ * Using comparer.identity will trigger the re-renders any time
92
+ * a message arrives for the given topic. We rely on the fact
93
+ * that MQTT will only re-send a message when the value changes,
94
+ * or on a full keep alive.
95
+ *
96
+ * Note: Receiving the same message for a given topic will cause re-renders,
97
+ * as we do not check structural identity of the message.
98
+ *
99
+ * @param topic - The MQTT topic to retrieve the message for
100
+ * @returns The message object for the topic, or undefined if topic is not provided or not found
101
+ */
119
102
  Object.defineProperty(this, "messageFromTopic", {
120
103
  enumerable: true,
121
104
  configurable: true,
@@ -126,10 +109,25 @@ var MqttStore = /** @class */ (function () {
126
109
  return topic ? _this.messages[topic] : undefined;
127
110
  }, { name: "Mqtt.store.messageFromTopic", equals: comparer.identity })
128
111
  });
129
- // Use comparer.identity to check the messages we get for given topics.
130
- // Will cause re-render when any new message for one of the topics arrives.
131
- // We rely on the fact that MQTT will only re-send a message when it
132
- // changes, and on full keep alive only.
112
+ /**
113
+ * Returns the current cached messages for a given set of MQTT topics.
114
+ *
115
+ * This is a memoized computed function - each set of topics has its own cached value.
116
+ *
117
+ * React Components using this method will re-render when
118
+ * any of the messages for specified topics change.
119
+ *
120
+ * Using comparer.identity will trigger the re-renders any time
121
+ * a message arrives for any of the specified topics. We rely on the fact
122
+ * that MQTT will only re-send a message when the value changes,
123
+ * or on a full keep alive.
124
+
125
+ * Note: Receiving the same message for a given topic will cause re-renders,
126
+ * as we do not check structural identity of the message.
127
+ *
128
+ * @param topics - The MQTT topics to retrieve the messages for
129
+ * @returns The messages objects for the given topics, or empty dictionary if topics not found
130
+ */
133
131
  Object.defineProperty(this, "messagesByTopics", {
134
132
  enumerable: true,
135
133
  configurable: true,
@@ -156,16 +154,24 @@ var MqttStore = /** @class */ (function () {
156
154
  return result;
157
155
  }, { name: "Mqtt.store.messagesByTopics", equals: comparer.identity })
158
156
  });
159
- // Use comparer.identity to check the messages we get for given topics.
160
- // Will cause re-render when any new message for one of the topic arrives,
161
- // or when we receive a new (yet unseen) topic.
162
- // We rely on the fact that MQTT will only re-send a message when it
163
- // changes, and on full keep alive
164
- // Only access Object.keys(this.messages),
165
- // and this.messages[k], where k matches the wildcard regex,
166
- // to make sure we invalidate:
167
- // - when new topics arrive
168
- // - when message with matching topic changes
157
+ /**
158
+ * Returns the current cached messages for MQTT topics specified via regex.
159
+ *
160
+ * React Components using this method will re-render when
161
+ * values of any of the matched topics change. The components also re-render
162
+ * when new MQTT topics are received and match needs to be checked.
163
+ *
164
+ * Using comparer.identity will trigger the re-renders any time
165
+ * a message arrives for any of the matched topics. We rely on the fact
166
+ * that MQTT will only re-send a message when the value changes,
167
+ * or on a full keep alive.
168
+ *
169
+ * Note: Receiving the same message for a given topic will cause re-renders,
170
+ * as we do not check structural identity of the message.
171
+ *
172
+ * @param wildcard - The MQTT wildcard to retrieve the message for
173
+ * @returns The messages objects for the given topics, or empty dictionary if topics not found
174
+ */
169
175
  Object.defineProperty(this, "messagesByWildcard", {
170
176
  enumerable: true,
171
177
  configurable: true,
@@ -216,52 +222,49 @@ var MqttStore = /** @class */ (function () {
216
222
  enumerable: true,
217
223
  configurable: true,
218
224
  writable: true,
219
- value: function (topic, message) { return __awaiter(_this, void 0, void 0, function () {
220
- var _a;
221
- return __generator(this, function (_b) {
222
- this.messageQueue[topic] = (_a = message.value) !== null && _a !== void 0 ? _a : undefined;
223
- return [2 /*return*/];
224
- });
225
- }); }
225
+ value: function (topic, message) {
226
+ var _a, _b;
227
+ // Logger.log(`DEBUG: addMessage: topic: ${topic}, urgentPrefixes: ${JSON.stringify(this.urgentTopicPrefixes)}`)
228
+ if (_this.urgentTopicPrefixes.some(function (prefix) { return topic.startsWith(prefix); })) {
229
+ Logger.log("DEBUG: addMessage: topic: ".concat(topic));
230
+ // NOTE: If topic starts with one of the urgent prefixes, deliver it immediately
231
+ _this.messages[topic] = (_a = message.value) !== null && _a !== void 0 ? _a : undefined;
232
+ }
233
+ else {
234
+ // NOTE: Otherwise store message to the queue, and move messages from the queue
235
+ // NOTE: to the React components that are MobX observers periodically and in batches
236
+ _this.messageQueue[topic] = (_b = message.value) !== null && _b !== void 0 ? _b : undefined;
237
+ }
238
+ }
226
239
  });
227
240
  Object.defineProperty(this, "addMessagesFromQueue", {
228
241
  enumerable: true,
229
242
  configurable: true,
230
243
  writable: true,
231
- value: function () { return __awaiter(_this, void 0, void 0, function () {
232
- return __generator(this, function (_a) {
233
- if (Object.values(this.messageQueue).length > 0) {
234
- // Logger.log(`DEBUG: addMessagesFromQueue: in queue: ${JSON.stringify(Object.values(this.messageQueue).length)}`)
235
- assign(this.messages, this.messageQueue);
236
- // Logger.log(`DEBUG: addMessagesFromQueue: to process: ${JSON.stringify(Object.values(this.messages).length)}`)
237
- this.messageQueue = {};
238
- }
239
- return [2 /*return*/];
240
- });
241
- }); }
244
+ value: function () {
245
+ if (Object.values(_this.messageQueue).length > 0) {
246
+ // Logger.log(`DEBUG: addMessagesFromQueue: in queue: ${JSON.stringify(Object.values(this.messageQueue).length)}`)
247
+ assign(_this.messages, _this.messageQueue);
248
+ // Logger.log(`DEBUG: addMessagesFromQueue: to process: ${JSON.stringify(Object.values(this.messages).length)}`)
249
+ _this.messageQueue = {};
250
+ }
251
+ }
242
252
  });
243
253
  Object.defineProperty(this, "scheduleNextQueueWorkerPass", {
244
254
  enumerable: true,
245
255
  configurable: true,
246
256
  writable: true,
247
257
  value: function (timeout) {
248
- _this.queueWorker = setTimeout(function () { return __awaiter(_this, void 0, void 0, function () {
249
- var started, ended, newTimeout;
250
- return __generator(this, function (_a) {
251
- switch (_a.label) {
252
- case 0:
253
- started = performance.now();
254
- return [4 /*yield*/, this.addMessagesFromQueue()];
255
- case 1:
256
- _a.sent();
257
- ended = performance.now();
258
- this.meanQueueWorkerPassDuration = addToMean(this.meanQueueWorkerPassDuration, 10, ended - started);
259
- newTimeout = Math.max(1000, Math.min(this.meanQueueWorkerPassDuration * 50, 3000));
260
- this.scheduleNextQueueWorkerPass(newTimeout);
261
- return [2 /*return*/];
262
- }
263
- });
264
- }); }, timeout);
258
+ _this.queueWorker = setTimeout(function () {
259
+ var started = performance.now();
260
+ _this.addMessagesFromQueue();
261
+ var ended = performance.now();
262
+ _this.meanQueueWorkerPassDuration = addToMean(_this.meanQueueWorkerPassDuration, 10, ended - started);
263
+ // Schedule next update after 1 - 3 seconds
264
+ // depending on how fast we were able to process the incoming messages
265
+ var newTimeout = Math.max(1000, Math.min(_this.meanQueueWorkerPassDuration * 50, 3000));
266
+ _this.scheduleNextQueueWorkerPass(newTimeout);
267
+ }, timeout);
265
268
  }
266
269
  });
267
270
  Object.defineProperty(this, "setupQueueWorker", {
@@ -291,6 +294,9 @@ var MqttStore = /** @class */ (function () {
291
294
  writable: true,
292
295
  value: function (portalId) {
293
296
  _this.portalId = portalId;
297
+ _this.urgentTopicPrefixes = [
298
+ "N/".concat(portalId, "/switch/"),
299
+ ];
294
300
  }
295
301
  });
296
302
  Object.defineProperty(this, "boot", {
@@ -308,6 +314,7 @@ var MqttStore = /** @class */ (function () {
308
314
  _this.client = undefined;
309
315
  _this.portalId = undefined;
310
316
  _this.topicsSubscribed = new Set();
317
+ _this.urgentTopicPrefixes = [];
311
318
  }
312
319
  var url;
313
320
  if (remote) {
@@ -361,39 +368,27 @@ var MqttStore = /** @class */ (function () {
361
368
  _this.setupKeepaliveTimer();
362
369
  });
363
370
  });
364
- client.on("message", function (topic, message) { return __awaiter(_this, void 0, void 0, function () {
365
- var portalId_1, uniqueId;
366
- var _this = this;
367
- return __generator(this, function (_a) {
368
- switch (_a.label) {
369
- case 0:
370
- // Logger.log(`DEBUG: Message received: ${topic} - ${message.toString()}`)
371
- if (topic.endsWith("/system/0/Serial") && !this.portalId) {
372
- portalId_1 = getMessageJson(message).value;
373
- if (this.portalId !== portalId_1 && portalId_1 !== undefined) {
374
- this.setPortalId(portalId_1);
375
- }
376
- runInAction(function () { return _this.subscribeToAllTopics(); });
377
- }
378
- if (!topic.endsWith("full_publish_completed")) return [3 /*break*/, 2];
379
- uniqueId = getMessageJson(message)["full-publish-completed-echo"] || "";
380
- Logger.log("Received full_publish_completed for ".concat(this.portalId, " with full-publish-completed-echo: '").concat(uniqueId, "'"));
381
- if (!(uniqueId === this.uniqueId)) return [3 /*break*/, 2];
382
- return [4 /*yield*/, this.addMessagesFromQueue()];
383
- case 1:
384
- _a.sent();
385
- this.setupQueueWorker();
386
- _a.label = 2;
387
- case 2:
388
- if (!(message.toString() !== "")) return [3 /*break*/, 4];
389
- return [4 /*yield*/, this.addMessage(topic, getMessageJson(message))];
390
- case 3:
391
- _a.sent();
392
- _a.label = 4;
393
- case 4: return [2 /*return*/];
371
+ client.on("message", function (topic, message) {
372
+ // Logger.log(`DEBUG: Message received: ${topic} - ${message.toString()}`)
373
+ if (topic.endsWith("/system/0/Serial") && !_this.portalId) {
374
+ var portalId_1 = getMessageJson(message).value;
375
+ if (_this.portalId !== portalId_1 && portalId_1 !== undefined) {
376
+ _this.setPortalId(portalId_1);
394
377
  }
395
- });
396
- }); });
378
+ runInAction(function () { return _this.subscribeToAllTopics(); });
379
+ }
380
+ if (topic.endsWith("full_publish_completed")) {
381
+ var uniqueId = getMessageJson(message)["full-publish-completed-echo"] || "";
382
+ Logger.log("Received full_publish_completed for ".concat(_this.portalId, " with full-publish-completed-echo: '").concat(uniqueId, "'"));
383
+ if (uniqueId === _this.uniqueId) {
384
+ _this.addMessagesFromQueue();
385
+ _this.setupQueueWorker();
386
+ }
387
+ }
388
+ if (message.toString() !== "") {
389
+ _this.addMessage(topic, getMessageJson(message));
390
+ }
391
+ });
397
392
  Logger.log("MQTT booted");
398
393
  }
399
394
  });
@@ -495,6 +490,7 @@ var MqttStore = /** @class */ (function () {
495
490
  });
496
491
  makeAutoObservable(this, {
497
492
  messageQueue: false,
493
+ urgentTopicPrefixes: false,
498
494
  setupKeepaliveTimer: false,
499
495
  clearKeepaliveTimer: false,
500
496
  sendFullKeepalive: false,
@@ -521,6 +517,7 @@ var MqttStore = /** @class */ (function () {
521
517
  value: function () {
522
518
  this.topicsSubscribed.clear();
523
519
  this.portalId = undefined;
520
+ this.urgentTopicPrefixes = [];
524
521
  }
525
522
  });
526
523
  Object.defineProperty(MqttStore.prototype, "setStatus", {
@@ -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: any\n queueWorker: any\n meanQueueWorkerPassDuration: number = 0\n\n // Use comparer.identity to check the message we get for given topic.\n // Will cause re-render when new message for given topic arrives.\n // We rely on the fact that MQTT will only re-send a message when it\n // changes, and on full keep alive only.\n messageFromTopic = computedFn((topic?: string) => {\n // Logger.log(`DEBUG: messageFromTopic: ${JSON.stringify(topic)}`)\n // trace()\n return topic ? this.messages[topic] : undefined\n }, { name: \"Mqtt.store.messageFromTopic\", equals: comparer.identity })\n\n // Use comparer.identity to check the messages we get for given topics.\n // Will cause re-render when any new message for one of the topics arrives.\n // We rely on the fact that MQTT will only re-send a message when it\n // changes, and on full keep alive only.\n messagesByTopics = computedFn((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 }, { name: \"Mqtt.store.messagesByTopics\", equals: comparer.identity })\n\n // Use comparer.identity to check the messages we get for given topics.\n // Will cause re-render when any new message for one of the topic arrives,\n // or when we receive a new (yet unseen) topic.\n // We rely on the fact that MQTT will only re-send a message when it\n // changes, and on full keep alive\n // Only access Object.keys(this.messages),\n // and this.messages[k], where k matches the wildcard regex,\n // to make sure we invalidate:\n // - when new topics arrive\n // - when message with matching topic changes\n messagesByWildcard = computedFn((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(([_, message]) =>\n message !== undefined && message !== null\n && (!Array.isArray(message) || (message.length !== 0 && !message.every((v) => v === undefined || v === null)))\n ),\n )\n }, { name: \"Mqtt.store.messagesByWildcard\", equals: comparer.identity })\n\n constructor() {\n makeAutoObservable(this, {\n messageQueue: 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 (granted !== undefined && granted[0])\n ? Logger.log(`Subscribed to ${granted[0].topic} with Qos ${granted[0].qos}`)\n : Logger.log(`Subscribed to ${topic} with Qos unknown`);\n })\n\n this.topicsSubscribed.add(topic)\n }\n }\n\n clearSubscribedTopics() {\n this.topicsSubscribed.clear()\n this.portalId = undefined\n }\n\n addMessage = async (topic: string, message: { value: string | null }) => {\n this.messageQueue[topic] = message.value ?? undefined\n }\n\n addMessagesFromQueue = async () => {\n if (Object.values(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(async () => {\n const started = performance.now()\n await 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 clearInterval(this.queueWorker)\n }\n this.queueWorker = undefined\n }\n\n setPortalId = (portalId: string) => {\n this.portalId = portalId\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 = new Set<string>()\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\", async (topic, message) => {\n // Logger.log(`DEBUG: Message received: ${topic} - ${message.toString()}`)\n\n if (topic.endsWith(\"/system/0/Serial\") && !this.portalId) {\n const portalId = getMessageJson(message).value\n\n if (this.portalId !== portalId && portalId !== undefined) {\n this.setPortalId(portalId)\n }\n\n runInAction(() => this.subscribeToAllTopics())\n }\n if (topic.endsWith(\"full_publish_completed\")) {\n const uniqueId = getMessageJson(message)[\"full-publish-completed-echo\"] || \"\"\n Logger.log(`Received full_publish_completed for ${this.portalId} with full-publish-completed-echo: '${uniqueId}'`)\n if (uniqueId === this.uniqueId) {\n await this.addMessagesFromQueue()\n this.setupQueueWorker()\n }\n }\n\n if (message.toString() !== \"\") {\n await this.addMessage(topic, getMessageJson(message))\n }\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\n const options = JSON.stringify({\"keepalive-options\": [\"suppress-republish\"]})\n const topic = `R/${this.portalId}/keepalive`\n\n Logger.log(`Sending keepalive for ${this.portalId} with ${options}`)\n this.client?.publish(topic, options)\n }\n }\n\n sendFullKeepalive = () => {\n if (this.portalId) {\n\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 && 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, options?: IClientPublishOptions) => {\n if (this.status !== STATUS.CONNECTED || !this.client) {\n Logger.log(\"Could not publish value, not connected to MQTT broker\")\n }\n const message = JSON.stringify({value: data})\n\n Logger.log(`Publishing to ${topic}: ${message}`)\n\n this.client?.publish(topic, message, options ?? {})\n }\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}"]}
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: any\n queueWorker: any\n meanQueueWorkerPassDuration: number = 0\n urgentTopicPrefixes: string[] = []\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((topic?: string) => {\n // Logger.log(`DEBUG: messageFromTopic: ${JSON.stringify(topic)}`)\n // trace()\n return topic ? this.messages[topic] : undefined\n }, { name: \"Mqtt.store.messageFromTopic\", equals: comparer.identity })\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((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 }, { name: \"Mqtt.store.messagesByTopics\", equals: comparer.identity })\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((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(([_, message]) =>\n message !== undefined && message !== null\n && (!Array.isArray(message) || (message.length !== 0 && !message.every((v) => v === undefined || v === null)))\n ),\n )\n }, { name: \"Mqtt.store.messagesByWildcard\", equals: comparer.identity })\n\n constructor() {\n makeAutoObservable(this, {\n messageQueue: false,\n urgentTopicPrefixes: 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 (granted !== undefined && granted[0])\n ? Logger.log(`Subscribed to ${granted[0].topic} with Qos ${granted[0].qos}`)\n : Logger.log(`Subscribed to ${topic} with Qos unknown`);\n })\n\n this.topicsSubscribed.add(topic)\n }\n }\n\n clearSubscribedTopics() {\n this.topicsSubscribed.clear()\n this.portalId = undefined\n this.urgentTopicPrefixes = []\n }\n\n addMessage = (topic: string, message: { value: string | null }) => {\n // Logger.log(`DEBUG: addMessage: topic: ${topic}, urgentPrefixes: ${JSON.stringify(this.urgentTopicPrefixes)}`)\n if (this.urgentTopicPrefixes.some((prefix) => topic.startsWith(prefix))) {\n Logger.log(`DEBUG: addMessage: topic: ${topic}`)\n // NOTE: If topic starts with one of the urgent prefixes, deliver it immediately\n this.messages[topic] = message.value ?? undefined\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 ?? undefined\n }\n }\n\n addMessagesFromQueue = () => {\n if (Object.values(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 clearInterval(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 }\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 = new Set<string>()\n this.urgentTopicPrefixes = []\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\",\n (topic, message) => {\n // Logger.log(`DEBUG: Message received: ${topic} - ${message.toString()}`)\n\n if (topic.endsWith(\"/system/0/Serial\") && !this.portalId) {\n const portalId = getMessageJson(message).value\n\n if (this.portalId !== portalId && portalId !== undefined) {\n this.setPortalId(portalId)\n }\n\n runInAction(() => this.subscribeToAllTopics())\n }\n if (topic.endsWith(\"full_publish_completed\")) {\n const uniqueId = getMessageJson(message)[\"full-publish-completed-echo\"] || \"\"\n Logger.log(`Received full_publish_completed for ${this.portalId} with full-publish-completed-echo: '${uniqueId}'`)\n if (uniqueId === this.uniqueId) {\n this.addMessagesFromQueue()\n this.setupQueueWorker()\n }\n }\n\n if (message.toString() !== \"\") {\n this.addMessage(topic, getMessageJson(message))\n }\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\n const options = JSON.stringify({\"keepalive-options\": [\"suppress-republish\"]})\n const topic = `R/${this.portalId}/keepalive`\n\n Logger.log(`Sending keepalive for ${this.portalId} with ${options}`)\n this.client?.publish(topic, options)\n }\n }\n\n sendFullKeepalive = () => {\n if (this.portalId) {\n\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 && 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, options?: IClientPublishOptions) => {\n if (this.status !== STATUS.CONNECTED || !this.client) {\n Logger.log(\"Could not publish value, not connected to MQTT broker\")\n }\n const message = JSON.stringify({value: data})\n\n Logger.log(`Publishing to ${topic}: ${message}`)\n\n this.client?.publish(topic, message, options ?? {})\n }\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}"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@victronenergy/mfd-modules",
3
- "version": "9.4.0",
3
+ "version": "9.5.0",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",