@rfranzoi/scrypted-mqtt-securitysystem 1.0.95 → 1.0.96

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.
@@ -34457,7 +34457,6 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34457
34457
  super();
34458
34458
  // device management
34459
34459
  this.sensorsCfg = [];
34460
- this.bypassCfg = [];
34461
34460
  this.devices = new Map();
34462
34461
  // load runtime flags
34463
34462
  updateRuntimeFromStorage((k) => this.storage.getItem(k) || '');
@@ -34481,7 +34480,6 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34481
34480
  this.online = this.online ?? false;
34482
34481
  // Load configs and announce devices
34483
34482
  this.loadSensorsFromStorage();
34484
- this.loadBypassFromStorage();
34485
34483
  this.discoverDevices().catch(e => this.console.error('discoverDevices error', e));
34486
34484
  // Connect on start
34487
34485
  this.connectMqtt().catch(e => this.console.error('MQTT connect error:', e));
@@ -34562,14 +34560,6 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34562
34560
  this.console.error('saveSensorsToStorage error', e);
34563
34561
  }
34564
34562
  }
34565
- saveBypassToStorage() {
34566
- try {
34567
- this.storage.setItem('bypassJson', JSON.stringify(this.bypassCfg));
34568
- }
34569
- catch (e) {
34570
- this.console.error('saveBypassToStorage error', e);
34571
- }
34572
- }
34573
34563
  /** ---- Settings UI ---- */
