node-red-contrib-alarm-ultimate 0.1.1 → 0.1.3

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.
@@ -11,7 +11,7 @@
11
11
  "type": "comment",
12
12
  "z": "a9f3e19b2b7c4d01",
13
13
  "name": "Requires node-red-dashboard",
14
- "info": "Installa `node-red-dashboard`, poi importa questo flow.\n\nSe hai cambiato `httpAdminRoot`, modifica l'URL dell'iframe nel nodo ui_template.",
14
+ "info": "Installa `node-red-dashboard`, poi importa questo flow.\n\nL'iframe usa un URL *relativo* che esce da `/ui` (`../alarm-ultimate/...`) così funziona anche con un path prefix (es. Home Assistant Ingress).\nPuoi usare anche `view=log` per mostrare il registro eventi all'utente.",
15
15
  "x": 200,
16
16
  "y": 60,
17
17
  "wires": []
@@ -35,6 +35,17 @@
35
35
  "collapse": false,
36
36
  "className": ""
37
37
  },
38
+ {
39
+ "id": "1e2d3c4b5a697801",
40
+ "type": "ui_group",
41
+ "name": "Log",
42
+ "tab": "f1c9d0f3d9b8a001",
43
+ "order": 2,
44
+ "disp": true,
45
+ "width": "12",
46
+ "collapse": false,
47
+ "className": ""
48
+ },
38
49
  {
39
50
  "id": "a1b2c3d4e5f6a7b8",
40
51
  "type": "AlarmSystemUltimate",
@@ -42,7 +53,6 @@
42
53
  "name": "Home Alarm",
43
54
  "controlTopic": "alarm",
44
55
  "payloadPropName": "payload",
45
- "translatorConfig": "",
46
56
  "persistState": true,
47
57
  "requireCodeForArm": false,
48
58
  "requireCodeForDisarm": false,
@@ -88,12 +98,31 @@
88
98
  "order": 1,
89
99
  "width": "12",
90
100
  "height": "18",
91
- "format": "<iframe src=\"/alarm-ultimate/alarm-panel?embed=1&id=a1b2c3d4e5f6a7b8\" style=\"width:100%; height:720px; border:0; border-radius:10px;\"></iframe>",
101
+ "format": "<iframe src=\"../alarm-ultimate/alarm-panel?embed=1&id=a1b2c3d4e5f6a7b8\" style=\"width:100%; height:720px; border:0; border-radius:10px;\"></iframe>",
92
102
  "storeOutMessages": false,
93
103
  "fwdInMessages": false,
94
104
  "resendOnRefresh": true,
95
105
  "templateScope": "local",
96
- "className": ""
106
+ "className": "",
107
+ "x": 520,
108
+ "y": 160
109
+ },
110
+ {
111
+ "id": "2f1e0d3c4b5a6978",
112
+ "type": "ui_template",
113
+ "z": "a9f3e19b2b7c4d01",
114
+ "group": "1e2d3c4b5a697801",
115
+ "name": "Alarm Log (embed)",
116
+ "order": 1,
117
+ "width": "12",
118
+ "height": "10",
119
+ "format": "<iframe src=\"../alarm-ultimate/alarm-panel?embed=1&view=log&id=a1b2c3d4e5f6a7b8\" style=\"width:100%; height:420px; border:0; border-radius:10px;\"></iframe>",
120
+ "storeOutMessages": false,
121
+ "fwdInMessages": false,
122
+ "resendOnRefresh": true,
123
+ "templateScope": "local",
124
+ "className": "",
125
+ "x": 520,
126
+ "y": 220
97
127
  }
98
128
  ]
