@rfranzoi/scrypted-mqtt-securitysystem 1.0.49 → 1.0.52

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.
@@ -34064,6 +34064,15 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
34064
34064
  const sdk_1 = __importStar(__webpack_require__(/*! @scrypted/sdk */ "./node_modules/@scrypted/sdk/dist/src/index.js"));
34065
34065
  const mqtt_1 = __importDefault(__webpack_require__(/*! mqtt */ "./node_modules/mqtt/build/index.js"));
34066
34066
  const { systemManager, deviceManager } = sdk_1.default;
34067
+ /** ---------- RUNTIME FLAGS (aggiornati da Settings) ---------- */
34068
+ const RUNTIME = {
34069
+ logSensors: false,
34070
+ logMqttAll: false,
34071
+ };
34072
+ function updateRuntimeFromStorage(get) {
34073
+ RUNTIME.logSensors = (get('logSensors') || '') === 'true';
34074
+ RUNTIME.logMqttAll = (get('logMqttAll') || '') === 'true';
34075
+ }
34067
34076
  /** utils */
34068
34077
  function truthy(v) {
34069
34078
  if (!v)
@@ -34077,12 +34086,8 @@ function falsy(v) {
34077
34086
  const s = v.toString().trim().toLowerCase();
34078
34087
  return s === '0' || s === 'false' || s === 'offline' || s === 'no' || s === 'off';
34079
34088
  }
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
- }
34089
+ function normalize(s) { return (s || '').trim().toLowerCase(); }
34090
+ function clamp(n, min, max) { return Math.max(min, Math.min(max, n)); }
34086
34091
  /** SecuritySystem outgoing defaults (PAI-like) */
