Skip to content

Commit

Permalink
Merge pull request #140 from doudar/Echelon
Browse files Browse the repository at this point in the history
Echelon
  • Loading branch information
doudar authored Mar 20, 2021
2 parents 2389e8d + 7a57884 commit 64df14c
Show file tree
Hide file tree
Showing 17 changed files with 217 additions and 18 deletions.
13 changes: 10 additions & 3 deletions include/BLE_Common.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,16 @@
#define FITNESSMACHINEPOWERRANGE_UUID BLEUUID((uint16_t)0x2AD8)

// GATT service/characteristic UUIDs for Flywheel Bike from ptx2/gymnasticon/
#define FLYWHEEL_UART_SERVICE_UUID BLEUUID((uint16_t)0xCA9E)
#define FLYWHEEL_UART_RX_UUID BLEUUID((uint16_t)0xCA9E)
#define FLYWHEEL_UART_TX_UUID BLEUUID((uint16_t)0xCA9E)
#define FLYWHEEL_UART_SERVICE_UUID BLEUUID("6e400001b5a3f393e0a9e50e24dcca9e")
#define FLYWHEEL_UART_RX_UUID BLEUUID("6e400002b5a3f393e0a9e50e24dcca9e")
#define FLYWHEEL_UART_TX_UUID BLEUUID("6e400003b5a3f393e0a9e50e24dcca9e")

// The Echelon Services
#define ECHELON_DEVICE_UUID BLEUUID("0bf669f0-45f2-11e7-9598-0800200c9a66")
#define ECHELON_SERVICE_UUID BLEUUID("0bf669f1-45f2-11e7-9598-0800200c9a66")
#define ECHELON_WRITE_UUID BLEUUID("0bf669f2-45f2-11e7-9598-0800200c9a66")
#define ECHELON_DATA_UUID BLEUUID("0bf669f4-45f2-11e7-9598-0800200c9a66")


// macros to convert different types of bytes into int The naming here sucks and should be fixed.
#define bytes_to_s16(MSB, LSB) (((signed int)((signed char)MSB))) << 8 | (((signed char)LSB))
Expand Down
7 changes: 7 additions & 0 deletions include/sensors/CyclePowerData.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
// SmartSpin2K code
// 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.
// BLE code based on examples from https://github.com/nkolban
// Copyright 2020 Anthony Doud & Joel Baranick
// This work is licensed under the GNU General Public License v2
// Prototype hardware build from plans in the SmartSpin2k repository are licensed under Cern Open Hardware Licence version 2 Permissive

#pragma once

#include <Arduino.h>
Expand Down
31 changes: 31 additions & 0 deletions include/sensors/EchelonData.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SmartSpin2K code
// 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.
// BLE code based on examples from https://github.com/nkolban
// Copyright 2020 Anthony Doud & Joel Baranick
// This work is licensed under the GNU General Public License v2
// Prototype hardware build from plans in the SmartSpin2k repository are licensed under Cern Open Hardware Licence version 2 Permissive

#pragma once

#include "SensorData.h"

class EchelonData : public SensorData
{
public:
EchelonData() : SensorData("ECH"), cadence(NAN), resistance(INT_MIN), power(INT_MIN) {};

bool hasHeartRate();
bool hasCadence();
bool hasPower();
bool hasSpeed();
int getHeartRate();
float getCadence();
int getPower();
float getSpeed();
void decode(uint8_t *data, size_t length);

private:
float cadence;
int resistance;
int power;
};
7 changes: 7 additions & 0 deletions include/sensors/FitnessMachineIndoorBikeData.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
// SmartSpin2K code
// 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.
// BLE code based on examples from https://github.com/nkolban
// Copyright 2020 Anthony Doud & Joel Baranick
// This work is licensed under the GNU General Public License v2
// Prototype hardware build from plans in the SmartSpin2k repository are licensed under Cern Open Hardware Licence version 2 Permissive

#pragma once

#include <Arduino.h>
Expand Down
7 changes: 7 additions & 0 deletions include/sensors/FlywheelData.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
// SmartSpin2K code
// 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.
// BLE code based on examples from https://github.com/nkolban
// Copyright 2020 Anthony Doud & Joel Baranick
// This work is licensed under the GNU General Public License v2
// Prototype hardware build from plans in the SmartSpin2k repository are licensed under Cern Open Hardware Licence version 2 Permissive

#pragma once

#include "SensorData.h"
Expand Down
7 changes: 7 additions & 0 deletions include/sensors/HeartRateData.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
// SmartSpin2K code
// 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.
// BLE code based on examples from https://github.com/nkolban
// Copyright 2020 Anthony Doud & Joel Baranick
// This work is licensed under the GNU General Public License v2
// Prototype hardware build from plans in the SmartSpin2k repository are licensed under Cern Open Hardware Licence version 2 Permissive

