First working version

This commit is contained in:
Marius Bezuidenhout 2021-07-13 16:49:40 +02:00
parent f14f86f6fe
commit ad8b557bec
1 changed files with 59 additions and 19 deletions

View File

@ -51,6 +51,14 @@
#define MCP2515_MAX_FRAMES 14 #define MCP2515_MAX_FRAMES 14
#endif #endif
#ifndef CAN_KEEP_ALIVE_SECS
#define CAN_KEEP_ALIVE_SECS 300
#endif
#ifndef MCP2515_TIMEOUT
#define MCP2515_TIMEOUT 10
#endif
#ifndef MCP2515_BMS_CLIENT #ifndef MCP2515_BMS_CLIENT
#define MCP2515_BMS_CLIENT #define MCP2515_BMS_CLIENT
// Look for Freedom Won BMS data in CAN message // Look for Freedom Won BMS data in CAN message
@ -63,15 +71,16 @@
struct BMS_Struct { struct BMS_Struct {
uint16_t stateOfCharge; uint16_t stateOfCharge;
uint16_t stateOfHealth; uint16_t stateOfHealth;
float battVoltage; uint16_t battVoltage; // Div 100
float battAmp = 0; int16_t battAmp; // Div 10
float battTemp; int16_t battTemp; // Div 10
char name[17]; char name[17];
} bms; } bms;
#endif #endif
int8_t mcp2515_init_status = 1; int8_t mcp2515_init_status = 1;
uint32_t lastFrameRecv = 0;
struct can_frame canFrame; struct can_frame canFrame;
MCP2515 *mcp2515 = nullptr; MCP2515 *mcp2515 = nullptr;
@ -96,12 +105,17 @@ void MCP2515_Init(void) {
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;
} }
#ifdef MCP2515_BMS_FREEDWON
// TODO: Filter CAN bus messages
//mcp2515->setFilterMask();
//mcp2515->setFilter();
#endif
} }
void MCP2515_Read() { void MCP2515_Read() {
uint8_t nCounter = 0; uint8_t nCounter = 0;
bool checkRcv; bool checkRcv;
if(mcp2515_init_status) { if (mcp2515_init_status) {
checkRcv = mcp2515->checkReceive(); checkRcv = mcp2515->checkReceive();
@ -109,31 +123,37 @@ void MCP2515_Read() {
mcp2515->checkReceive(); mcp2515->checkReceive();
nCounter++; nCounter++;
if (mcp2515->readMessage(&canFrame) == MCP2515::ERROR_OK) { if (mcp2515->readMessage(&canFrame) == MCP2515::ERROR_OK) {
lastFrameRecv = TasmotaGlobal.uptime;
#ifdef MCP2515_BMS_CLIENT #ifdef MCP2515_BMS_CLIENT
#ifdef MCP2515_BMS_FREEDWON #ifdef MCP2515_BMS_FREEDWON
switch(canFrame.can_id) { switch (canFrame.can_id) {
// Charge/Discharge parameters // Charge/Discharge parameters
case 0x351: case 0x351:
break; break;
// State of Charge/Health // State of Charge/Health
case 0x355: case 0x355:
if(6 >= canFrame.can_dlc) { if (6 >= canFrame.can_dlc) {
bms.stateOfCharge = (canFrame.data[1] << 8) + canFrame.data[0]; bms.stateOfCharge = (canFrame.data[1] << 8) | canFrame.data[0];
bms.stateOfHealth = (canFrame.data[3] << 8) + canFrame.data[2]; bms.stateOfHealth = (canFrame.data[3] << 8) | canFrame.data[2];
} else { } else {
AddLog(LOG_LEVEL_DEBUG, PSTR("MCP2515: Unexpected length (%d) for ID 0x355"), canFrame.can_dlc); AddLog(LOG_LEVEL_DEBUG, PSTR("MCP2515: Unexpected length (%d) for ID 0x355"), canFrame.can_dlc);
} }
break; break;
// Voltage/Current/Temperature // Voltage/Current/Temperature
case 0x356: case 0x356:
if(6 >= canFrame.can_dlc) { if (6 >= canFrame.can_dlc) {
bms.battVoltage = (float)((canFrame.data[1] << 8) + canFrame.data[0])/100; bms.battVoltage = (canFrame.data[1] << 8) | canFrame.data[0];
bms.battAmp = (float)((canFrame.data[3] << 8) + canFrame.data[2])/10; bms.battAmp = (canFrame.data[3] << 8) | canFrame.data[2];
bms.battTemp = ConvertTemp((float)((canFrame.data[5] << 8) + canFrame.data[4])/10); // Convert to fahrenheit if SetOpion8 is set bms.battTemp = (canFrame.data[5] << 8) | canFrame.data[4]; // Convert to fahrenheit if SetOpion8 is set
} else { } else {
AddLog(LOG_LEVEL_DEBUG, PSTR("MCP2515: Unexpected length (%d) for ID 0x356"), canFrame.can_dlc); AddLog(LOG_LEVEL_DEBUG, PSTR("MCP2515: Unexpected length (%d) for ID 0x356"), canFrame.can_dlc);
} }
break; break;
// Manufacturer name
case 0x35E:
// Battery Model / Firmware version
case 0x35F:
break;
// Battery / BMS name // Battery / BMS name
case 0x370: case 0x370:
case 0x371: case 0x371:
@ -145,10 +165,16 @@ void MCP2515_Read() {
break; break;
// Modules status // Modules status
case 0x372: case 0x372:
// Min/Max cell voltage/temperature
case 0x373:
// Min. cell voltage id string // Min. cell voltage id string
case 0x374: case 0x374:
// Max. cell voltage id string
case 0x375:
// Min. cell temperature id string // Min. cell temperature id string
case 0x376: case 0x376:
// Max. cell temperature id string
case 0x377:
// Installed capacity // Installed capacity
case 0x379: case 0x379:
// Serial number // Serial number
@ -162,7 +188,7 @@ void MCP2515_Read() {
canMsg[i*2] = c2h(canFrame.data[i]>>4); canMsg[i*2] = c2h(canFrame.data[i]>>4);
canMsg[i*2+1] = c2h(canFrame.data[i]); canMsg[i*2+1] = c2h(canFrame.data[i]);
} }
if(canFrame.can_dlc > 0) { if (canFrame.can_dlc > 0) {
canMsg[(canFrame.can_dlc - 1) * 2 + 2] = 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); AddLog(LOG_LEVEL_DEBUG, PSTR("MCP2515: Received message 0x%s from ID 0x%X"), canMsg, (uint32_t)canFrame.can_id);
@ -170,32 +196,46 @@ void MCP2515_Read() {
} }
#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;
} }
} }
#ifdef MCP2515_BMS_FREEDWON
if (!(TasmotaGlobal.uptime%CAN_KEEP_ALIVE_SECS) && TasmotaGlobal.uptime>60) {
canFrame.can_id = 0x305;
canFrame.can_dlc = 0;
if (MCP2515::ERROR_OK != mcp2515->sendMessage(&canFrame)) {
AddLog(LOG_LEVEL_ERROR, PSTR("MCP2515: Failed to send keep alive frame"));
}
}
#endif
} }
} }
void MCP2515_Show(bool Json) { void MCP2515_Show(bool Json) {
if (Json) { if (Json) {
if (lastFrameRecv > 0 && TasmotaGlobal.uptime - lastFrameRecv <= MCP2515_TIMEOUT ) {
#ifdef MCP2515_BMS_CLIENT #ifdef MCP2515_BMS_CLIENT
ResponseAppend_P(PSTR(",\"MCP2515\":{\"SOC\":%d,\"SOH\":%d}"), bms.stateOfCharge, bms.stateOfHealth); ResponseAppend_P(PSTR(",\"MCP2515\":{\"SOC\":%d,\"SOH\":%d}"), \
bms.stateOfCharge,
bms.stateOfHealth
);
#endif // MCP2515_BMS_CLIENT #endif // MCP2515_BMS_CLIENT
}
#ifdef USE_WEBSERVER #ifdef USE_WEBSERVER
} else { } else {
#ifdef MCP2515_BMS_CLIENT #ifdef MCP2515_BMS_CLIENT
char ampStr[6]; char ampStr[6];
dtostrf(bms.battAmp, 5, 1, ampStr); dtostrf((float(bms.battAmp) / 10), 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, (float(bms.battVoltage) / 100));
WSContentSend_PD(HTTP_SNS_CURRENT, ampStr); WSContentSend_PD(HTTP_SNS_CURRENT, ampStr);
WSContentSend_Temp(bms.name, bms.battTemp); WSContentSend_Temp(bms.name, ConvertTemp(float(bms.battTemp) / 10));
#endif // MCP2515_BMS_CLIENT #endif // MCP2515_BMS_CLIENT
#endif // USE_WEBSERVER #endif // USE_WEBSERVER
} }