Skip to content

Commit 64df14c

Browse files
authored
Merge pull request doudar#140 from doudar/Echelon
Echelon
2 parents 2389e8d + 7a57884 commit 64df14c

17 files changed

+217
-18
lines changed

include/BLE_Common.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,16 @@
3737
#define FITNESSMACHINEPOWERRANGE_UUID BLEUUID((uint16_t)0x2AD8)
3838

3939
// GATT service/characteristic UUIDs for Flywheel Bike from ptx2/gymnasticon/
40-
#define FLYWHEEL_UART_SERVICE_UUID BLEUUID((uint16_t)0xCA9E)
41-
#define FLYWHEEL_UART_RX_UUID BLEUUID((uint16_t)0xCA9E)
42-
#define FLYWHEEL_UART_TX_UUID BLEUUID((uint16_t)0xCA9E)
40+
#define FLYWHEEL_UART_SERVICE_UUID BLEUUID("6e400001b5a3f393e0a9e50e24dcca9e")
41+
#define FLYWHEEL_UART_RX_UUID BLEUUID("6e400002b5a3f393e0a9e50e24dcca9e")
42+
#define FLYWHEEL_UART_TX_UUID BLEUUID("6e400003b5a3f393e0a9e50e24dcca9e")
43+
44+
// The Echelon Services
45+
#define ECHELON_DEVICE_UUID BLEUUID("0bf669f0-45f2-11e7-9598-0800200c9a66")
46+
#define ECHELON_SERVICE_UUID BLEUUID("0bf669f1-45f2-11e7-9598-0800200c9a66")
47+
#define ECHELON_WRITE_UUID BLEUUID("0bf669f2-45f2-11e7-9598-0800200c9a66")
48+
#define ECHELON_DATA_UUID BLEUUID("0bf669f4-45f2-11e7-9598-0800200c9a66")
49+
4350

4451
// macros to convert different types of bytes into int The naming here sucks and should be fixed.
4552
#define bytes_to_s16(MSB, LSB) (((signed int)((signed char)MSB))) << 8 | (((signed char)LSB))

include/sensors/CyclePowerData.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
// SmartSpin2K code
2+
// This software registers an ESP32 as a BLE FTMS device which then uses a stepper motor to turn the resistance knob on a regular spin bike.
3+
// BLE code based on examples from https://github.com/nkolban
4+
// Copyright 2020 Anthony Doud & Joel Baranick
5+
// This work is licensed under the GNU General Public License v2
6+
// Prototype hardware build from plans in the SmartSpin2k repository are licensed under Cern Open Hardware Licence version 2 Permissive
7+
18
#pragma once
29

310
#include <Arduino.h>

include/sensors/EchelonData.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// SmartSpin2K code
2+
// This software registers an ESP32 as a BLE FTMS device which then uses a stepper motor to turn the resistance knob on a regular spin bike.
3+
// BLE code based on examples from https://github.com/nkolban
4+
// Copyright 2020 Anthony Doud & Joel Baranick
5+
// This work is licensed under the GNU General Public License v2
6+
// Prototype hardware build from plans in the SmartSpin2k repository are licensed under Cern Open Hardware Licence version 2 Permissive
7+
8+
#pragma once
9+
10+
#include "SensorData.h"
11+
12+
class EchelonData : public SensorData
13+
{
14+
public:
15+
EchelonData() : SensorData("ECH"), cadence(NAN), resistance(INT_MIN), power(INT_MIN) {};
16+
17+
bool hasHeartRate();
18+
bool hasCadence();
19+
bool hasPower();
20+
bool hasSpeed();
21+
int getHeartRate();
22+
float getCadence();
23+
int getPower();
24+
float getSpeed();
25+
void decode(uint8_t *data, size_t length);
26+
27+
private:
28+
float cadence;
29+
int resistance;
30+
int power;
31+
};

include/sensors/FitnessMachineIndoorBikeData.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
// SmartSpin2K code
2+
// This software registers an ESP32 as a BLE FTMS device which then uses a stepper motor to turn the resistance knob on a regular spin bike.
3+
// BLE code based on examples from https://github.com/nkolban
4+
// Copyright 2020 Anthony Doud & Joel Baranick
5+
// This work is licensed under the GNU General Public License v2
6+
// Prototype hardware build from plans in the SmartSpin2k repository are licensed under Cern Open Hardware Licence version 2 Permissive
7+
18
#pragma once
29

310
#include <Arduino.h>

