11/*
22 * Copyright 2019-2021 Ilker Temir <ilker@ilkertemir.com>
3- * Copyright 2021-2024 Francois Lacroix <xbgmsharp@gmail.com>
3+ * Copyright 2021-2025 Francois Lacroix <xbgmsharp@gmail.com>
44 *
55 * Licensed under the Apache License, Version 2.0 (the "License");
66 * you may not use this file except in compliance with the License.
@@ -44,8 +44,6 @@ module.exports = function (app) {
4444 var statusProcess ;
4545 var db ;
4646 var API ;
47- var host ;
48- var token ;
4947 var gpsSource ;
5048 var status = null ;
5149 var metrics = { } ;
@@ -60,11 +58,12 @@ module.exports = function (app) {
6058 var angleSpeedApparent = 0 ;
6159 var previousSpeeds = [ ] ;
6260 var previousCOGs = [ ] ;
61+ var retrieveMonitoringConfigInProgress = false ;
6362
6463 var metadata = {
6564 name : app . getSelfPath ( "name" ) ? app . getSelfPath ( "name" ) : null ,
6665 mmsi : app . getSelfPath ( "mmsi" ) ? app . getSelfPath ( "mmsi" ) : null ,
67- client_id : app . selfContext ,
66+ // client_id: app.selfContext,
6867 length : app . getSelfPath ( "design.length.value.overall" )
6968 ? app . getSelfPath ( "design.length.value.overall" )
7069 : null ,
@@ -81,7 +80,8 @@ module.exports = function (app) {
8180 signalk_version : app . config . version ,
8281 time : new Date ( ) . toISOString ( ) ,
8382 platform : null ,
84- configuration : null ,
83+ //configuration: null,
84+ available_keys : null ,
8585 } ;
8686
8787 plugin . id = "signalk-postgsail" ;
@@ -97,23 +97,23 @@ module.exports = function (app) {
9797
9898 metadata . platform = findPlatform ( ) ;
9999 app . debug ( `Running on ${ metadata . platform } ` ) ;
100- metadata . configuration = options ;
101100 app . setPluginStatus ( "PostgSail started. Please wait for a status update." ) ;
101+ configuration = options ;
102+ monitoringConfiguration = options ?. monitoring == null ? null : options . monitoring ;
102103
103- host = options . host ;
104- token = options . token ;
105104 gpsSource = options . source ;
106105 app . debug ( `host ${ options . host } , token:${ options . token } ` ) ;
107106
108107 API = axios . create ( {
109- baseURL : host ,
108+ baseURL : options . host ,
110109 timeout : 50000 ,
111110 headers : {
112- Authorization : `Bearer ${ token } ` ,
111+ Authorization : `Bearer ${ options . token } ` ,
113112 "User-Agent" : `postgsail.signalk v${ metadata . plugin_version } ` ,
114113 } ,
115114 httpsAgent : new https . Agent ( { KeepAlive : true } ) ,
116115 } ) ;
116+ getConfiguration ( ) ;
117117 sendMetadata ( ) ;
118118
119119 let dbFile = filePath . join ( app . getDataDirPath ( ) , "postgsail.sqlite3" ) ;
@@ -175,7 +175,6 @@ module.exports = function (app) {
175175 } else {
176176 message = `no data in the queue,` ;
177177 }
178-
179178 if ( lastSuccessfulUpdate ) {
180179 let since = timeSince ( lastSuccessfulUpdate ) ;
181180 message += ` last connection to the server was ${ since } ago.` ;
@@ -194,6 +193,8 @@ module.exports = function (app) {
194193 app . setPluginError (
195194 "No navigation.state path, please install signalk-autostate."
196195 ) ;
196+ } else {
197+ app . setPluginError ( "" ) ;
197198 }
198199 }
199200 app . setPluginStatus ( message ) ;
@@ -258,7 +259,7 @@ module.exports = function (app) {
258259 return platform ;
259260 }
260261
261- let platform = null ;
262+ let platform = "" ;
262263 try {
263264 const cpuInfo = fs . readFileSync ( "/proc/cpuinfo" , {
264265 encoding : "utf8" ,
@@ -284,10 +285,99 @@ module.exports = function (app) {
284285 return platform ;
285286 }
286287
288+ function saveConfiguration ( ) {
289+ app . savePluginOptions ( configuration , ( ) => {
290+ app . debug ( "Plugin options saved" ) ;
291+ } ) ;
292+ }
293+
294+ function loadConfiguration ( ) {
295+ let options = app . readPluginOptions ( ) ;
296+ app . debug ( "loadConfiguration" , options ) ;
297+ configuration = options . configuration ;
298+ }
299+
300+ function getConfiguration ( update = false ) {
301+ if ( retrieveMonitoringConfigInProgress ) {
302+ app . debug ( "Monitoring configuration retrieval already in progress" ) ;
303+ return ;
304+ }
305+ retrieveMonitoringConfigInProgress = true ;
306+ let url = "/metadata?select=configuration" ;
307+ if ( update && configuration ?. monitoring ?. update_at ) {
308+ url += "&configuration->>update_at=gt." + configuration . monitoring . update_at ;
309+ }
310+ app . debug ( "Retrieving monitoring configuration" , url ) ;
311+ API . get ( url )
312+ . then ( function ( response ) {
313+ //console.log(response);
314+ //app.debug(response);
315+ if (
316+ response &&
317+ response . status == 200 &&
318+ Array . isArray ( response . data ) &&
319+ response . data . length > 0
320+ ) {
321+ app . debug ( "Successfully retrieved monitoring configuration" ) ;
322+ app . debug ( "Server monitoring configuration" , response . data [ 0 ] . configuration ) ;
323+ app . debug ( "Local current configuration" , configuration ) ;
324+ if ( typeof response . data [ 0 ] . configuration !== "object" ) {
325+ app . debug ( "Invalid monitoring configuration, ignore" ) ;
326+ return ;
327+ }
328+ configuration [ "monitoring" ] = response . data [ 0 ] . configuration ;
329+ saveConfiguration ( ) ;
330+ retrieveMonitoringConfigInProgress = false ;
331+ }
332+ } )
333+ . catch ( function ( error ) {
334+ app . debug ( error ) ;
335+ app . debug ( "Retrieving monitoring configuration failed" ) ;
336+ console . log (
337+ "signalk-postgsail - Retrieving monitoring configuration failed"
338+ ) ;
339+ app . debug (
340+ "Failed to get monitoring configuration, trying to load from local storage"
341+ ) ;
342+ loadConfiguration ( ) ;
343+ retrieveMonitoringConfigInProgress = false ;
344+ } ) ;
345+ }
346+
287347 function sendMetadata ( ) {
348+ function getAllKeys ( obj , parentKey = "" , result = [ ] ) {
349+ for ( let key in obj ) {
350+ if ( obj . hasOwnProperty ( key ) ) {
351+ const newKey = parentKey ? `${ parentKey } .${ key } ` : key ;
352+ if ( obj [ key ] !== null && typeof obj [ key ] === "object" ) {
353+ if ( obj [ key ] [ "$source" ] ) {
354+ if (
355+ obj [ key ] . value !== null &&
356+ typeof obj [ key ] . value === "number"
357+ ) {
358+ result . push ( {
359+ key : newKey ,
360+ unit : obj [ key ] ?. meta ?. units ?? null ,
361+ } ) ;
362+ }
363+ } else {
364+ getAllKeys ( obj [ key ] , newKey , result ) ;
365+ }
366+ }
367+ }
368+ }
369+ return result ;
370+ }
371+
372+ let self = app . getPath ( "self" ) ;
373+ let dataModel = app . getPath ( self ) ;
374+ let availableKeys = getAllKeys ( dataModel ) ;
375+ //console.log(availableKeys);
376+ app . debug ( 'available_keys: ' , availableKeys ) ;
377+ metadata . available_keys = availableKeys ;
288378 // Update metadata time
289379 metadata . time = new Date ( ) . toISOString ( ) ;
290- app . debug ( "DEBUG: metadata: " , metadata ) ;
380+ app . debug ( "Sending metadata to the server: " , metadata ) ;
291381 API . post ( "/metadata?on_conflict=vessel_id" , metadata , {
292382 headers : {
293383 Prefer : "return=headers-only,resolution=merge-duplicates" ,
@@ -300,6 +390,7 @@ module.exports = function (app) {
300390 //app.debug(response);
301391 lastSuccessfulUpdate = Date . now ( ) ;
302392 submitDataToServer ( ) ;
393+ getConfiguration ( true )
303394 }
304395 } )
305396 . catch ( function ( error ) {
@@ -358,6 +449,16 @@ module.exports = function (app) {
358449 return ;
359450 }
360451
452+ let monitoringDataInJson = null ;
453+ if ( configuration ?. monitoring ) {
454+ let monitoringData = getMonitoringData ( configuration . monitoring ) ;
455+ //monitoringDataInJson = JSON.stringify(monitoringData);
456+ metrics = Object . assign ( metrics , monitoringData ) ;
457+ } else {
458+ getConfiguration ( ) ;
459+ monitoringDataInJson = null ;
460+ }
461+
361462 let values = [
362463 new Date ( ) . toISOString ( ) ,
363464 null ,
@@ -843,8 +944,11 @@ module.exports = function (app) {
843944 /* Skip String, Object (typeof?) or skip Moon, Sun, Course */
844945 // environment.moon.*
845946 // environment.sunlight.*
947+ // environment.forecast.*
846948 // navigation.courseGreatCircle.*
847949 // design.*
950+ // entertainment.*
951+ // observations.*
848952
849953 // Debug
850954 //app.debug(`default: path '${path}' is invalid?, '${value}'`);
@@ -876,5 +980,51 @@ module.exports = function (app) {
876980 return Number ( n ) === n ;
877981 } ;
878982
983+ function getMonitoringData ( configuration ) {
984+ let data = {
985+ sog : getKeyValue ( 'navigation.speedOverGround' , 60 ) ,
986+ cog : getKeyValue ( 'navigation.courseOverGroundTrue' , 60 ) ,
987+ heading : getKeyValue ( 'navigation.headingTrue' , 60 ) ,
988+ anchor : {
989+ position : getKeyValue ( 'navigation.anchor.position' , 60 ) ,
990+ radius : getKeyValue ( 'navigation.anchor.maxRadius' , 60 )
991+ } ,
992+ water : {
993+ depth : getKeyValue ( configuration . depthKey , 10 ) ,
994+ temperature :getKeyValue ( configuration . waterTemperatureKey , 90 )
995+ } ,
996+ wind : {
997+ speed : getKeyValue ( configuration . windSpeedKey , 90 ) ,
998+ direction : getKeyValue ( configuration . windDirectionKey , 90 )
999+ } ,
1000+ temperature : {
1001+ inside : getKeyValue ( configuration . insidePressureKey , 90 ) ,
1002+ outside : getKeyValue ( configuration . outsidePressureKey , 90 )
1003+ } ,
1004+ temperature : {
1005+ inside : getKeyValue ( configuration . insideTemperatureKey , 90 ) ,
1006+ outside : getKeyValue ( configuration . outsideTemperatureKey , 90 )
1007+ } ,
1008+ humidity : {
1009+ inside : getKeyValue ( configuration . insideHumidityKey , 90 ) ,
1010+ outside : getKeyValue ( configuration . outsideHumidityKey , 90 )
1011+ } ,
1012+ battery : {
1013+ voltage : getKeyValue ( configuration . batteryVoltageKey , 60 ) ,
1014+ charge : getKeyValue ( configuration . batteryChargeKey , 60 )
1015+ }
1016+ } ;
1017+
1018+ for ( let i = 0 ; i < configuration ?. additionalDataKeys ?. length ; i ++ ) {
1019+ let key = configuration . additionalDataKeys [ i ] ;
1020+ let value = getKeyValue ( key , 90 ) ;
1021+ if ( value ) {
1022+ data [ key ] = value ;
1023+ }
1024+ }
1025+
1026+ return data ;
1027+ }
1028+
8791029 return plugin ;
8801030} ;
0 commit comments