Skip to content

Commit

Permalink
feature: use CustomName for sk paths if available (#128)
Browse files Browse the repository at this point in the history
  • Loading branch information
sbender9 authored Sep 24, 2023
1 parent fa27cf9 commit ae0f656
Show file tree
Hide file tree
Showing 4 changed files with 255 additions and 56 deletions.
58 changes: 51 additions & 7 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) => {
Expand Down Expand Up @@ -82,10 +83,32 @@ module.exports = function (app, messageCallback, address, plugin, pollInterval)
} 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) {
Expand Down Expand Up @@ -122,21 +145,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({
Expand Down Expand Up @@ -216,7 +251,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 => {
Expand All @@ -225,7 +260,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

Expand Down
90 changes: 77 additions & 13 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const PLUGIN_ID = 'venus'
const PLUGIN_NAME = 'Victron Venus Plugin'

const camelcase = require('camelcase')
const promiseRetry = require('promise-retry')
const _ = require('lodash')
const mqtt = require('mqtt');
Expand All @@ -18,6 +19,8 @@ module.exports = function (app) {
let pluginStarted = false
var fluidTypes = {}
var temperatureTypes = {}
var customNames = {}
var customNameTimeouts = {}
let sentDeltas = {}
let pollInterval
let keepAlive
Expand Down Expand Up @@ -74,6 +77,11 @@ module.exports = function (app) {
title: 'Interval (in seconds) to poll venus for current values',
default: 20
},
useDeviceNames: {
type: 'boolean',
title: 'Use the device names for paths',
default: false
},
usePosition: {
type: 'boolean',
title: 'Use the position from Venus OS',
Expand Down Expand Up @@ -177,12 +185,19 @@ module.exports = function (app) {
dbusSetValue(msg.destination, msg.path, msg.value)
}

function actionHandler(context, skpath, input, dest, vpath, mqttTopic, converter, putPath, cb) {
function actionHandler(context, skpath, input, dest, vpath, mqttTopic, converter, confirmChange, putPath, cb) {
let realPath = putPath ? putPath : vpath
app.debug(`setting mode ${dest} ${realPath} to ${input}`)

let value = converter ? converter(input) : input

if ( value === undefined ) {
return {
state: 'FAILURE',
message: `Invalid input value: ${input}`
}
}

if ( plugin.options.installType === 'mqtt' ) {
let wtopic
if ( putPath ) {
Expand All @@ -199,7 +214,13 @@ module.exports = function (app) {

setTimeout(() => {
var val = app.getSelfPath(skpath)
if ( val && val.value == value ) {
let match = false
if ( confirmChange ) {
match = val && confirmChange(val.value, value)
} else if ( val && val.value == value ) {
match = true
}
if ( match ) {
cb({ state: 'SUCCESS' })
} else {
cb({
Expand All @@ -212,31 +233,32 @@ module.exports = function (app) {
return { state: 'PENDING' }
}

function getActionHandler(m, converter, putPath) {
function getActionHandler(m, converter, confirmChange, putPath) {
return (context, path, value, cb) => {
return actionHandler(context, path, value, m.senderName, m.path, m.topic, converter, putPath, cb)
return actionHandler(context, path, value, m.senderName, m.path, m.topic, converter, confirmChange, putPath, cb)
}
}


/*
Called when the plugin is started (server is started with plugin enabled
or the plugin is enabled from ui on a running server).
*/
plugin.start = function (options) {
var { toDelta, getKnownPaths } =
var { toDelta, getKnownPaths, hasCustomName } =
venusToDeltas(app, options, {},
(path, m, converter, confirmPath) => {
(path, m, converter, confirmChange, putPath) => {
app.registerActionHandler('vessels.self',
path,
getActionHandler(m,converter,
confirmPath))
confirmChange,
putPath))
})

pluginStarted = true
plugin.options = options
plugin.onError = () => {}
plugin.getKnownPaths = getKnownPaths
plugin.hasCustomName = hasCustomName

if ( options.relayDisplayName0 && options.relayDisplayName0.length ) {
sendMeta(options.relayPath0, { displayName: options.relayDisplayName0 })
Expand Down Expand Up @@ -333,6 +355,10 @@ module.exports = function (app) {
onStop.forEach(f => f())
onStop = []
sentDeltas = {}
customNames = {}
customNameTimeouts = {}
plugin.needsID = true
plugin.portalID = null
if ( pollInterval ) {
clearInterval(pollInterval)
pollInterval = null
Expand Down Expand Up @@ -382,6 +408,8 @@ module.exports = function (app) {

client.on('close', () => {
sentDeltas = {}
customNames = {}
customNameTimeouts = {}
plugin.needsID = true
plugin.portalID = null
app.debug(`mqtt close`)
Expand Down Expand Up @@ -458,6 +486,30 @@ module.exports = function (app) {
return
}

let senderName = `com.victronenergy.${type}.${instance}`

if ( plugin.options.useDeviceNames !== undefined &&
plugin.options.useDeviceNames ) {
if ( customNames[senderName] === undefined &&
plugin.hasCustomName(`com.victronenergy.${type}`) ) {
if ( parts[parts.length-1] === 'CustomName' ) {
app.debug('got CustomName "%s" for %s', message.value, senderName)
customNames[senderName] = camelcase(message.value)
} else {
let timeout = customNameTimeouts[senderName]
if ( timeout === undefined ) {
customNameTimeouts[senderName] = Date.now()
return
} else if ( Date.now() - timeout > 10 * 1000 ) {
customNames[senderName] = instance
app.debug('timed out waiting on CustomName for %s', senderName)
} else {
return
}
}
}
}

if ( type == 'tank' ) {
if ( parts[parts.length-1] == 'FluidType' ) {
fluidTypes[instance] = message.value
Expand All @@ -478,28 +530,40 @@ module.exports = function (app) {
return
}
temperatureType = temperatureTypes[instance]
if ( fluidType == 'unknown' ) {
if ( temperatureType == 'unknown' ) {
return
} else if ( _.isUndefined(temperatureType) ) {
} else if ( _.isUndefined(temperatureType) ) {
client.publish(`R/${parts[1]}/${type}/${instance}/TemperatureType`)
temperatureTypes[instance] = 'unknown'
return
}
}

let senderName = `com.victronenergy.${type}.${instance}`
let instanceName
if ( options.instanceMappings ) {
const mapping = plugin.options.instanceMappings.find(mapping => {
return senderName.startsWith(mapping.type) && mapping.venusId == instance
})
if ( !_.isUndefined(mapping) ) {
instance = mapping.signalkId
instanceName = mapping.signalkId
}
}

if ( instanceName === undefined )
{
if ( plugin.options.useDeviceNames !== undefined &&
plugin.options.useDeviceNames &&
customNames[senderName] !== undefined &&
customNames[senderName] !== '' ) {
instanceName = customNames[senderName]
}
else
instanceName = instance
}

var m = {
path: '/' + parts.slice(4).join('/'),
instanceName: instance,
instanceName: instanceName,
senderName,
value: message.value,
fluidType: fluidType,
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"description": "Victron Venus-SignalK Integration",
"main": "index.js",
"dependencies": {
"camelcase": "^6.3.0",
"dbus-native": "^0.2.5",
"debug": "^3.1.0",
"lodash": "^4.17.4",
Expand Down
Loading

0 comments on commit ae0f656

Please sign in to comment.