99
-
@@ -0,0 +1,335 @@
1
+ [
2
+ {
3
+ "id": "b3b0c2c1a9e7d001",
4
+ "type": "tab",
5
+ "label": "Alarm Ultimate - Home Assistant (Alarm Panel)",
6
+ "disabled": false,
7
+ "info": ""
8
+ },
9
+ {
10
+ "id": "8b2d0e6a71a54e10",
11
+ "type": "comment",
12
+ "z": "b3b0c2c1a9e7d001",
13
+ "name": "Home Assistant integration (no MQTT)",
14
+ "info": "Requires `node-red-contrib-home-assistant-websocket`.\n\nThis example is designed for Node-RED running as the Home Assistant Add-on.\n\nWhat it does:\n- Takes Home Assistant `binary_sensor.*` state changes (\"on\"/\"off\") and feeds Alarm zones.\n- Receives arm/disarm commands from a Home Assistant Template Alarm Control Panel via an HA event.\n- Mirrors Alarm events back into Home Assistant by updating `input_select.alarm_ultimate_state`.\n\nYou must create in Home Assistant:\n1) An input_select named `input_select.alarm_ultimate_state` with options:\n - disarmed\n - arming\n - armed_away\n - armed_home\n - pending\n - triggered\n2) A Template Alarm Control Panel (example YAML):\n\ntemplate:\n - alarm_control_panel:\n - name: \"Alarm Ultimate\"\n unique_id: alarm_ultimate\n state: \"{{ states('input_select.alarm_ultimate_state') }}\"\n code_format: no_code\n arm_away:\n - event: alarm_ultimate_command\n event_data:\n action: arm_away\n arm_home:\n - event: alarm_ultimate_command\n event_data:\n action: arm_home\n disarm:\n - event: alarm_ultimate_command\n event_data:\n action: disarm\n trigger:\n - event: alarm_ultimate_command\n event_data:\n action: trigger\n\nThen add the standard HA \"Alarm panel\" card and select this entity.\n\nEdit these entities in this flow:\n- binary_sensor.front_door_contact\n- binary_sensor.living_room_motion\n\nAnd edit the Alarm zones topic to match those entity_ids (already set in this example).\n",
15
+ "x": 330,
16
+ "y": 60,
17
+ "wires": []
18
+ },
19
+ {
20
+ "id": "a6c9d8f2b7f24a10",
21
+ "type": "server",
22
+ "name": "Home Assistant",
23
+ "addon": true,
24
+ "rejectUnauthorizedCerts": true,
25
+ "ha_boolean": "y|yes|true|on|home|open",
26
+ "connectionDelay": true,
27
+ "cacheJson": true,
28
+ "heartbeat": false,
29
+ "heartbeatInterval": "30",
30
+ "areaSelector": "id",
31
+ "deviceSelector": "id",
32
+ "entitySelector": "id",
33
+ "statusSeparator": "at: ",
34
+ "statusYear": "hidden",
35
+ "statusMonth": "short",
36
+ "statusDay": "numeric",
37
+ "statusHourCycle": "default",
38
+ "statusTimeFormat": "h:m",
39
+ "enableGlobalContextStore": false,
40
+ "version": 5
41
+ },
42
+ {
43
+ "id": "d0c1b2a3f4e50617",
44
+ "type": "AlarmSystemUltimate",
45
+ "z": "b3b0c2c1a9e7d001",
46
+ "name": "Home Alarm",
47
+ "controlTopic": "alarm",
48
+ "payloadPropName": "payload",
49
+ "persistState": true,
50
+ "requireCodeForArm": false,
51
+ "requireCodeForDisarm": false,
52
+ "armCode": "",
53
+ "duressCode": "",
54
+ "blockArmOnViolations": true,
55
+ "exitDelaySeconds": 10,
56
+ "entryDelaySeconds": 30,
57
+ "emitOpenZonesDuringArming": false,
58
+ "openZonesArmingIntervalSeconds": 1,
59
+ "openZonesRequestTopic": "alarm/listOpenZones",
60
+ "openZonesRequestIntervalSeconds": 0,
61
+ "sirenDurationSeconds": 180,
62
+ "sirenLatchUntilDisarm": false,
63
+ "sirenTopic": "alarm/siren",
64
+ "sirenOnPayload": true,
65
+ "sirenOnPayloadType": "bool",
66
+ "sirenOffPayload": false,
67
+ "sirenOffPayloadType": "bool",
68
+ "emitRestoreEvents": false,
69
+ "maxLogEntries": 200,
70
+ "zones": "[\n {\n \"id\": \"front_door\",\n \"name\": \"Front door\",\n \"topic\": \"binary_sensor.front_door_contact\",\n \"type\": \"perimeter\",\n \"entry\": true,\n \"bypassable\": true,\n \"chime\": true\n },\n {\n \"id\": \"living_pir\",\n \"name\": \"Living room motion\",\n \"topic\": \"binary_sensor.living_room_motion\",\n \"type\": \"motion\",\n \"entry\": false,\n \"bypassable\": true,\n \"cooldownSeconds\": 10\n }\n]",
71
+ "x": 760,
72
+ "y": 240,
73
+ "wires": [
74
+ [
75
+ "e3e4f5060718293a",
76
+ "3f50b6a7c1c8b3d10"
77
+ ],
78
+ [
79
+ "3f50b6a7c1c8b3d11"
80
+ ],
81
+ [],
82
+ [],
83
+ [],
84
+ [
85
+ "3f50b6a7c1c8b3d12"
86
+ ],
87
+ [],
88
+ [],
89
+ []
90
+ ]
91
+ },
92
+ {
93
+ "id": "c44ac2b6af1a1e2a",
94
+ "type": "AlarmUltimateInputAdapter",
95
+ "z": "b3b0c2c1a9e7d001",
96
+ "name": "HA sensors on/off → boolean",
97
+ "presetSource": "builtin",
98
+ "presetId": "home_assistant_on_off",
99
+ "userCode": "return msg;",
100
+ "x": 500,
101
+ "y": 240,
102
+ "wires": [
103
+ [
104
+ "d0c1b2a3f4e50617"
105
+ ]
106
+ ]
107
+ },
108
+ {
109
+ "id": "c2b3a4d5e6f70819",
110
+ "type": "server-state-changed",
111
+ "z": "b3b0c2c1a9e7d001",
112
+ "name": "HA binary_sensor.* → Alarm zones",
113
+ "server": "a6c9d8f2b7f24a10",
114
+ "version": 6,
115
+ "outputs": 1,
116
+ "exposeAsEntityConfig": "",
117
+ "entities": {
118
+ "entity": [
119
+ "binary_sensor.front_door_contact",
120
+ "binary_sensor.living_room_motion"
121
+ ],
122
+ "substring": [],
123
+ "regex": []
124
+ },
125
+ "outputInitially": true,
126
+ "stateType": "str",
127
+ "ifState": "",
128
+ "ifStateType": "str",
129
+ "ifStateOperator": "is",
130
+ "outputOnlyOnStateChange": true,
131
+ "for": "0",
132
+ "forType": "num",
133
+ "forUnits": "seconds",
134
+ "ignorePrevStateNull": false,
135
+ "ignorePrevStateUnknown": false,
136
+ "ignorePrevStateUnavailable": false,
137
+ "ignoreCurrentStateUnknown": false,
138
+ "ignoreCurrentStateUnavailable": false,
139
+ "outputProperties": [
140
+ {
141
+ "property": "topic",
142
+ "propertyType": "msg",
143
+ "value": "triggerId",
144
+ "valueType": "eventData"
145
+ },
146
+ {
147
+ "property": "payload",
148
+ "propertyType": "msg",
149
+ "value": "new_state.state",
150
+ "valueType": "eventData"
151
+ }
152
+ ],
153
+ "x": 220,
154
+ "y": 240,
155
+ "wires": [
156
+ [
157
+ "c44ac2b6af1a1e2a"
158
+ ]
159
+ ]
160
+ },
161
+ {
162
+ "id": "e1f2a3b4c5d60718",
163
+ "type": "server-events",
164
+ "z": "b3b0c2c1a9e7d001",
165
+ "name": "HA event: alarm_ultimate_command",
166
+ "server": "a6c9d8f2b7f24a10",
167
+ "version": 3,
168
+ "exposeAsEntityConfig": "",
169
+ "eventType": "alarm_ultimate_command",
170
+ "eventData": "",
171
+ "waitForRunning": true,
172
+ "outputProperties": [
173
+ {
174
+ "property": "payload",
175
+ "propertyType": "msg",
176
+ "value": "",
177
+ "valueType": "eventData"
178
+ }
179
+ ],
180
+ "x": 230,
181
+ "y": 380,
182
+ "wires": [
183
+ [
184
+ "f2a3b4c5d6e70819"
185
+ ]
186
+ ]
187
+ },
188
+ {
189
+ "id": "f2a3b4c5d6e70819",
190
+ "type": "function",
191
+ "z": "b3b0c2c1a9e7d001",
192
+ "name": "HA command → Alarm control msg",
193
+ "func": "const root = msg && typeof msg === \"object\" ? msg : {};\nconst eventData = root.payload && typeof root.payload === \"object\" ? root.payload : {};\nconst ev = eventData.event && typeof eventData.event === \"object\" ? eventData.event : {};\n\nconst action = String(ev.action || ev.command || \"\").trim().toLowerCase();\nconst mode = String(ev.mode || \"\").trim().toLowerCase();\nconst code = typeof ev.code === \"string\" ? ev.code.trim() : \"\";\n\nif (!action) return null;\n\nconst out = { topic: \"alarm\" };\n\nif (action === \"disarm\") {\n out.command = \"disarm\";\n} else if (action === \"trigger\" || action === \"panic\") {\n out.command = \"panic\";\n} else if (action.startsWith(\"arm\")) {\n out.command = \"arm\";\n} else {\n return null;\n}\n\nif (code) out.code = code;\nif (mode) {\n // AlarmSystemUltimate maps legacy modes to \"armed\".\n out.mode = mode;\n}\n\n// Remember last requested arm mode to map HA state on \"armed\" events.\nif (out.command === \"arm\") {\n const map = {\n arm_home: \"armed_home\",\n arm_away: \"armed_away\",\n arm_night: \"armed_home\",\n arm: \"armed_away\",\n };\n flow.set(\"alarmUltimate:lastArmMode\", map[action] || \"armed_away\");\n}\n\nreturn out;",
194
+ "outputs": 1,
195
+ "noerr": 0,
196
+ "initialize": "",
197
+ "finalize": "",
198
+ "libs": [],
199
+ "x": 520,
200
+ "y": 380,
201
+ "wires": [
202
+ [
203
+ "d0c1b2a3f4e50617"
204
+ ]
205
+ ]
206
+ },
207
+ {
208
+ "id": "e3e4f5060718293a",
209
+ "type": "function",
210
+ "z": "b3b0c2c1a9e7d001",
211
+ "name": "Alarm events → HA alarm state",
212
+ "func": "const evt = msg && typeof msg.event === \"string\" ? msg.event : \"\";\nlet haState = null;\n\nif (evt === \"disarmed\" || evt === \"reset\") {\n haState = \"disarmed\";\n} else if (evt === \"arming\") {\n haState = \"arming\";\n} else if (evt === \"armed\") {\n haState = flow.get(\"alarmUltimate:lastArmMode\") || \"armed_away\";\n} else if (evt === \"entry_delay\") {\n haState = \"pending\";\n} else if (evt === \"alarm\") {\n haState = \"triggered\";\n}\n\nif (!haState) return null;\n\nmsg.haState = haState;\nreturn msg;",
213
+ "outputs": 1,
214
+ "noerr": 0,
215
+ "initialize": "",
216
+ "finalize": "",
217
+ "libs": [],
218
+ "x": 520,
219
+ "y": 500,
220
+ "wires": [
221
+ [
222
+ "a1b2c3d4e5f60718"
223
+ ]
224
+ ]
225
+ },
226
+ {
227
+ "id": "a1b2c3d4e5f60718",
228
+ "type": "api-call-service",
229
+ "z": "b3b0c2c1a9e7d001",
230
+ "name": "Set input_select.alarm_ultimate_state",
231
+ "server": "a6c9d8f2b7f24a10",
232
+ "version": 5,
233
+ "debugenabled": false,
234
+ "domain": "input_select",
235
+ "service": "select_option",
236
+ "areaId": [],
237
+ "deviceId": [],
238
+ "entityId": [
239
+ "input_select.alarm_ultimate_state"
240
+ ],
241
+ "data": "{\"option\":haState}",
242
+ "dataType": "jsonata",
243
+ "mergeContext": "",
244
+ "mustacheAltTags": false,
245
+ "outputProperties": [],
246
+ "queue": "none",
247
+ "x": 830,
248
+ "y": 500,
249
+ "wires": [
250
+ []
251
+ ]
252
+ },
253
+ {
254
+ "id": "b0a1c2d3e4f50607",
255
+ "type": "inject",
256
+ "z": "b3b0c2c1a9e7d001",
257
+ "name": "Sync on deploy (status)",
258
+ "props": [
259
+ {
260
+ "p": "topic",
261
+ "v": "alarm",
262
+ "vt": "str"
263
+ },
264
+ {
265
+ "p": "command",
266
+ "v": "status",
267
+ "vt": "str"
268
+ }
269
+ ],
270
+ "repeat": "",
271
+ "crontab": "",
272
+ "once": true,
273
+ "onceDelay": 0.5,
274
+ "topic": "",
275
+ "x": 260,
276
+ "y": 500,
277
+ "wires": [
278
+ [
279
+ "d0c1b2a3f4e50617"
280
+ ]
281
+ ]
282
+ },
283
+ {
284
+ "id": "3f50b6a7c1c8b3d10",
285
+ "type": "debug",
286
+ "z": "b3b0c2c1a9e7d001",
287
+ "name": "All events",
288
+ "active": true,
289
+ "tosidebar": true,
290
+ "console": false,
291
+ "tostatus": false,
292
+ "complete": "true",
293
+ "targetType": "full",
294
+ "statusVal": "",
295
+ "statusType": "auto",
296
+ "x": 1040,
297
+ "y": 200,
298
+ "wires": []
299
+ },
300
+ {
301
+ "id": "3f50b6a7c1c8b3d11",
302
+ "type": "debug",
303
+ "z": "b3b0c2c1a9e7d001",
304
+ "name": "Siren output",
305
+ "active": true,
306
+ "tosidebar": true,
307
+ "console": false,
308
+ "tostatus": false,
309
+ "complete": "true",
310
+ "targetType": "full",
311
+ "statusVal": "",
312
+ "statusType": "auto",
313
+ "x": 1050,
314
+ "y": 240,
315
+ "wires": []
316
+ },
317
+ {
318
+ "id": "3f50b6a7c1c8b3d12",
319
+ "type": "debug",
320
+ "z": "b3b0c2c1a9e7d001",
321
+ "name": "Errors / denied",
322
+ "active": true,
323
+ "tosidebar": true,
324
+ "console": false,
325
+ "tostatus": false,
326
+ "complete": "true",
327
+ "targetType": "full",
328
+ "statusVal": "",
329
+ "statusType": "auto",
330
+ "x": 1060,
331
+ "y": 280,
332
+ "wires": []
333
+ }
334
+ ]
335
+