Merge pull request #135 from MalteSchm/pylontech_can_bus_lib_change

swap CAN bus library to better support newer ESPs
This commit is contained in:
Bernhard Kaszt 2023-03-12 18:24:00 +01:00 committed by GitHub
commit c7f6aea763
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 71 additions and 49 deletions

View File

@ -3,8 +3,8 @@
#include "Configuration.h" #include "Configuration.h"
#include <espMqttClient.h> #include <espMqttClient.h>
#include <driver/twai.h>
#include <Arduino.h> #include <Arduino.h>
#include <Hoymiles.h>
#include <memory> #include <memory>
#ifndef PYLONTECH_PIN_RX #ifndef PYLONTECH_PIN_RX
@ -24,15 +24,16 @@ public:
void mqtt(); void mqtt();
private: private:
uint8_t readUnsignedInt8(); uint16_t readUnsignedInt16(uint8_t *data);
uint16_t readUnsignedInt16(); int16_t readSignedInt16(uint8_t *data);
int16_t readSignedInt16();
void readString(char* str, uint8_t numBytes); void readString(char* str, uint8_t numBytes);
void readBooleanBits8(bool* b, uint8_t numBits); void readBooleanBits8(bool* b, uint8_t numBits);
float scaleValue(int16_t value, float factor); float scaleValue(int16_t value, float factor);
bool getBit(uint8_t value, uint8_t bit); bool getBit(uint8_t value, uint8_t bit);
uint32_t _lastPublish; uint32_t _lastPublish;
twai_general_config_t g_config;
}; };
extern PylontechCanReceiverClass PylontechCanReceiver; extern PylontechCanReceiverClass PylontechCanReceiver;

View File

@ -28,7 +28,6 @@ lib_deps =
nrf24/RF24 @ ^1.4.5 nrf24/RF24 @ ^1.4.5
olikraus/U8g2 @ ^2.34.13 olikraus/U8g2 @ ^2.34.13
buelowp/sunset @ ^1.1.7 buelowp/sunset @ ^1.1.7
https://github.com/berni2288/arduino-CAN
extra_scripts = extra_scripts =
pre:auto_firmware_version.py pre:auto_firmware_version.py

View File

