Receiving SOC, SOH and Product name

This commit is contained in:
Marius Bezuidenhout 2021-07-12 17:47:04 +02:00
parent 024cc0b9b6
commit f14f86f6fe
3 changed files with 96 additions and 49 deletions

View File

@ -1765,7 +1765,8 @@ void GpioInit(void)
ValidSpiPinUsed(GPIO_ST7789_DC) || // ST7789 CS may be omitted so chk DC too ValidSpiPinUsed(GPIO_ST7789_DC) || // ST7789 CS may be omitted so chk DC too
ValidSpiPinUsed(GPIO_ST7789_CS) || ValidSpiPinUsed(GPIO_ST7789_CS) ||
(ValidSpiPinUsed(GPIO_SSD1331_CS) && ValidSpiPinUsed(GPIO_SSD1331_DC)) || (ValidSpiPinUsed(GPIO_SSD1331_CS) && ValidSpiPinUsed(GPIO_SSD1331_DC)) ||
ValidSpiPinUsed(GPIO_SDCARD_CS) ValidSpiPinUsed(GPIO_SDCARD_CS) ||
ValidSpiPinUsed(GPIO_MCP2515_CS)
); );
// If SPI_CS and/or SPI_DC is used they must be valid // If SPI_CS and/or SPI_DC is used they must be valid
TasmotaGlobal.spi_enabled = (valid_cs) ? SPI_MOSI_MISO : SPI_NONE; TasmotaGlobal.spi_enabled = (valid_cs) ? SPI_MOSI_MISO : SPI_NONE;

View File

