@signalk/vedirect-serial-usb 1.5.0 → 1.6.0
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/LICENSE +201 -0
- package/README.md +13 -24
- package/dist/Parser.d.ts +50 -0
- package/dist/Parser.d.ts.map +1 -0
- package/dist/Parser.js +350 -0
- package/dist/Parser.js.map +1 -0
- package/dist/constants.d.ts +5 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +14 -0
- package/dist/constants.js.map +1 -0
- package/dist/fields.d.ts +14 -0
- package/dist/fields.d.ts.map +1 -0
- package/dist/fields.js +438 -0
- package/dist/fields.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +209 -0
- package/dist/index.js.map +1 -0
- package/dist/productIds.d.ts +9 -0
- package/dist/productIds.d.ts.map +1 -0
- package/dist/productIds.js +95 -0
- package/dist/productIds.js.map +1 -0
- package/dist/serial.d.ts +5 -0
- package/dist/serial.d.ts.map +1 -0
- package/dist/serial.js +78 -0
- package/dist/serial.js.map +1 -0
- package/dist/standalone.d.ts +22 -0
- package/dist/standalone.d.ts.map +1 -0
- package/dist/standalone.js +69 -0
- package/dist/standalone.js.map +1 -0
- package/dist/tcp.d.ts +5 -0
- package/dist/tcp.d.ts.map +1 -0
- package/dist/tcp.js +106 -0
- package/dist/tcp.js.map +1 -0
- package/dist/types.d.ts +159 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +15 -0
- package/dist/types.js.map +1 -0
- package/dist/udp.d.ts +5 -0
- package/dist/udp.d.ts.map +1 -0
- package/dist/udp.js +67 -0
- package/dist/udp.js.map +1 -0
- package/docs/screenshots/1_config.png +0 -0
- package/logo.svg +46 -0
- package/package.json +79 -19
- package/.github/FUNDING.yml +0 -1
- package/.travis.yml +0 -13
- package/index.js +0 -159
- package/lib/Parser.js +0 -396
- package/lib/fields.js +0 -503
- package/lib/filestream.js +0 -38
- package/lib/productIds.json +0 -84
- package/lib/serial.js +0 -48
- package/lib/tcp.js +0 -53
- package/lib/udp.js +0 -26
- package/log/one.txt +0 -18
- package/log/run-log.js +0 -7
- package/log/sampleOutput.txt +0 -297
- package/migration.js +0 -57
- package/run.js +0 -10
- package/standalone.js +0 -68
- package/test/index.js +0 -52
- package/todo.md +0 -14
package/lib/Parser.js
DELETED
|
@@ -1,396 +0,0 @@
|
|
|
1
|
-
const debug = require('debug')
|
|
2
|
-
const EventEmitter = require('events')
|
|
3
|
-
|
|
4
|
-
const defaults = {
|
|
5
|
-
productIds: require('./productIds.json'),
|
|
6
|
-
fields: require('./fields'),
|
|
7
|
-
defaultUnitId: 'victronDevice',
|
|
8
|
-
mainBatt: 'house',
|
|
9
|
-
auxBatt: 'starter',
|
|
10
|
-
bmv: 'bmv',
|
|
11
|
-
solar: 'solar'
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
class VEDirectParser extends EventEmitter {
|
|
15
|
-
constructor (opts) {
|
|
16
|
-
super()
|
|
17
|
-
this.options = Object.assign({}, defaults, opts || {})
|
|
18
|
-
this.fields = this.options.fields
|
|
19
|
-
this.debug = debug('signalk-vedirect-parser')
|
|
20
|
-
this.line = []
|
|
21
|
-
this.data = {}
|
|
22
|
-
this.cache = ''
|
|
23
|
-
this.sum = 0
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
addChunk (buf, items) {
|
|
27
|
-
if (!Buffer.isBuffer(buf)) {
|
|
28
|
-
return this.warn('addChunk: incoming data is not a buffer: ' + typeof buf)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const chunk = buf.toString('ascii')
|
|
32
|
-
|
|
33
|
-
buf.forEach(b => {
|
|
34
|
-
this.sum += b
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
this.cache += chunk
|
|
38
|
-
if (chunk.toLowerCase().includes('checksum')) {
|
|
39
|
-
// Last line of block. Verify checksum of block in cache and parse line-by-line if checksum is correct.
|
|
40
|
-
this._verifyCacheAndParse(items)
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
parse (line) {
|
|
45
|
-
if (typeof line !== 'string') {
|
|
46
|
-
return
|
|
47
|
-
}
|
|
48
|
-
this.line = line.trim().split('\t')
|
|
49
|
-
this._parse()
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
set (key, value) {
|
|
53
|
-
this.data[key] = value
|
|
54
|
-
this.emit('change', Object.assign({}, this.data))
|
|
55
|
-
this.emit('set', { key, value })
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
get (key) {
|
|
59
|
-
return this.data[key]
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
unset (key) {
|
|
63
|
-
if (!this.data.hasOwnProperty(key)) {
|
|
64
|
-
return
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
this.debug(`Unsetting ${key}`)
|
|
68
|
-
this.emit('change', Object.assign({}, this.data))
|
|
69
|
-
this.emit('unset', key)
|
|
70
|
-
|
|
71
|
-
this.data[key] = null
|
|
72
|
-
delete this.data[key]
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
getData () {
|
|
76
|
-
return Object.assign({}, this.data)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
_verifyCacheAndParse (items) {
|
|
80
|
-
// Verify checksum if ignoreChecksum isn't true.
|
|
81
|
-
if (this.options.vedirect[items].ignoreChecksum !== true && this.sum % 256 !== 0) {
|
|
82
|
-
this.warn(`block checksum doesn't equal 0: ${this.sum % 256}`)
|
|
83
|
-
this.cache = ''
|
|
84
|
-
this.sum = 0
|
|
85
|
-
return
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
this.cache
|
|
89
|
-
.trim()
|
|
90
|
-
.split('\n')
|
|
91
|
-
.map(line => line.trim())
|
|
92
|
-
.filter(line => line !== '')
|
|
93
|
-
.forEach(line => {
|
|
94
|
-
this.line = line.split('\t')
|
|
95
|
-
this._parse()
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
this.cache = ''
|
|
99
|
-
this.sum = 0
|
|
100
|
-
this.generateDelta(items)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
_parse () {
|
|
104
|
-
let field = null
|
|
105
|
-
let data = null
|
|
106
|
-
let converted = null
|
|
107
|
-
|
|
108
|
-
if (!Array.isArray(this.line) || this.line.length !== 2) {
|
|
109
|
-
return this.warn('_parse() called on invalid line: ' + JSON.stringify({ line: this.line }))
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
field = String(this.line[0]).toUpperCase()
|
|
113
|
-
|
|
114
|
-
if (!Object.keys(this.fields).includes(field) || typeof this.fields[field] !== 'object' || this.fields[field] === null) {
|
|
115
|
-
return this.warn(`No field definition for: ${field}, ignoring`)
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
field = this.fields[field]
|
|
119
|
-
data = this.line[1]
|
|
120
|
-
|
|
121
|
-
if (data === undefined || data === null) {
|
|
122
|
-
return this.warn(`Data is NULL, ignoring`)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
if (typeof field.value === 'function') {
|
|
126
|
-
converted = field.value(data, this)
|
|
127
|
-
} else {
|
|
128
|
-
converted = data
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (typeof converted !== 'undefined' && converted !== null) {
|
|
132
|
-
this.set(field.name, Object.assign({}, field, {
|
|
133
|
-
value: converted
|
|
134
|
-
}))
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
getAlarmReason (alarmReason) {
|
|
139
|
-
alarmReason = parseInt(alarmReason, 10)
|
|
140
|
-
|
|
141
|
-
switch (alarmReason) {
|
|
142
|
-
case 1:
|
|
143
|
-
return 'Low voltage'
|
|
144
|
-
|
|
145
|
-
case 2:
|
|
146
|
-
return 'High voltage'
|
|
147
|
-
|
|
148
|
-
case 4:
|
|
149
|
-
return 'Low state-of-charge'
|
|
150
|
-
|
|
151
|
-
case 8:
|
|
152
|
-
return 'Low starter voltage'
|
|
153
|
-
|
|
154
|
-
case 16:
|
|
155
|
-
return 'High starter voltage'
|
|
156
|
-
|
|
157
|
-
case 32:
|
|
158
|
-
return 'Low temperature'
|
|
159
|
-
|
|
160
|
-
case 64:
|
|
161
|
-
return 'High temperature'
|
|
162
|
-
|
|
163
|
-
case 128:
|
|
164
|
-
return 'Mid voltage'
|
|
165
|
-
|
|
166
|
-
case 256:
|
|
167
|
-
return 'Overload'
|
|
168
|
-
|
|
169
|
-
case 512:
|
|
170
|
-
return 'DC ripple'
|
|
171
|
-
|
|
172
|
-
case 1024:
|
|
173
|
-
return 'Low V AC out'
|
|
174
|
-
|
|
175
|
-
case 2048:
|
|
176
|
-
return 'High V AC out'
|
|
177
|
-
|
|
178
|
-
default:
|
|
179
|
-
return null
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
getErrorString (err) {
|
|
184
|
-
err = parseInt(err, 10)
|
|
185
|
-
|
|
186
|
-
switch (err) {
|
|
187
|
-
case 2:
|
|
188
|
-
return 'Battery voltage too high'
|
|
189
|
-
|
|
190
|
-
case 17:
|
|
191
|
-
return 'Charger temperature too high'
|
|
192
|
-
|
|
193
|
-
case 18:
|
|
194
|
-
return 'Charger overcurrent'
|
|
195
|
-
|
|
196
|
-
// Can be ignored according to victron protocol
|
|
197
|
-
// case 19:
|
|
198
|
-
// return 'Charger current reversed'
|
|
199
|
-
|
|
200
|
-
case 20:
|
|
201
|
-
return 'Bulk time limit exceeded'
|
|
202
|
-
|
|
203
|
-
// Can be ignored according to victron protocol
|
|
204
|
-
// case 21:
|
|
205
|
-
// return 'Current sensor issue (sensor bias/sensor broken)'
|
|
206
|
-
|
|
207
|
-
case 26:
|
|
208
|
-
return 'Terminals overheated'
|
|
209
|
-
|
|
210
|
-
case 33:
|
|
211
|
-
return 'Input voltage too high (solar panel)'
|
|
212
|
-
|
|
213
|
-
case 34:
|
|
214
|
-
return 'Input current too high (solar panel)'
|
|
215
|
-
|
|
216
|
-
case 38:
|
|
217
|
-
return 'Input shutdown (due to excessive battery voltage)'
|
|
218
|
-
|
|
219
|
-
case 116:
|
|
220
|
-
return 'Factory calibration data lost'
|
|
221
|
-
|
|
222
|
-
case 117:
|
|
223
|
-
return 'Invalid/incompatible firmware'
|
|
224
|
-
|
|
225
|
-
case 119:
|
|
226
|
-
return 'User settings invalid'
|
|
227
|
-
|
|
228
|
-
default:
|
|
229
|
-
return null
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
getMode (mode) {
|
|
234
|
-
mode = parseInt(mode, 10)
|
|
235
|
-
|
|
236
|
-
switch (mode) {
|
|
237
|
-
case 2:
|
|
238
|
-
return 'on'
|
|
239
|
-
|
|
240
|
-
case 4:
|
|
241
|
-
return 'off'
|
|
242
|
-
|
|
243
|
-
case 5:
|
|
244
|
-
return 'eco'
|
|
245
|
-
|
|
246
|
-
default:
|
|
247
|
-
return null
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
getStateOfOperation (cs) {
|
|
252
|
-
cs = parseInt(cs, 10)
|
|
253
|
-
|
|
254
|
-
switch (cs) {
|
|
255
|
-
case 0:
|
|
256
|
-
return 'off'
|
|
257
|
-
|
|
258
|
-
case 1:
|
|
259
|
-
return 'low power'
|
|
260
|
-
|
|
261
|
-
case 2:
|
|
262
|
-
return 'fault'
|
|
263
|
-
|
|
264
|
-
case 3:
|
|
265
|
-
return 'bulk'
|
|
266
|
-
|
|
267
|
-
case 4:
|
|
268
|
-
return 'absorption'
|
|
269
|
-
|
|
270
|
-
case 5:
|
|
271
|
-
return 'float'
|
|
272
|
-
|
|
273
|
-
case 9:
|
|
274
|
-
return 'inverting'
|
|
275
|
-
|
|
276
|
-
default:
|
|
277
|
-
return null
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
getTrackerOperationMode (mppt) {
|
|
282
|
-
mppt = parseInt(mppt, 10)
|
|
283
|
-
|
|
284
|
-
switch (mppt) {
|
|
285
|
-
case 0:
|
|
286
|
-
return 'off'
|
|
287
|
-
|
|
288
|
-
case 1:
|
|
289
|
-
return 'voltage or current limited'
|
|
290
|
-
|
|
291
|
-
case 2:
|
|
292
|
-
return 'mpp tracker active'
|
|
293
|
-
|
|
294
|
-
default:
|
|
295
|
-
return null
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
getProductLongname (pid) {
|
|
300
|
-
pid = String(pid)
|
|
301
|
-
|
|
302
|
-
if (!pid.includes('0x')) {
|
|
303
|
-
pid = `0x${pid}`
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
if (!Object.keys(this.options.productIds).includes(pid)) {
|
|
307
|
-
return 'Unknown'
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
return this.options.productIds[pid]
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
generateDelta (items) {
|
|
314
|
-
const keys = Object.keys(this.data)
|
|
315
|
-
|
|
316
|
-
const values = keys.map(name => {
|
|
317
|
-
const path = this.getPath(name, items)
|
|
318
|
-
if (path === null) {
|
|
319
|
-
return null
|
|
320
|
-
}
|
|
321
|
-
return {
|
|
322
|
-
path,
|
|
323
|
-
value: this.data[name].value
|
|
324
|
-
}
|
|
325
|
-
}).filter(update => update !== null)
|
|
326
|
-
|
|
327
|
-
if (values.length === 0) {
|
|
328
|
-
return this.warn('No mutations in this delta')
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
this.emit('delta', {
|
|
332
|
-
context: 'vessels.self',
|
|
333
|
-
updates: [
|
|
334
|
-
{
|
|
335
|
-
source: {
|
|
336
|
-
label: '@signalk/vedirect-serial-usb',
|
|
337
|
-
type: 'VE.direct'
|
|
338
|
-
},
|
|
339
|
-
timestamp: new Date().toISOString(),
|
|
340
|
-
values
|
|
341
|
-
}
|
|
342
|
-
]
|
|
343
|
-
})
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
getPath (name, items) {
|
|
347
|
-
return Object.keys(this.fields).reduce((found, key) => {
|
|
348
|
-
const field = this.fields[key]
|
|
349
|
-
if (field.name === name && field.hasOwnProperty('path')) {
|
|
350
|
-
let unitID = ''
|
|
351
|
-
found = field.path
|
|
352
|
-
|
|
353
|
-
if (field.hasOwnProperty('unitId')) {
|
|
354
|
-
if (field.unitId === 'mainBatt' && this.options.hasOwnProperty('mainBatt')) {
|
|
355
|
-
unitID = this.options.vedirect[items].mainBatt
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
if (field.unitId === 'auxBatt' && this.options.hasOwnProperty('auxBatt')) {
|
|
359
|
-
unitID = this.options.vedirect[items].auxBatt
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
if (field.unitId === 'bmv' && this.options.hasOwnProperty('bmv')) {
|
|
363
|
-
unitID = this.options.vedirect[items].bmv
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
if (field.unitId === 'solar' && this.options.hasOwnProperty('solar')) {
|
|
367
|
-
unitID = this.options.vedirect[items].solar
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
if ((!unitID || unitID === '') && this.options.hasOwnProperty('defaultUnitId') && typeof this.options.defaultUnitId === 'string') {
|
|
371
|
-
unitID = this.options.defaultUnitId
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
if (this.options.hasOwnProperty('overrideUnitId') && typeof this.options.overrideUnitId === 'string') {
|
|
375
|
-
unitID = this.options.overrideUnitId
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
found = found.replace('*', unitID)
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
return found
|
|
382
|
-
}, null)
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
warn (message) {
|
|
386
|
-
this.debug(`Warning: ${message}`)
|
|
387
|
-
this.emit('warn', message)
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
error (err) {
|
|
391
|
-
this.debug(`Error: ${err.message}`)
|
|
392
|
-
this.emit('error', err)
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
module.exports = VEDirectParser
|