include/sensors/FlywheelData.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
// SmartSpin2K code
2+
// This software registers an ESP32 as a BLE FTMS device which then uses a stepper motor to turn the resistance knob on a regular spin bike.
3+
// BLE code based on examples from https://github.com/nkolban
4+
// Copyright 2020 Anthony Doud & Joel Baranick
5+
// This work is licensed under the GNU General Public License v2
6+
// Prototype hardware build from plans in the SmartSpin2k repository are licensed under Cern Open Hardware Licence version 2 Permissive
7+
18
#pragma once
29

310
#include "SensorData.h"

include/sensors/HeartRateData.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
// SmartSpin2K code
2+
// This software registers an ESP32 as a BLE FTMS device which then uses a stepper motor to turn the resistance knob on a regular spin bike.
3+
// BLE code based on examples from https://github.com/nkolban
4+
// Copyright 2020 Anthony Doud & Joel Baranick
5+
// This work is licensed under the GNU General Public License v2
6+
// Prototype hardware build from plans in the SmartSpin2k repository are licensed under Cern Open Hardware Licence version 2 Permissive
7+
18
#pragma once
29

310
#include "SensorData.h"

include/sensors/SensorData.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
// SmartSpin2K code
2+
// This software registers an ESP32 as a BLE FTMS device which then uses a stepper motor to turn the resistance knob on a regular spin bike.
3+
// BLE code based on examples from https://github.com/nkolban
4+
// Copyright 2020 Anthony Doud & Joel Baranick
5+
// This work is licensed under the GNU General Public License v2
6+
// Prototype hardware build from plans in the SmartSpin2k repository are licensed under Cern Open Hardware Licence version 2 Permissive
7+
18
#pragma once
29

310
#include <Arduino.h>

include/sensors/SensorDataFactory.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
// SmartSpin2K code
2+
// This software registers an ESP32 as a BLE FTMS device which then uses a stepper motor to turn the resistance knob on a regular spin bike.
3+
// BLE code based on examples from https://github.com/nkolban
4+
// Copyright 2020 Anthony Doud & Joel Baranick
5+
// This work is licensed under the GNU General Public License v2
6+
// Prototype hardware build from plans in the SmartSpin2k repository are licensed under Cern Open Hardware Licence version 2 Permissive
7+
18
#pragma once
29

310
#include <memory>
@@ -8,6 +15,7 @@
815
#include "FlywheelData.h"
916
#include "FitnessMachineIndoorBikeData.h"
1017
#include "HeartRateData.h"
18+
#include "EchelonData.h"
1119

1220
class SensorDataFactory
1321
{

src/BLE_Client.cpp

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,12 @@ bool SpinBLEClient::connectToServer()
122122
charUUID = FITNESSMACHINEINDOORBIKEDATA_UUID;
123123
debugDirector("trying to connect to Fitness machine service");
124124
}
125+
else if (myDevice->isAdvertisingService(ECHELON_DEVICE_UUID))
126+
{
127+
serviceUUID = ECHELON_SERVICE_UUID;
128+
charUUID = ECHELON_DATA_UUID;
129+
debugDirector("Trying to connect to Echelon Bike");
130+
}
125131
else if (myDevice->isAdvertisingService(HEARTSERVICE_UUID))
126132
{
127133
serviceUUID = HEARTSERVICE_UUID;
@@ -200,7 +206,7 @@ bool SpinBLEClient::connectToServer()
200206
}
201207