@ -1,8 +1,9 @@
#include "PylontechCanReceiver.h" #include "PylontechCanReceiver.h"
#include "Battery.h" #include "Battery.h"
#include "Configuration.h" #include "Configuration.h"
#include "MessageOutput.h"
#include "MqttSettings.h" #include "MqttSettings.h"
#include <CAN.h> #include <driver/twai.h>
#include <ctime> #include <ctime>
//#define PYLONTECH_DEBUG_ENABLED //#define PYLONTECH_DEBUG_ENABLED
@ -11,21 +12,35 @@ PylontechCanReceiverClass PylontechCanReceiver;
void PylontechCanReceiverClass::init(int8_t rx, int8_t tx) void PylontechCanReceiverClass::init(int8_t rx, int8_t tx)
{ {
CAN.setPins(rx, tx);
CONFIG_T& config = Configuration.get(); CONFIG_T& config = Configuration.get();
if (!config.Battery_Enabled) { if (!config.Battery_Enabled) {
return; return;
} }
enable(); g_config = TWAI_GENERAL_CONFIG_DEFAULT((gpio_num_t)tx, (gpio_num_t)rx, TWAI_MODE_NORMAL);
enable();
} }
void PylontechCanReceiverClass::enable() void PylontechCanReceiverClass::enable()
{ {
if (!CAN.begin(500E3)) {
Hoymiles.getMessageOutput()->println("Starting CAN failed!"); // Initialize configuration structures using macro initializers
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_500KBITS();
twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
// Install TWAI driver
if (twai_driver_install(&g_config, &t_config, &f_config) == ESP_OK) {
MessageOutput.printf("Driver installed\n");
} else {
MessageOutput.printf("Failed to install driver\n");
}
// Start TWAI driver
if (twai_start() == ESP_OK) {
MessageOutput.printf("Driver started\n");
} else {
MessageOutput.printf("Failed to start driver\n");
} }
} }
@ -83,65 +98,75 @@ void PylontechCanReceiverClass::mqtt()
void PylontechCanReceiverClass::parseCanPackets() void PylontechCanReceiverClass::parseCanPackets()
{ {
// try to parse packet
int packetSize = CAN.parsePacket();
if ((packetSize <= 0 && CAN.packetId() == -1) // Check for messages. twai_recive is blocking when there is no data so we return if there are no frames in the buffer
|| CAN.packetRtr()) { twai_status_info_t status_info;
if (twai_get_status_info(&status_info) != ESP_OK) {
MessageOutput .printf("Failed to get status info\n");
return;
}
if (status_info.msgs_to_rx == 0) {
return; return;
} }
switch (CAN.packetId()) { // Wait for message to be received, function is blocking
twai_message_t rx_message;
if (twai_receive(&rx_message, pdMS_TO_TICKS(100)) != ESP_OK) {
MessageOutput.printf("Failed to receive message\n");
return;
}
switch (rx_message.identifier) {
case 0x351: { case 0x351: {
Battery.chargeVoltage = this->scaleValue(this->readUnsignedInt16(), 0.1); Battery.chargeVoltage = this->scaleValue(this->readUnsignedInt16(rx_message.data), 0.1);
Battery.chargeCurrentLimitation = this->scaleValue(this->readSignedInt16(), 0.1); Battery.chargeCurrentLimitation = this->scaleValue(this->readSignedInt16(rx_message.data + 2), 0.1);
Battery.dischargeCurrentLimitation = this->scaleValue(this->readSignedInt16(), 0.1); Battery.dischargeCurrentLimitation = this->scaleValue(this->readSignedInt16(rx_message.data + 4), 0.1);
#ifdef PYLONTECH_DEBUG_ENABLED #ifdef PYLONTECH_DEBUG_ENABLED
Hoymiles.getMessageOutput()->printf("[Pylontech] chargeVoltage: %f chargeCurrentLimitation: %f dischargeCurrentLimitation: %f\n", MessageOutput.printf("[Pylontech] chargeVoltage: %f chargeCurrentLimitation: %f dischargeCurrentLimitation: %f\n",
Battery.chargeVoltage, Battery.chargeCurrentLimitation, Battery.dischargeCurrentLimitation); Battery.chargeVoltage, Battery.chargeCurrentLimitation, Battery.dischargeCurrentLimitation);
#endif #endif
break; break;
} }
case 0x355: { case 0x355: {
Battery.stateOfCharge = this->readUnsignedInt16(); Battery.stateOfCharge = this->readUnsignedInt16(rx_message.data);
Battery.stateOfChargeLastUpdate = millis(); Battery.stateOfChargeLastUpdate = millis();
Battery.stateOfHealth = this->readUnsignedInt16(); Battery.stateOfHealth = this->readUnsignedInt16(rx_message.data + 2);
#ifdef PYLONTECH_DEBUG_ENABLED #ifdef PYLONTECH_DEBUG_ENABLED
Hoymiles.getMessageOutput()->printf("[Pylontech] soc: %d soh: %d\n", MessageOutput.printf("[Pylontech] soc: %d soh: %d\n",
Battery.stateOfCharge, Battery.stateOfHealth); Battery.stateOfCharge, Battery.stateOfHealth);
#endif #endif
break; break;
} }
case 0x356: { case 0x356: {
Battery.voltage = this->scaleValue(this->readSignedInt16(), 0.01); Battery.voltage = this->scaleValue(this->readSignedInt16(rx_message.data), 0.01);
Battery.current = this->scaleValue(this->readSignedInt16(), 0.1); Battery.current = this->scaleValue(this->readSignedInt16(rx_message.data + 2), 0.1);
Battery.temperature = this->scaleValue(this->readSignedInt16(), 0.1); Battery.temperature = this->scaleValue(this->readSignedInt16(rx_message.data + 4), 0.1);
#ifdef PYLONTECH_DEBUG_ENABLED #ifdef PYLONTECH_DEBUG_ENABLED
Hoymiles.getMessageOutput()->printf("[Pylontech] voltage: %f current: %f temperature: %f\n", MessageOutput.printf("[Pylontech] voltage: %f current: %f temperature: %f\n",
Battery.voltage, Battery.current, Battery.temperature); Battery.voltage, Battery.current, Battery.temperature);
#endif #endif
break; break;
} }
case 0x359: { case 0x359: {
uint16_t alarmBits = this->readUnsignedInt8(); uint16_t alarmBits = rx_message.data[0];
Battery.alarmOverCurrentDischarge = this->getBit(alarmBits, 7); Battery.alarmOverCurrentDischarge = this->getBit(alarmBits, 7);
Battery.alarmUnderTemperature = this->getBit(alarmBits, 4); Battery.alarmUnderTemperature = this->getBit(alarmBits, 4);
Battery.alarmOverTemperature = this->getBit(alarmBits, 3); Battery.alarmOverTemperature = this->getBit(alarmBits, 3);
Battery.alarmUnderVoltage = this->getBit(alarmBits, 2); Battery.alarmUnderVoltage = this->getBit(alarmBits, 2);
Battery.alarmOverVoltage= this->getBit(alarmBits, 1); Battery.alarmOverVoltage= this->getBit(alarmBits, 1);
alarmBits = this->readUnsignedInt8(); alarmBits = rx_message.data[1];
Battery.alarmBmsInternal= this->getBit(alarmBits, 3); Battery.alarmBmsInternal= this->getBit(alarmBits, 3);
Battery.alarmOverCurrentCharge = this->getBit(alarmBits, 0); Battery.alarmOverCurrentCharge = this->getBit(alarmBits, 0);
#ifdef PYLONTECH_DEBUG_ENABLED #ifdef PYLONTECH_DEBUG_ENABLED
Hoymiles.getMessageOutput()->printf("[Pylontech] Alarms: %d %d %d %d %d %d %d\n", MessageOutput.printf("[Pylontech] Alarms: %d %d %d %d %d %d %d\n",
Battery.alarmOverCurrentDischarge, Battery.alarmOverCurrentDischarge,
Battery.alarmUnderTemperature, Battery.alarmUnderTemperature,
Battery.alarmOverTemperature, Battery.alarmOverTemperature,
@ -151,19 +176,19 @@ void PylontechCanReceiverClass::parseCanPackets()
Battery.alarmOverCurrentCharge); Battery.alarmOverCurrentCharge);
#endif #endif
uint16_t warningBits = this->readUnsignedInt8(); uint16_t warningBits = rx_message.data[2];
Battery.warningHighCurrentDischarge = this->getBit(warningBits, 7); Battery.warningHighCurrentDischarge = this->getBit(warningBits, 7);
Battery.warningLowTemperature = this->getBit(warningBits, 4); Battery.warningLowTemperature = this->getBit(warningBits, 4);
Battery.warningHighTemperature = this->getBit(warningBits, 3); Battery.warningHighTemperature = this->getBit(warningBits, 3);
Battery.warningLowVoltage = this->getBit(warningBits, 2); Battery.warningLowVoltage = this->getBit(warningBits, 2);
Battery.warningHighVoltage = this->getBit(warningBits, 1); Battery.warningHighVoltage = this->getBit(warningBits, 1);
warningBits = this->readUnsignedInt8(); warningBits = rx_message.data[3];
Battery.warningBmsInternal= this->getBit(warningBits, 3); Battery.warningBmsInternal= this->getBit(warningBits, 3);
Battery.warningHighCurrentCharge = this->getBit(warningBits, 0); Battery.warningHighCurrentCharge = this->getBit(warningBits, 0);
#ifdef PYLONTECH_DEBUG_ENABLED #ifdef PYLONTECH_DEBUG_ENABLED
Hoymiles.getMessageOutput()->printf("[Pylontech] Warnings: %d %d %d %d %d %d %d\n", MessageOutput.printf("[Pylontech] Warnings: %d %d %d %d %d %d %d\n",
Battery.warningHighCurrentDischarge, Battery.warningHighCurrentDischarge,
Battery.warningLowTemperature, Battery.warningLowTemperature,
Battery.warningHighTemperature, Battery.warningHighTemperature,
@ -177,7 +202,8 @@ void PylontechCanReceiverClass::parseCanPackets()
case 0x35E: { case 0x35E: {
String manufacturer = CAN.readString(); String manufacturer = String(rx_message.data, rx_message.data_length_code);
//CAN.readString();
if (manufacturer == "") { if (manufacturer == "") {
break; break;
@ -186,47 +212,43 @@ void PylontechCanReceiverClass::parseCanPackets()
strlcpy(Battery.manufacturer, manufacturer.c_str(), sizeof(Battery.manufacturer)); strlcpy(Battery.manufacturer, manufacturer.c_str(), sizeof(Battery.manufacturer));
#ifdef PYLONTECH_DEBUG_ENABLED #ifdef PYLONTECH_DEBUG_ENABLED
Hoymiles.getMessageOutput()->printf("[Pylontech] Manufacturer: %s\n", manufacturer.c_str()); MessageOutput.printf("[Pylontech] Manufacturer: %s\n", manufacturer.c_str());
#endif #endif
break; break;
} }
case 0x35C: { case 0x35C: {
uint16_t chargeStatusBits = this->readUnsignedInt8(); uint16_t chargeStatusBits = rx_message.data[0];
Battery.chargeEnabled = this->getBit(chargeStatusBits, 7); Battery.chargeEnabled = this->getBit(chargeStatusBits, 7);
Battery.dischargeEnabled = this->getBit(chargeStatusBits, 6); Battery.dischargeEnabled = this->getBit(chargeStatusBits, 6);
Battery.chargeImmediately = this->getBit(chargeStatusBits, 5); Battery.chargeImmediately = this->getBit(chargeStatusBits, 5);
#ifdef PYLONTECH_DEBUG_ENABLED #ifdef PYLONTECH_DEBUG_ENABLED
Hoymiles.getMessageOutput()->printf("[Pylontech] chargeStatusBits: %d %d %d\n", MessageOutput.printf("[Pylontech] chargeStatusBits: %d %d %d\n",
Battery.chargeEnabled, Battery.chargeEnabled,
Battery.dischargeEnabled, Battery.dischargeEnabled,
Battery.chargeImmediately); Battery.chargeImmediately);
#endif #endif
this->readUnsignedInt8(); // this->readUnsignedInt8();
break; break;
} }
} }
} }
uint8_t PylontechCanReceiverClass::readUnsignedInt8()
{
return CAN.read();
}
uint16_t PylontechCanReceiverClass::readUnsignedInt16() uint16_t PylontechCanReceiverClass::readUnsignedInt16(uint8_t *data)
{ {
uint8_t bytes[2]; uint8_t bytes[2];
bytes[0] = (uint8_t)CAN.read(); bytes[0] = *data;
bytes[1] = (uint8_t)CAN.read(); bytes[1] = *(data + 1);
return (bytes[1] << 8) + bytes[0]; return (bytes[1] << 8) + bytes[0];
} }
int16_t PylontechCanReceiverClass::readSignedInt16() int16_t PylontechCanReceiverClass::readSignedInt16(uint8_t *data)
{ {
return this->readUnsignedInt16(); return this->readUnsignedInt16(data);
} }
float PylontechCanReceiverClass::scaleValue(int16_t value, float factor) float PylontechCanReceiverClass::scaleValue(int16_t value, float factor)