dsc-itv2-client 1.0.7
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/README.md +342 -0
- package/package.json +46 -0
- package/src/ITV2Client.js +502 -0
- package/src/constants.js +106 -0
- package/src/event-handler.js +323 -0
- package/src/examples/README.md +287 -0
- package/src/examples/arm-disarm-example.js +152 -0
- package/src/examples/basic-monitoring.js +82 -0
- package/src/examples/interactive-cli.js +1033 -0
- package/src/index.js +17 -0
- package/src/itv2-crypto.js +310 -0
- package/src/itv2-session.js +1069 -0
- package/src/response-parsers.js +185 -0
- package/src/utils.js +240 -0
package/README.md
ADDED
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
# DSC ITV2 Client Library
|
|
2
|
+
|
|
3
|
+
Reverse engineered, completely unofficial node.js library for communicating with DSC alarm panels using the ITV2 protocol over TL280R communicators.
|
|
4
|
+
Not affiliated with DSC or DSC Alarm in any way, shape or form. Use at your own risk.
|
|
5
|
+
|
|
6
|
+
## Features
|
|
7
|
+
|
|
8
|
+
✅ **Event-Driven Architecture** - Subscribe to zone changes with EventEmitter
|
|
9
|
+
✅ **Full Protocol Implementation** - Complete ITV2 handshake with Type 1 encryption
|
|
10
|
+
✅ **Real-Time Notifications** - Automatic zone status updates from panel
|
|
11
|
+
✅ **Partition Control** - Arm and disarm partitions
|
|
12
|
+
✅ **Encrypted Communication** - AES-128-ECB with dynamic key exchange
|
|
13
|
+
✅ **Auto-Reconnect** - Graceful handling of disconnections
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
### Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install dsc-itv2-client
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Basic Zone Monitoring
|
|
24
|
+
|
|
25
|
+
```javascript
|
|
26
|
+
import { ITV2Client } from 'dsc-itv2-client';
|
|
27
|
+
|
|
28
|
+
const client = new ITV2Client({
|
|
29
|
+
integrationId: '250228754543',
|
|
30
|
+
accessCode: '28754543',
|
|
31
|
+
port: 3073
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Subscribe to events
|
|
35
|
+
client.on('session:established', () => {
|
|
36
|
+
console.log('Connected to panel!');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
client.on('zone:open', (zoneNumber) => {
|
|
40
|
+
console.log(`Zone ${zoneNumber} opened`);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
client.on('zone:closed', (zoneNumber) => {
|
|
44
|
+
console.log(`Zone ${zoneNumber} closed`);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Start listening
|
|
48
|
+
await client.start();
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Arm/Disarm Control
|
|
52
|
+
|
|
53
|
+
```javascript
|
|
54
|
+
// Arm partition in STAY mode
|
|
55
|
+
client.armStay(1, '5555');
|
|
56
|
+
|
|
57
|
+
// Arm partition in AWAY mode
|
|
58
|
+
client.armAway(1, '5555');
|
|
59
|
+
|
|
60
|
+
// Disarm partition
|
|
61
|
+
client.disarm(1, '5555');
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Examples
|
|
65
|
+
|
|
66
|
+
Run the included examples:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# Basic zone monitoring
|
|
70
|
+
npm run example:basic
|
|
71
|
+
|
|
72
|
+
# Arm/disarm control
|
|
73
|
+
npm run example:control
|
|
74
|
+
|
|
75
|
+
# Full interactive CLI
|
|
76
|
+
npm run example:cli
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
See [src/examples/README.md](src/examples/README.md) for detailed examples and usage.
|
|
80
|
+
|
|
81
|
+
## API Reference
|
|
82
|
+
|
|
83
|
+
### Constructor
|
|
84
|
+
|
|
85
|
+
```javascript
|
|
86
|
+
const client = new ITV2Client(options);
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Options:**
|
|
90
|
+
- `integrationId` (string) - 12-digit panel integration ID
|
|
91
|
+
- `accessCode` (string) - 8-digit (Type 1) or 32-hex (Type 2) access code
|
|
92
|
+
- `masterCode` (string, optional) - Master code for arm/disarm (default: '5555')
|
|
93
|
+
- `port` (number, optional) - UDP port to listen on (default: 3073)
|
|
94
|
+
- `encryptionType` (number, optional) - null=auto-detect, 1=Type 1, 2=Type 2 (default: null)
|
|
95
|
+
- `logLevel` (string, optional) - 'silent', 'minimal', 'verbose' (default: 'minimal')
|
|
96
|
+
|
|
97
|
+
#### Encryption Types
|
|
98
|
+
|
|
99
|
+
**Type 1 (default, most common):**
|
|
100
|
+
```javascript
|
|
101
|
+
new ITV2Client({
|
|
102
|
+
integrationId: '250228754543',
|
|
103
|
+
accessCode: '28754543' // 8-digit code
|
|
104
|
+
});
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**Type 2 (for panels requiring 32-hex code):**
|
|
108
|
+
```javascript
|
|
109
|
+
new ITV2Client({
|
|
110
|
+
integrationId: '250228754543',
|
|
111
|
+
accessCode: '25022875250228752502287525022875', // 32-hex code
|
|
112
|
+
encryptionType: 2 // Optional: auto-detected from panel
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
#### Log Levels
|
|
117
|
+
|
|
118
|
+
**'silent'** - No logging output at all
|
|
119
|
+
**'minimal'** (default) - Key events only (session established, zone changes)
|
|
120
|
+
**'verbose'** - Full protocol details including packet dumps and crypto operations
|
|
121
|
+
|
|
122
|
+
```javascript
|
|
123
|
+
// Minimal logging (default)
|
|
124
|
+
const client = new ITV2Client({
|
|
125
|
+
integrationId: '...',
|
|
126
|
+
accessCode: '...'
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Verbose logging for debugging
|
|
130
|
+
const client = new ITV2Client({
|
|
131
|
+
integrationId: '...',
|
|
132
|
+
accessCode: '...',
|
|
133
|
+
logLevel: 'verbose'
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// Silent mode
|
|
137
|
+
const client = new ITV2Client({
|
|
138
|
+
integrationId: '...',
|
|
139
|
+
accessCode: '...',
|
|
140
|
+
logLevel: 'silent'
|
|
141
|
+
});
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Methods
|
|
145
|
+
|
|
146
|
+
| Method | Description |
|
|
147
|
+
|--------|-------------|
|
|
148
|
+
| `start()` | Start UDP server and wait for panel connection |
|
|
149
|
+
| `stop()` | Gracefully close session and shutdown |
|
|
150
|
+
| `armStay(partition, code)` | Arm partition in STAY mode |
|
|
151
|
+
| `armAway(partition, code)` | Arm partition in AWAY mode |
|
|
152
|
+
| `disarm(partition, code)` | Disarm partition |
|
|
153
|
+
| `getZones()` | Get current zone states |
|
|
154
|
+
| `getPartitions()` | Get current partition states |
|
|
155
|
+
|
|
156
|
+
### Events
|
|
157
|
+
|
|
158
|
+
#### Session Events
|
|
159
|
+
|
|
160
|
+
| Event | Payload | Description |
|
|
161
|
+
|-------|---------|-------------|
|
|
162
|
+
| `listening` | `{ address, port }` | UDP server started |
|
|
163
|
+
| `session:connecting` | - | Panel initiated connection |
|
|
164
|
+
| `session:established` | `{ encryptionType, sendKey, recvKey }` | Handshake complete |
|
|
165
|
+
| `session:closed` | - | Session ended |
|
|
166
|
+
| `session:error` | `Error` | Handshake failed |
|
|
167
|
+
|
|
168
|
+
#### Zone Events
|
|
169
|
+
|
|
170
|
+
| Event | Payload | Description |
|
|
171
|
+
|-------|---------|-------------|
|
|
172
|
+
| `zone:open` | `zoneNumber` | Zone opened |
|
|
173
|
+
| `zone:closed` | `zoneNumber` | Zone closed |
|
|
174
|
+
| `zone:status` | `zoneNumber, status` | Full zone status |
|
|
175
|
+
|
|
176
|
+
**Status Object:**
|
|
177
|
+
```javascript
|
|
178
|
+
{
|
|
179
|
+
open: boolean,
|
|
180
|
+
tamper: boolean,
|
|
181
|
+
fault: boolean,
|
|
182
|
+
lowBattery: boolean,
|
|
183
|
+
delinquency: boolean,
|
|
184
|
+
alarm: boolean,
|
|
185
|
+
alarmInMemory: boolean,
|
|
186
|
+
bypassed: boolean,
|
|
187
|
+
statusByte: number
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
#### Partition Events
|
|
192
|
+
|
|
193
|
+
| Event | Payload | Description |
|
|
194
|
+
|-------|---------|-------------|
|
|
195
|
+
| `partition:armed` | `partition, mode` | Partition armed |
|
|
196
|
+
| `partition:disarmed` | `partition` | Partition disarmed |
|
|
197
|
+
|
|
198
|
+
#### Error Events
|
|
199
|
+
|
|
200
|
+
| Event | Payload | Description |
|
|
201
|
+
|-------|---------|-------------|
|
|
202
|
+
| `error` | `Error` | General error |
|
|
203
|
+
| `command:error` | `{ code, message, rawData }` | Panel rejected command |
|
|
204
|
+
|
|
205
|
+
## Panel Configuration
|
|
206
|
+
|
|
207
|
+
To use this library, your DSC panel must be configured with the TL280R communicator module and proper integration settings.
|
|
208
|
+
|
|
209
|
+
### Required Panel Settings
|
|
210
|
+
|
|
211
|
+
#### 1. Integration ID (Section [422])
|
|
212
|
+
|
|
213
|
+
The 12-digit Integration ID identifies your integration to the panel. This must match the `integrationId` in your client configuration.
|
|
214
|
+
|
|
215
|
+
**Default:** `250228754543`
|
|
216
|
+
|
|
217
|
+
#### 2. Access Code (Section [423] for Type 1)
|
|
218
|
+
|
|
219
|
+
An 8-digit numeric code used for encryption key derivation in Type 1 encryption.
|
|
220
|
+
|
|
221
|
+
**Default:** `28754543`
|
|
222
|
+
|
|
223
|
+
#### 3. Integration Access Code (Section [700] for Type 2)
|
|
224
|
+
|
|
225
|
+
A 32-digit hexadecimal code used for Type 2 encryption. Less common than Type 1.
|
|
226
|
+
|
|
227
|
+
**Example:** `25022875250228752502287525022875`
|
|
228
|
+
|
|
229
|
+
#### 4. Integration Polling Port (Section [430])
|
|
230
|
+
|
|
231
|
+
The UDP port where your server listens for panel connections.
|
|
232
|
+
|
|
233
|
+
**Default:** `3073` (0x0C01)
|
|
234
|
+
|
|
235
|
+
### TL280R Communicator Setup
|
|
236
|
+
|
|
237
|
+
1. **Install TL280R module** in your DSC panel
|
|
238
|
+
2. **Configure network settings:**
|
|
239
|
+
- Set TL280R IP address (static recommended)
|
|
240
|
+
- Configure your server's IP address as the destination
|
|
241
|
+
- Set integration polling port (default: 3073)
|
|
242
|
+
|
|
243
|
+
3. **Configure integration settings:**
|
|
244
|
+
- Enter Integration ID in section [422]
|
|
245
|
+
- Enter Access Code in section [423] (Type 1) or [700] (Type 2)
|
|
246
|
+
- Enable integration polling
|
|
247
|
+
|
|
248
|
+
4. **Test connection:**
|
|
249
|
+
- TL280R should initiate connection to your server
|
|
250
|
+
- Panel will send OPEN_SESSION to start handshake
|
|
251
|
+
|
|
252
|
+
### Finding Your Panel Configuration
|
|
253
|
+
|
|
254
|
+
If you don't know your Integration ID and Access Code:
|
|
255
|
+
|
|
256
|
+
- **Check panel programming:**
|
|
257
|
+
- Enter installer code (*8 + installer code)
|
|
258
|
+
- Navigate to integration settings
|
|
259
|
+
- Section [422] = Integration ID
|
|
260
|
+
- Section [423] = Access Code (Type 1)
|
|
261
|
+
- Section [700] = Integration Access Code (Type 2)
|
|
262
|
+
|
|
263
|
+
### Network Requirements
|
|
264
|
+
|
|
265
|
+
- **Firewall:** Allow UDP port 3073 inbound
|
|
266
|
+
- **Network:** Panel and server must be on same network (or routable)
|
|
267
|
+
- **Static IP recommended:** For the server running this library
|
|
268
|
+
- **NAT:** If using NAT, configure port forwarding for UDP 3073
|
|
269
|
+
|
|
270
|
+
### Encryption Type Detection
|
|
271
|
+
|
|
272
|
+
The library automatically detects whether your panel uses Type 1 or Type 2 encryption.
|
|
273
|
+
You don't need to configure this - it's auto-detected during the handshake.
|
|
274
|
+
|
|
275
|
+
## Protocol Notes
|
|
276
|
+
|
|
277
|
+
### Push Notification Model
|
|
278
|
+
|
|
279
|
+
The DSC panel uses **push notifications**, not query/response:
|
|
280
|
+
|
|
281
|
+
- ✅ Panel automatically pushes zone status changes (0x0210)
|
|
282
|
+
- ✅ Real-time updates when zones open/close
|
|
283
|
+
- ❌ Cannot query for current status on demand
|
|
284
|
+
- ℹ️ Must wait for panel to send notifications
|
|
285
|
+
|
|
286
|
+
### Session Establishment
|
|
287
|
+
|
|
288
|
+
1. Panel sends OPEN_SESSION (plaintext)
|
|
289
|
+
2. Encrypted handshake with REQUEST_ACCESS
|
|
290
|
+
3. Type 1 key exchange (asymmetric encryption keys)
|
|
291
|
+
4. All post-handshake communication uses AES-128-ECB encryption
|
|
292
|
+
|
|
293
|
+
### Tested On
|
|
294
|
+
|
|
295
|
+
- DSC TL280R Communicator
|
|
296
|
+
- DSC Neo Panel (firmware 2905)
|
|
297
|
+
- Protocol version 6202
|
|
298
|
+
|
|
299
|
+
## Configuration
|
|
300
|
+
|
|
301
|
+
Use environment variables to configure:
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
INTEGRATION_ID=250228754543 \
|
|
305
|
+
ACCESS_CODE=28754543 \
|
|
306
|
+
MASTER_CODE=5555 \
|
|
307
|
+
UDP_PORT=3073 \
|
|
308
|
+
npm run example:basic
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
## Development
|
|
312
|
+
|
|
313
|
+
Run the full interactive CLI (includes all commands and debugging features):
|
|
314
|
+
|
|
315
|
+
```bash
|
|
316
|
+
npm run example:cli
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
## Troubleshooting
|
|
320
|
+
|
|
321
|
+
### No zone events
|
|
322
|
+
|
|
323
|
+
- Panel only sends notifications when zones **change state**
|
|
324
|
+
- Open/close a door or window to trigger notifications
|
|
325
|
+
- Ensure session is established first
|
|
326
|
+
|
|
327
|
+
### Session won't establish
|
|
328
|
+
|
|
329
|
+
- Verify `integrationId` and `accessCode` match panel configuration
|
|
330
|
+
- Check panel is configured to connect to your server IP
|
|
331
|
+
- Ensure UDP port 3073 is open in firewall
|
|
332
|
+
- Enable `debug: true` for detailed protocol logs
|
|
333
|
+
|
|
334
|
+
### Authentication/command errors
|
|
335
|
+
|
|
336
|
+
- Verify `masterCode` is correct
|
|
337
|
+
- Panel may require specific access codes
|
|
338
|
+
- Some commands may not be supported by all panel firmware versions
|
|
339
|
+
|
|
340
|
+
## License
|
|
341
|
+
|
|
342
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dsc-itv2-client",
|
|
3
|
+
"author": "fajitacat",
|
|
4
|
+
"version": "1.0.7",
|
|
5
|
+
"description": "Reverse engineered DSC ITV2 Protocol Client Library for TL280R Communicator - Monitor and control DSC alarm panels",
|
|
6
|
+
"main": "src/index.js",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./src/index.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"example:basic": "node src/examples/basic-monitoring.js",
|
|
13
|
+
"example:control": "node src/examples/arm-disarm-example.js",
|
|
14
|
+
"example:cli": "node src/examples/interactive-cli.js"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"src/ITV2Client.js",
|
|
18
|
+
"src/itv2-session.js",
|
|
19
|
+
"src/itv2-crypto.js",
|
|
20
|
+
"src/response-parsers.js",
|
|
21
|
+
"src/event-handler.js",
|
|
22
|
+
"src/constants.js",
|
|
23
|
+
"src/utils.js",
|
|
24
|
+
"src/index.js",
|
|
25
|
+
"src/examples/",
|
|
26
|
+
"README.md"
|
|
27
|
+
],
|
|
28
|
+
"keywords": [
|
|
29
|
+
"dsc",
|
|
30
|
+
"neo",
|
|
31
|
+
"itv2",
|
|
32
|
+
"alarm",
|
|
33
|
+
"security",
|
|
34
|
+
"tl280r",
|
|
35
|
+
"event-emitter",
|
|
36
|
+
"monitoring",
|
|
37
|
+
"home-automation",
|
|
38
|
+
"alarm-panel",
|
|
39
|
+
"dsc-alarm"
|
|
40
|
+
],
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=14.0.0"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {}
|
|
46
|
+
}
|