@rfranzoi/scrypted-mqtt-securitysystem 1.0.48 → 1.0.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.nodejs.js +113 -52
- package/dist/plugin.zip +0 -0
- package/package.json +1 -1
package/dist/main.nodejs.js
CHANGED
|
@@ -34077,8 +34077,12 @@ function falsy(v) {
|
|
|
34077
34077
|
const s = v.toString().trim().toLowerCase();
|
|
34078
34078
|
return s === '0' || s === 'false' || s === 'offline' || s === 'no' || s === 'off';
|
|
34079
34079
|
}
|
|
34080
|
-
function normalize(s) {
|
|
34081
|
-
|
|
34080
|
+
function normalize(s) {
|
|
34081
|
+
return (s || '').trim().toLowerCase();
|
|
34082
|
+
}
|
|
34083
|
+
function clamp(n, min, max) {
|
|
34084
|
+
return Math.max(min, Math.min(max, n));
|
|
34085
|
+
}
|
|
34082
34086
|
/** SecuritySystem outgoing defaults (PAI-like) */
|
|
34083
34087
|
const DEFAULT_OUTGOING = {
|
|
34084
34088
|
[sdk_1.SecuritySystemMode.Disarmed]: 'disarm',
|
|
@@ -34149,6 +34153,7 @@ class BaseMqttSensor extends sdk_1.ScryptedDeviceBase {
|
|
|
34149
34153
|
this.setAndEmit('batteryLevel', n, sdk_1.ScryptedInterface.Battery);
|
|
34150
34154
|
}
|
|
34151
34155
|
else if (topic === this.cfg.topics.lowBattery && !this.cfg.topics.batteryLevel) {
|
|
34156
|
+
// Se abbiamo solo lowBattery: true => 10%, false => 100% (ma solo se non c'è già un valore)
|
|
34152
34157
|
if (truthy(np))
|
|
34153
34158
|
this.setAndEmit('batteryLevel', 10, sdk_1.ScryptedInterface.Battery);
|
|
34154
34159
|
else if (falsy(np) && this.batteryLevel === undefined)
|
|
@@ -34204,14 +34209,17 @@ class OccupancyMqttSensor extends BaseMqttSensor {
|
|
|
34204
34209
|
class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
34205
34210
|
constructor() {
|
|
34206
34211
|
super();
|
|
34212
|
+
// sensor management
|
|
34207
34213
|
this.sensorsCfg = [];
|
|
34208
34214
|
this.devices = new Map();
|
|
34215
|
+
// (facoltativo) Imposta il device type in UI
|
|
34209
34216
|
setTimeout(() => {
|
|
34210
34217
|
try {
|
|
34211
34218
|
systemManager.getDeviceById(this.id)?.setType?.(sdk_1.ScryptedDeviceType.SecuritySystem);
|
|
34212
34219
|
}
|
|
34213
34220
|
catch { }
|
|
34214
34221
|
});
|
|
34222
|
+
// Default state
|
|
34215
34223
|
this.securitySystemState = this.securitySystemState || {
|
|
34216
34224
|
mode: sdk_1.SecuritySystemMode.Disarmed,
|
|
34217
34225
|
supportedModes: [
|
|
@@ -34222,9 +34230,12 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34222
34230
|
],
|
|
34223
34231
|
};
|
|
34224
34232
|
this.online = this.online ?? false;
|
|
34233
|
+
// Load sensors config and announce devices
|
|
34225
34234
|
this.loadSensorsFromStorage();
|
|
34226
34235
|
this.discoverSensors().catch(e => this.console.error('discoverSensors error', e));
|
|
34236
|
+
// Connect on start
|
|
34227
34237
|
this.connectMqtt().catch(e => this.console.error('MQTT connect error:', e));
|
|
34238
|
+
// chiusura pulita del client MQTT ai reload/stop del plugin
|
|
34228
34239
|
try {
|
|
34229
34240
|
process.once('SIGTERM', () => { try {
|
|
34230
34241
|
this.client?.end(true);
|
|
@@ -34241,7 +34252,7 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34241
34252
|
}
|
|
34242
34253
|
catch { }
|
|
34243
34254
|
}
|
|
34244
|
-
|
|
34255
|
+
// ====== Strict parsing helpers ======
|
|
34245
34256
|
parseJsonArray(key, fallback) {
|
|
34246
34257
|
try {
|
|
34247
34258
|
const raw = (this.storage.getItem(key) || '').trim();
|
|
@@ -34256,45 +34267,46 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34256
34267
|
return fallback;
|
|
34257
34268
|
}
|
|
34258
34269
|
}
|
|
34259
|
-
getStrictTokens() {
|
|
34260
|
-
const target = this.parseJsonArray('targetStateValues', ['armed_home', 'armed_away', 'armed_night', 'disarmed']);
|
|
34261
|
-
const current = this.parseJsonArray('currentStateValues', ['armed_home', 'armed_away', 'armed_night', 'disarmed', 'triggered']);
|
|
34262
|
-
const triggered = this.parseJsonArray('triggeredValues', ['triggered', 'alarm']);
|
|
34263
|
-
const union = new Set([...target, ...current]);
|
|
34264
|
-
return {
|
|
34265
|
-
union,
|
|
34266
|
-
triggered: new Set(triggered),
|
|
34267
|
-
};
|
|
34268
|
-
}
|
|
34269
34270
|
useStrict() {
|
|
34270
34271
|
return this.storage.getItem('strictParsing') === 'true';
|
|
34271
34272
|
}
|
|
34272
34273
|
parseIncomingMode(payload) {
|
|
34273
|
-
const
|
|
34274
|
-
const np = normalize(p);
|
|
34274
|
+
const np = normalize(payload?.toString?.() ?? String(payload ?? ''));
|
|
34275
34275
|
if (!this.useStrict())
|
|
34276
34276
|
return payloadToModeLoose(np);
|
|
34277
|
-
|
|
34278
|
-
|
|
34279
|
-
if (union.has('disarmed') && np === 'disarmed')
|
|
34277
|
+
const currentVals = new Set(this.parseJsonArray('currentStateValues', ['armed_home', 'armed_away', 'armed_night', 'disarmed', 'triggered']));
|
|
34278
|
+
if (currentVals.has('disarmed') && np === 'disarmed')
|
|
34280
34279
|
return sdk_1.SecuritySystemMode.Disarmed;
|
|
34281
|
-
if (
|
|
34280
|
+
if (currentVals.has('armed_home') && np === 'armed_home')
|
|
34282
34281
|
return sdk_1.SecuritySystemMode.HomeArmed;
|
|
34283
|
-
if (
|
|
34282
|
+
if (currentVals.has('armed_away') && np === 'armed_away')
|
|
34284
34283
|
return sdk_1.SecuritySystemMode.AwayArmed;
|
|
34285
|
-
if (
|
|
34284
|
+
if (currentVals.has('armed_night') && np === 'armed_night')
|
|
34286
34285
|
return sdk_1.SecuritySystemMode.NightArmed;
|
|
34287
|
-
// transitori/altro: ignora
|
|
34288
34286
|
return undefined;
|
|
34289
34287
|
}
|
|
34290
34288
|
isTriggeredToken(np) {
|
|
34291
34289
|
if (this.useStrict()) {
|
|
34292
|
-
const
|
|
34290
|
+
const triggered = new Set(this.parseJsonArray('triggeredValues', ['triggered', 'alarm']));
|
|
34293
34291
|
return triggered.has(np);
|
|
34294
34292
|
}
|
|
34295
|
-
// loose
|
|
34296
34293
|
return np === 'triggered' || np === 'alarm';
|
|
34297
34294
|
}
|
|
34295
|
+
/** Sceglie il token di publish preferito per ciascuna modalità usando targetStateValues quando strict=ON */
|
|
34296
|
+
preferredTokenForMode(mode) {
|
|
34297
|
+
const t = this.parseJsonArray('targetStateValues', ['armed_home', 'armed_away', 'armed_night', 'disarmed']);
|
|
34298
|
+
const pick = (...cands) => cands.find(c => t.includes(c));
|
|
34299
|
+
switch (mode) {
|
|
34300
|
+
case sdk_1.SecuritySystemMode.Disarmed:
|
|
34301
|
+
return pick('disarmed', 'disarm') || 'disarmed';
|
|
34302
|
+
case sdk_1.SecuritySystemMode.HomeArmed:
|
|
34303
|
+
return pick('armed_home', 'arm_home', 'home', 'stay') || 'armed_home';
|
|
34304
|
+
case sdk_1.SecuritySystemMode.AwayArmed:
|
|
34305
|
+
return pick('armed_away', 'arm_away', 'away') || 'armed_away';
|
|
34306
|
+
case sdk_1.SecuritySystemMode.NightArmed:
|
|
34307
|
+
return pick('armed_night', 'arm_night', 'night', 'sleep') || 'armed_night';
|
|
34308
|
+
}
|
|
34309
|
+
}
|
|
34298
34310
|
// helpers persistenza
|
|
34299
34311
|
saveSensorsToStorage() {
|
|
34300
34312
|
try {
|
|
@@ -34327,6 +34339,11 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34327
34339
|
{ group: 'Parsing / State tokens', key: 'targetStateValues', title: 'Accepted Target State Values (JSON array)', placeholder: '["armed_home","armed_away","armed_night","disarmed"]', value: this.storage.getItem('targetStateValues') || '["armed_home","armed_away","armed_night","disarmed"]' },
|
|
34328
34340
|
{ group: 'Parsing / State tokens', key: 'currentStateValues', title: 'Accepted Current State Values (JSON array)', placeholder: '["armed_home","armed_away","armed_night","disarmed","triggered"]', value: this.storage.getItem('currentStateValues') || '["armed_home","armed_away","armed_night","disarmed","triggered"]' },
|
|
34329
34341
|
{ group: 'Parsing / State tokens', key: 'triggeredValues', title: 'Triggered tokens (JSON array)', placeholder: '["triggered","alarm"]', value: this.storage.getItem('triggeredValues') || '["triggered","alarm"]' },
|
|
34342
|
+
// --- Publish Payloads (override) ---
|
|
34343
|
+
{ group: 'Publish Payloads (override)', key: 'payloadDisarm', title: 'Payload for Disarm', placeholder: 'disarmed', value: this.storage.getItem('payloadDisarm') || '', description: 'Se vuoto: usa targetStateValues (strict ON) o i default arm_*/disarm (strict OFF).' },
|
|
34344
|
+
{ group: 'Publish Payloads (override)', key: 'payloadHome', title: 'Payload for Home Armed', placeholder: 'armed_home', value: this.storage.getItem('payloadHome') || '' },
|
|
34345
|
+
{ group: 'Publish Payloads (override)', key: 'payloadAway', title: 'Payload for Away Armed', placeholder: 'armed_away', value: this.storage.getItem('payloadAway') || '' },
|
|
34346
|
+
{ group: 'Publish Payloads (override)', key: 'payloadNight', title: 'Payload for Night Armed', placeholder: 'armed_night', value: this.storage.getItem('payloadNight') || '' },
|
|
34330
34347
|
];
|
|
34331
34348
|
// ---- UI Add Sensor ----
|
|
34332
34349
|
out.push({ group: 'Add Sensor', key: 'new.id', title: 'New Sensor ID', placeholder: 'porta-ingresso', value: this.storage.getItem('new.id') || '' }, { group: 'Add Sensor', key: 'new.name', title: 'Name', placeholder: 'Porta Ingresso', value: this.storage.getItem('new.name') || '' }, { group: 'Add Sensor', key: 'new.kind', title: 'Type', value: this.storage.getItem('new.kind') || 'contact', choices: ['contact', 'motion', 'occupancy'] }, { group: 'Add Sensor', key: 'new.create', title: 'Create sensor', type: 'boolean', description: 'Fill the fields above and toggle this on to create the sensor. After creation, restart this plugin to see the accessory listed below. To show it in HomeKit, restart the HomeKit plugin as well.' });
|
|
@@ -34334,6 +34351,7 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34334
34351
|
for (const cfg of this.sensorsCfg) {
|
|
34335
34352
|
const gid = `Sensor: ${cfg.name} [${cfg.id}]`;
|
|
34336
34353
|
out.push({ group: gid, key: `sensor.${cfg.id}.name`, title: 'Name', value: cfg.name }, { group: gid, key: `sensor.${cfg.id}.kind`, title: 'Type', value: cfg.kind, choices: ['contact', 'motion', 'occupancy'] });
|
|
34354
|
+
// primary per tipo
|
|
34337
34355
|
if (cfg.kind === 'contact') {
|
|
34338
34356
|
out.push({ group: gid, key: `sensor.${cfg.id}.topic.contact`, title: 'Contact State Topic', value: cfg.topics.contact || '', placeholder: 'paradox/states/zones/XYZ/open' });
|
|
34339
34357
|
}
|
|
@@ -34343,13 +34361,15 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34343
34361
|
else {
|
|
34344
34362
|
out.push({ group: gid, key: `sensor.${cfg.id}.topic.occupancy`, title: 'Occupancy Detected Topic', value: cfg.topics.occupancy || '', placeholder: 'paradox/states/zones/XYZ/open' });
|
|
34345
34363
|
}
|
|
34364
|
+
// extra opzionali
|
|
34346
34365
|
out.push({ group: gid, key: `sensor.${cfg.id}.topic.batteryLevel`, title: 'Battery Level Topic (0..100)', value: cfg.topics.batteryLevel || '' }, { group: gid, key: `sensor.${cfg.id}.topic.lowBattery`, title: 'Low Battery Topic (bool)', value: cfg.topics.lowBattery || '' }, { group: gid, key: `sensor.${cfg.id}.topic.tamper`, title: 'Tamper Topic', value: cfg.topics.tamper || '' }, { group: gid, key: `sensor.${cfg.id}.topic.online`, title: 'Online Topic', value: cfg.topics.online || '' }, { group: gid, key: `sensor.${cfg.id}.remove`, title: 'Remove sensor', type: 'boolean' });
|
|
34347
34366
|
}
|
|
34348
34367
|
return out;
|
|
34349
34368
|
}
|
|
34350
34369
|
async putSetting(key, value) {
|
|
34370
|
+
// salva sempre nella storage la value del campo (così resta in UI)
|
|
34351
34371
|
this.storage.setItem(key, String(value));
|
|
34352
|
-
// Add Sensor
|
|
34372
|
+
// --- Add Sensor workflow ---
|
|
34353
34373
|
if (key === 'new.create' && String(value) === 'true') {
|
|
34354
34374
|
const id = (this.storage.getItem('new.id') || '').trim();
|
|
34355
34375
|
const name = (this.storage.getItem('new.name') || '').trim() || id;
|
|
@@ -34364,6 +34384,7 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34364
34384
|
}
|
|
34365
34385
|
this.sensorsCfg.push({ id, name, kind, topics: {} });
|
|
34366
34386
|
this.saveSensorsToStorage();
|
|
34387
|
+
// pulisci i campi "new.*"
|
|
34367
34388
|
this.storage.removeItem('new.id');
|
|
34368
34389
|
this.storage.removeItem('new.name');
|
|
34369
34390
|
this.storage.removeItem('new.kind');
|
|
@@ -34372,7 +34393,7 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34372
34393
|
await this.connectMqtt(true);
|
|
34373
34394
|
return;
|
|
34374
34395
|
}
|
|
34375
|
-
// Edit/Remove sensore
|
|
34396
|
+
// --- Edit/Remove sensore esistente ---
|
|
34376
34397
|
const m = key.match(/^sensor\.([^\.]+)\.(.+)$/);
|
|
34377
34398
|
if (m) {
|
|
34378
34399
|
const sid = m[1];
|
|
@@ -34383,6 +34404,7 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34383
34404
|
return;
|
|
34384
34405
|
}
|
|
34385
34406
|
if (prop === 'remove' && String(value) === 'true') {
|
|
34407
|
+
// elimina
|
|
34386
34408
|
this.sensorsCfg = this.sensorsCfg.filter(s => s.id !== sid);
|
|
34387
34409
|
this.saveSensorsToStorage();
|
|
34388
34410
|
try {
|
|
@@ -34390,15 +34412,18 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34390
34412
|
deviceManager.onDeviceRemoved?.(`sensor:${sid}`);
|
|
34391
34413
|
}
|
|
34392
34414
|
catch { }
|
|
34415
|
+
// pulisci flag
|
|
34393
34416
|
this.storage.removeItem(key);
|
|
34394
34417
|
await this.discoverSensors();
|
|
34395
34418
|
await this.connectMqtt(true);
|
|
34396
34419
|
return;
|
|
34397
34420
|
}
|
|
34398
|
-
if (prop === 'name')
|
|
34421
|
+
if (prop === 'name') {
|
|
34399
34422
|
cfg.name = String(value);
|
|
34400
|
-
|
|
34423
|
+
}
|
|
34424
|
+
else if (prop === 'kind') {
|
|
34401
34425
|
cfg.kind = String(value);
|
|
34426
|
+
}
|
|
34402
34427
|
else if (prop.startsWith('topic.')) {
|
|
34403
34428
|
const tk = prop.substring('topic.'.length);
|
|
34404
34429
|
cfg.topics[tk] = String(value).trim();
|
|
@@ -34408,8 +34433,9 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34408
34433
|
await this.connectMqtt(true);
|
|
34409
34434
|
return;
|
|
34410
34435
|
}
|
|
34411
|
-
//
|
|
34436
|
+
// --- Altro (MQTT / Alarm settings / parsing / payloads) ---
|
|
34412
34437
|
if (key === 'sensorsJson') {
|
|
34438
|
+
// non più mostrato, ma se presente da vecchie versioni
|
|
34413
34439
|
this.loadSensorsFromStorage();
|
|
34414
34440
|
await this.discoverSensors();
|
|
34415
34441
|
await this.connectMqtt(true);
|
|
@@ -34419,12 +34445,15 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34419
34445
|
}
|
|
34420
34446
|
}
|
|
34421
34447
|
/** ---- DeviceProvider ---- */
|
|
34422
|
-
async getDevice(nativeId) {
|
|
34448
|
+
async getDevice(nativeId) {
|
|
34449
|
+
return this.devices.get(nativeId);
|
|
34450
|
+
}
|
|
34423
34451
|
async releaseDevice(_id, nativeId) {
|
|
34424
34452
|
try {
|
|
34425
34453
|
const dev = this.devices.get(nativeId);
|
|
34426
|
-
if (dev)
|
|
34454
|
+
if (dev) {
|
|
34427
34455
|
this.devices.delete(nativeId);
|
|
34456
|
+
}
|
|
34428
34457
|
try {
|
|
34429
34458
|
deviceManager.onDeviceRemoved?.(nativeId);
|
|
34430
34459
|
}
|
|
@@ -34438,6 +34467,7 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34438
34467
|
try {
|
|
34439
34468
|
const raw = this.storage.getItem('sensorsJson') || '[]';
|
|
34440
34469
|
const parsed = JSON.parse(raw);
|
|
34470
|
+
// sanitize
|
|
34441
34471
|
this.sensorsCfg = (parsed || []).filter(x => x && x.id && x.name && x.kind && x.topics);
|
|
34442
34472
|
}
|
|
34443
34473
|
catch (e) {
|
|
@@ -34447,21 +34477,25 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34447
34477
|
}
|
|
34448
34478
|
/** ===== discoverSensors: annuncia PRIMA, istanzia DOPO ===== */
|
|
34449
34479
|
async discoverSensors() {
|
|
34450
|
-
// 1)
|
|
34480
|
+
// 1) Prepara i manifest (niente istanze qui)
|
|
34451
34481
|
const manifests = this.sensorsCfg.map(cfg => {
|
|
34452
34482
|
const nativeId = `sensor:${cfg.id}`;
|
|
34453
34483
|
const t = cfg.topics || {};
|
|
34454
34484
|
const interfaces = [sdk_1.ScryptedInterface.Online];
|
|
34485
|
+
// Tamper solo se c'è un topic tamper
|
|
34455
34486
|
if (t.tamper)
|
|
34456
34487
|
interfaces.push(sdk_1.ScryptedInterface.TamperSensor);
|
|
34488
|
+
// Interfaccia primaria
|
|
34457
34489
|
if (cfg.kind === 'contact')
|
|
34458
34490
|
interfaces.unshift(sdk_1.ScryptedInterface.EntrySensor);
|
|
34459
34491
|
else if (cfg.kind === 'motion')
|
|
34460
34492
|
interfaces.unshift(sdk_1.ScryptedInterface.MotionSensor);
|
|
34461
34493
|
else
|
|
34462
34494
|
interfaces.unshift(sdk_1.ScryptedInterface.OccupancySensor);
|
|
34463
|
-
|
|
34495
|
+
// Battery solo se previsto
|
|
34496
|
+
if ((t.batteryLevel && t.batteryLevel.trim()) || (t.lowBattery && t.lowBattery.trim())) {
|
|
34464
34497
|
interfaces.push(sdk_1.ScryptedInterface.Battery);
|
|
34498
|
+
}
|
|
34465
34499
|
return { nativeId, name: cfg.name, type: sdk_1.ScryptedDeviceType.Sensor, interfaces };
|
|
34466
34500
|
});
|
|
34467
34501
|
// 2) Annuncio
|
|
@@ -34476,7 +34510,7 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34476
34510
|
this.console.log('Annunciato:', m.nativeId);
|
|
34477
34511
|
}
|
|
34478
34512
|
}
|
|
34479
|
-
// 3) Istanzia/aggiorna
|
|
34513
|
+
// 3) Istanzia/aggiorna DOPO l’annuncio
|
|
34480
34514
|
for (const cfg of this.sensorsCfg) {
|
|
34481
34515
|
const nativeId = `sensor:${cfg.id}`;
|
|
34482
34516
|
let dev = this.devices.get(nativeId);
|
|
@@ -34492,9 +34526,17 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34492
34526
|
else {
|
|
34493
34527
|
dev.cfg = cfg;
|
|
34494
34528
|
}
|
|
34495
|
-
//
|
|
34529
|
+
// Default “OK” se abbiamo Battery ma nessun valore ancora ricevuto
|
|
34530
|
+
const hasBattery = !!(cfg.topics.batteryLevel && cfg.topics.batteryLevel.trim()) || !!(cfg.topics.lowBattery && cfg.topics.lowBattery.trim());
|
|
34531
|
+
if (hasBattery && dev.batteryLevel === undefined) {
|
|
34532
|
+
dev.batteryLevel = 100;
|
|
34533
|
+
try {
|
|
34534
|
+
dev.onDeviceEvent(sdk_1.ScryptedInterface.Battery, 100);
|
|
34535
|
+
}
|
|
34536
|
+
catch { }
|
|
34537
|
+
}
|
|
34496
34538
|
}
|
|
34497
|
-
// 4)
|
|
34539
|
+
// 4) Rimuovi quelli spariti
|
|
34498
34540
|
const announced = new Set(manifests.map(m => m.nativeId));
|
|
34499
34541
|
for (const [nativeId] of this.devices) {
|
|
34500
34542
|
if (!announced.has(nativeId)) {
|
|
@@ -34515,7 +34557,13 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34515
34557
|
const clientId = this.storage.getItem('clientId') || 'scrypted-paradox';
|
|
34516
34558
|
const tls = this.storage.getItem('tls') === 'true';
|
|
34517
34559
|
const rejectUnauthorized = this.storage.getItem('rejectUnauthorized') !== 'false';
|
|
34518
|
-
const opts = {
|
|
34560
|
+
const opts = {
|
|
34561
|
+
clientId,
|
|
34562
|
+
username,
|
|
34563
|
+
password,
|
|
34564
|
+
clean: true,
|
|
34565
|
+
reconnectPeriod: 3000,
|
|
34566
|
+
};
|
|
34519
34567
|
if (tls) {
|
|
34520
34568
|
opts.protocol = 'mqtts';
|
|
34521
34569
|
opts.rejectUnauthorized = rejectUnauthorized;
|
|
@@ -34524,11 +34572,13 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34524
34572
|
}
|
|
34525
34573
|
collectAllSubscriptions() {
|
|
34526
34574
|
const subs = new Set();
|
|
34575
|
+
// alarm
|
|
34527
34576
|
for (const k of ['topicGetTarget', 'topicGetCurrent', 'topicTamper', 'topicOnline']) {
|
|
34528
34577
|
const v = this.storage.getItem(k);
|
|
34529
34578
|
if (v)
|
|
34530
34579
|
subs.add(v);
|
|
34531
34580
|
}
|
|
34581
|
+
// sensors
|
|
34532
34582
|
for (const s of this.sensorsCfg) {
|
|
34533
34583
|
const t = s.topics || {};
|
|
34534
34584
|
[t.contact, t.motion, t.occupancy, t.batteryLevel, t.lowBattery, t.tamper, t.online]
|
|
@@ -34547,13 +34597,13 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34547
34597
|
this.client.end(true);
|
|
34548
34598
|
}
|
|
34549
34599
|
catch { }
|
|
34550
|
-
;
|
|
34551
34600
|
this.client = undefined;
|
|
34552
34601
|
}
|
|
34553
34602
|
const { url, opts } = this.getMqttOptions();
|
|
34554
34603
|
this.console.log(`Connecting MQTT ${url} ...`);
|
|
34555
34604
|
const client = mqtt_1.default.connect(url, opts);
|
|
34556
34605
|
this.client = client;
|
|
34606
|
+
// cache alarm topics for fast compare
|
|
34557
34607
|
const tTarget = this.storage.getItem('topicGetTarget') || '';
|
|
34558
34608
|
const tCurrent = this.storage.getItem('topicGetCurrent') || '';
|
|
34559
34609
|
const tTamper = this.storage.getItem('topicTamper') || '';
|
|
@@ -34565,9 +34615,12 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34565
34615
|
this.onDeviceEvent(sdk_1.ScryptedInterface.Online, true);
|
|
34566
34616
|
}
|
|
34567
34617
|
catch { }
|
|
34568
|
-
if (subs.length)
|
|
34569
|
-
client.subscribe(subs, { qos: 0 }, (err) => {
|
|
34570
|
-
|
|
34618
|
+
if (subs.length) {
|
|
34619
|
+
client.subscribe(subs, { qos: 0 }, (err) => {
|
|
34620
|
+
if (err)
|
|
34621
|
+
this.console.error('subscribe error', err);
|
|
34622
|
+
});
|
|
34623
|
+
}
|
|
34571
34624
|
});
|
|
34572
34625
|
client.on('reconnect', () => this.console.log('MQTT reconnecting...'));
|
|
34573
34626
|
client.on('close', () => {
|
|
@@ -34583,6 +34636,7 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34583
34636
|
try {
|
|
34584
34637
|
const p = payload?.toString() ?? '';
|
|
34585
34638
|
const np = normalize(p);
|
|
34639
|
+
// ---- Alarm handling ----
|
|
34586
34640
|
if (topic === tOnline) {
|
|
34587
34641
|
if (truthy(np) || np === 'online') {
|
|
34588
34642
|
this.online = true;
|
|
@@ -34645,8 +34699,9 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34645
34699
|
return;
|
|
34646
34700
|
}
|
|
34647
34701
|
// ---- Sensor dispatch ----
|
|
34648
|
-
for (const dev of this.devices.values())
|
|
34702
|
+
for (const dev of this.devices.values()) {
|
|
34649
34703
|
dev.handleMqtt(topic, payload);
|
|
34704
|
+
}
|
|
34650
34705
|
}
|
|
34651
34706
|
catch (e) {
|
|
34652
34707
|
this.console.error('MQTT message handler error', e);
|
|
@@ -34668,10 +34723,25 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34668
34723
|
this.console.error('publish error', err);
|
|
34669
34724
|
});
|
|
34670
34725
|
}
|
|
34726
|
+
/** Sceglie il payload di publish rispettando override → strict tokens → default arm_* */
|
|
34727
|
+
getOutgoing(mode) {
|
|
34728
|
+
const overrides = {
|
|
34729
|
+
[sdk_1.SecuritySystemMode.Disarmed]: this.storage.getItem('payloadDisarm') || null,
|
|
34730
|
+
[sdk_1.SecuritySystemMode.HomeArmed]: this.storage.getItem('payloadHome') || null,
|
|
34731
|
+
[sdk_1.SecuritySystemMode.AwayArmed]: this.storage.getItem('payloadAway') || null,
|
|
34732
|
+
[sdk_1.SecuritySystemMode.NightArmed]: this.storage.getItem('payloadNight') || null,
|
|
34733
|
+
};
|
|
34734
|
+
const override = overrides[mode];
|
|
34735
|
+
if (override && override.trim().length)
|
|
34736
|
+
return override.trim();
|
|
34737
|
+
if (this.useStrict())
|
|
34738
|
+
return this.preferredTokenForMode(mode);
|
|
34739
|
+
return DEFAULT_OUTGOING[mode];
|
|
34740
|
+
}
|
|
34671
34741
|
async armSecuritySystem(mode) {
|
|
34672
34742
|
const payload = this.getOutgoing(mode);
|
|
34673
34743
|
this.console.log('armSecuritySystem', mode, '->', payload);
|
|
34674
|
-
this.pendingTarget = mode;
|
|
34744
|
+
this.pendingTarget = mode; // memorizza target, ma NON cambiare il current
|
|
34675
34745
|
this.publishSetTarget(payload);
|
|
34676
34746
|
}
|
|
34677
34747
|
async disarmSecuritySystem() {
|
|
@@ -34680,15 +34750,6 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34680
34750
|
this.pendingTarget = sdk_1.SecuritySystemMode.Disarmed;
|
|
34681
34751
|
this.publishSetTarget(payload);
|
|
34682
34752
|
}
|
|
34683
|
-
getOutgoing(mode) {
|
|
34684
|
-
const map = {
|
|
34685
|
-
[sdk_1.SecuritySystemMode.Disarmed]: this.storage.getItem('payloadDisarm') || DEFAULT_OUTGOING[sdk_1.SecuritySystemMode.Disarmed],
|
|
34686
|
-
[sdk_1.SecuritySystemMode.HomeArmed]: this.storage.getItem('payloadHome') || DEFAULT_OUTGOING[sdk_1.SecuritySystemMode.HomeArmed],
|
|
34687
|
-
[sdk_1.SecuritySystemMode.AwayArmed]: this.storage.getItem('payloadAway') || DEFAULT_OUTGOING[sdk_1.SecuritySystemMode.AwayArmed],
|
|
34688
|
-
[sdk_1.SecuritySystemMode.NightArmed]: this.storage.getItem('payloadNight') || DEFAULT_OUTGOING[sdk_1.SecuritySystemMode.NightArmed],
|
|
34689
|
-
};
|
|
34690
|
-
return map[mode];
|
|
34691
|
-
}
|
|
34692
34753
|
}
|
|
34693
34754
|
exports["default"] = ParadoxMqttSecuritySystem;
|
|
34694
34755
|
|
package/dist/plugin.zip
CHANGED
|
Binary file
|
package/package.json
CHANGED