'use strict' /* Open Rowing Monitor, https://github.com/laberning/openrowingmonitor Creates a Bluetooth Low Energy (BLE) Peripheral with all the Services that are required for a Fitness Machine Device Relevant parts from https://www.bluetooth.com/specifications/specs/fitness-machine-profile-1-0/ The Fitness Machine shall instantiate one and only one Fitness Machine Service as Primary Service The User Data Service, if supported, shall be instantiated as a Primary Service. The Fitness Machine may instantiate the Device Information Service (Manufacturer Name String, Model Number String) */ import bleno from '@abandonware/bleno' import FitnessMachineService from './ftms/FitnessMachineService.js' // import DeviceInformationService from './ftms/DeviceInformationService.js' import config from '../tools/ConfigManager.js' import log from 'loglevel' function createFtmsPeripheral (controlCallback, options) { const peripheralName = options?.simulateIndoorBike ? config.ftmsBikePeripheralName : config.ftmsRowerPeripheralName const fitnessMachineService = new FitnessMachineService(options, controlPointCallback) // const deviceInformationService = new DeviceInformationService() bleno.on('stateChange', (state) => { triggerAdvertising(state) }) bleno.on('advertisingStart', (error) => { if (!error) { bleno.setServices( // [fitnessMachineService, deviceInformationService], [fitnessMachineService], (error) => { if (error) log.error(error) }) } }) bleno.on('accept', (clientAddress) => { log.debug(`ble central connected: ${clientAddress}`) bleno.updateRssi() }) bleno.on('disconnect', (clientAddress) => { log.debug(`ble central disconnected: ${clientAddress}`) }) bleno.on('platform', (event) => { log.debug('platform', event) }) bleno.on('addressChange', (event) => { log.debug('addressChange', event) }) bleno.on('mtuChange', (event) => { log.debug('mtuChange', event) }) bleno.on('advertisingStartError', (event) => { log.debug('advertisingStartError', event) }) bleno.on('servicesSetError', (event) => { log.debug('servicesSetError', event) }) bleno.on('rssiUpdate', (event) => { log.debug('rssiUpdate', event) }) function controlPointCallback (event) { const obj = { req: event, res: {} } if (controlCallback) controlCallback(obj) return obj.res } function destroy () { return new Promise((resolve) => { bleno.disconnect() bleno.removeAllListeners() bleno.stopAdvertising(resolve) }) } function triggerAdvertising (eventState) { const activeState = eventState || bleno.state if (activeState === 'poweredOn') { bleno.startAdvertising( peripheralName, // [fitnessMachineService.uuid, deviceInformationService.uuid], [fitnessMachineService.uuid], (error) => { if (error) log.error(error) } ) } else { bleno.stopAdvertising() } } // present current rowing metrics to FTMS central function notifyData (type, data) { if (type === 'strokeFinished' || type === 'metricsUpdate') { fitnessMachineService.notifyData(data) } } // present current rowing status to FTMS central function notifyStatus (status) { fitnessMachineService.notifyStatus(status) } return { triggerAdvertising, notifyData, notifyStatus, destroy } } export { createFtmsPeripheral }