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
149 lines (123 loc) • 4.66 kB
JavaScript
const BTSensor = require("../BTSensor");
function bytesToBase10String(bytes){
let s = ""
for (let byte of bytes){
s+=byte.toString(16)
}
return s
}
class JunctekBMS extends BTSensor{
static Domain = BTSensor.SensorDomains.electrical
constructor(device, config, gattConfig) {
super(device, config, gattConfig)
}
static async identify(device){
return null
}
hasGATT(){
return true
}
async initSchema(){
super.initSchema()
this.addDefaultParam("batteryID")
this.addDefaultPath("voltage","electrical.batteries.voltage")
this.addDefaultPath("current","electrical.batteries.current")
this.addDefaultPath("power","electrical.batteries.power")
this.addDefaultPath("cycles",'electrical.batteries.cycles')
this.addDefaultPath("soc",'electrical.batteries.capacity.stateOfCharge')
this.addDefaultPath("remainingAh",'electrical.batteries.capacity.remaining')
this.addDefaultPath("timeRemaining",'electrical.batteries.capacity.timeRemaining')
this.addDefaultPath("discharge",'electrical.batteries.capacity.dischargeSinceFull')
this.addDefaultPath("charge",'electrical.batteries.capacity.charge')
this.addDefaultPath("temperature",'electrical.batteries.temperature')
this.addDefaultPath("actualCapacity",'electrical.batteries.capacity.actual')
this.addMetadatum('impedance','mOhm', 'measured resistance')
.default='electrical.batteries.{batteryID}.impedance'
}
emitFrom(buffer){
var value=[], chargeDirection = 1
for (let byte of buffer){
if (byte==0xBB) {
value=[]
continue
}
if (byte==0xEE){
continue
}
value.push[byte]
if (parseInt(byte.toString(16))==NaN){ //not a base-10 number. seriously. that's how Junctek does this.
const v = parseInt(bytesToBase10String(value))
switch (byte){
case 0xC0:{
emitData("voltage",v/100)
}
case 0xC1:{
emitData("current",(v/100)*chargeDirection)
}
case 0xD1:{
if (byte==0)
chargeDirection=-1
}
case 0xD2:{
emitData("remainingAh",v/1000)
}
case 0xD3:{
emitData("discharge",v/100000)
}
case 0xD4:{
emitData("charge",v/100000)
}
case 0xD6:{
emitData("timeRemaining",v*60)
}
case 0xD7:{
emitData("impedance",v/100)
}
case 0xD8:{
emitData("power",(v/100)*chargeDirection)
}
case 0xD9:{
emitData("temperature",v + 173.15) //assume C not F
}
case 0xB1:{
emitData("capacityActual",v /10 )
}
}
}
}
}
emitGATT(){
this.battCharacteristic.readValue()
.then((buffer)=>{
this.emitFrom(buffer)
})
}
initGATTConnection(){
return new Promise((resolve,reject )=>{ this.deviceConnect().then(async ()=>{
if (!this.gattServer) {
this.gattServer = await this.device.gatt()
this.battService = await this.gattServer.getPrimaryService("0000fff0-0000-1000-8000-00805f9b34fb")
this.battCharacteristic = await this.battService.getCharacteristic("0000ffe1-0000-1000-8000-00805f9b34fb")
}
resolve(this)
}) .catch((e)=>{ reject(e.message) }) })
}
initGATTNotifications() {
Promise.resolve(this.battCharacteristic.startNotifications().then(()=>{
this.battCharacteristic.on('valuechanged', buffer => {
this.emitFrom(buffer)
})
}))
}
async stopListening(){
super.stopListening()
if (this.battCharacteristic && await this.battCharacteristic.isNotifying()) {
await this.battCharacteristic.stopNotifications()
this.battCharacteristic=null
}
if (await this.device.isConnected()){
await this.device.disconnect()
}
}
}
module.exports=JunctekBMS