@rfranzoi/scrypted-mqtt-securitysystem 1.0.15 → 1.0.17
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 +228 -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,21 @@ 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
|
+
/** SecuritySystem outgoing defaults (PAI-like) */
|
|
34083
34087
|
const DEFAULT_OUTGOING = {
|
|
34084
34088
|
[sdk_1.SecuritySystemMode.Disarmed]: 'disarm',
|
|
34085
34089
|
[sdk_1.SecuritySystemMode.HomeArmed]: 'arm_home',
|
|
34086
34090
|
[sdk_1.SecuritySystemMode.AwayArmed]: 'arm_away',
|
|
34087
34091
|
[sdk_1.SecuritySystemMode.NightArmed]: 'arm_night',
|
|
34088
34092
|
};
|
|
34089
|
-
/**
|
|
34090
|
-
* (transitori non alterano la modalità corrente) */
|
|
34093
|
+
/** Parse incoming payload -> final mode (ignore transition states) */
|
|
34091
34094
|
function payloadToMode(payload) {
|
|
34092
34095
|
if (payload == null)
|
|
34093
34096
|
return;
|
|
34094
34097
|
const p = normalize(payload.toString());
|
|
34095
|
-
// final modes
|
|
34096
34098
|
if (['disarm', 'disarmed', 'off', '0', 'idle', 'ready'].includes(p))
|
|
34097
34099
|
return sdk_1.SecuritySystemMode.Disarmed;
|
|
34098
34100
|
if (['arm_home', 'home', 'stay', 'armed_home'].includes(p))
|
|
@@ -34106,9 +34108,83 @@ function payloadToMode(payload) {
|
|
|
34106
34108
|
return undefined;
|
|
34107
34109
|
return undefined;
|
|
34108
34110
|
}
|
|
34111
|
+
class BaseMqttSensor extends sdk_1.ScryptedDeviceBase {
|
|
34112
|
+
constructor(nativeId, cfg) {
|
|
34113
|
+
super(nativeId);
|
|
34114
|
+
this.cfg = cfg;
|
|
34115
|
+
this.online = this.online ?? true;
|
|
34116
|
+
}
|
|
34117
|
+
/** Called by parent on each MQTT message */
|
|
34118
|
+
handleMqtt(topic, payload) {
|
|
34119
|
+
const p = payload?.toString() ?? '';
|
|
34120
|
+
const np = normalize(p);
|
|
34121
|
+
// online
|
|
34122
|
+
if (topic === this.cfg.topics.online) {
|
|
34123
|
+
if (truthy(np) || np === 'online')
|
|
34124
|
+
this.online = true;
|
|
34125
|
+
if (falsy(np) || np === 'offline')
|
|
34126
|
+
this.online = false;
|
|
34127
|
+
}
|
|
34128
|
+
// tamper
|
|
34129
|
+
if (topic === this.cfg.topics.tamper) {
|
|
34130
|
+
if (truthy(np) || ['tamper', 'intrusion', 'cover', 'motion', 'magnetic'].includes(np)) {
|
|
34131
|
+
this.tampered = ['cover', 'intrusion', 'motion', 'magnetic'].find(x => x === np) || true;
|
|
34132
|
+
}
|
|
34133
|
+
else if (falsy(np)) {
|
|
34134
|
+
this.tampered = false;
|
|
34135
|
+
}
|
|
34136
|
+
}
|
|
34137
|
+
// battery
|
|
34138
|
+
if (topic === this.cfg.topics.batteryLevel) {
|
|
34139
|
+
const n = clamp(parseFloat(p), 0, 100);
|
|
34140
|
+
if (isFinite(n))
|
|
34141
|
+
this.batteryLevel = n;
|
|
34142
|
+
}
|
|
34143
|
+
else if (topic === this.cfg.topics.lowBattery && !this.cfg.topics.batteryLevel) {
|
|
34144
|
+
// sintetizza se non c'è batteryLevel
|
|
34145
|
+
this.batteryLevel = truthy(np) ? 10 : 100;
|
|
34146
|
+
}
|
|
34147
|
+
// primary handled by subclasses
|
|
34148
|
+
this.handlePrimary(topic, np, p);
|
|
34149
|
+
}
|
|
34150
|
+
}
|
|
34151
|
+
class ContactMqttSensor extends BaseMqttSensor {
|
|
34152
|
+
constructor(nativeId, cfg) {
|
|
34153
|
+
super(nativeId, cfg);
|
|
34154
|
+
}
|
|
34155
|
+
handlePrimary(topic, np, _raw) {
|
|
34156
|
+
if (topic === this.cfg.topics.contact) {
|
|
34157
|
+
this.entryOpen = truthy(np);
|
|
34158
|
+
}
|
|
34159
|
+
}
|
|
34160
|
+
}
|
|
34161
|
+
class MotionMqttSensor extends BaseMqttSensor {
|
|
34162
|
+
constructor(nativeId, cfg) {
|
|
34163
|
+
super(nativeId, cfg);
|
|
34164
|
+
}
|
|
34165
|
+
handlePrimary(topic, np, _raw) {
|
|
34166
|
+
if (topic === this.cfg.topics.motion) {
|
|
34167
|
+
this.motionDetected = truthy(np);
|
|
34168
|
+
}
|
|
34169
|
+
}
|
|
34170
|
+
}
|
|
34171
|
+
class OccupancyMqttSensor extends BaseMqttSensor {
|
|
34172
|
+
constructor(nativeId, cfg) {
|
|
34173
|
+
super(nativeId, cfg);
|
|
34174
|
+
}
|
|
34175
|
+
handlePrimary(topic, np, _raw) {
|
|
34176
|
+
if (topic === this.cfg.topics.occupancy) {
|
|
34177
|
+
this.occupied = truthy(np);
|
|
34178
|
+
}
|
|
34179
|
+
}
|
|
34180
|
+
}
|
|
34181
|
+
/** ----------------- Main Plugin ----------------- */
|
|
34109
34182
|
class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
34110
34183
|
constructor() {
|
|
34111
34184
|
super();
|
|
34185
|
+
// sensor management
|
|
34186
|
+
this.sensorsCfg = [];
|
|
34187
|
+
this.devices = new Map();
|
|
34112
34188
|
// (facoltativo) Imposta il device type in UI
|
|
34113
34189
|
setTimeout(() => {
|
|
34114
34190
|
try {
|
|
@@ -34127,6 +34203,9 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34127
34203
|
],
|
|
34128
34204
|
};
|
|
34129
34205
|
this.online = this.online ?? false;
|
|
34206
|
+
// Load sensors config and announce devices
|
|
34207
|
+
this.loadSensorsFromStorage();
|
|
34208
|
+
this.discoverSensors();
|
|
34130
34209
|
// Connect on start
|
|
34131
34210
|
this.connectMqtt().catch(e => this.console.error('MQTT connect error:', e));
|
|
34132
34211
|
// chiusura pulita del client MQTT ai reload/stop del plugin
|
|
@@ -34146,33 +34225,134 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34146
34225
|
}
|
|
34147
34226
|
catch { }
|
|
34148
34227
|
}
|
|
34149
|
-
|
|
34228
|
+
/** ---- Settings UI ---- */
|
|
34150
34229
|
async getSettings() {
|
|
34151
34230
|
return [
|
|
34231
|
+
// MQTT Core
|
|
34152
34232
|
{ 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
34233
|
{ group: 'MQTT', key: 'username', title: 'Username', type: 'string', value: this.storage.getItem('username') || '' },
|
|
34154
34234
|
{ group: 'MQTT', key: 'password', title: 'Password', type: 'password', value: this.storage.getItem('password') || '' },
|
|
34155
34235
|
{ group: 'MQTT', key: 'clientId', title: 'Client ID', placeholder: 'scrypted-paradox', value: this.storage.getItem('clientId') || 'scrypted-paradox' },
|
|
34156
34236
|
{ group: 'MQTT', key: 'tls', title: 'Use TLS', type: 'boolean', value: this.storage.getItem('tls') === 'true' },
|
|
34157
34237
|
{ 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: '
|
|
34238
|
+
// Alarm Topics
|
|
34239
|
+
{ group: 'Alarm Topics', key: 'topicSetTarget', title: 'Set Target State (publish)', placeholder: 'paradox/control/partitions/Area_1', value: this.storage.getItem('topicSetTarget') || '' },
|
|
34240
|
+
{ group: 'Alarm Topics', key: 'topicGetTarget', title: 'Get Target State (subscribe)', placeholder: 'paradox/states/partitions/Area_1/target_state', value: this.storage.getItem('topicGetTarget') || '' },
|
|
34241
|
+
{ group: 'Alarm Topics', key: 'topicGetCurrent', title: 'Get Current State (subscribe)', placeholder: 'paradox/states/partitions/Area_1/current_state', value: this.storage.getItem('topicGetCurrent') || '' },
|
|
34242
|
+
{ group: 'Alarm Topics', key: 'topicTamper', title: 'Get Status Tampered (subscribe)', placeholder: 'paradox/states/system/troubles/zone_tamper_trouble', value: this.storage.getItem('topicTamper') || '' },
|
|
34243
|
+
{ group: 'Alarm Topics', key: 'topicOnline', title: 'Get Online (subscribe)', placeholder: 'paradox/interface/availability', value: this.storage.getItem('topicOnline') || '' },
|
|
34163
34244
|
{ group: 'Publish Options', key: 'qos', title: 'QoS', type: 'integer', value: parseInt(this.storage.getItem('qos') || '0') },
|
|
34164
34245
|
{ group: 'Publish Options', key: 'retain', title: 'Retain', type: 'boolean', value: this.storage.getItem('retain') === 'true' },
|
|
34165
34246
|
{ group: 'Outgoing Payloads', key: 'payloadDisarm', title: 'Payload Disarm', value: this.storage.getItem('payloadDisarm') || DEFAULT_OUTGOING[sdk_1.SecuritySystemMode.Disarmed] },
|
|
34166
34247
|
{ group: 'Outgoing Payloads', key: 'payloadHome', title: 'Payload HomeArmed', value: this.storage.getItem('payloadHome') || DEFAULT_OUTGOING[sdk_1.SecuritySystemMode.HomeArmed] },
|
|
34167
34248
|
{ group: 'Outgoing Payloads', key: 'payloadAway', title: 'Payload AwayArmed', value: this.storage.getItem('payloadAway') || DEFAULT_OUTGOING[sdk_1.SecuritySystemMode.AwayArmed] },
|
|
34168
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
|
+
},
|
|
34169
34259
|
];
|
|
34170
34260
|
}
|
|
34171
34261
|
async putSetting(key, value) {
|
|
34172
34262
|
this.storage.setItem(key, String(value));
|
|
34173
|
-
|
|
34263
|
+
if (key === 'sensorsJson') {
|
|
34264
|
+
this.loadSensorsFromStorage();
|
|
34265
|
+
await this.discoverSensors();
|
|
34266
|
+
await this.connectMqtt(true);
|
|
34267
|
+
}
|
|
34268
|
+
else {
|
|
34269
|
+
await this.connectMqtt(true);
|
|
34270
|
+
}
|
|
34271
|
+
}
|
|
34272
|
+
/** ---- DeviceProvider ---- */
|
|
34273
|
+
async getDevice(nativeId) {
|
|
34274
|
+
return this.devices.get(nativeId);
|
|
34174
34275
|
}
|
|
34175
|
-
|
|
34276
|
+
async releaseDevice(id, nativeId) {
|
|
34277
|
+
try {
|
|
34278
|
+
// chiudi e rimuovi l’istanza locale se esiste
|
|
34279
|
+
const dev = this.devices.get(nativeId);
|
|
34280
|
+
if (dev) {
|
|
34281
|
+
this.devices.delete(nativeId);
|
|
34282
|
+
}
|
|
34283
|
+
// notifica (best effort) la rimozione al device manager
|
|
34284
|
+
try {
|
|
34285
|
+
deviceManager.onDeviceRemoved?.(nativeId);
|
|
34286
|
+
}
|
|
34287
|
+
catch { }
|
|
34288
|
+
}
|
|
34289
|
+
catch (e) {
|
|
34290
|
+
this.console.warn('releaseDevice error', e);
|
|
34291
|
+
}
|
|
34292
|
+
}
|
|
34293
|
+
loadSensorsFromStorage() {
|
|
34294
|
+
try {
|
|
34295
|
+
const raw = this.storage.getItem('sensorsJson') || '[]';
|
|
34296
|
+
const parsed = JSON.parse(raw);
|
|
34297
|
+
// sanitize
|
|
34298
|
+
this.sensorsCfg = (parsed || []).filter(x => x && x.id && x.name && x.kind && x.topics);
|
|
34299
|
+
}
|
|
34300
|
+
catch (e) {
|
|
34301
|
+
this.console.error('Invalid sensorsJson:', e);
|
|
34302
|
+
this.sensorsCfg = [];
|
|
34303
|
+
}
|
|
34304
|
+
}
|
|
34305
|
+
async discoverSensors() {
|
|
34306
|
+
const announced = new Set();
|
|
34307
|
+
for (const cfg of this.sensorsCfg) {
|
|
34308
|
+
const nativeId = `sensor:${cfg.id}`;
|
|
34309
|
+
announced.add(nativeId);
|
|
34310
|
+
let interfaces = [sdk_1.ScryptedInterface.Online, sdk_1.ScryptedInterface.TamperSensor, sdk_1.ScryptedInterface.Battery];
|
|
34311
|
+
switch (cfg.kind) {
|
|
34312
|
+
case 'contact':
|
|
34313
|
+
interfaces = [sdk_1.ScryptedInterface.EntrySensor, ...interfaces];
|
|
34314
|
+
break;
|
|
34315
|
+
case 'motion':
|
|
34316
|
+
interfaces = [sdk_1.ScryptedInterface.MotionSensor, ...interfaces];
|
|
34317
|
+
break;
|
|
34318
|
+
case 'occupancy':
|
|
34319
|
+
interfaces = [sdk_1.ScryptedInterface.OccupancySensor, ...interfaces];
|
|
34320
|
+
break;
|
|
34321
|
+
}
|
|
34322
|
+
deviceManager.onDeviceDiscovered({
|
|
34323
|
+
nativeId,
|
|
34324
|
+
name: cfg.name,
|
|
34325
|
+
type: sdk_1.ScryptedDeviceType.Sensor,
|
|
34326
|
+
interfaces,
|
|
34327
|
+
});
|
|
34328
|
+
// create/update instance
|
|
34329
|
+
let dev = this.devices.get(nativeId);
|
|
34330
|
+
if (!dev) {
|
|
34331
|
+
if (cfg.kind === 'contact')
|
|
34332
|
+
dev = new ContactMqttSensor(nativeId, cfg);
|
|
34333
|
+
else if (cfg.kind === 'motion')
|
|
34334
|
+
dev = new MotionMqttSensor(nativeId, cfg);
|
|
34335
|
+
else
|
|
34336
|
+
dev = new OccupancyMqttSensor(nativeId, cfg);
|
|
34337
|
+
this.devices.set(nativeId, dev);
|
|
34338
|
+
}
|
|
34339
|
+
else {
|
|
34340
|
+
// update config reference
|
|
34341
|
+
dev.cfg = cfg;
|
|
34342
|
+
}
|
|
34343
|
+
}
|
|
34344
|
+
// drop removed sensors
|
|
34345
|
+
for (const [nativeId] of this.devices) {
|
|
34346
|
+
if (!announced.has(nativeId)) {
|
|
34347
|
+
try {
|
|
34348
|
+
this.devices.delete(nativeId);
|
|
34349
|
+
deviceManager.onDeviceRemoved?.(nativeId);
|
|
34350
|
+
}
|
|
34351
|
+
catch { }
|
|
34352
|
+
}
|
|
34353
|
+
}
|
|
34354
|
+
}
|
|
34355
|
+
/** ---- MQTT ---- */
|
|
34176
34356
|
getMqttOptions() {
|
|
34177
34357
|
const url = this.storage.getItem('brokerUrl') || 'mqtt://127.0.0.1:1883';
|
|
34178
34358
|
const username = this.storage.getItem('username') || undefined;
|
|
@@ -34193,12 +34373,25 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34193
34373
|
}
|
|
34194
34374
|
return { url, opts };
|
|
34195
34375
|
}
|
|
34376
|
+
collectAllSubscriptions() {
|
|
34377
|
+
const subs = new Set();
|
|
34378
|
+
// alarm
|
|
34379
|
+
for (const k of ['topicGetTarget', 'topicGetCurrent', 'topicTamper', 'topicOnline']) {
|
|
34380
|
+
const v = this.storage.getItem(k);
|
|
34381
|
+
if (v)
|
|
34382
|
+
subs.add(v);
|
|
34383
|
+
}
|
|
34384
|
+
// sensors
|
|
34385
|
+
for (const s of this.sensorsCfg) {
|
|
34386
|
+
const t = s.topics;
|
|
34387
|
+
[t.contact, t.motion, t.occupancy, t.batteryLevel, t.lowBattery, t.tamper, t.online]
|
|
34388
|
+
.filter(Boolean)
|
|
34389
|
+
.forEach(x => subs.add(String(x)));
|
|
34390
|
+
}
|
|
34391
|
+
return Array.from(subs);
|
|
34392
|
+
}
|
|
34196
34393
|
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);
|
|
34394
|
+
const subs = this.collectAllSubscriptions();
|
|
34202
34395
|
if (!subs.length && !this.storage.getItem('topicSetTarget')) {
|
|
34203
34396
|
this.console.warn('Configura almeno un topic nelle impostazioni.');
|
|
34204
34397
|
}
|
|
@@ -34213,6 +34406,11 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34213
34406
|
this.console.log(`Connecting MQTT ${url} ...`);
|
|
34214
34407
|
const client = mqtt_1.default.connect(url, opts);
|
|
34215
34408
|
this.client = client;
|
|
34409
|
+
// cache alarm topics for fast compare
|
|
34410
|
+
const tTarget = this.storage.getItem('topicGetTarget') || '';
|
|
34411
|
+
const tCurrent = this.storage.getItem('topicGetCurrent') || '';
|
|
34412
|
+
const tTamper = this.storage.getItem('topicTamper') || '';
|
|
34413
|
+
const tOnline = this.storage.getItem('topicOnline') || '';
|
|
34216
34414
|
client.on('connect', () => {
|
|
34217
34415
|
this.console.log('MQTT connected');
|
|
34218
34416
|
this.online = true;
|
|
@@ -34229,29 +34427,27 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34229
34427
|
client.on('message', (topic, payload) => {
|
|
34230
34428
|
try {
|
|
34231
34429
|
const p = payload?.toString() ?? '';
|
|
34232
|
-
|
|
34430
|
+
const np = normalize(p);
|
|
34431
|
+
// ---- Alarm handling ----
|
|
34233
34432
|
if (topic === tOnline) {
|
|
34234
|
-
if (truthy(
|
|
34433
|
+
if (truthy(np) || np === 'online')
|
|
34235
34434
|
this.online = true;
|
|
34236
|
-
if (falsy(
|
|
34435
|
+
if (falsy(np) || np === 'offline')
|
|
34237
34436
|
this.online = false;
|
|
34238
34437
|
return;
|
|
34239
34438
|
}
|
|
34240
|
-
// Tamper
|
|
34241
34439
|
if (topic === tTamper) {
|
|
34242
|
-
|
|
34243
|
-
|
|
34244
|
-
this.tampered = ['cover', 'intrusion', 'motion', 'magnetic'].find(x => x === np) || true;
|
|
34440
|
+
if (truthy(np) || ['tamper', 'intrusion', 'cover'].includes(np)) {
|
|
34441
|
+
this.tampered = ['cover', 'intrusion'].find(x => x === np) || true;
|
|
34245
34442
|
}
|
|
34246
34443
|
else if (falsy(np)) {
|
|
34247
34444
|
this.tampered = false;
|
|
34248
34445
|
}
|
|
34249
34446
|
return;
|
|
34250
34447
|
}
|
|
34251
|
-
// CURRENT state → aggiorna il mode mostrato
|
|
34252
34448
|
if (topic === tCurrent) {
|
|
34253
34449
|
const mode = payloadToMode(payload);
|
|
34254
|
-
const isAlarm = ['alarm', 'triggered'].includes(
|
|
34450
|
+
const isAlarm = ['alarm', 'triggered'].includes(np);
|
|
34255
34451
|
const current = this.securitySystemState || { mode: sdk_1.SecuritySystemMode.Disarmed };
|
|
34256
34452
|
const newState = {
|
|
34257
34453
|
mode: mode ?? current.mode,
|
|
@@ -34266,19 +34462,22 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34266
34462
|
this.securitySystemState = newState;
|
|
34267
34463
|
return;
|
|
34268
34464
|
}
|
|
34269
|
-
// TARGET state → NON cambia il mode; lo memorizziamo solo come pending
|
|
34270
34465
|
if (topic === tTarget) {
|
|
34271
34466
|
this.pendingTarget = payloadToMode(payload);
|
|
34272
34467
|
this.console.log('Target state reported:', p, '->', this.pendingTarget);
|
|
34273
34468
|
return;
|
|
34274
34469
|
}
|
|
34470
|
+
// ---- Sensor dispatch ----
|
|
34471
|
+
for (const dev of this.devices.values()) {
|
|
34472
|
+
dev.handleMqtt(topic, payload);
|
|
34473
|
+
}
|
|
34275
34474
|
}
|
|
34276
34475
|
catch (e) {
|
|
34277
34476
|
this.console.error('MQTT message handler error', e);
|
|
34278
34477
|
}
|
|
34279
34478
|
});
|
|
34280
34479
|
}
|
|
34281
|
-
|
|
34480
|
+
/** ---- SecuritySystem commands ---- */
|
|
34282
34481
|
publishSetTarget(payload) {
|
|
34283
34482
|
const topic = this.storage.getItem('topicSetTarget');
|
|
34284
34483
|
if (!topic || !this.client) {
|
|
@@ -34298,14 +34497,12 @@ class ParadoxMqttSecuritySystem extends sdk_1.ScryptedDeviceBase {
|
|
|
34298
34497
|
this.console.log('armSecuritySystem', mode, '->', payload);
|
|
34299
34498
|
this.pendingTarget = mode; // memorizza target, ma NON cambiare il current
|
|
34300
34499
|
this.publishSetTarget(payload);
|
|
34301
|
-
// niente update ottimistico: HomeKit vedrà Target ≠ Current e mostrerà "Arming..."
|
|
34302
34500
|
}
|
|
34303
34501
|
async disarmSecuritySystem() {
|
|
34304
34502
|
const payload = this.getOutgoing(sdk_1.SecuritySystemMode.Disarmed);
|
|
34305
34503
|
this.console.log('disarmSecuritySystem ->', payload);
|
|
34306
34504
|
this.pendingTarget = sdk_1.SecuritySystemMode.Disarmed;
|
|
34307
34505
|
this.publishSetTarget(payload);
|
|
34308
|
-
// niente update ottimistico: aspetta il feedback CURRENT
|
|
34309
34506
|
}
|
|
34310
34507
|
getOutgoing(mode) {
|
|
34311
34508
|
const map = {
|
package/dist/plugin.zip
CHANGED
|
Binary file
|
package/package.json
CHANGED