#pragma once

#include "SensorData.h"
Expand Down
7 changes: 7 additions & 0 deletions include/sensors/SensorData.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
// SmartSpin2K code
// 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.
// BLE code based on examples from https://github.com/nkolban
// Copyright 2020 Anthony Doud & Joel Baranick
// This work is licensed under the GNU General Public License v2
// Prototype hardware build from plans in the SmartSpin2k repository are licensed under Cern Open Hardware Licence version 2 Permissive

#pragma once

#include <Arduino.h>
Expand Down
8 changes: 8 additions & 0 deletions include/sensors/SensorDataFactory.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
// SmartSpin2K code
// 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.
// BLE code based on examples from https://github.com/nkolban
// Copyright 2020 Anthony Doud & Joel Baranick
// This work is licensed under the GNU General Public License v2
// Prototype hardware build from plans in the SmartSpin2k repository are licensed under Cern Open Hardware Licence version 2 Permissive

#pragma once

#include <memory>
Expand All @@ -8,6 +15,7 @@
#include "FlywheelData.h"
#include "FitnessMachineIndoorBikeData.h"
#include "HeartRateData.h"
#include "EchelonData.h"

class SensorDataFactory
{
Expand Down
47 changes: 33 additions & 14 deletions src/BLE_Client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@ bool SpinBLEClient::connectToServer()
charUUID = FITNESSMACHINEINDOORBIKEDATA_UUID;
debugDirector("trying to connect to Fitness machine service");
}
else if (myDevice->isAdvertisingService(ECHELON_DEVICE_UUID))
{
serviceUUID = ECHELON_SERVICE_UUID;
charUUID = ECHELON_DATA_UUID;
debugDirector("Trying to connect to Echelon Bike");
}
else if (myDevice->isAdvertisingService(HEARTSERVICE_UUID))
{
serviceUUID = HEARTSERVICE_UUID;
Expand Down Expand Up @@ -200,7 +206,7 @@ bool SpinBLEClient::connectToServer()
}

