Skip to content

Commit

Permalink
feature: add daily log
Browse files Browse the repository at this point in the history
Add optional output of daily distance log values every 5 minutes.
  • Loading branch information
tkurki committed Jul 17, 2024
1 parent 09dc4ca commit 37847d4
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 9 deletions.
78 changes: 71 additions & 7 deletions src/HistoryAPI.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { DateTimeFormatter, ZonedDateTime } from '@js-joda/core'
import { DateTimeFormatter, LocalDate, ZoneId, ZonedDateTime } from '@js-joda/core'

import { Request, Response, Router } from 'express'
import { SKInflux } from './influx'
import { InfluxDB as InfluxV1 } from 'influx'
import { FluxResultObserver, FluxTableMetaData } from '@influxdata/influxdb-client'
import { Brand, Context, Path, Timestamp } from '@signalk/server-api'
import { start } from 'repl'

type AggregateMethod = Brand<string, 'aggregatemethod'>

Expand Down Expand Up @@ -158,17 +159,17 @@ export function getValues(
const positionResult = positionPathSpecs.length
? getPositions(influx.v1Client, context, from, to, timeResolutionMillis, debug)
: Promise.resolve({
values: [],
data: [],
})
values: [],
data: [],
})

const nonPositionPathSpecs = pathSpecs.filter(({ path }) => path !== 'navigation.position')
const nonPositionResult: Promise<DataResult> = nonPositionPathSpecs.length
? getNumericValues(influx, context, from, to, timeResolutionMillis, nonPositionPathSpecs, format, debug)
: Promise.resolve({
values: [],
data: [],
})
values: [],
data: [],
})

return Promise.all([positionResult, nonPositionResult])
.then(([positionResult, nonPositionResult]) => {
Expand Down Expand Up @@ -491,3 +492,66 @@ const getRequestParams = ({ query }: FromToContextRequest, selfId: string) => {
throw new Error(`Error extracting from/to query parameters from ${JSON.stringify(query)}`)
}
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function getDailyLogData(influx: SKInflux, selfId: string, debug:(...args: any) => void) {
return new Promise<{length: number}>((resolve) => {
const startOfToday = LocalDate.now().atStartOfDay().atZone(ZoneId.of('UTC'))
getValues(influx, `vessels.${selfId}` as Context, startOfToday, ZonedDateTime.now(), '', debug, {
query: { paths: 'navigation.position', resolution: `${60}` }
}, {
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
status: function (s: number): void {
},
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
json: (result: any) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const validData = result.data.filter((d: any) => Array.isArray(d) && d[1][0] !== null && d[1][1] !== null)
resolve(trackStats(validData))
},
// eslint-disable-next-line @typescript-eslint/no-unused-vars
header: function (n: string, v: string): void {
throw new Error('Function not implemented.')
},
// eslint-disable-next-line @typescript-eslint/no-unused-vars
send: function (c: string): void {
throw new Error('Function not implemented.')
}
}
)
})
}

const R = 6371 * 1000; // Earth's radius in meters

function haversineDistance([lon1, lat1]: number[], [lon2, lat2]: number[]) {
const dLat = lat2 - lat1;
const dLon = lon2 - lon1;
const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(lat1) * Math.cos(lat2) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);

return 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function trackStats(track: any[][]) {
if (track.length === 0) {
return {
length: 0
}
}
let previousPoint = [toRadians(track[0][1][0]), toRadians(track[0][1][1])]
return {
length: track.slice(1).reduce((acc, trackPoint) => {
const thisPoint = [toRadians(trackPoint[1][0]), toRadians(trackPoint[1][1])]
acc += haversineDistance(previousPoint, thisPoint)
previousPoint = thisPoint
return acc
}, 0) * R
}
}

function toRadians(degrees: number) {
return degrees * Math.PI / 180;
}
1 change: 1 addition & 0 deletions src/influx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ export class SKInflux {
}
}


const typeFor = (pathValue: PathValue): JsValueType => {
let r = VALUETYPECACHE[pathValue.path]
if (!r) {
Expand Down
2 changes: 2 additions & 0 deletions src/plugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ describe('Plugin', () => {
resolution: 0,
},
],
outputDailyLog: false
})
})

Expand Down Expand Up @@ -260,6 +261,7 @@ describe('Plugin', () => {
resolution: 0,
},
],
outputDailyLog: false
})
const FIXED_TIMESTAMP = '2023-08-17T17:01:00Z'
app.signalk.emit('delta', {
Expand Down
49 changes: 47 additions & 2 deletions src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@

import { SKInflux, SKInfluxConfig } from './influx'
import { EventEmitter } from 'stream'
import { registerHistoryApiRoute } from './HistoryAPI'
import { getDailyLogData, registerHistoryApiRoute } from './HistoryAPI'
import { IRouter } from 'express'
import { Context, Delta, PathValue, SourceRef, ValuesDelta } from '@signalk/server-api'
import { Context, Delta, MetaDelta, Path, PathValue, SourceRef, ValuesDelta } from '@signalk/server-api'

// eslint-disable-next-line @typescript-eslint/no-var-requires
const packageInfo = require('../package.json')
Expand All @@ -29,6 +29,7 @@ export interface Logging {
error: (...args: any) => void
}
export interface App extends Logging, Pick<IRouter, 'get'> {
handleMessage(id: string, delta: Delta): void
signalk: EventEmitter
selfId: string
setPluginStatus: (msg: string) => void
Expand Down Expand Up @@ -60,6 +61,12 @@ export interface InfluxPlugin {
}

export interface PluginConfig {
/**
* @title Output Daily Distance Log values
* @description Calculate periodically daily distance from navigation.position values since 00:00 local time and output under navigation.trip.daily
* @default false
*/
outputDailyLog: boolean
influxes: SKInfluxConfig[]
}

Expand Down Expand Up @@ -94,6 +101,44 @@ export default function InfluxPluginFactory(app: App): Plugin & InfluxPlugin {
onStop.push(() => clearInterval(pruner))
})

if (config.outputDailyLog) {
app.handleMessage('', {
updates: [
{
meta: [
{
path: 'navigation.trip.daily.log',
value: {
units: 'm'
}
}
]
}
]
} as unknown as MetaDelta)
let previousLength = 0
const get = () => {
app.debug('getDailyLogData')
getDailyLogData(skInfluxes[0], app.selfId, app.debug).then(({ length }) => {
app.debug(length)
if (length !== previousLength) {
previousLength = length
app.handleMessage('', {
updates: [{
values: [{
path: 'navigation.trip.daily.log' as Path,
value: length
}]
}]
})
}
})
}
const interval = setInterval(get, 5 * 60 * 1000)
get()
onStop.push(() => clearInterval(interval))
}

return Promise.all(skInfluxes.map((skInflux) => skInflux.init())).then(() => {
const onDelta = (_delta: Delta) => {
const delta = _delta as ValuesDelta
Expand Down

0 comments on commit 37847d4

Please sign in to comment.