@rfranzoi/scrypted-mqtt-securitysystem 1.0.38 → 1.0.39
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 +90 -86
- package/dist/plugin.zip +0 -0
- package/package.json +1 -1
package/dist/main.nodejs.js
CHANGED
|
@@ -34029,7 +34029,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
34029
34029
|
};
|
|
34030
34030
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
34031
34031
|
// --- Preload: silenzia SOLO il warning facoltativo di sdk.json ---
|
|
34032
|
-
// Copre console.error e console.warn (alcune versioni usano warn).
|
|
34033
34032
|
(() => {
|
|
34034
34033
|
const swallow = (orig) => (...args) => {
|
|
34035
34034
|
const txt = args.map(a => typeof a === 'string' ? a : (a?.message || '')).join(' ');
|
|
@@ -34040,38 +34039,53 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
|
34040
34039
|
console.error = swallow(console.error.bind(console));
|
|
34041
34040
|
console.warn = swallow(console.warn.bind(console));
|
|
34042
34041
|
})();
|
|
34043
|
-
//
|
|
34042
|
+
// Runtime SDK via require (evita esecuzione anticipata del bundler)
|
|
34044
34043
|
const sdk = __webpack_require__(/*! @scrypted/sdk */ "./node_modules/@scrypted/sdk/dist/src/index.js");
|
|
34045
|
-
|
|
34046
|
-
const { ScryptedDeviceBase, ScryptedDeviceType, ScryptedInterface, // enum (valori)
|
|
34047
|
-
SecuritySystemMode, // enum (valori)
|
|
34048
|
-
systemManager, } = sdk;
|
|
34044
|
+
const { ScryptedDeviceBase, ScryptedDeviceType, ScryptedInterface, SecuritySystemMode, systemManager, } = sdk;
|
|
34049
34045
|
const mqtt_1 = __importDefault(__webpack_require__(/*! mqtt */ "./node_modules/mqtt/build/index.js"));
|
|
34050
34046
|
/** utils */
|
|
34047
|
+
function normalize(s) { return (s || '').trim().toLowerCase(); }
|
|
34051
34048
|
function truthy(v) {
|
|
34052
34049
|
if (!v)
|
|
34053
34050
|
return false;
|
|
34054
|
-
const s = v
|
|
34055
|
-
return s === '1' || s === 'true' || s === 'online' || s === 'yes' || s === 'on' || s === 'ok';
|
|
34051
|
+
const s = normalize(v);
|
|
34052
|
+
return s === '1' || s === 'true' || s === 'online' || s === 'yes' || s === 'on' || s === 'ok' || s === 'open';
|
|
34056
34053
|
}
|
|
34057
34054
|
function falsy(v) {
|
|
34058
34055
|
if (!v)
|
|
34059
34056
|
return false;
|
|
34060
|
-
const s = v
|
|
34061
|
-
return s === '0' || s === 'false' || s === 'offline' || s === 'no' || s === 'off';
|
|
34057
|
+
const s = normalize(v);
|
|
34058
|
+
return s === '0' || s === 'false' || s === 'offline' || s === 'no' || s === 'off' || s === 'closed' || s === 'close';
|
|
34062
34059
|
}
|
|
34063
|
-
function normalize(s) { return (s || '').trim().toLowerCase(); }
|
|
34064
34060
|
function clamp(n, min, max) { return Math.max(min, Math.min(max, n)); }
|
|
34065
|
-
function deepEqual(a, b) {
|
|
34061
|
+
function deepEqual(a, b) { try {
|
|
34062
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
34063
|
+
}
|
|
34064
|
+
catch {
|
|
34065
|
+
return a === b;
|
|
34066
|
+
} }
|
|
34067
|
+
/** Match topic con wildcard MQTT (+, #) oppure confronto esatto */
|
|
34068
|
+
function topicMatches(topic, pattern) {
|
|
34069
|
+
if (!pattern)
|
|
34070
|
+
return false;
|
|
34071
|
+
if (pattern === topic)
|
|
34072
|
+
return true;
|
|
34073
|
+
if (!pattern.includes('+') && !pattern.includes('#'))
|
|
34074
|
+
return false;
|
|
34075
|
+
// Escapa tutto tranne '/'
|
|
34076
|
+
const esc = pattern.replace(/[-/\\^$*?.()|[\]{}]/g, '\\$&');
|
|
34077
|
+
const rx = '^' + esc
|
|
34078
|
+
.replace(/\\\+/g, '[^/]+') // '+' => un segmento
|
|
34079
|
+
.replace(/\\\#/g, '.+'); // '#" => qualsiasi suffisso
|
|
34066
34080
|
try {
|
|
34067
|
-
return
|
|
34081
|
+
return new RegExp(rx + '$').test(topic);
|
|
34068
34082
|
}
|
|
34069
34083
|
catch {
|
|
34070
|
-
return
|
|
34084
|
+
return false;
|
|
34071
34085
|
}
|
|
34072
34086
|
}
|
|
34073
|
-
/**
|
|
34074
|
-
function setAndEmit(dev, key, value, iface) {
|
|
34087
|
+
/** set + emit evento scrypted */
|
|
34088
|
+
function setAndEmit(dev, key, value, iface, log) {
|
|
34075
34089
|
if (dev[key] === value)
|
|
34076
34090
|
return;
|
|
34077
34091
|
dev[key] = value;
|
|
@@ -34079,15 +34093,19 @@ function setAndEmit(dev, key, value, iface) {
|
|
|
34079
34093
|
dev.onDeviceEvent?.(iface, value);
|
|
34080
34094
|
}
|
|
34081
34095
|
catch { }
|
|
34096
|
+
try {
|
|
34097
|
+
if (log)
|
|
34098
|
+
dev.console?.log?.(log);
|
|
34099
|
+
}
|
|
34100
|
+
catch { }
|
|
34082
34101
|
}
|
|
34083
|
-
/** Outgoing predefiniti (PAI-like). Chiavi numeriche per
|
|
34102
|
+
/** Outgoing predefiniti (PAI-like). Chiavi numeriche per compat enum */
|
|
34084
34103
|
const DEFAULT_OUTGOING = {
|
|
34085
34104
|
[SecuritySystemMode.Disarmed]: 'disarm',
|
|
34086
34105
|
[SecuritySystemMode.HomeArmed]: 'arm_home',
|
|
34087
34106
|
[SecuritySystemMode.AwayArmed]: 'arm_away',
|
|
34088
34107
|
[SecuritySystemMode.NightArmed]: 'arm_night',
|
|
34089
34108
|
};
|
|
34090
|
-
/** Parse incoming payload -> final mode (ignora transitori) */
|
|
34091
34109
|
function payloadToMode(payload) {
|
|
34092
34110
|
if (payload == null)
|
|
34093
34111
|
return;
|
|
@@ -34110,45 +34128,46 @@ class BaseMqttSensor extends ScryptedDeviceBase {
|
|
|
34110
34128
|
this.cfg = cfg;
|
|
34111
34129
|
}
|
|
34112
34130
|
handleMqtt(topic, payload) {
|
|
34113
|
-
const
|
|
34114
|
-
const np = normalize(
|
|
34131
|
+
const raw = payload?.toString() ?? '';
|
|
34132
|
+
const np = normalize(raw);
|
|
34115
34133
|
// Online
|
|
34116
|
-
if (topic
|
|
34134
|
+
if (topicMatches(topic, this.cfg.topics.online)) {
|
|
34117
34135
|
if (truthy(np) || np === 'online')
|
|
34118
|
-
setAndEmit(this, 'online', true, ScryptedInterface.Online);
|
|
34119
|
-
if (falsy(np) || np === 'offline')
|
|
34120
|
-
setAndEmit(this, 'online', false, ScryptedInterface.Online);
|
|
34136
|
+
setAndEmit(this, 'online', true, ScryptedInterface.Online, `[${this.name}] online=true`);
|
|
34137
|
+
else if (falsy(np) || np === 'offline')
|
|
34138
|
+
setAndEmit(this, 'online', false, ScryptedInterface.Online, `[${this.name}] online=false`);
|
|
34121
34139
|
}
|
|
34122
34140
|
// Tamper
|
|
34123
|
-
if (topic
|
|
34141
|
+
if (topicMatches(topic, this.cfg.topics.tamper)) {
|
|
34124
34142
|
if (truthy(np) || ['tamper', 'intrusion', 'cover', 'motion', 'magnetic'].includes(np)) {
|
|
34125
34143
|
const t = ['cover', 'intrusion', 'motion', 'magnetic'].find(x => x === np) || true;
|
|
34126
|
-
setAndEmit(this, 'tampered', t, ScryptedInterface.TamperSensor);
|
|
34144
|
+
setAndEmit(this, 'tampered', t, ScryptedInterface.TamperSensor, `[${this.name}] tampered=${t}`);
|
|
34145
|
+
}
|
|
34146
|
+
else if (falsy(np)) {
|
|
34147
|
+
setAndEmit(this, 'tampered', false, ScryptedInterface.TamperSensor, `[${this.name}] tampered=false`);
|
|
34127
34148
|
}
|
|
34128
|
-
else if (falsy(np))
|
|
34129
|
-
setAndEmit(this, 'tampered', false, ScryptedInterface.TamperSensor);
|
|
34130
34149
|
}
|
|
34131
34150
|
// Battery
|
|
34132
|
-
if (topic
|
|
34133
|
-
const n = clamp(parseFloat(
|
|
34151
|
+
if (topicMatches(topic, this.cfg.topics.batteryLevel)) {
|
|
34152
|
+
const n = clamp(parseFloat(raw), 0, 100);
|
|
34134
34153
|
if (isFinite(n))
|
|
34135
|
-
setAndEmit(this, 'batteryLevel', n, ScryptedInterface.Battery);
|
|
34154
|
+
setAndEmit(this, 'batteryLevel', n, ScryptedInterface.Battery, `[${this.name}] batteryLevel=${n}`);
|
|
34136
34155
|
}
|
|
34137
|
-
else if (topic
|
|
34156
|
+
else if (topicMatches(topic, this.cfg.topics.lowBattery) && !this.cfg.topics.batteryLevel) {
|
|
34138
34157
|
const n = truthy(np) ? 10 : 100;
|
|
34139
|
-
setAndEmit(this, 'batteryLevel', n, ScryptedInterface.Battery);
|
|
34158
|
+
setAndEmit(this, 'batteryLevel', n, ScryptedInterface.Battery, `[${this.name}] batteryLevel=${n} (lowBattery)`);
|
|
34140
34159
|
}
|
|
34141
|
-
//
|
|
34142
|
-
this.handlePrimary(topic, np,
|
|
34160
|
+
// Primario
|
|
34161
|
+
this.handlePrimary(topic, np, raw);
|
|
34143
34162
|
}
|
|
34144
34163
|
}
|
|
34145
|
-
/** === SENSORI
|
|
34164
|
+
/** === SENSORI: parsing robusto + eventi === */
|
|
34146
34165
|
class ContactMqttSensor extends BaseMqttSensor {
|
|
34147
34166
|
handlePrimary(topic, np, raw) {
|
|
34148
|
-
if (topic
|
|
34167
|
+
if (!topicMatches(topic, this.cfg.topics.contact))
|
|
34149
34168
|
return;
|
|
34150
34169
|
let val;
|
|
34151
|
-
// stringhe comuni
|
|
34170
|
+
// stringhe comuni (True/False compresi via normalize)
|
|
34152
34171
|
if (['open', 'opened', '1', 'true', 'on', 'yes'].includes(np))
|
|
34153
34172
|
val = true;
|
|
34154
34173
|
else if (['closed', 'close', '0', 'false', 'off', 'no', 'shut'].includes(np))
|
|
@@ -34162,9 +34181,9 @@ class ContactMqttSensor extends BaseMqttSensor {
|
|
|
34162
34181
|
else if (typeof j?.opened === 'boolean')
|
|
34163
34182
|
val = !!j.opened;
|
|
34164
34183
|
else if (typeof j?.contact === 'boolean')
|
|
34165
|
-
val = !j.contact; // contact:false =>
|
|
34184
|
+
val = !j.contact; // contact:false => aperto
|
|
34166
34185
|
else if (typeof j?.state === 'string') {
|
|
34167
|
-
const s =
|
|
34186
|
+
const s = normalize(j.state);
|
|
34168
34187
|
if (s === 'open')
|
|
34169
34188
|
val = true;
|
|
34170
34189
|
if (s === 'closed')
|
|
@@ -34174,16 +34193,16 @@ class ContactMqttSensor extends BaseMqttSensor {
|
|
|
34174
34193
|
catch { }
|
|
34175
34194
|
}
|
|
34176
34195
|
if (val !== undefined) {
|
|
34177
|
-
setAndEmit(this, 'entryOpen', val, ScryptedInterface.EntrySensor);
|
|
34196
|
+
setAndEmit(this, 'entryOpen', val, ScryptedInterface.EntrySensor, `[${this.name}] entryOpen=${val} (${topic})`);
|
|
34178
34197
|
}
|
|
34179
34198
|
else {
|
|
34180
|
-
this.console?.debug?.(`Contact payload non gestito (${this.cfg.id})
|
|
34199
|
+
this.console?.debug?.(`Contact payload non gestito (${this.cfg.id}) topic=${topic} raw="${raw}"`);
|
|
34181
34200
|
}
|
|
34182
34201
|
}
|
|
34183
34202
|
}
|
|
34184
34203
|
class MotionMqttSensor extends BaseMqttSensor {
|
|
34185
34204
|
handlePrimary(topic, np, raw) {
|
|
34186
|
-
if (topic
|
|
34205
|
+
if (!topicMatches(topic, this.cfg.topics.motion))
|
|
34187
34206
|
return;
|
|
34188
34207
|
let val;
|
|
34189
34208
|
if (['motion', 'detected', 'active', '1', 'true', 'on', 'yes'].includes(np))
|
|
@@ -34200,7 +34219,7 @@ class MotionMqttSensor extends BaseMqttSensor {
|
|
|
34200
34219
|
else if (typeof j?.presence === 'boolean')
|
|
34201
34220
|
val = !!j.presence;
|
|
34202
34221
|
else if (typeof j?.state === 'string') {
|
|
34203
|
-
const s =
|
|
34222
|
+
const s = normalize(j.state);
|
|
34204
34223
|
if (['on', 'motion', 'detected', 'active'].includes(s))
|
|
34205
34224
|
val = true;
|
|
34206
34225
|
if (['off', 'clear', 'inactive'].includes(s))
|
|
@@ -34210,16 +34229,16 @@ class MotionMqttSensor extends BaseMqttSensor {
|
|
|
34210
34229
|
catch { }
|
|
34211
34230
|
}
|
|
34212
34231
|
if (val !== undefined) {
|
|
34213
|
-
setAndEmit(this, 'motionDetected', val, ScryptedInterface.MotionSensor);
|
|
34232
|
+
setAndEmit(this, 'motionDetected', val, ScryptedInterface.MotionSensor, `[${this.name}] motionDetected=${val} (${topic})`);
|
|
34214
34233
|
}
|
|
34215
34234
|
else {
|
|
34216
|
-
this.console?.debug?.(`Motion payload non gestito (${this.cfg.id})
|
|
34235
|
+
this.console?.debug?.(`Motion payload non gestito (${this.cfg.id}) topic=${topic} raw="${raw}"`);
|
|
34217
34236
|
}
|
|
34218
34237
|
}
|
|
34219
34238
|
}
|
|
34220
34239
|
class OccupancyMqttSensor extends BaseMqttSensor {
|
|
34221
34240
|
handlePrimary(topic, np, raw) {
|
|
34222
|
-
if (topic
|
|
34241
|
+
if (!topicMatches(topic, this.cfg.topics.occupancy))
|
|
34223
34242
|
return;
|
|
34224
34243
|
let val;
|
|
34225
34244
|
if (['occupied', 'presence', 'present', '1', 'true', 'on', 'yes'].includes(np))
|
|
@@ -34236,7 +34255,7 @@ class OccupancyMqttSensor extends BaseMqttSensor {
|
|
|
34236
34255
|
else if (typeof j?.occupancy === 'boolean')
|
|
34237
34256
|
val = !!j.occupancy;
|
|
34238
34257
|
else if (typeof j?.state === 'string') {
|
|
34239
|
-
const s =
|
|
34258
|
+
const s = normalize(j.state);
|
|
34240
34259
|
if (['occupied', 'presence', 'present', 'on'].includes(s))
|
|
34241
34260
|
val = true;
|
|
34242
34261
|
if (['vacant', 'absent', 'clear', 'off'].includes(s))
|
|
@@ -34246,10 +34265,10 @@ class OccupancyMqttSensor extends BaseMqttSensor {
|
|
|
34246
34265
|
catch { }
|
|
34247
34266
|
}
|
|
34248
34267
|
if (val !== undefined) {
|
|
34249
|
-
setAndEmit(this, 'occupied', val, ScryptedInterface.OccupancySensor);
|
|
34268
|
+
setAndEmit(this, 'occupied', val, ScryptedInterface.OccupancySensor, `[${this.name}] occupied=${val} (${topic})`);
|
|
34250
34269
|
}
|
|
34251
34270
|
else {
|
|
34252
|
-
this.console?.debug?.(`Occupancy payload non gestito (${this.cfg.id})
|
|
34271
|
+
this.console?.debug?.(`Occupancy payload non gestito (${this.cfg.id}) topic=${topic} raw="${raw}"`);
|
|
34253
34272
|
}
|
|
34254
34273
|
}
|
|
34255
34274
|
}
|
|
@@ -34259,7 +34278,6 @@ class ParadoxMqttSecuritySystem extends ScryptedDeviceBase {
|
|
|
34259
34278
|
super();
|
|
34260
34279
|
this.sensorsCfg = [];
|
|
34261
34280
|
this.devices = new Map();
|
|
34262
|
-
// Evita loop di log: tenta una volta finché deviceManager non c’è, poi riprova su eventi utili.
|
|
34263
34281
|
this.discoveryPostponed = false;
|
|
34264
34282
|
// Tipo in UI (best-effort)
|
|
34265
34283
|
setTimeout(() => {
|
|
@@ -34279,12 +34297,9 @@ class ParadoxMqttSecuritySystem extends ScryptedDeviceBase {
|
|
|
34279
34297
|
],
|
|
34280
34298
|
};
|
|
34281
34299
|
this.online = this.online ?? false;
|
|
34282
|
-
// Config sensori e (tentativo) announce
|
|
34283
34300
|
this.loadSensorsFromStorage();
|
|
34284
|
-
this.safeDiscoverSensors();
|
|
34285
|
-
// Connect MQTT
|
|
34301
|
+
this.safeDiscoverSensors();
|
|
34286
34302
|
this.connectMqtt().catch((e) => this.console.error('MQTT connect error:', e));
|
|
34287
|
-
// Shutdown pulito
|
|
34288
34303
|
try {
|
|
34289
34304
|
process.once('SIGTERM', () => { try {
|
|
34290
34305
|
this.client?.end(true);
|
|
@@ -34328,12 +34343,11 @@ class ParadoxMqttSecuritySystem extends ScryptedDeviceBase {
|
|
|
34328
34343
|
];
|
|
34329
34344
|
// Add Sensor
|
|
34330
34345
|
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: 'Toggle ON to create the sensor.' });
|
|
34331
|
-
// Sensors esistenti
|
|
34332
34346
|
for (const cfg of this.sensorsCfg) {
|
|
34333
34347
|
const gid = `Sensor: ${cfg.name} [${cfg.id}]`;
|
|
34334
34348
|
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'] });
|
|
34335
34349
|
if (cfg.kind === 'contact')
|
|
34336
|
-
out.push({ group: gid, key: `sensor.${cfg.id}.topic.contact`, title: 'Contact State Topic', value: cfg.topics.contact || '' });
|
|
34350
|
+
out.push({ group: gid, key: `sensor.${cfg.id}.topic.contact`, title: 'Contact State Topic', value: cfg.topics.contact || '', placeholder: 'paradox/states/zones/XYZ/open (supporta +/#)' });
|
|
34337
34351
|
else if (cfg.kind === 'motion')
|
|
34338
34352
|
out.push({ group: gid, key: `sensor.${cfg.id}.topic.motion`, title: 'Motion Detected Topic', value: cfg.topics.motion || '' });
|
|
34339
34353
|
else
|
|
@@ -34436,11 +34450,9 @@ class ParadoxMqttSecuritySystem extends ScryptedDeviceBase {
|
|
|
34436
34450
|
this.sensorsCfg = [];
|
|
34437
34451
|
}
|
|
34438
34452
|
}
|
|
34439
|
-
/** Annuncia i sensori SOLO se deviceManager è pronto. Niente loop infinito. */
|
|
34440
34453
|
safeDiscoverSensors(triggeredByChange = false) {
|
|
34441
34454
|
const dmAny = sdk?.deviceManager;
|
|
34442
34455
|
if (!dmAny) {
|
|
34443
|
-
// Posticipa una sola volta; poi riproviamo su connect MQTT e al primo messaggio
|
|
34444
34456
|
if (!this.discoveryPostponed) {
|
|
34445
34457
|
this.console.log('Device discovery postponed: deviceManager not ready yet.');
|
|
34446
34458
|
this.discoveryPostponed = true;
|
|
@@ -34452,9 +34464,7 @@ class ParadoxMqttSecuritySystem extends ScryptedDeviceBase {
|
|
|
34452
34464
|
if (triggeredByChange)
|
|
34453
34465
|
this.console.log('Sensors discovered/updated.');
|
|
34454
34466
|
}
|
|
34455
|
-
/** discoverSensors con deviceManager garantito */
|
|
34456
34467
|
discoverSensors(dmAny) {
|
|
34457
|
-
// 1) Manifests
|
|
34458
34468
|
const manifests = this.sensorsCfg.map(cfg => {
|
|
34459
34469
|
const nativeId = `sensor:${cfg.id}`;
|
|
34460
34470
|
const t = cfg.topics || {};
|
|
@@ -34471,15 +34481,11 @@ class ParadoxMqttSecuritySystem extends ScryptedDeviceBase {
|
|
|
34471
34481
|
interfaces.push(ScryptedInterface.Battery);
|
|
34472
34482
|
return { nativeId, name: cfg.name, type: ScryptedDeviceType.Sensor, interfaces };
|
|
34473
34483
|
});
|
|
34474
|
-
|
|
34475
|
-
if (typeof dmAny.onDevicesChanged === 'function') {
|
|
34484
|
+
if (typeof dmAny.onDevicesChanged === 'function')
|
|
34476
34485
|
dmAny.onDevicesChanged({ devices: manifests });
|
|
34477
|
-
|
|
34478
|
-
else if (typeof dmAny.onDeviceDiscovered === 'function') {
|
|
34486
|
+
else if (typeof dmAny.onDeviceDiscovered === 'function')
|
|
34479
34487
|
for (const m of manifests)
|
|
34480
34488
|
dmAny.onDeviceDiscovered(m);
|
|
34481
|
-
}
|
|
34482
|
-
// 3) Istanzia/aggiorna
|
|
34483
34489
|
for (const cfg of this.sensorsCfg) {
|
|
34484
34490
|
const nativeId = `sensor:${cfg.id}`;
|
|
34485
34491
|
let dev = this.devices.get(nativeId);
|
|
@@ -34497,9 +34503,8 @@ class ParadoxMqttSecuritySystem extends ScryptedDeviceBase {
|
|
|
34497
34503
|
}
|
|
34498
34504
|
const hasBattery = !!(cfg.topics.batteryLevel || cfg.topics.lowBattery);
|
|
34499
34505
|
if (hasBattery && dev.batteryLevel === undefined)
|
|
34500
|
-
setAndEmit(dev, 'batteryLevel', 100, ScryptedInterface.Battery);
|
|
34506
|
+
setAndEmit(dev, 'batteryLevel', 100, ScryptedInterface.Battery, `[${cfg.name}] batteryLevel=100 (default)`);
|
|
34501
34507
|
}
|
|
34502
|
-
// 4) Cleanup
|
|
34503
34508
|
const announced = new Set(manifests.map(m => m.nativeId));
|
|
34504
34509
|
for (const [nativeId] of this.devices) {
|
|
34505
34510
|
if (!announced.has(nativeId)) {
|
|
@@ -34562,38 +34567,37 @@ class ParadoxMqttSecuritySystem extends ScryptedDeviceBase {
|
|
|
34562
34567
|
const tOnline = this.storage.getItem('topicOnline') || '';
|
|
34563
34568
|
client.on('connect', () => {
|
|
34564
34569
|
this.console.log('MQTT connected');
|
|
34565
|
-
setAndEmit(this, 'online', true, ScryptedInterface.Online);
|
|
34570
|
+
setAndEmit(this, 'online', true, ScryptedInterface.Online, `[Alarm] online=true`);
|
|
34566
34571
|
if (subs.length)
|
|
34567
34572
|
client.subscribe(subs, { qos: 0 }, (err) => { if (err)
|
|
34568
34573
|
this.console.error('subscribe error', err); });
|
|
34569
|
-
// Al primo connect riprova (silenziosamente) ad annunciare i sensori
|
|
34570
34574
|
this.safeDiscoverSensors(true);
|
|
34571
34575
|
});
|
|
34572
34576
|
client.on('reconnect', () => this.console.log('MQTT reconnecting...'));
|
|
34573
|
-
client.on('close', () => { this.console.log('MQTT closed'); setAndEmit(this, 'online', false, ScryptedInterface.Online); });
|
|
34577
|
+
client.on('close', () => { this.console.log('MQTT closed'); setAndEmit(this, 'online', false, ScryptedInterface.Online, `[Alarm] online=false`); });
|
|
34574
34578
|
client.on('error', (e) => { this.console.error('MQTT error', e); });
|
|
34575
34579
|
client.on('message', (topic, payload) => {
|
|
34576
34580
|
try {
|
|
34577
|
-
const
|
|
34578
|
-
const np = normalize(
|
|
34579
|
-
if (topic
|
|
34581
|
+
const raw = payload?.toString() ?? '';
|
|
34582
|
+
const np = normalize(raw);
|
|
34583
|
+
if (topicMatches(topic, tOnline)) {
|
|
34580
34584
|
if (truthy(np) || np === 'online')
|
|
34581
|
-
setAndEmit(this, 'online', true, ScryptedInterface.Online);
|
|
34582
|
-
if (falsy(np) || np === 'offline')
|
|
34583
|
-
setAndEmit(this, 'online', false, ScryptedInterface.Online);
|
|
34585
|
+
setAndEmit(this, 'online', true, ScryptedInterface.Online, `[Alarm] online=true (${topic})`);
|
|
34586
|
+
else if (falsy(np) || np === 'offline')
|
|
34587
|
+
setAndEmit(this, 'online', false, ScryptedInterface.Online, `[Alarm] online=false (${topic})`);
|
|
34584
34588
|
return;
|
|
34585
34589
|
}
|
|
34586
|
-
if (topic
|
|
34590
|
+
if (topicMatches(topic, tTamper)) {
|
|
34587
34591
|
if (truthy(np) || ['tamper', 'intrusion', 'cover'].includes(np)) {
|
|
34588
34592
|
const t = ['cover', 'intrusion'].find(x => x === np) || true;
|
|
34589
|
-
setAndEmit(this, 'tampered', t, ScryptedInterface.TamperSensor);
|
|
34593
|
+
setAndEmit(this, 'tampered', t, ScryptedInterface.TamperSensor, `[Alarm] tampered=${t} (${topic})`);
|
|
34590
34594
|
}
|
|
34591
34595
|
else if (falsy(np)) {
|
|
34592
|
-
setAndEmit(this, 'tampered', false, ScryptedInterface.TamperSensor);
|
|
34596
|
+
setAndEmit(this, 'tampered', false, ScryptedInterface.TamperSensor, `[Alarm] tampered=false (${topic})`);
|
|
34593
34597
|
}
|
|
34594
34598
|
return;
|
|
34595
34599
|
}
|
|
34596
|
-
if (topic
|
|
34600
|
+
if (topicMatches(topic, tCurrent)) {
|
|
34597
34601
|
const mode = payloadToMode(payload);
|
|
34598
34602
|
const isAlarm = ['alarm', 'triggered'].includes(np);
|
|
34599
34603
|
const current = this.securitySystemState || { mode: SecuritySystemMode.Disarmed };
|
|
@@ -34613,16 +34617,16 @@ class ParadoxMqttSecuritySystem extends ScryptedDeviceBase {
|
|
|
34613
34617
|
this.onDeviceEvent?.(ScryptedInterface.SecuritySystem, newState);
|
|
34614
34618
|
}
|
|
34615
34619
|
catch { }
|
|
34620
|
+
this.console.log(`[Alarm] currentState=${JSON.stringify(newState)} (${topic})`);
|
|
34616
34621
|
}
|
|
34617
34622
|
return;
|
|
34618
34623
|
}
|
|
34619
|
-
if (topic
|
|
34624
|
+
if (topicMatches(topic, tTarget)) {
|
|
34620
34625
|
this.pendingTarget = payloadToMode(payload);
|
|
34621
|
-
this.console.log(
|
|
34626
|
+
this.console.log(`[Alarm] target reported: "${raw}" -> ${this.pendingTarget} (${topic})`);
|
|
34622
34627
|
return;
|
|
34623
34628
|
}
|
|
34624
|
-
//
|
|
34625
|
-
// (E prova ad annunciare se era stato posticipato e ora il manager è pronto)
|
|
34629
|
+
// Sensors: se discovery rimandata, riprova
|
|
34626
34630
|
if (this.discoveryPostponed)
|
|
34627
34631
|
this.safeDiscoverSensors(true);
|
|
34628
34632
|
for (const dev of this.devices.values())
|
package/dist/plugin.zip
CHANGED
|
Binary file
|
package/package.json
CHANGED