node-red-contrib-alarm-ultimate 0.3.0-beta.7 → 1.0.1
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/CHANGELOG.MD +47 -20
- package/README.md +21 -16
- package/nodes/AlarmSystemUltimate.html +47 -45
- package/nodes/AlarmSystemUltimate.js +24 -0
- package/nodes/AlarmUltimateSiren.html +12 -3
- package/nodes/AlarmUltimateSiren.js +11 -1
- package/nodes/AlarmUltimateState.html +13 -4
- package/nodes/AlarmUltimateState.js +11 -1
- package/nodes/AlarmUltimateZone.html +13 -4
- package/nodes/AlarmUltimateZone.js +13 -1
- package/package.json +16 -4
- package/tools/alarm-json-mapper.html +290 -749
- package/tools/alarm-panel.html +230 -514
- package/tools/alarm-settings.html +386 -0
- package/tools/assets/alarm-tools-pages.css +619 -0
- package/tools/assets/alarm-vue-shell.css +425 -0
- package/tools/assets/alarm-vue-shell.js +94 -0
- package/tools/assets/vue.global.prod.js +13 -0
- package/test/alarm-system-advanced.spec.js +0 -290
- package/test/alarm-system.spec.js +0 -898
- package/test/embedded-adapters.spec.js +0 -332
- package/test/helpers.js +0 -28
- package/test/output-nodes.spec.js +0 -179
package/CHANGELOG.MD
CHANGED
|
@@ -1,11 +1,38 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
>
|
|
4
|
-
>
|
|
3
|
+
> Stable release track from `0.3.0`.
|
|
4
|
+
> Previous pre-release history is preserved below.
|
|
5
5
|
|
|
6
|
-
## [
|
|
6
|
+
## [1.0.1] - 2026-04-07
|
|
7
7
|
|
|
8
|
-
###
|
|
8
|
+
### Changed
|
|
9
|
+
|
|
10
|
+
- **Tools UI (Vue shell):** aligned all pages in `tools/` to the KNX AI visual style (layout, colors, typography, shared CSS shell).
|
|
11
|
+
- **Navigation:** renamed sections to **Control Panel**, **Zones**, and **Settings** with SVG icons and improved selected-menu highlighting.
|
|
12
|
+
- **Zones page:** reorganized import flow by moving the full **Import Wizard** into its own dedicated box (now positioned above the zones list).
|
|
13
|
+
- **Settings page:** moved JSON import/export actions from Zones to Settings and renamed actions to **Export Zones** / **Import Zones**.
|
|
14
|
+
- **Control Panel page:** removed redundant helper texts in the Node box and improved node-selection button readability.
|
|
15
|
+
- **Zones supervision timeout:** default timeout is now `120` seconds and empty timeout fields no longer trigger validation errors.
|
|
16
|
+
- **Packaging:** added `prepublishOnly` hook to automatically run `build:vue-tools` before publishing.
|
|
17
|
+
|
|
18
|
+
## [0.3.0] - 2026-02-18
|
|
19
|
+
|
|
20
|
+
### Release
|
|
21
|
+
|
|
22
|
+
- First stable release of `node-red-contrib-alarm-ultimate` (from `0.3.0-pre-release.7`).
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- **Security (Zones JSON Mapper):** fixed XSS risk in the target-alarm context rendering by removing unsafe `innerHTML` usage for the node name.
|
|
27
|
+
- **Output-only nodes:** initial retry intervals now stop automatically once the first valid state is received (`AlarmUltimateState`, `AlarmUltimateZone`, `AlarmUltimateSiren`).
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- **Packaging:** added explicit npm publish allowlist (`package.json` `files`) to avoid accidental inclusion of unwanted files.
|
|
32
|
+
|
|
33
|
+
## [0.3.0-pre-release.7] - 2026-02-08
|
|
34
|
+
|
|
35
|
+
### Breaking (pre-release)
|
|
9
36
|
|
|
10
37
|
- **Alarm outputs (Open zones):** removed **Open zones (on request)** output + `list_open_zones` / request-topic behavior. Open zones listing while arming and cyclic listing are now always-on outputs (configurable intervals). Total outputs: **9**.
|
|
11
38
|
- **Alarm Zone / Alarm State (outputs):** `msg.payload` is now always a boolean (`true|false`). All extra fields are emitted as root properties on `msg`.
|
|
@@ -19,9 +46,9 @@
|
|
|
19
46
|
- **Alarm System:** output label renamed to **Any zone open (bool)** and help now documents each output pin.
|
|
20
47
|
- **Examples/Docs/Tests:** updated for new pins and helper node payload shape.
|
|
21
48
|
|
|
22
|
-
## [0.3.0-
|
|
49
|
+
## [0.3.0-pre-release.6] - 2026-02-07
|
|
23
50
|
|
|
24
|
-
### Breaking (
|
|
51
|
+
### Breaking (pre-release)
|
|
25
52
|
|
|
26
53
|
- **Alarm Zone:** `AlarmUltimateZone` is now output-only (removed Input mode and all adapters).
|
|
27
54
|
- **Alarm System:** moved zone input adapters into the Alarm node (**Zones → Zone input adapter** + **AX Pro match**).
|
|
@@ -34,9 +61,9 @@
|
|
|
34
61
|
|
|
35
62
|
- **Tests:** expanded unit test coverage for core Alarm behaviors (arming violations, topic prefix matching, code denial, persistence fallback).
|
|
36
63
|
|
|
37
|
-
## [0.3.0-
|
|
64
|
+
## [0.3.0-pre-release.5] - 2026-02-07
|
|
38
65
|
|
|
39
|
-
### Breaking (
|
|
66
|
+
### Breaking (pre-release)
|
|
40
67
|
|
|
41
68
|
- **Alarm System:** removed `blockArmOnViolations`. Arming is now always blocked by violations (open zones, or supervised zones that are **MISSING** when `supervision.blockArm: true`).
|
|
42
69
|
|
|
@@ -50,7 +77,7 @@
|
|
|
50
77
|
- **Tools:** moved **Export JSON** / **Import JSON** from the node edit dialog to `/alarm-ultimate/alarm-json-mapper`.
|
|
51
78
|
- **Tools / Runtime:** `supervision.blockArm` now treats false-like values (e.g. `"false"`, `0`) as `false`.
|
|
52
79
|
|
|
53
|
-
## [0.3.0-
|
|
80
|
+
## [0.3.0-pre-release.4] - 2026-02-06
|
|
54
81
|
|
|
55
82
|
### Changed
|
|
56
83
|
|
|
@@ -58,7 +85,7 @@
|
|
|
58
85
|
- **UI:** `AlarmUltimateZone` now allows selecting the **Ax Pro** adapter also in **Output** mode.
|
|
59
86
|
- **Docs:** refreshed node help and README for coherence (HomeKit input notes, Ax Pro mapping notes, "click Done" reminder).
|
|
60
87
|
|
|
61
|
-
## [0.3.0-
|
|
88
|
+
## [0.3.0-pre-release.3] - 2026-02-06
|
|
62
89
|
|
|
63
90
|
### Changed
|
|
64
91
|
|
|
@@ -70,7 +97,7 @@
|
|
|
70
97
|
- **Tools (Zones JSON Mapper):** improved visibility of the "click Done in Node-RED editor to apply" reminder.
|
|
71
98
|
- **UI:** clarified AX Pro matching help text in `AlarmUltimateZone`.
|
|
72
99
|
|
|
73
|
-
## [0.3.0-
|
|
100
|
+
## [0.3.0-pre-release.2] - 2026-02-04
|
|
74
101
|
|
|
75
102
|
### Changed
|
|
76
103
|
|
|
@@ -79,9 +106,9 @@
|
|
|
79
106
|
- **Tools:** Zones JSON Mapper now accepts **JSON array only** (aligned with `AlarmSystemUltimate.zones`).
|
|
80
107
|
- **UI:** refined AX Pro “match” option labels in `AlarmUltimateZone`.
|
|
81
108
|
|
|
82
|
-
## [0.3.0-
|
|
109
|
+
## [0.3.0-pre-release.1] - 2026-02-04
|
|
83
110
|
|
|
84
|
-
### Breaking (
|
|
111
|
+
### Breaking (pre-release)
|
|
85
112
|
|
|
86
113
|
- **Zones identifier:** removed the `id`/`zoneId` field from zones. Zones are identified only by `topic`.
|
|
87
114
|
- **Zones format:** `AlarmSystemUltimate.zones` now accepts **JSON array only** (no single-object, no JSON-per-line).
|
|
@@ -98,9 +125,9 @@
|
|
|
98
125
|
- **Alarm State (Input + AX Pro):** added support for AX Pro `CIDEvent.code` to inject arm/disarm (`3401` Away, `3441` Stay, `1401` Disarmed).
|
|
99
126
|
- **Tools:** Alarm JSON Mapper and Alarm Panel updated to reflect topic-only zones and the simplified zones format.
|
|
100
127
|
|
|
101
|
-
## [0.3.0-
|
|
128
|
+
## [0.3.0-pre-release.0] - 2026-02-04
|
|
102
129
|
|
|
103
|
-
### Breaking (
|
|
130
|
+
### Breaking (pre-release)
|
|
104
131
|
|
|
105
132
|
- **Removed adapter nodes:** `AlarmUltimateInputAdapter` and `AlarmUltimateOutputAdapter` have been removed.
|
|
106
133
|
- **Alarm State / Alarm Zone I/O mode:** `AlarmUltimateState` and `AlarmUltimateZone` can now be configured as **Input** (flow → selected alarm) or **Output** (selected alarm → flow).
|
|
@@ -116,9 +143,9 @@
|
|
|
116
143
|
- Replace any `AlarmUltimateOutputAdapter` nodes with:
|
|
117
144
|
- `AlarmUltimateState` / `AlarmUltimateZone` → **Mode: Output**, pick an **Adapter**, wire their output to your integrations.
|
|
118
145
|
|
|
119
|
-
## [0.2.0-
|
|
146
|
+
## [0.2.0-pre-release.0] - 2026-02-03
|
|
120
147
|
|
|
121
|
-
### Breaking (
|
|
148
|
+
### Breaking (pre-release)
|
|
122
149
|
|
|
123
150
|
- **Canonical envelope:** all nodes now emit `msg.alarmUltimate` (versioned) as the stable, canonical representation of alarm messages.
|
|
124
151
|
- **Output-only helper nodes:** `Alarm State`, `Alarm Zone`, `Alarm Siren` now emit the same “default telegrams” as `AlarmSystemUltimate`:
|
|
@@ -140,7 +167,7 @@
|
|
|
140
167
|
|
|
141
168
|
## [0.1.17] - 2026-02-02
|
|
142
169
|
|
|
143
|
-
### Breaking (
|
|
170
|
+
### Breaking (pre-release)
|
|
144
171
|
|
|
145
172
|
- **Output Adapter (Homekit Alarm Status):** on `arming` the node keeps `SecuritySystemCurrentState` at the previous value (while updating `SecuritySystemTargetState`). If you relied on both being the same during arming, update your downstream flows.
|
|
146
173
|
|
|
@@ -182,7 +209,7 @@
|
|
|
182
209
|
|
|
183
210
|
## [Unreleased]
|
|
184
211
|
|
|
185
|
-
### Breaking (
|
|
212
|
+
### Breaking (pre-release)
|
|
186
213
|
|
|
187
214
|
- TBD.
|
|
188
215
|
|
|
@@ -200,7 +227,7 @@
|
|
|
200
227
|
|
|
201
228
|
## [0.1.9] - 2026-02-02
|
|
202
229
|
|
|
203
|
-
### Breaking (
|
|
230
|
+
### Breaking (pre-release)
|
|
204
231
|
|
|
205
232
|
- **Alarm node:** removed classic multi-output mode; `AlarmSystemUltimate` now has a single output only.
|
|
206
233
|
|
package/README.md
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
[![Node-RED Flows][flows-image]][flows-url]
|
|
8
8
|
[![License][license-image]][license-url]
|
|
9
9
|
[![GitHub issues][issues-image]][issues-url]
|
|
10
|
-
[![Status: beta][beta-image]][repo-url]
|
|
11
10
|
|
|
12
11
|
# node-red-contrib-alarm-ultimate
|
|
13
12
|
|
|
@@ -23,14 +22,14 @@ Alarm System Ultimate nodes + web panel for Node-RED.
|
|
|
23
22
|
|
|
24
23
|
Includes:
|
|
25
24
|
|
|
26
|
-
- `AlarmSystemUltimate
|
|
25
|
+
- `AlarmSystemUltimate`: main alarm node with panel-style behavior (zones, entry/exit delays, bypass, chime, 24h/fire/tamper, siren, event log, optional per-zone sensor supervision).
|
|
27
26
|
- Helper nodes: `AlarmUltimateState`, `AlarmUltimateZone`, `AlarmUltimateSiren`.
|
|
28
|
-
- `AlarmUltimateState`:
|
|
27
|
+
- `AlarmUltimateState`: input/output helper for arm/disarm and state integration (Default / Homekit / Ax Pro / KNX-Ultimate).
|
|
29
28
|
- `AlarmUltimateZone`: output-only zone events splitter (no adapters).
|
|
30
29
|
- `AlarmUltimateSiren`: output-only siren state splitter.
|
|
31
30
|
- Web tools: Zones JSON mapper + web Alarm Panel (embeddable in Node-RED Dashboard).
|
|
32
31
|
|
|
33
|
-
|
|
32
|
+
`AlarmSystemUltimate` is now stable.
|
|
34
33
|
|
|
35
34
|
## Table of contents
|
|
36
35
|
|
|
@@ -40,8 +39,8 @@ Note: `AlarmSystemUltimate` is currently **BETA**.
|
|
|
40
39
|
- [Nodes](#nodes)
|
|
41
40
|
- [Web tools](#web-tools)
|
|
42
41
|
- [Examples](#examples)
|
|
43
|
-
- [
|
|
44
|
-
- [
|
|
42
|
+
- [Advanced integration reference (optional)](#advanced-integration-reference-optional)
|
|
43
|
+
- [Contributing (optional)](#contributing-optional)
|
|
45
44
|
|
|
46
45
|
## Install
|
|
47
46
|
|
|
@@ -56,8 +55,8 @@ npm i node-red-contrib-alarm-ultimate
|
|
|
56
55
|
|
|
57
56
|
Beginner-friendly flow:
|
|
58
57
|
|
|
59
|
-
1. Add an **AlarmSystemUltimate
|
|
60
|
-
2. Click **Manage zones** and add at least one zone (example topic: `sensor/frontdoor`).
|
|
58
|
+
1. Add an **AlarmSystemUltimate** node.
|
|
59
|
+
2. Click **Manage zones** and add at least one zone (example topic: `sensor/frontdoor`). For backup/restore use **Export Zones** / **Import Zones** in the **Settings** page.
|
|
61
60
|
**Important:** after editing zones, click **Done** in the Node-RED editor to save (if you click **Cancel**, changes are lost).
|
|
62
61
|
3. Send sensor messages to the Alarm node:
|
|
63
62
|
- open: `msg.topic="sensor/frontdoor"`, `msg.payload=true`
|
|
@@ -91,7 +90,7 @@ Optional (recommended):
|
|
|
91
90
|
|
|
92
91
|
## Nodes
|
|
93
92
|
|
|
94
|
-
### Alarm System Ultimate
|
|
93
|
+
### Alarm System Ultimate
|
|
95
94
|
|
|
96
95
|
Main node that:
|
|
97
96
|
|
|
@@ -152,7 +151,9 @@ Example zone:
|
|
|
152
151
|
- `Alarm Zone` (`AlarmUltimateZone`): emits `zone_open` / `zone_close` as `.../event` telegrams
|
|
153
152
|
- `Alarm Siren` (`AlarmUltimateSiren`): emits siren telegrams (`msg.topic = <controlTopic>/siren`, `msg.event = siren_on|siren_off`, `msg.payload = true|false`)
|
|
154
153
|
|
|
155
|
-
###
|
|
154
|
+
### Advanced integration (optional): `msg.alarmUltimate`
|
|
155
|
+
|
|
156
|
+
If you are just wiring nodes in Node-RED, you can safely skip this section.
|
|
156
157
|
|
|
157
158
|
All nodes in this package add a stable, versioned object to every output message:
|
|
158
159
|
|
|
@@ -168,11 +169,11 @@ msg.alarmUltimate = {
|
|
|
168
169
|
};
|
|
169
170
|
```
|
|
170
171
|
|
|
171
|
-
|
|
172
|
+
Adapters and advanced integrations can use `msg.alarmUltimate` as a consistent source of alarm details.
|
|
172
173
|
|
|
173
174
|
## Web tools
|
|
174
175
|
|
|
175
|
-
These pages are
|
|
176
|
+
These web pages are available from your Node-RED editor at:
|
|
176
177
|
|
|
177
178
|
- Zones JSON Mapper: `/alarm-ultimate/alarm-json-mapper`
|
|
178
179
|
- Alarm Panel: `/alarm-ultimate/alarm-panel`
|
|
@@ -187,9 +188,12 @@ The Zones JSON Mapper supports:
|
|
|
187
188
|
|
|
188
189
|
- Sample message mapping (e.g. KNX Ultimate): map `topic`/`payload` fields and generate a zone template.
|
|
189
190
|
- ETS Group Addresses export (TSV): paste the exported table and generate zones in batch (boolean datapoints only).
|
|
190
|
-
- Backup/restore: **Export JSON** / **Import JSON** for zone definitions.
|
|
191
191
|
- Quality-of-life: bulk apply (Kind/Supervision), sorting, duplicate-topic skipping on import, persisted Step 1 input.
|
|
192
192
|
|
|
193
|
+
The Settings page supports:
|
|
194
|
+
|
|
195
|
+
- Backup/restore: **Export Zones** / **Import Zones** for zone definitions.
|
|
196
|
+
|
|
193
197
|
## Examples
|
|
194
198
|
|
|
195
199
|
- `examples/alarm-ultimate-basic.json`: ready-to-import flow with `AlarmSystemUltimate`, injects and debug nodes.
|
|
@@ -200,7 +204,7 @@ The Zones JSON Mapper supports:
|
|
|
200
204
|
|
|
201
205
|
See `examples/README.md`.
|
|
202
206
|
|
|
203
|
-
##
|
|
207
|
+
## Contributing (optional)
|
|
204
208
|
|
|
205
209
|
Run tests:
|
|
206
210
|
|
|
@@ -208,7 +212,9 @@ Run tests:
|
|
|
208
212
|
npm test
|
|
209
213
|
```
|
|
210
214
|
|
|
211
|
-
##
|
|
215
|
+
## Advanced integration reference (optional)
|
|
216
|
+
|
|
217
|
+
If you are using the package normally in flows, you can ignore this section.
|
|
212
218
|
|
|
213
219
|
When Node-RED authentication is enabled, the admin endpoints use these permissions (if available):
|
|
214
220
|
|
|
@@ -236,4 +242,3 @@ HTTP admin endpoints:
|
|
|
236
242
|
[flows-image]: https://img.shields.io/badge/Node--RED%20Flows-library-8f0000?logo=nodered&logoColor=white
|
|
237
243
|
[license-image]: https://img.shields.io/npm/l/node-red-contrib-alarm-ultimate.svg
|
|
238
244
|
[issues-image]: https://img.shields.io/github/issues/Supergiovane/node-red-contrib-alarm-ultimate.svg
|
|
239
|
-
[beta-image]: https://img.shields.io/badge/status-beta-orange.svg
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script type="text/javascript">
|
|
2
2
|
RED.nodes.registerType("AlarmSystemUltimate", {
|
|
3
3
|
category: "Alarm Ultimate",
|
|
4
|
-
color: "#
|
|
4
|
+
color: "#D9B26B",
|
|
5
5
|
defaults: {
|
|
6
6
|
name: { value: "" },
|
|
7
7
|
controlTopic: { value: "alarm" },
|
|
@@ -51,10 +51,10 @@
|
|
|
51
51
|
],
|
|
52
52
|
icon: "alarm-ultimate.svg",
|
|
53
53
|
label: function () {
|
|
54
|
-
return this.name || "Alarm System
|
|
54
|
+
return this.name || "Alarm System";
|
|
55
55
|
},
|
|
56
56
|
paletteLabel: function () {
|
|
57
|
-
return "Alarm System
|
|
57
|
+
return "Alarm System";
|
|
58
58
|
},
|
|
59
59
|
oneditprepare: function () {
|
|
60
60
|
const nodeId = this.id;
|
|
@@ -445,21 +445,22 @@
|
|
|
445
445
|
|
|
446
446
|
<div class="alarm-ultimate-editor">
|
|
447
447
|
<div class="form-row">
|
|
448
|
-
<
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
448
|
+
<label>VIDEO</label>
|
|
449
|
+
<a
|
|
450
|
+
target="_blank"
|
|
451
|
+
rel="noopener noreferrer"
|
|
452
|
+
href="https://www.youtube.com/watch?v=HUPzhVgObBE&list=PL9Yh1bjbLAYrybBZKykfKLDrRAspj9to4"
|
|
453
|
+
><i class="fa fa-youtube-play" style="color:#cc0000;"></i> See it on YouTube</a>
|
|
454
|
+
</div>
|
|
455
|
+
|
|
456
|
+
<div class="form-row">
|
|
457
|
+
<b>Alarm System Ultimate</b>
|
|
458
|
+
<span style="color:red">
|
|
459
|
+
<i class="fa fa-question-circle"></i> <a
|
|
460
|
+
target="_blank"
|
|
461
|
+
href="https://github.com/Supergiovane/node-red-contrib-alarm-ultimate"
|
|
462
|
+
><u>Help online</u></a>
|
|
463
|
+
</span>
|
|
463
464
|
</div>
|
|
464
465
|
|
|
465
466
|
<div class="form-row">
|
|
@@ -742,12 +743,12 @@
|
|
|
742
743
|
</script>
|
|
743
744
|
|
|
744
745
|
<script type="text/markdown" data-help-name="AlarmSystemUltimate">
|
|
745
|
-
<p
|
|
746
|
+
<p>Alarm control panel node with a single armed/disarmed state, zones, entry/exit delays, bypass, chime, tamper/fire/24h zones, siren control, status and event log.</p>
|
|
746
747
|
|
|
747
748
|
## Quick start (5 minutes)
|
|
748
749
|
|
|
749
|
-
1. Add an **Alarm System
|
|
750
|
-
2. Click **Manage zones** and create at least one zone (example topic: `sensor/frontdoor`).
|
|
750
|
+
1. Add an **Alarm System** node to your flow.
|
|
751
|
+
2. Click **Manage zones** and create at least one zone (example topic: `sensor/frontdoor`). For backup/restore use **Export Zones** / **Import Zones** in the **Settings** web page.
|
|
751
752
|
**Important:** after editing zones, click **Done** in the Node-RED editor to save (if you click **Cancel**, changes are lost).
|
|
752
753
|
3. Send sensor messages to the Alarm node:
|
|
753
754
|
- open: `msg.topic="sensor/frontdoor"` + `msg.payload=true` (also works: `"open"`, `"on"`, `1`)
|
|
@@ -768,10 +769,11 @@
|
|
|
768
769
|
|
|
769
770
|
<br/>
|
|
770
771
|
|
|
771
|
-
###
|
|
772
|
+
### Editor and web pages
|
|
772
773
|
|
|
773
774
|
- **Panel**: `/alarm-ultimate/alarm-panel` (supports `?id=<alarmNodeId>` and `?embed=1&id=<alarmNodeId>`).
|
|
774
|
-
- **Zones**: use **Manage zones** to open `/alarm-ultimate/alarm-json-mapper` and sync
|
|
775
|
+
- **Zones**: use **Manage zones** to open `/alarm-ultimate/alarm-json-mapper` and sync zones back into the editor. Click **Done** in the Node-RED node editor to apply/save.
|
|
776
|
+
- **Settings**: open `/alarm-ultimate/alarm-settings` to **Export Zones** / **Import Zones**.
|
|
775
777
|
- **Name**: optional label shown in the Alarm Panel.
|
|
776
778
|
- **Control topic**: topic that receives commands (and is used as base for some outputs).
|
|
777
779
|
- **With Input**: message property evaluated as sensor value (default `payload`). It must be convertible to boolean (`true/false`, `open/closed`, `on/off`, `1/0`, ...).
|
|
@@ -799,11 +801,11 @@
|
|
|
799
801
|
| Emit restore events | Emits `zone_restore` when a zone returns to false. |
|
|
800
802
|
| Event log size | Max stored log entries in node context (0 disables log). |
|
|
801
803
|
| Sync other alarms | Optional: when this node is armed/disarmed, it can arm/disarm other Alarm nodes. The original `msg.code` is forwarded. |
|
|
802
|
-
| Zones | Zone definitions. Use **Manage zones**
|
|
804
|
+
| Zones | Zone definitions. Use **Manage zones** to edit them in the web page (including optional supervision). For backup/restore use **Settings** → **Export Zones / Import Zones**. |
|
|
803
805
|
|
|
804
806
|
<br/>
|
|
805
807
|
|
|
806
|
-
## Zones
|
|
808
|
+
## Zones (advanced, optional)
|
|
807
809
|
|
|
808
810
|
Each zone can optionally enable **sensor supervision** (per-zone): if no valid sensor updates are received within `timeoutSeconds`, the node emits `supervision_lost` (supervision starts immediately when the node runs, and `supervision_restored` is emitted on the next valid update).
|
|
809
811
|
|
|
@@ -826,11 +828,11 @@
|
|
|
826
828
|
|
|
827
829
|
<br/>
|
|
828
830
|
|
|
829
|
-
## Output
|
|
831
|
+
## Output reference
|
|
830
832
|
|
|
831
833
|
The node has **9 outputs** (pins).
|
|
832
834
|
|
|
833
|
-
Important: **Output #1 (All messages)**
|
|
835
|
+
Important: **Output #1 (All messages)** includes everything from the other outputs. It can emit:
|
|
834
836
|
|
|
835
837
|
- a single message, or
|
|
836
838
|
- an array of messages (for example, when the node emits an event **and** a siren update at the same time).
|
|
@@ -888,7 +890,7 @@
|
|
|
888
890
|
|
|
889
891
|
<br/>
|
|
890
892
|
|
|
891
|
-
##
|
|
893
|
+
## Event reference (`msg.event`, optional)
|
|
892
894
|
|
|
893
895
|
Arming / state:
|
|
894
896
|
|
|
@@ -920,7 +922,7 @@
|
|
|
920
922
|
|
|
921
923
|
<br/>
|
|
922
924
|
|
|
923
|
-
## Control
|
|
925
|
+
## Control message reference (`msg.topic === controlTopic`)
|
|
924
926
|
|
|
925
927
|
Arm:
|
|
926
928
|
|
|
@@ -936,11 +938,11 @@
|
|
|
936
938
|
|
|
937
939
|
- `msg.command = "status"` or `msg.status = true`
|
|
938
940
|
|
|
939
|
-
|
|
941
|
+
Bypass / unbypass (zone topic):
|
|
940
942
|
|
|
941
943
|
- `msg.command = "bypass"` / `msg.command = "unbypass"`
|
|
942
944
|
- or `msg.bypass = true` / `msg.unbypass = true`
|
|
943
|
-
|
|
945
|
+
- pass the zone **topic** in `msg.zoneTopic`
|
|
944
946
|
|
|
945
947
|
Siren:
|
|
946
948
|
|
|
@@ -962,18 +964,18 @@
|
|
|
962
964
|
|
|
963
965
|
<br/>
|
|
964
966
|
|
|
965
|
-
##
|
|
967
|
+
## Zone fields
|
|
966
968
|
|
|
967
|
-
|
|
969
|
+
Zones must be configured as a JSON array of objects.
|
|
968
970
|
|
|
969
|
-
|
|
971
|
+
Minimal fields:
|
|
970
972
|
|
|
971
|
-
|
|
973
|
+
- `topic` (exact topic, or a prefix ending with `*`)
|
|
972
974
|
|
|
973
|
-
|
|
975
|
+
Common fields:
|
|
974
976
|
|
|
975
|
-
|
|
976
|
-
|
|
977
|
+
- `topic`: **unique identifier** of the zone (used for bypass via `msg.zoneTopic`)
|
|
978
|
+
- `name`: label used in events (optional; defaults to `topic`)
|
|
977
979
|
- `type`: `perimeter` (default), `motion`, `tamper`, `fire`, `24h`
|
|
978
980
|
- `entry`: `true` to use entry delay, otherwise triggers instantly
|
|
979
981
|
- `entryDelaySeconds`: overrides the global entry delay
|
|
@@ -989,13 +991,13 @@
|
|
|
989
991
|
|
|
990
992
|
Example (formatted JSON array):
|
|
991
993
|
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
994
|
+
```json
|
|
995
|
+
[
|
|
996
|
+
{
|
|
997
|
+
"name": "Front door",
|
|
998
|
+
"topic": "house/door/front",
|
|
999
|
+
"type": "perimeter",
|
|
1000
|
+
"entry": true,
|
|
999
1001
|
"entryDelaySeconds": 30,
|
|
1000
1002
|
"bypassable": true,
|
|
1001
1003
|
"chime": true
|
|
@@ -97,6 +97,22 @@ module.exports = function (RED) {
|
|
|
97
97
|
});
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
function sendToolAssetFile(res, filename) {
|
|
101
|
+
const assetsRoot = path.join(__dirname, '..', 'tools', 'assets');
|
|
102
|
+
const requested = String(filename || '').replace(/^\/+/, '');
|
|
103
|
+
const rootPath = path.resolve(assetsRoot);
|
|
104
|
+
const fullPath = path.resolve(rootPath, requested);
|
|
105
|
+
if (!fullPath.startsWith(rootPath + path.sep)) {
|
|
106
|
+
res.status(403).end();
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
res.sendFile(fullPath, (err) => {
|
|
110
|
+
if (err) {
|
|
111
|
+
res.status(err.statusCode || 404).end();
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
100
116
|
RED.httpAdmin.get('/alarm-ultimate/alarm-json-mapper', needsRead, (req, res) => {
|
|
101
117
|
sendToolFile(res, 'alarm-json-mapper.html');
|
|
102
118
|
});
|
|
@@ -105,6 +121,14 @@ module.exports = function (RED) {
|
|
|
105
121
|
sendToolFile(res, 'alarm-panel.html');
|
|
106
122
|
});
|
|
107
123
|
|
|
124
|
+
RED.httpAdmin.get('/alarm-ultimate/alarm-settings', needsRead, (req, res) => {
|
|
125
|
+
sendToolFile(res, 'alarm-settings.html');
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
RED.httpAdmin.get('/alarm-ultimate/alarm-tools/assets/:file', needsRead, (req, res) => {
|
|
129
|
+
sendToolAssetFile(res, req.params.file);
|
|
130
|
+
});
|
|
131
|
+
|
|
108
132
|
RED.httpAdmin.get('/alarm-ultimate/alarm/nodes', needsRead, (req, res) => {
|
|
109
133
|
const nodes = Array.from(alarmInstances.values()).map((api) => ({
|
|
110
134
|
id: api.id,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script type="text/javascript">
|
|
2
2
|
RED.nodes.registerType("AlarmUltimateSiren", {
|
|
3
3
|
category: "Alarm Ultimate",
|
|
4
|
-
color: "#
|
|
4
|
+
color: "#E6C58A",
|
|
5
5
|
defaults: {
|
|
6
6
|
name: { value: "" },
|
|
7
7
|
alarmId: { value: "", required: true },
|
|
@@ -61,6 +61,15 @@
|
|
|
61
61
|
</script>
|
|
62
62
|
|
|
63
63
|
<script type="text/html" data-template-name="AlarmUltimateSiren">
|
|
64
|
+
<div class="form-row">
|
|
65
|
+
<label>VIDEO</label>
|
|
66
|
+
<a
|
|
67
|
+
target="_blank"
|
|
68
|
+
rel="noopener noreferrer"
|
|
69
|
+
href="https://www.youtube.com/watch?v=HUPzhVgObBE&list=PL9Yh1bjbLAYrybBZKykfKLDrRAspj9to4"
|
|
70
|
+
><i class="fa fa-youtube-play" style="color:#cc0000;"></i> See it on YouTube</a>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
64
73
|
<div class="form-row">
|
|
65
74
|
<label>WEB PAGE</label>
|
|
66
75
|
<button type="button" class="red-ui-button" id="node-input-alarm-panel">
|
|
@@ -103,10 +112,10 @@ Output message (same format as the Alarm node siren output):
|
|
|
103
112
|
- `msg.event`: `siren_on` or `siren_off`
|
|
104
113
|
- `msg.payload`: `true` when the siren is on, otherwise `false`
|
|
105
114
|
- `msg.reason`: `manual|timeout|arm|disarm|...`
|
|
106
|
-
- `msg.alarmUltimate`:
|
|
115
|
+
- `msg.alarmUltimate`: optional standard object with extra alarm details
|
|
107
116
|
|
|
108
117
|
Notes:
|
|
109
118
|
|
|
110
|
-
- No
|
|
119
|
+
- No wire from the Alarm node is required: just select the Alarm node in this editor.
|
|
111
120
|
- Use the **Panel** button to open the Alarm Panel preselected on the chosen Alarm node.
|
|
112
121
|
</script>
|
|
@@ -17,6 +17,13 @@ module.exports = function (RED) {
|
|
|
17
17
|
const outputInitialState = config.outputInitialState !== false;
|
|
18
18
|
|
|
19
19
|
let lastActive = null;
|
|
20
|
+
let initRetryInterval = null;
|
|
21
|
+
|
|
22
|
+
function stopInitRetryInterval() {
|
|
23
|
+
if (!initRetryInterval) return;
|
|
24
|
+
timerBag.clearInterval(initRetryInterval);
|
|
25
|
+
initRetryInterval = null;
|
|
26
|
+
}
|
|
20
27
|
|
|
21
28
|
function buildTopic(controlTopic) {
|
|
22
29
|
if (configuredTopic) return configuredTopic;
|
|
@@ -28,6 +35,7 @@ module.exports = function (RED) {
|
|
|
28
35
|
if (typeof active !== 'boolean') return;
|
|
29
36
|
if (lastActive === active && reason !== 'init') return;
|
|
30
37
|
lastActive = active;
|
|
38
|
+
stopInitRetryInterval();
|
|
31
39
|
|
|
32
40
|
setNodeStatus({
|
|
33
41
|
fill: active ? 'red' : 'green',
|
|
@@ -80,10 +88,12 @@ module.exports = function (RED) {
|
|
|
80
88
|
|
|
81
89
|
if (outputInitialState) {
|
|
82
90
|
timerBag.setTimeout(() => emitCurrent('init'), 0);
|
|
83
|
-
timerBag.setInterval(() => {
|
|
91
|
+
initRetryInterval = timerBag.setInterval(() => {
|
|
84
92
|
if (lastActive === null) {
|
|
85
93
|
emitCurrent('init_retry');
|
|
94
|
+
return;
|
|
86
95
|
}
|
|
96
|
+
stopInitRetryInterval();
|
|
87
97
|
}, 1000);
|
|
88
98
|
} else {
|
|
89
99
|
setNodeStatus({ fill: 'grey', shape: 'ring', text: 'Ready' });
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script type="text/javascript">
|
|
2
2
|
RED.nodes.registerType("AlarmUltimateState", {
|
|
3
3
|
category: "Alarm Ultimate",
|
|
4
|
-
color: "#
|
|
4
|
+
color: "#E8D6AA",
|
|
5
5
|
defaults: {
|
|
6
6
|
name: { value: "" },
|
|
7
7
|
alarmId: { value: "", required: true },
|
|
@@ -92,6 +92,15 @@
|
|
|
92
92
|
</script>
|
|
93
93
|
|
|
94
94
|
<script type="text/html" data-template-name="AlarmUltimateState">
|
|
95
|
+
<div class="form-row">
|
|
96
|
+
<label>VIDEO</label>
|
|
97
|
+
<a
|
|
98
|
+
target="_blank"
|
|
99
|
+
rel="noopener noreferrer"
|
|
100
|
+
href="https://www.youtube.com/watch?v=HUPzhVgObBE&list=PL9Yh1bjbLAYrybBZKykfKLDrRAspj9to4"
|
|
101
|
+
><i class="fa fa-youtube-play" style="color:#cc0000;"></i> See it on YouTube</a>
|
|
102
|
+
</div>
|
|
103
|
+
|
|
95
104
|
<div class="form-row">
|
|
96
105
|
<label>WEB PAGE</label>
|
|
97
106
|
<button type="button" class="red-ui-button" id="node-input-alarm-panel">
|
|
@@ -157,11 +166,11 @@ Output message (same format as the Alarm node `.../event` output):
|
|
|
157
166
|
- `msg.payload`: `true|false` (armed/active boolean)
|
|
158
167
|
- `msg.mode`: `armed|disarmed`
|
|
159
168
|
- other event fields (reason, seconds, violations, ...) are emitted as **root properties** on `msg`
|
|
160
|
-
- `msg.alarmUltimate`:
|
|
169
|
+
- `msg.alarmUltimate`: optional standard object with extra alarm details
|
|
161
170
|
|
|
162
171
|
Notes:
|
|
163
172
|
|
|
164
|
-
- No
|
|
173
|
+
- No wire from the Alarm node is required: just select the Alarm node in this editor.
|
|
165
174
|
- Use the **Panel** button to open the Alarm Panel preselected on the chosen Alarm node.
|
|
166
175
|
|
|
167
176
|
## Input mode details
|
|
@@ -206,7 +215,7 @@ Only arming/disarming CID codes are handled (other CID events are ignored):
|
|
|
206
215
|
- `3441` → `arm` (Stay)
|
|
207
216
|
- `1401` → `disarm`
|
|
208
217
|
|
|
209
|
-
##
|
|
218
|
+
## Adapter output behavior
|
|
210
219
|
|
|
211
220
|
- **Default / Ax Pro**: keeps a boolean `msg.payload` and emits details as root properties.
|
|
212
221
|
- **Homekit**: emits `msg.SecuritySystemTargetState` and `msg.SecuritySystemCurrentState` as root properties (while keeping boolean `msg.payload`).
|
|
@@ -286,6 +286,13 @@ module.exports = function (RED) {
|
|
|
286
286
|
const adapter = typeof config.adapter === 'string' && config.adapter.trim() ? config.adapter.trim() : 'default';
|
|
287
287
|
|
|
288
288
|
let lastMode = null;
|
|
289
|
+
let initRetryInterval = null;
|
|
290
|
+
|
|
291
|
+
function stopInitRetryInterval() {
|
|
292
|
+
if (!initRetryInterval) return;
|
|
293
|
+
timerBag.clearInterval(initRetryInterval);
|
|
294
|
+
initRetryInterval = null;
|
|
295
|
+
}
|
|
289
296
|
|
|
290
297
|
function buildTopic(controlTopic) {
|
|
291
298
|
if (configuredTopic) return configuredTopic;
|
|
@@ -325,6 +332,7 @@ module.exports = function (RED) {
|
|
|
325
332
|
return;
|
|
326
333
|
}
|
|
327
334
|
lastMode = m;
|
|
335
|
+
stopInitRetryInterval();
|
|
328
336
|
}
|
|
329
337
|
|
|
330
338
|
setNodeStatus({
|
|
@@ -479,10 +487,12 @@ module.exports = function (RED) {
|
|
|
479
487
|
|
|
480
488
|
if (outputInitialState) {
|
|
481
489
|
timerBag.setTimeout(() => emitCurrent('init'), 0);
|
|
482
|
-
timerBag.setInterval(() => {
|
|
490
|
+
initRetryInterval = timerBag.setInterval(() => {
|
|
483
491
|
if (lastMode === null) {
|
|
484
492
|
emitCurrent('init_retry');
|
|
493
|
+
return;
|
|
485
494
|
}
|
|
495
|
+
stopInitRetryInterval();
|
|
486
496
|
}, 1000);
|
|
487
497
|
} else {
|
|
488
498
|
setNodeStatus({ fill: 'grey', shape: 'ring', text: `Ready (${adapter || 'default'})` });
|