Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: sbender9/signalk-venus-plugin
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.30.2
Choose a base ref
...
head repository: sbender9/signalk-venus-plugin
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
Loading
Showing with 1,083 additions and 170 deletions.
  1. +4 −33 README.md
  2. +66 −12 dbus-listener.js
  3. +258 −58 index.js
  4. +5 −2 ios.js
  5. +7 −6 package.json
  6. +743 −59 venusToDeltas.js
37 changes: 4 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
@@ -9,29 +9,22 @@ possible to run [Venus OS](https://github.com/victronenergy/venus/wiki) on a
[RaspberryPi2 or 3](https://github.com/victronenergy/venus/wiki/raspberrypi-install-venus-image),
for example.

Supported Victron products:
- Inverter/Chargers: Multis, Quattros
- Battery Monitors: any type that is supported by Venus. For example the BMV-700 series, or the
Lynx Shunt VE.Can, as well as various integrated Lithium battery systems.
- Solar Chargers: both the types with a VE.Direct and the types with a VE.Can connection
- Tank senders: the resistive inputs on the Venus GX, as well as a tank sender connected to Venus
over N2K

Know that there is also a version of Venus OS with signalk-server, and this plug-in pre-installed.
In which case you don't need to self install or configure this plugin. See
[Venus OS large](https://www.victronenergy.com/live/venus-os:large).

## Support
Use the #victron channel on the [Signal K Slack](http://slack-invite.signalk.org/).
Use the #victron channel on [Discord](https://discord.gg/uuZrwz4dCS).

## Plugin installation & configuration
Installing is simple. The plugin is available in the signalk app store. Simply click to install.

Then there are two settings. The first is how to connect to Venus OS. Choose between these:

- A. Connect to localhost
- A. Connect to localhost via dbus
- B. Connect to a GX-device over tcp using MQTT (Plain text)
- C. Connect to a GX-device over tcp using MQTT (SSL)
- D. Connect via VRM

Use option A when signalk-server is installed on the GX-device itself.

@@ -43,26 +36,4 @@ When using option B or C go enter the hostname or ipaddress of the Venus device

Also ensure that MQTT is turned on in the GX-devices Services Settings.

## Test harness

To see data, without having actual Victron or other Venus compatible hardware setup,
get and run below explained Dummy data script. Or, clone
[dbus-recorder](https://github.com/victronenergy/dbus-recorder) and run play.sh.

Note that using the test harness could cause for some errors during init, as it
doesn't support doing a GetValue on the root item (/).

## How to develop this plugin outside of Signal K

First run `npm install`.

Use ./demo.sh to run the code with full debug logging and the produced delta
serialised to stdout.

When not tested on an actual Venus device, there will be no output since there
is no data coming in. Use a dummy data script to test / develop on a pc:

https://gist.github.com/mpvader/94672c05d68bb6762859ba70240ea887

dbus-listener.py is an example of how similar data would be read in Python. It
is not required to use the plugin.
Option D is mostly usefull for developer testing/debugging with other peoples systems, but could also be used if running signalk in a different location or network that the GC device
78 changes: 66 additions & 12 deletions dbus-listener.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const dbus = require('dbus-native')
const _ = require('lodash')
const camelcase = require('camelcase')

module.exports = function (app, messageCallback, address, plugin, pollInterval) {
return new Promise((resolve, reject) => {
@@ -77,15 +78,39 @@ module.exports = function (app, messageCallback, address, plugin, pollInterval)
// a process to manage settings on the dbus, the logger to VRM Portal
// and others. All services that send out data for connected devices do
// have the /DeviceInstance path.
app.debug(`warning: error getting device instance for ${name}`)
services[owner].deviceInstance = 99
if ( services[owner] ) {
app.debug(`warning: error getting device instance for ${name}`)
services[owner].deviceInstance = 99
}
} else {
services[owner].deviceInstance = res[1][0]
}

if ( plugin.options.useDeviceNames !== undefined &&
plugin.options.useDeviceNames ) {
app.debug('requesting custom name for %s', name)
bus.invoke(
{
path: '/CustomName',
destination: name,
interface: 'com.victronenergy.BusItem',
member: 'GetValue'
},
function (err, res) {
if (!err) {
let customName = res[1][0]
app.debug('got custom name %s for %s', customName, name)
services[owner].customName = camelcase(customName)
} else {
services[owner].customName = ''
}
requestRoot(service)
})
} else {
requestRoot(service)
}
}
)

requestRoot(service)
}

function requestRoot (service) {
@@ -106,9 +131,17 @@ module.exports = function (app, messageCallback, address, plugin, pollInterval)
)
} else {
var data = {}
res[1][0].forEach(kp => {
data[kp[0]] = kp[1][1][0]
})

if ( res[0][0].type == 'a' ) {
res[1][0].forEach(kp => {
data[kp[0]] = kp[1][1][0]
})
} else {
//for some reason virtual devices come in this way
res.forEach(kp => {
data[kp[0]] = kp[1][1][0]
})
}

service.deviceInstance = data.DeviceInstance

@@ -122,21 +155,33 @@ module.exports = function (app, messageCallback, address, plugin, pollInterval)

// app.debug(`${service.name} ${JSON.stringify(data)}`)

let deviceInstance = service.deviceInstance
let deviceInstance

/*
//FIXME: paths that don't require instance??
if ( _.isUndefined(deviceInstance) ) {
return
}
}
*/

if ( plugin.options.instanceMappings ) {
const mapping = plugin.options.instanceMappings.find(mapping => {
return service.name.startsWith(mapping.type) && mapping.venusId == deviceInstance
return service.name.startsWith(mapping.type) && mapping.venusId == service.deviceInstance
})
if ( !_.isUndefined(mapping) ) {
deviceInstance = mapping.signalkId
}
}

if ( deviceInstance === undefined )
{
if ( plugin.options.useDeviceNames !== undefined && plugin.options.useDeviceNames && service.customName !== '' ) {
deviceInstance = service.customName
}
else
deviceInstance = service.deviceInstance
}

var messages = []
_.keys(data).forEach(path => {
messages.push({
@@ -216,7 +261,7 @@ module.exports = function (app, messageCallback, address, plugin, pollInterval)
}

const senderName = service.name
let instanceName = service.deviceInstance
let instanceName

if ( plugin.options.instanceMappings ) {
const mapping = plugin.options.instanceMappings.find(mapping => {
@@ -225,7 +270,16 @@ module.exports = function (app, messageCallback, address, plugin, pollInterval)
if ( !_.isUndefined(mapping) ) {
instanceName = mapping.signalkId
}
}
}

if ( instanceName === undefined )
{
if ( plugin.options.useDeviceNames !== undefined && plugin.options.useDeviceNames && service.customName !== '' ) {
instanceName = service.customName
}
else
instanceName = service.deviceInstance
}

let entries

Loading