bt-sensors-plugin-sk
Version:
Bluetooth Sensors for Signalk - see https://www.npmjs.com/package/bt-sensors-plugin-sk for a list of supported classes
217 lines (188 loc) • 7.76 kB
JavaScript
function arduinoDateDecode (elapsedSeconds) {
const date = new Date("2000-01-01")
date.setTime(date.getTime() + 1000 * elapsedSeconds)
return date
}
const errors= {
0: "Undefined",
1: "Invalid Battery",
2: "Overheat",
3: "Overheat Shutdown",
4: "Generator lead 1 disconnected",
5: "Generator lead 2 disconnected",
6: "Generator lead 3 disconnected",
7: "Short Circuit"
}
const eventTypes = {
0: "Reboot",
1: "Invalid Battery",
2: "Overheat",
3: "Overheat Shutdown",
4: "Generator lead 1 disconnected",
5: "Generator lead 2 disconnected",
6: "Generator lead 3 disconnected",
7: "Short Circuit",
255: "Debug"
}
const states= ["Charging Needed", "Charging", "Floating", "Idle"]
const BTSensor = require("../BTSensor");
class RemoranWave3 extends BTSensor{
static Domain = BTSensor.SensorDomains.electrical
serviceUUID = "81D08DF0-C0F8-422A-9D9D-E4379BB1EA3B"
info1CharUUID = "62C91222-FAFE-4F6E-95F0-AFC02BD19F2E"
info2CharUUID = "f5d12d34-4390-486c-b906-24ea8906af71"
eventUuid = "f12a8e25-59f7-42f2-b7ae-ba96fb25c13c"
static async identify(device){
const name = await this.getDeviceProp(device,"Name")
if (name == 'Remoran Wave.3')
return this
else
return null
}
hasGATT(){
return true
}
usingGATT(){
return true
}
emitInfo1Data(buffer){
if (buffer.length < 20) {
app.debug(`Bad buffer size ${buffer.length}. Buffer size must be 20 bytes or more.`)
return
}
emitData("versionNumber", buffer.readUInt8(0))
const errors = buffer.readUInt8(2)
const errorState = []
for (var i = 0; i < 8; ++i) {
var c = 1 << i;
r & c && errorState.push(errors[i])
}
emitData("errors", errorState)
emitData("state", states[buffer.readUInt8(3)])
emitData("rpm", buffer.readUInt32LE(4))
emitData( "voltage" , buffer.readFloatLE(8))
emitData("current", buffer.readFloatLE(12))
emitData( "power", buffer.readFloatLE(16))
if (buffer.length > 23) {
emitData( "temp", buffer.readFloatLE(20).toFixed(1))
emitData( "uptime", buffer.readUInt32(24))
if (versionNumber>1 && buffer.size > 31) {
emitData("energy", buffer.readFloatLE(32).toFixed(1))
}
}
}
emitInfo2Data(buffer){
if (buffer.size < 12) {
app.debug(`Bad buffer size ${buffer.length}. Buffer size must be 12 bytes or more.`)
return
}
emitData("versionNumber", buffer.getUint8(0))
emitData("temp", buffer.readFloat32LE(4))
emitData("uptime", buffer.readUInt32(8))
emitData("lastBootTime", arduinoDateDecode(buffer.getUInt32LE(12)))
emitData("energy", buffer.readFloat32LE(16))
}
emitEventData(buffer){
if (buffer.size < 14) {
app.debug(`Bad buffer size ${buffer.length}. Buffer size must be 14 bytes or more.`)
return
}
this.emitData("event",
{
firstDate: arduinoDateDecode(buffer.readUInt32LE(0)),
lastDate: arduinoDateDecode(buffer.readUInt32LE(4)),
eventType: buffer.readUInt16LE(8),
count: buffer.readUInt16LE(10),
index: buffer.readUInt16LE(12),
eventDesc: eventTypes[i]
}
)
}
emitGATT(){
this.info1Characteristic.readValue()
.then((buffer)=>
this.emitInfo1Data( buffer)
)
this.info2Characteristic.readValue()
.then((buffer)=>
this.emitInfo2Data(buffer)
)
this.eventCharacteristic.readValue()
.then((buffer)=>
this.emitEventData(buffer)
)
}
initSchema(){
super.initSchema()
this.addDefaultParam("id")
.default="RemoranWave3"
this.getGATTParams()["useGATT"].default=true
this.addMetadatum('errorCodes','', 'charger error codes (array)')
.default= "electrical.chargers.{id}.errorCodes"
this.addMetadatum('state','', 'charger state')
.default= "electrical.chargers.{id}.state"
this.addMetadatum('voltage','V', 'battery voltage')
.default= "electrical.chargers.{id}.battery.voltage"
this.addMetadatum('current','A', 'battery current')
.default= "electrical.chargers.{id}.battery.current"
this.addMetadatum('power','W', 'battery power')
.default= "electrical.chargers.{id}.battery.power"
this.addMetadatum('temp', 'K', 'charger temperature')
.default= "electrical.chargers.{id}.temperature"
this.addMetadatum('energy', 'wh', 'energy created today in Wh')
.default= "electrical.chargers.{id}.energy"
this.addMetadatum('event', '', 'charger event')
.default= "electrical.chargers.{id}.event"
this.addMetadatum('lastBootTime', 's', 'last boot time')
.default= "electrical.chargers.{id}.lastBootTime"
this.addMetadatum('rpm', '', 'revolutions per minute')
.default= "sensors.{macAndName}.rpm"
this.addMetadatum('uptime', 's', 'charger/sensor uptime')
.default= "sensors.{macAndName}.uptime"
this.addMetadatum('versionNumber', '', 'charger/sensor version number')
.default= "sensors.{macAndName}.version"
}
initGATTConnection(){
return new Promise((resolve,reject )=>{ this.deviceConnect().then(async ()=>{
if (!this.gattServer) {
this.gattServer = await this.device.gatt()
this.service = await this.gattServer.getPrimaryService(this.serviceUUID)
this.info1Characteristic = await this.service.getCharacteristic(this.info1CharUUID)
this.info2Characteristic = await this.service.getPrimaryService(this.info2CharUUID)
this.eventCharacteristic = await this.service.getCharacteristic(this.eventUUID)
resolve(this)
}}) .catch((e)=>{ reject(e.message) }) })
}
initGATTNotifications() {
Promise.resolve(this.info1Characteristic.startNotifications().then(()=>{
this.info1Characteristic.on('valuechanged', buffer => {
this.emitInfo1Data(buffer)
})
}))
Promise.resolve(this.info2Characteristic.startNotifications().then(()=>{
this.info2Characteristic.on('valuechanged', buffer => {
this.emitInfo2Data(buffer)
})
}))
Promise.resolve(this.eventCharacteristic.startNotifications().then(()=>{
this.eventCharacteristic.on('valuechanged', buffer => {
this.emitEventData(buffer)
})
}))
}
async stopNotifications(characteristic){
if (characteristic && await characteristic.isNotifying()) {
await characteristic.stopNotifications()
}
}
async stopListening(){
super.stopListening()
await stopNotifations(this.info1Characteristic)
await stopNotifations(this.info2Characteristic)
await stopNotifations(this.eventCharacteristic)
if (await this.device.isConnected()){
await this.device.disconnect()
}
}
}
module.exports=RemoranWave3