openrowingmonitor/app/ble/pm5/characteristic/AdditionalStatus.js

79 lines
3.0 KiB
JavaScript

'use strict'
/*
Open Rowing Monitor, https://github.com/laberning/openrowingmonitor
Implementation of the AdditionalStatus as defined in:
https://www.concept2.co.uk/files/pdf/us/monitors/PM5_BluetoothSmartInterfaceDefinition.pdf
*/
import bleno from '@abandonware/bleno'
import { getFullUUID } from '../Pm5Constants.js'
import log from 'loglevel'
import BufferBuilder from '../../BufferBuilder.js'
export default class AdditionalStatus extends bleno.Characteristic {
constructor (multiplexedCharacteristic) {
super({
// id for AdditionalStatus as defined in the spec
uuid: getFullUUID('0032'),
value: null,
properties: ['notify']
})
this._updateValueCallback = null
this._multiplexedCharacteristic = multiplexedCharacteristic
}
onSubscribe (maxValueSize, updateValueCallback) {
log.debug(`AdditionalStatus - central subscribed with maxSize: ${maxValueSize}`)
this._updateValueCallback = updateValueCallback
return this.RESULT_SUCCESS
}
onUnsubscribe () {
log.debug('AdditionalStatus - central unsubscribed')
this._updateValueCallback = null
return this.RESULT_UNLIKELY_ERROR
}
notify (data) {
if (this._updateValueCallback || this._multiplexedCharacteristic.centralSubscribed()) {
const bufferBuilder = new BufferBuilder()
// elapsedTime: UInt24LE in 0.01 sec
bufferBuilder.writeUInt24LE(Math.round(data.durationTotal * 100))
// speed: UInt16LE in 0.001 m/sec
bufferBuilder.writeUInt16LE(Math.round(data.speed * 1000 / 3.6))
// strokeRate: UInt8 in strokes/min
bufferBuilder.writeUInt8(Math.round(data.strokesPerMinute))
// heartrate: UInt8 in bpm, 255 if invalid
bufferBuilder.writeUInt8(Math.round(data.heartrate))
// currentPace: UInt16LE in 0.01 sec/500m
// if split is infinite (i.e. while pausing), use the highest possible number
bufferBuilder.writeUInt16LE(data.split !== Infinity ? Math.round(data.split * 100) : 0xFFFF)
// averagePace: UInt16LE in 0.01 sec/500m
let averagePace = 0
if (data.distanceTotal && data.distanceTotal !== 0) {
averagePace = data.durationTotal / data.distanceTotal * 500
}
bufferBuilder.writeUInt16LE(Math.round(averagePace * 100))
// restDistance: UInt16LE
bufferBuilder.writeUInt16LE(0)
// restTime: UInt24LE in 0.01 sec
bufferBuilder.writeUInt24LE(0 * 100)
if (!this._updateValueCallback) {
// the multiplexer uses a slightly different format for the AdditionalStatus
// it adds averagePower before the ergMachineType
// averagePower: UInt16LE in watts
bufferBuilder.writeUInt16LE(Math.round(data.power))
}
// ergMachineType: 0 TYPE_STATIC_D
bufferBuilder.writeUInt8(0)
if (this._updateValueCallback) {
this._updateValueCallback(bufferBuilder.getBuffer())
} else {
this._multiplexedCharacteristic.notify(0x32, bufferBuilder.getBuffer())
}
return this.RESULT_SUCCESS
}
}
}