Skip to content

Commit ae1c040

Browse files
Add a new unifi-protect node (#48)
1 parent 38c7197 commit ae1c040

15 files changed

+1185
-57
lines changed

build/nodes/AccessController.html

Lines changed: 95 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,125 @@
11
<script type="text/javascript">
2-
RED.nodes.registerType('unifi-access-controller',
3-
{
4-
category: 'config',
5-
defaults:
6-
{
7-
name: {
8-
value: '',
9-
required: true
10-
},
11-
controllerIp: {
12-
value: '',
13-
required: true
14-
},
15-
controllerPort: {
16-
value: '',
17-
required: false
18-
},
19-
controllerType: {
20-
value: 'UniFiOSConsole',
21-
required: true
22-
}
23-
},
24-
credentials: {
25-
username: {type: "text"},
26-
password: {type: "password"}
2+
RED.nodes.registerType('unifi-access-controller', {
3+
category: 'config',
4+
defaults: {
5+
name: {
6+
value: '',
7+
required: true,
278
},
28-
label: function () {
29-
return this.name || "unifi-access-controller";
9+
controllerIp: {
10+
value: '',
11+
required: true,
3012
},
31-
labelStyle: function () {
32-
return this.name ? 'node_label_italic' : ''
33-
}
34-
});
13+
controllerPort: {
14+
value: '',
15+
required: false,
16+
},
17+
controllerType: {
18+
value: 'UniFiOSConsole',
19+
required: true,
20+
},
21+
protectSocketReconnectTimeout: {
22+
value: 0,
23+
validate: RED.validators.number(),
24+
required: true,
25+
},
26+
protectSocketHeartbeatInterval: {
27+
value: 0,
28+
validate: RED.validators.number(),
29+
required: true,
30+
},
31+
},
32+
oneditprepare: restoreValue,
33+
oneditsave: storeAsNumber,
34+
credentials: {
35+
username: { type: 'text' },
36+
password: { type: 'password' },
37+
},
38+
label: function () {
39+
return this.name || 'unifi-access-controller'
40+
},
41+
labelStyle: function () {
42+
return this.name ? 'node_label_italic' : ''
43+
},
44+
})
45+
46+
function storeAsNumber() {
47+
const el_protectSocketReconnectTimeout = $(
48+
'#el-node-config-input-protectSocketReconnectTimeout'
49+
)
50+
this.protectSocketReconnectTimeout = parseInt(
51+
el_protectSocketReconnectTimeout.val()
52+
)
53+
54+
const el_protectSocketHeartbeatInterval = $(
55+
'#el-node-config-input-protectSocketHeartbeatInterval'
56+
)
57+
this.protectSocketHeartbeatInterval = parseInt(
58+
el_protectSocketHeartbeatInterval.val()
59+
)
60+
}
61+
function restoreValue() {
62+
const reconnectValue = this.protectSocketReconnectTimeout || 0
63+
const heartBeatValue = this.protectSocketHeartbeatInterval || 0
64+
$('#el-node-config-input-protectSocketReconnectTimeout').val(
65+
reconnectValue
66+
)
67+
$('#el-node-config-input-protectSocketHeartbeatInterval').val(
68+
heartBeatValue
69+
)
70+
}
3571
</script>
3672

73+
<!-- prettier-ignore -->
3774
<script data-template-name="unifi-access-controller" type="text/html">
3875
<div class="form-row unifi-flex">
3976
<label for="node-config-input-name" class="unifi-width-50"><i class="fa fa-tag"></i> Name</label>
40-
<input type="text" id="node-config-input-name" class="unifi-grow" placeholder="Name">
77+
<input type="text" id="node-config-input-name" class="unifi-grow" placeholder="Name"/>
4178
</div>
4279
<div class="unifi-text-divider">Controller</div>
4380
<div class="form-row unifi-flex">
4481
<label for="node-config-input-controllerIp" class="unifi-width-50"><i class="fa fa-globe"></i> IP</label>
45-
<input type="text" id="node-config-input-controllerIp" class="unifi-grow" placeholder="Controller IP">
82+
<input type="text" id="node-config-input-controllerIp" class="unifi-grow" placeholder="Controller IP"/>
4683
</div>
4784
<div class="form-row unifi-flex">
4885
<label for="node-config-input-controllerPort" class="unifi-width-50"><i class="fa fa-globe"></i> Port</label>
49-
<input type="text" id="node-config-input-controllerPort" class="unifi-grow" placeholder="8443">
86+
<input type="text" id="node-config-input-controllerPort" class="unifi-grow" placeholder="8443"/>
5087
</div>
5188
<div class="form-row unifi-flex">
5289
<label for="node-config-input-controllerType" class="unifi-width-50"><i class="fa fa-server"></i> Type</label>
53-
<select id="node-config-input-controllerType" class="unifi-grow" >
54-
<option value="UniFiOSConsole" selected="selected">UniFi OS Console</option>
55-
<option value="UniFiNetworkApplication">UniFi Network Application</option>
90+
<select id="node-config-input-controllerType" class="unifi-grow">
91+
<option value="UniFiOSConsole" selected="selected">
92+
UniFi OS Console
93+
</option>
94+
<option value="UniFiNetworkApplication">
95+
UniFi Network Application
96+
</option>
5697
</select>
5798
</div>
99+
<div class="unifi-text-divider">Protect Shared Socket timeouts (ms, 0 - Use defaults)</div>
100+
<div class="form-row unifi-flex">
101+
<label for="el-node-config-input-protectSocketReconnectTimeout" class="unifi-width-50"><i class="fa fa-clock-o"></i> Reconnect</label>
102+
<input type="number" id="el-node-config-input-protectSocketReconnectTimeout" class="unifi-grow" placeholder="90000"/>
103+
</div>
104+
<div class="form-row unifi-flex">
105+
<label for="el-node-config-input-protectSocketHeartbeatInterval" class="unifi-width-50"><i class="fa fa-clock-o"></i> Heartbeat</label>
106+
<input type="number" id="el-node-config-input-protectSocketHeartbeatInterval" class="unifi-grow" placeholder="15000"/>
107+
</div>
58108
<div class="unifi-text-divider">Credentials</div>
59109
<div class="form-row unifi-flex">
60110
<label for="node-config-input-username" class="unifi-width-50"><i class="fa fa-user"></i> Username</label>
61-
<input type="text" id="node-config-input-username" class="unifi-grow" placeholder="Username">
111+
<input type="text" id="node-config-input-username" class="unifi-grow" placeholder="Username"/>
62112
</div>
63113
<div class="form-row unifi-flex">
64-
<label for="node-config-input-password" class="unifi-width-50"><i class="fa fa-key"></i> Password</label>
65-
<input type="password" id="node-config-input-password" class="unifi-grow" placeholder="Password">
114+
<label for="node-config-input-password" class="unifi-width-50" ><i class="fa fa-key"></i> Password</label>
115+
<input type="password" id="node-config-input-password" class="unifi-grow" placeholder="Password"/>
66116
</div>
67117
</script>
68118

119+
<!-- prettier-ignore -->
69120
<script data-help-name="unifi-access-controller" type="text/html">
70-
<p>A simple node that logs into Unifi OS and sends the cookies to a single output.</p>
121+
<p>
122+
A simple node that logs into Unifi OS and sends the cookies to a single
123+
output.
124+
</p>
71125
</script>
72-

build/nodes/Protect.html

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
<script type="text/javascript">
2+
let selectedCamera
3+
let selectedController
4+
RED.nodes.registerType('unifi-protect', {
5+
category: 'UniFi',
6+
defaults: {
7+
name: {
8+
value: '',
9+
required: false,
10+
},
11+
accessControllerNodeId: {
12+
value: '',
13+
type: 'unifi-access-controller',
14+
required: true,
15+
},
16+
cameraId: {
17+
value: '',
18+
required: true,
19+
},
20+
eventIds: {
21+
value: [],
22+
required: true,
23+
},
24+
snapshotMode: {
25+
value: 'None',
26+
required: true,
27+
},
28+
snapshotW: {
29+
validate: RED.validators.number(),
30+
value: 360,
31+
required: true,
32+
},
33+
snapshotH: {
34+
validate: RED.validators.number(),
35+
value: 360,
36+
required: true,
37+
},
38+
delayedSnapshotTime: {
39+
validate: RED.validators.number(),
40+
value: 2000,
41+
required: true,
42+
},
43+
},
44+
inputs: 1,
45+
outputs: 2,
46+
outputLabels: function (index) {
47+
switch (index) {
48+
case 0:
49+
return 'Event Data'
50+
51+
case 1:
52+
return 'Delayed Snapshots'
53+
54+
default:
55+
return ''
56+
}
57+
},
58+
icon: 'protect.png',
59+
color: '#159eda',
60+
label: function () {
61+
return this.name || 'Unifi Protect Camera'
62+
},
63+
labelStyle: function () {
64+
return this.name ? 'node_label_italic' : ''
65+
},
66+
oneditsave: function () {
67+
const Element = $('#el-node-input-delayedSnapshotTime')
68+
this.delayedSnapshotTime = parseInt(Element.val())
69+
},
70+
oneditprepare: function () {
71+
selectedCamera = undefined
72+
$('#el-node-input-delayedSnapshotTime').val(
73+
this.delayedSnapshotTime
74+
)
75+
if (this.cameraId) {
76+
selectedCamera = this.cameraId
77+
}
78+
$('#node-input-accessControllerNodeId').change(controllerSelected)
79+
showHideSnapshotOptions()
80+
},
81+
})
82+
83+
function controllerSelected() {
84+
const ControllerID = $('#node-input-accessControllerNodeId').val()
85+
if (ControllerID && ControllerID !== '_ADD_') {
86+
listCameras(ControllerID)
87+
}
88+
}
89+
90+
function listCameras(ControllerID) {
91+
$('#node-input-cameraId').empty()
92+
$('#node-input-cameraId').append(
93+
`<option value="" selected>Choose...</option>`
94+
)
95+
96+
$.getJSON(`nrchkb/unifi/bootsrap/${ControllerID}`, (data) => {
97+
data.cameras.forEach((Camera) => {
98+
$('#node-input-cameraId').append(
99+
`<option value="${Camera.id}">${Camera.name} (${Camera.type})</option>`
100+
)
101+
})
102+
if (selectedCamera) {
103+
$('#node-input-cameraId').val(selectedCamera)
104+
}
105+
$('#node-warning').fadeOut('fast')
106+
}).fail(function () {
107+
$('#node-warning').fadeIn('fast')
108+
})
109+
}
110+
111+
function showHideSnapshotOptions() {
112+
const Value = $('#node-input-snapshotMode').val()
113+
switch (Value) {
114+
case 'None':
115+
$('.unifi-snapshot').fadeOut('fast')
116+
break
117+
118+
default:
119+
$('.unifi-snapshot').fadeIn('fast')
120+
break
121+
}
122+
}
123+
</script>
124+
125+
<!-- prettier-ignore -->
126+
<script data-template-name="unifi-protect" type="text/html">
127+
<div class="form-row">
128+
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
129+
<input type="text" id="node-input-name" placeholder="Name" />
130+
</div>
131+
<div class="form-row">
132+
<label for="node-input-accessControllerNodeId"><i class="fa fa-globe"></i> Controller</label>
133+
<select id="node-input-accessControllerNodeId">
134+
<option value="">Choose...</option>
135+
</select>
136+
</div>
137+
<div class="form-row">
138+
<label for="node-input-cameraId"><i class="fa fa-video-camera"></i> Camera</label >
139+
<select id="node-input-cameraId">
140+
<option value="" selected>Choose...</option>
141+
</select>
142+
</div>
143+
<div class="form-row">
144+
<label for="node-input-eventIds"><i class="fa fa-list"></i> Events</label >
145+
<select id="node-input-eventIds" multiple style="height:120px">
146+
<option value="MotionEvent">Motion Event</option>
147+
<option value="MotionDetection">Motion Detection</option>
148+
<option value="DoorBell">Door Bell Ring</option>
149+
<option value="Package">Package Detected</option>
150+
<option value="Vehicle">Vehicle Detected</option>
151+
<option value="Person">Person Detected</option>
152+
</select>
153+
</div>
154+
<div class="form-row">
155+
<label for="node-input-snapshotMode"><i class="fa fa-image"></i> Snapshots</label>
156+
<select id="node-input-snapshotMode" onchange="showHideSnapshotOptions()">
157+
<option value="None" selected>None</option>
158+
<option value="Initial">Initial Only (if supported)</option>
159+
<option value="InitialDelayed">Initial And Delayed (if supported)</option>
160+
<option value="InitialRetain">Retain Initial (if supported)</option>
161+
</select>
162+
</div>
163+
<div class="form-row unifi-snapshot">
164+
<label for="node-input-snapshotW"><i class="fa fa fa-arrows-h"></i> Width</label>
165+
<input type="number" id="node-input-snapshotW" placeholder="360" />
166+
</div>
167+
<div class="form-row unifi-snapshot">
168+
<label for="node-input-snapshotH"><i class="fa fa-arrows-v"></i> Height</label>
169+
<input type="number" id="node-input-snapshotH" placeholder="360" />
170+
</div>
171+
<div class="form-row unifi-snapshot">
172+
<label for="el-node-input-delayedSnapshotTime"><i class="fa fa-clock-o"></i> Delay Time</label>
173+
<input type="number" id="el-node-input-delayedSnapshotTime" placeholder="2000" />
174+
</div>
175+
<div class="form-tips unifi-snapshot" id="node-tip">
176+
<span style="font-weight:bold;">Caution:</span> The larger the snapshot size, the more time needed to deliver the event to your flow. Not all event types support a snapshot, therefore will not be included.
177+
The <code>Delay Time</code> value represents how long to give the controller to generate any snapshot that are not immediately available at the time of the event.
178+
</div>
179+
<div class="form-tips" id="node-warning">
180+
<span style="color:red; font-weight:bold;">Warning:</span> The selected console does not appear to have a protect Instance running, or it's config has just been created and needs deploying before cameras can be fetched.
181+
</div>
182+
</script>
183+
184+
<!-- prettier-ignore -->
185+
<script data-help-name="unifi-protect" type="text/html">
186+
<p>A Unifi Protect Camera.</p>
187+
</script>

build/nodes/icons/protect.png

11.6 KB
Loading

build/nodes/unifi.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,4 @@
3434
.unifi-grow {
3535
flex-grow: 1;
3636
}
37-
</style>
37+
</style>

0 commit comments

Comments
 (0)