Move BMS files into Arduino sketch folder

This commit is contained in:
Nick Ward
2026-06-04 00:38:15 -06:00
parent 49ddb01a42
commit 6adddc358e
3 changed files with 1 additions and 1 deletions
+204
View File
@@ -0,0 +1,204 @@
#include "bms.h"
#include <Arduino.h>
#include <NimBLEDevice.h>
static const char* BMS_ADDRESS = "a5:c2:37:2c:05:dc";
static const char* BMS_SERVICE_UUID = "ff00";
static const char* BMS_NOTIFY_UUID = "ff01";
static const char* BMS_WRITE_UUID = "ff02";
static NimBLEClient* client = nullptr;
static NimBLERemoteCharacteristic* notifyChar = nullptr;
static NimBLERemoteCharacteristic* writeChar = nullptr;
static uint8_t responseBuffer[128];
static size_t responseLength = 0;
static bool responseReady = false;
static unsigned long lastReadAttempt = 0;
static const unsigned long READ_INTERVAL_MS = 5000;
BmsData bmsData;
static uint8_t JBD_STATUS_REQUEST[] = {
0xDD, 0xA5, 0x03, 0x00, 0xFF, 0xFD, 0x77
};
static uint16_t readU16(const uint8_t* data, int index) {
return ((uint16_t)data[index] << 8) | data[index + 1];
}
static int16_t readS16(const uint8_t* data, int index) {
return (int16_t)readU16(data, index);
}
static void resetResponseBuffer() {
responseLength = 0;
responseReady = false;
}
static void handleNotify(
NimBLERemoteCharacteristic* characteristic,
uint8_t* data,
size_t length,
bool isNotify
) {
if (responseLength + length > sizeof(responseBuffer)) {
resetResponseBuffer();
return;
}
memcpy(responseBuffer + responseLength, data, length);
responseLength += length;
if (responseLength > 0 && responseBuffer[responseLength - 1] == 0x77) {
responseReady = true;
}
}
static bool connectBms() {
if (client && client->isConnected()) {
return true;
}
Serial.println("BMS: Connecting...");
NimBLEAddress address(std::string(BMS_ADDRESS), BLE_ADDR_PUBLIC);
client = NimBLEDevice::createClient();
if (!client->connect(address)) {
Serial.println("BMS: Connect failed");
bmsData.connected = false;
return false;
}
NimBLERemoteService* service = client->getService(BMS_SERVICE_UUID);
if (!service) {
Serial.println("BMS: Service ff00 not found");
client->disconnect();
bmsData.connected = false;
return false;
}
notifyChar = service->getCharacteristic(BMS_NOTIFY_UUID);
writeChar = service->getCharacteristic(BMS_WRITE_UUID);
if (!notifyChar || !writeChar) {
Serial.println("BMS: Characteristics not found");
client->disconnect();
bmsData.connected = false;
return false;
}
if (!notifyChar->subscribe(true, handleNotify)) {
Serial.println("BMS: Notify subscribe failed");
client->disconnect();
bmsData.connected = false;
return false;
}
Serial.println("BMS: Connected");
bmsData.connected = true;
return true;
}
static bool parseBasicInfo() {
if (responseLength < 40) {
Serial.println("BMS: Response too short");
return false;
}
if (responseBuffer[0] != 0xDD || responseBuffer[1] != 0x03) {
Serial.println("BMS: Unexpected response header");
return false;
}
uint16_t voltageRaw = readU16(responseBuffer, 4);
int16_t currentRaw = readS16(responseBuffer, 6);
uint16_t remainingRaw = readU16(responseBuffer, 8);
uint16_t capacityRaw = readU16(responseBuffer, 10);
uint16_t cyclesRaw = readU16(responseBuffer, 12);
uint8_t socRaw = responseBuffer[23];
uint8_t mosTempAndCellOffset = 24;
uint8_t cellCount = responseBuffer[mosTempAndCellOffset + 1];
uint8_t ntcCount = responseBuffer[mosTempAndCellOffset + 2];
int tempOffset = mosTempAndCellOffset + 3;
float tempF = 0;
if (ntcCount > 0 && responseLength > (size_t)(tempOffset + 1)) {
uint16_t tempRaw = readU16(responseBuffer, tempOffset);
float tempC = (tempRaw - 2731) / 10.0;
tempF = tempC * 9.0 / 5.0 + 32.0;
}
bmsData.voltage = voltageRaw / 100.0;
bmsData.current = currentRaw / 100.0;
bmsData.remainingAh = remainingRaw / 100.0;
bmsData.capacityAh = capacityRaw / 100.0;
bmsData.cycleCount = cyclesRaw;
bmsData.soc = socRaw;
bmsData.cellCount = cellCount;
bmsData.ntcCount = ntcCount;
bmsData.temperatureF = tempF;
bmsData.valid = true;
Serial.print("BMS: SOC ");
Serial.print(bmsData.soc);
Serial.print("%, V ");
Serial.print(bmsData.voltage);
Serial.print(", A ");
Serial.print(bmsData.current);
Serial.print(", Ah ");
Serial.println(bmsData.remainingAh);
return true;
}
void initBms() {
NimBLEDevice::init("XterraESP32");
NimBLEDevice::setPower(ESP_PWR_LVL_P9);
resetResponseBuffer();
}
void updateBms() {
if (millis() - lastReadAttempt < READ_INTERVAL_MS) {
return;
}
lastReadAttempt = millis();
if (!connectBms()) {
return;
}
resetResponseBuffer();
bool ok = writeChar->writeValue(
JBD_STATUS_REQUEST,
sizeof(JBD_STATUS_REQUEST),
false
);
if (!ok) {
Serial.println("BMS: Write failed");
bmsData.connected = false;
return;
}
unsigned long start = millis();
while (!responseReady && millis() - start < 2000) {
delay(10);
}
if (!responseReady) {
Serial.println("BMS: Read timeout");
return;
}
parseBasicInfo();
}