@signalk/vedirect-serial-usb 1.3.0 → 1.5.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/README.md CHANGED
@@ -9,13 +9,13 @@ Alternatively, this plugin also supports receiving the data via UDP and on a TCP
9
9
 
10
10
  Compatible Victron products:
11
11
 
12
- - BMV-700 series of Battery Monitors
12
+ - BMV-700 series of Battery Monitors (reported to work also on the BMV-600)
13
13
  - SmartShunt series of Battery Monitors
14
14
  - SmartSolar Chargers
15
15
  - BlueSolar Chargers
16
16
  - Phoenix Inverters, including the Smarts, having a VE.Direct comms port
17
17
 
18
- Note that above list may not be complete.
18
+ Note that above list may not be complete.
19
19
 
20
20
  The TCP and UDP connection methods are to allow connecting to a Victron product
21
21
  too far away to run a serial cable. Ie. using a bridge to LAN/Wi-Fi that takes
@@ -31,34 +31,58 @@ plugin. Details for that [here](https://github.com/sbender9/signalk-venus-plugin
31
31
 
32
32
  Use the Signal K app store or install via NPM in the Signal K server root directory: `npm install @signalk/vedirect-serial-usb`
33
33
 
34
-
35
34
  ### Usage
36
35
 
37
36
  Set up the appropiate device on the settings page of this plugin in the Signal K server admin UI, for instance to `/dev/ttyUSB0` and enable the plugin. Your VE.Direct data will be available in Signal K format via various clients and apps.
38
37
 
39
38
  ### Connections
39
+
40
40
  **Select device**
41
+
41
42
  - Serial, UDP or TCP
42
43
 
43
44
  **Connection details**
45
+
44
46
  - Serial: Enter device path e.g `/dev/ttyUSB0`
45
- - UDP: *`ignored`*
47
+ - UDP: _`ignored`_
46
48
  - TCP: Enter host `IP address`
47
49
 
48
50
  **Port**
49
- - Serial: *`ignored`*
51
+
52
+ - Serial: _`ignored`_
50
53
  - UDP/TCP: `port`
51
54
 
52
55
  **Ignore Checksum**
56
+
53
57
  - If you want to ignore checksum, use this option. Default `ON`
54
58
 
55
59
  **SK Paths**
56
- - Give each device unique SK paths
60
+
61
+ - Give each device unique SK paths
62
+
63
+ ### Usage as a library
64
+
65
+ It's possible to use this plugin as a library, in other Node.js code. This feature simply wraps the plugin in an easy-to-consume manner, so functionality is identical. Example:
66
+
67
+ ```javascript
68
+ const VEDirect = require('@signalk/vedirect-serial-usb/standalone')
69
+ const consumer = new VEDirect({
70
+ device: '/dev/ttyUSB0',
71
+ ignoreChecksum: true,
72
+ mainBatt: 'House',
73
+ auxBatt: 'Starter',
74
+ solar: 'Main',
75
+ })
76
+
77
+ consumer.on('delta', (delta) => console.log('[onDelta]', delta))
78
+ consumer.stop() // stop the plugin, destruct the connections
79
+ consumer.start() // (re-)start the plugin
80
+ ```
57
81
 
58
82
  ### License
59
83
 
60
84
  ```
61
- Copyright 2018 Joachim Bakke <github@heiamoss.com>, Fabian Tollenaar <fabian@decipher.industries> and
85
+ Copyright 2018 Joachim Bakke <github@heiamoss.com>, Fabian Tollenaar <fabian@decipher.industries> and
62
86
  Karl-Erik Gustafsson <ke.gustafsson@gmail.com>
63
87
 
64
88
  Licensed under the Apache License, Version 2.0 (the "License");
package/index.js CHANGED
@@ -2,6 +2,7 @@ const serial = require('./lib/serial')
2
2
  const udp = require('./lib/udp')
3
3
  const tcp = require('./lib/tcp')
4
4
  const Parser = require('./lib/Parser')
5
+ const VEDirect = require('./standalone')
5
6
 
6
7
  module.exports = function (app) {
7
8
  let parser = []
@@ -36,13 +37,13 @@ module.exports = function (app) {
36
37
  } else {
37
38
  if (options.device) {
38
39
  oldConfig = {vedirect: [{device: 'Serial', connection: options.device, ignoreChecksum: options.ignoreChecksum,
39
- mainBatt: options.mainBatt, auxBatt: options.auxBatt, solar: options.solar}]}
40
+ mainBatt: options.mainBatt, auxBatt: options.auxBatt, bmv: options.bmv, solar: options.solar}]}
40
41
  } else if (options.udpPort) {
41
42
  oldConfig = {vedirect: [{device: 'UDP', port: options.udpPort, ignoreChecksum: options.ignoreChecksum,
42
- mainBatt: options.mainBatt, auxBatt: options.auxBatt, solar: options.solar}]}
43
+ mainBatt: options.mainBatt, auxBatt: options.auxBatt, bmv: options.bmv, solar: options.solar}]}
43
44
  } else if (options.host) {
44
45
  oldConfig = {vedirect: [{device: 'TCP', connection: options.host, port: options.tcpPort, ignoreChecksum: options.ignoreChecksum,
45
- mainBatt: options.mainBatt, auxBatt: options.auxBatt, solar: options.solar}]}
46
+ mainBatt: options.mainBatt, auxBatt: options.auxBatt, bmv: options.bmv, solar: options.solar}]}
46
47
  }
47
48
  parser[0] = new Parser(oldConfig)
48
49
 
@@ -138,6 +139,11 @@ module.exports = function (app) {
138
139
  title: 'Aux Battery name in SK path',
139
140
  default: 'Starter'
140
141
  },
142
+ bmv: {
143
+ type: 'string',
144
+ title: 'BMV name in SK path',
145
+ default: 'bmv'
146
+ },
141
147
  solar: {
142
148
  type: 'string',
143
149
  title: 'Solar name in SK path',
package/lib/Parser.js CHANGED
@@ -7,6 +7,7 @@ const defaults = {
7
7
  defaultUnitId: 'victronDevice',
8
8
  mainBatt: 'house',
9
9
  auxBatt: 'starter',
10
+ bmv: 'bmv',
10
11
  solar: 'solar'
11
12
  }
12
13
 
@@ -358,6 +359,10 @@ class VEDirectParser extends EventEmitter {
358
359
  unitID = this.options.vedirect[items].auxBatt
359
360
  }
360
361
 
362
+ if (field.unitId === 'bmv' && this.options.hasOwnProperty('bmv')) {
363
+ unitID = this.options.vedirect[items].bmv
364
+ }
365
+
361
366
  if (field.unitId === 'solar' && this.options.hasOwnProperty('solar')) {
362
367
  unitID = this.options.vedirect[items].solar
363
368
  }
package/lib/fields.js CHANGED
@@ -83,6 +83,22 @@ module.exports = {
83
83
  units: 'V',
84
84
  type: 'metric'
85
85
  },
86
+ V2: {
87
+ name: 'auxBattVoltage',
88
+ path: 'electrical.batteries.*.voltage',
89
+ unitId: 'auxBatt',
90
+ value: common.mV,
91
+ units: 'V',
92
+ type: 'metric'
93
+ },
94
+ V3: {
95
+ name: 'aux2BattVoltage',
96
+ path: 'electrical.batteries.*.voltage',
97
+ unitId: 'aux2Batt',
98
+ value: common.mV,
99
+ units: 'V',
100
+ type: 'metric'
101
+ },
86
102
  VS: {
87
103
  name: 'auxBatteryVoltage',
88
104
  path: 'electrical.batteries.*.voltage',
@@ -126,6 +142,22 @@ module.exports = {
126
142
  units: 'A',
127
143
  type: 'metric'
128
144
  },
145
+ I2: {
146
+ name: 'auxbatteryCurrent',
147
+ path: 'electrical.batteries.*.current',
148
+ unitId: 'auxBatt',
149
+ value: common.mA,
150
+ units: 'A',
151
+ type: 'metric'
152
+ },
153
+ I3: {
154
+ name: 'aux2batteryCurrent',
155
+ path: 'electrical.batteries.*.current',
156
+ unitId: 'aux2Batt',
157
+ value: common.mA,
158
+ units: 'A',
159
+ type: 'metric'
160
+ },
129
161
  IL: {
130
162
  name: 'loadCurrent',
131
163
  path: 'electrical.solar.*.loadCurrent',
@@ -209,6 +241,8 @@ module.exports = {
209
241
  RELAY: {
210
242
  name: 'relay',
211
243
  type: 'boolean',
244
+ path: 'electrical.batteries.*.relay',
245
+ unitId: 'bmv',
212
246
  value (value) {
213
247
  value = value.toUpperCase()
214
248
  return value === 'ON' ? 1 : 0
@@ -78,5 +78,7 @@
78
78
  "0xA274": "Phoenix Inverter 48V 1200VA 230V",
79
79
  "0xA279": "Phoenix Inverter 12V 1200VA 120V",
80
80
  "0xA27A": "Phoenix Inverter 24V 1200VA 120V",
81
- "0xA27C": "Phoenix Inverter 48V 1200VA 120V"
81
+ "0xA27C": "Phoenix Inverter 48V 1200VA 120V",
82
+ "0xA345": "Phoenix Smart Charger 12V 30A 3 rev2",
83
+ "0xA381": "BMV-712 Smart"
82
84
  }
package/lib/serial.js CHANGED
@@ -1,11 +1,10 @@
1
- const SerialPort = require('serialport')
2
- const Delimiter = require('@serialport/parser-delimiter')
1
+ const { SerialPort } = require('serialport')
2
+ const { DelimiterParser } = require('@serialport/parser-delimiter')
3
3
  let port = []
4
4
  let delim = []
5
5
 
6
6
  module.exports = {
7
7
  open: (device, parser, debug, items) => {
8
- console.log(port[items])
9
8
  if (typeof port[items] !== 'undefined' ) {
10
9
  try {
11
10
  port[items].close()
@@ -13,7 +12,9 @@ module.exports = {
13
12
  } catch (e) {}
14
13
  }
15
14
 
16
- port[items] = new SerialPort(device, { baudRate: 19200 }) // @NOTE FT: should this be configurable?
15
+ debug(`Serial: connecting to ${device}`)
16
+
17
+ port[items] = new SerialPort({ path: device, baudRate: 19200 }) // @NOTE FT: should this be configurable?
17
18
 
18
19
  port[items].on('open', function() {
19
20
  debug(`Connected to ${device}`)
@@ -23,7 +24,7 @@ module.exports = {
23
24
  debug(`${chunk}`)
24
25
  })
25
26
 
26
- delim[items] = port[items].pipe(new Delimiter({delimiter: '\r' , includeDelimiter: true}))
27
+ delim[items] = port[items].pipe(new DelimiterParser({ delimiter: '\r', includeDelimiter: true }))
27
28
 
28
29
  delim[items].on('data', chunk => {
29
30
  // Chunk is a node.js Buffer
package/lib/tcp.js CHANGED
@@ -4,6 +4,7 @@ let client = [];
4
4
  function makeConnection(host, port, debug, items) {
5
5
  client[items] = new Net.Socket();
6
6
  client[items].connect({ port: port, host: host });
7
+ client[items].setTimeout(5000);
7
8
  debug(`Connection to ${host}:${port}`);
8
9
  return client[items]
9
10
  }
@@ -17,9 +18,8 @@ function onClose(host, port, parser, debug, items) {
17
18
  if(client[items]) {
18
19
  setTimeout(() => {
19
20
  debug('Trying to reconnect');
20
- client[items].destroy();
21
21
  module.exports.connect(host, port, parser, debug, items);
22
- }, 10000)
22
+ }, 10000);
23
23
  }
24
24
  }
25
25
 
@@ -31,11 +31,17 @@ module.exports = {
31
31
  });
32
32
  client[items].on('close', () => {
33
33
  debug('TCP connection closed');
34
+ client[items].destroy();
34
35
  onClose(host, port, parser, debug, items);
35
36
  });
36
37
  client[items].on('error', () => {
37
38
  debug('TCP connection error');
39
+ client[items].destroy();
38
40
  });
41
+ client[items].on('timeout', () => {
42
+ debug('TCP connection timeout');
43
+ client[items].destroy();
44
+ });
39
45
  },
40
46
  close: (debug, items) => {
41
47
  if (client[items]) {
package/migration.js CHANGED
@@ -19,6 +19,7 @@ fs.readFile(path.resolve(jsonPath, 'vedirect-signalk.json'), 'UTF-8', (err, data
19
19
  'ignoreChecksum': obj.configuration.ignoreChecksum,
20
20
  'mainBatt': obj.configuration.mainBatt,
21
21
  'auxBatt': obj.configuration.auxBatt,
22
+ 'bmv': obj.configuration.bmv,
22
23
  'solar': obj.configuration.solar
23
24
  }]
24
25
  } else if (obj.configuration.udpPort) {
@@ -29,6 +30,7 @@ fs.readFile(path.resolve(jsonPath, 'vedirect-signalk.json'), 'UTF-8', (err, data
29
30
  'ignoreChecksum': obj.configuration.ignoreChecksum,
30
31
  'mainBatt': obj.configuration.mainBatt,
31
32
  'auxBatt': obj.configuration.auxBatt,
33
+ 'bmv': obj.configuration.bmv,
32
34
  'solar': obj.configuration.solar
33
35
  }]
34
36
  } else if (obj.configuration.host) {
@@ -39,6 +41,7 @@ fs.readFile(path.resolve(jsonPath, 'vedirect-signalk.json'), 'UTF-8', (err, data
39
41
  'ignoreChecksum': obj.configuration.ignoreChecksum,
40
42
  'mainBatt': obj.configuration.mainBatt,
41
43
  'auxBatt': obj.configuration.auxBatt,
44
+ 'bmv': obj.configuration.bmv,
42
45
  'solar': obj.configuration.solar
43
46
  }]
44
47
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signalk/vedirect-serial-usb",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
4
4
  "description": "Signal K Node.js server plugin to read VE.Direct data via serial USB",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -25,7 +25,7 @@
25
25
  "dependencies": {
26
26
  "debug": "^4.0.1",
27
27
  "package-lock.json": "^1.0.0",
28
- "serialport": "^9.0.0"
28
+ "serialport": "^11.0.0"
29
29
  },
30
30
  "standard": {
31
31
  "globals": [
@@ -38,6 +38,6 @@
38
38
  "devDependencies": {
39
39
  "chai": "^4.1.2",
40
40
  "chai-things": "^0.2.0",
41
- "mocha": "^6.0.0"
41
+ "mocha": "^10.2.0"
42
42
  }
43
43
  }
package/standalone.js ADDED
@@ -0,0 +1,68 @@
1
+ /**
2
+ * standalone.js
3
+ *
4
+ * @description exports a class that shims the Signal K server, in order to make this plugin available as a library in other software
5
+ * @module @signalk/vedirect-serial-usb
6
+ * @author Fabian Tollenaar <fabian@essense.ai> (https://essense.ai)
7
+ * @license Apache_2.0
8
+ */
9
+
10
+ const EventEmitter = require('events')
11
+ const SKPlugin = require('./index')
12
+ class VEDirect extends EventEmitter {
13
+ constructor (config = {}, _debug = false) {
14
+ super()
15
+
16
+ this._debug = _debug
17
+ this.app = {
18
+ handleMessage: (kind, data) => {
19
+ if (kind === 'pluginId') {
20
+ this.emit('delta', data)
21
+ return
22
+ }
23
+ this.emit(kind, data)
24
+ },
25
+ debug: (args) => this.debug(args),
26
+ options: {
27
+ device: 'Serial',
28
+ connection: '/dev/ttyUSB0',
29
+ port: 7878,
30
+ ignoreChecksum: true,
31
+ mainBatt: 'House',
32
+ auxBatt: 'Starter',
33
+ bmv: 'bmv',
34
+ solar: 'Main',
35
+ ...(config || {}),
36
+ }
37
+ }
38
+
39
+ this.plugin = SKPlugin(this.app)
40
+ this.start()
41
+ }
42
+
43
+ start () {
44
+ if (!this.plugin || !this.plugin.hasOwnProperty('start')) {
45
+ this.debug(`Plugin not initialised, can't start`)
46
+ return
47
+ }
48
+
49
+ this.plugin.start(this.app.options)
50
+ }
51
+
52
+ stop () {
53
+ if (!this.plugin || !this.plugin.hasOwnProperty('stop')) {
54
+ this.debug(`Plugin not initialised, can't stop`)
55
+ return
56
+ }
57
+
58
+ this.plugin.stop()
59
+ }
60
+
61
+ debug (...args) {
62
+ if (this._debug) {
63
+ console.log.apply(console, args)
64
+ }
65
+ }
66
+ }
67
+
68
+ module.exports = VEDirect