iobroker.proscenic 0.1.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.
- package/LICENSE +21 -0
- package/README.md +93 -0
- package/admin/i18n/de.json +9 -0
- package/admin/i18n/en.json +9 -0
- package/admin/i18n/es.json +9 -0
- package/admin/i18n/fr.json +9 -0
- package/admin/i18n/it.json +9 -0
- package/admin/i18n/nl.json +9 -0
- package/admin/i18n/pl.json +9 -0
- package/admin/i18n/pt.json +9 -0
- package/admin/i18n/ru.json +9 -0
- package/admin/i18n/uk.json +9 -0
- package/admin/i18n/zh-cn.json +9 -0
- package/admin/jsonConfig.json +85 -0
- package/admin/proscenic-m7-pro.png +0 -0
- package/admin/proscenic.png +0 -0
- package/build/domain/commands.js +129 -0
- package/build/domain/commands.js.map +7 -0
- package/build/domain/consumables.js +63 -0
- package/build/domain/consumables.js.map +7 -0
- package/build/domain/live-map.js +829 -0
- package/build/domain/live-map.js.map +7 -0
- package/build/domain/maintenance-message.js +128 -0
- package/build/domain/maintenance-message.js.map +7 -0
- package/build/domain/map.js +58 -0
- package/build/domain/map.js.map +7 -0
- package/build/domain/reconnect-policy.js +45 -0
- package/build/domain/reconnect-policy.js.map +7 -0
- package/build/domain/status.js +108 -0
- package/build/domain/status.js.map +7 -0
- package/build/main.js +529 -0
- package/build/main.js.map +7 -0
- package/build/objects/object-definitions.js +214 -0
- package/build/objects/object-definitions.js.map +7 -0
- package/build/objects/projector.js +231 -0
- package/build/objects/projector.js.map +7 -0
- package/build/protocol/crypto.js +81 -0
- package/build/protocol/crypto.js.map +7 -0
- package/build/protocol/gateway-client.js +136 -0
- package/build/protocol/gateway-client.js.map +7 -0
- package/build/protocol/rest-client.js +184 -0
- package/build/protocol/rest-client.js.map +7 -0
- package/build/protocol/types.js +17 -0
- package/build/protocol/types.js.map +7 -0
- package/io-package.json +125 -0
- package/package.json +80 -0
package/build/main.js
ADDED
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (let key of __getOwnPropNames(from))
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
+
}
|
|
14
|
+
return to;
|
|
15
|
+
};
|
|
16
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
+
mod
|
|
23
|
+
));
|
|
24
|
+
var utils = __toESM(require("@iobroker/adapter-core"));
|
|
25
|
+
var import_consumables = require("./domain/consumables");
|
|
26
|
+
var import_commands = require("./domain/commands");
|
|
27
|
+
var import_live_map = require("./domain/live-map");
|
|
28
|
+
var import_maintenance_message = require("./domain/maintenance-message");
|
|
29
|
+
var import_map = require("./domain/map");
|
|
30
|
+
var import_reconnect_policy = require("./domain/reconnect-policy");
|
|
31
|
+
var import_status = require("./domain/status");
|
|
32
|
+
var import_object_definitions = require("./objects/object-definitions");
|
|
33
|
+
var import_projector = require("./objects/projector");
|
|
34
|
+
var import_gateway_client = require("./protocol/gateway-client");
|
|
35
|
+
var import_rest_client = require("./protocol/rest-client");
|
|
36
|
+
const DEFAULT_TIMEOUT_MS = 1e4;
|
|
37
|
+
const CONSUMABLE_GATEWAY_TIMEOUT_MS = 35e3;
|
|
38
|
+
const MAX_GATEWAY_BUFFER_BYTES = 512 * 1024;
|
|
39
|
+
const MAX_LIVE_MAP_POSES = 1e3;
|
|
40
|
+
class Proscenic extends utils.Adapter {
|
|
41
|
+
gatewayClient;
|
|
42
|
+
reconnectTimer;
|
|
43
|
+
reconnectAttempt = 0;
|
|
44
|
+
reconnectInProgress = false;
|
|
45
|
+
commandInProgress = false;
|
|
46
|
+
commandEnabled = false;
|
|
47
|
+
commandClient;
|
|
48
|
+
commandToken;
|
|
49
|
+
commandSerial;
|
|
50
|
+
shuttingDown = false;
|
|
51
|
+
recentRobotPoses = [];
|
|
52
|
+
latestMapData;
|
|
53
|
+
latestMapPathId;
|
|
54
|
+
latestMapId;
|
|
55
|
+
latestMapCoordinateMetadata;
|
|
56
|
+
liveMapPathResetCount = 0;
|
|
57
|
+
lastPoseUpdated;
|
|
58
|
+
maintenanceEventCount = 0;
|
|
59
|
+
auxiliaryReadInProgress = false;
|
|
60
|
+
pendingConsumableRead;
|
|
61
|
+
constructor(options = {}) {
|
|
62
|
+
super({
|
|
63
|
+
...options,
|
|
64
|
+
name: "proscenic"
|
|
65
|
+
});
|
|
66
|
+
this.on("ready", this.onReady.bind(this));
|
|
67
|
+
this.on("stateChange", this.onStateChange.bind(this));
|
|
68
|
+
this.on("unload", this.onUnload.bind(this));
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Is called when databases are connected and adapter received configuration.
|
|
72
|
+
*/
|
|
73
|
+
async onReady() {
|
|
74
|
+
await (0, import_object_definitions.extendAdapterObjects)(this);
|
|
75
|
+
await this.setState("info.connection", false, true);
|
|
76
|
+
await (0, import_projector.setConnectionState)(this, "cloud", false);
|
|
77
|
+
await (0, import_projector.setConnectionState)(this, "gateway", false);
|
|
78
|
+
await (0, import_projector.setInitialCapabilityStates)(this);
|
|
79
|
+
this.subscribeStates("commands.*");
|
|
80
|
+
if (!this.config.username || !this.config.password) {
|
|
81
|
+
this.log.warn("Proscenic cloud credentials are not configured yet.");
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
await this.connectReadOnlyGateway();
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Is called when adapter shuts down - callback has to be called under any circumstances!
|
|
88
|
+
*
|
|
89
|
+
* @param callback - Callback function
|
|
90
|
+
*/
|
|
91
|
+
onUnload(callback) {
|
|
92
|
+
var _a;
|
|
93
|
+
try {
|
|
94
|
+
this.shuttingDown = true;
|
|
95
|
+
this.clearReconnectTimer();
|
|
96
|
+
this.rejectPendingConsumableRead(new Error("Adapter unload interrupted consumable read"));
|
|
97
|
+
(_a = this.gatewayClient) == null ? void 0 : _a.destroy();
|
|
98
|
+
this.gatewayClient = void 0;
|
|
99
|
+
this.clearCommandSession();
|
|
100
|
+
callback();
|
|
101
|
+
} catch (error) {
|
|
102
|
+
this.log.error(`Error during unloading: ${error.message}`);
|
|
103
|
+
callback();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async connectReadOnlyGateway() {
|
|
107
|
+
if (this.shuttingDown || this.reconnectInProgress) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
this.clearReconnectTimer();
|
|
111
|
+
this.reconnectInProgress = true;
|
|
112
|
+
try {
|
|
113
|
+
await this.startReadOnlyGateway();
|
|
114
|
+
} catch (error) {
|
|
115
|
+
this.clearCommandSession();
|
|
116
|
+
await (0, import_projector.setLastError)(this, error);
|
|
117
|
+
await (0, import_projector.setConnectionState)(this, "cloud", false);
|
|
118
|
+
await (0, import_projector.setConnectionState)(this, "gateway", false);
|
|
119
|
+
this.log.warn(`Could not start Proscenic read-only connection: ${(0, import_projector.redactedErrorMessage)(error)}`);
|
|
120
|
+
this.scheduleReconnect("connection failure");
|
|
121
|
+
} finally {
|
|
122
|
+
this.reconnectInProgress = false;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
async startReadOnlyGateway() {
|
|
126
|
+
var _a;
|
|
127
|
+
const client = new import_rest_client.ProscenicRestClient({
|
|
128
|
+
username: this.config.username,
|
|
129
|
+
password: this.config.password,
|
|
130
|
+
region: this.config.region,
|
|
131
|
+
timeoutMs: DEFAULT_TIMEOUT_MS
|
|
132
|
+
});
|
|
133
|
+
this.log.info("Connecting to the Proscenic legacy cloud.");
|
|
134
|
+
const token = await client.login();
|
|
135
|
+
this.commandEnabled = false;
|
|
136
|
+
this.commandClient = client;
|
|
137
|
+
this.commandToken = token;
|
|
138
|
+
await (0, import_projector.setConnectionState)(this, "cloud", true);
|
|
139
|
+
const devices = await client.listDevices();
|
|
140
|
+
const device = selectDevice(devices, this.config.deviceCode);
|
|
141
|
+
await (0, import_projector.projectDevice)(this, device);
|
|
142
|
+
if (!device.sn) {
|
|
143
|
+
throw new Error("Selected device cannot be used because its protocol serial is missing");
|
|
144
|
+
}
|
|
145
|
+
this.commandSerial = device.sn;
|
|
146
|
+
this.commandEnabled = isM7Pro(device);
|
|
147
|
+
await this.setStateAsync("capabilities.commands", { val: this.commandEnabled, ack: true });
|
|
148
|
+
const gateway = await client.getGateway(token, device.sn);
|
|
149
|
+
const endpoint = selectGatewayEndpoint(gateway);
|
|
150
|
+
(_a = this.gatewayClient) == null ? void 0 : _a.destroy();
|
|
151
|
+
this.gatewayClient = new import_gateway_client.ProscenicGatewayClient({
|
|
152
|
+
endpoint,
|
|
153
|
+
token,
|
|
154
|
+
serial: device.sn,
|
|
155
|
+
timeoutMs: DEFAULT_TIMEOUT_MS,
|
|
156
|
+
maxBufferBytes: MAX_GATEWAY_BUFFER_BYTES,
|
|
157
|
+
onConnect: () => {
|
|
158
|
+
this.reconnectAttempt = 0;
|
|
159
|
+
void (0, import_projector.setConnectionState)(this, "gateway", true);
|
|
160
|
+
this.log.info("Connected to the Proscenic gateway.");
|
|
161
|
+
void this.refreshVerifiedReadPaths();
|
|
162
|
+
},
|
|
163
|
+
onEvent: (event) => {
|
|
164
|
+
void this.handleGatewayEvent(event.infoType, event.data);
|
|
165
|
+
},
|
|
166
|
+
onClose: () => {
|
|
167
|
+
void (0, import_projector.setConnectionState)(this, "gateway", false);
|
|
168
|
+
this.rejectPendingConsumableRead(new Error("Gateway closed before consumable data was received"));
|
|
169
|
+
if (!this.shuttingDown) {
|
|
170
|
+
this.log.warn("Proscenic gateway connection closed.");
|
|
171
|
+
this.scheduleReconnect("gateway close");
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
onError: (error) => {
|
|
175
|
+
void (0, import_projector.setLastError)(this, error);
|
|
176
|
+
if (!this.shuttingDown) {
|
|
177
|
+
this.log.warn(`Proscenic gateway error: ${(0, import_projector.redactedErrorMessage)(error)}`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
this.gatewayClient.connect();
|
|
182
|
+
}
|
|
183
|
+
scheduleReconnect(reason) {
|
|
184
|
+
if (this.shuttingDown || this.reconnectTimer) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
this.reconnectAttempt += 1;
|
|
188
|
+
const delayMs = (0, import_reconnect_policy.reconnectDelayMs)(this.reconnectAttempt);
|
|
189
|
+
this.log.info(
|
|
190
|
+
`Scheduling Proscenic gateway reconnect in ${Math.round(delayMs / 1e3)} seconds after ${reason}.`
|
|
191
|
+
);
|
|
192
|
+
this.reconnectTimer = this.setTimeout(() => {
|
|
193
|
+
this.reconnectTimer = void 0;
|
|
194
|
+
void this.connectReadOnlyGateway();
|
|
195
|
+
}, delayMs);
|
|
196
|
+
}
|
|
197
|
+
clearReconnectTimer() {
|
|
198
|
+
if (this.reconnectTimer) {
|
|
199
|
+
this.clearTimeout(this.reconnectTimer);
|
|
200
|
+
this.reconnectTimer = void 0;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
async handleGatewayEvent(infoType, data) {
|
|
204
|
+
if (infoType === 21015) {
|
|
205
|
+
const consumables = (0, import_consumables.normalizeConsumables21015)(data);
|
|
206
|
+
if (consumables) {
|
|
207
|
+
await (0, import_projector.projectConsumables)(this, consumables);
|
|
208
|
+
this.resolvePendingConsumableRead(consumables);
|
|
209
|
+
}
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
if (infoType === 20001) {
|
|
213
|
+
const pose = (0, import_live_map.extractRobotPose20001)(data);
|
|
214
|
+
if (pose) {
|
|
215
|
+
this.lastPoseUpdated = (/* @__PURE__ */ new Date()).toISOString();
|
|
216
|
+
this.recentRobotPoses.push(pose);
|
|
217
|
+
if (this.recentRobotPoses.length > MAX_LIVE_MAP_POSES) {
|
|
218
|
+
this.recentRobotPoses = this.recentRobotPoses.slice(-MAX_LIVE_MAP_POSES);
|
|
219
|
+
}
|
|
220
|
+
await this.projectLatestLiveMapImage("pose");
|
|
221
|
+
}
|
|
222
|
+
const status = (0, import_status.normalizeStatus20001)(data);
|
|
223
|
+
if (status) {
|
|
224
|
+
await (0, import_projector.projectStatus)(this, status);
|
|
225
|
+
}
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
if (infoType === 20002) {
|
|
229
|
+
const map = (0, import_map.normalizeMap20002)(data);
|
|
230
|
+
const coordinateMetadata = (0, import_live_map.extractLiveMapCoordinateMetadata20002)(data);
|
|
231
|
+
if (map) {
|
|
232
|
+
if (map.mapId !== void 0 && this.latestMapId !== void 0 && map.mapId !== this.latestMapId) {
|
|
233
|
+
this.latestMapCoordinateMetadata = void 0;
|
|
234
|
+
}
|
|
235
|
+
if (map.pathId !== void 0 && this.latestMapPathId !== void 0 && map.pathId !== this.latestMapPathId) {
|
|
236
|
+
this.recentRobotPoses = [];
|
|
237
|
+
this.liveMapPathResetCount += 1;
|
|
238
|
+
this.lastPoseUpdated = void 0;
|
|
239
|
+
}
|
|
240
|
+
if (map.pathId !== void 0) {
|
|
241
|
+
this.latestMapPathId = map.pathId;
|
|
242
|
+
}
|
|
243
|
+
if (map.mapId !== void 0) {
|
|
244
|
+
this.latestMapId = map.mapId;
|
|
245
|
+
}
|
|
246
|
+
if (coordinateMetadata) {
|
|
247
|
+
this.latestMapCoordinateMetadata = (0, import_live_map.mergeLiveMapCoordinateMetadataCache)(
|
|
248
|
+
this.latestMapCoordinateMetadata,
|
|
249
|
+
coordinateMetadata
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
await (0, import_projector.projectMapMetadata)(this, map);
|
|
253
|
+
}
|
|
254
|
+
this.latestMapData = data;
|
|
255
|
+
await this.projectLatestLiveMapImage("map");
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
if (infoType === 20003) {
|
|
259
|
+
const message = (0, import_maintenance_message.normalizeMaintenanceMessage20003)(data);
|
|
260
|
+
if (message) {
|
|
261
|
+
this.maintenanceEventCount += 1;
|
|
262
|
+
await (0, import_projector.projectMaintenanceMessage)(this, message, this.maintenanceEventCount);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
async refreshVerifiedReadPaths() {
|
|
267
|
+
if (this.auxiliaryReadInProgress || this.shuttingDown) {
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
if (!this.commandEnabled) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
if (!this.commandClient || !this.commandToken || !this.commandSerial) {
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
this.auxiliaryReadInProgress = true;
|
|
277
|
+
try {
|
|
278
|
+
await Promise.all([this.refreshMaintenanceHistory(), this.refreshConsumables()]);
|
|
279
|
+
} finally {
|
|
280
|
+
this.auxiliaryReadInProgress = false;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
async refreshMaintenanceHistory() {
|
|
284
|
+
if (!this.commandClient || !this.commandToken || !this.commandSerial) {
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
try {
|
|
288
|
+
const data = await this.commandClient.getMaintenanceHistory(this.commandToken, this.commandSerial);
|
|
289
|
+
const history = (0, import_maintenance_message.normalizeMaintenanceHistory20003)(data);
|
|
290
|
+
if (!history) {
|
|
291
|
+
throw new Error("Maintenance history response did not contain usable events");
|
|
292
|
+
}
|
|
293
|
+
await (0, import_projector.projectMaintenanceHistory)(this, history);
|
|
294
|
+
} catch (error) {
|
|
295
|
+
await (0, import_projector.setMaintenanceHistoryReadFailure)(this, error);
|
|
296
|
+
this.log.debug(`Could not refresh Proscenic maintenance history: ${(0, import_projector.redactedErrorMessage)(error)}`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
async refreshConsumables() {
|
|
300
|
+
if (!this.commandClient || !this.commandToken || !this.commandSerial) {
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
let consumableRead;
|
|
304
|
+
try {
|
|
305
|
+
consumableRead = this.awaitNextConsumables();
|
|
306
|
+
await this.commandClient.requestConsumables(this.commandToken, this.commandSerial);
|
|
307
|
+
await consumableRead;
|
|
308
|
+
} catch (error) {
|
|
309
|
+
void (consumableRead == null ? void 0 : consumableRead.catch(() => void 0));
|
|
310
|
+
this.rejectPendingConsumableRead(error instanceof Error ? error : new Error(String(error)));
|
|
311
|
+
await (0, import_projector.setConsumablesReadFailure)(this, error);
|
|
312
|
+
this.log.debug(`Could not refresh Proscenic consumables: ${(0, import_projector.redactedErrorMessage)(error)}`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
awaitNextConsumables() {
|
|
316
|
+
this.rejectPendingConsumableRead(new Error("Superseded by a newer consumable read"));
|
|
317
|
+
return new Promise((resolve, reject) => {
|
|
318
|
+
const timer = this.setTimeout(() => {
|
|
319
|
+
this.pendingConsumableRead = void 0;
|
|
320
|
+
reject(new Error(`No consumable gateway event received within ${CONSUMABLE_GATEWAY_TIMEOUT_MS} ms`));
|
|
321
|
+
}, CONSUMABLE_GATEWAY_TIMEOUT_MS);
|
|
322
|
+
if (timer === void 0) {
|
|
323
|
+
reject(new Error("Could not schedule consumable gateway timeout"));
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
this.pendingConsumableRead = { timer, resolve, reject };
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
resolvePendingConsumableRead(consumables) {
|
|
330
|
+
if (!this.pendingConsumableRead) {
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
this.clearTimeout(this.pendingConsumableRead.timer);
|
|
334
|
+
this.pendingConsumableRead.resolve(consumables);
|
|
335
|
+
this.pendingConsumableRead = void 0;
|
|
336
|
+
}
|
|
337
|
+
rejectPendingConsumableRead(error) {
|
|
338
|
+
if (!this.pendingConsumableRead) {
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
this.clearTimeout(this.pendingConsumableRead.timer);
|
|
342
|
+
this.pendingConsumableRead.reject(error);
|
|
343
|
+
this.pendingConsumableRead = void 0;
|
|
344
|
+
}
|
|
345
|
+
async projectLatestLiveMapImage(renderReason) {
|
|
346
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
347
|
+
if (!this.latestMapData) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
try {
|
|
351
|
+
const renderData = (0, import_live_map.mergeLiveMapCoordinateMetadata20002)(
|
|
352
|
+
this.latestMapData,
|
|
353
|
+
this.latestMapCoordinateMetadata
|
|
354
|
+
);
|
|
355
|
+
const image = (0, import_live_map.renderLiveMapImage20002)(renderData, this.recentRobotPoses);
|
|
356
|
+
if (image) {
|
|
357
|
+
await (0, import_projector.projectLiveMapImage)(this, image, {
|
|
358
|
+
renderReason,
|
|
359
|
+
lastPathId: this.latestMapPathId,
|
|
360
|
+
pathResetCount: this.liveMapPathResetCount,
|
|
361
|
+
lastPoseUpdated: this.lastPoseUpdated,
|
|
362
|
+
currentAreaCount: (0, import_live_map.countLiveMapAreas20002)(this.latestMapData),
|
|
363
|
+
cachedAreaCount: (_c = (_b = (_a = this.latestMapCoordinateMetadata) == null ? void 0 : _a.area) == null ? void 0 : _b.length) != null ? _c : 0,
|
|
364
|
+
hasCachedStaticOverlays: ((_f = (_e = (_d = this.latestMapCoordinateMetadata) == null ? void 0 : _d.area) == null ? void 0 : _e.length) != null ? _f : 0) > 0 || ((_g = this.latestMapCoordinateMetadata) == null ? void 0 : _g.chargeHandlePos) !== void 0
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
} catch (error) {
|
|
368
|
+
this.log.debug(`Could not render experimental live map image: ${(0, import_projector.redactedErrorMessage)(error)}`);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
// If you need to react to object changes, uncomment the following block and the corresponding line in the constructor.
|
|
372
|
+
// You also need to subscribe to the objects with `this.subscribeObjects`, similar to `this.subscribeStates`.
|
|
373
|
+
// /**
|
|
374
|
+
// * Is called if a subscribed object changes
|
|
375
|
+
// */
|
|
376
|
+
// private onObjectChange(id: string, obj: ioBroker.Object | null | undefined): void {
|
|
377
|
+
// if (obj) {
|
|
378
|
+
// // The object was changed
|
|
379
|
+
// this.log.info(`object ${id} changed: ${JSON.stringify(obj)}`);
|
|
380
|
+
// } else {
|
|
381
|
+
// // The object was deleted
|
|
382
|
+
// this.log.info(`object ${id} deleted`);
|
|
383
|
+
// }
|
|
384
|
+
// }
|
|
385
|
+
/**
|
|
386
|
+
* Is called if a subscribed state changes
|
|
387
|
+
*
|
|
388
|
+
* @param id - State ID
|
|
389
|
+
* @param state - State object
|
|
390
|
+
*/
|
|
391
|
+
onStateChange(id, state) {
|
|
392
|
+
if (!state || state.ack !== false) {
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
const relativeId = this.relativeStateId(id);
|
|
396
|
+
const command = (0, import_commands.commandForStateId)(relativeId);
|
|
397
|
+
if (!command) {
|
|
398
|
+
this.log.debug(`Ignoring unsupported state command for ${relativeId}.`);
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
const trigger = (0, import_commands.normalizeCommandButtonValue)(state.val);
|
|
402
|
+
if (trigger === false) {
|
|
403
|
+
void this.setStateAsync(relativeId, { val: false, ack: true });
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
if (trigger === void 0) {
|
|
407
|
+
this.log.debug(`Ignoring unsupported command button value for ${relativeId}.`);
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
void this.executeCommand(relativeId, command);
|
|
411
|
+
}
|
|
412
|
+
relativeStateId(id) {
|
|
413
|
+
const prefix = `${this.namespace}.`;
|
|
414
|
+
return id.startsWith(prefix) ? id.slice(prefix.length) : id;
|
|
415
|
+
}
|
|
416
|
+
async executeCommand(stateId, command) {
|
|
417
|
+
if (this.commandInProgress) {
|
|
418
|
+
await this.setCommandFailure(
|
|
419
|
+
stateId,
|
|
420
|
+
command,
|
|
421
|
+
new Error("Another Proscenic command is already in progress")
|
|
422
|
+
);
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
this.commandInProgress = true;
|
|
426
|
+
await this.setStateAsync("commands.lastCommand", { val: command, ack: true });
|
|
427
|
+
await this.setStateAsync("commands.lastResult", { val: "running", ack: true });
|
|
428
|
+
await this.setStateAsync("commands.lastError", { val: "", ack: true });
|
|
429
|
+
await this.setStateAsync("commands.lastExecution", { val: (/* @__PURE__ */ new Date()).toISOString(), ack: true });
|
|
430
|
+
try {
|
|
431
|
+
if (!this.commandClient || !this.commandToken || !this.commandSerial || !this.config.username) {
|
|
432
|
+
throw new Error("Proscenic command session is not ready");
|
|
433
|
+
}
|
|
434
|
+
if (!this.commandEnabled) {
|
|
435
|
+
throw new Error("Proscenic commands are not enabled for the selected device");
|
|
436
|
+
}
|
|
437
|
+
const request = (0, import_commands.buildCommandRequest)(command, this.commandSerial, this.config.username);
|
|
438
|
+
const result = await this.commandClient.sendCommand(this.commandToken, request);
|
|
439
|
+
await this.setStateAsync("commands.lastResult", {
|
|
440
|
+
val: result.code === void 0 || result.code === 0 ? "sent" : `api-code-${result.code}`,
|
|
441
|
+
ack: true
|
|
442
|
+
});
|
|
443
|
+
await this.setStateAsync(stateId, { val: false, ack: true });
|
|
444
|
+
} catch (error) {
|
|
445
|
+
await this.setCommandFailure(stateId, command, error);
|
|
446
|
+
} finally {
|
|
447
|
+
this.commandInProgress = false;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
async setCommandFailure(stateId, command, error) {
|
|
451
|
+
const message = (0, import_projector.redactedErrorMessage)(error);
|
|
452
|
+
await this.setStateAsync("commands.lastCommand", { val: command, ack: true });
|
|
453
|
+
await this.setStateAsync("commands.lastResult", { val: "failed", ack: true });
|
|
454
|
+
await this.setStateAsync("commands.lastError", { val: message, ack: true });
|
|
455
|
+
await this.setStateAsync("commands.lastExecution", { val: (/* @__PURE__ */ new Date()).toISOString(), ack: true });
|
|
456
|
+
await this.setStateAsync(stateId, { val: false, ack: true });
|
|
457
|
+
this.log.warn(`Proscenic command ${command} failed: ${message}`);
|
|
458
|
+
}
|
|
459
|
+
clearCommandSession() {
|
|
460
|
+
this.commandEnabled = false;
|
|
461
|
+
this.commandClient = void 0;
|
|
462
|
+
this.commandToken = void 0;
|
|
463
|
+
this.commandSerial = void 0;
|
|
464
|
+
}
|
|
465
|
+
// If you need to accept messages in your adapter, uncomment the following block and the corresponding line in the constructor.
|
|
466
|
+
// /**
|
|
467
|
+
// * Some message was sent to this instance over message box. Used by email, pushover, text2speech, ...
|
|
468
|
+
// * Using this method requires "common.messagebox" property to be set to true in io-package.json
|
|
469
|
+
// */
|
|
470
|
+
//
|
|
471
|
+
// private onMessage(obj: ioBroker.Message): void {
|
|
472
|
+
// if (typeof obj === "object" && obj.message) {
|
|
473
|
+
// if (obj.command === "send") {
|
|
474
|
+
// // e.g. send email or pushover or whatever
|
|
475
|
+
// this.log.info("send command");
|
|
476
|
+
// // Send response in callback if required
|
|
477
|
+
// if (obj.callback) this.sendTo(obj.from, obj.command, "Message received", obj.callback);
|
|
478
|
+
// }
|
|
479
|
+
// }
|
|
480
|
+
// }
|
|
481
|
+
}
|
|
482
|
+
function selectDevice(devices, deviceCode) {
|
|
483
|
+
if (devices.length === 0) {
|
|
484
|
+
throw new Error("No Proscenic devices returned by legacy cloud");
|
|
485
|
+
}
|
|
486
|
+
const selected = deviceCode ? devices.find((device) => device.code === deviceCode) : devices[0];
|
|
487
|
+
if (!selected) {
|
|
488
|
+
throw new Error("Configured Proscenic device code was not found");
|
|
489
|
+
}
|
|
490
|
+
if (!selected.sn) {
|
|
491
|
+
throw new Error("Selected Proscenic device has no protocol serial");
|
|
492
|
+
}
|
|
493
|
+
return selected;
|
|
494
|
+
}
|
|
495
|
+
function isM7Pro(device) {
|
|
496
|
+
return device.code === "M7_PRO" && device.model === "811_LDS";
|
|
497
|
+
}
|
|
498
|
+
function selectGatewayEndpoint(gateway) {
|
|
499
|
+
const endpoints = selectGatewayEndpoints(gateway.addr_list);
|
|
500
|
+
if (endpoints.length === 0) {
|
|
501
|
+
throw new Error("No Proscenic gateway endpoint returned");
|
|
502
|
+
}
|
|
503
|
+
return endpoints[0];
|
|
504
|
+
}
|
|
505
|
+
function selectGatewayEndpoints(addresses) {
|
|
506
|
+
if (!Array.isArray(addresses)) {
|
|
507
|
+
return [];
|
|
508
|
+
}
|
|
509
|
+
return addresses.map((entry, index) => {
|
|
510
|
+
const candidate = entry;
|
|
511
|
+
if (typeof candidate.ip !== "string" || candidate.ip.length === 0) {
|
|
512
|
+
throw new Error(`Gateway endpoint ${index + 1} has no host`);
|
|
513
|
+
}
|
|
514
|
+
const port = typeof candidate.port === "number" ? candidate.port : Number.parseInt(String(candidate.port), 10);
|
|
515
|
+
if (!Number.isSafeInteger(port) || port <= 0 || port > 65535) {
|
|
516
|
+
throw new Error(`Gateway endpoint ${index + 1} has invalid port`);
|
|
517
|
+
}
|
|
518
|
+
return {
|
|
519
|
+
host: candidate.ip,
|
|
520
|
+
port
|
|
521
|
+
};
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
if (require.main !== module) {
|
|
525
|
+
module.exports = (options) => new Proscenic(options);
|
|
526
|
+
} else {
|
|
527
|
+
(() => new Proscenic())();
|
|
528
|
+
}
|
|
529
|
+
//# sourceMappingURL=main.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/main.ts"],
|
|
4
|
+
"sourcesContent": ["/*\n * Created with @iobroker/create-adapter v3.1.5\n */\n\n// The adapter-core module gives you access to the core ioBroker functions\n// you need to create an adapter\nimport * as utils from \"@iobroker/adapter-core\";\nimport { normalizeConsumables21015, type ConsumableStates } from \"./domain/consumables\";\nimport {\n\tbuildCommandRequest,\n\tcommandForStateId,\n\tnormalizeCommandButtonValue,\n\ttype RobotCommand,\n} from \"./domain/commands\";\nimport {\n\tcountLiveMapAreas20002,\n\textractLiveMapCoordinateMetadata20002,\n\textractRobotPose20001,\n\tmergeLiveMapCoordinateMetadataCache,\n\tmergeLiveMapCoordinateMetadata20002,\n\trenderLiveMapImage20002,\n\ttype LiveMapCoordinateMetadata,\n\ttype RobotPose,\n} from \"./domain/live-map\";\nimport { normalizeMaintenanceHistory20003, normalizeMaintenanceMessage20003 } from \"./domain/maintenance-message\";\nimport { normalizeMap20002 } from \"./domain/map\";\nimport { reconnectDelayMs } from \"./domain/reconnect-policy\";\nimport { normalizeStatus20001 } from \"./domain/status\";\nimport { extendAdapterObjects } from \"./objects/object-definitions\";\nimport {\n\tprojectDevice,\n\tprojectConsumables,\n\tprojectLiveMapImage,\n\tprojectMapMetadata,\n\tprojectMaintenanceHistory,\n\tprojectMaintenanceMessage,\n\tprojectStatus,\n\tredactedErrorMessage,\n\tsetConsumablesReadFailure,\n\tsetConnectionState,\n\tsetInitialCapabilityStates,\n\tsetLastError,\n\tsetMaintenanceHistoryReadFailure,\n} from \"./objects/projector\";\nimport { ProscenicGatewayClient } from \"./protocol/gateway-client\";\nimport { ProscenicRestClient } from \"./protocol/rest-client\";\nimport type { DeviceRecord, GatewayData, GatewayEndpoint } from \"./protocol/types\";\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst CONSUMABLE_GATEWAY_TIMEOUT_MS = 35_000;\nconst MAX_GATEWAY_BUFFER_BYTES = 512 * 1024;\nconst MAX_LIVE_MAP_POSES = 1_000;\n\ninterface PendingConsumableRead {\n\ttimer: ioBroker.Timeout;\n\tresolve: (consumables: ConsumableStates) => void;\n\treject: (error: Error) => void;\n}\n\nclass Proscenic extends utils.Adapter {\n\tprivate gatewayClient: ProscenicGatewayClient | undefined;\n\tprivate reconnectTimer: ioBroker.Timeout | undefined;\n\tprivate reconnectAttempt = 0;\n\tprivate reconnectInProgress = false;\n\tprivate commandInProgress = false;\n\tprivate commandEnabled = false;\n\tprivate commandClient: ProscenicRestClient | undefined;\n\tprivate commandToken: string | undefined;\n\tprivate commandSerial: string | undefined;\n\tprivate shuttingDown = false;\n\tprivate recentRobotPoses: RobotPose[] = [];\n\tprivate latestMapData: unknown;\n\tprivate latestMapPathId: number | undefined;\n\tprivate latestMapId: number | undefined;\n\tprivate latestMapCoordinateMetadata: LiveMapCoordinateMetadata | undefined;\n\tprivate liveMapPathResetCount = 0;\n\tprivate lastPoseUpdated: string | undefined;\n\tprivate maintenanceEventCount = 0;\n\tprivate auxiliaryReadInProgress = false;\n\tprivate pendingConsumableRead: PendingConsumableRead | undefined;\n\n\tpublic constructor(options: Partial<utils.AdapterOptions> = {}) {\n\t\tsuper({\n\t\t\t...options,\n\t\t\tname: \"proscenic\",\n\t\t});\n\t\tthis.on(\"ready\", this.onReady.bind(this));\n\t\tthis.on(\"stateChange\", this.onStateChange.bind(this));\n\t\t// this.on(\"objectChange\", this.onObjectChange.bind(this));\n\t\t// this.on(\"message\", this.onMessage.bind(this));\n\t\tthis.on(\"unload\", this.onUnload.bind(this));\n\t}\n\n\t/**\n\t * Is called when databases are connected and adapter received configuration.\n\t */\n\tprivate async onReady(): Promise<void> {\n\t\tawait extendAdapterObjects(this);\n\t\tawait this.setState(\"info.connection\", false, true);\n\t\tawait setConnectionState(this, \"cloud\", false);\n\t\tawait setConnectionState(this, \"gateway\", false);\n\t\tawait setInitialCapabilityStates(this);\n\t\tthis.subscribeStates(\"commands.*\");\n\n\t\tif (!this.config.username || !this.config.password) {\n\t\t\tthis.log.warn(\"Proscenic cloud credentials are not configured yet.\");\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.connectReadOnlyGateway();\n\t}\n\n\t/**\n\t * Is called when adapter shuts down - callback has to be called under any circumstances!\n\t *\n\t * @param callback - Callback function\n\t */\n\tprivate onUnload(callback: () => void): void {\n\t\ttry {\n\t\t\tthis.shuttingDown = true;\n\t\t\tthis.clearReconnectTimer();\n\t\t\tthis.rejectPendingConsumableRead(new Error(\"Adapter unload interrupted consumable read\"));\n\t\t\tthis.gatewayClient?.destroy();\n\t\t\tthis.gatewayClient = undefined;\n\t\t\tthis.clearCommandSession();\n\t\t\tcallback();\n\t\t} catch (error) {\n\t\t\tthis.log.error(`Error during unloading: ${(error as Error).message}`);\n\t\t\tcallback();\n\t\t}\n\t}\n\n\tprivate async connectReadOnlyGateway(): Promise<void> {\n\t\tif (this.shuttingDown || this.reconnectInProgress) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.clearReconnectTimer();\n\t\tthis.reconnectInProgress = true;\n\t\ttry {\n\t\t\tawait this.startReadOnlyGateway();\n\t\t} catch (error) {\n\t\t\tthis.clearCommandSession();\n\t\t\tawait setLastError(this, error);\n\t\t\tawait setConnectionState(this, \"cloud\", false);\n\t\t\tawait setConnectionState(this, \"gateway\", false);\n\t\t\tthis.log.warn(`Could not start Proscenic read-only connection: ${redactedErrorMessage(error)}`);\n\t\t\tthis.scheduleReconnect(\"connection failure\");\n\t\t} finally {\n\t\t\tthis.reconnectInProgress = false;\n\t\t}\n\t}\n\n\tprivate async startReadOnlyGateway(): Promise<void> {\n\t\tconst client = new ProscenicRestClient({\n\t\t\tusername: this.config.username,\n\t\t\tpassword: this.config.password,\n\t\t\tregion: this.config.region,\n\t\t\ttimeoutMs: DEFAULT_TIMEOUT_MS,\n\t\t});\n\n\t\tthis.log.info(\"Connecting to the Proscenic legacy cloud.\");\n\t\tconst token = await client.login();\n\t\tthis.commandEnabled = false;\n\t\tthis.commandClient = client;\n\t\tthis.commandToken = token;\n\t\tawait setConnectionState(this, \"cloud\", true);\n\n\t\tconst devices = await client.listDevices();\n\t\tconst device = selectDevice(devices, this.config.deviceCode);\n\t\tawait projectDevice(this, device);\n\n\t\tif (!device.sn) {\n\t\t\tthrow new Error(\"Selected device cannot be used because its protocol serial is missing\");\n\t\t}\n\t\tthis.commandSerial = device.sn;\n\t\tthis.commandEnabled = isM7Pro(device);\n\t\tawait this.setStateAsync(\"capabilities.commands\", { val: this.commandEnabled, ack: true });\n\n\t\tconst gateway = await client.getGateway(token, device.sn);\n\t\tconst endpoint = selectGatewayEndpoint(gateway);\n\n\t\tthis.gatewayClient?.destroy();\n\t\tthis.gatewayClient = new ProscenicGatewayClient({\n\t\t\tendpoint,\n\t\t\ttoken,\n\t\t\tserial: device.sn,\n\t\t\ttimeoutMs: DEFAULT_TIMEOUT_MS,\n\t\t\tmaxBufferBytes: MAX_GATEWAY_BUFFER_BYTES,\n\t\t\tonConnect: () => {\n\t\t\t\tthis.reconnectAttempt = 0;\n\t\t\t\tvoid setConnectionState(this, \"gateway\", true);\n\t\t\t\tthis.log.info(\"Connected to the Proscenic gateway.\");\n\t\t\t\tvoid this.refreshVerifiedReadPaths();\n\t\t\t},\n\t\t\tonEvent: event => {\n\t\t\t\tvoid this.handleGatewayEvent(event.infoType, event.data);\n\t\t\t},\n\t\t\tonClose: () => {\n\t\t\t\tvoid setConnectionState(this, \"gateway\", false);\n\t\t\t\tthis.rejectPendingConsumableRead(new Error(\"Gateway closed before consumable data was received\"));\n\t\t\t\tif (!this.shuttingDown) {\n\t\t\t\t\tthis.log.warn(\"Proscenic gateway connection closed.\");\n\t\t\t\t\tthis.scheduleReconnect(\"gateway close\");\n\t\t\t\t}\n\t\t\t},\n\t\t\tonError: error => {\n\t\t\t\tvoid setLastError(this, error);\n\t\t\t\tif (!this.shuttingDown) {\n\t\t\t\t\tthis.log.warn(`Proscenic gateway error: ${redactedErrorMessage(error)}`);\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\t\tthis.gatewayClient.connect();\n\t}\n\n\tprivate scheduleReconnect(reason: string): void {\n\t\tif (this.shuttingDown || this.reconnectTimer) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.reconnectAttempt += 1;\n\t\tconst delayMs = reconnectDelayMs(this.reconnectAttempt);\n\t\tthis.log.info(\n\t\t\t`Scheduling Proscenic gateway reconnect in ${Math.round(delayMs / 1_000)} seconds after ${reason}.`,\n\t\t);\n\t\tthis.reconnectTimer = this.setTimeout(() => {\n\t\t\tthis.reconnectTimer = undefined;\n\t\t\tvoid this.connectReadOnlyGateway();\n\t\t}, delayMs);\n\t}\n\n\tprivate clearReconnectTimer(): void {\n\t\tif (this.reconnectTimer) {\n\t\t\tthis.clearTimeout(this.reconnectTimer);\n\t\t\tthis.reconnectTimer = undefined;\n\t\t}\n\t}\n\n\tprivate async handleGatewayEvent(infoType: unknown, data: unknown): Promise<void> {\n\t\tif (infoType === 21015) {\n\t\t\tconst consumables = normalizeConsumables21015(data);\n\t\t\tif (consumables) {\n\t\t\t\tawait projectConsumables(this, consumables);\n\t\t\t\tthis.resolvePendingConsumableRead(consumables);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (infoType === 20001) {\n\t\t\tconst pose = extractRobotPose20001(data);\n\t\t\tif (pose) {\n\t\t\t\tthis.lastPoseUpdated = new Date().toISOString();\n\t\t\t\tthis.recentRobotPoses.push(pose);\n\t\t\t\tif (this.recentRobotPoses.length > MAX_LIVE_MAP_POSES) {\n\t\t\t\t\tthis.recentRobotPoses = this.recentRobotPoses.slice(-MAX_LIVE_MAP_POSES);\n\t\t\t\t}\n\t\t\t\tawait this.projectLatestLiveMapImage(\"pose\");\n\t\t\t}\n\n\t\t\tconst status = normalizeStatus20001(data);\n\t\t\tif (status) {\n\t\t\t\tawait projectStatus(this, status);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (infoType === 20002) {\n\t\t\tconst map = normalizeMap20002(data);\n\t\t\tconst coordinateMetadata = extractLiveMapCoordinateMetadata20002(data);\n\t\t\tif (map) {\n\t\t\t\tif (map.mapId !== undefined && this.latestMapId !== undefined && map.mapId !== this.latestMapId) {\n\t\t\t\t\tthis.latestMapCoordinateMetadata = undefined;\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\tmap.pathId !== undefined &&\n\t\t\t\t\tthis.latestMapPathId !== undefined &&\n\t\t\t\t\tmap.pathId !== this.latestMapPathId\n\t\t\t\t) {\n\t\t\t\t\tthis.recentRobotPoses = [];\n\t\t\t\t\tthis.liveMapPathResetCount += 1;\n\t\t\t\t\tthis.lastPoseUpdated = undefined;\n\t\t\t\t}\n\t\t\t\tif (map.pathId !== undefined) {\n\t\t\t\t\tthis.latestMapPathId = map.pathId;\n\t\t\t\t}\n\t\t\t\tif (map.mapId !== undefined) {\n\t\t\t\t\tthis.latestMapId = map.mapId;\n\t\t\t\t}\n\t\t\t\tif (coordinateMetadata) {\n\t\t\t\t\tthis.latestMapCoordinateMetadata = mergeLiveMapCoordinateMetadataCache(\n\t\t\t\t\t\tthis.latestMapCoordinateMetadata,\n\t\t\t\t\t\tcoordinateMetadata,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tawait projectMapMetadata(this, map);\n\t\t\t}\n\t\t\tthis.latestMapData = data;\n\t\t\tawait this.projectLatestLiveMapImage(\"map\");\n\t\t\treturn;\n\t\t}\n\n\t\tif (infoType === 20003) {\n\t\t\tconst message = normalizeMaintenanceMessage20003(data);\n\t\t\tif (message) {\n\t\t\t\tthis.maintenanceEventCount += 1;\n\t\t\t\tawait projectMaintenanceMessage(this, message, this.maintenanceEventCount);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async refreshVerifiedReadPaths(): Promise<void> {\n\t\tif (this.auxiliaryReadInProgress || this.shuttingDown) {\n\t\t\treturn;\n\t\t}\n\t\tif (!this.commandEnabled) {\n\t\t\treturn;\n\t\t}\n\t\tif (!this.commandClient || !this.commandToken || !this.commandSerial) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.auxiliaryReadInProgress = true;\n\t\ttry {\n\t\t\tawait Promise.all([this.refreshMaintenanceHistory(), this.refreshConsumables()]);\n\t\t} finally {\n\t\t\tthis.auxiliaryReadInProgress = false;\n\t\t}\n\t}\n\n\tprivate async refreshMaintenanceHistory(): Promise<void> {\n\t\tif (!this.commandClient || !this.commandToken || !this.commandSerial) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst data = await this.commandClient.getMaintenanceHistory(this.commandToken, this.commandSerial);\n\t\t\tconst history = normalizeMaintenanceHistory20003(data);\n\t\t\tif (!history) {\n\t\t\t\tthrow new Error(\"Maintenance history response did not contain usable events\");\n\t\t\t}\n\t\t\tawait projectMaintenanceHistory(this, history);\n\t\t} catch (error) {\n\t\t\tawait setMaintenanceHistoryReadFailure(this, error);\n\t\t\tthis.log.debug(`Could not refresh Proscenic maintenance history: ${redactedErrorMessage(error)}`);\n\t\t}\n\t}\n\n\tprivate async refreshConsumables(): Promise<void> {\n\t\tif (!this.commandClient || !this.commandToken || !this.commandSerial) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet consumableRead: Promise<ConsumableStates> | undefined;\n\t\ttry {\n\t\t\tconsumableRead = this.awaitNextConsumables();\n\t\t\tawait this.commandClient.requestConsumables(this.commandToken, this.commandSerial);\n\t\t\tawait consumableRead;\n\t\t} catch (error) {\n\t\t\tvoid consumableRead?.catch(() => undefined);\n\t\t\tthis.rejectPendingConsumableRead(error instanceof Error ? error : new Error(String(error)));\n\t\t\tawait setConsumablesReadFailure(this, error);\n\t\t\tthis.log.debug(`Could not refresh Proscenic consumables: ${redactedErrorMessage(error)}`);\n\t\t}\n\t}\n\n\tprivate awaitNextConsumables(): Promise<ConsumableStates> {\n\t\tthis.rejectPendingConsumableRead(new Error(\"Superseded by a newer consumable read\"));\n\n\t\treturn new Promise<ConsumableStates>((resolve, reject) => {\n\t\t\tconst timer = this.setTimeout(() => {\n\t\t\t\tthis.pendingConsumableRead = undefined;\n\t\t\t\treject(new Error(`No consumable gateway event received within ${CONSUMABLE_GATEWAY_TIMEOUT_MS} ms`));\n\t\t\t}, CONSUMABLE_GATEWAY_TIMEOUT_MS);\n\t\t\tif (timer === undefined) {\n\t\t\t\treject(new Error(\"Could not schedule consumable gateway timeout\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.pendingConsumableRead = { timer, resolve, reject };\n\t\t});\n\t}\n\n\tprivate resolvePendingConsumableRead(consumables: ConsumableStates): void {\n\t\tif (!this.pendingConsumableRead) {\n\t\t\treturn;\n\t\t}\n\t\tthis.clearTimeout(this.pendingConsumableRead.timer);\n\t\tthis.pendingConsumableRead.resolve(consumables);\n\t\tthis.pendingConsumableRead = undefined;\n\t}\n\n\tprivate rejectPendingConsumableRead(error: Error): void {\n\t\tif (!this.pendingConsumableRead) {\n\t\t\treturn;\n\t\t}\n\t\tthis.clearTimeout(this.pendingConsumableRead.timer);\n\t\tthis.pendingConsumableRead.reject(error);\n\t\tthis.pendingConsumableRead = undefined;\n\t}\n\n\tprivate async projectLatestLiveMapImage(renderReason: \"map\" | \"pose\"): Promise<void> {\n\t\tif (!this.latestMapData) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst renderData = mergeLiveMapCoordinateMetadata20002(\n\t\t\t\tthis.latestMapData,\n\t\t\t\tthis.latestMapCoordinateMetadata,\n\t\t\t);\n\t\t\tconst image = renderLiveMapImage20002(renderData, this.recentRobotPoses);\n\t\t\tif (image) {\n\t\t\t\tawait projectLiveMapImage(this, image, {\n\t\t\t\t\trenderReason,\n\t\t\t\t\tlastPathId: this.latestMapPathId,\n\t\t\t\t\tpathResetCount: this.liveMapPathResetCount,\n\t\t\t\t\tlastPoseUpdated: this.lastPoseUpdated,\n\t\t\t\t\tcurrentAreaCount: countLiveMapAreas20002(this.latestMapData),\n\t\t\t\t\tcachedAreaCount: this.latestMapCoordinateMetadata?.area?.length ?? 0,\n\t\t\t\t\thasCachedStaticOverlays:\n\t\t\t\t\t\t(this.latestMapCoordinateMetadata?.area?.length ?? 0) > 0 ||\n\t\t\t\t\t\tthis.latestMapCoordinateMetadata?.chargeHandlePos !== undefined,\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthis.log.debug(`Could not render experimental live map image: ${redactedErrorMessage(error)}`);\n\t\t}\n\t}\n\n\t// If you need to react to object changes, uncomment the following block and the corresponding line in the constructor.\n\t// You also need to subscribe to the objects with `this.subscribeObjects`, similar to `this.subscribeStates`.\n\t// /**\n\t// * Is called if a subscribed object changes\n\t// */\n\t// private onObjectChange(id: string, obj: ioBroker.Object | null | undefined): void {\n\t// \tif (obj) {\n\t// \t\t// The object was changed\n\t// \t\tthis.log.info(`object ${id} changed: ${JSON.stringify(obj)}`);\n\t// \t} else {\n\t// \t\t// The object was deleted\n\t// \t\tthis.log.info(`object ${id} deleted`);\n\t// \t}\n\t// }\n\n\t/**\n\t * Is called if a subscribed state changes\n\t *\n\t * @param id - State ID\n\t * @param state - State object\n\t */\n\tprivate onStateChange(id: string, state: ioBroker.State | null | undefined): void {\n\t\tif (!state || state.ack !== false) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst relativeId = this.relativeStateId(id);\n\t\tconst command = commandForStateId(relativeId);\n\t\tif (!command) {\n\t\t\tthis.log.debug(`Ignoring unsupported state command for ${relativeId}.`);\n\t\t\treturn;\n\t\t}\n\n\t\tconst trigger = normalizeCommandButtonValue(state.val);\n\t\tif (trigger === false) {\n\t\t\tvoid this.setStateAsync(relativeId, { val: false, ack: true });\n\t\t\treturn;\n\t\t}\n\t\tif (trigger === undefined) {\n\t\t\tthis.log.debug(`Ignoring unsupported command button value for ${relativeId}.`);\n\t\t\treturn;\n\t\t}\n\n\t\tvoid this.executeCommand(relativeId, command);\n\t}\n\n\tprivate relativeStateId(id: string): string {\n\t\tconst prefix = `${this.namespace}.`;\n\t\treturn id.startsWith(prefix) ? id.slice(prefix.length) : id;\n\t}\n\n\tprivate async executeCommand(stateId: string, command: RobotCommand): Promise<void> {\n\t\tif (this.commandInProgress) {\n\t\t\tawait this.setCommandFailure(\n\t\t\t\tstateId,\n\t\t\t\tcommand,\n\t\t\t\tnew Error(\"Another Proscenic command is already in progress\"),\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.commandInProgress = true;\n\t\tawait this.setStateAsync(\"commands.lastCommand\", { val: command, ack: true });\n\t\tawait this.setStateAsync(\"commands.lastResult\", { val: \"running\", ack: true });\n\t\tawait this.setStateAsync(\"commands.lastError\", { val: \"\", ack: true });\n\t\tawait this.setStateAsync(\"commands.lastExecution\", { val: new Date().toISOString(), ack: true });\n\n\t\ttry {\n\t\t\tif (!this.commandClient || !this.commandToken || !this.commandSerial || !this.config.username) {\n\t\t\t\tthrow new Error(\"Proscenic command session is not ready\");\n\t\t\t}\n\t\t\tif (!this.commandEnabled) {\n\t\t\t\tthrow new Error(\"Proscenic commands are not enabled for the selected device\");\n\t\t\t}\n\n\t\t\tconst request = buildCommandRequest(command, this.commandSerial, this.config.username);\n\t\t\tconst result = await this.commandClient.sendCommand(this.commandToken, request);\n\t\t\tawait this.setStateAsync(\"commands.lastResult\", {\n\t\t\t\tval: result.code === undefined || result.code === 0 ? \"sent\" : `api-code-${result.code}`,\n\t\t\t\tack: true,\n\t\t\t});\n\t\t\tawait this.setStateAsync(stateId, { val: false, ack: true });\n\t\t} catch (error) {\n\t\t\tawait this.setCommandFailure(stateId, command, error);\n\t\t} finally {\n\t\t\tthis.commandInProgress = false;\n\t\t}\n\t}\n\n\tprivate async setCommandFailure(stateId: string, command: RobotCommand, error: unknown): Promise<void> {\n\t\tconst message = redactedErrorMessage(error);\n\t\tawait this.setStateAsync(\"commands.lastCommand\", { val: command, ack: true });\n\t\tawait this.setStateAsync(\"commands.lastResult\", { val: \"failed\", ack: true });\n\t\tawait this.setStateAsync(\"commands.lastError\", { val: message, ack: true });\n\t\tawait this.setStateAsync(\"commands.lastExecution\", { val: new Date().toISOString(), ack: true });\n\t\tawait this.setStateAsync(stateId, { val: false, ack: true });\n\t\tthis.log.warn(`Proscenic command ${command} failed: ${message}`);\n\t}\n\n\tprivate clearCommandSession(): void {\n\t\tthis.commandEnabled = false;\n\t\tthis.commandClient = undefined;\n\t\tthis.commandToken = undefined;\n\t\tthis.commandSerial = undefined;\n\t}\n\n\t// If you need to accept messages in your adapter, uncomment the following block and the corresponding line in the constructor.\n\t// /**\n\t// * Some message was sent to this instance over message box. Used by email, pushover, text2speech, ...\n\t// * Using this method requires \"common.messagebox\" property to be set to true in io-package.json\n\t// */\n\t//\n\t// private onMessage(obj: ioBroker.Message): void {\n\t// \tif (typeof obj === \"object\" && obj.message) {\n\t// \t\tif (obj.command === \"send\") {\n\t// \t\t\t// e.g. send email or pushover or whatever\n\t// \t\t\tthis.log.info(\"send command\");\n\t// \t\t\t// Send response in callback if required\n\t// \t\t\tif (obj.callback) this.sendTo(obj.from, obj.command, \"Message received\", obj.callback);\n\t// \t\t}\n\t// \t}\n\t// }\n}\n\nfunction selectDevice(devices: DeviceRecord[], deviceCode: string): DeviceRecord {\n\tif (devices.length === 0) {\n\t\tthrow new Error(\"No Proscenic devices returned by legacy cloud\");\n\t}\n\n\tconst selected = deviceCode ? devices.find(device => device.code === deviceCode) : devices[0];\n\tif (!selected) {\n\t\tthrow new Error(\"Configured Proscenic device code was not found\");\n\t}\n\tif (!selected.sn) {\n\t\tthrow new Error(\"Selected Proscenic device has no protocol serial\");\n\t}\n\n\treturn selected;\n}\n\nfunction isM7Pro(device: DeviceRecord): boolean {\n\treturn device.code === \"M7_PRO\" && device.model === \"811_LDS\";\n}\n\nfunction selectGatewayEndpoint(gateway: GatewayData): GatewayEndpoint {\n\tconst endpoints = selectGatewayEndpoints(gateway.addr_list);\n\tif (endpoints.length === 0) {\n\t\tthrow new Error(\"No Proscenic gateway endpoint returned\");\n\t}\n\n\treturn endpoints[0];\n}\n\nfunction selectGatewayEndpoints(addresses: unknown): GatewayEndpoint[] {\n\tif (!Array.isArray(addresses)) {\n\t\treturn [];\n\t}\n\n\treturn addresses.map((entry, index) => {\n\t\tconst candidate = entry as { ip?: unknown; port?: unknown };\n\t\tif (typeof candidate.ip !== \"string\" || candidate.ip.length === 0) {\n\t\t\tthrow new Error(`Gateway endpoint ${index + 1} has no host`);\n\t\t}\n\n\t\tconst port = typeof candidate.port === \"number\" ? candidate.port : Number.parseInt(String(candidate.port), 10);\n\t\tif (!Number.isSafeInteger(port) || port <= 0 || port > 65_535) {\n\t\t\tthrow new Error(`Gateway endpoint ${index + 1} has invalid port`);\n\t\t}\n\n\t\treturn {\n\t\t\thost: candidate.ip,\n\t\t\tport,\n\t\t};\n\t});\n}\n\nif (require.main !== module) {\n\t// Export the constructor in compact mode\n\tmodule.exports = (options: Partial<utils.AdapterOptions> | undefined) => new Proscenic(options);\n} else {\n\t// otherwise start the instance directly\n\t(() => new Proscenic())();\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|