34574
34564
  async getSettings() {
34575
34565
  const out = [
@@ -34604,8 +34594,6 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34604
34594
  ];
34605
34595
  // ---- UI Add Sensor ----
34606
34596
  out.push({ group: 'Add Sensor', key: 'new.id', title: 'New Sensor ID', placeholder: 'front-door', value: this.storage.getItem('new.id') || '' }, { group: 'Add Sensor', key: 'new.name', title: 'Name', placeholder: 'Front Door', 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.' });
34607
- // ---- UI Add Bypass Switch ----
34608
- out.push({ group: 'Add Bypass Switch', key: 'bypass.new.id', title: 'New Bypass ID', placeholder: 'living-room-window', value: this.storage.getItem('bypass.new.id') || '' }, { group: 'Add Bypass Switch', key: 'bypass.new.zoneName', title: 'Zone Name', placeholder: 'Living Room Window', value: this.storage.getItem('bypass.new.zoneName') || '' }, { group: 'Add Bypass Switch', key: 'bypass.new.topic.control', title: 'Control Topic', placeholder: 'paradox/control/zones/Living_Room_Window', value: this.storage.getItem('bypass.new.topic.control') || '' }, { group: 'Add Bypass Switch', key: 'bypass.new.topic.state', title: 'State Topic', placeholder: 'paradox/states/zones/Living_Room_Window/bypassed', value: this.storage.getItem('bypass.new.topic.state') || '' }, { group: 'Add Bypass Switch', key: 'bypass.new.payloadOn', title: 'Payload for ON', placeholder: 'bypass', value: this.storage.getItem('bypass.new.payloadOn') || 'bypass' }, { group: 'Add Bypass Switch', key: 'bypass.new.payloadOff', title: 'Payload for OFF', placeholder: 'clear_bypass', value: this.storage.getItem('bypass.new.payloadOff') || 'clear_bypass' }, { group: 'Add Bypass Switch', key: 'bypass.new.create', title: 'Create bypass switch', type: 'boolean', description: 'Fill the fields above and toggle this on to create the bypass switch. After creation, restart this plugin to see the accessory listed below.' });
34609
34597
  // ---- UI for existing sensors ----
34610
34598
  for (const cfg of this.sensorsCfg) {
34611
34599
  const gid = `Sensor: ${cfg.name} [${cfg.id}]`;
@@ -34616,12 +34604,7 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34616
34604
  out.push({ group: gid, key: `sensor.${cfg.id}.topic.motion`, title: 'Motion Detected Topic', value: cfg.topics.motion || '', placeholder: 'paradox/states/zones/XYZ/open' });
34617
34605
  else
34618
34606
  out.push({ group: gid, key: `sensor.${cfg.id}.topic.occupancy`, title: 'Occupancy Detected Topic', value: cfg.topics.occupancy || '', placeholder: 'paradox/states/zones/XYZ/open' });
34619
- 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' });
34620
- }
34621
- // ---- UI for existing bypass switches ----
34622
- for (const cfg of this.bypassCfg) {
34623
- const gid = `Bypass: ${cfg.zoneName} [${cfg.id}]`;
34624
- out.push({ group: gid, key: `bypass.${cfg.id}.zoneName`, title: 'Zone Name', value: cfg.zoneName }, { group: gid, key: `bypass.${cfg.id}.topic.control`, title: 'Control Topic', value: cfg.topics.control || '', placeholder: 'paradox/control/zones/Living_Room_Window' }, { group: gid, key: `bypass.${cfg.id}.topic.state`, title: 'State Topic', value: cfg.topics.state || '', placeholder: 'paradox/states/zones/Living_Room_Window/bypassed' }, { group: gid, key: `bypass.${cfg.id}.payloadOn`, title: 'Payload for ON', value: cfg.payloadOn || 'bypass' }, { group: gid, key: `bypass.${cfg.id}.payloadOff`, title: 'Payload for OFF', value: cfg.payloadOff || 'clear_bypass' }, { group: gid, key: `bypass.${cfg.id}.remove`, title: 'Remove bypass switch', type: 'boolean' });
34607
+ 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}.bypass.control`, title: 'Bypass Control Topic', value: cfg.bypass?.control || '', placeholder: 'paradox/control/zones/Living_Room_Window', description: 'Configuring bypass topics creates a separate bypass switch accessory for this sensor.' }, { group: gid, key: `sensor.${cfg.id}.bypass.state`, title: 'Bypass State Topic', value: cfg.bypass?.state || '', placeholder: 'paradox/states/zones/Living_Room_Window/bypassed' }, { group: gid, key: `sensor.${cfg.id}.bypass.payloadOn`, title: 'Bypass Payload ON', value: cfg.bypass?.payloadOn || 'bypass' }, { group: gid, key: `sensor.${cfg.id}.bypass.payloadOff`, title: 'Bypass Payload OFF', value: cfg.bypass?.payloadOff || 'clear_bypass' }, { group: gid, key: `sensor.${cfg.id}.remove`, title: 'Remove sensor', type: 'boolean' });
34625
34608
  }
34626
34609
  return out;
34627
34610
  }
@@ -34654,44 +34637,6 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34654
34637
  await this.connectMqtt(true);
34655
34638
  return;
34656
34639
  }
34657
- // --- Add Bypass Switch workflow ---
34658
- if (key === 'bypass.new.create' && String(value) === 'true') {
34659
- const id = (this.storage.getItem('bypass.new.id') || '').trim();
34660
- const zoneName = (this.storage.getItem('bypass.new.zoneName') || '').trim() || id;
34661
- const control = (this.storage.getItem('bypass.new.topic.control') || '').trim();
34662
- const state = (this.storage.getItem('bypass.new.topic.state') || '').trim();
34663
- const payloadOn = (this.storage.getItem('bypass.new.payloadOn') || 'bypass').trim() || 'bypass';
34664
- const payloadOff = (this.storage.getItem('bypass.new.payloadOff') || 'clear_bypass').trim() || 'clear_bypass';
34665
- if (!id) {
34666
- this.console.warn('Create bypass: missing id');
34667
- return;
34668
- }
34669
- if (this.bypassCfg.find(b => b.id === id)) {
34670
- this.console.warn('Create bypass: id already exists');
34671
- return;
34672
- }
34673
- this.bypassCfg.push({
34674
- id,
34675
- zoneName,
34676
- topics: { control, state },
34677
- payloadOn,
34678
- payloadOff,
34679
- });
34680
- this.saveBypassToStorage();
34681
- // clear "bypass.new.*" fields
34682
- this.storage.removeItem('bypass.new.id');
34683
- this.storage.removeItem('bypass.new.zoneName');
34684
- this.storage.removeItem('bypass.new.topic.control');
34685
- this.storage.removeItem('bypass.new.topic.state');
34686
- this.storage.removeItem('bypass.new.payloadOn');
34687
- this.storage.removeItem('bypass.new.payloadOff');
34688
- this.storage.removeItem('bypass.new.create');
34689
- await this.discoverDevices();
34690
- await this.connectMqtt(true);
34691
- return;
34692
- }
34693
- if (key.startsWith('bypass.new.'))
34694
- return;
34695
34640
  // --- Edit/Remove existing sensor ---
34696
34641
  const m = key.match(/^sensor\.([^\.]+)\.(.+)$/);
34697
34642
  if (m) {
@@ -34725,53 +34670,19 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34725
34670
  const tk = prop.substring('topic.'.length);
34726
34671
  cfg.topics[tk] = String(value).trim();
34727
34672
  }
34728
- this.saveSensorsToStorage();
34729
- await this.discoverDevices();
34730
- await this.connectMqtt(true);
34731
- return;
34732
- }
34733
- // --- Edit/Remove existing bypass ---
34734
- const mb = key.match(/^bypass\.([^\.]+)\.(.+)$/);
34735
- if (mb) {
34736
- const bid = mb[1];
34737
- const prop = mb[2];
34738
- const cfg = this.bypassCfg.find(b => b.id === bid);
34739
- if (!cfg) {
34740
- this.console.warn('putSetting: bypass not found', bid);
34741
- return;
34673
+ else if (prop.startsWith('bypass.')) {
34674
+ const bk = prop.substring('bypass.'.length);
34675
+ cfg.bypass = cfg.bypass || {};
34676
+ cfg.bypass[bk] = String(value).trim();
34742
34677
  }
34743
- if (prop === 'remove' && String(value) === 'true') {
34744
- this.bypassCfg = this.bypassCfg.filter(b => b.id !== bid);
34745
- this.saveBypassToStorage();
34746
- try {
34747
- this.devices.delete(`bypass:${bid}`);
34748
- deviceManager.onDeviceRemoved?.(`bypass:${bid}`);
34749
- }
34750
- catch { }
34751
- this.storage.removeItem(key);
34752
- await this.discoverDevices();
34753
- await this.connectMqtt(true);
34754
- return;
34755
- }
34756
- if (prop === 'zoneName')
34757
- cfg.zoneName = String(value);
34758
- else if (prop === 'payloadOn')
34759
- cfg.payloadOn = String(value).trim();
34760
- else if (prop === 'payloadOff')
34761
- cfg.payloadOff = String(value).trim();
34762
- else if (prop.startsWith('topic.')) {
34763
- const tk = prop.substring('topic.'.length);
34764
- cfg.topics[tk] = String(value).trim();
34765
- }
34766
- this.saveBypassToStorage();
34678
+ this.saveSensorsToStorage();
34767
34679
  await this.discoverDevices();
34768
34680
  await this.connectMqtt(true);
34769
34681
  return;
34770
34682
  }
34771
34683
  // --- Other (MQTT / Alarm settings / parsing / payloads / logging) ---
34772
- if (key === 'sensorsJson' || key === 'bypassJson') {
34684
+ if (key === 'sensorsJson') {
34773
34685
  this.loadSensorsFromStorage();
34774
- this.loadBypassFromStorage();
34775
34686
  await this.discoverDevices();
34776
34687
  await this.connectMqtt(true);
34777
34688
  }
@@ -34812,7 +34723,8 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34812
34723
  }
34813
34724
  if (nativeId.startsWith('bypass:')) {
34814
34725
  const bid = nativeId.substring('bypass:'.length);
34815
- const cfg = this.bypassCfg.find(b => b.id === bid);
34726
+ const sensor = this.sensorsCfg.find(s => s.id === bid);
34727
+ const cfg = sensor ? this.buildBypassConfig(sensor) : undefined;
34816
34728
  if (!cfg)
34817
34729
  return undefined;
34818
34730
  const dev = new BypassMqttSwitch(nativeId, cfg, this);
@@ -34847,33 +34759,75 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34847
34759
  name: String(x.name),
34848
34760
  kind: x.kind,
34849
34761
  topics: x.topics || {},
34762
+ bypass: {
34763
+ control: x.bypass?.control || '',
34764
+ state: x.bypass?.state || '',
34765
+ payloadOn: x.bypass?.payloadOn || 'bypass',
34766
+ payloadOff: x.bypass?.payloadOff || 'clear_bypass',
34767
+ },
34850
34768
  }));
34851
34769
  }
34852
34770
  catch (e) {
34853
34771
  this.console.error('Invalid sensorsJson:', e);
34854
34772
  this.sensorsCfg = [];
34855
34773
  }
34774
+ this.migrateBypassFromStorage();
34856
34775
  }
34857
- loadBypassFromStorage() {
34776
+ migrateBypassFromStorage() {
34858
34777
  try {
34859
34778
  const raw = this.storage.getItem('bypassJson') || '[]';
34860
34779
  const parsed = JSON.parse(raw);
34861
- this.bypassCfg = (parsed || []).filter(x => x && x.id && x.zoneName && x.topics).map(x => ({
34862
- id: String(x.id),
34863
- zoneName: String(x.zoneName),
34864
- topics: {
34865
- control: x.topics?.control || '',
34866
- state: x.topics?.state || '',
34867
- },
34868
- payloadOn: String(x.payloadOn || 'bypass'),
34869
- payloadOff: String(x.payloadOff || 'clear_bypass'),
34870
- }));
34780
+ if (!Array.isArray(parsed))
34781
+ return;
34782
+ let changed = false;
34783
+ for (const b of (parsed || [])) {
34784
+ if (!b || !b.id)
34785
+ continue;
34786
+ const sensor = this.sensorsCfg.find(s => s.id === String(b.id));
34787
+ if (!sensor)
34788
+ continue;
34789
+ const bypass = sensor.bypass || {};
34790
+ if (!bypass.control && b.topics?.control) {
34791
+ bypass.control = String(b.topics.control);
34792
+ changed = true;
34793
+ }
34794
+ if (!bypass.state && b.topics?.state) {
34795
+ bypass.state = String(b.topics.state);
34796
+ changed = true;
34797
+ }
34798
+ if ((!bypass.payloadOn || bypass.payloadOn === 'bypass') && b.payloadOn) {
34799
+ bypass.payloadOn = String(b.payloadOn);
34800
+ changed = true;
34801
+ }
34802
+ if ((!bypass.payloadOff || bypass.payloadOff === 'clear_bypass') && b.payloadOff) {
34803
+ bypass.payloadOff = String(b.payloadOff);
34804
+ changed = true;
34805
+ }
34806
+ sensor.bypass = bypass;
34807
+ }
34808
+ if (changed)
34809
+ this.saveSensorsToStorage();
34871
34810
  }
34872
34811
  catch (e) {
34873
34812
  this.console.error('Invalid bypassJson:', e);
34874
- this.bypassCfg = [];
34875
34813
  }
34876
34814
  }
34815
+ buildBypassConfig(sensor) {
34816
+ const bypass = sensor.bypass;
34817
+ if (!bypass)
34818
+ return;
34819
+ const control = (bypass.control || '').trim();
34820
+ const state = (bypass.state || '').trim();
34821
+ if (!control && !state)
34822
+ return;
34823
+ return {
34824
+ id: sensor.id,
34825
+ zoneName: (sensor.name || '').trim() || sensor.id,
34826
+ topics: { control, state },
34827
+ payloadOn: (bypass.payloadOn || 'bypass').trim() || 'bypass',
34828
+ payloadOff: (bypass.payloadOff || 'clear_bypass').trim() || 'clear_bypass',
34829
+ };
34830
+ }
34877
34831
  /** ===== discoverDevices: announce first, instantiate after ===== */
34878
34832
  async discoverDevices() {
34879
34833
  // 1) manifest
@@ -34895,7 +34849,10 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34895
34849
  interfaces.push(sdk_1.ScryptedInterface.Battery);
34896
34850
  manifests.push({ nativeId, name: cfg.name, type: sdk_1.ScryptedDeviceType.Sensor, interfaces });
34897
34851
  }
34898
- for (const cfg of this.bypassCfg) {
34852
+ for (const sensor of this.sensorsCfg) {
34853
+ const cfg = this.buildBypassConfig(sensor);
34854
+ if (!cfg)
34855
+ continue;
34899
34856
  const nativeId = `bypass:${cfg.id}`;
34900
34857
  const zoneName = (cfg.zoneName || '').trim() || cfg.id;
34901
34858
  const name = `${zoneName} Bypass`;
@@ -34944,7 +34901,10 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
34944
34901
  catch { }
34945
34902
  }
34946
34903
  }
34947
- for (const cfg of this.bypassCfg) {
34904
+ for (const sensor of this.sensorsCfg) {
34905
+ const cfg = this.buildBypassConfig(sensor);
34906
+ if (!cfg)
34907
+ continue;
34948
34908
  const nativeId = `bypass:${cfg.id}`;
34949
34909
  let dev = this.devices.get(nativeId);
34950
34910
  if (!dev) {
@@ -35005,11 +34965,10 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
35005
34965
  .forEach(x => subs.add(String(x)));
35006
34966
  }
35007
34967
  // bypass switches
35008
- for (const b of this.bypassCfg) {
35009
- const t = b.topics || {};
35010
- [t.state]
35011
- .filter((x) => !!x && String(x).trim().length > 0)
35012
- .forEach(x => subs.add(String(x)));
34968
+ for (const s of this.sensorsCfg) {
34969
+ const state = s.bypass?.state;
34970
+ if (state && state.trim().length > 0)
34971
+ subs.add(state);
35013
34972
  }
35014
34973
  return Array.from(subs);
35015
34974
  }
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.95",
3
+ "version": "1.0.96",
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",