bt-sensors-plugin-sk
Version:
Bluetooth Sensors for Signalk - see https://www.npmjs.com/package/bt-sensors-plugin-sk#supported-sensors for a list of supported sensors
142 lines (122 loc) • 5.14 kB
JavaScript
const OutOfRangeDevice = require('../../OutOfRangeDevice')
const DistanceManager = require('../../DistanceManager')
function getDistances(distanceManager, mac, txPower, rssi ){
const accuracy = (Math.min(1,+(txPower/rssi).toFixed(3)))
return {
avgDistance: +distanceManager.getDistance(mac, txPower, DistanceManager.METHOD_AVG, true).toFixed(2),
weightedAvgDistance: +distanceManager.getDistance(mac, txPower, DistanceManager.METHOD_WEIGHTED_AVG, true).toFixed(2),
sampledDistance: +distanceManager.getDistance(mac, txPower, DistanceManager.METHOD_LAST_FEW_SAMPLES, true).toFixed(2),
accuracy: accuracy
}
}
class AbstractBeaconMixin {
static logSize = 5
constructor(obj){
this.elapsedTimeSinceLastContact=this.elapsedTimeSinceLastContact.bind(obj)
this.initSchema=this.initSchema.bind(obj)
this.initListen=this.initListen.bind(obj)
this.propertiesChanged=this.propertiesChanged.bind(obj)
this.activate=this.activate.bind(obj)
this.stopListening=this.stopListening.bind(obj)
obj.GPSLog={log:[],beam:0,loa:0}
}
initListen() {
if (this.device instanceof OutOfRangeDevice){
this.emit("onBoard",false)
//{message:`Crew Member: ${this.crewMember} evidently not on board.`})
}
}
initSchema() {
this.addDefaultParam("id")
.examples=["captain_keyring", "firstMate_keyring"]
this.addParameter(
"crewMember",
{
title:'crew member associated with beacon',
default: "Captain"
}
)
this.addParameter(
"presenceThreshold",
{
title:'distance in meters beyond which presence on board should not be presumed',
type: 'integer',
default: 20
}
)
this.addParameter(
"lastContactThreshold",
{
title:'time in seconds beyond which presence on board should not be presumed',
type: 'integer',
default: 30
}
)
this.addMetadatum("approxDistance","","approximate sensor distance from server")
.default="sensors.{macAndName}.distance.approximate"
this.addMetadatum("onBoard","","boolean indicating crew member likely presence on board")
.default="manifest.crew.{crewMember}.onBoard"
this.addMetadatum("GPSLog","","log of crew member's last known GPS coordinates")
.default="manifest.crew.{crewMember}.GPSLog"
}
elapsedTimeSinceLastContact(lc){
if (Number.isNaN(lc) || lc > this.lastContactThreshold){
this.emit("onBoard",false)
}
return lc
}
propertiesChanged(props){
if(Object.hasOwn(props,"RSSI")){
const mac = this.getMacAddress()
const rssi = props.RSSI.value
this.constructor.DistanceManagerSingleton.addSample(mac, rssi)
const distances= getDistances(this.constructor.DistanceManagerSingleton, mac, this.getTxPower(), rssi)
if (distances){
this.emit("approxDistance", distances)
this.emit("onBoard", distances.avgDistance<this?.presenceThreshold??20)
}
if (his.GPSLog.currentPosition){
this.GPSLog.log.unshift(
{
timestamp: new Date().toISOString(),
heading: this.GPSLog.heading,
distances: distances
})
Object.assign(this.GPSLog.log[0], this.GPSLog.currentPosition)
if (this.GPSLog.log.length>AbstractBeaconMixin.logSize){
this.GPSLog.log = this.GPSLog.log.slice(0,AbstractBeaconMixin.logSize)
}
this.emit("GPSLog", this.GPSLog)
}
}
}
async activate(config,paths){
this.GPSLog.beam=this._app.getSelfPath('design.beam')
this.GPSLog.loa=this._app.getSelfPath('design.length.overall')
this._positionSub = this._app.streambundle.getSelfStream('navigation.position')
.onValue(
(pos) => {
this.GPSLog.currentPosition=pos
this.emit("GPSLog",this.GPSLog)
}
);
this._headingSub = this._app.streambundle.getSelfStream('navigation.headingTrue')
.onValue(
(pos) => {
this.GPSLog.heading=heading
this.emit("GPSLog",this.GPSLog)
}
);
}
async stopListening(){
if (this._positionSub){
this._positionSub()
this._positionSub = null
}
if (this._headingSub){
this._headingSub()
this._headingSub = null
}
}
}
module.exports=AbstractBeaconMixin