@rfranzoi/scrypted-mqtt-securitysystem 1.0.15 → 1.0.18
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 +249 -31
- package/dist/plugin.zip +0 -0
- package/package.json +1 -1
package/dist/main.nodejs.js
CHANGED
|
@@ -34063,7 +34063,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
34063
34063
|
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
|
-
const { systemManager } = sdk_1.default;
|
|
34066
|
+
const { systemManager, deviceManager } = sdk_1.default;
|
|
34067
|
+
/** utils */
|
|
34067
34068
|
function truthy(v) {
|
|
34068
34069
|
if (!v)
|
|
34069
34070
|
return false;
|
|
@@ -34079,20 +34080,24 @@ function falsy(v) {
|
|
|
34079
34080
|
function normalize(s) {
|
|
34080
34081
|
return (s || '').trim().toLowerCase();
|
|
34081
34082
|
}
|
|
34082
|
-
|
|
34083
|
+
function clamp(n, min, max) {
|
|
34084
|
+
return Math.max(min, Math.min(max, n));
|
|
34085
|
+
}
|
|
34086
|
+
function delay(ms) {
|
|
34087
|
+
return new Promise(res => setTimeout(res, ms));
|
|
34088
|
+
}
|
|
34089
|
+
/** SecuritySystem outgoing defaults (PAI-like) */
|
|
34083
34090
|
const DEFAULT_OUTGOING = {
|
|
34084
34091
|
[sdk_1.SecuritySystemMode.Disarmed]: 'disarm',
|
|
34085
34092
|
[sdk_1.SecuritySystemMode.HomeArmed]: 'arm_home',
|
|
34086
34093
|
[sdk_1.SecuritySystemMode.AwayArmed]: 'arm_away',
|
|
34087
34094
|
[sdk_1.SecuritySystemMode.NightArmed]: 'arm_night',
|
|
34088
34095
|
};
|
|
34089
|
-
/**
|
|
34090
|
-
* (transitori non alterano la modalità corrente) */
|
|
34096
|
+
/** Parse incoming payload -> final mode (ignore transition states) */
|
|
34091
34097
|
function payloadToMode(payload) {
|
|
34092
34098
|
if (payload == null)
|
|
34093
34099
|
return;
|
|
34094
34100
|
const p = normalize(payload.toString());
|
|
34095
|
-
// final modes
|
|
34096
34101
|
if (['disarm', 'disarmed', 'off', '0', 'idle', 'ready'].includes(p))
|
|
34097
34102
|
return sdk_1.SecuritySystemMode.Disarmed;
|
|
34098
34103
|
if (['arm_home', 'home', 'stay', 'armed_home'].includes(p))
|
|
@@ -34106,9 +34111,83 @@ function payloadToMode(payload) {
|
|
|
34106
34111
|
return undefined;
|
|
34107
34112
|
return undefined;
|
|
34108
34113
|
}
|
|
34114
|
+
class BaseMqttSensor extends sdk_1.ScryptedDeviceBase {
|
|
34115
|
+
constructor(nativeId, cfg) {
|
|
34116
|
+
super(nativeId);
|
|
34117
|
+
this.cfg = cfg;
|
|
34118
|
+
this.online = this.online ?? true;
|
|
34119
|
+
}
|
|
34120
|
+
/** Called by parent on each MQTT message */
|
|
34121
|
+
handleMqtt(topic, payload) {
|
|
34122
|
+
const p = payload?.toString() ?? '';
|
|
34123
|
+
const np = normalize(p);
|
|
34124
|
+
// online
|
|
34125
|
+
if (topic === this.cfg.topics.online) {
|
|
34126
|
+
if (truthy(np) || np === 'online')
|
|
34127
|
+
this.online = true;
|
|
34128
|
+
if (falsy(np) || np === 'offline')
|
|
34129
|
+
this.online = false;
|
|
34130
|
+
}
|
|
34131
|
+
// tamper
|
|
34132
|
+
if (topic === this.cfg.topics.tamper) {
|
|
34133
|
+
if (truthy(np) || ['tamper', 'intrusion', 'cover', 'motion', 'magnetic'].includes(np)) {
|
|
34134
|
+
this.tampered = ['cover', 'intrusion', 'motion', 'magnetic'].find(x => x === np) || true;
|
|
34135
|
+
}
|
|
34136
|
+
else if (falsy(np)) {
|
|
34137
|
+
this.tampered = false;
|
|
34138
|
+
}
|
|
34139
|
+
}
|
|
34140
|
+
// battery
|
|
34141
|
+
if (topic === this.cfg.topics.batteryLevel) {
|
|
34142
|
+
const n = clamp(parseFloat(p), 0, 100);
|
|
34143
|
+
if (isFinite(n))
|
|
34144
|
+
this.batteryLevel = n;
|
|
34145
|
+
}
|
|
34146
|
+
else if (topic === this.cfg.topics.lowBattery && !this.cfg.topics.batteryLevel) {
|
|
34147
|
+
// sintetizza se non c'è batteryLevel
|
|
34148
|
+
this.batteryLevel = truthy(np) ? 10 : 100;
|
|
34149
|
+
}
|
|
34150
|
+
// primary handled by subclasses
|
|
34151
|
+
this.handlePrimary(topic, np, p);
|
|
34152
|
+
}
|
|
34153
|
+
}
|
|
34154
|
+
class ContactMqttSensor extends BaseMqttSensor {
|
|
34155
|
+
constructor(nativeId, cfg) {
|
|
34156
|
+
super(nativeId, cfg);
|
|
34157
|
+
}
|
|
34158
|
+
handlePrimary(topic, np, _raw) {
|
|
34159
|
+
if (topic === this.cfg.topics.contact) {
|
|
34160
|
+
this.entryOpen = truthy(np);
|
|
34161
|
+
}
|
|
34162
|
+
}
|
|
34163
|
+
}
|
|
34164
|
+
class MotionMqttSensor extends BaseMqttSensor {
|
|
34165
|
+
constructor(nativeId, cfg) {
|
|
34166
|
+
super(nativeId, cfg);
|
|
34167
|
+
}
|
|
34168
|
+
handlePrimary(topic, np, _raw) {
|
|
34169
|
+
if (topic === this.cfg.topics.motion) {
|
|
34170
|
+
this.motionDetected = truthy(np);
|
|
34171
|
+
}
|
|
34172
|
+
}
|
|
34173
|
+
}
|
|
34174
|
+
class OccupancyMqttSensor extends BaseMqttSensor {
|
|
34175
|
+
constructor(nativeId, cfg) {
|
|
34176
|
+
super(nativeId, cfg);
|
|
34177
|
+
}
|
|
34178
|
+
handlePrimary(topic, np, _raw) {
|
|
34179
|
+
if (topic === this.cfg.topics.occupancy) {
|
|
34180
|
+
this.occupied = truthy(np);
|
|
34181
|
+
}
|
|
34182
|
+
}
|
|
34183
|
+
}
|
|
34184
|
+
/** ----------------- Main Plugin ----------------- */
|
|
34109
34185
|
class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
34110
34186
|
constructor() {
|
|
34111
34187
|
super();
|
|
34188
|
+
// sensor management
|
|
34189
|
+
this.sensorsCfg = [];
|
|
34190
|
+
this.devices = new Map();
|
|
34112
34191
|
// (facoltativo) Imposta il device type in UI
|
|
34113
34192
|
setTimeout(() => {
|
|
34114
34193
|
try {
|
|
@@ -34127,6 +34206,9 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34127
34206
|
],
|
|
34128
34207
|
};
|
|
34129
34208
|
this.online = this.online ?? false;
|
|
34209
|
+
// Load sensors config and announce devices
|
|
34210
|
+
this.loadSensorsFromStorage();
|
|
34211
|
+
this.discoverSensors();
|
|
34130
34212
|
// Connect on start
|
|
34131
34213
|
this.connectMqtt().catch(e => this.console.error('MQTT connect error:', e));
|
|
34132
34214
|
// chiusura pulita del client MQTT ai reload/stop del plugin
|
|
@@ -34146,33 +34228,152 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34146
34228
|
}
|
|
34147
34229
|
catch { }
|
|
34148
34230
|
}
|
|
34149
|
-
|
|
34231
|
+
/** ---- Settings UI ---- */
|
|
34150
34232
|
async getSettings() {
|
|
34151
34233
|
return [
|
|
34234
|
+
// MQTT Core
|
|
34152
34235
|
{ 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' },
|
|
34153
34236
|
{ group: 'MQTT', key: 'username', title: 'Username', type: 'string', value: this.storage.getItem('username') || '' },
|
|
34154
34237
|
{ group: 'MQTT', key: 'password', title: 'Password', type: 'password', value: this.storage.getItem('password') || '' },
|
|
34155
34238
|
{ group: 'MQTT', key: 'clientId', title: 'Client ID', placeholder: 'scrypted-paradox', value: this.storage.getItem('clientId') || 'scrypted-paradox' },
|
|
34156
34239
|
{ group: 'MQTT', key: 'tls', title: 'Use TLS', type: 'boolean', value: this.storage.getItem('tls') === 'true' },
|
|
34157
34240
|
{ group: 'MQTT', key: 'rejectUnauthorized', title: 'Reject Unauthorized (TLS)', type: 'boolean', value: this.storage.getItem('rejectUnauthorized') !== 'false', description: 'Disattiva solo con broker self-signed.' },
|
|
34158
|
-
|
|
34159
|
-
{ group: 'Topics', key: '
|
|
34160
|
-
{ group: 'Topics', key: '
|
|
34161
|
-
{ group: 'Topics', key: '
|
|
34162
|
-
{ group: 'Topics', key: '
|
|
34241
|
+
// Alarm Topics
|
|
34242
|
+
{ group: 'Alarm Topics', key: 'topicSetTarget', title: 'Set Target State (publish)', placeholder: 'paradox/control/partitions/Area_1', value: this.storage.getItem('topicSetTarget') || '' },
|
|
34243
|
+
{ group: 'Alarm Topics', key: 'topicGetTarget', title: 'Get Target State (subscribe)', placeholder: 'paradox/states/partitions/Area_1/target_state', value: this.storage.getItem('topicGetTarget') || '' },
|
|
34244
|
+
{ group: 'Alarm Topics', key: 'topicGetCurrent', title: 'Get Current State (subscribe)', placeholder: 'paradox/states/partitions/Area_1/current_state', value: this.storage.getItem('topicGetCurrent') || '' },
|
|
34245
|
+
{ group: 'Alarm Topics', key: 'topicTamper', title: 'Get Status Tampered (subscribe)', placeholder: 'paradox/states/system/troubles/zone_tamper_trouble', value: this.storage.getItem('topicTamper') || '' },
|
|
34246
|
+
{ group: 'Alarm Topics', key: 'topicOnline', title: 'Get Online (subscribe)', placeholder: 'paradox/interface/availability', value: this.storage.getItem('topicOnline') || '' },
|
|
34163
34247
|
{ group: 'Publish Options', key: 'qos', title: 'QoS', type: 'integer', value: parseInt(this.storage.getItem('qos') || '0') },
|
|
34164
34248
|
{ group: 'Publish Options', key: 'retain', title: 'Retain', type: 'boolean', value: this.storage.getItem('retain') === 'true' },
|
|
34165
34249
|
{ group: 'Outgoing Payloads', key: 'payloadDisarm', title: 'Payload Disarm', value: this.storage.getItem('payloadDisarm') || DEFAULT_OUTGOING[sdk_1.SecuritySystemMode.Disarmed] },
|
|
34166
34250
|
{ group: 'Outgoing Payloads', key: 'payloadHome', title: 'Payload HomeArmed', value: this.storage.getItem('payloadHome') || DEFAULT_OUTGOING[sdk_1.SecuritySystemMode.HomeArmed] },
|
|
34167
34251
|
{ group: 'Outgoing Payloads', key: 'payloadAway', title: 'Payload AwayArmed', value: this.storage.getItem('payloadAway') || DEFAULT_OUTGOING[sdk_1.SecuritySystemMode.AwayArmed] },
|
|
34168
34252
|
{ group: 'Outgoing Payloads', key: 'payloadNight', title: 'Payload NightArmed', value: this.storage.getItem('payloadNight') || DEFAULT_OUTGOING[sdk_1.SecuritySystemMode.NightArmed] },
|
|
34253
|
+
// Sensors config (JSON)
|
|
34254
|
+
{
|
|
34255
|
+
group: 'Sensors',
|
|
34256
|
+
key: 'sensorsJson',
|
|
34257
|
+
title: 'Sensors JSON (contact/motion/occupancy)',
|
|
34258
|
+
description: 'Definisci i sensori e i topic MQTT (vedi README). Incolla JSON; le interruzioni di riga sono accettate.',
|
|
34259
|
+
type: 'string',
|
|
34260
|
+
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]'
|
|
34261
|
+
},
|
|
34169
34262
|
];
|
|
34170
34263
|
}
|
|
34171
34264
|
async putSetting(key, value) {
|
|
34172
34265
|
this.storage.setItem(key, String(value));
|
|
34173
|
-
|
|
34266
|
+
if (key === 'sensorsJson') {
|
|
34267
|
+
this.loadSensorsFromStorage();
|
|
34268
|
+
await this.discoverSensors();
|
|
34269
|
+
await this.connectMqtt(true);
|
|
34270
|
+
}
|
|
34271
|
+
else {
|
|
34272
|
+
await this.connectMqtt(true);
|
|
34273
|
+
}
|
|
34274
|
+
}
|
|
34275
|
+
/** ---- DeviceProvider ---- */
|
|
34276
|
+
async getDevice(nativeId) {
|
|
34277
|
+
return this.devices.get(nativeId);
|
|
34278
|
+
}
|
|
34279
|
+
async releaseDevice(id, nativeId) {
|
|
34280
|
+
try {
|
|
34281
|
+
const dev = this.devices.get(nativeId);
|
|
34282
|
+
if (dev) {
|
|
34283
|
+
this.devices.delete(nativeId);
|
|
34284
|
+
}
|
|
34285
|
+
try {
|
|
34286
|
+
deviceManager.onDeviceRemoved?.(nativeId);
|
|
34287
|
+
}
|
|
34288
|
+
catch { }
|
|
34289
|
+
}
|
|
34290
|
+
catch (e) {
|
|
34291
|
+
this.console.warn('releaseDevice error', e);
|
|
34292
|
+
}
|
|
34293
|
+
}
|
|
34294
|
+
loadSensorsFromStorage() {
|
|
34295
|
+
try {
|
|
34296
|
+
const raw = this.storage.getItem('sensorsJson') || '[]';
|
|
34297
|
+
const parsed = JSON.parse(raw);
|
|
34298
|
+
// sanitize
|
|
34299
|
+
this.sensorsCfg = (parsed || []).filter(x => x && x.id && x.name && x.kind && x.topics);
|
|
34300
|
+
}
|
|
34301
|
+
catch (e) {
|
|
34302
|
+
this.console.error('Invalid sensorsJson:', e);
|
|
34303
|
+
this.sensorsCfg = [];
|
|
34304
|
+
}
|
|
34305
|
+
}
|
|
34306
|
+
/** ===== discoverSensors con batch/fallback (FIX type) ===== */
|
|
34307
|
+
async discoverSensors() {
|
|
34308
|
+
// Prepara i manifest e istanzia/aggiorna le classi locali
|
|
34309
|
+
const manifests = this.sensorsCfg.map(cfg => {
|
|
34310
|
+
const nativeId = `sensor:${cfg.id}`;
|
|
34311
|
+
let interfaces = [
|
|
34312
|
+
sdk_1.ScryptedInterface.Online,
|
|
34313
|
+
sdk_1.ScryptedInterface.TamperSensor,
|
|
34314
|
+
sdk_1.ScryptedInterface.Battery,
|
|
34315
|
+
];
|
|
34316
|
+
// Il tipo RESTA generico "Sensor" per compatibilità SDK,
|
|
34317
|
+
// le capacità sono date dalle interfacce.
|
|
34318
|
+
const type = sdk_1.ScryptedDeviceType.Sensor;
|
|
34319
|
+
switch (cfg.kind) {
|
|
34320
|
+
case 'contact':
|
|
34321
|
+
interfaces = [sdk_1.ScryptedInterface.EntrySensor, ...interfaces];
|
|
34322
|
+
break;
|
|
34323
|
+
case 'motion':
|
|
34324
|
+
interfaces = [sdk_1.ScryptedInterface.MotionSensor, ...interfaces];
|
|
34325
|
+
break;
|
|
34326
|
+
case 'occupancy':
|
|
34327
|
+
interfaces = [sdk_1.ScryptedInterface.OccupancySensor, ...interfaces];
|
|
34328
|
+
break;
|
|
34329
|
+
}
|
|
34330
|
+
let dev = this.devices.get(nativeId);
|
|
34331
|
+
if (!dev) {
|
|
34332
|
+
if (cfg.kind === 'contact')
|
|
34333
|
+
dev = new ContactMqttSensor(nativeId, cfg);
|
|
34334
|
+
else if (cfg.kind === 'motion')
|
|
34335
|
+
dev = new MotionMqttSensor(nativeId, cfg);
|
|
34336
|
+
else
|
|
34337
|
+
dev = new OccupancyMqttSensor(nativeId, cfg);
|
|
34338
|
+
this.devices.set(nativeId, dev);
|
|
34339
|
+
}
|
|
34340
|
+
else {
|
|
34341
|
+
dev.cfg = cfg;
|
|
34342
|
+
}
|
|
34343
|
+
return {
|
|
34344
|
+
nativeId,
|
|
34345
|
+
name: cfg.name,
|
|
34346
|
+
type,
|
|
34347
|
+
interfaces,
|
|
34348
|
+
};
|
|
34349
|
+
});
|
|
34350
|
+
// Annuncio in batch se disponibile, altrimenti uno per volta con un piccolo delay
|
|
34351
|
+
const dm = deviceManager;
|
|
34352
|
+
if (typeof dm.onDevicesChanged === 'function') {
|
|
34353
|
+
dm.onDevicesChanged({ devices: manifests });
|
|
34354
|
+
this.console.log('Annunciati (batch):', manifests.map(m => m.nativeId).join(', '));
|
|
34355
|
+
}
|
|
34356
|
+
else {
|
|
34357
|
+
for (const m of manifests) {
|
|
34358
|
+
deviceManager.onDeviceDiscovered(m);
|
|
34359
|
+
this.console.log('Annunciato:', m.nativeId);
|
|
34360
|
+
await new Promise(res => setTimeout(res, 50));
|
|
34361
|
+
}
|
|
34362
|
+
}
|
|
34363
|
+
// Rimuovi eventuali sensori non più presenti
|
|
34364
|
+
const announced = new Set(manifests.map(m => m.nativeId));
|
|
34365
|
+
for (const [nativeId] of this.devices) {
|
|
34366
|
+
if (!announced.has(nativeId)) {
|
|
34367
|
+
try {
|
|
34368
|
+
this.devices.delete(nativeId);
|
|
34369
|
+
deviceManager.onDeviceRemoved?.(nativeId);
|
|
34370
|
+
this.console.log('Rimosso:', nativeId);
|
|
34371
|
+
}
|
|
34372
|
+
catch { }
|
|
34373
|
+
}
|
|
34374
|
+
}
|
|
34174
34375
|
}
|
|
34175
|
-
|
|
34376
|
+
/** ---- MQTT ---- */
|
|
34176
34377
|
getMqttOptions() {
|
|
34177
34378
|
const url = this.storage.getItem('brokerUrl') || 'mqtt://127.0.0.1:1883';
|
|
34178
34379
|
const username = this.storage.getItem('username') || undefined;
|
|
@@ -34193,12 +34394,25 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34193
34394
|
}
|
|
34194
34395
|
return { url, opts };
|
|
34195
34396
|
}
|
|
34397
|
+
collectAllSubscriptions() {
|
|
34398
|
+
const subs = new Set();
|
|
34399
|
+
// alarm
|
|
34400
|
+
for (const k of ['topicGetTarget', 'topicGetCurrent', 'topicTamper', 'topicOnline']) {
|
|
34401
|
+
const v = this.storage.getItem(k);
|
|
34402
|
+
if (v)
|
|
34403
|
+
subs.add(v);
|
|
34404
|
+
}
|
|
34405
|
+
// sensors
|
|
34406
|
+
for (const s of this.sensorsCfg) {
|
|
34407
|
+
const t = s.topics;
|
|
34408
|
+
[t.contact, t.motion, t.occupancy, t.batteryLevel, t.lowBattery, t.tamper, t.online]
|
|
34409
|
+
.filter(Boolean)
|
|
34410
|
+
.forEach(x => subs.add(String(x)));
|
|
34411
|
+
}
|
|
34412
|
+
return Array.from(subs);
|
|
34413
|
+
}
|
|
34196
34414
|
async connectMqtt(reconnect = false) {
|
|
34197
|
-
const
|
|
34198
|
-
const tCurrent = this.storage.getItem('topicGetCurrent') || '';
|
|
34199
|
-
const tTamper = this.storage.getItem('topicTamper') || '';
|
|
34200
|
-
const tOnline = this.storage.getItem('topicOnline') || '';
|
|
34201
|
-
const subs = [tTarget, tCurrent, tTamper, tOnline].filter(Boolean);
|
|
34415
|
+
const subs = this.collectAllSubscriptions();
|
|
34202
34416
|
if (!subs.length && !this.storage.getItem('topicSetTarget')) {
|
|
34203
34417
|
this.console.warn('Configura almeno un topic nelle impostazioni.');
|
|
34204
34418
|
}
|
|
@@ -34213,6 +34427,11 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34213
34427
|
this.console.log(`Connecting MQTT ${url} ...`);
|
|
34214
34428
|
const client = mqtt_1.default.connect(url, opts);
|
|
34215
34429
|
this.client = client;
|
|
34430
|
+
// cache alarm topics for fast compare
|
|
34431
|
+
const tTarget = this.storage.getItem('topicGetTarget') || '';
|
|
34432
|
+
const tCurrent = this.storage.getItem('topicGetCurrent') || '';
|
|
34433
|
+
const tTamper = this.storage.getItem('topicTamper') || '';
|
|
34434
|
+
const tOnline = this.storage.getItem('topicOnline') || '';
|
|
34216
34435
|
client.on('connect', () => {
|
|
34217
34436
|
this.console.log('MQTT connected');
|
|
34218
34437
|
this.online = true;
|
|
@@ -34229,29 +34448,27 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34229
34448
|
client.on('message', (topic, payload) => {
|
|
34230
34449
|
try {
|
|
34231
34450
|
const p = payload?.toString() ?? '';
|
|
34232
|
-
|
|
34451
|
+
const np = normalize(p);
|
|
34452
|
+
// ---- Alarm handling ----
|
|
34233
34453
|
if (topic === tOnline) {
|
|
34234
|
-
if (truthy(
|
|
34454
|
+
if (truthy(np) || np === 'online')
|
|
34235
34455
|
this.online = true;
|
|
34236
|
-
if (falsy(
|
|
34456
|
+
if (falsy(np) || np === 'offline')
|
|
34237
34457
|
this.online = false;
|
|
34238
34458
|
return;
|
|
34239
34459
|
}
|
|
34240
|
-
// Tamper
|
|
34241
34460
|
if (topic === tTamper) {
|
|
34242
|
-
|
|
34243
|
-
|
|
34244
|
-
this.tampered = ['cover', 'intrusion', 'motion', 'magnetic'].find(x => x === np) || true;
|
|
34461
|
+
if (truthy(np) || ['tamper', 'intrusion', 'cover'].includes(np)) {
|
|
34462
|
+
this.tampered = ['cover', 'intrusion'].find(x => x === np) || true;
|
|
34245
34463
|
}
|
|
34246
34464
|
else if (falsy(np)) {
|
|
34247
34465
|
this.tampered = false;
|
|
34248
34466
|
}
|
|
34249
34467
|
return;
|
|
34250
34468
|
}
|
|
34251
|
-
// CURRENT state → aggiorna il mode mostrato
|
|
34252
34469
|
if (topic === tCurrent) {
|
|
34253
34470
|
const mode = payloadToMode(payload);
|
|
34254
|
-
const isAlarm = ['alarm', 'triggered'].includes(
|
|
34471
|
+
const isAlarm = ['alarm', 'triggered'].includes(np);
|
|
34255
34472
|
const current = this.securitySystemState || { mode: sdk_1.SecuritySystemMode.Disarmed };
|
|
34256
34473
|
const newState = {
|
|
34257
34474
|
mode: mode ?? current.mode,
|
|
@@ -34266,19 +34483,22 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34266
34483
|
this.securitySystemState = newState;
|
|
34267
34484
|
return;
|
|
34268
34485
|
}
|
|
34269
|
-
// TARGET state → NON cambia il mode; lo memorizziamo solo come pending
|
|
34270
34486
|
if (topic === tTarget) {
|
|
34271
34487
|
this.pendingTarget = payloadToMode(payload);
|
|
34272
34488
|
this.console.log('Target state reported:', p, '->', this.pendingTarget);
|
|
34273
34489
|
return;
|
|
34274
34490
|
}
|
|
34491
|
+
// ---- Sensor dispatch ----
|
|
34492
|
+
for (const dev of this.devices.values()) {
|
|
34493
|
+
dev.handleMqtt(topic, payload);
|
|
34494
|
+
}
|
|
34275
34495
|
}
|
|
34276
34496
|
catch (e) {
|
|
34277
34497
|
this.console.error('MQTT message handler error', e);
|
|
34278
34498
|
}
|
|
34279
34499
|
});
|
|
34280
34500
|
}
|
|
34281
|
-
|
|
34501
|
+
/** ---- SecuritySystem commands ---- */
|
|
34282
34502
|
publishSetTarget(payload) {
|
|
34283
34503
|
const topic = this.storage.getItem('topicSetTarget');
|
|
34284
34504
|
if (!topic || !this.client) {
|
|
@@ -34298,14 +34518,12 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34298
34518
|
this.console.log('armSecuritySystem', mode, '->', payload);
|
|
34299
34519
|
this.pendingTarget = mode; // memorizza target, ma NON cambiare il current
|
|
34300
34520
|
this.publishSetTarget(payload);
|
|
34301
|
-
// niente update ottimistico: HomeKit vedrà Target ≠ Current e mostrerà "Arming..."
|
|
34302
34521
|
}
|
|
34303
34522
|
async disarmSecuritySystem() {
|
|
34304
34523
|
const payload = this.getOutgoing(sdk_1.SecuritySystemMode.Disarmed);
|
|
34305
34524
|
this.console.log('disarmSecuritySystem ->', payload);
|
|
34306
34525
|
this.pendingTarget = sdk_1.SecuritySystemMode.Disarmed;
|
|
34307
34526
|
this.publishSetTarget(payload);
|
|
34308
|
-
// niente update ottimistico: aspetta il feedback CURRENT
|
|
34309
34527
|
}
|
|
34310
34528
|
getOutgoing(mode) {
|
|
34311
34529
|
const map = {
|
package/dist/plugin.zip
CHANGED
|
Binary file
|
package/package.json
CHANGED