@rfranzoi/scrypted-mqtt-securitysystem 1.0.20 → 1.0.22
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 +116 -31
- package/dist/plugin.zip +0 -0
- package/package.json +1 -1
package/dist/main.nodejs.js
CHANGED
|
@@ -34112,7 +34112,7 @@ class BaseMqttSensor extends sdk_1.ScryptedDeviceBase {
|
|
|
34112
34112
|
constructor(nativeId, cfg) {
|
|
34113
34113
|
super(nativeId);
|
|
34114
34114
|
this.cfg = cfg;
|
|
34115
|
-
//
|
|
34115
|
+
// non impostare stati qui: l'annuncio device deve avvenire prima
|
|
34116
34116
|
}
|
|
34117
34117
|
/** Called by parent on each MQTT message */
|
|
34118
34118
|
handleMqtt(topic, payload) {
|
|
@@ -34141,7 +34141,9 @@ class BaseMqttSensor extends sdk_1.ScryptedDeviceBase {
|
|
|
34141
34141
|
this.batteryLevel = n;
|
|
34142
34142
|
}
|
|
34143
34143
|
else if (topic === this.cfg.topics.lowBattery && !this.cfg.topics.batteryLevel) {
|
|
34144
|
-
//
|
|
34144
|
+
// Solo se abbiamo lowBattery (booleano) ma NON batteryLevel:
|
|
34145
|
+
// True -> 10% (warning)
|
|
34146
|
+
// False -> 100% (ok)
|
|
34145
34147
|
this.batteryLevel = truthy(np) ? 10 : 100;
|
|
34146
34148
|
}
|
|
34147
34149
|
// primary handled by subclasses
|
|
@@ -34225,9 +34227,18 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34225
34227
|
}
|
|
34226
34228
|
catch { }
|
|
34227
34229
|
}
|
|
34230
|
+
// helpers persistenza
|
|
34231
|
+
saveSensorsToStorage() {
|
|
34232
|
+
try {
|
|
34233
|
+
this.storage.setItem('sensorsJson', JSON.stringify(this.sensorsCfg));
|
|
34234
|
+
}
|
|
34235
|
+
catch (e) {
|
|
34236
|
+
this.console.error('saveSensorsToStorage error', e);
|
|
34237
|
+
}
|
|
34238
|
+
}
|
|
34228
34239
|
/** ---- Settings UI ---- */
|
|
34229
34240
|
async getSettings() {
|
|
34230
|
-
|
|
34241
|
+
const out = [
|
|
34231
34242
|
// MQTT Core
|
|
34232
34243
|
{ group: 'MQTT', key: 'brokerUrl', title: 'Broker URL', placeholder: 'mqtt://127.0.0.1:1883', value: this.storage.getItem('brokerUrl') || 'mqtt://127.0.0.1:1883' },
|
|
34233
34244
|
{ group: 'MQTT', key: 'username', title: 'Username', type: 'string', value: this.storage.getItem('username') || '' },
|
|
@@ -34243,24 +34254,98 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34243
34254
|
{ group: 'Alarm Topics', key: 'topicOnline', title: 'Get Online (subscribe)', placeholder: 'paradox/interface/availability', value: this.storage.getItem('topicOnline') || '' },
|
|
34244
34255
|
{ group: 'Publish Options', key: 'qos', title: 'QoS', type: 'integer', value: parseInt(this.storage.getItem('qos') || '0') },
|
|
34245
34256
|
{ group: 'Publish Options', key: 'retain', title: 'Retain', type: 'boolean', value: this.storage.getItem('retain') === 'true' },
|
|
34246
|
-
{ group: 'Outgoing Payloads', key: 'payloadDisarm', title: 'Payload Disarm', value: this.storage.getItem('payloadDisarm') || DEFAULT_OUTGOING[sdk_1.SecuritySystemMode.Disarmed] },
|
|
34247
|
-
{ group: 'Outgoing Payloads', key: 'payloadHome', title: 'Payload HomeArmed', value: this.storage.getItem('payloadHome') || DEFAULT_OUTGOING[sdk_1.SecuritySystemMode.HomeArmed] },
|
|
34248
|
-
{ group: 'Outgoing Payloads', key: 'payloadAway', title: 'Payload AwayArmed', value: this.storage.getItem('payloadAway') || DEFAULT_OUTGOING[sdk_1.SecuritySystemMode.AwayArmed] },
|
|
34249
|
-
{ group: 'Outgoing Payloads', key: 'payloadNight', title: 'Payload NightArmed', value: this.storage.getItem('payloadNight') || DEFAULT_OUTGOING[sdk_1.SecuritySystemMode.NightArmed] },
|
|
34250
|
-
// Sensors config (JSON)
|
|
34251
|
-
{
|
|
34252
|
-
group: 'Sensors',
|
|
34253
|
-
key: 'sensorsJson',
|
|
34254
|
-
title: 'Sensors JSON (contact/motion/occupancy)',
|
|
34255
|
-
description: 'Definisci i sensori e i topic MQTT (vedi README). Incolla JSON; le interruzioni di riga sono accettate.',
|
|
34256
|
-
type: 'string',
|
|
34257
|
-
value: this.storage.getItem('sensorsJson') || '[\n {\n "id": "front-door",\n "name": "Front Door",\n "kind": "contact",\n "topics": { "contact": "SYSTEM/zones/front/contact" }\n }\n]'
|
|
34258
|
-
},
|
|
34259
34257
|
];
|
|
34258
|
+
// ---- UI Add Sensor ----
|
|
34259
|
+
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: 'Compila i campi sopra e attiva per creare.' });
|
|
34260
|
+
// ---- UI per sensori esistenti ----
|
|
34261
|
+
for (const cfg of this.sensorsCfg) {
|
|
34262
|
+
const gid = `Sensor: ${cfg.name} [${cfg.id}]`;
|
|
34263
|
+
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'] });
|
|
34264
|
+
// primary per tipo
|
|
34265
|
+
if (cfg.kind === 'contact') {
|
|
34266
|
+
out.push({ group: gid, key: `sensor.${cfg.id}.topic.contact`, title: 'Contact State Topic', value: cfg.topics.contact || '', placeholder: 'paradox/states/zones/XYZ/open' });
|
|
34267
|
+
}
|
|
34268
|
+
else if (cfg.kind === 'motion') {
|
|
34269
|
+
out.push({ group: gid, key: `sensor.${cfg.id}.topic.motion`, title: 'Motion Detected Topic', value: cfg.topics.motion || '', placeholder: 'paradox/states/zones/XYZ/open' });
|
|
34270
|
+
}
|
|
34271
|
+
else {
|
|
34272
|
+
out.push({ group: gid, key: `sensor.${cfg.id}.topic.occupancy`, title: 'Occupancy Detected Topic', value: cfg.topics.occupancy || '', placeholder: 'paradox/states/zones/XYZ/open' });
|
|
34273
|
+
}
|
|
34274
|
+
// extra opzionali
|
|
34275
|
+
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' });
|
|
34276
|
+
}
|
|
34277
|
+
return out;
|
|
34260
34278
|
}
|
|
34261
34279
|
async putSetting(key, value) {
|
|
34280
|
+
// salva sempre nella storage la value del campo (così resta in UI)
|
|
34262
34281
|
this.storage.setItem(key, String(value));
|
|
34282
|
+
// --- Add Sensor workflow ---
|
|
34283
|
+
if (key === 'new.create' && String(value) === 'true') {
|
|
34284
|
+
const id = (this.storage.getItem('new.id') || '').trim();
|
|
34285
|
+
const name = (this.storage.getItem('new.name') || '').trim() || id;
|
|
34286
|
+
const kind = (this.storage.getItem('new.kind') || 'contact').trim();
|
|
34287
|
+
if (!id) {
|
|
34288
|
+
this.console.warn('Create sensor: id mancante');
|
|
34289
|
+
return;
|
|
34290
|
+
}
|
|
34291
|
+
if (this.sensorsCfg.find(s => s.id === id)) {
|
|
34292
|
+
this.console.warn('Create sensor: id già esistente');
|
|
34293
|
+
return;
|
|
34294
|
+
}
|
|
34295
|
+
this.sensorsCfg.push({ id, name, kind, topics: {} });
|
|
34296
|
+
this.saveSensorsToStorage();
|
|
34297
|
+
// pulisci i campi "new.*"
|
|
34298
|
+
this.storage.removeItem('new.id');
|
|
34299
|
+
this.storage.removeItem('new.name');
|
|
34300
|
+
this.storage.removeItem('new.kind');
|
|
34301
|
+
this.storage.removeItem('new.create');
|
|
34302
|
+
await this.discoverSensors();
|
|
34303
|
+
await this.connectMqtt(true);
|
|
34304
|
+
return;
|
|
34305
|
+
}
|
|
34306
|
+
// --- Edit/Remove sensore esistente ---
|
|
34307
|
+
const m = key.match(/^sensor\.([^\.]+)\.(.+)$/);
|
|
34308
|
+
if (m) {
|
|
34309
|
+
const sid = m[1];
|
|
34310
|
+
const prop = m[2];
|
|
34311
|
+
const cfg = this.sensorsCfg.find(s => s.id === sid);
|
|
34312
|
+
if (!cfg) {
|
|
34313
|
+
this.console.warn('putSetting: sensor non trovato', sid);
|
|
34314
|
+
return;
|
|
34315
|
+
}
|
|
34316
|
+
if (prop === 'remove' && String(value) === 'true') {
|
|
34317
|
+
// elimina
|
|
34318
|
+
this.sensorsCfg = this.sensorsCfg.filter(s => s.id !== sid);
|
|
34319
|
+
this.saveSensorsToStorage();
|
|
34320
|
+
try {
|
|
34321
|
+
this.devices.delete(`sensor:${sid}`);
|
|
34322
|
+
deviceManager.onDeviceRemoved?.(`sensor:${sid}`);
|
|
34323
|
+
}
|
|
34324
|
+
catch { }
|
|
34325
|
+
// pulisci flag
|
|
34326
|
+
this.storage.removeItem(key);
|
|
34327
|
+
await this.discoverSensors();
|
|
34328
|
+
await this.connectMqtt(true);
|
|
34329
|
+
return;
|
|
34330
|
+
}
|
|
34331
|
+
if (prop === 'name') {
|
|
34332
|
+
cfg.name = String(value);
|
|
34333
|
+
}
|
|
34334
|
+
else if (prop === 'kind') {
|
|
34335
|
+
cfg.kind = String(value);
|
|
34336
|
+
}
|
|
34337
|
+
else if (prop.startsWith('topic.')) {
|
|
34338
|
+
const tk = prop.substring('topic.'.length);
|
|
34339
|
+
cfg.topics[tk] = String(value).trim();
|
|
34340
|
+
}
|
|
34341
|
+
this.saveSensorsToStorage();
|
|
34342
|
+
await this.discoverSensors();
|
|
34343
|
+
await this.connectMqtt(true);
|
|
34344
|
+
return;
|
|
34345
|
+
}
|
|
34346
|
+
// --- Altro (MQTT / Alarm settings) ---
|
|
34263
34347
|
if (key === 'sensorsJson') {
|
|
34348
|
+
// non più mostrato, ma se presente da vecchie versioni
|
|
34264
34349
|
this.loadSensorsFromStorage();
|
|
34265
34350
|
await this.discoverSensors();
|
|
34266
34351
|
await this.connectMqtt(true);
|
|
@@ -34305,30 +34390,25 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34305
34390
|
// 1) Prepara i manifest (niente istanze qui)
|
|
34306
34391
|
const manifests = this.sensorsCfg.map(cfg => {
|
|
34307
34392
|
const nativeId = `sensor:${cfg.id}`;
|
|
34308
|
-
// interfacce dinamiche
|
|
34309
34393
|
const t = cfg.topics || {};
|
|
34310
|
-
const interfaces = [
|
|
34311
|
-
|
|
34312
|
-
|
|
34313
|
-
|
|
34394
|
+
const interfaces = [sdk_1.ScryptedInterface.Online];
|
|
34395
|
+
// Tamper solo se c'è un topic tamper
|
|
34396
|
+
if (t.tamper)
|
|
34397
|
+
interfaces.push(sdk_1.ScryptedInterface.TamperSensor);
|
|
34398
|
+
// Interfaccia primaria
|
|
34314
34399
|
if (cfg.kind === 'contact')
|
|
34315
34400
|
interfaces.unshift(sdk_1.ScryptedInterface.EntrySensor);
|
|
34316
34401
|
else if (cfg.kind === 'motion')
|
|
34317
34402
|
interfaces.unshift(sdk_1.ScryptedInterface.MotionSensor);
|
|
34318
34403
|
else
|
|
34319
34404
|
interfaces.unshift(sdk_1.ScryptedInterface.OccupancySensor);
|
|
34320
|
-
//
|
|
34405
|
+
// Battery solo se previsto
|
|
34321
34406
|
if (t.batteryLevel || t.lowBattery) {
|
|
34322
34407
|
interfaces.push(sdk_1.ScryptedInterface.Battery);
|
|
34323
34408
|
}
|
|
34324
|
-
return {
|
|
34325
|
-
nativeId,
|
|
34326
|
-
name: cfg.name,
|
|
34327
|
-
type: sdk_1.ScryptedDeviceType.Sensor,
|
|
34328
|
-
interfaces,
|
|
34329
|
-
};
|
|
34409
|
+
return { nativeId, name: cfg.name, type: sdk_1.ScryptedDeviceType.Sensor, interfaces };
|
|
34330
34410
|
});
|
|
34331
|
-
// 2)
|
|
34411
|
+
// 2) Annuncio
|
|
34332
34412
|
const dmAny = deviceManager;
|
|
34333
34413
|
if (typeof dmAny.onDevicesChanged === 'function') {
|
|
34334
34414
|
dmAny.onDevicesChanged({ devices: manifests });
|
|
@@ -34340,7 +34420,7 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34340
34420
|
this.console.log('Annunciato:', m.nativeId);
|
|
34341
34421
|
}
|
|
34342
34422
|
}
|
|
34343
|
-
// 3) Istanzia/aggiorna
|
|
34423
|
+
// 3) Istanzia/aggiorna DOPO l’annuncio
|
|
34344
34424
|
for (const cfg of this.sensorsCfg) {
|
|
34345
34425
|
const nativeId = `sensor:${cfg.id}`;
|
|
34346
34426
|
let dev = this.devices.get(nativeId);
|
|
@@ -34356,6 +34436,11 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34356
34436
|
else {
|
|
34357
34437
|
dev.cfg = cfg;
|
|
34358
34438
|
}
|
|
34439
|
+
// Default “OK” se abbiamo Battery ma nessun valore ancora ricevuto
|
|
34440
|
+
const hasBattery = !!(cfg.topics.batteryLevel || cfg.topics.lowBattery);
|
|
34441
|
+
if (hasBattery && dev.batteryLevel === undefined) {
|
|
34442
|
+
dev.batteryLevel = 100;
|
|
34443
|
+
}
|
|
34359
34444
|
}
|
|
34360
34445
|
// 4) Rimuovi quelli spariti
|
|
34361
34446
|
const announced = new Set(manifests.map(m => m.nativeId));
|
|
@@ -34408,7 +34493,7 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34408
34493
|
}
|
|
34409
34494
|
return Array.from(subs);
|
|
34410
34495
|
}
|
|
34411
|
-
async connectMqtt(
|
|
34496
|
+
async connectMqtt(_reconnect = false) {
|
|
34412
34497
|
const subs = this.collectAllSubscriptions();
|
|
34413
34498
|
if (!subs.length && !this.storage.getItem('topicSetTarget')) {
|
|
34414
34499
|
this.console.warn('Configura almeno un topic nelle impostazioni.');
|
package/dist/plugin.zip
CHANGED
|
Binary file
|
package/package.json
CHANGED