@ -158,7 +158,7 @@ enum UserSelectablePins {
GPIO_MAX7219CLK, GPIO_MAX7219DIN, GPIO_MAX7219CS, // MAX7219 interface GPIO_MAX7219CLK, GPIO_MAX7219DIN, GPIO_MAX7219CS, // MAX7219 interface
GPIO_TFMINIPLUS_TX, GPIO_TFMINIPLUS_RX, // TFmini Plus ToF sensor GPIO_TFMINIPLUS_TX, GPIO_TFMINIPLUS_RX, // TFmini Plus ToF sensor
GPIO_ZEROCROSS, GPIO_ZEROCROSS,
GPIO_MCP2515_CS, // MCP2515 Chip Select GPIO_MCP2515_CS, // MCP2515 Chip Select
#ifdef ESP32 #ifdef ESP32
GPIO_HALLEFFECT, GPIO_HALLEFFECT,
GPIO_EPD_DATA, // Base connection EPD driver GPIO_EPD_DATA, // Base connection EPD driver
@ -462,7 +462,7 @@ const uint16_t kGpioNiceList[] PROGMEM = {
AGPIO(GPIO_SDCARD_CS), AGPIO(GPIO_SDCARD_CS),
#endif // USE_SDCARD #endif // USE_SDCARD
#ifdef USE_MCP2515 #ifdef USE_MCP2515
AGPIO(GPIO_MCP2515_CS) AGPIO(GPIO_MCP2515_CS),
#endif // USE_MCP2515 #endif // USE_MCP2515
#endif // USE_SPI #endif // USE_SPI

View File

@ -47,8 +47,8 @@
#define MCP2515_CLOCK MCP_8MHZ #define MCP2515_CLOCK MCP_8MHZ
#endif #endif
#ifndef MCP2515_MAX_MSG #ifndef MCP2515_MAX_FRAMES
#define MCP2515_MAX_MSG 14 #define MCP2515_MAX_FRAMES 14
#endif #endif
#ifndef MCP2515_BMS_CLIENT #ifndef MCP2515_BMS_CLIENT
@ -60,11 +60,11 @@
#endif // MCP2515_BMS_CLIENT #endif // MCP2515_BMS_CLIENT
#ifdef MCP2515_BMS_CLIENT #ifdef MCP2515_BMS_CLIENT
struct BMS_Struct { struct BMS_Struct {
uint16_t stateOfCharge; uint16_t stateOfCharge;
uint16_t stateOfHealth; uint16_t stateOfHealth;
float battVoltage; float battVoltage;
float battMilliAmp; float battAmp = 0;
float battTemp; float battTemp;
char name[17]; char name[17];
} bms; } bms;
@ -72,66 +72,110 @@
int8_t mcp2515_init_status = 1; int8_t mcp2515_init_status = 1;
struct can_frame canMsg; struct can_frame canFrame;
MCP2515 mcp2515; MCP2515 *mcp2515 = nullptr;
char c2h(char c)
{
return "0123456789ABCDEF"[0x0F & (unsigned char)c];
}
void MCP2515_Init(void) { void MCP2515_Init(void) {
mcp2515 = new MCP2515(5); mcp2515 = new MCP2515(5);
if (MCP2515::ERROR_OK != mcp2515.reset()) { if (MCP2515::ERROR_OK != mcp2515->reset()) {
AddLog(LOG_LEVEL_ERROR, PSTR("MCP2515: Failed to reset module")); AddLog(LOG_LEVEL_ERROR, PSTR("MCP2515: Failed to reset module"));
mcp2515_init_status = 0; mcp2515_init_status = 0;
} }
if (MCP2515::ERROR_OK != mcp2515.setBitrate(CAN_500KBPS, MCP_8MHZ)) { if (MCP2515::ERROR_OK != mcp2515->setBitrate(MCP2515_BITRATE, MCP2515_CLOCK)) {
AddLog(LOG_LEVEL_ERROR, PSTR("MCP2515: Failed to set module bitrate"); AddLog(LOG_LEVEL_ERROR, PSTR("MCP2515: Failed to set module bitrate"));
mcp2515_init_status = 0; mcp2515_init_status = 0;
} }
if (mcp2515_init_status && MCP2515::ERROR_OK != mcp2515.setNormalMode()) { if (mcp2515_init_status && MCP2515::ERROR_OK != mcp2515->setNormalMode()) {
AddLog(LOG_LEVEL_ERROR, PSTR("MCP2515: Failed to set normal mode"); AddLog(LOG_LEVEL_ERROR, PSTR("MCP2515: Failed to set normal mode"));
mcp2515_init_status = 0; mcp2515_init_status = 0;
} }
} }
void MCP2515_Read() { void MCP2515_Read() {
uint8_t nCounter = 0; uint8_t nCounter = 0;
while (mcp2515.checkReceive() && nCounter <= MCP2515_MAX_MSG) { bool checkRcv;
nCounter++; if(mcp2515_init_status) {
if (mcp2515.readMessage(&canMsg) == MCP2515::ERROR_OK) {
checkRcv = mcp2515->checkReceive();
while (checkRcv && nCounter <= MCP2515_MAX_FRAMES) {
mcp2515->checkReceive();
nCounter++;
if (mcp2515->readMessage(&canFrame) == MCP2515::ERROR_OK) {
#ifdef MCP2515_BMS_CLIENT #ifdef MCP2515_BMS_CLIENT
#ifdef MCP2515_BMS_FREEDWON #ifdef MCP2515_BMS_FREEDWON
switch(canMsg.can_id) { switch(canFrame.can_id) {
case 0x355: // Charge/Discharge parameters
bms.stateOfCharge = canMsg.data[1] << 8 + canMsg.data[0]; case 0x351:
bms.stateOfHealth = canMsg.data[3] << 8 + canMsg.data[2]; break;
break; // State of Charge/Health
case 0x356: case 0x355:
bms.battVoltage = (canMsg.data[1] << 8 + canMsg.data[0])/100; if(6 >= canFrame.can_dlc) {
bms.battMilliAmp = (canMsg.data[3] << 8 + canMsg.data[2])*100; bms.stateOfCharge = (canFrame.data[1] << 8) + canFrame.data[0];
bms.battTemp = ConvertTemp((canMsg.data[5] << 8 + canMsg.data[4])/10); // Convert to fahrenheit if SetOpion8 is set bms.stateOfHealth = (canFrame.data[3] << 8) + canFrame.data[2];
break; } else {
case 0x370: AddLog(LOG_LEVEL_DEBUG, PSTR("MCP2515: Unexpected length (%d) for ID 0x355"), canFrame.can_dlc);
case 0x371: }
for(int i = 0; i < canMsg.can_dlc; i++) { break;
bms.name[i + (8 * canMsg.can_id & 0x1)] = canMsg.data[i]; // If can_id is 0x371 then fill from byte 8 onwards // Voltage/Current/Temperature
} case 0x356:
bms.name[16] = 0; // Ensure that name is null terminated if(6 >= canFrame.can_dlc) {
break; bms.battVoltage = (float)((canFrame.data[1] << 8) + canFrame.data[0])/100;
default: bms.battAmp = (float)((canFrame.data[3] << 8) + canFrame.data[2])/10;
String canMsg; bms.battTemp = ConvertTemp((float)((canFrame.data[5] << 8) + canFrame.data[4])/10); // Convert to fahrenheit if SetOpion8 is set
for(int i = 0; i < canMsg.can_dlc; i++) { } else {
canMsg += String(canMsg.data[i], HEX); AddLog(LOG_LEVEL_DEBUG, PSTR("MCP2515: Unexpected length (%d) for ID 0x356"), canFrame.can_dlc);
} }
AddLog(LOG_LEVEL_DEBUG, PSTR("MCP2515: Received message 0x%s from ID 0x%X", canMsg, canMsg.can_id); break;
break; // Battery / BMS name
} case 0x370:
case 0x371:
for(int i = 0; i < canFrame.can_dlc; i++) {
uint8_t nameStrPos = i + ((canFrame.can_id & 0x1) * 8); // If can_id is 0x371 then fill from byte 8 onwards
bms.name[nameStrPos] = canFrame.data[i];
}
bms.name[16] = 0; // Ensure that name is null terminated
break;
// Modules status
case 0x372:
// Min. cell voltage id string
case 0x374:
// Min. cell temperature id string
case 0x376:
// Installed capacity
case 0x379:
// Serial number
case 0x380:
case 0x381:
break;
default:
char canMsg[17];
canMsg[0] = 0;
for(int i = 0; i < canFrame.can_dlc; i++) {
canMsg[i*2] = c2h(canFrame.data[i]>>4);
canMsg[i*2+1] = c2h(canFrame.data[i]);
}
if(canFrame.can_dlc > 0) {
canMsg[(canFrame.can_dlc - 1) * 2 + 2] = 0;
}
AddLog(LOG_LEVEL_DEBUG, PSTR("MCP2515: Received message 0x%s from ID 0x%X"), canMsg, (uint32_t)canFrame.can_id);
break;
}
#endif // MCP2515_BMS_FREEDWON #endif // MCP2515_BMS_FREEDWON
#endif // MCP2515_BMS_CLIENT #endif // MCP2515_BMS_CLIENT
} else if(mcp2515.checkError()) { } else if(mcp2515->checkError()) {
uint8_t errFlags = mcp2515.getErrorFlags(); uint8_t errFlags = mcp2515->getErrorFlags();
mcp2515.clearRXnOVRFlags(); mcp2515->clearRXnOVRFlags();
AddLog(LOG_LEVEL_DEBUG, PSTR("MCP2515: Received error %d", errFlags); AddLog(LOG_LEVEL_DEBUG, PSTR("MCP2515: Received error %d"), errFlags);
break; break;
}
} }
} }
} }
@ -145,10 +189,12 @@ void MCP2515_Show(bool Json) {
#ifdef USE_WEBSERVER #ifdef USE_WEBSERVER
} else { } else {
#ifdef MCP2515_BMS_CLIENT #ifdef MCP2515_BMS_CLIENT
char ampStr[6];
dtostrf(bms.battAmp, 5, 1, ampStr);
WSContentSend_PD(HTTP_SNS_SOC, bms.name, bms.stateOfCharge); WSContentSend_PD(HTTP_SNS_SOC, bms.name, bms.stateOfCharge);
WSContentSend_PD(HTTP_SNS_SOH, bms.name, bms.stateOfHealth); WSContentSend_PD(HTTP_SNS_SOH, bms.name, bms.stateOfHealth);
WSContentSend_Voltage(bms.name, bms.battVoltage); WSContentSend_Voltage(bms.name, bms.battVoltage);
WSContentSend_CurrentMA(bms.name, bms.battMilliAmp); WSContentSend_PD(HTTP_SNS_CURRENT, ampStr);
WSContentSend_Temp(bms.name, bms.battTemp); WSContentSend_Temp(bms.name, bms.battTemp);
#endif // MCP2515_BMS_CLIENT #endif // MCP2515_BMS_CLIENT
#endif // USE_WEBSERVER #endif // USE_WEBSERVER
@ -168,7 +214,7 @@ bool Xsns89(uint8_t function)
case FUNC_INIT: case FUNC_INIT:
MCP2515_Init(); MCP2515_Init();
break; break;
case FUNC_EVERY_SECOND: case FUNC_EVERY_50_MSECOND:
MCP2515_Read(); MCP2515_Read();
break; break;
case FUNC_JSON_APPEND: case FUNC_JSON_APPEND: