@rfranzoi/scrypted-mqtt-securitysystem 1.0.38 → 1.0.40

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.
@@ -34029,7 +34029,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
34029
34029
  };
34030
34030
  Object.defineProperty(exports, "__esModule", ({ value: true }));
34031
34031
  // --- Preload: silenzia SOLO il warning facoltativo di sdk.json ---
34032
- // Copre console.error e console.warn (alcune versioni usano warn).
34033
34032
  (() => {
34034
34033
  const swallow = (orig) => (...args) => {
34035
34034
  const txt = args.map(a => typeof a === 'string' ? a : (a?.message || '')).join(' ');
@@ -34040,11 +34039,11 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
34040
34039
  console.error = swallow(console.error.bind(console));
34041
34040
  console.warn = swallow(console.warn.bind(console));
34042
34041
  })();
34043
- // Carica lo SDK (runtime only: niente import ESM per evitare che il bundler lo esegua prima del preload)
34042
+ // Carica lo SDK in runtime (evita ESM per garantire l’ordine col preload)
34044
34043
  const sdk = __webpack_require__(/*! @scrypted/sdk */ "./node_modules/@scrypted/sdk/dist/src/index.js");
34045
- // Valori runtime dal modulo SDK
34046
- const { ScryptedDeviceBase, ScryptedDeviceType, ScryptedInterface, // enum (valori)
34047
- SecuritySystemMode, // enum (valori)
34044
+ // Valori runtime (enum, classi, manager)
34045
+ const { ScryptedDeviceBase, ScryptedDeviceType, ScryptedInterface, // enum: valori
34046
+ SecuritySystemMode, // enum: valori
34048
34047
  systemManager, } = sdk;
34049
34048
  const mqtt_1 = __importDefault(__webpack_require__(/*! mqtt */ "./node_modules/mqtt/build/index.js"));
34050
34049
  /** utils */
@@ -34062,24 +34061,6 @@ function falsy(v) {
34062
34061
  }
34063
34062
  function normalize(s) { return (s || '').trim().toLowerCase(); }
34064
34063
  function clamp(n, min, max) { return Math.max(min, Math.min(max, n)); }
34065
- function deepEqual(a, b) {
34066
- try {
34067
- return JSON.stringify(a) === JSON.stringify(b);
34068
- }
34069
- catch {
34070
- return a === b;
34071
- }
34072
- }
34073
- /** Imposta una property e, se cambia, emette anche l'evento Scrypted corrispondente */
34074
- function setAndEmit(dev, key, value, iface) {
34075
- if (dev[key] === value)
34076
- return;
34077
- dev[key] = value;
34078
- try {
34079
- dev.onDeviceEvent?.(iface, value);
34080
- }
34081
- catch { }
34082
- }
34083
34064
  /** Outgoing predefiniti (PAI-like). Chiavi numeriche per compatibilità enum */
34084
34065
  const DEFAULT_OUTGOING = {
34085
34066
  [SecuritySystemMode.Disarmed]: 'disarm',
@@ -34112,145 +34093,46 @@ class BaseMqttSensor extends ScryptedDeviceBase {
34112
34093
  handleMqtt(topic, payload) {
34113
34094
  const p = payload?.toString() ?? '';
34114
34095
  const np = normalize(p);
34115
- // Online
34116
34096
  if (topic === this.cfg.topics.online) {
34117
34097
  if (truthy(np) || np === 'online')
34118
- setAndEmit(this, 'online', true, ScryptedInterface.Online);
34098
+ this.online = true;
34119
34099
  if (falsy(np) || np === 'offline')
34120
- setAndEmit(this, 'online', false, ScryptedInterface.Online);
34100
+ this.online = false;
34121
34101
  }
34122
- // Tamper
34123
34102
  if (topic === this.cfg.topics.tamper) {
34124
34103
  if (truthy(np) || ['tamper', 'intrusion', 'cover', 'motion', 'magnetic'].includes(np)) {
34125
- const t = ['cover', 'intrusion', 'motion', 'magnetic'].find(x => x === np) || true;
34126
- setAndEmit(this, 'tampered', t, ScryptedInterface.TamperSensor);
34104
+ this.tampered = ['cover', 'intrusion', 'motion', 'magnetic'].find(x => x === np) || true;
34127
34105
  }
34128
34106
  else if (falsy(np))
34129
- setAndEmit(this, 'tampered', false, ScryptedInterface.TamperSensor);
34107
+ this.tampered = false;
34130
34108
  }
34131
- // Battery
34132
34109
  if (topic === this.cfg.topics.batteryLevel) {
34133
34110
  const n = clamp(parseFloat(p), 0, 100);
34134
34111
  if (isFinite(n))
34135
- setAndEmit(this, 'batteryLevel', n, ScryptedInterface.Battery);
34112
+ this.batteryLevel = n;
34136
34113
  }
34137
34114
  else if (topic === this.cfg.topics.lowBattery && !this.cfg.topics.batteryLevel) {
34138
- const n = truthy(np) ? 10 : 100;
34139
- setAndEmit(this, 'batteryLevel', n, ScryptedInterface.Battery);
34115
+ this.batteryLevel = truthy(np) ? 10 : 100;
34140
34116
  }
34141
- // Primary
34142
34117
  this.handlePrimary(topic, np, p);
34143
34118
  }
34144
34119
  }
34145
- /** === SENSORI CON PARSING ROBUSTO + EMISSIONE EVENTI === */
34146
34120
  class ContactMqttSensor extends BaseMqttSensor {
34147
- handlePrimary(topic, np, raw) {
34148
- if (topic !== this.cfg.topics.contact)
34149
- return;
34150
- let val;
34151
- // stringhe comuni
34152
- if (['open', 'opened', '1', 'true', 'on', 'yes'].includes(np))
34153
- val = true;
34154
- else if (['closed', 'close', '0', 'false', 'off', 'no', 'shut'].includes(np))
34155
- val = false;
34156
- // JSON comuni
34157
- if (val === undefined) {
34158
- try {
34159
- const j = JSON.parse(raw);
34160
- if (typeof j?.open === 'boolean')
34161
- val = !!j.open;
34162
- else if (typeof j?.opened === 'boolean')
34163
- val = !!j.opened;
34164
- else if (typeof j?.contact === 'boolean')
34165
- val = !j.contact; // contact:false => OPEN
34166
- else if (typeof j?.state === 'string') {
34167
- const s = String(j.state).toLowerCase();
34168
- if (s === 'open')
34169
- val = true;
34170
- if (s === 'closed')
34171
- val = false;
34172
- }
34173
- }
34174
- catch { }
34175
- }
34176
- if (val !== undefined) {
34177
- setAndEmit(this, 'entryOpen', val, ScryptedInterface.EntrySensor);
34178
- }
34179
- else {
34180
- this.console?.debug?.(`Contact payload non gestito (${this.cfg.id}): "${raw}"`);
34181
- }
34121
+ handlePrimary(topic, np) {
34122
+ if (topic === this.cfg.topics.contact)
34123
+ this.entryOpen = truthy(np);
34182
34124
  }
34183
34125
  }
34184
34126
  class MotionMqttSensor extends BaseMqttSensor {
34185
- handlePrimary(topic, np, raw) {
34186
- if (topic !== this.cfg.topics.motion)
34187
- return;
34188
- let val;
34189
- if (['motion', 'detected', 'active', '1', 'true', 'on', 'yes'].includes(np))
34190
- val = true;
34191
- else if (['clear', 'inactive', 'no_motion', 'none', '0', 'false', 'off', 'no'].includes(np))
34192
- val = false;
34193
- if (val === undefined) {
34194
- try {
34195
- const j = JSON.parse(raw);
34196
- if (typeof j?.motion === 'boolean')
34197
- val = !!j.motion;
34198
- else if (typeof j?.occupancy === 'boolean')
34199
- val = !!j.occupancy;
34200
- else if (typeof j?.presence === 'boolean')
34201
- val = !!j.presence;
34202
- else if (typeof j?.state === 'string') {
34203
- const s = String(j.state).toLowerCase();
34204
- if (['on', 'motion', 'detected', 'active'].includes(s))
34205
- val = true;
34206
- if (['off', 'clear', 'inactive'].includes(s))
34207
- val = false;
34208
- }
34209
- }
34210
- catch { }
34211
- }
34212
- if (val !== undefined) {
34213
- setAndEmit(this, 'motionDetected', val, ScryptedInterface.MotionSensor);
34214
- }
34215
- else {
34216
- this.console?.debug?.(`Motion payload non gestito (${this.cfg.id}): "${raw}"`);
34217
- }
34127
+ handlePrimary(topic, np) {
34128
+ if (topic === this.cfg.topics.motion)
34129
+ this.motionDetected = truthy(np);
34218
34130
  }
34219
34131
  }
34220
34132
  class OccupancyMqttSensor extends BaseMqttSensor {
34221
- handlePrimary(topic, np, raw) {
34222
- if (topic !== this.cfg.topics.occupancy)
34223
- return;
34224
- let val;
34225
- if (['occupied', 'presence', 'present', '1', 'true', 'on', 'yes'].includes(np))
34226
- val = true;
34227
- else if (['unoccupied', 'vacant', 'absent', '0', 'false', 'off', 'no', 'clear'].includes(np))
34228
- val = false;
34229
- if (val === undefined) {
34230
- try {
34231
- const j = JSON.parse(raw);
34232
- if (typeof j?.occupied === 'boolean')
34233
- val = !!j.occupied;
34234
- else if (typeof j?.presence === 'boolean')
34235
- val = !!j.presence;
34236
- else if (typeof j?.occupancy === 'boolean')
34237
- val = !!j.occupancy;
34238
- else if (typeof j?.state === 'string') {
34239
- const s = String(j.state).toLowerCase();
34240
- if (['occupied', 'presence', 'present', 'on'].includes(s))
34241
- val = true;
34242
- if (['vacant', 'absent', 'clear', 'off'].includes(s))
34243
- val = false;
34244
- }
34245
- }
34246
- catch { }
34247
- }
34248
- if (val !== undefined) {
34249
- setAndEmit(this, 'occupied', val, ScryptedInterface.OccupancySensor);
34250
- }
34251
- else {
34252
- this.console?.debug?.(`Occupancy payload non gestito (${this.cfg.id}): "${raw}"`);
34253
- }
34133
+ handlePrimary(topic, np) {
34134
+ if (topic === this.cfg.topics.occupancy)
34135
+ this.occupied = truthy(np);
34254
34136
  }
34255
34137
  }
34256
34138
  /** ----------------- Main Plugin ----------------- */
@@ -34259,8 +34141,7 @@ class ParadoxMqttSecuritySystem extends ScryptedDeviceBase {
34259
34141
  super();
34260
34142
  this.sensorsCfg = [];
34261
34143
  this.devices = new Map();
34262
- // Evita loop di log: tenta una volta finché deviceManager non c’è, poi riprova su eventi utili.
34263
- this.discoveryPostponed = false;
34144
+ this.triedDiscoveryOnce = false;
34264
34145
  // Tipo in UI (best-effort)
34265
34146
  setTimeout(() => {
34266
34147
  try {
@@ -34279,7 +34160,7 @@ class ParadoxMqttSecuritySystem extends ScryptedDeviceBase {
34279
34160
  ],
34280
34161
  };
34281
34162
  this.online = this.online ?? false;
34282
- // Config sensori e (tentativo) announce
34163
+ // Config sensori e announce
34283
34164
  this.loadSensorsFromStorage();
34284
34165
  this.safeDiscoverSensors(); // non spamma se deviceManager non c'è
34285
34166
  // Connect MQTT
@@ -34325,13 +34206,17 @@ class ParadoxMqttSecuritySystem extends ScryptedDeviceBase {
34325
34206
  { group: 'Alarm Topics', key: 'topicOnline', title: 'Get Online (subscribe)', placeholder: 'paradox/interface/availability', value: this.storage.getItem('topicOnline') || '' },
34326
34207
  { group: 'Publish Options', key: 'qos', title: 'QoS', type: 'integer', value: parseInt(this.storage.getItem('qos') || '0') },
34327
34208
  { group: 'Publish Options', key: 'retain', title: 'Retain', type: 'boolean', value: this.storage.getItem('retain') === 'true' },
34209
+ // ---- Danger Zone ----
34210
+ { group: 'Danger Zone', key: 'danger.resetSensors', title: 'Reset all sensors (wipe)', type: 'boolean', description: 'Cancella tutti i sensori salvati e rimuove i device annunciati.' },
34211
+ { group: 'Danger Zone', key: 'danger.export', title: 'Export sensors JSON (read-only)', value: JSON.stringify(this.sensorsCfg, null, 2), readonly: true },
34212
+ { group: 'Danger Zone', key: 'danger.import', title: 'Import sensors JSON (paste & Save)', type: 'string', placeholder: '[]', description: 'Incolla JSON valido per sovrascrivere l’elenco sensori.' },
34328
34213
  ];
34329
- // Add Sensor
34330
- 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: 'Toggle ON to create the sensor.' });
34331
- // Sensors esistenti
34214
+ // ---- Add Sensor
34215
+ out.push({ group: 'Add Sensor', key: 'new.id', title: 'New Sensor ID', placeholder: 'porta-sogg', value: this.storage.getItem('new.id') || '' }, { group: 'Add Sensor', key: 'new.name', title: 'Name', placeholder: 'Porta Soggiorno', 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: 'Toggle ON e Save per creare.' });
34216
+ // ---- Sensors esistenti
34332
34217
  for (const cfg of this.sensorsCfg) {
34333
34218
  const gid = `Sensor: ${cfg.name} [${cfg.id}]`;
34334
- 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'] });
34219
+ out.push({ group: gid, key: `sensor.${cfg.id}.id`, title: 'ID (read-only)', value: cfg.id, readonly: true, description: 'L’ID identifica il device. Evita spazi/puntini.' }, { 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'] }, { group: gid, key: `sensor.${cfg.id}.renameTo`, title: 'Clone/Rename → New ID', placeholder: 'es. porta-sogg', description: 'Compila e Save per clonare con nuovo ID e rimuovere il vecchio.' });
34335
34220
  if (cfg.kind === 'contact')
34336
34221
  out.push({ group: gid, key: `sensor.${cfg.id}.topic.contact`, title: 'Contact State Topic', value: cfg.topics.contact || '' });
34337
34222
  else if (cfg.kind === 'motion')
@@ -34344,6 +34229,46 @@ class ParadoxMqttSecuritySystem extends ScryptedDeviceBase {
34344
34229
  }
34345
34230
  async putSetting(key, value) {
34346
34231
  this.storage.setItem(key, String(value));
34232
+ // ---- Danger Zone: reset all ----
34233
+ if (key === 'danger.resetSensors' && String(value) === 'true') {
34234
+ this.storage.removeItem('danger.resetSensors');
34235
+ // rimuovi device annunciati
34236
+ try {
34237
+ const dm = sdk?.deviceManager;
34238
+ for (const nativeId of Array.from(this.devices.keys())) {
34239
+ try {
34240
+ dm?.onDeviceRemoved?.(nativeId);
34241
+ }
34242
+ catch { }
34243
+ }
34244
+ }
34245
+ catch { }
34246
+ this.devices.clear();
34247
+ this.sensorsCfg = [];
34248
+ this.saveSensorsToStorage();
34249
+ this.safeDiscoverSensors(true);
34250
+ await this.connectMqtt(true);
34251
+ return;
34252
+ }
34253
+ // ---- Danger Zone: import JSON ----
34254
+ if (key === 'danger.import') {
34255
+ try {
34256
+ const parsed = JSON.parse(String(value) || '[]');
34257
+ if (!Array.isArray(parsed))
34258
+ throw new Error('JSON non è un array.');
34259
+ // sanifica
34260
+ this.sensorsCfg = (parsed || []).filter(x => x && x.id && x.name && x.kind && x.topics);
34261
+ this.saveSensorsToStorage();
34262
+ this.storage.removeItem('danger.import');
34263
+ this.safeDiscoverSensors(true);
34264
+ await this.connectMqtt(true);
34265
+ }
34266
+ catch (e) {
34267
+ this.console.error('Import JSON error:', e);
34268
+ }
34269
+ return;
34270
+ }
34271
+ // ---- Add Sensor ----
34347
34272
  if (key === 'new.create' && String(value) === 'true') {
34348
34273
  const id = (this.storage.getItem('new.id') || '').trim();
34349
34274
  const name = (this.storage.getItem('new.name') || '').trim() || id;
@@ -34366,6 +34291,7 @@ class ParadoxMqttSecuritySystem extends ScryptedDeviceBase {
34366
34291
  await this.connectMqtt(true);
34367
34292
  return;
34368
34293
  }
34294
+ // ---- Edit/Remove/Rename sensore ----
34369
34295
  const m = key.match(/^sensor\.([^\.]+)\.(.+)$/);
34370
34296
  if (m) {
34371
34297
  const sid = m[1];
@@ -34375,6 +34301,30 @@ class ParadoxMqttSecuritySystem extends ScryptedDeviceBase {
34375
34301
  this.console.warn('putSetting: sensor non trovato', sid);
34376
34302
  return;
34377
34303
  }
34304
+ // rename/clone
34305
+ if (prop === 'renameTo') {
34306
+ const newId = String(value).trim();
34307
+ this.storage.removeItem(key);
34308
+ if (!newId)
34309
+ return;
34310
+ if (this.sensorsCfg.find(s => s.id === newId)) {
34311
+ this.console.warn('renameTo: ID già esistente:', newId);
34312
+ return;
34313
+ }
34314
+ const cloned = { ...cfg, id: newId, name: cfg.name };
34315
+ this.sensorsCfg.push(cloned);
34316
+ // rimuovi vecchio
34317
+ this.sensorsCfg = this.sensorsCfg.filter(s => s !== cfg);
34318
+ try {
34319
+ sdk?.deviceManager?.onDeviceRemoved?.(`sensor:${sid}`);
34320
+ }
34321
+ catch { }
34322
+ this.saveSensorsToStorage();
34323
+ this.safeDiscoverSensors(true);
34324
+ await this.connectMqtt(true);
34325
+ return;
34326
+ }
34327
+ // remove
34378
34328
  if (prop === 'remove' && String(value) === 'true') {
34379
34329
  this.sensorsCfg = this.sensorsCfg.filter(s => s.id !== sid);
34380
34330
  this.saveSensorsToStorage();
@@ -34387,6 +34337,7 @@ class ParadoxMqttSecuritySystem extends ScryptedDeviceBase {
34387
34337
  await this.connectMqtt(true);
34388
34338
  return;
34389
34339
  }
34340
+ // edit
34390
34341
  if (prop === 'name')
34391
34342
  cfg.name = String(value);
34392
34343
  else if (prop === 'kind')
@@ -34400,6 +34351,7 @@ class ParadoxMqttSecuritySystem extends ScryptedDeviceBase {
34400
34351
  await this.connectMqtt(true);
34401
34352
  return;
34402
34353
  }
34354
+ // Altre impostazioni: riconnetti
34403
34355
  if (key === 'sensorsJson') {
34404
34356
  this.loadSensorsFromStorage();
34405
34357
  this.safeDiscoverSensors(true);
@@ -34436,21 +34388,18 @@ class ParadoxMqttSecuritySystem extends ScryptedDeviceBase {
34436
34388
  this.sensorsCfg = [];
34437
34389
  }
34438
34390
  }
34439
- /** Annuncia i sensori SOLO se deviceManager è pronto. Niente loop infinito. */
34391
+ /** Annuncia i sensori SOLO se deviceManager è pronto. */
34440
34392
  safeDiscoverSensors(triggeredByChange = false) {
34441
34393
  const dmAny = sdk?.deviceManager;
34442
34394
  if (!dmAny) {
34443
- // Posticipa una sola volta; poi riproviamo su connect MQTT e al primo messaggio
34444
- if (!this.discoveryPostponed) {
34395
+ if (!this.triedDiscoveryOnce) {
34445
34396
  this.console.log('Device discovery postponed: deviceManager not ready yet.');
34446
- this.discoveryPostponed = true;
34397
+ this.triedDiscoveryOnce = true;
34447
34398
  }
34448
34399
  return;
34449
34400
  }
34450
- this.discoveryPostponed = false;
34401
+ this.triedDiscoveryOnce = false;
34451
34402
  this.discoverSensors(dmAny);
34452
- if (triggeredByChange)
34453
- this.console.log('Sensors discovered/updated.');
34454
34403
  }
34455
34404
  /** discoverSensors con deviceManager garantito */
34456
34405
  discoverSensors(dmAny) {
@@ -34497,7 +34446,7 @@ class ParadoxMqttSecuritySystem extends ScryptedDeviceBase {
34497
34446
  }
34498
34447
  const hasBattery = !!(cfg.topics.batteryLevel || cfg.topics.lowBattery);
34499
34448
  if (hasBattery && dev.batteryLevel === undefined)
34500
- setAndEmit(dev, 'batteryLevel', 100, ScryptedInterface.Battery);
34449
+ dev.batteryLevel = 100;
34501
34450
  }
34502
34451
  // 4) Cleanup
34503
34452
  const announced = new Set(manifests.map(m => m.nativeId));
@@ -34562,15 +34511,15 @@ class ParadoxMqttSecuritySystem extends ScryptedDeviceBase {
34562
34511
  const tOnline = this.storage.getItem('topicOnline') || '';
34563
34512
  client.on('connect', () => {
34564
34513
  this.console.log('MQTT connected');
34565
- setAndEmit(this, 'online', true, ScryptedInterface.Online);
34514
+ this.online = true;
34566
34515
  if (subs.length)
34567
34516
  client.subscribe(subs, { qos: 0 }, (err) => { if (err)
34568
34517
  this.console.error('subscribe error', err); });
34569
- // Al primo connect riprova (silenziosamente) ad annunciare i sensori
34518
+ // Al primo connect riprova ad annunciare i sensori
34570
34519
  this.safeDiscoverSensors(true);
34571
34520
  });
34572
34521
  client.on('reconnect', () => this.console.log('MQTT reconnecting...'));
34573
- client.on('close', () => { this.console.log('MQTT closed'); setAndEmit(this, 'online', false, ScryptedInterface.Online); });
34522
+ client.on('close', () => { this.console.log('MQTT closed'); this.online = false; });
34574
34523
  client.on('error', (e) => { this.console.error('MQTT error', e); });
34575
34524
  client.on('message', (topic, payload) => {
34576
34525
  try {
@@ -34578,26 +34527,23 @@ class ParadoxMqttSecuritySystem extends ScryptedDeviceBase {
34578
34527
  const np = normalize(p);
34579
34528
  if (topic === tOnline) {
34580
34529
  if (truthy(np) || np === 'online')
34581
- setAndEmit(this, 'online', true, ScryptedInterface.Online);
34530
+ this.online = true;
34582
34531
  if (falsy(np) || np === 'offline')
34583
- setAndEmit(this, 'online', false, ScryptedInterface.Online);
34532
+ this.online = false;
34584
34533
  return;
34585
34534
  }
34586
34535
  if (topic === tTamper) {
34587
- if (truthy(np) || ['tamper', 'intrusion', 'cover'].includes(np)) {
34588
- const t = ['cover', 'intrusion'].find(x => x === np) || true;
34589
- setAndEmit(this, 'tampered', t, ScryptedInterface.TamperSensor);
34590
- }
34591
- else if (falsy(np)) {
34592
- setAndEmit(this, 'tampered', false, ScryptedInterface.TamperSensor);
34593
- }
34536
+ if (truthy(np) || ['tamper', 'intrusion', 'cover'].includes(np))
34537
+ this.tampered = ['cover', 'intrusion'].find(x => x === np) || true;
34538
+ else if (falsy(np))
34539
+ this.tampered = false;
34594
34540
  return;
34595
34541
  }
34596
34542
  if (topic === tCurrent) {
34597
34543
  const mode = payloadToMode(payload);
34598
34544
  const isAlarm = ['alarm', 'triggered'].includes(np);
34599
34545
  const current = this.securitySystemState || { mode: SecuritySystemMode.Disarmed };
34600
- const newState = {
34546
+ this.securitySystemState = {
34601
34547
  mode: mode ?? current.mode,
34602
34548
  supportedModes: current.supportedModes ?? [
34603
34549
  SecuritySystemMode.Disarmed,
@@ -34607,13 +34553,6 @@ class ParadoxMqttSecuritySystem extends ScryptedDeviceBase {
34607
34553
  ],
34608
34554
  triggered: isAlarm || undefined,
34609
34555
  };
34610
- if (!deepEqual(this.securitySystemState, newState)) {
34611
- this.securitySystemState = newState;
34612
- try {
34613
- this.onDeviceEvent?.(ScryptedInterface.SecuritySystem, newState);
34614
- }
34615
- catch { }
34616
- }
34617
34556
  return;
34618
34557
  }
34619
34558
  if (topic === tTarget) {
@@ -34621,9 +34560,8 @@ class ParadoxMqttSecuritySystem extends ScryptedDeviceBase {
34621
34560
  this.console.log('Target state reported:', p, '->', this.pendingTarget);
34622
34561
  return;
34623
34562
  }
34624
- // Dispatch ai sensori
34625
- // (E prova ad annunciare se era stato posticipato e ora il manager è pronto)
34626
- if (this.discoveryPostponed)
34563
+ // Dispatch ai sensori + eventuale discover ritardato
34564
+ if (this.triedDiscoveryOnce)
34627
34565
  this.safeDiscoverSensors(true);
34628
34566
  for (const dev of this.devices.values())
34629
34567
  dev.handleMqtt(topic, payload);
package/dist/plugin.zip CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rfranzoi/scrypted-mqtt-securitysystem",
3
- "version": "1.0.38",
3
+ "version": "1.0.40",
4
4
  "description": "Scrypted plugin: Paradox Security System via MQTT (PAI/PAI-MQTT style).",
5
5
  "license": "MIT",
6
6
  "main": "dist/main.nodejs.js",