if (pRemoteCharacteristic->canNotify())
{
{
debugDirector("Found " + String(pRemoteCharacteristic->getUUID().toString().c_str()) + " on reconnect.");
reconnectTries = MAX_RECONNECT_TRIES;
//VV Is this really needed? Shouldn't it just carry over from the previous connection? VV
Expand Down Expand Up @@ -242,7 +248,6 @@ bool SpinBLEClient::connectToServer()
pClient->connect(myDevice->getAddress()); // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private)
debugDirector(" - Connected to server", true);
debugDirector(" - RSSI " + pClient->getRssi(), true);

// Obtain a reference to the service we are after in the remote BLE server.
BLERemoteService *pRemoteService = pClient->getService(serviceUUID);
if (pRemoteService == nullptr)
Expand Down Expand Up @@ -313,7 +318,7 @@ bool SpinBLEClient::connectToServer()

void SpinBLEClient::MyClientCallback::onConnect(NimBLEClient *pClient)
{
//debugDirector("Connect Called"); This callback happens so early for us it's nearly useless.
//debugDirector("Connect Called"); This callback happens so early for us it's nearly useless.
}

void SpinBLEClient::MyClientCallback::onDisconnect(NimBLEClient *pclient)
Expand All @@ -340,7 +345,7 @@ void SpinBLEClient::MyClientCallback::onDisconnect(NimBLEClient *pclient)
//spinBLEClient.myBLEDevices[i].connectedClientID = BLE_HS_CONN_HANDLE_NONE;
debugDirector("Detected " + String(spinBLEClient.myBLEDevices[i].serviceUUID.toString().c_str()) + " Disconnect");
spinBLEClient.myBLEDevices[i].doConnect = true;
if ((spinBLEClient.myBLEDevices[i].charUUID == CYCLINGPOWERMEASUREMENT_UUID) || (spinBLEClient.myBLEDevices[i].charUUID == FITNESSMACHINEINDOORBIKEDATA_UUID) || (spinBLEClient.myBLEDevices[i].charUUID == FLYWHEEL_UART_RX_UUID))
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))
{

debugDirector("Deregistered PM on Disconnect");
Expand Down Expand Up @@ -394,7 +399,7 @@ void SpinBLEClient::MyAdvertisedDeviceCallback::onResult(BLEAdvertisedDevice *ad
{
aDevName = "";
}
if ((advertisedDevice->haveServiceUUID()) && (advertisedDevice->isAdvertisingService(CYCLINGPOWERSERVICE_UUID) || advertisedDevice->isAdvertisingService(FLYWHEEL_UART_SERVICE_UUID) || advertisedDevice->isAdvertisingService(FITNESSMACHINESERVICE_UUID) || advertisedDevice->isAdvertisingService(HEARTSERVICE_UUID)))
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)))
{
//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")))
//{ //notice the subtle difference vv getServiceUUID(int) returns the index of the service in the list or the 0 slot if not specified.
Expand All @@ -410,7 +415,8 @@ void SpinBLEClient::MyAdvertisedDeviceCallback::onResult(BLEAdvertisedDevice *ad
{
debugDirector("Skipping non-selected HRM |" + aDevName + "|" + String(userConfig.getconnectedHeartMonitor()));
return;
}else if (aDevName == String(userConfig.getconnectedHeartMonitor()))
}
else if (aDevName == String(userConfig.getconnectedHeartMonitor()))
{
debugDirector("HR String Matched " + aDevName);
}
Expand All @@ -426,7 +432,8 @@ void SpinBLEClient::MyAdvertisedDeviceCallback::onResult(BLEAdvertisedDevice *ad
{
debugDirector("Skipping non-selected PM |" + aDevName + "|" + String(userConfig.getconnectedPowerMeter()));
return;
}else if (aDevName == String(userConfig.getconnectedPowerMeter()))
}
else if (aDevName == String(userConfig.getconnectedPowerMeter()))
{
debugDirector("PM String Matched " + aDevName);
}
Expand Down Expand Up @@ -456,6 +463,7 @@ void SpinBLEClient::scanProcess()
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallback());
pBLEScan->setInterval(550);
pBLEScan->setWindow(500);
pBLEScan->setDuplicateFilter(true);
pBLEScan->setActiveScan(true);
BLEScanResults foundDevices = pBLEScan->start(10, false);
// Load the scan into a Json String
Expand All @@ -468,7 +476,7 @@ void SpinBLEClient::scanProcess()
for (int i = 0; i < count; i++)
{
BLEAdvertisedDevice d = foundDevices.getDevice(i);
if (d.isAdvertisingService(CYCLINGPOWERSERVICE_UUID) || d.isAdvertisingService(HEARTSERVICE_UUID) || d.isAdvertisingService(FLYWHEEL_UART_SERVICE_UUID) || d.isAdvertisingService(FITNESSMACHINESERVICE_UUID))
if (d.isAdvertisingService(CYCLINGPOWERSERVICE_UUID) || d.isAdvertisingService(HEARTSERVICE_UUID) || d.isAdvertisingService(FLYWHEEL_UART_SERVICE_UUID) || d.isAdvertisingService(FITNESSMACHINESERVICE_UUID) || d.isAdvertisingService(ECHELON_DEVICE_UUID))
{
device = "device " + String(i);
devices[device]["address"] = d.getAddress().toString();
Expand Down Expand Up @@ -566,14 +574,29 @@ void SpinBLEClient::resetDevices()

void SpinBLEClient::postConnect(NimBLEClient *pClient)
{
for (size_t i = 0; i < NUM_BLE_DEVICES; i++)
for (size_t i = 0; i < NUM_BLE_DEVICES; i++)
{
if (pClient->getPeerAddress() == this->myBLEDevices[i].peerAddress)
{
if ((this->myBLEDevices[i].charUUID == CYCLINGPOWERMEASUREMENT_UUID) || (this->myBLEDevices[i].charUUID == FITNESSMACHINEINDOORBIKEDATA_UUID) || (this->myBLEDevices[i].charUUID == FLYWHEEL_UART_RX_UUID))
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))
{
this->connectedPM = true;
debugDirector("Registered PM on Connect");
if (this->myBLEDevices[i].charUUID == ECHELON_DATA_UUID)
{
NimBLERemoteCharacteristic *writeCharacteristic = pClient->getService(ECHELON_SERVICE_UUID)->getCharacteristic(ECHELON_WRITE_UUID);
if (writeCharacteristic == nullptr)
{
debugDirector("Failed to find Echelon write characteristic UUID: ",false);
debugDirector(String(ECHELON_WRITE_UUID.toString().c_str()));
pClient->disconnect();
return;
}
// Enable device notifications
byte message[] = {0xF0, 0xB0, 0x01, 0x01, 0xA2};
writeCharacteristic->writeValue(message, 5);
debugDirector("Activated Echelon callbacks.");
}
//spinBLEClient.removeDuplicates(pclient);
return;
}
Expand Down Expand Up @@ -607,7 +630,3 @@ void SpinBLEAdvertisedDevice::print()
strcat(logBufP, "|");
debugDirector(String(logBuf));
}




2 changes: 1 addition & 1 deletion src/BLE_Common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ void BLECommunications(void *pvParameters)
{
logBufP += sprintf(logBufP, "%02x ", pData[i]);
}
logBufP += sprintf(logBufP, "<- %s | %s", myAdvertisedDevice.serviceUUID.toString().c_str(), myAdvertisedDevice.charUUID.toString().c_str());
logBufP += sprintf(logBufP, "<- %.8s | %.8s", myAdvertisedDevice.serviceUUID.toString().c_str(), myAdvertisedDevice.charUUID.toString().c_str());

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

Expand Down
7 changes: 7 additions & 0 deletions src/sensors/CyclePowerData.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
// SmartSpin2K code
// 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.
// BLE code based on examples from https://github.com/nkolban
// Copyright 2020 Anthony Doud & Joel Baranick
// This work is licensed under the GNU General Public License v2
// Prototype hardware build from plans in the SmartSpin2k repository are licensed under Cern Open Hardware Licence version 2 Permissive

#include "BLE_Common.h"
#include "sensors/CyclePowerData.h"

Expand Down
52 changes: 52 additions & 0 deletions src/sensors/EchelonData.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SmartSpin2K code
// 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.
// BLE code based on examples from https://github.com/nkolban
// Copyright 2020 Anthony Doud & Joel Baranick
// This work is licensed under the GNU General Public License v2
// Prototype hardware build from plans in the SmartSpin2k repository are licensed under Cern Open Hardware Licence version 2 Permissive
// Echelon Decoding model based on https://github.com/snowzach/echbt

#include "BLE_Common.h"
#include "sensors/EchelonData.h"

bool EchelonData::hasHeartRate() { return false; }

bool EchelonData::hasCadence() { return !isnan(this->cadence); }

bool EchelonData::hasPower() { return this->cadence >= 0 && this->resistance >= 0; }

bool EchelonData::hasSpeed() { return false; }

int EchelonData::getHeartRate() { return INT_MIN; }

float EchelonData::getCadence() { return this->cadence; };

int EchelonData::getPower() { return this->power; };

float EchelonData::getSpeed() { return NAN; }

void EchelonData::decode(uint8_t *data, size_t length)
{
switch (data[1])
{
// Cadence notification
case 0xD1:
this->cadence = int((data[9] << 8) + data[10]);
break;
// Resistance notification
case 0xD2:
this->resistance = int(data[3]);
break;
}
if (isnan(this->cadence) || this->resistance < 0) {
return;
}
if (this->cadence == 0 || this->resistance == 0)
{
power = 0;
}
else
{
power = pow(1.090112, resistance) * pow(1.015343, cadence) * 7.228958;
}
}
7 changes: 7 additions & 0 deletions src/sensors/FitnessMachineIndoorBikeData.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
// SmartSpin2K code
// 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.
// BLE code based on examples from https://github.com/nkolban
// Copyright 2020 Anthony Doud & Joel Baranick
// This work is licensed under the GNU General Public License v2
// Prototype hardware build from plans in the SmartSpin2k repository are licensed under Cern Open Hardware Licence version 2 Permissive

#include "BLE_Common.h"
#include "sensors/FitnessMachineIndoorBikeData.h"

Expand Down
7 changes: 7 additions & 0 deletions src/sensors/FlywheelData.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
// SmartSpin2K code
// 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.
// BLE code based on examples from https://github.com/nkolban
// Copyright 2020 Anthony Doud & Joel Baranick
// This work is licensed under the GNU General Public License v2
// Prototype hardware build from plans in the SmartSpin2k repository are licensed under Cern Open Hardware Licence version 2 Permissive

#include "BLE_Common.h"
#include "sensors/FlywheelData.h"

Expand Down
7 changes: 7 additions & 0 deletions src/sensors/HeartRateData.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
// SmartSpin2K code
// 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.
// BLE code based on examples from https://github.com/nkolban
// Copyright 2020 Anthony Doud & Joel Baranick
// This work is licensed under the GNU General Public License v2
// Prototype hardware build from plans in the SmartSpin2k repository are licensed under Cern Open Hardware Licence version 2 Permissive

#include "sensors/HeartRateData.h"

bool HeartRateData::hasHeartRate() { return true; }
Expand Down
7 changes: 7 additions & 0 deletions src/sensors/SensorData.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
// SmartSpin2K code
// 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.
// BLE code based on examples from https://github.com/nkolban
// Copyright 2020 Anthony Doud & Joel Baranick
// This work is licensed under the GNU General Public License v2
// Prototype hardware build from plans in the SmartSpin2k repository are licensed under Cern Open Hardware Licence version 2 Permissive

#include "sensors/SensorData.h"

String SensorData::getId() { return this->id; }
Loading

0 comments on commit 64df14c

Please sign in to comment.