@rfranzoi/scrypted-mqtt-securitysystem 1.0.90 → 1.0.93
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 +78 -224
- package/dist/plugin.zip +0 -0
- package/package.json +3 -2
package/dist/main.nodejs.js
CHANGED
|
@@ -34241,9 +34241,10 @@ function payloadToModeLoose(payload) {
|
|
|
34241
34241
|
return undefined;
|
|
34242
34242
|
}
|
|
34243
34243
|
class BaseMqttSensor extends sdk_1.ScryptedDeviceBase {
|
|
34244
|
-
constructor(nativeId, cfg) {
|
|
34244
|
+
constructor(nativeId, cfg, publishBypass) {
|
|
34245
34245
|
super(nativeId);
|
|
34246
34246
|
this.cfg = cfg;
|
|
34247
|
+
this.publishBypass = publishBypass;
|
|
34247
34248
|
}
|
|
34248
34249
|
/** setter centralizzato + evento + (log opzionale) */
|
|
34249
34250
|
setAndEmit(prop, val, iface, logContext) {
|
|
@@ -34299,7 +34300,17 @@ class BaseMqttSensor extends sdk_1.ScryptedDeviceBase {
|
|
|
34299
34300
|
});
|
|
34300
34301
|
return;
|
|
34301
34302
|
}
|
|
34302
|
-
// 4)
|
|
34303
|
+
// 4) BYPASS STATE
|
|
34304
|
+
if (topic === this.cfg.bypass?.state) {
|
|
34305
|
+
if (truthy(np)) {
|
|
34306
|
+
this.setAndEmit('on', true, sdk_1.ScryptedInterface.OnOff, { topic, raw, propLabel: 'bypass' });
|
|
34307
|
+
}
|
|
34308
|
+
else if (falsy(np)) {
|
|
34309
|
+
this.setAndEmit('on', false, sdk_1.ScryptedInterface.OnOff, { topic, raw, propLabel: 'bypass' });
|
|
34310
|
+
}
|
|
34311
|
+
return;
|
|
34312
|
+
}
|
|
34313
|
+
// 5) LOW BATTERY (bool)
|
|
34303
34314
|
if (topic === topics.lowBattery) {
|
|
34304
34315
|
const isLow = np === 'true' ||
|
|
34305
34316
|
np === '1' ||
|
|
@@ -34322,7 +34333,7 @@ class BaseMqttSensor extends sdk_1.ScryptedDeviceBase {
|
|
|
34322
34333
|
}
|
|
34323
34334
|
return;
|
|
34324
34335
|
}
|
|
34325
|
-
//
|
|
34336
|
+
// 6) BATTERY LEVEL (0..100)
|
|
34326
34337
|
if (topic === topics.batteryLevel) {
|
|
34327
34338
|
const n = Number(raw);
|
|
34328
34339
|
if (isFinite(n)) {
|
|
@@ -34342,6 +34353,34 @@ class BaseMqttSensor extends sdk_1.ScryptedDeviceBase {
|
|
|
34342
34353
|
return;
|
|
34343
34354
|
}
|
|
34344
34355
|
}
|
|
34356
|
+
async turnOn() {
|
|
34357
|
+
const bypass = this.cfg.bypass;
|
|
34358
|
+
if (!bypass?.control) {
|
|
34359
|
+
this.console?.warn?.('Bypass control topic non configurato.');
|
|
34360
|
+
return;
|
|
34361
|
+
}
|
|
34362
|
+
const payload = (bypass.payloadOn || 'bypass').trim() || 'bypass';
|
|
34363
|
+
if (this.publishBypass(this.cfg, payload))
|
|
34364
|
+
this.setAndEmit('on', true, sdk_1.ScryptedInterface.OnOff, { propLabel: 'bypass' });
|
|
34365
|
+
}
|
|
34366
|
+
async turnOff() {
|
|
34367
|
+
const bypass = this.cfg.bypass;
|
|
34368
|
+
if (!bypass?.control) {
|
|
34369
|
+
this.console?.warn?.('Bypass control topic non configurato.');
|
|
34370
|
+
return;
|
|
34371
|
+
}
|
|
34372
|
+
const payload = (bypass.payloadOff || 'clear_bypass').trim() || 'clear_bypass';
|
|
34373
|
+
if (this.publishBypass(this.cfg, payload))
|
|
34374
|
+
this.setAndEmit('on', false, sdk_1.ScryptedInterface.OnOff, { propLabel: 'bypass' });
|
|
34375
|
+
}
|
|
34376
|
+
async setPowerState(on) {
|
|
34377
|
+
if (on)
|
|
34378
|
+
return this.turnOn();
|
|
34379
|
+
return this.turnOff();
|
|
34380
|
+
}
|
|
34381
|
+
async setOn(on) {
|
|
34382
|
+
return this.setPowerState(on);
|
|
34383
|
+
}
|
|
34345
34384
|
}
|
|
34346
34385
|
class ContactMqttSensor extends BaseMqttSensor {
|
|
34347
34386
|
handlePrimary(topic, np, raw) {
|
|
@@ -34367,72 +34406,12 @@ class OccupancyMqttSensor extends BaseMqttSensor {
|
|
|
34367
34406
|
}
|
|
34368
34407
|
}
|
|
34369
34408
|
}
|
|
34370
|
-
class BypassMqttSwitch extends sdk_1.ScryptedDeviceBase {
|
|
34371
|
-
constructor(nativeId, cfg, parent) {
|
|
34372
|
-
super(nativeId);
|
|
34373
|
-
this.cfg = cfg;
|
|
34374
|
-
this.parent = parent;
|
|
34375
|
-
}
|
|
34376
|
-
updateConfig(cfg) {
|
|
34377
|
-
this.cfg = cfg;
|
|
34378
|
-
}
|
|
34379
|
-
setOn(val, logContext) {
|
|
34380
|
-
if (this.on === val)
|
|
34381
|
-
return;
|
|
34382
|
-
this.on = val;
|
|
34383
|
-
try {
|
|
34384
|
-
this.onDeviceEvent(sdk_1.ScryptedInterface.OnOff, val);
|
|
34385
|
-
}
|
|
34386
|
-
catch (e) {
|
|
34387
|
-
this.console?.warn?.('onDeviceEvent error', e);
|
|
34388
|
-
}
|
|
34389
|
-
if (RUNTIME.logSensors) {
|
|
34390
|
-
const source = logContext?.source ? ` ${logContext.source}` : '';
|
|
34391
|
-
const extra = logContext?.topic ? ` (${logContext.topic}="${logContext.raw ?? ''}")` : '';
|
|
34392
|
-
this.console?.log?.(`[Bypass] ${this.cfg.zoneName} [${this.cfg.id}] on -> ${val}${source}${extra}`);
|
|
34393
|
-
}
|
|
34394
|
-
}
|
|
34395
|
-
handleMqtt(topic, payload) {
|
|
34396
|
-
if (topic !== this.cfg.topics.state)
|
|
34397
|
-
return;
|
|
34398
|
-
const raw = payload?.toString() ?? '';
|
|
34399
|
-
const np = normalize(raw);
|
|
34400
|
-
if (truthy(np))
|
|
34401
|
-
this.setOn(true, { topic, raw, source: 'state' });
|
|
34402
|
-
else if (falsy(np))
|
|
34403
|
-
this.setOn(false, { topic, raw, source: 'state' });
|
|
34404
|
-
}
|
|
34405
|
-
async turnOn() {
|
|
34406
|
-
if (RUNTIME.logSensors) {
|
|
34407
|
-
const topic = this.cfg.topics?.control || '';
|
|
34408
|
-
this.console?.log?.(`[Bypass] cmd ON ${this.cfg.zoneName} [${this.cfg.id}] -> ${topic}`);
|
|
34409
|
-
}
|
|
34410
|
-
const payload = (this.cfg.payloadOn || 'bypass').trim() || 'bypass';
|
|
34411
|
-
if (this.parent.publishBypass(this.cfg, payload))
|
|
34412
|
-
this.setOn(true, { source: 'local' });
|
|
34413
|
-
}
|
|
34414
|
-
async turnOff() {
|
|
34415
|
-
if (RUNTIME.logSensors) {
|
|
34416
|
-
const topic = this.cfg.topics?.control || '';
|
|
34417
|
-
this.console?.log?.(`[Bypass] cmd OFF ${this.cfg.zoneName} [${this.cfg.id}] -> ${topic}`);
|
|
34418
|
-
}
|
|
34419
|
-
const payload = (this.cfg.payloadOff || 'clear_bypass').trim() || 'clear_bypass';
|
|
34420
|
-
if (this.parent.publishBypass(this.cfg, payload))
|
|
34421
|
-
this.setOn(false, { source: 'local' });
|
|
34422
|
-
}
|
|
34423
|
-
async setPowerState(on) {
|
|
34424
|
-
if (on)
|
|
34425
|
-
return this.turnOn();
|
|
34426
|
-
return this.turnOff();
|
|
34427
|
-
}
|
|
34428
|
-
}
|
|
34429
34409
|
/** ----------------- Main Plugin ----------------- */
|
|
34430
34410
|
class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
34431
34411
|
constructor() {
|
|
34432
34412
|
super();
|
|
34433
34413
|
// sensor management
|
|
34434
34414
|
this.sensorsCfg = [];
|
|
34435
|
-
this.bypassCfg = [];
|
|
34436
34415
|
this.devices = new Map();
|
|
34437
34416
|
// carica flag runtime
|
|
34438
34417
|
updateRuntimeFromStorage((k) => this.storage.getItem(k) || '');
|
|
@@ -34456,7 +34435,6 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34456
34435
|
this.online = this.online ?? false;
|
|
34457
34436
|
// Load configs and announce devices
|
|
34458
34437
|
this.loadSensorsFromStorage();
|
|
34459
|
-
this.loadBypassFromStorage();
|
|
34460
34438
|
this.discoverDevices().catch(e => this.console.error('discoverDevices error', e));
|
|
34461
34439
|
// Connect on start
|
|
34462
34440
|
this.connectMqtt().catch(e => this.console.error('MQTT connect error:', e));
|
|
@@ -34537,14 +34515,6 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34537
34515
|
this.console.error('saveSensorsToStorage error', e);
|
|
34538
34516
|
}
|
|
34539
34517
|
}
|
|
34540
|
-
saveBypassToStorage() {
|
|
34541
|
-
try {
|
|
34542
|
-
this.storage.setItem('bypassJson', JSON.stringify(this.bypassCfg));
|
|
34543
|
-
}
|
|
34544
|
-
catch (e) {
|
|
34545
|
-
this.console.error('saveBypassToStorage error', e);
|
|
34546
|
-
}
|
|
34547
|
-
}
|
|
34548
34518
|
/** ---- Settings UI ---- */
|
|
34549
34519
|
async getSettings() {
|
|
34550
34520
|
const out = [
|
|
@@ -34579,8 +34549,6 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34579
34549
|
];
|
|
34580
34550
|
// ---- UI Add Sensor ----
|
|
34581
34551
|
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.' });
|
|
34582
|
-
// ---- UI Add Bypass Switch ----
|
|
34583
|
-
out.push({ group: 'Add Bypass Switch', key: 'bypass.new.id', title: 'New Bypass ID', placeholder: 'zona-1', value: this.storage.getItem('bypass.new.id') || '' }, { group: 'Add Bypass Switch', key: 'bypass.new.zoneName', title: 'Zone Name', placeholder: 'Zona 1', value: this.storage.getItem('bypass.new.zoneName') || '' }, { group: 'Add Bypass Switch', key: 'bypass.new.topic.control', title: 'Control Topic', placeholder: 'paradox/control/zones/Zona_1', value: this.storage.getItem('bypass.new.topic.control') || '' }, { group: 'Add Bypass Switch', key: 'bypass.new.topic.state', title: 'State Topic', placeholder: 'paradox/states/zones/Zona_1/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.' });
|
|
34584
34552
|
// ---- UI per sensori esistenti ----
|
|
34585
34553
|
for (const cfg of this.sensorsCfg) {
|
|
34586
34554
|
const gid = `Sensor: ${cfg.name} [${cfg.id}]`;
|
|
@@ -34591,12 +34559,7 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34591
34559
|
out.push({ group: gid, key: `sensor.${cfg.id}.topic.motion`, title: 'Motion Detected Topic', value: cfg.topics.motion || '', placeholder: 'paradox/states/zones/XYZ/open' });
|
|
34592
34560
|
else
|
|
34593
34561
|
out.push({ group: gid, key: `sensor.${cfg.id}.topic.occupancy`, title: 'Occupancy Detected Topic', value: cfg.topics.occupancy || '', placeholder: 'paradox/states/zones/XYZ/open' });
|
|
34594
|
-
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' });
|
|
34595
|
-
}
|
|
34596
|
-
// ---- UI per bypass esistenti ----
|
|
34597
|
-
for (const cfg of this.bypassCfg) {
|
|
34598
|
-
const gid = `Bypass: ${cfg.zoneName} [${cfg.id}]`;
|
|
34599
|
-
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/Zona_1' }, { group: gid, key: `bypass.${cfg.id}.topic.state`, title: 'State Topic', value: cfg.topics.state || '', placeholder: 'paradox/states/zones/Zona_1/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' });
|
|
34562
|
+
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/Zona_1' }, { group: gid, key: `sensor.${cfg.id}.bypass.state`, title: 'Bypass State Topic', value: cfg.bypass?.state || '', placeholder: 'paradox/states/zones/Zona_1/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' });
|
|
34600
34563
|
}
|
|
34601
34564
|
return out;
|
|
34602
34565
|
}
|
|
@@ -34629,44 +34592,6 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34629
34592
|
await this.connectMqtt(true);
|
|
34630
34593
|
return;
|
|
34631
34594
|
}
|
|
34632
|
-
// --- Add Bypass Switch workflow ---
|
|
34633
|
-
if (key === 'bypass.new.create' && String(value) === 'true') {
|
|
34634
|
-
const id = (this.storage.getItem('bypass.new.id') || '').trim();
|
|
34635
|
-
const zoneName = (this.storage.getItem('bypass.new.zoneName') || '').trim() || id;
|
|
34636
|
-
const control = (this.storage.getItem('bypass.new.topic.control') || '').trim();
|
|
34637
|
-
const state = (this.storage.getItem('bypass.new.topic.state') || '').trim();
|
|
34638
|
-
const payloadOn = (this.storage.getItem('bypass.new.payloadOn') || 'bypass').trim() || 'bypass';
|
|
34639
|
-
const payloadOff = (this.storage.getItem('bypass.new.payloadOff') || 'clear_bypass').trim() || 'clear_bypass';
|
|
34640
|
-
if (!id) {
|
|
34641
|
-
this.console.warn('Create bypass: id mancante');
|
|
34642
|
-
return;
|
|
34643
|
-
}
|
|
34644
|
-
if (this.bypassCfg.find(b => b.id === id)) {
|
|
34645
|
-
this.console.warn('Create bypass: id già esistente');
|
|
34646
|
-
return;
|
|
34647
|
-
}
|
|
34648
|
-
this.bypassCfg.push({
|
|
34649
|
-
id,
|
|
34650
|
-
zoneName,
|
|
34651
|
-
topics: { control, state },
|
|
34652
|
-
payloadOn,
|
|
34653
|
-
payloadOff,
|
|
34654
|
-
});
|
|
34655
|
-
this.saveBypassToStorage();
|
|
34656
|
-
// pulizia campi "bypass.new.*"
|
|
34657
|
-
this.storage.removeItem('bypass.new.id');
|
|
34658
|
-
this.storage.removeItem('bypass.new.zoneName');
|
|
34659
|
-
this.storage.removeItem('bypass.new.topic.control');
|
|
34660
|
-
this.storage.removeItem('bypass.new.topic.state');
|
|
34661
|
-
this.storage.removeItem('bypass.new.payloadOn');
|
|
34662
|
-
this.storage.removeItem('bypass.new.payloadOff');
|
|
34663
|
-
this.storage.removeItem('bypass.new.create');
|
|
34664
|
-
await this.discoverDevices();
|
|
34665
|
-
await this.connectMqtt(true);
|
|
34666
|
-
return;
|
|
34667
|
-
}
|
|
34668
|
-
if (key.startsWith('bypass.new.'))
|
|
34669
|
-
return;
|
|
34670
34595
|
// --- Edit/Remove sensore esistente ---
|
|
34671
34596
|
const m = key.match(/^sensor\.([^\.]+)\.(.+)$/);
|
|
34672
34597
|
if (m) {
|
|
@@ -34700,53 +34625,19 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34700
34625
|
const tk = prop.substring('topic.'.length);
|
|
34701
34626
|
cfg.topics[tk] = String(value).trim();
|
|
34702
34627
|
}
|
|
34703
|
-
|
|
34704
|
-
|
|
34705
|
-
|
|
34706
|
-
|
|
34707
|
-
}
|
|
34708
|
-
// --- Edit/Remove bypass esistente ---
|
|
34709
|
-
const mb = key.match(/^bypass\.([^\.]+)\.(.+)$/);
|
|
34710
|
-
if (mb) {
|
|
34711
|
-
const bid = mb[1];
|
|
34712
|
-
const prop = mb[2];
|
|
34713
|
-
const cfg = this.bypassCfg.find(b => b.id === bid);
|
|
34714
|
-
if (!cfg) {
|
|
34715
|
-
this.console.warn('putSetting: bypass non trovato', bid);
|
|
34716
|
-
return;
|
|
34717
|
-
}
|
|
34718
|
-
if (prop === 'remove' && String(value) === 'true') {
|
|
34719
|
-
this.bypassCfg = this.bypassCfg.filter(b => b.id !== bid);
|
|
34720
|
-
this.saveBypassToStorage();
|
|
34721
|
-
try {
|
|
34722
|
-
this.devices.delete(`bypass:${bid}`);
|
|
34723
|
-
deviceManager.onDeviceRemoved?.(`bypass:${bid}`);
|
|
34724
|
-
}
|
|
34725
|
-
catch { }
|
|
34726
|
-
this.storage.removeItem(key);
|
|
34727
|
-
await this.discoverDevices();
|
|
34728
|
-
await this.connectMqtt(true);
|
|
34729
|
-
return;
|
|
34730
|
-
}
|
|
34731
|
-
if (prop === 'zoneName')
|
|
34732
|
-
cfg.zoneName = String(value);
|
|
34733
|
-
else if (prop === 'payloadOn')
|
|
34734
|
-
cfg.payloadOn = String(value).trim();
|
|
34735
|
-
else if (prop === 'payloadOff')
|
|
34736
|
-
cfg.payloadOff = String(value).trim();
|
|
34737
|
-
else if (prop.startsWith('topic.')) {
|
|
34738
|
-
const tk = prop.substring('topic.'.length);
|
|
34739
|
-
cfg.topics[tk] = String(value).trim();
|
|
34628
|
+
else if (prop.startsWith('bypass.')) {
|
|
34629
|
+
const bk = prop.substring('bypass.'.length);
|
|
34630
|
+
cfg.bypass = cfg.bypass || {};
|
|
34631
|
+
cfg.bypass[bk] = String(value).trim();
|
|
34740
34632
|
}
|
|
34741
|
-
this.
|
|
34633
|
+
this.saveSensorsToStorage();
|
|
34742
34634
|
await this.discoverDevices();
|
|
34743
34635
|
await this.connectMqtt(true);
|
|
34744
34636
|
return;
|
|
34745
34637
|
}
|
|
34746
34638
|
// --- Altro (MQTT / Alarm settings / parsing / payloads / logging) ---
|
|
34747
|
-
if (key === 'sensorsJson'
|
|
34639
|
+
if (key === 'sensorsJson') {
|
|
34748
34640
|
this.loadSensorsFromStorage();
|
|
34749
|
-
this.loadBypassFromStorage();
|
|
34750
34641
|
await this.discoverDevices();
|
|
34751
34642
|
await this.connectMqtt(true);
|
|
34752
34643
|
}
|
|
@@ -34756,6 +34647,8 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34756
34647
|
}
|
|
34757
34648
|
/** ---- DeviceProvider ---- */
|
|
34758
34649
|
async getDevice(nativeId) {
|
|
34650
|
+
if (RUNTIME.logSensors)
|
|
34651
|
+
this.console.log(`[DeviceProvider] getDevice ${nativeId}`);
|
|
34759
34652
|
const existing = this.devices.get(nativeId);
|
|
34760
34653
|
if (existing)
|
|
34761
34654
|
return existing;
|
|
@@ -34766,11 +34659,11 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34766
34659
|
return undefined;
|
|
34767
34660
|
let dev;
|
|
34768
34661
|
if (cfg.kind === 'contact')
|
|
34769
|
-
dev = new ContactMqttSensor(nativeId, cfg);
|
|
34662
|
+
dev = new ContactMqttSensor(nativeId, cfg, this.publishSensorBypass.bind(this));
|
|
34770
34663
|
else if (cfg.kind === 'motion')
|
|
34771
|
-
dev = new MotionMqttSensor(nativeId, cfg);
|
|
34664
|
+
dev = new MotionMqttSensor(nativeId, cfg, this.publishSensorBypass.bind(this));
|
|
34772
34665
|
else
|
|
34773
|
-
dev = new OccupancyMqttSensor(nativeId, cfg);
|
|
34666
|
+
dev = new OccupancyMqttSensor(nativeId, cfg, this.publishSensorBypass.bind(this));
|
|
34774
34667
|
this.devices.set(nativeId, dev);
|
|
34775
34668
|
const hasBattery = !!(cfg.topics.batteryLevel && cfg.topics.batteryLevel.trim())
|
|
34776
34669
|
|| !!(cfg.topics.lowBattery && cfg.topics.lowBattery.trim());
|
|
@@ -34783,17 +34676,6 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34783
34676
|
}
|
|
34784
34677
|
return dev;
|
|
34785
34678
|
}
|
|
34786
|
-
if (nativeId.startsWith('bypass:')) {
|
|
34787
|
-
const bid = nativeId.substring('bypass:'.length);
|
|
34788
|
-
const cfg = this.bypassCfg.find(b => b.id === bid);
|
|
34789
|
-
if (!cfg)
|
|
34790
|
-
return undefined;
|
|
34791
|
-
const dev = new BypassMqttSwitch(nativeId, cfg, this);
|
|
34792
|
-
if (dev.on === undefined)
|
|
34793
|
-
dev.on = false;
|
|
34794
|
-
this.devices.set(nativeId, dev);
|
|
34795
|
-
return dev;
|
|
34796
|
-
}
|
|
34797
34679
|
return undefined;
|
|
34798
34680
|
}
|
|
34799
34681
|
async releaseDevice(_id, nativeId) {
|
|
@@ -34815,31 +34697,22 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34815
34697
|
const raw = this.storage.getItem('sensorsJson') || '[]';
|
|
34816
34698
|
const parsed = JSON.parse(raw);
|
|
34817
34699
|
// sanitize
|
|
34818
|
-
this.sensorsCfg = (parsed || []).filter(x => x && x.id && x.name && x.kind && x.topics)
|
|
34819
|
-
}
|
|
34820
|
-
catch (e) {
|
|
34821
|
-
this.console.error('Invalid sensorsJson:', e);
|
|
34822
|
-
this.sensorsCfg = [];
|
|
34823
|
-
}
|
|
34824
|
-
}
|
|
34825
|
-
loadBypassFromStorage() {
|
|
34826
|
-
try {
|
|
34827
|
-
const raw = this.storage.getItem('bypassJson') || '[]';
|
|
34828
|
-
const parsed = JSON.parse(raw);
|
|
34829
|
-
this.bypassCfg = (parsed || []).filter(x => x && x.id && x.zoneName && x.topics).map(x => ({
|
|
34700
|
+
this.sensorsCfg = (parsed || []).filter(x => x && x.id && x.name && x.kind && x.topics).map(x => ({
|
|
34830
34701
|
id: String(x.id),
|
|
34831
|
-
|
|
34832
|
-
|
|
34833
|
-
|
|
34834
|
-
|
|
34702
|
+
name: String(x.name),
|
|
34703
|
+
kind: x.kind,
|
|
34704
|
+
topics: x.topics || {},
|
|
34705
|
+
bypass: {
|
|
34706
|
+
control: x.bypass?.control || '',
|
|
34707
|
+
state: x.bypass?.state || '',
|
|
34708
|
+
payloadOn: x.bypass?.payloadOn || 'bypass',
|
|
34709
|
+
payloadOff: x.bypass?.payloadOff || 'clear_bypass',
|
|
34835
34710
|
},
|
|
34836
|
-
payloadOn: String(x.payloadOn || 'bypass'),
|
|
34837
|
-
payloadOff: String(x.payloadOff || 'clear_bypass'),
|
|
34838
34711
|
}));
|
|
34839
34712
|
}
|
|
34840
34713
|
catch (e) {
|
|
34841
|
-
this.console.error('Invalid
|
|
34842
|
-
this.
|
|
34714
|
+
this.console.error('Invalid sensorsJson:', e);
|
|
34715
|
+
this.sensorsCfg = [];
|
|
34843
34716
|
}
|
|
34844
34717
|
}
|
|
34845
34718
|
/** ===== discoverDevices: annuncia PRIMA, istanzia DOPO ===== */
|
|
@@ -34861,19 +34734,18 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34861
34734
|
// Battery solo se definita davvero
|
|
34862
34735
|
if ((t.batteryLevel && t.batteryLevel.trim()) || (t.lowBattery && t.lowBattery.trim()))
|
|
34863
34736
|
interfaces.push(sdk_1.ScryptedInterface.Battery);
|
|
34737
|
+
const hasBypass = !!(cfg.bypass?.control?.trim() || cfg.bypass?.state?.trim());
|
|
34738
|
+
if (hasBypass)
|
|
34739
|
+
interfaces.push(sdk_1.ScryptedInterface.OnOff);
|
|
34864
34740
|
manifests.push({ nativeId, name: cfg.name, type: sdk_1.ScryptedDeviceType.Sensor, interfaces });
|
|
34865
34741
|
}
|
|
34866
|
-
for (const cfg of this.bypassCfg) {
|
|
34867
|
-
const nativeId = `bypass:${cfg.id}`;
|
|
34868
|
-
const zoneName = (cfg.zoneName || '').trim() || cfg.id;
|
|
34869
|
-
const name = `${zoneName} Bypass`;
|
|
34870
|
-
const interfaces = [sdk_1.ScryptedInterface.OnOff];
|
|
34871
|
-
manifests.push({ nativeId, name, type: sdk_1.ScryptedDeviceType.Switch, interfaces });
|
|
34872
|
-
}
|
|
34873
34742
|
// 2) annuncio
|
|
34874
34743
|
const dmAny = deviceManager;
|
|
34875
34744
|
if (typeof dmAny.onDevicesChanged === 'function') {
|
|
34876
|
-
|
|
34745
|
+
const payload = { devices: manifests };
|
|
34746
|
+
if (this.nativeId)
|
|
34747
|
+
payload.providerNativeId = this.nativeId;
|
|
34748
|
+
dmAny.onDevicesChanged(payload);
|
|
34877
34749
|
this.console.log('Annunciati (batch):', manifests.map(m => m.nativeId).join(', '));
|
|
34878
34750
|
}
|
|
34879
34751
|
else {
|
|
@@ -34888,11 +34760,11 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34888
34760
|
let dev = this.devices.get(nativeId);
|
|
34889
34761
|
if (!dev) {
|
|
34890
34762
|
if (cfg.kind === 'contact')
|
|
34891
|
-
dev = new ContactMqttSensor(nativeId, cfg);
|
|
34763
|
+
dev = new ContactMqttSensor(nativeId, cfg, this.publishSensorBypass.bind(this));
|
|
34892
34764
|
else if (cfg.kind === 'motion')
|
|
34893
|
-
dev = new MotionMqttSensor(nativeId, cfg);
|
|
34765
|
+
dev = new MotionMqttSensor(nativeId, cfg, this.publishSensorBypass.bind(this));
|
|
34894
34766
|
else
|
|
34895
|
-
dev = new OccupancyMqttSensor(nativeId, cfg);
|
|
34767
|
+
dev = new OccupancyMqttSensor(nativeId, cfg, this.publishSensorBypass.bind(this));
|
|
34896
34768
|
this.devices.set(nativeId, dev);
|
|
34897
34769
|
}
|
|
34898
34770
|
else {
|
|
@@ -34909,17 +34781,6 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34909
34781
|
catch { }
|
|
34910
34782
|
}
|
|
34911
34783
|
}
|
|
34912
|
-
for (const cfg of this.bypassCfg) {
|
|
34913
|
-
const nativeId = `bypass:${cfg.id}`;
|
|
34914
|
-
let dev = this.devices.get(nativeId);
|
|
34915
|
-
if (!dev) {
|
|
34916
|
-
dev = new BypassMqttSwitch(nativeId, cfg, this);
|
|
34917
|
-
this.devices.set(nativeId, dev);
|
|
34918
|
-
}
|
|
34919
|
-
else {
|
|
34920
|
-
dev.updateConfig(cfg);
|
|
34921
|
-
}
|
|
34922
|
-
}
|
|
34923
34784
|
// 4) cleanup
|
|
34924
34785
|
const announced = new Set(manifests.map(m => m.nativeId));
|
|
34925
34786
|
for (const [nativeId] of this.devices) {
|
|
@@ -34965,14 +34826,7 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34965
34826
|
// sensors
|
|
34966
34827
|
for (const s of this.sensorsCfg) {
|
|
34967
34828
|
const t = s.topics || {};
|
|
34968
|
-
[t.contact, t.motion, t.occupancy, t.batteryLevel, t.lowBattery, t.tamper, t.online]
|
|
34969
|
-
.filter((x) => !!x && String(x).trim().length > 0)
|
|
34970
|
-
.forEach(x => subs.add(String(x)));
|
|
34971
|
-
}
|
|
34972
|
-
// bypass switches
|
|
34973
|
-
for (const b of this.bypassCfg) {
|
|
34974
|
-
const t = b.topics || {};
|
|
34975
|
-
[t.state]
|
|
34829
|
+
[t.contact, t.motion, t.occupancy, t.batteryLevel, t.lowBattery, t.tamper, t.online, s.bypass?.state]
|
|
34976
34830
|
.filter((x) => !!x && String(x).trim().length > 0)
|
|
34977
34831
|
.forEach(x => subs.add(String(x)));
|
|
34978
34832
|
}
|
|
@@ -35121,8 +34975,8 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
35121
34975
|
this.console.log(`[Alarm] published target "${payload}" to ${topic}`);
|
|
35122
34976
|
});
|
|
35123
34977
|
}
|
|
35124
|
-
|
|
35125
|
-
const topic = cfg.
|
|
34978
|
+
publishSensorBypass(cfg, payload) {
|
|
34979
|
+
const topic = cfg.bypass?.control?.trim();
|
|
35126
34980
|
if (!topic || !this.client) {
|
|
35127
34981
|
this.console.warn('Bypass topic control o MQTT non configurati.');
|
|
35128
34982
|
return false;
|
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.
|
|
3
|
+
"version": "1.0.93",
|
|
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",
|
|
@@ -42,7 +42,8 @@
|
|
|
42
42
|
"SecuritySystem",
|
|
43
43
|
"Settings",
|
|
44
44
|
"TamperSensor",
|
|
45
|
-
"Online"
|
|
45
|
+
"Online",
|
|
46
|
+
"DeviceProvider"
|
|
46
47
|
]
|
|
47
48
|
}
|
|
48
49
|
}
|