@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.
- package/dist/main.nodejs.js +81 -96
- package/dist/plugin.zip +0 -0
- package/package.json +1 -1
package/dist/main.nodejs.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
/**
|
|
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
|
-
//
|
|
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
|
|
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
|
|
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
|
|
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
|
-
/**
|
|
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
|
-
|
|
34302
|
-
case sdk_1.SecuritySystemMode.
|
|
34303
|
-
|
|
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: '
|
|
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
|
-
|
|
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
|
-
//
|
|
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)
|
|
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
|
-
|
|
34496
|
-
|
|
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)
|
|
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)
|
|
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
|
-
//
|
|
34530
|
-
const hasBattery = !!(cfg.topics.batteryLevel && cfg.topics.batteryLevel.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)
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
/**
|
|
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;
|
|
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