openrowingmonitor/app/ble/ftms/FitnessMachineStatusCharact...

89 lines
2.8 KiB
JavaScript

'use strict'
/*
Open Rowing Monitor, https://github.com/laberning/openrowingmonitor
Implements the Status Characteristics, that can be used to notify the central about the current
training machine settings. Currently only used to notify the central about training resets.
From the specs:
If the Server supports the Fitness Machine Control Point, the Fitness Machine Status characteristic
shall be exposed by the Server. Otherwise, supporting the Fitness Machine Status characteristic is optional.
*/
import bleno from '@abandonware/bleno'
import log from 'loglevel'
// see page 67 https://www.bluetooth.com/specifications/specs/fitness-machine-service-1-0
const StatusOpCode = {
reservedForFutureUse: 0x00,
reset: 0x01,
stoppedOrPausedByUser: 0x02,
stoppedBySafetyKey: 0x03,
startedOrResumedByUser: 0x04,
targetSpeedChanged: 0x05,
targetInclineChanged: 0x06,
targetResistanceLevelChanged: 0x07,
targetPowerChanged: 0x08,
targetHeartRateChanged: 0x09,
targetExpendedEnergyChanged: 0x0a,
targetNumberOfStepsChanged: 0x0b,
targetNumberOfStridesChanged: 0x0c,
targetDistanceChanged: 0x0d,
targetTrainingTimeChanged: 0x0e,
targetedTimeInTwoHeartRateZonesChanged: 0x0f,
targetedTimeInThreeHeartRateZonesChanged: 0x10,
targetedTimeInFiveHeartRateZonesChanged: 0x11,
indoorBikeSimulationParametersChanged: 0x12,
wheelCircumferenceChanged: 0x13,
spinDownStatus: 0x14,
targetedCadenceChanged: 0x15
}
export default class FitnessMachineStatusCharacteristic extends bleno.Characteristic {
constructor () {
super({
// Fitness Machine Status
uuid: '2ADA',
value: null,
properties: ['notify']
})
this._updateValueCallback = null
}
onSubscribe (maxValueSize, updateValueCallback) {
log.debug(`FitnessMachineStatusCharacteristic - central subscribed with maxSize: ${maxValueSize}`)
this._updateValueCallback = updateValueCallback
return this.RESULT_SUCCESS
}
onUnsubscribe () {
log.debug('FitnessMachineStatusCharacteristic - central unsubscribed')
this._updateValueCallback = null
return this.RESULT_UNLIKELY_ERROR
}
notify (status) {
if (!(status && status.name)) {
log.error('can not deliver status without name')
return this.RESULT_SUCCESS
}
if (this._updateValueCallback) {
const buffer = Buffer.alloc(2)
switch (status.name) {
case 'reset':
buffer.writeUInt8(StatusOpCode.reset, 0)
break
case 'stoppedOrPausedByUser':
buffer.writeUInt8(StatusOpCode.stoppedOrPausedByUser, 0)
break
case 'startedOrResumedByUser':
buffer.writeUInt8(StatusOpCode.startedOrResumedByUser, 0)
break
default:
log.error(`status ${status.name} is not supported`)
}
this._updateValueCallback(buffer)
}
return this.RESULT_SUCCESS
}
}