34087
34092
  const DEFAULT_OUTGOING = {
34088
34093
  [sdk_1.SecuritySystemMode.Disarmed]: 'disarm',
@@ -34090,7 +34095,7 @@ const DEFAULT_OUTGOING = {
34090
34095
  [sdk_1.SecuritySystemMode.AwayArmed]: 'arm_away',
34091
34096
  [sdk_1.SecuritySystemMode.NightArmed]: 'arm_night',
34092
34097
  };
34093
- /** Fallback (non-strict) parser con sinonimi */
34098
+ /** Parser loose con sinonimi (usato se strict=OFF) */
34094
34099
  function payloadToModeLoose(payload) {
34095
34100
  if (payload == null)
34096
34101
  return;
@@ -34112,8 +34117,8 @@ class BaseMqttSensor extends sdk_1.ScryptedDeviceBase {
34112
34117
  super(nativeId);
34113
34118
  this.cfg = cfg;
34114
34119
  }
34115
- /** setter centralizzato + evento */
34116
- setAndEmit(prop, val, iface) {
34120
+ /** setter centralizzato + evento + (log opzionale) */
34121
+ setAndEmit(prop, val, iface, logContext) {
34117
34122
  const prev = this[prop];
34118
34123
  if (prev === val)
34119
34124
  return;
@@ -34124,6 +34129,11 @@ class BaseMqttSensor extends sdk_1.ScryptedDeviceBase {
34124
34129
  catch (e) {
34125
34130
  this.console?.warn?.('onDeviceEvent error', iface, e);
34126
34131
  }
34132
+ if (RUNTIME.logSensors) {
34133
+ const label = logContext?.propLabel || prop;
34134
+ const extra = logContext?.topic ? ` (${logContext.topic}="${logContext.raw ?? ''}")` : '';
34135
+ this.console?.log?.(`[Sensor] ${this.cfg.name} [${this.cfg.id}] ${label} -> ${JSON.stringify(val)}${extra}`);
34136
+ }
34127
34137
  }
34128
34138
  /** Called by parent on each MQTT message */
34129
34139
  handleMqtt(topic, payload) {
@@ -34132,76 +34142,58 @@ class BaseMqttSensor extends sdk_1.ScryptedDeviceBase {
34132
34142
  // online
34133
34143
  if (topic === this.cfg.topics.online) {
34134
34144
  if (truthy(np) || np === 'online')
34135
- this.setAndEmit('online', true, sdk_1.ScryptedInterface.Online);
34145
+ this.setAndEmit('online', true, sdk_1.ScryptedInterface.Online, { topic, raw, propLabel: 'online' });
34136
34146
  if (falsy(np) || np === 'offline')
34137
- this.setAndEmit('online', false, sdk_1.ScryptedInterface.Online);
34147
+ this.setAndEmit('online', false, sdk_1.ScryptedInterface.Online, { topic, raw, propLabel: 'online' });
34138
34148
  }
34139
34149
  // tamper
34140
34150
  if (topic === this.cfg.topics.tamper) {
34141
34151
  if (truthy(np) || ['tamper', 'intrusion', 'cover', 'motion', 'magnetic'].includes(np)) {
34142
34152
  const value = ['cover', 'intrusion', 'motion', 'magnetic'].find(x => x === np) || true;
34143
- this.setAndEmit('tampered', value, sdk_1.ScryptedInterface.TamperSensor);
34153
+ this.setAndEmit('tampered', value, sdk_1.ScryptedInterface.TamperSensor, { topic, raw, propLabel: 'tampered' });
34144
34154
  }
34145
34155
  else if (falsy(np)) {
34146
- this.setAndEmit('tampered', false, sdk_1.ScryptedInterface.TamperSensor);
34156
+ this.setAndEmit('tampered', false, sdk_1.ScryptedInterface.TamperSensor, { topic, raw, propLabel: 'tampered' });
34147
34157
  }
34148
34158
  }
34149
34159
  // battery
34150
34160
  if (topic === this.cfg.topics.batteryLevel) {
34151
34161
  const n = clamp(parseFloat(raw), 0, 100);
34152
34162
  if (Number.isFinite(n))
34153
- this.setAndEmit('batteryLevel', n, sdk_1.ScryptedInterface.Battery);
34163
+ this.setAndEmit('batteryLevel', n, sdk_1.ScryptedInterface.Battery, { topic, raw, propLabel: 'batteryLevel' });
34154
34164
  }
34155
34165
  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)
34166
+ // solo se abbiamo lowBattery (bool) ma NON batteryLevel
34157
34167
  if (truthy(np))
34158
- this.setAndEmit('batteryLevel', 10, sdk_1.ScryptedInterface.Battery);
34168
+ this.setAndEmit('batteryLevel', 10, sdk_1.ScryptedInterface.Battery, { topic, raw, propLabel: 'batteryLevel (low)' });
34159
34169
  else if (falsy(np) && this.batteryLevel === undefined)
34160
- this.setAndEmit('batteryLevel', 100, sdk_1.ScryptedInterface.Battery);
34170
+ this.setAndEmit('batteryLevel', 100, sdk_1.ScryptedInterface.Battery, { topic, raw, propLabel: 'batteryLevel (ok)' });
34161
34171
  }
34162
34172
  // primary handled by subclasses
34163
34173
  this.handlePrimary(topic, np, raw);
34164
34174
  }
34165
34175
  }
34166
34176
  class ContactMqttSensor extends BaseMqttSensor {
34167
- handlePrimary(topic, np) {
34177
+ handlePrimary(topic, np, raw) {
34168
34178
  if (topic === this.cfg.topics.contact) {
34169
34179
  const v = truthy(np);
34170
- this.setAndEmit?.('entryOpen', v, sdk_1.ScryptedInterface.EntrySensor);
34171
- if (this.setAndEmit === undefined) {
34172
- if (this.entryOpen !== v) {
34173
- this.entryOpen = v;
34174
- this.onDeviceEvent(sdk_1.ScryptedInterface.EntrySensor, v);
34175
- }
34176
- }
34180
+ this.setAndEmit('entryOpen', v, sdk_1.ScryptedInterface.EntrySensor, { topic, raw, propLabel: 'entryOpen' });
34177
34181
  }
34178
34182
  }
34179
34183
  }
34180
34184
  class MotionMqttSensor extends BaseMqttSensor {
34181
- handlePrimary(topic, np) {
34185
+ handlePrimary(topic, np, raw) {
34182
34186
  if (topic === this.cfg.topics.motion) {
34183
34187
  const v = truthy(np);
34184
- this.setAndEmit?.('motionDetected', v, sdk_1.ScryptedInterface.MotionSensor);
34185
- if (this.setAndEmit === undefined) {
34186
- if (this.motionDetected !== v) {
34187
- this.motionDetected = v;
34188
- this.onDeviceEvent(sdk_1.ScryptedInterface.MotionSensor, v);
34189
- }
34190
- }
34188
+ this.setAndEmit('motionDetected', v, sdk_1.ScryptedInterface.MotionSensor, { topic, raw, propLabel: 'motionDetected' });
34191
34189
  }
34192
34190
  }
34193
34191
  }
34194
34192
  class OccupancyMqttSensor extends BaseMqttSensor {
34195
- handlePrimary(topic, np) {
34193
+ handlePrimary(topic, np, raw) {
34196
34194
  if (topic === this.cfg.topics.occupancy) {
34197
34195
  const v = truthy(np);
34198
- this.setAndEmit?.('occupied', v, sdk_1.ScryptedInterface.OccupancySensor);
34199
- if (this.setAndEmit === undefined) {
34200
- if (this.occupied !== v) {
34201
- this.occupied = v;
34202
- this.onDeviceEvent(sdk_1.ScryptedInterface.OccupancySensor, v);
34203
- }
34204
- }
34196
+ this.setAndEmit('occupied', v, sdk_1.ScryptedInterface.OccupancySensor, { topic, raw, propLabel: 'occupied' });
34205
34197
  }
34206
34198
  }
34207
34199
  }
@@ -34212,6 +34204,8 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34212
34204
  // sensor management
34213
34205
  this.sensorsCfg = [];
34214
34206
  this.devices = new Map();
34207
+ // carica flag runtime
34208
+ updateRuntimeFromStorage((k) => this.storage.getItem(k) || '');
34215
34209
  // (facoltativo) Imposta il device type in UI
34216
34210
  setTimeout(() => {
34217
34211
  try {
@@ -34292,19 +34286,15 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34292
34286
  }
34293
34287
  return np === 'triggered' || np === 'alarm';
34294
34288
  }
34295
- /** Sceglie il token di publish preferito per ciascuna modalità usando targetStateValues quando strict=ON */
34289
+ /** Token di publish preferito (strict=ON usa targetStateValues) */
34296
34290
  preferredTokenForMode(mode) {
34297
34291
  const t = this.parseJsonArray('targetStateValues', ['armed_home', 'armed_away', 'armed_night', 'disarmed']);
34298
34292
  const pick = (...cands) => cands.find(c => t.includes(c));
34299
34293
  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';
34294
+ case sdk_1.SecuritySystemMode.Disarmed: return pick('disarmed', 'disarm') || 'disarmed';
34295
+ case sdk_1.SecuritySystemMode.HomeArmed: return pick('armed_home', 'arm_home', 'home', 'stay') || 'armed_home';
34296
+ case sdk_1.SecuritySystemMode.AwayArmed: return pick('armed_away', 'arm_away', 'away') || 'armed_away';
34297
+ case sdk_1.SecuritySystemMode.NightArmed: return pick('armed_night', 'arm_night', 'night', 'sleep') || 'armed_night';
34308
34298
  }
34309
34299
  }
34310
34300
  // helpers persistenza
@@ -34340,10 +34330,13 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34340
34330
  { 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"]' },
34341
34331
  { group: 'Parsing / State tokens', key: 'triggeredValues', title: 'Triggered tokens (JSON array)', placeholder: '["triggered","alarm"]', value: this.storage.getItem('triggeredValues') || '["triggered","alarm"]' },
34342
34332
  // --- 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).' },
34333
+ { group: 'Publish Payloads (override)', key: 'payloadDisarm', title: 'Payload for Disarm', placeholder: 'disarmed', value: this.storage.getItem('payloadDisarm') || '', description: 'If empty, use targetStateValues (strict ON) or the arm_*/disarm defaults (strict OFF).' },
34344
34334
  { group: 'Publish Payloads (override)', key: 'payloadHome', title: 'Payload for Home Armed', placeholder: 'armed_home', value: this.storage.getItem('payloadHome') || '' },
34345
34335
  { group: 'Publish Payloads (override)', key: 'payloadAway', title: 'Payload for Away Armed', placeholder: 'armed_away', value: this.storage.getItem('payloadAway') || '' },
34346
34336
  { group: 'Publish Payloads (override)', key: 'payloadNight', title: 'Payload for Night Armed', placeholder: 'armed_night', value: this.storage.getItem('payloadNight') || '' },
34337
+ // --- Logging ---
34338
+ { group: 'Logging', key: 'logSensors', title: 'Log sensor state changes', type: 'boolean', value: this.storage.getItem('logSensors') === 'true' },
34339
+ { group: 'Logging', key: 'logMqttAll', title: 'Log ALL MQTT messages', type: 'boolean', value: this.storage.getItem('logMqttAll') === 'true', description: 'Warning: this will be very verbose.' },
34347
34340
  ];
34348
34341
  // ---- UI Add Sensor ----
34349
34342
  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.' });
@@ -34351,17 +34344,12 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34351
34344
  for (const cfg of this.sensorsCfg) {
34352
34345
  const gid = `Sensor: ${cfg.name} [${cfg.id}]`;
34353
34346
  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
34355
- if (cfg.kind === 'contact') {
34347
+ if (cfg.kind === 'contact')
34356
34348
  out.push({ group: gid, key: `sensor.${cfg.id}.topic.contact`, title: 'Contact State Topic', value: cfg.topics.contact || '', placeholder: 'paradox/states/zones/XYZ/open' });
34357
- }
34358
- else if (cfg.kind === 'motion') {
34349
+ else if (cfg.kind === 'motion')
34359
34350
  out.push({ group: gid, key: `sensor.${cfg.id}.topic.motion`, title: 'Motion Detected Topic', value: cfg.topics.motion || '', placeholder: 'paradox/states/zones/XYZ/open' });
34360
- }
34361
- else {
34351
+ else
34362
34352
  out.push({ group: gid, key: `sensor.${cfg.id}.topic.occupancy`, title: 'Occupancy Detected Topic', value: cfg.topics.occupancy || '', placeholder: 'paradox/states/zones/XYZ/open' });
34363
- }
34364
- // extra opzionali
34365
34353
  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' });
34366
34354
  }
34367
34355
  return out;
@@ -34369,6 +34357,8 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34369
34357
  async putSetting(key, value) {
34370
34358
  // salva sempre nella storage la value del campo (così resta in UI)
34371
34359
  this.storage.setItem(key, String(value));
34360
+ // aggiorna i flag runtime ogni volta
34361
+ updateRuntimeFromStorage((k) => this.storage.getItem(k) || '');
34372
34362
  // --- Add Sensor workflow ---
34373
34363
  if (key === 'new.create' && String(value) === 'true') {
34374
34364
  const id = (this.storage.getItem('new.id') || '').trim();
@@ -34384,7 +34374,7 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34384
34374
  }
34385
34375
  this.sensorsCfg.push({ id, name, kind, topics: {} });
34386
34376
  this.saveSensorsToStorage();
34387
- // pulisci i campi "new.*"
34377
+ // pulizia campi "new.*"
34388
34378
  this.storage.removeItem('new.id');
34389
34379
  this.storage.removeItem('new.name');
34390
34380
  this.storage.removeItem('new.kind');
@@ -34418,12 +34408,10 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34418
34408
  await this.connectMqtt(true);
34419
34409
  return;
34420
34410
  }
34421
- if (prop === 'name') {
34411
+ if (prop === 'name')
34422
34412
  cfg.name = String(value);
34423
- }
34424
- else if (prop === 'kind') {
34413
+ else if (prop === 'kind')
34425
34414
  cfg.kind = String(value);
34426
- }
34427
34415
  else if (prop.startsWith('topic.')) {
34428
34416
  const tk = prop.substring('topic.'.length);
34429
34417
  cfg.topics[tk] = String(value).trim();
@@ -34433,9 +34421,8 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34433
34421
  await this.connectMqtt(true);
34434
34422
  return;
34435
34423
  }
34436
- // --- Altro (MQTT / Alarm settings / parsing / payloads) ---
34424
+ // --- Altro (MQTT / Alarm settings / parsing / payloads / logging) ---
34437
34425
  if (key === 'sensorsJson') {
34438
- // non più mostrato, ma se presente da vecchie versioni
34439
34426
  this.loadSensorsFromStorage();
34440
34427
  await this.discoverSensors();
34441
34428
  await this.connectMqtt(true);
@@ -34445,15 +34432,12 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34445
34432
  }
34446
34433
  }
34447
34434
  /** ---- DeviceProvider ---- */
34448
- async getDevice(nativeId) {
34449
- return this.devices.get(nativeId);
34450
- }
34435
+ async getDevice(nativeId) { return this.devices.get(nativeId); }
34451
34436
  async releaseDevice(_id, nativeId) {
34452
34437
  try {
34453
34438
  const dev = this.devices.get(nativeId);
34454
- if (dev) {
34439
+ if (dev)
34455
34440
  this.devices.delete(nativeId);
34456
- }
34457
34441
  try {
34458
34442
  deviceManager.onDeviceRemoved?.(nativeId);
34459
34443
  }
@@ -34477,28 +34461,25 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34477
34461
  }
34478
34462
  /** ===== discoverSensors: annuncia PRIMA, istanzia DOPO ===== */
34479
34463
  async discoverSensors() {
34480
- // 1) Prepara i manifest (niente istanze qui)
34464
+ // 1) manifest
34481
34465
  const manifests = this.sensorsCfg.map(cfg => {
34482
34466
  const nativeId = `sensor:${cfg.id}`;
34483
34467
  const t = cfg.topics || {};
34484
34468
  const interfaces = [sdk_1.ScryptedInterface.Online];
34485
- // Tamper solo se c'è un topic tamper
34486
- if (t.tamper)
34487
- interfaces.push(sdk_1.ScryptedInterface.TamperSensor);
34488
- // Interfaccia primaria
34489
34469
  if (cfg.kind === 'contact')
34490
34470
  interfaces.unshift(sdk_1.ScryptedInterface.EntrySensor);
34491
34471
  else if (cfg.kind === 'motion')
34492
34472
  interfaces.unshift(sdk_1.ScryptedInterface.MotionSensor);
34493
34473
  else
34494
34474
  interfaces.unshift(sdk_1.ScryptedInterface.OccupancySensor);
34495
- // Battery solo se previsto
34496
- if ((t.batteryLevel && t.batteryLevel.trim()) || (t.lowBattery && t.lowBattery.trim())) {
34475
+ if (t.tamper)
34476
+ interfaces.push(sdk_1.ScryptedInterface.TamperSensor);
34477
+ // Battery solo se definita davvero
34478
+ if ((t.batteryLevel && t.batteryLevel.trim()) || (t.lowBattery && t.lowBattery.trim()))
34497
34479
  interfaces.push(sdk_1.ScryptedInterface.Battery);
34498
- }
34499
34480
  return { nativeId, name: cfg.name, type: sdk_1.ScryptedDeviceType.Sensor, interfaces };
34500
34481
  });
34501
- // 2) Annuncio
34482
+ // 2) annuncio
34502
34483
  const dmAny = deviceManager;
34503
34484
  if (typeof dmAny.onDevicesChanged === 'function') {
34504
34485
  dmAny.onDevicesChanged({ devices: manifests });
@@ -34510,7 +34491,7 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34510
34491
  this.console.log('Annunciato:', m.nativeId);
34511
34492
  }
34512
34493
  }
34513
- // 3) Istanzia/aggiorna DOPO l’annuncio
34494
+ // 3) istanzia/aggiorna
34514
34495
  for (const cfg of this.sensorsCfg) {
34515
34496
  const nativeId = `sensor:${cfg.id}`;
34516
34497
  let dev = this.devices.get(nativeId);
@@ -34526,8 +34507,9 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34526
34507
  else {
34527
34508
  dev.cfg = cfg;
34528
34509
  }
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());
34510
+ // default OK per battery se non abbiamo ancora un valore
34511
+ const hasBattery = !!(cfg.topics.batteryLevel && cfg.topics.batteryLevel.trim())
34512
+ || !!(cfg.topics.lowBattery && cfg.topics.lowBattery.trim());
34531
34513
  if (hasBattery && dev.batteryLevel === undefined) {
34532
34514
  dev.batteryLevel = 100;
34533
34515
  try {
@@ -34536,7 +34518,7 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34536
34518
  catch { }
34537
34519
  }
34538
34520
  }
34539
- // 4) Rimuovi quelli spariti
34521
+ // 4) cleanup
34540
34522
  const announced = new Set(manifests.map(m => m.nativeId));
34541
34523
  for (const [nativeId] of this.devices) {
34542
34524
  if (!announced.has(nativeId)) {
@@ -34603,7 +34585,7 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34603
34585
  this.console.log(`Connecting MQTT ${url} ...`);
34604
34586
  const client = mqtt_1.default.connect(url, opts);
34605
34587
  this.client = client;
34606
- // cache alarm topics for fast compare
34588
+ // cache alarm topics
34607
34589
  const tTarget = this.storage.getItem('topicGetTarget') || '';
34608
34590
  const tCurrent = this.storage.getItem('topicGetCurrent') || '';
34609
34591
  const tTamper = this.storage.getItem('topicTamper') || '';
@@ -34615,12 +34597,9 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34615
34597
  this.onDeviceEvent(sdk_1.ScryptedInterface.Online, true);
34616
34598
  }
34617
34599
  catch { }
34618
- if (subs.length) {
34619
- client.subscribe(subs, { qos: 0 }, (err) => {
34620
- if (err)
34621
- this.console.error('subscribe error', err);
34622
- });
34623
- }
34600
+ if (subs.length)
34601
+ client.subscribe(subs, { qos: 0 }, (err) => { if (err)
34602
+ this.console.error('subscribe error', err); });
34624
34603
  });
34625
34604
  client.on('reconnect', () => this.console.log('MQTT reconnecting...'));
34626
34605
  client.on('close', () => {
@@ -34636,6 +34615,8 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34636
34615
  try {
34637
34616
  const p = payload?.toString() ?? '';
34638
34617
  const np = normalize(p);
34618
+ if (RUNTIME.logMqttAll)
34619
+ this.console.log(`[MQTT] ${topic} -> "${p}"`);
34639
34620
  // ---- Alarm handling ----
34640
34621
  if (topic === tOnline) {
34641
34622
  if (truthy(np) || np === 'online') {
@@ -34691,17 +34672,19 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34691
34672
  this.onDeviceEvent(sdk_1.ScryptedInterface.SecuritySystem, newState);
34692
34673
  }
34693
34674
  catch { }
34675
+ if (RUNTIME.logSensors)
34676
+ this.console.log(`[Alarm] current: mode=${newState.mode} triggered=${!!newState.triggered} (${topic}="${p}")`);
34694
34677
  return;
34695
34678
  }
34696
34679
  if (topic === tTarget) {
34697
34680
  this.pendingTarget = this.parseIncomingMode(payload);
34698
- this.console.log('Target state reported:', p, '->', this.pendingTarget);
34681
+ if (RUNTIME.logSensors)
34682
+ this.console.log(`[Alarm] target reported: "${p}" -> ${this.pendingTarget}`);
34699
34683
  return;
34700
34684
  }
34701
34685
  // ---- Sensor dispatch ----
34702
- for (const dev of this.devices.values()) {
34686
+ for (const dev of this.devices.values())
34703
34687
  dev.handleMqtt(topic, payload);
34704
- }
34705
34688
  }
34706
34689
  catch (e) {
34707
34690
  this.console.error('MQTT message handler error', e);
@@ -34721,9 +34704,11 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34721
34704
  this.client.publish(topic, payload, { qos, retain }, (err) => {
34722
34705
  if (err)
34723
34706
  this.console.error('publish error', err);
34707
+ else if (RUNTIME.logSensors)
34708
+ this.console.log(`[Alarm] published target "${payload}" to ${topic}`);
34724
34709
  });
34725
34710
  }
34726
- /** Sceglie il payload di publish rispettando override → strict tokens → default arm_* */
34711
+ /** Payload publish: override → strict tokens → default arm_* */
34727
34712
  getOutgoing(mode) {
34728
34713
  const overrides = {
34729
34714
  [sdk_1.SecuritySystemMode.Disarmed]: this.storage.getItem('payloadDisarm') || null,
@@ -34741,7 +34726,7 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34741
34726
  async armSecuritySystem(mode) {
34742
34727
  const payload = this.getOutgoing(mode);
34743
34728
  this.console.log('armSecuritySystem', mode, '->', payload);
34744
- this.pendingTarget = mode; // memorizza target, ma NON cambiare il current
34729
+ this.pendingTarget = mode;
34745
34730
  this.publishSetTarget(payload);
34746
34731
  }
34747
34732
  async disarmSecuritySystem() {
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.49",
3
+ "version": "1.0.52",
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",