202208
if (pRemoteCharacteristic->canNotify())
203-
{
209+
{
204210
debugDirector("Found " + String(pRemoteCharacteristic->getUUID().toString().c_str()) + " on reconnect.");
205211
reconnectTries = MAX_RECONNECT_TRIES;
206212
//VV Is this really needed? Shouldn't it just carry over from the previous connection? VV
@@ -242,7 +248,6 @@ bool SpinBLEClient::connectToServer()
242248
pClient->connect(myDevice->getAddress()); // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private)
243249
debugDirector(" - Connected to server", true);
244250
debugDirector(" - RSSI " + pClient->getRssi(), true);
245-
246251
// Obtain a reference to the service we are after in the remote BLE server.
247252
BLERemoteService *pRemoteService = pClient->getService(serviceUUID);
248253
if (pRemoteService == nullptr)
@@ -313,7 +318,7 @@ bool SpinBLEClient::connectToServer()
313318

314319
void SpinBLEClient::MyClientCallback::onConnect(NimBLEClient *pClient)
315320
{
316-
//debugDirector("Connect Called"); This callback happens so early for us it's nearly useless.
321+
//debugDirector("Connect Called"); This callback happens so early for us it's nearly useless.
317322
}
318323

319324
void SpinBLEClient::MyClientCallback::onDisconnect(NimBLEClient *pclient)
@@ -340,7 +345,7 @@ void SpinBLEClient::MyClientCallback::onDisconnect(NimBLEClient *pclient)
340345
//spinBLEClient.myBLEDevices[i].connectedClientID = BLE_HS_CONN_HANDLE_NONE;
341346
debugDirector("Detected " + String(spinBLEClient.myBLEDevices[i].serviceUUID.toString().c_str()) + " Disconnect");
342347
spinBLEClient.myBLEDevices[i].doConnect = true;
343-
if ((spinBLEClient.myBLEDevices[i].charUUID == CYCLINGPOWERMEASUREMENT_UUID) || (spinBLEClient.myBLEDevices[i].charUUID == FITNESSMACHINEINDOORBIKEDATA_UUID) || (spinBLEClient.myBLEDevices[i].charUUID == FLYWHEEL_UART_RX_UUID))
348+
if ((spinBLEClient.myBLEDevices[i].charUUID == CYCLINGPOWERMEASUREMENT_UUID) || (spinBLEClient.myBLEDevices[i].charUUID == FITNESSMACHINEINDOORBIKEDATA_UUID) || (spinBLEClient.myBLEDevices[i].charUUID == FLYWHEEL_UART_RX_UUID) || (spinBLEClient.myBLEDevices[i].charUUID == ECHELON_SERVICE_UUID))
344349
{
345350

346351
debugDirector("Deregistered PM on Disconnect");
@@ -394,7 +399,7 @@ void SpinBLEClient::MyAdvertisedDeviceCallback::onResult(BLEAdvertisedDevice *ad
394399
{
395400
aDevName = "";
396401
}
397-
if ((advertisedDevice->haveServiceUUID()) && (advertisedDevice->isAdvertisingService(CYCLINGPOWERSERVICE_UUID) || advertisedDevice->isAdvertisingService(FLYWHEEL_UART_SERVICE_UUID) || advertisedDevice->isAdvertisingService(FITNESSMACHINESERVICE_UUID) || advertisedDevice->isAdvertisingService(HEARTSERVICE_UUID)))
402+
if ((advertisedDevice->haveServiceUUID()) && (advertisedDevice->isAdvertisingService(CYCLINGPOWERSERVICE_UUID) || advertisedDevice->isAdvertisingService(FLYWHEEL_UART_SERVICE_UUID) || advertisedDevice->isAdvertisingService(FITNESSMACHINESERVICE_UUID) || advertisedDevice->isAdvertisingService(HEARTSERVICE_UUID) || advertisedDevice->isAdvertisingService(ECHELON_DEVICE_UUID)))
398403
{
399404
//if ((aDevName == c_PM) || (advertisedDevice->getAddress().toString().c_str() == c_PM) || (aDevName == c_HR) || (advertisedDevice->getAddress().toString().c_str() == c_HR) || (String(c_PM) == ("any")) || (String(c_HR) == ("any")))
400405
//{ //notice the subtle difference vv getServiceUUID(int) returns the index of the service in the list or the 0 slot if not specified.
@@ -410,7 +415,8 @@ void SpinBLEClient::MyAdvertisedDeviceCallback::onResult(BLEAdvertisedDevice *ad
410415
{
411416
debugDirector("Skipping non-selected HRM |" + aDevName + "|" + String(userConfig.getconnectedHeartMonitor()));
412417
return;
413-
}else if (aDevName == String(userConfig.getconnectedHeartMonitor()))
418+
}
419+
else if (aDevName == String(userConfig.getconnectedHeartMonitor()))
414420
{
415421
debugDirector("HR String Matched " + aDevName);
416422
}
@@ -426,7 +432,8 @@ void SpinBLEClient::MyAdvertisedDeviceCallback::onResult(BLEAdvertisedDevice *ad
426432
{
427433
debugDirector("Skipping non-selected PM |" + aDevName + "|" + String(userConfig.getconnectedPowerMeter()));
428434
return;
429-
}else if (aDevName == String(userConfig.getconnectedPowerMeter()))
435+
}
436+
else if (aDevName == String(userConfig.getconnectedPowerMeter()))
430437
{
431438
debugDirector("PM String Matched " + aDevName);
432439
}
@@ -456,6 +463,7 @@ void SpinBLEClient::scanProcess()
456463
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallback());
457464
pBLEScan->setInterval(550);
458465
pBLEScan->setWindow(500);
466+
pBLEScan->setDuplicateFilter(true);
459467
pBLEScan->setActiveScan(true);
460468
BLEScanResults foundDevices = pBLEScan->start(10, false);
461469
// Load the scan into a Json String
@@ -468,7 +476,7 @@ void SpinBLEClient::scanProcess()
468476
for (int i = 0; i < count; i++)
469477
{
470478
BLEAdvertisedDevice d = foundDevices.getDevice(i);
471-
if (d.isAdvertisingService(CYCLINGPOWERSERVICE_UUID) || d.isAdvertisingService(HEARTSERVICE_UUID) || d.isAdvertisingService(FLYWHEEL_UART_SERVICE_UUID) || d.isAdvertisingService(FITNESSMACHINESERVICE_UUID))
479+
if (d.isAdvertisingService(CYCLINGPOWERSERVICE_UUID) || d.isAdvertisingService(HEARTSERVICE_UUID) || d.isAdvertisingService(FLYWHEEL_UART_SERVICE_UUID) || d.isAdvertisingService(FITNESSMACHINESERVICE_UUID) || d.isAdvertisingService(ECHELON_DEVICE_UUID))
472480
{
473481
device = "device " + String(i);
474482
devices[device]["address"] = d.getAddress().toString();
@@ -566,14 +574,29 @@ void SpinBLEClient::resetDevices()
566574

567575
void SpinBLEClient::postConnect(NimBLEClient *pClient)
568576
{
569-
for (size_t i = 0; i < NUM_BLE_DEVICES; i++)
577+
for (size_t i = 0; i < NUM_BLE_DEVICES; i++)
570578
{
571579
if (pClient->getPeerAddress() == this->myBLEDevices[i].peerAddress)
572580
{
573-
if ((this->myBLEDevices[i].charUUID == CYCLINGPOWERMEASUREMENT_UUID) || (this->myBLEDevices[i].charUUID == FITNESSMACHINEINDOORBIKEDATA_UUID) || (this->myBLEDevices[i].charUUID == FLYWHEEL_UART_RX_UUID))
581+
if ((this->myBLEDevices[i].charUUID == CYCLINGPOWERMEASUREMENT_UUID) || (this->myBLEDevices[i].charUUID == FITNESSMACHINEINDOORBIKEDATA_UUID) || (this->myBLEDevices[i].charUUID == FLYWHEEL_UART_RX_UUID)|| (this->myBLEDevices[i].charUUID == ECHELON_DATA_UUID))
574582
{
575583
this->connectedPM = true;
576584
debugDirector("Registered PM on Connect");
585+
if (this->myBLEDevices[i].charUUID == ECHELON_DATA_UUID)
586+
{
587+
NimBLERemoteCharacteristic *writeCharacteristic = pClient->getService(ECHELON_SERVICE_UUID)->getCharacteristic(ECHELON_WRITE_UUID);
588+
if (writeCharacteristic == nullptr)
589+
{
590+
debugDirector("Failed to find Echelon write characteristic UUID: ",false);
591+
debugDirector(String(ECHELON_WRITE_UUID.toString().c_str()));
592+
pClient->disconnect();
593+
return;
594+
}
595+
// Enable device notifications
596+
byte message[] = {0xF0, 0xB0, 0x01, 0x01, 0xA2};
597+
writeCharacteristic->writeValue(message, 5);
598+
debugDirector("Activated Echelon callbacks.");
599+
}
577600
//spinBLEClient.removeDuplicates(pclient);
578601
return;
579602
}
@@ -607,7 +630,3 @@ void SpinBLEAdvertisedDevice::print()
607630
strcat(logBufP, "|");
608631
debugDirector(String(logBuf));
609632
}
610-
611-
612-
613-

src/BLE_Common.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ void BLECommunications(void *pvParameters)
5656
{
5757
logBufP += sprintf(logBufP, "%02x ", pData[i]);
5858
}
59-
logBufP += sprintf(logBufP, "<- %s | %s", myAdvertisedDevice.serviceUUID.toString().c_str(), myAdvertisedDevice.charUUID.toString().c_str());
59+
logBufP += sprintf(logBufP, "<- %.8s | %.8s", myAdvertisedDevice.serviceUUID.toString().c_str(), myAdvertisedDevice.charUUID.toString().c_str());
6060

6161
std::shared_ptr<SensorData> sensorData = sensorDataFactory.getSensorData(pRemoteBLECharacteristic, pData, length);
6262

0 commit comments

Comments
 (0)