Merge branch 'enhancement/tesla-safety-check' of https://github.com/josiahhiggs/Battery-Emulator into enhancement/tesla-safety-check

This commit is contained in:
josiahhiggs 2024-12-29 22:18:32 +13:00
commit a91e4845c9
46 changed files with 4764 additions and 2944 deletions

View file

@ -70,6 +70,7 @@ jobs:
- RENAULT_ZOE_GEN1_BATTERY - RENAULT_ZOE_GEN1_BATTERY
- RENAULT_ZOE_GEN2_BATTERY - RENAULT_ZOE_GEN2_BATTERY
- SANTA_FE_PHEV_BATTERY - SANTA_FE_PHEV_BATTERY
- STELLANTIS_ECMP_BATTERY
- TESLA_MODEL_3Y_BATTERY - TESLA_MODEL_3Y_BATTERY
- TESLA_MODEL_SX_BATTERY - TESLA_MODEL_SX_BATTERY
- VOLVO_SPA_BATTERY - VOLVO_SPA_BATTERY

View file

@ -63,6 +63,7 @@ jobs:
- RENAULT_ZOE_GEN1_BATTERY - RENAULT_ZOE_GEN1_BATTERY
- RENAULT_ZOE_GEN2_BATTERY - RENAULT_ZOE_GEN2_BATTERY
- SANTA_FE_PHEV_BATTERY - SANTA_FE_PHEV_BATTERY
- STELLANTIS_ECMP_BATTERY
- TESLA_MODEL_3Y_BATTERY - TESLA_MODEL_3Y_BATTERY
- TESLA_MODEL_SX_BATTERY - TESLA_MODEL_SX_BATTERY
- VOLVO_SPA_BATTERY - VOLVO_SPA_BATTERY

View file

@ -85,7 +85,7 @@ This code uses the following excellent libraries:
- [eModbus/eModbus](https://github.com/eModbus/eModbus) MIT-License - [eModbus/eModbus](https://github.com/eModbus/eModbus) MIT-License
- [knolleary/pubsubclient](https://github.com/knolleary/pubsubclient) MIT-License - [knolleary/pubsubclient](https://github.com/knolleary/pubsubclient) MIT-License
- [mackelec/SerialDataLink](https://github.com/mackelec/SerialDataLink) - [mackelec/SerialDataLink](https://github.com/mackelec/SerialDataLink)
- [mathieucarbou/AsyncTCP](https://github.com/mathieucarbou/AsyncTCP) LGPL-3.0 license - [me-no-dev/AsyncTCP](https://github.com/me-no-dev/AsyncTCP) LGPL-3.0 license
- [me-no-dev/ESPAsyncWebServer](https://github.com/me-no-dev/ESPAsyncWebServer) - [me-no-dev/ESPAsyncWebServer](https://github.com/me-no-dev/ESPAsyncWebServer)
- [miwagner/ESP32-Arduino-CAN](https://github.com/miwagner/ESP32-Arduino-CAN/) MIT-License - [miwagner/ESP32-Arduino-CAN](https://github.com/miwagner/ESP32-Arduino-CAN/) MIT-License
- [pierremolinaro/acan2515](https://github.com/pierremolinaro/acan2515) MIT-License - [pierremolinaro/acan2515](https://github.com/pierremolinaro/acan2515) MIT-License

View file

@ -1,16 +1,13 @@
/* Do not change any code below this line unless you are sure what you are doing */ /* Do not change any code below this line unless you are sure what you are doing */
/* Only change battery specific settings in "USER_SETTINGS.h" */ /* Only change battery specific settings in "USER_SETTINGS.h" */
#include "src/include.h"
#include "HardwareSerial.h" #include "HardwareSerial.h"
#include "USER_SECRETS.h"
#include "USER_SETTINGS.h" #include "USER_SETTINGS.h"
#include "esp_system.h" #include "esp_system.h"
#include "esp_task_wdt.h" #include "esp_task_wdt.h"
#include "esp_timer.h" #include "esp_timer.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "src/charger/CHARGERS.h"
#include "src/communication/can/comm_can.h" #include "src/communication/can/comm_can.h"
#include "src/communication/contactorcontrol/comm_contactorcontrol.h" #include "src/communication/contactorcontrol/comm_contactorcontrol.h"
#include "src/communication/equipmentstopbutton/comm_equipmentstopbutton.h" #include "src/communication/equipmentstopbutton/comm_equipmentstopbutton.h"
@ -22,6 +19,7 @@
#include "src/devboard/utils/led_handler.h" #include "src/devboard/utils/led_handler.h"
#include "src/devboard/utils/logging.h" #include "src/devboard/utils/logging.h"
#include "src/devboard/utils/value_mapping.h" #include "src/devboard/utils/value_mapping.h"
#include "src/include.h"
#include "src/lib/YiannisBourkelis-Uptime-Library/src/uptime.h" #include "src/lib/YiannisBourkelis-Uptime-Library/src/uptime.h"
#include "src/lib/YiannisBourkelis-Uptime-Library/src/uptime_formatter.h" #include "src/lib/YiannisBourkelis-Uptime-Library/src/uptime_formatter.h"
#include "src/lib/bblanchon-ArduinoJson/ArduinoJson.h" #include "src/lib/bblanchon-ArduinoJson/ArduinoJson.h"
@ -30,7 +28,10 @@
#include "src/lib/eModbus-eModbus/scripts/mbServerFCs.h" #include "src/lib/eModbus-eModbus/scripts/mbServerFCs.h"
#include "src/lib/miwagner-ESP32-Arduino-CAN/CAN_config.h" #include "src/lib/miwagner-ESP32-Arduino-CAN/CAN_config.h"
#include "src/lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" #include "src/lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
#ifndef AP_PASSWORD
#error \
"Initial setup not completed, USER_SECRETS.h is missing. Please rename the file USER_SECRETS.TEMPLATE.h to USER_SECRETS.h and fill in the required credentials. This file is ignored by version control to keep sensitive information private."
#endif
#ifdef WIFI #ifdef WIFI
#include "src/devboard/wifi/wifi.h" #include "src/devboard/wifi/wifi.h"
#ifdef WEBSERVER #ifdef WEBSERVER
@ -233,9 +234,6 @@ void core_loop(void* task_time_us) {
update_machineryprotection(); // Check safeties (Not on serial link reciever board) update_machineryprotection(); // Check safeties (Not on serial link reciever board)
#endif // SERIAL_LINK_RECEIVER #endif // SERIAL_LINK_RECEIVER
update_values_inverter(); // Update values heading towards inverter update_values_inverter(); // Update values heading towards inverter
if (DUMMY_EVENT_ENABLED) {
set_event(EVENT_DUMMY_ERROR, (uint8_t)millis());
}
} }
END_TIME_MEASUREMENT_MAX(time_values, datalayer.system.status.time_values_us); END_TIME_MEASUREMENT_MAX(time_values, datalayer.system.status.time_values_us);

View file

@ -1,13 +1,20 @@
#define WIFI_SSID "REPLACE_WITH_YOUR_SSID" // Maximum of 63 characters /* This file should be renamed to USER_SECRETS.h to be able to use the software!
#define WIFI_PASSWORD "REPLACE_WITH_YOUR_PASSWORD" // Minimum of 8 characters It contains all the credentials that should never be made public */
//Password to the access point generated by the Battery-Emulator
#define AP_PASSWORD "123456789" // Minimum of 8 characters; set to blank if you want the access point to be open #define AP_PASSWORD "123456789" // Minimum of 8 characters; set to blank if you want the access point to be open
#define WEBSERVER_AUTH_REQUIRED \ //Name and password of Wifi network you want the emulator to connect to
false //Set this line to true to activate webserver authentication (this line must not be commented). #define WIFI_SSID "REPLACE_WITH_YOUR_SSID" // Maximum of 63 characters
#define HTTP_USERNAME "admin" // username to webserver authentication; #define WIFI_PASSWORD "REPLACE_WITH_YOUR_PASSWORD" // Minimum of 8 characters
#define HTTP_PASSWORD "admin" // password to webserver authentication;
#define MQTT_SERVER "192.168.xxx.yyy" // mqtt server address //Set WEBSERVER_AUTH_REQUIRED to true to require a password when accessing the webserver homepage. Improves cybersecurity.
#define MQTT_PORT 1883 // mqtt server port #define WEBSERVER_AUTH_REQUIRED false
#define MQTT_USER NULL // mqtt username, leave blank for no authentication #define HTTP_USERNAME "admin" // Username for webserver authentication
#define MQTT_PASSWORD NULL // mqtt password, leave blank for no authentication #define HTTP_PASSWORD "admin" // Password for webserver authentication
//MQTT credentials
#define MQTT_SERVER "192.168.xxx.yyy" // MQTT server address
#define MQTT_PORT 1883 // MQTT server port
#define MQTT_USER NULL // MQTT username, leave blank for no authentication
#define MQTT_PASSWORD NULL // MQTT password, leave blank for no authentication

View file

@ -20,28 +20,21 @@ volatile CAN_Configuration can_config = {
.charger = CAN_NATIVE // (OPTIONAL) Which CAN is your charger connected to? .charger = CAN_NATIVE // (OPTIONAL) Which CAN is your charger connected to?
}; };
#ifdef WIFI
volatile uint8_t AccessPointEnabled = true; //Set to either true/false to enable direct wifi access point
std::string ssid = WIFI_SSID; // Set in USER_SECRETS.h std::string ssid = WIFI_SSID; // Set in USER_SECRETS.h
std::string password = WIFI_PASSWORD; // Set in USER_SECRETS.h std::string password = WIFI_PASSWORD; // Set in USER_SECRETS.h
const char* ssidAP = "Battery Emulator"; // Maximum of 63 characters, also used for device name on web interface const char* ssidAP = "Battery Emulator"; // Maximum of 63 characters, also used for device name on web interface
const char* passwordAP = AP_PASSWORD; // Set in USER_SECRETS.h const char* passwordAP = AP_PASSWORD; // Set in USER_SECRETS.h
const uint8_t wifi_channel = 0; // Set to 0 for automatic channel selection const uint8_t wifi_channel = 0; // Set to 0 for automatic channel selection
#ifdef WIFICONFIG
// Set your Static IP address
IPAddress local_IP(192, 168, 10, 150);
// Set your Gateway IP address
IPAddress gateway(192, 168, 10, 1);
// Set your Subnet IP address
IPAddress subnet(255, 255, 255, 0);
#endif
#ifdef WEBSERVER #ifdef WEBSERVER
const char* http_username = HTTP_USERNAME; // Set in USER_SECRETS.h const char* http_username = HTTP_USERNAME; // Set in USER_SECRETS.h
const char* http_password = HTTP_PASSWORD; // Set in USER_SECRETS.h const char* http_password = HTTP_PASSWORD; // Set in USER_SECRETS.h
// Set your Static IP address. Only used incase WIFICONFIG is set in USER_SETTINGS.h
IPAddress local_IP(192, 168, 10, 150);
IPAddress gateway(192, 168, 10, 1);
IPAddress subnet(255, 255, 255, 0);
#endif // WEBSERVER #endif // WEBSERVER
// MQTT // MQTT
#ifdef MQTT #ifdef MQTT
const char* mqtt_user = MQTT_USER; // Set in USER_SECRETS.h const char* mqtt_user = MQTT_USER; // Set in USER_SECRETS.h
@ -55,7 +48,6 @@ const char* mqtt_device_name =
"Battery Emulator"; // Custom device name in Home Assistant. Previously, the name was automatically set to "BatteryEmulator_esp32-XXXXXX" "Battery Emulator"; // Custom device name in Home Assistant. Previously, the name was automatically set to "BatteryEmulator_esp32-XXXXXX"
#endif // MQTT_MANUAL_TOPIC_OBJECT_NAME #endif // MQTT_MANUAL_TOPIC_OBJECT_NAME
#endif // USE_MQTT #endif // USE_MQTT
#endif // WIFI
#ifdef EQUIPMENT_STOP_BUTTON #ifdef EQUIPMENT_STOP_BUTTON
// Equipment stop button behavior. Use NC button for safety reasons. // Equipment stop button behavior. Use NC button for safety reasons.

View file

@ -31,6 +31,7 @@
//#define RENAULT_ZOE_GEN1_BATTERY //#define RENAULT_ZOE_GEN1_BATTERY
//#define RENAULT_ZOE_GEN2_BATTERY //#define RENAULT_ZOE_GEN2_BATTERY
//#define SANTA_FE_PHEV_BATTERY //#define SANTA_FE_PHEV_BATTERY
//#define STELLANTIS_ECMP_BATTERY
//#define TESLA_MODEL_3Y_BATTERY //#define TESLA_MODEL_3Y_BATTERY
//#define TESLA_MODEL_SX_BATTERY //#define TESLA_MODEL_SX_BATTERY
//#define VOLVO_SPA_BATTERY //#define VOLVO_SPA_BATTERY
@ -77,20 +78,17 @@
//#define CAN_ADDON //Enable this line to activate an isolated secondary CAN Bus using add-on MCP2515 chip (Needed for some inverters / double battery) //#define CAN_ADDON //Enable this line to activate an isolated secondary CAN Bus using add-on MCP2515 chip (Needed for some inverters / double battery)
#define CRYSTAL_FREQUENCY_MHZ 8 //CAN_ADDON option, what is your MCP2515 add-on boards crystal frequency? #define CRYSTAL_FREQUENCY_MHZ 8 //CAN_ADDON option, what is your MCP2515 add-on boards crystal frequency?
//#define CANFD_ADDON //Enable this line to activate an isolated secondary CAN-FD bus using add-on MCP2518FD chip / Native CANFD on Stark board //#define CANFD_ADDON //Enable this line to activate an isolated secondary CAN-FD bus using add-on MCP2518FD chip / Native CANFD on Stark board
#ifdef CANFD_ADDON // CANFD_ADDON additional options if enabled
#define CANFD_ADDON_CRYSTAL_FREQUENCY_MHZ \ #define CANFD_ADDON_CRYSTAL_FREQUENCY_MHZ \
ACAN2517FDSettings:: \ ACAN2517FDSettings::OSC_40MHz //CANFD_ADDON option, what is your MCP2518 add-on boards crystal frequency?
OSC_40MHz //CANFD_ADDON option, what is your MCP2518 add-on boards crystal frequency? (Default OSC_40MHz)
#endif // CANFD_ADDON
//#define USE_CANFD_INTERFACE_AS_CLASSIC_CAN // Enable this line if you intend to use the CANFD as normal CAN //#define USE_CANFD_INTERFACE_AS_CLASSIC_CAN // Enable this line if you intend to use the CANFD as normal CAN
//#define SERIAL_LINK_RECEIVER //Enable this line to receive battery data over RS485 pins from another Lilygo (This LilyGo interfaces with inverter) //#define SERIAL_LINK_RECEIVER //Enable this line to receive battery data over RS485 pins from another Lilygo (This LilyGo interfaces with inverter)
//#define SERIAL_LINK_TRANSMITTER //Enable this line to send battery data over RS485 pins to another Lilygo (This LilyGo interfaces with battery) //#define SERIAL_LINK_TRANSMITTER //Enable this line to send battery data over RS485 pins to another Lilygo (This LilyGo interfaces with battery)
#define WIFI #define WIFI
//#define WIFICONFIG //Enable this line to set a static IP address / gateway /subnet mask for the device. see USER_SETTINGS.cpp for the settings //#define WIFICONFIG //Enable this line to set a static IP address / gateway /subnet mask for the device. see USER_SETTINGS.cpp for the settings
#define WEBSERVER //Enable this line to enable WiFi, and to run the webserver. See USER_SETTINGS.cpp for the Wifi settings. #define WEBSERVER //Enable this line to enable WiFi, and to run the webserver. See USER_SETTINGS.cpp for the Wifi settings.
#define WIFIAP //Disable this line to permanently disable WIFI AP mode (make sure to hardcode ssid and password of you home wifi network). When enabled WIFI AP can still be disabled by a setting in the future. #define WIFIAP //When enabled, the emulator will broadcast its own access point Wifi. Can be used at the same time as a normal Wifi connection to a router.
#define MDNSRESPONDER //Enable this line to enable MDNS, allows battery monitor te be found by .local address. Requires WEBSERVER to be enabled. #define MDNSRESPONDER //Enable this line to enable MDNS, allows battery monitor te be found by .local address. Requires WEBSERVER to be enabled.
#define LOAD_SAVED_SETTINGS_ON_BOOT //Enable this line to read settings stored via the webserver on boot (overrides Wifi/battery settings set below) #define LOAD_SAVED_SETTINGS_ON_BOOT // Enable this line to read settings stored via the webserver on boot (overrides Wifi credentials set here)
//#define FUNCTION_TIME_MEASUREMENT // Enable this to record execution times and present them in the web UI (WARNING, raises CPU load, do not use for production) //#define FUNCTION_TIME_MEASUREMENT // Enable this to record execution times and present them in the web UI (WARNING, raises CPU load, do not use for production)
//#define EQUIPMENT_STOP_BUTTON // Enable this to allow an equipment stop button connected to the Battery-Emulator to disengage the battery //#define EQUIPMENT_STOP_BUTTON // Enable this to allow an equipment stop button connected to the Battery-Emulator to disengage the battery
@ -107,9 +105,6 @@
/* Home Assistant options */ /* Home Assistant options */
#define HA_AUTODISCOVERY // Enable this line to send Home Assistant autodiscovery messages. If not enabled manual configuration of Home Assitant is required #define HA_AUTODISCOVERY // Enable this line to send Home Assistant autodiscovery messages. If not enabled manual configuration of Home Assitant is required
/* Event options*/
#define DUMMY_EVENT_ENABLED false //Enable this line to have a dummy event that gets logged to test the interface
/* Select charger used (Optional) */ /* Select charger used (Optional) */
//#define CHEVYVOLT_CHARGER //Enable this line to control a Chevrolet Volt charger connected to battery - for example, when generator charging or using an inverter without a charging function. //#define CHEVYVOLT_CHARGER //Enable this line to control a Chevrolet Volt charger connected to battery - for example, when generator charging or using an inverter without a charging function.
//#define NISSANLEAF_CHARGER //Enable this line to control a Nissan LEAF PDM connected to battery - for example, when generator charging //#define NISSANLEAF_CHARGER //Enable this line to control a Nissan LEAF PDM connected to battery - for example, when generator charging
@ -138,8 +133,8 @@
// 3000 = 300.0V, Target discharge voltage (Value can be tuned on the fly via webserver). Not used unless BATTERY_USE_VOLTAGE_LIMITS = true // 3000 = 300.0V, Target discharge voltage (Value can be tuned on the fly via webserver). Not used unless BATTERY_USE_VOLTAGE_LIMITS = true
#define BATTERY_MAX_DISCHARGE_VOLTAGE 3000 #define BATTERY_MAX_DISCHARGE_VOLTAGE 3000
/* Do not change any code below this line unless you are sure what you are doing */ /* Do not change any code below this line */
/* Only change battery specific settings in "USER_SETTINGS.h" */ /* Only change battery specific settings above and in "USER_SETTINGS.cpp" */
typedef enum { CAN_NATIVE = 0, CANFD_NATIVE = 1, CAN_ADDON_MCP2515 = 2, CANFD_ADDON_MCP2518 = 3 } CAN_Interface; typedef enum { CAN_NATIVE = 0, CANFD_NATIVE = 1, CAN_ADDON_MCP2515 = 2, CANFD_ADDON_MCP2518 = 3 } CAN_Interface;
typedef struct { typedef struct {
CAN_Interface battery; CAN_Interface battery;
@ -169,9 +164,7 @@ extern volatile STOP_BUTTON_BEHAVIOR equipment_stop_behavior;
#ifdef WIFICONFIG #ifdef WIFICONFIG
extern IPAddress local_IP; extern IPAddress local_IP;
// Set your Gateway IP address
extern IPAddress gateway; extern IPAddress gateway;
// Set your Subnet IP address
extern IPAddress subnet; extern IPAddress subnet;
#endif #endif

View file

@ -27,6 +27,10 @@
#include "CHADEMO-SHUNTS.h" #include "CHADEMO-SHUNTS.h"
#endif #endif
#ifdef STELLANTIS_ECMP_BATTERY
#include "ECMP-BATTERY.h"
#endif
#ifdef IMIEV_CZERO_ION_BATTERY #ifdef IMIEV_CZERO_ION_BATTERY
#include "IMIEV-CZERO-ION-BATTERY.h" #include "IMIEV-CZERO-ION-BATTERY.h"
#endif #endif

View file

@ -0,0 +1,308 @@
#include "../include.h"
#ifdef STELLANTIS_ECMP_BATTERY
#include <algorithm> // For std::min and std::max
#include "../datalayer/datalayer.h"
#include "../devboard/utils/events.h"
#include "ECMP-BATTERY.h"
/* TODO:
This integration is still ongoing. Here is what still needs to be done in order to use this battery type
- Find SOC%
- Find battery voltage
- Find current value
- Find/estimate charge/discharge limits
- Find temperature
- Figure out contactor closing
- Which CAN messages need to be sent towards the battery?
*/
/* Do not change code below unless you are sure what you are doing */
static unsigned long previousMillis1000 = 0; // will store last time a 1s CAN Message was sent
//Actual content messages
CAN_frame ECMP_XXX = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x301,
.data = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
static uint16_t battery_voltage = 37000;
static uint16_t battery_soc = 0;
static uint16_t cellvoltages[108];
void update_values_battery() {
datalayer.battery.status.real_soc = battery_soc * 100;
datalayer.battery.status.soh_pptt;
datalayer.battery.status.voltage_dV = (battery_voltage / 10);
datalayer.battery.status.current_dA;
datalayer.battery.status.active_power_W = //Power in watts, Negative = charging batt
((datalayer.battery.status.voltage_dV * datalayer.battery.status.current_dA) / 100);
datalayer.battery.status.max_charge_power_W;
datalayer.battery.status.max_discharge_power_W;
datalayer.battery.status.temperature_min_dC;
datalayer.battery.status.temperature_max_dC;
// Initialize min and max, lets find which cells are min and max!
uint16_t min_cell_mv_value = std::numeric_limits<uint16_t>::max();
uint16_t max_cell_mv_value = 0;
// Loop to find the min and max while ignoring zero values
for (uint8_t i = 0; i < datalayer.battery.info.number_of_cells; ++i) {
uint16_t voltage_mV = datalayer.battery.status.cell_voltages_mV[i];
if (voltage_mV != 0) { // Skip unread values (0)
min_cell_mv_value = std::min(min_cell_mv_value, voltage_mV);
max_cell_mv_value = std::max(max_cell_mv_value, voltage_mV);
}
}
// If all array values are 0, reset min/max to 3700
if (min_cell_mv_value == std::numeric_limits<uint16_t>::max()) {
min_cell_mv_value = 3700;
max_cell_mv_value = 3700;
}
datalayer.battery.status.cell_min_voltage_mV = min_cell_mv_value;
datalayer.battery.status.cell_max_voltage_mV = max_cell_mv_value;
}
void receive_can_battery(CAN_frame rx_frame) {
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
switch (rx_frame.ID) {
case 0x125:
break;
case 0x127:
break;
case 0x129:
break;
case 0x31B:
break;
case 0x358:
break;
case 0x359:
break;
case 0x361:
battery_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
break;
case 0x362:
break;
case 0x454:
break;
case 0x494:
break;
case 0x594:
break;
case 0x6D0:
battery_soc = (100 - rx_frame.data.u8[0]);
break;
case 0x6D1:
break;
case 0x6D2:
break;
case 0x6D3:
cellvoltages[0] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
cellvoltages[1] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
cellvoltages[2] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
cellvoltages[3] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
break;
case 0x6D4:
cellvoltages[4] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
cellvoltages[5] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
cellvoltages[6] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
cellvoltages[7] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
break;
case 0x6E0:
break;
case 0x6E1:
cellvoltages[8] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
cellvoltages[9] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
cellvoltages[10] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
cellvoltages[11] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
break;
case 0x6E2:
cellvoltages[12] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
cellvoltages[13] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
cellvoltages[14] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
cellvoltages[15] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
break;
case 0x6E3:
break;
case 0x6E4:
break;
case 0x6E5:
break;
case 0x6E6:
break;
case 0x6E7:
cellvoltages[16] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
cellvoltages[17] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
cellvoltages[18] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
cellvoltages[19] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
break;
case 0x6E8:
cellvoltages[20] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
cellvoltages[21] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
cellvoltages[22] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
cellvoltages[23] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
break;
case 0x6E9:
cellvoltages[24] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
cellvoltages[25] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
cellvoltages[26] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
cellvoltages[27] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
break;
case 0x6EB:
cellvoltages[28] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
cellvoltages[29] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
cellvoltages[30] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
cellvoltages[31] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
break;
case 0x6EC:
//Not available on e-C4
break;
case 0x6ED:
cellvoltages[32] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
cellvoltages[33] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
cellvoltages[34] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
cellvoltages[35] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
break;
case 0x6EE:
cellvoltages[36] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
cellvoltages[37] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
cellvoltages[38] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
cellvoltages[39] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
break;
case 0x6EF:
cellvoltages[40] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
cellvoltages[41] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
cellvoltages[42] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
cellvoltages[43] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
break;
case 0x6F0:
cellvoltages[44] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
cellvoltages[45] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
cellvoltages[46] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
cellvoltages[47] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
break;
case 0x6F1:
cellvoltages[48] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
cellvoltages[49] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
cellvoltages[50] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
cellvoltages[51] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
break;
case 0x6F2:
cellvoltages[52] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
cellvoltages[53] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
cellvoltages[54] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
cellvoltages[55] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
break;
case 0x6F3:
cellvoltages[56] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
cellvoltages[57] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
cellvoltages[58] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
cellvoltages[59] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
break;
case 0x6F4:
cellvoltages[60] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
cellvoltages[61] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
cellvoltages[62] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
cellvoltages[63] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
break;
case 0x6F5:
cellvoltages[64] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
cellvoltages[65] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
cellvoltages[66] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
cellvoltages[67] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
break;
case 0x6F6:
cellvoltages[68] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
cellvoltages[69] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
cellvoltages[70] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
cellvoltages[71] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
break;
case 0x6F7:
cellvoltages[72] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
cellvoltages[73] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
cellvoltages[74] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
cellvoltages[75] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
break;
case 0x6F8:
cellvoltages[76] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
cellvoltages[77] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
cellvoltages[78] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
cellvoltages[79] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
break;
case 0x6F9:
cellvoltages[80] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
cellvoltages[81] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
cellvoltages[82] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
cellvoltages[83] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
break;
case 0x6FA:
cellvoltages[84] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
cellvoltages[85] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
cellvoltages[86] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
cellvoltages[87] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
break;
case 0x6FB:
cellvoltages[88] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
cellvoltages[89] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
cellvoltages[90] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
cellvoltages[91] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
break;
case 0x6FC:
cellvoltages[92] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
cellvoltages[93] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
cellvoltages[94] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
cellvoltages[95] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
break;
case 0x6FD:
cellvoltages[96] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
cellvoltages[97] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
cellvoltages[98] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
cellvoltages[99] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
break;
case 0x6FE:
cellvoltages[100] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
cellvoltages[101] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
cellvoltages[102] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
cellvoltages[103] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
break;
case 0x6FF:
cellvoltages[104] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
cellvoltages[105] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
cellvoltages[106] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
cellvoltages[107] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
memcpy(datalayer.battery.status.cell_voltages_mV, cellvoltages, 108 * sizeof(uint16_t));
break;
case 0x794:
break;
default:
break;
}
}
void send_can_battery() {
unsigned long currentMillis = millis();
// Send 1s CAN Message
if (currentMillis - previousMillis1000 >= INTERVAL_1_S) {
previousMillis1000 = currentMillis;
}
}
void setup_battery(void) { // Performs one time setup at startup
#ifdef DEBUG_VIA_USB
Serial.println("ECMP battery selected");
#endif
datalayer.battery.info.number_of_cells = 108;
datalayer.battery.info.max_design_voltage_dV = 4546; // 454.6V, charging over this is not possible
datalayer.battery.info.min_design_voltage_dV = 3210; // 321.0V, under this, discharging further is disabled
}
#endif

View file

@ -0,0 +1,12 @@
#ifndef STELLANTIS_ECMP_BATTERY_H
#define STELLANTIS_ECMP_BATTERY_H
#include <Arduino.h>
#include "../include.h"
#define BATTERY_SELECTED
#define MAX_CELL_DEVIATION_MV 250
void setup_battery(void);
void transmit_can(CAN_frame* tx_frame, int interface);
#endif

File diff suppressed because it is too large Load diff

View file

@ -9,11 +9,13 @@ volatile bool send_ok = 0;
#ifdef CAN_ADDON #ifdef CAN_ADDON
static const uint32_t QUARTZ_FREQUENCY = CRYSTAL_FREQUENCY_MHZ * 1000000UL; //MHZ configured in USER_SETTINGS.h static const uint32_t QUARTZ_FREQUENCY = CRYSTAL_FREQUENCY_MHZ * 1000000UL; //MHZ configured in USER_SETTINGS.h
ACAN2515 can(MCP2515_CS, SPI, MCP2515_INT); SPIClass SPI2515;
ACAN2515 can(MCP2515_CS, SPI2515, MCP2515_INT);
static ACAN2515_Buffer16 gBuffer; static ACAN2515_Buffer16 gBuffer;
#endif //CAN_ADDON #endif //CAN_ADDON
#ifdef CANFD_ADDON #ifdef CANFD_ADDON
ACAN2517FD canfd(MCP2517_CS, SPI, MCP2517_INT); SPIClass SPI2517;
ACAN2517FD canfd(MCP2517_CS, SPI2517, MCP2517_INT);
#endif //CANFD_ADDON #endif //CANFD_ADDON
// Initialization functions // Initialization functions
@ -39,20 +41,20 @@ void init_CAN() {
logging.println("Dual CAN Bus (ESP32+MCP2515) selected"); logging.println("Dual CAN Bus (ESP32+MCP2515) selected");
#endif // DEBUG_LOG #endif // DEBUG_LOG
gBuffer.initWithSize(25); gBuffer.initWithSize(25);
SPI.begin(MCP2515_SCK, MCP2515_MISO, MCP2515_MOSI); SPI2515.begin(MCP2515_SCK, MCP2515_MISO, MCP2515_MOSI);
ACAN2515Settings settings(QUARTZ_FREQUENCY, 500UL * 1000UL); // CAN bit rate 500 kb/s ACAN2515Settings settings2515(QUARTZ_FREQUENCY, 500UL * 1000UL); // CAN bit rate 500 kb/s
settings.mRequestedMode = ACAN2515Settings::NormalMode; settings2515.mRequestedMode = ACAN2515Settings::NormalMode;
const uint16_t errorCodeMCP = can.begin(settings, [] { can.isr(); }); const uint16_t errorCode2515 = can.begin(settings2515, [] { can.isr(); });
if (errorCodeMCP == 0) { if (errorCode2515 == 0) {
#ifdef DEBUG_LOG #ifdef DEBUG_LOG
logging.println("Can ok"); logging.println("Can ok");
#endif // DEBUG_LOG #endif // DEBUG_LOG
} else { } else {
#ifdef DEBUG_LOG #ifdef DEBUG_LOG
logging.print("Error Can: 0x"); logging.print("Error Can: 0x");
logging.println(errorCodeMCP, HEX); logging.println(errorCode2515, HEX);
#endif // DEBUG_LOG #endif // DEBUG_LOG
set_event(EVENT_CANMCP_INIT_FAILURE, (uint8_t)errorCodeMCP); set_event(EVENT_CANMCP2515_INIT_FAILURE, (uint8_t)errorCode2515);
} }
#endif // CAN_ADDON #endif // CAN_ADDON
@ -60,41 +62,41 @@ void init_CAN() {
#ifdef DEBUG_LOG #ifdef DEBUG_LOG
logging.println("CAN FD add-on (ESP32+MCP2517) selected"); logging.println("CAN FD add-on (ESP32+MCP2517) selected");
#endif // DEBUG_LOG #endif // DEBUG_LOG
SPI.begin(MCP2517_SCK, MCP2517_SDO, MCP2517_SDI); SPI2517.begin(MCP2517_SCK, MCP2517_SDO, MCP2517_SDI);
ACAN2517FDSettings settings(CANFD_ADDON_CRYSTAL_FREQUENCY_MHZ, 500 * 1000, ACAN2517FDSettings settings2517(CANFD_ADDON_CRYSTAL_FREQUENCY_MHZ, 500 * 1000,
DataBitRateFactor::x4); // Arbitration bit rate: 500 kbit/s, data bit rate: 2 Mbit/s DataBitRateFactor::x4); // Arbitration bit rate: 500 kbit/s, data bit rate: 2 Mbit/s
#ifdef USE_CANFD_INTERFACE_AS_CLASSIC_CAN #ifdef USE_CANFD_INTERFACE_AS_CLASSIC_CAN
settings.mRequestedMode = ACAN2517FDSettings::Normal20B; // ListenOnly / Normal20B / NormalFD settings2517.mRequestedMode = ACAN2517FDSettings::Normal20B; // ListenOnly / Normal20B / NormalFD
#else // not USE_CANFD_INTERFACE_AS_CLASSIC_CAN #else // not USE_CANFD_INTERFACE_AS_CLASSIC_CAN
settings.mRequestedMode = ACAN2517FDSettings::NormalFD; // ListenOnly / Normal20B / NormalFD settings2517.mRequestedMode = ACAN2517FDSettings::NormalFD; // ListenOnly / Normal20B / NormalFD
#endif // USE_CANFD_INTERFACE_AS_CLASSIC_CAN #endif // USE_CANFD_INTERFACE_AS_CLASSIC_CAN
const uint32_t errorCode = canfd.begin(settings, [] { canfd.isr(); }); const uint32_t errorCode2517 = canfd.begin(settings2517, [] { canfd.isr(); });
canfd.poll(); canfd.poll();
if (errorCode == 0) { if (errorCode2517 == 0) {
#ifdef DEBUG_LOG #ifdef DEBUG_LOG
logging.print("Bit Rate prescaler: "); logging.print("Bit Rate prescaler: ");
logging.println(settings.mBitRatePrescaler); logging.println(settings2517.mBitRatePrescaler);
logging.print("Arbitration Phase segment 1: "); logging.print("Arbitration Phase segment 1: ");
logging.print(settings.mArbitrationPhaseSegment1); logging.print(settings2517.mArbitrationPhaseSegment1);
logging.print(" segment 2: "); logging.print(" segment 2: ");
logging.print(settings.mArbitrationPhaseSegment2); logging.print(settings2517.mArbitrationPhaseSegment2);
logging.print(" SJW: "); logging.print(" SJW: ");
logging.println(settings.mArbitrationSJW); logging.println(settings2517.mArbitrationSJW);
logging.print("Actual Arbitration Bit Rate: "); logging.print("Actual Arbitration Bit Rate: ");
logging.print(settings.actualArbitrationBitRate()); logging.print(settings2517.actualArbitrationBitRate());
logging.print(" bit/s"); logging.print(" bit/s");
logging.print(" (Exact:"); logging.print(" (Exact:");
logging.println(settings.exactArbitrationBitRate() ? "yes)" : "no)"); logging.println(settings2517.exactArbitrationBitRate() ? "yes)" : "no)");
logging.print("Arbitration Sample point: "); logging.print("Arbitration Sample point: ");
logging.print(settings.arbitrationSamplePointFromBitStart()); logging.print(settings2517.arbitrationSamplePointFromBitStart());
logging.println("%"); logging.println("%");
#endif // DEBUG_LOG #endif // DEBUG_LOG
} else { } else {
#ifdef DEBUG_LOG #ifdef DEBUG_LOG
logging.print("CAN-FD Configuration error 0x"); logging.print("CAN-FD Configuration error 0x");
logging.println(errorCode, HEX); logging.println(errorCode2517, HEX);
#endif // DEBUG_LOG #endif // DEBUG_LOG
set_event(EVENT_CANFD_INIT_FAILURE, (uint8_t)errorCode); set_event(EVENT_CANMCP2517FD_INIT_FAILURE, (uint8_t)errorCode2517);
} }
#endif // CANFD_ADDON #endif // CANFD_ADDON
} }

View file

@ -90,9 +90,9 @@ void init_contactors() {
// Main functions // Main functions
void handle_contactors() { void handle_contactors() {
#ifdef BYD_SMA #if defined(BYD_SMA) || defined(SMA_TRIPOWER_CAN)
datalayer.system.status.inverter_allows_contactor_closing = digitalRead(INVERTER_CONTACTOR_ENABLE_PIN); datalayer.system.status.inverter_allows_contactor_closing = digitalRead(INVERTER_CONTACTOR_ENABLE_PIN);
#endif // BYD_SMA #endif
#ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY #ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY
handle_contactors_battery2(); handle_contactors_battery2();

View file

@ -215,7 +215,12 @@ typedef struct {
uint8_t packCtrsClosingAllowed = 0; uint8_t packCtrsClosingAllowed = 0;
/** uint8_t */ /** uint8_t */
/** Pyro test in progress */ /** Pyro test in progress */
uint8_t pyroTestInProgress = 0; bool pyroTestInProgress = false;
bool battery_packCtrsOpenNowRequested = false;
bool battery_packCtrsOpenRequested = false;
uint8_t battery_packCtrsRequestStatus = 0;
bool battery_packCtrsResetRequestRequired = false;
bool battery_dcLinkAllowedToEnergize = false;
uint8_t battery_beginning_of_life = 0; uint8_t battery_beginning_of_life = 0;
uint8_t battery_battTempPct = 0; uint8_t battery_battTempPct = 0;
uint16_t battery_dcdcLvBusVolt = 0; uint16_t battery_dcdcLvBusVolt = 0;
@ -231,10 +236,20 @@ typedef struct {
uint16_t battery_energy_to_charge_complete_m1 = 0; uint16_t battery_energy_to_charge_complete_m1 = 0;
uint16_t battery_energy_buffer = 0; uint16_t battery_energy_buffer = 0;
uint16_t battery_energy_buffer_m1 = 0; uint16_t battery_energy_buffer_m1 = 0;
uint16_t battery_full_charge_complete = 0; uint16_t battery_expected_energy_remaining = 0;
uint8_t battery_fully_charged = 0; uint16_t battery_expected_energy_remaining_m1 = 0;
bool battery_full_charge_complete = false;
bool battery_fully_charged = false;
uint16_t battery_total_discharge = 0; uint16_t battery_total_discharge = 0;
uint16_t battery_total_charge = 0; uint16_t battery_total_charge = 0;
uint16_t battery_BrickVoltageMax = 0;
uint16_t battery_BrickVoltageMin = 0;
uint8_t battery_BrickVoltageMaxNum = 0;
uint8_t battery_BrickVoltageMinNum = 0;
uint8_t battery_BrickTempMaxNum = 0;
uint8_t battery_BrickTempMinNum = 0;
uint8_t battery_BrickModelTMax = 0;
uint8_t battery_BrickModelTMin = 0;
uint16_t battery_packConfigMultiplexer = 0; uint16_t battery_packConfigMultiplexer = 0;
uint16_t battery_moduleType = 0; uint16_t battery_moduleType = 0;
uint16_t battery_reservedConfig = 0; uint16_t battery_reservedConfig = 0;
@ -248,6 +263,123 @@ typedef struct {
uint32_t battery_soc_max = 0; uint32_t battery_soc_max = 0;
uint32_t battery_soc_ave = 0; uint32_t battery_soc_ave = 0;
uint32_t battery_soc_ui = 0; uint32_t battery_soc_ui = 0;
uint8_t battery_BMS_contactorState = 0;
uint8_t battery_BMS_state = 0;
uint8_t battery_BMS_hvState = 0;
uint16_t battery_BMS_isolationResistance = 0;
uint8_t battery_BMS_uiChargeStatus = 0;
bool battery_BMS_diLimpRequest = false;
uint16_t battery_BMS_chgPowerAvailable = 0;
bool battery_BMS_pcsPwmEnabled = false;
uint8_t battery_PCS_dcdcPrechargeStatus = 0;
uint8_t battery_PCS_dcdc12VSupportStatus = 0;
uint8_t battery_PCS_dcdcHvBusDischargeStatus = 0;
uint8_t battery_PCS_dcdcMainState = 0;
uint8_t battery_PCS_dcdcSubState = 0;
bool battery_PCS_dcdcFaulted = false;
bool battery_PCS_dcdcOutputIsLimited = false;
uint16_t battery_PCS_dcdcMaxOutputCurrentAllowed = 0;
uint8_t battery_PCS_dcdcPrechargeRtyCnt = 0;
uint8_t battery_PCS_dcdc12VSupportRtyCnt = 0;
uint8_t battery_PCS_dcdcDischargeRtyCnt = 0;
uint8_t battery_PCS_dcdcPwmEnableLine = 0;
uint8_t battery_PCS_dcdcSupportingFixedLvTarget = 0;
uint8_t battery_PCS_dcdcPrechargeRestartCnt = 0;
uint8_t battery_PCS_dcdcInitialPrechargeSubState = 0;
uint16_t BMS_maxRegenPower = 0;
uint16_t BMS_maxDischargePower = 0;
uint16_t BMS_maxStationaryHeatPower = 0;
uint16_t BMS_hvacPowerBudget = 0;
uint8_t BMS_notEnoughPowerForHeatPump = 0;
uint8_t BMS_powerLimitState = 0;
uint8_t BMS_inverterTQF = 0;
uint16_t BMS_powerDissipation = 0;
uint8_t BMS_flowRequest = 0;
uint16_t BMS_inletActiveCoolTargetT = 0;
uint16_t BMS_inletPassiveTargetT = 0;
uint16_t BMS_inletActiveHeatTargetT = 0;
uint16_t BMS_packTMin = 0;
uint16_t BMS_packTMax = 0;
bool BMS_pcsNoFlowRequest = false;
bool BMS_noFlowRequest = false;
uint16_t PCS_dcdcTemp = 0;
uint16_t PCS_ambientTemp = 0;
uint16_t PCS_dcdcMaxLvOutputCurrent = 0;
uint16_t PCS_dcdcCurrentLimit = 0;
uint16_t PCS_dcdcLvOutputCurrentTempLimit = 0;
uint16_t PCS_dcdcUnifiedCommand = 0;
uint16_t PCS_dcdcCLAControllerOutput = 0;
uint16_t PCS_dcdcTankVoltage = 0;
uint16_t PCS_dcdcTankVoltageTarget = 0;
uint16_t PCS_dcdcClaCurrentFreq = 0;
uint16_t PCS_dcdcTCommMeasured = 0;
uint16_t PCS_dcdcShortTimeUs = 0;
uint16_t PCS_dcdcHalfPeriodUs = 0;
uint16_t PCS_dcdcIntervalMaxFrequency = 0;
uint16_t PCS_dcdcIntervalMaxHvBusVolt = 0;
uint16_t PCS_dcdcIntervalMaxLvBusVolt = 0;
uint16_t PCS_dcdcIntervalMaxLvOutputCurr = 0;
uint16_t PCS_dcdcIntervalMinFrequency = 0;
uint16_t PCS_dcdcIntervalMinHvBusVolt = 0;
uint16_t PCS_dcdcIntervalMinLvBusVolt = 0;
uint16_t PCS_dcdcIntervalMinLvOutputCurr = 0;
uint32_t PCS_dcdc12vSupportLifetimekWh = 0;
bool HVP_gpioPassivePyroDepl = false;
bool HVP_gpioPyroIsoEn = false;
bool HVP_gpioCpFaultIn = false;
bool HVP_gpioPackContPowerEn = false;
bool HVP_gpioHvCablesOk = false;
bool HVP_gpioHvpSelfEnable = false;
bool HVP_gpioLed = false;
bool HVP_gpioCrashSignal = false;
bool HVP_gpioShuntDataReady = false;
bool HVP_gpioFcContPosAux = false;
bool HVP_gpioFcContNegAux = false;
bool HVP_gpioBmsEout = false;
bool HVP_gpioCpFaultOut = false;
bool HVP_gpioPyroPor = false;
bool HVP_gpioShuntEn = false;
bool HVP_gpioHvpVerEn = false;
bool HVP_gpioPackCoontPosFlywheel = false;
bool HVP_gpioCpLatchEnable = false;
bool HVP_gpioPcsEnable = false;
bool HVP_gpioPcsDcdcPwmEnable = false;
bool HVP_gpioPcsChargePwmEnable = false;
bool HVP_gpioFcContPowerEnable = false;
bool HVP_gpioHvilEnable = false;
bool HVP_gpioSecDrdy = false;
uint16_t HVP_hvp1v5Ref = 0;
uint16_t HVP_shuntCurrentDebug = 0;
bool HVP_packCurrentMia = false;
bool HVP_auxCurrentMia = false;
bool HVP_currentSenseMia = false;
bool HVP_shuntRefVoltageMismatch = false;
bool HVP_shuntThermistorMia = false;
uint8_t HVP_shuntHwMia = 0;
uint16_t HVP_dcLinkVoltage = 0;
uint16_t HVP_packVoltage = 0;
uint16_t HVP_fcLinkVoltage = 0;
uint16_t HVP_packContVoltage = 0;
uint16_t HVP_packNegativeV = 0;
uint16_t HVP_packPositiveV = 0;
uint16_t HVP_pyroAnalog = 0;
uint16_t HVP_dcLinkNegativeV = 0;
uint16_t HVP_dcLinkPositiveV = 0;
uint16_t HVP_fcLinkNegativeV = 0;
uint16_t HVP_fcContCoilCurrent = 0;
uint16_t HVP_fcContVoltage = 0;
uint16_t HVP_hvilInVoltage = 0;
uint16_t HVP_hvilOutVoltage = 0;
uint16_t HVP_fcLinkPositiveV = 0;
uint16_t HVP_packContCoilCurrent = 0;
uint16_t HVP_battery12V = 0;
uint16_t HVP_shuntRefVoltageDbg = 0;
uint16_t HVP_shuntAuxCurrentDbg = 0;
uint16_t HVP_shuntBarTempDbg = 0;
uint16_t HVP_shuntAsicTempDbg = 0;
uint8_t HVP_shuntAuxCurrentStatus = 0;
uint8_t HVP_shuntBarTempStatus = 0;
uint8_t HVP_shuntAsicTempStatus = 0;
} DATALAYER_INFO_TESLA; } DATALAYER_INFO_TESLA;
typedef struct { typedef struct {

View file

@ -140,8 +140,8 @@ void init_events(void) {
events.entries[i].MQTTpublished = false; // Not published by default events.entries[i].MQTTpublished = false; // Not published by default
} }
events.entries[EVENT_CANFD_INIT_FAILURE].level = EVENT_LEVEL_WARNING; events.entries[EVENT_CANMCP2517FD_INIT_FAILURE].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_CANMCP_INIT_FAILURE].level = EVENT_LEVEL_WARNING; events.entries[EVENT_CANMCP2515_INIT_FAILURE].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_CANFD_BUFFER_FULL].level = EVENT_LEVEL_WARNING; events.entries[EVENT_CANFD_BUFFER_FULL].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_CAN_OVERRUN].level = EVENT_LEVEL_INFO; events.entries[EVENT_CAN_OVERRUN].level = EVENT_LEVEL_INFO;
events.entries[EVENT_CANFD_RX_OVERRUN].level = EVENT_LEVEL_WARNING; events.entries[EVENT_CANFD_RX_OVERRUN].level = EVENT_LEVEL_WARNING;
@ -264,9 +264,9 @@ void set_event_MQTTpublished(EVENTS_ENUM_TYPE event) {
const char* get_event_message_string(EVENTS_ENUM_TYPE event) { const char* get_event_message_string(EVENTS_ENUM_TYPE event) {
switch (event) { switch (event) {
case EVENT_CANFD_INIT_FAILURE: case EVENT_CANMCP2517FD_INIT_FAILURE:
return "CAN-FD initialization failed. Check hardware or bitrate settings"; return "CAN-FD initialization failed. Check hardware or bitrate settings";
case EVENT_CANMCP_INIT_FAILURE: case EVENT_CANMCP2515_INIT_FAILURE:
return "CAN-MCP addon initialization failed. Check hardware"; return "CAN-MCP addon initialization failed. Check hardware";
case EVENT_CANFD_BUFFER_FULL: case EVENT_CANFD_BUFFER_FULL:
return "CAN-FD buffer overflowed. Some CAN messages were not sent. Contact developers."; return "CAN-FD buffer overflowed. Some CAN messages were not sent. Contact developers.";

View file

@ -26,8 +26,8 @@
*/ */
#define EVENTS_ENUM_TYPE(XX) \ #define EVENTS_ENUM_TYPE(XX) \
XX(EVENT_CANFD_INIT_FAILURE) \ XX(EVENT_CANMCP2517FD_INIT_FAILURE) \
XX(EVENT_CANMCP_INIT_FAILURE) \ XX(EVENT_CANMCP2515_INIT_FAILURE) \
XX(EVENT_CANFD_BUFFER_FULL) \ XX(EVENT_CANFD_BUFFER_FULL) \
XX(EVENT_CAN_OVERRUN) \ XX(EVENT_CAN_OVERRUN) \
XX(EVENT_CANFD_RX_OVERRUN) \ XX(EVENT_CANFD_RX_OVERRUN) \

View file

@ -349,6 +349,8 @@ String advanced_battery_processor(const String& var) {
static_cast<float>(datalayer_extended.tesla.battery_energy_to_charge_complete_m1) * 0.02; static_cast<float>(datalayer_extended.tesla.battery_energy_to_charge_complete_m1) * 0.02;
float energy_buffer = static_cast<float>(datalayer_extended.tesla.battery_energy_buffer) * 0.1; float energy_buffer = static_cast<float>(datalayer_extended.tesla.battery_energy_buffer) * 0.1;
float energy_buffer_m1 = static_cast<float>(datalayer_extended.tesla.battery_energy_buffer_m1) * 0.01; float energy_buffer_m1 = static_cast<float>(datalayer_extended.tesla.battery_energy_buffer_m1) * 0.01;
float expected_energy_remaining_m1 =
static_cast<float>(datalayer_extended.tesla.battery_expected_energy_remaining_m1) * 0.02;
float total_discharge = static_cast<float>(datalayer_extended.tesla.battery_total_discharge); float total_discharge = static_cast<float>(datalayer_extended.tesla.battery_total_discharge);
float total_charge = static_cast<float>(datalayer_extended.tesla.battery_total_charge); float total_charge = static_cast<float>(datalayer_extended.tesla.battery_total_charge);
float packMass = static_cast<float>(datalayer_extended.tesla.battery_packMass); float packMass = static_cast<float>(datalayer_extended.tesla.battery_packMass);
@ -362,50 +364,85 @@ String advanced_battery_processor(const String& var) {
float soc_max = static_cast<float>(datalayer_extended.tesla.battery_soc_max) * 0.1; float soc_max = static_cast<float>(datalayer_extended.tesla.battery_soc_max) * 0.1;
float soc_min = static_cast<float>(datalayer_extended.tesla.battery_soc_min) * 0.1; float soc_min = static_cast<float>(datalayer_extended.tesla.battery_soc_min) * 0.1;
float soc_ui = static_cast<float>(datalayer_extended.tesla.battery_soc_ui) * 0.1; float soc_ui = static_cast<float>(datalayer_extended.tesla.battery_soc_ui) * 0.1;
float BrickVoltageMax = static_cast<float>(datalayer_extended.tesla.battery_BrickVoltageMax) * 0.002;
// Comment what data you would like to dislay, order can be changed. float BrickVoltageMin = static_cast<float>(datalayer_extended.tesla.battery_BrickVoltageMin) * 0.002;
content += "<h4>Battery Beginning of Life: " + String(beginning_of_life) + " kWh</h4>"; float BrickModelTMax = static_cast<float>(datalayer_extended.tesla.battery_BrickTempMinNum) * 0.5 - 40;
content += "<h4>BattTempPct: " + String(battTempPct) + " </h4>"; float BrickModelTMin = static_cast<float>(datalayer_extended.tesla.battery_BrickModelTMin) * 0.5 - 40;
content += "<h4>PCS Lv Bus: " + String(dcdcLvBusVolt) + " V</h4>"; float isolationResistance = static_cast<float>(datalayer_extended.tesla.battery_BMS_isolationResistance) * 10;
content += "<h4>PCS Hv Bus: " + String(dcdcHvBusVolt) + " V</h4>"; float PCS_dcdcMaxOutputCurrentAllowed =
content += "<h4>PCS Lv Output: " + String(dcdcLvOutputCurrent) + " A</h4>"; static_cast<float>(datalayer_extended.tesla.battery_PCS_dcdcMaxOutputCurrentAllowed) * 0.1;
float PCS_dcdcTemp = static_cast<float>(datalayer_extended.tesla.PCS_dcdcTemp) * 0.1 - 40;
//if using older BMS <2021 and comment 0x352 without MUX float PCS_ambientTemp = static_cast<float>(datalayer_extended.tesla.PCS_ambientTemp) * 0.1 - 40;
//content += "<h4>Nominal Full Pack Energy: " + String(nominal_full_pack_energy) + " kWh</h4>"; float BMS_maxRegenPower = static_cast<float>(datalayer_extended.tesla.BMS_maxRegenPower) * 0.01;
//content += "<h4>Nominal Energy Remaining: " + String(nominal_energy_remaining) + " kWh</h4>"; float BMS_maxDischargePower = static_cast<float>(datalayer_extended.tesla.BMS_maxDischargePower) * 0.013;
//content += "<h4>Ideal Energy Remaining: " + String(ideal_energy_remaining) + " kWh</h4>"; float BMS_maxStationaryHeatPower = static_cast<float>(datalayer_extended.tesla.BMS_maxStationaryHeatPower) * 0.01;
//content += "<h4>Energy to Charge Complete: " + String(energy_to_charge_complete) + " kWh</h4>"; float BMS_hvacPowerBudget = static_cast<float>(datalayer_extended.tesla.BMS_hvacPowerBudget) * 0.02;
//content += "<h4>Energy Buffer: " + String(energy_buffer) + " kWh</h4>"; float BMS_powerDissipation = static_cast<float>(datalayer_extended.tesla.BMS_powerDissipation) * 0.02;
float BMS_flowRequest = static_cast<float>(datalayer_extended.tesla.BMS_flowRequest) * 0.3;
//if using newer BMS >2021 and comment 0x352 with MUX float BMS_inletActiveCoolTargetT =
content += "<h4>Nominal Full Pack Energy m0: " + String(nominal_full_pack_energy_m0) + " kWh</h4>"; static_cast<float>(datalayer_extended.tesla.BMS_inletActiveCoolTargetT) * 0.25 - 25;
content += "<h4>Nominal Energy Remaining m0: " + String(nominal_energy_remaining_m0) + " kWh</h4>"; float BMS_inletPassiveTargetT = static_cast<float>(datalayer_extended.tesla.BMS_inletPassiveTargetT) * 0.25 - 25;
content += "<h4>Ideal Energy Remaining m0: " + String(ideal_energy_remaining_m0) + " kWh</h4>"; float BMS_inletActiveHeatTargetT =
content += "<h4>Energy to Charge Complete m1: " + String(energy_to_charge_complete_m1) + " kWh</h4>"; static_cast<float>(datalayer_extended.tesla.BMS_inletActiveHeatTargetT) * 0.25 - 25;
content += "<h4>Energy Buffer m1: " + String(energy_buffer_m1) + " kWh</h4>"; float BMS_packTMin = static_cast<float>(datalayer_extended.tesla.BMS_packTMin) * 0.25 - 25;
float BMS_packTMax = static_cast<float>(datalayer_extended.tesla.BMS_packTMax) * 0.25 - 25;
content += "<h4>packConfigMultiplexer: " + String(datalayer_extended.tesla.battery_packConfigMultiplexer) + "</h4>"; float PCS_dcdcMaxLvOutputCurrent = static_cast<float>(datalayer_extended.tesla.PCS_dcdcMaxLvOutputCurrent) * 0.1;
content += "<h4>moduleType: " + String(datalayer_extended.tesla.battery_moduleType) + "</h4>"; float PCS_dcdcCurrentLimit = static_cast<float>(datalayer_extended.tesla.PCS_dcdcCurrentLimit) * 0.1;
content += "<h4>reserveConfig: " + String(datalayer_extended.tesla.battery_reservedConfig) + "</h4>"; float PCS_dcdcLvOutputCurrentTempLimit =
content += "<h4>Full Charge Complete: " + String(datalayer_extended.tesla.battery_full_charge_complete) + "</h4>"; static_cast<float>(datalayer_extended.tesla.PCS_dcdcLvOutputCurrentTempLimit) * 0.1;
content += "<h4>Total Discharge: " + String(total_discharge) + " kWh</h4>"; float PCS_dcdcUnifiedCommand = static_cast<float>(datalayer_extended.tesla.PCS_dcdcUnifiedCommand) * 0.001;
content += "<h4>Total Charge: " + String(total_charge) + " kWh</h4>"; float PCS_dcdcCLAControllerOutput =
content += "<h4>Battery Pack Mass: " + String(packMass) + " KG</h4>"; static_cast<float>(datalayer_extended.tesla.PCS_dcdcCLAControllerOutput * 0.001);
content += "<h4>Platform Max Bus Voltage: " + String(platformMaxBusVoltage) + " V</h4>"; float PCS_dcdcTankVoltage = static_cast<float>(datalayer_extended.tesla.PCS_dcdcTankVoltage);
content += "<h4>BMS Min Voltage: " + String(bms_min_voltage) + " V</h4>"; float PCS_dcdcTankVoltageTarget = static_cast<float>(datalayer_extended.tesla.PCS_dcdcTankVoltageTarget);
content += "<h4>BMS Max Voltage: " + String(bms_max_voltage) + " V</h4>"; float PCS_dcdcClaCurrentFreq = static_cast<float>(datalayer_extended.tesla.PCS_dcdcClaCurrentFreq) * 0.0976563;
content += "<h4>Max Charge Current: " + String(max_charge_current) + " A</h4>"; float PCS_dcdcTCommMeasured = static_cast<float>(datalayer_extended.tesla.PCS_dcdcTCommMeasured) * 0.00195313;
content += "<h4>Max Discharge Current: " + String(max_discharge_current) + " A</h4>"; float PCS_dcdcShortTimeUs = static_cast<float>(datalayer_extended.tesla.PCS_dcdcShortTimeUs) * 0.000488281;
content += "<h4>Battery SOC Ave: " + String(soc_ave) + " </h4>"; float PCS_dcdcHalfPeriodUs = static_cast<float>(datalayer_extended.tesla.PCS_dcdcHalfPeriodUs) * 0.000488281;
content += "<h4>Battery SOC Max: " + String(soc_max) + " </h4>"; float PCS_dcdcIntervalMaxFrequency = static_cast<float>(datalayer_extended.tesla.PCS_dcdcIntervalMaxFrequency);
content += "<h4>Battery SOC Min: " + String(soc_min) + " </h4>"; float PCS_dcdcIntervalMaxHvBusVolt =
content += "<h4>Battery SOC UI: " + String(soc_ui) + " </h4>"; static_cast<float>(datalayer_extended.tesla.PCS_dcdcIntervalMaxHvBusVolt) * 0.1;
float PCS_dcdcIntervalMaxLvBusVolt =
static_cast<float>(datalayer_extended.tesla.PCS_dcdcIntervalMaxLvBusVolt) * 0.1;
float PCS_dcdcIntervalMaxLvOutputCurr =
static_cast<float>(datalayer_extended.tesla.PCS_dcdcIntervalMaxLvOutputCurr);
float PCS_dcdcIntervalMinFrequency = static_cast<float>(datalayer_extended.tesla.PCS_dcdcIntervalMinFrequency);
float PCS_dcdcIntervalMinHvBusVolt =
static_cast<float>(datalayer_extended.tesla.PCS_dcdcIntervalMinHvBusVolt) * 0.1;
float PCS_dcdcIntervalMinLvBusVolt =
static_cast<float>(datalayer_extended.tesla.PCS_dcdcIntervalMinLvBusVolt) * 0.1;
float PCS_dcdcIntervalMinLvOutputCurr =
static_cast<float>(datalayer_extended.tesla.PCS_dcdcIntervalMinLvOutputCurr);
float PCS_dcdc12vSupportLifetimekWh =
static_cast<float>(datalayer_extended.tesla.PCS_dcdc12vSupportLifetimekWh) * 0.01;
float HVP_hvp1v5Ref = static_cast<float>(datalayer_extended.tesla.HVP_hvp1v5Ref) * 0.1;
float HVP_shuntCurrentDebug = static_cast<float>(datalayer_extended.tesla.HVP_shuntCurrentDebug) * 0.1;
float HVP_dcLinkVoltage = static_cast<float>(datalayer_extended.tesla.HVP_dcLinkVoltage) * 0.1;
float HVP_packVoltage = static_cast<float>(datalayer_extended.tesla.HVP_packVoltage) * 0.1;
float HVP_fcLinkVoltage = static_cast<float>(datalayer_extended.tesla.HVP_fcLinkVoltage) * 0.1;
float HVP_packContVoltage = static_cast<float>(datalayer_extended.tesla.HVP_packContVoltage) * 0.1;
float HVP_packNegativeV = static_cast<float>(datalayer_extended.tesla.HVP_packNegativeV) * 0.1;
float HVP_packPositiveV = static_cast<float>(datalayer_extended.tesla.HVP_packPositiveV) * 0.1;
float HVP_pyroAnalog = static_cast<float>(datalayer_extended.tesla.HVP_pyroAnalog) * 0.1;
float HVP_dcLinkNegativeV = static_cast<float>(datalayer_extended.tesla.HVP_dcLinkNegativeV) * 0.1;
float HVP_dcLinkPositiveV = static_cast<float>(datalayer_extended.tesla.HVP_dcLinkPositiveV) * 0.1;
float HVP_fcLinkNegativeV = static_cast<float>(datalayer_extended.tesla.HVP_fcLinkNegativeV) * 0.1;
float HVP_fcContCoilCurrent = static_cast<float>(datalayer_extended.tesla.HVP_fcContCoilCurrent) * 0.1;
float HVP_fcContVoltage = static_cast<float>(datalayer_extended.tesla.HVP_fcContVoltage) * 0.1;
float HVP_hvilInVoltage = static_cast<float>(datalayer_extended.tesla.HVP_hvilInVoltage) * 0.1;
float HVP_hvilOutVoltage = static_cast<float>(datalayer_extended.tesla.HVP_hvilOutVoltage) * 0.1;
float HVP_fcLinkPositiveV = static_cast<float>(datalayer_extended.tesla.HVP_fcLinkPositiveV) * 0.1;
float HVP_packContCoilCurrent = static_cast<float>(datalayer_extended.tesla.HVP_packContCoilCurrent) * 0.1;
float HVP_battery12V = static_cast<float>(datalayer_extended.tesla.HVP_battery12V) * 0.1;
float HVP_shuntRefVoltageDbg = static_cast<float>(datalayer_extended.tesla.HVP_shuntRefVoltageDbg) * 0.001;
float HVP_shuntAuxCurrentDbg = static_cast<float>(datalayer_extended.tesla.HVP_shuntAuxCurrentDbg) * 0.1;
float HVP_shuntBarTempDbg = static_cast<float>(datalayer_extended.tesla.HVP_shuntBarTempDbg) * 0.01;
float HVP_shuntAsicTempDbg = static_cast<float>(datalayer_extended.tesla.HVP_shuntAsicTempDbg) * 0.01;
static const char* contactorText[] = {"UNKNOWN(0)", "OPEN", "CLOSING", "BLOCKED", "OPENING", static const char* contactorText[] = {"UNKNOWN(0)", "OPEN", "CLOSING", "BLOCKED", "OPENING",
"CLOSED", "UNKNOWN(6)", "WELDED", "POS_CL", "NEG_CL", "CLOSED", "UNKNOWN(6)", "WELDED", "POS_CL", "NEG_CL",
"UNKNOWN(10)", "UNKNOWN(11)", "UNKNOWN(12)"}; "UNKNOWN(10)", "UNKNOWN(11)", "UNKNOWN(12)"};
content += "<h4>Contactor Status: " + String(contactorText[datalayer_extended.tesla.status_contactor]) + "</h4>"; static const char* hvilStatusState[] = {"NOT Ok",
static const char* hvilStatusState[] = {"NOT OK",
"STATUS_OK", "STATUS_OK",
"CURRENT_SOURCE_FAULT", "CURRENT_SOURCE_FAULT",
"INTERNAL_OPEN_FAULT", "INTERNAL_OPEN_FAULT",
@ -421,17 +458,292 @@ String advanced_battery_processor(const String& var) {
"UNKNOWN(13)", "UNKNOWN(13)",
"UNKNOWN(14)", "UNKNOWN(14)",
"UNKNOWN(15)"}; "UNKNOWN(15)"};
content += "<h4>HVIL: " + String(hvilStatusState[datalayer_extended.tesla.hvil_status]) + "</h4>";
static const char* contactorState[] = {"SNA", "OPEN", "PRECHARGE", "BLOCKED", static const char* contactorState[] = {"SNA", "OPEN", "PRECHARGE", "BLOCKED",
"PULLED_IN", "OPENING", "ECONOMIZED", "WELDED", "PULLED_IN", "OPENING", "ECONOMIZED", "WELDED",
"UNKNOWN(8)", "UNKNOWN(9)", "UNKNOWN(10)", "UNKNOWN(11)"}; "UNKNOWN(8)", "UNKNOWN(9)", "UNKNOWN(10)", "UNKNOWN(11)"};
static const char* BMS_state[] = {"STANDBY", "DRIVE", "SUPPORT", "CHARGE", "FEIM",
"CLEAR_FAULT", "FAULT", "WELD", "TEST", "SNA"};
static const char* BMS_contactorState[] = {"SNA", "OPEN", "OPENING", "CLOSING", "CLOSED", "WELDED", "BLOCKED"};
static const char* BMS_hvState[] = {"DOWN", "COMING_UP", "GOING_DOWN", "UP_FOR_DRIVE",
"UP_FOR_CHARGE", "UP_FOR_DC_CHARGE", "UP"};
static const char* BMS_uiChargeStatus[] = {"DISCONNECTED", "NO_POWER", "ABOUT_TO_CHARGE",
"CHARGING", "CHARGE_COMPLETE", "CHARGE_STOPPED"};
static const char* PCS_dcdcStatus[] = {"IDLE", "ACTIVE", "FAULTED"};
static const char* PCS_dcdcMainState[] = {"STANDBY", "12V_SUPPORT_ACTIVE", "PRECHARGE_STARTUP",
"PRECHARGE_ACTIVE", "DIS_HVBUS_ACTIVE", "SHUTDOWN",
"FAULTED"};
static const char* PCS_dcdcSubState[] = {"PWR_UP_INIT",
"STANDBY",
"12V_SUPPORT_ACTIVE",
"DIS_HVBUS",
"PCHG_FAST_DIS_HVBUS",
"PCHG_SLOW_DIS_HVBUS",
"PCHG_DWELL_CHARGE",
"PCHG_DWELL_WAIT",
"PCHG_DI_RECOVERY_WAIT",
"PCHG_ACTIVE",
"PCHG_FLT_FAST_DIS_HVBUS",
"SHUTDOWN",
"12V_SUPPORT_FAULTED",
"DIS_HVBUS_FAULTED",
"PCHG_FAULTED",
"CLEAR_FAULTS",
"FAULTED",
"NUM"};
static const char* BMS_powerLimitState[] = {"NOT_CALCULATED_FOR_DRIVE", "CALCULATED_FOR_DRIVE"};
static const char* HVP_status[] = {"INVALID", "NOT_AVAILABLE", "STALE", "VALID"};
static const char* HVP_contactor[] = {"NOT_ACTIVE", "ACTIVE", "COMPLETED"};
static const char* falseTrue[] = {"False", "True"};
static const char* noYes[] = {"No", "Yes"};
static const char* Fault[] = {"NOT_ACTIVE", "ACTIVE"};
//0x20A 522 HVP_contatorState
content += "<h4>Contactor Status: " + String(contactorText[datalayer_extended.tesla.status_contactor]) + "</h4>";
content += "<h4>HVIL: " + String(hvilStatusState[datalayer_extended.tesla.hvil_status]) + "</h4>";
content += content +=
"<h4>Negative contactor: " + String(contactorState[datalayer_extended.tesla.packContNegativeState]) + "</h4>"; "<h4>Negative contactor: " + String(contactorState[datalayer_extended.tesla.packContNegativeState]) + "</h4>";
content += content +=
"<h4>Positive contactor: " + String(contactorState[datalayer_extended.tesla.packContPositiveState]) + "</h4>"; "<h4>Positive contactor: " + String(contactorState[datalayer_extended.tesla.packContPositiveState]) + "</h4>";
static const char* falseTrue[] = {"False", "True"}; content +=
content += "<h4>Closing allowed?: " + String(falseTrue[datalayer_extended.tesla.packCtrsClosingAllowed]) + "</h4>"; "<h4>Closing allowed?: " + String(noYes[datalayer_extended.tesla.packCtrsClosingAllowed]) + "</h4>"; //bool
content += "<h4>Pyrotest: " + String(falseTrue[datalayer_extended.tesla.pyroTestInProgress]) + "</h4>"; content +=
"<h4>Pyrotest in Progress: " + String(noYes[datalayer_extended.tesla.pyroTestInProgress]) + "</h4>"; //bool
content += "<h4>Contactors Open Now Requested: " +
String(noYes[datalayer_extended.tesla.battery_packCtrsOpenNowRequested]) + "</h4>"; //bool
content +=
"<h4>Contactors Open Requested: " + String(noYes[datalayer_extended.tesla.battery_packCtrsOpenRequested]) +
"</h4>"; //bool
content += "<h4>Contactors Request Status: " +
String(HVP_contactor[datalayer_extended.tesla.battery_packCtrsRequestStatus]) + "</h4>";
content += "<h4>Contactors Reset Request Required: " +
String(noYes[datalayer_extended.tesla.battery_packCtrsResetRequestRequired]) + "</h4>"; //bool
content +=
"<h4>DC Link Allowed to Energize: " + String(noYes[datalayer_extended.tesla.battery_dcLinkAllowedToEnergize]) +
"</h4>"; //bool
// Comment what data you would like to dislay, order can be changed.
//0x292 658 BMS_socStates
content += "<h4>Battery Beginning of Life: " + String(beginning_of_life) + " KWh</h4>";
content += "<h4>BattTempPct: " + String(battTempPct) + " </h4>";
content += "<h4>Battery SOC Ave: " + String(soc_ave) + " </h4>";
content += "<h4>Battery SOC Max: " + String(soc_max) + " </h4>";
content += "<h4>Battery SOC Min: " + String(soc_min) + " </h4>";
content += "<h4>Battery SOC UI: " + String(soc_ui) + " </h4>";
//0x2B4 PCS_dcdcRailStatus
content += "<h4>PCS Lv Bus: " + String(dcdcLvBusVolt) + " V</h4>";
content += "<h4>PCS Hv Bus: " + String(dcdcHvBusVolt) + " V</h4>";
content += "<h4>PCS Lv Output: " + String(dcdcLvOutputCurrent) + " A</h4>";
//0x2A4 676 PCS_thermalStatus
content += "<h4>PCS dcdc Temp: " + String(PCS_dcdcTemp) + " DegC</h4>";
content += "<h4>PCS Ambient Temp: " + String(PCS_ambientTemp) + " DegC</h4>";
//0x224 548 PCS_dcdcStatus
content +=
"<h4>Precharge Status: " + String(PCS_dcdcStatus[datalayer_extended.tesla.battery_PCS_dcdcPrechargeStatus]) +
"</h4>";
content +=
"<h4>12V Support Status: " + String(PCS_dcdcStatus[datalayer_extended.tesla.battery_PCS_dcdc12VSupportStatus]) +
"</h4>";
content += "<h4>HV Bus Discharge Status: " +
String(PCS_dcdcStatus[datalayer_extended.tesla.battery_PCS_dcdcHvBusDischargeStatus]) + "</h4>";
content +=
"<h4>Main State: " + String(PCS_dcdcMainState[datalayer_extended.tesla.battery_PCS_dcdcMainState]) + "</h4>";
content +=
"<h4>Sub State: " + String(PCS_dcdcSubState[datalayer_extended.tesla.battery_PCS_dcdcSubState]) + "</h4>";
content += "<h4>PCS Faulted: " + String(Fault[datalayer_extended.tesla.battery_PCS_dcdcFaulted]) + "</h4>"; //bool
content += "<h4>Output Is Limited: " + String(Fault[datalayer_extended.tesla.battery_PCS_dcdcOutputIsLimited]) +
"</h4>"; //bool
content += "<h4>Max Output Current Allowed: " + String(PCS_dcdcMaxOutputCurrentAllowed) + " A</h4>";
content += "<h4>Precharge Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcPrechargeRtyCnt]) +
"</h4>"; //bool
content +=
"<h4>12V Support Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdc12VSupportRtyCnt]) +
"</h4>"; // bool
content += "<h4>Discharge Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcDischargeRtyCnt]) +
"</h4>"; //bool
content += "<h4>PWM Enable Line: " + String(Fault[datalayer_extended.tesla.battery_PCS_dcdcPwmEnableLine]) +
"</h4>"; //bool
content += "<h4>Supporting Fixed LV Target: " +
String(Fault[datalayer_extended.tesla.battery_PCS_dcdcSupportingFixedLvTarget]) + "</h4>"; //bool
content += "<h4>Precharge Restart Cnt: " +
String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcPrechargeRestartCnt]) + "</h4>"; //bool
content += "<h4>Initial Precharge Substate: " +
String(PCS_dcdcSubState[datalayer_extended.tesla.battery_PCS_dcdcInitialPrechargeSubState]) + "</h4>";
//0x2C4 708 PCS_logging
content += "<h4>PCS_dcdcMaxLvOutputCurrent: " + String(PCS_dcdcMaxLvOutputCurrent) + " A</h4>";
content += "<h4>PCS_dcdcCurrentLimit: " + String(PCS_dcdcCurrentLimit) + " A</h4>";
content += "<h4>PCS_dcdcLvOutputCurrentTempLimit: " + String(PCS_dcdcLvOutputCurrentTempLimit) + " A</h4>";
content += "<h4>PCS_dcdcUnifiedCommand: " + String(PCS_dcdcUnifiedCommand) + "</h4>";
content += "<h4>PCS_dcdcCLAControllerOutput: " + String(PCS_dcdcCLAControllerOutput) + "</h4>";
content += "<h4>PCS_dcdcTankVoltage: " + String(PCS_dcdcTankVoltage) + " V</h4>";
content += "<h4>PCS_dcdcTankVoltageTarget: " + String(PCS_dcdcTankVoltageTarget) + " V</h4>";
content += "<h4>PCS_dcdcClaCurrentFreq: " + String(PCS_dcdcClaCurrentFreq) + " kHz</h4>";
content += "<h4>PCS_dcdcTCommMeasured: " + String(PCS_dcdcTCommMeasured) + " us</h4>";
content += "<h4>PCS_dcdcShortTimeUs: " + String(PCS_dcdcShortTimeUs) + " us</h4>";
content += "<h4>PCS_dcdcHalfPeriodUs: " + String(PCS_dcdcHalfPeriodUs) + " us</h4>";
content += "<h4>PCS_dcdcIntervalMaxFrequency: " + String(PCS_dcdcIntervalMaxFrequency) + " kHz</h4>";
content += "<h4>PCS_dcdcIntervalMaxHvBusVolt: " + String(PCS_dcdcIntervalMaxHvBusVolt) + " V</h4>";
content += "<h4>PCS_dcdcIntervalMaxLvBusVolt: " + String(PCS_dcdcIntervalMaxLvBusVolt) + " V</h4>";
content += "<h4>PCS_dcdcIntervalMaxLvOutputCurr: " + String(PCS_dcdcIntervalMaxLvOutputCurr) + " A</h4>";
content += "<h4>PCS_dcdcIntervalMinFrequency: " + String(PCS_dcdcIntervalMinFrequency) + " kHz</h4>";
content += "<h4>PCS_dcdcIntervalMinHvBusVolt: " + String(PCS_dcdcIntervalMinHvBusVolt) + " V</h4>";
content += "<h4>PCS_dcdcIntervalMinLvBusVolt: " + String(PCS_dcdcIntervalMinLvBusVolt) + " V</h4>";
content += "<h4>PCS_dcdcIntervalMinLvOutputCurr: " + String(PCS_dcdcIntervalMinLvOutputCurr) + " A</h4>";
content += "<h4>PCS_dcdc12vSupportLifetimekWh: " + String(PCS_dcdc12vSupportLifetimekWh) + " kWh</h4>";
//0x3D2 978 BMS_kwhCounter
content += "<h4>Total Discharge: " + String(total_discharge) + " KWh</h4>";
content += "<h4>Total Charge: " + String(total_charge) + " KWh</h4>";
//0x212 530 BMS_status
content += "<h4>Isolation Resistance: " + String(isolationResistance) + " kOhms</h4>";
content +=
"<h4>BMS Contactor State: " + String(BMS_contactorState[datalayer_extended.tesla.battery_BMS_contactorState]) +
"</h4>";
content += "<h4>BMS State: " + String(BMS_state[datalayer_extended.tesla.battery_BMS_state]) + "</h4>";
content += "<h4>BMS HV State: " + String(BMS_hvState[datalayer_extended.tesla.battery_BMS_hvState]) + "</h4>";
content += "<h4>BMS UI Charge Status: " + String(BMS_uiChargeStatus[datalayer_extended.tesla.battery_BMS_hvState]) +
"</h4>";
content += "<h4>BMS PCS PWM Enabled: " + String(Fault[datalayer_extended.tesla.battery_BMS_pcsPwmEnabled]) +
"</h4>"; //bool
//0x352 850 BMS_energyStatus
content += "<h3>Early BMS 0x352:</h3>"; //if using older BMS <2021 and comment 0x352 without MUX
content += "<h4>Calculated SOH: " + String(nominal_full_pack_energy * 100 / beginning_of_life) + "</h4>";
content += "<h4>Nominal Full Pack Energy: " + String(nominal_full_pack_energy) + " KWh</h4>";
content += "<h4>Nominal Energy Remaining: " + String(nominal_energy_remaining) + " KWh</h4>";
content += "<h4>Ideal Energy Remaining: " + String(ideal_energy_remaining) + " KWh</h4>";
content += "<h4>Energy to Charge Complete: " + String(energy_to_charge_complete) + " KWh</h4>";
content += "<h4>Energy Buffer: " + String(energy_buffer) + " KWh</h4>";
content += "<h4>Full Charge Complete: " + String(noYes[datalayer_extended.tesla.battery_full_charge_complete]) +
"</h4>"; //bool
//0x352 850 BMS_energyStatus
content += "<h3>Late BMS 0x352 with Mux:</h3>"; //if using newer BMS >2021 and comment 0x352 with MUX
content += "<h4>Calculated SOH: " + String(nominal_full_pack_energy_m0 * 100 / beginning_of_life) + "</h4>";
content += "<h4>Nominal Full Pack Energy: " + String(nominal_full_pack_energy_m0) + " KWh</h4>";
content += "<h4>Nominal Energy Remaining: " + String(nominal_energy_remaining_m0) + " KWh</h4>";
content += "<h4>Ideal Energy Remaining: " + String(ideal_energy_remaining_m0) + " KWh</h4>";
content += "<h4>Energy to Charge Complete: " + String(energy_to_charge_complete_m1) + " KWh</h4>";
content += "<h4>Energy Buffer: " + String(energy_buffer_m1) + " KWh</h4>";
content += "<h4>Expected Energy Remaining: " + String(expected_energy_remaining_m1) + " KWh</h4>";
content += "<h4>Fully Charged: " + String(noYes[datalayer_extended.tesla.battery_fully_charged]) + "</h4>"; //bool
//0x392 BMS_packConfig
//content += "<h4>packConfigMultiplexer: " + String(datalayer_extended.tesla.battery_packConfigMultiplexer) + "</h4>";
//content += "<h4>moduleType: " + String(datalayer_extended.tesla.battery_moduleType) + "</h4>";
//content += "<h4>reserveConfig: " + String(datalayer_extended.tesla.battery_reservedConfig) + "</h4>";
content += "<h4>Battery Pack Mass: " + String(packMass) + " KG</h4>";
content += "<h4>Platform Max Bus Voltage: " + String(platformMaxBusVoltage) + " V</h4>";
//0x2D2 722 BMSVAlimits
content += "<h4>BMS Min Voltage: " + String(bms_min_voltage) + " V</h4>";
content += "<h4>BMS Max Voltage: " + String(bms_max_voltage) + " V</h4>";
content += "<h4>Max Charge Current: " + String(max_charge_current) + " A</h4>";
content += "<h4>Max Discharge Current: " + String(max_discharge_current) + " A</h4>";
//0x332 818 BMS_bmbMinMax
content += "<h4>Brick Voltage Max: " + String(BrickVoltageMax) + " V</h4>";
content += "<h4>Brick Voltage Min: " + String(BrickVoltageMin) + " V</h4>";
content += "<h4>Brick Temp Max Num: " + String(datalayer_extended.tesla.battery_BrickTempMaxNum) + " </h4>";
content += "<h4>Brick Temp Min Num: " + String(datalayer_extended.tesla.battery_BrickTempMinNum) + " </h4>";
content += "<h4>Brick Model Temp Max: " + String(BrickModelTMax) + " C</h4>";
content += "<h4>Brick Model Temp Min: " + String(BrickModelTMin) + " C</h4>";
//0x252 594 BMS_powerAvailable
content += "<h4>Max Regen Power: " + String(BMS_maxRegenPower) + " KW</h4>";
content += "<h4>Max Discharge Power: " + String(BMS_maxDischargePower) + " KW</h4>";
content += "<h4>Max Stationary Heat Power: " + String(BMS_maxStationaryHeatPower) + " KWh</h4>";
content += "<h4>HVAC Power Budget: " + String(BMS_hvacPowerBudget) + " KW</h4>";
content += "<h4>Not Enough Power For Heat Pump: " +
String(falseTrue[datalayer_extended.tesla.BMS_notEnoughPowerForHeatPump]) + "</h4>"; //bool
content +=
"<h4>Power Limit State: " + String(BMS_powerLimitState[datalayer_extended.tesla.BMS_powerLimitState]) + "</h4>";
content += "<h4>Inverter TQF: " + String(datalayer_extended.tesla.BMS_inverterTQF) + "</h4>";
//0x312 786 BMS_thermalStatus
content += "<h4>Power Dissipation: " + String(BMS_powerDissipation) + " kW</h4>";
content += "<h4>Flow Request: " + String(BMS_flowRequest) + " LPM</h4>";
content += "<h4>Inlet Active Cool Target Temp: " + String(BMS_inletActiveCoolTargetT) + " DegC</h4>";
content += "<h4>Inlet Passive Target Temp: " + String(BMS_inletPassiveTargetT) + " DegC</h4>";
content += "<h4>Inlet Active Heat Target Temp: " + String(BMS_inletActiveHeatTargetT) + " DegC</h4>";
content += "<h4>Pack Temp Min: " + String(BMS_packTMin) + " DegC</h4>";
content += "<h4>Pack Temp Max: " + String(BMS_packTMax) + " DegC</h4>";
content +=
"<h4>PCS No Flow Request: " + String(Fault[datalayer_extended.tesla.BMS_pcsNoFlowRequest]) + "</h4>"; //bool
content +=
"<h4>BMS No Flow Request: " + String(Fault[datalayer_extended.tesla.BMS_noFlowRequest]) + "</h4>"; //bool
//0x7AA 1962 HVP_debugMessage
content += "<h4>HVP_gpioPassivePyroDepl: " + String(Fault[datalayer_extended.tesla.HVP_gpioPassivePyroDepl]) +
"</h4>"; //bool
content += "<h4>HVP_gpioPyroIsoEn: " + String(Fault[datalayer_extended.tesla.HVP_gpioPyroIsoEn]) + "</h4>"; //bool
content += "<h4>HVP_gpioCpFaultIn: " + String(Fault[datalayer_extended.tesla.HVP_gpioCpFaultIn]) + "</h4>"; //bool
content += "<h4>HVP_gpioPackContPowerEn: " + String(Fault[datalayer_extended.tesla.HVP_gpioPackContPowerEn]) +
"</h4>"; //bool
content +=
"<h4>HVP_gpioHvCablesOk: " + String(Fault[datalayer_extended.tesla.HVP_gpioHvCablesOk]) + "</h4>"; //bool
content +=
"<h4>HVP_gpioHvpSelfEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioHvpSelfEnable]) + "</h4>"; //bool
content += "<h4>HVP_gpioLed: " + String(Fault[datalayer_extended.tesla.HVP_gpioLed]) + "</h4>"; //bool
content +=
"<h4>HVP_gpioCrashSignal: " + String(Fault[datalayer_extended.tesla.HVP_gpioCrashSignal]) + "</h4>"; //bool
content += "<h4>HVP_gpioShuntDataReady: " + String(Fault[datalayer_extended.tesla.HVP_gpioShuntDataReady]) +
"</h4>"; //bool
content +=
"<h4>HVP_gpioFcContPosAux: " + String(Fault[datalayer_extended.tesla.HVP_gpioFcContPosAux]) + "</h4>"; //bool
content +=
"<h4>HVP_gpioFcContNegAux: " + String(Fault[datalayer_extended.tesla.HVP_gpioFcContNegAux]) + "</h4>"; //bool
content += "<h4>HVP_gpioBmsEout: " + String(Fault[datalayer_extended.tesla.HVP_gpioBmsEout]) + "</h4>"; //bool
content +=
"<h4>HVP_gpioCpFaultOut: " + String(Fault[datalayer_extended.tesla.HVP_gpioCpFaultOut]) + "</h4>"; //bool
content += "<h4>HVP_gpioPyroPor: " + String(Fault[datalayer_extended.tesla.HVP_gpioPyroPor]) + "</h4>"; //bool
content += "<h4>HVP_gpioShuntEn: " + String(Fault[datalayer_extended.tesla.HVP_gpioShuntEn]) + "</h4>"; //bool
content += "<h4>HVP_gpioHvpVerEn: " + String(Fault[datalayer_extended.tesla.HVP_gpioHvpVerEn]) + "</h4>"; //bool
content +=
"<h4>HVP_gpioPackCoontPosFlywheel: " + String(Fault[datalayer_extended.tesla.HVP_gpioPackCoontPosFlywheel]) +
"</h4>"; //bool
content +=
"<h4>HVP_gpioCpLatchEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioCpLatchEnable]) + "</h4>"; //bool
content += "<h4>HVP_gpioPcsEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioPcsEnable]) + "</h4>"; //bool
content += "<h4>HVP_gpioPcsDcdcPwmEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioPcsDcdcPwmEnable]) +
"</h4>"; //bool
content += "<h4>HVP_gpioPcsChargePwmEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioPcsChargePwmEnable]) +
"</h4>"; //bool
content += "<h4>HVP_gpioFcContPowerEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioFcContPowerEnable]) +
"</h4>"; //bool
content +=
"<h4>HVP_gpioHvilEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioHvilEnable]) + "</h4>"; //bool
content += "<h4>HVP_gpioSecDrdy: " + String(Fault[datalayer_extended.tesla.HVP_gpioSecDrdy]) + "</h4>"; //bool
content += "<h4>HVP_hvp1v5Ref: " + String(HVP_hvp1v5Ref) + " V</h4>";
content += "<h4>HVP_shuntCurrentDebug: " + String(HVP_shuntCurrentDebug) + " A</h4>";
content +=
"<h4>HVP_packCurrentMia: " + String(noYes[datalayer_extended.tesla.HVP_packCurrentMia]) + "</h4>"; //bool
content += "<h4>HVP_auxCurrentMia: " + String(noYes[datalayer_extended.tesla.HVP_auxCurrentMia]) + "</h4>"; //bool
content +=
"<h4>HVP_currentSenseMia: " + String(noYes[datalayer_extended.tesla.HVP_currentSenseMia]) + "</h4>"; //bool
content +=
"<h4>HVP_shuntRefVoltageMismatch: " + String(noYes[datalayer_extended.tesla.HVP_shuntRefVoltageMismatch]) +
"</h4>"; //bool
content += "<h4>HVP_shuntThermistorMia: " + String(noYes[datalayer_extended.tesla.HVP_shuntThermistorMia]) +
"</h4>"; //bool
content += "<h4>HVP_shuntHwMia: " + String(noYes[datalayer_extended.tesla.HVP_shuntHwMia]) + "</h4>"; //bool
content += "<h4>HVP_dcLinkVoltage: " + String(HVP_dcLinkVoltage) + " V</h4>";
content += "<h4>HVP_packVoltage: " + String(HVP_packVoltage) + " V</h4>";
content += "<h4>HVP_fcLinkVoltage: " + String(HVP_fcLinkVoltage) + " V</h4>";
content += "<h4>HVP_packContVoltage: " + String(HVP_packContVoltage) + " V</h4>";
content += "<h4>HVP_packNegativeV: " + String(HVP_packNegativeV) + " V</h4>";
content += "<h4>HVP_packPositiveV: " + String(HVP_packPositiveV) + " V</h4>";
content += "<h4>HVP_pyroAnalog: " + String(HVP_pyroAnalog) + " V</h4>";
content += "<h4>HVP_dcLinkNegativeV: " + String(HVP_dcLinkNegativeV) + " V</h4>";
content += "<h4>HVP_dcLinkPositiveV: " + String(HVP_dcLinkPositiveV) + " V</h4>";
content += "<h4>HVP_fcLinkNegativeV: " + String(HVP_fcLinkNegativeV) + " V</h4>";
content += "<h4>HVP_fcContCoilCurrent: " + String(HVP_fcContCoilCurrent) + " A</h4>";
content += "<h4>HVP_fcContVoltage: " + String(HVP_fcContVoltage) + " V</h4>";
content += "<h4>HVP_hvilInVoltage: " + String(HVP_hvilInVoltage) + " V</h4>";
content += "<h4>HVP_hvilOutVoltage: " + String(HVP_hvilOutVoltage) + " V</h4>";
content += "<h4>HVP_fcLinkPositiveV: " + String(HVP_fcLinkPositiveV) + " V</h4>";
content += "<h4>HVP_packContCoilCurrent: " + String(HVP_packContCoilCurrent) + " A</h4>";
content += "<h4>HVP_battery12V: " + String(HVP_battery12V) + " V</h4>";
content += "<h4>HVP_shuntRefVoltageDbg: " + String(HVP_shuntRefVoltageDbg) + " V</h4>";
content += "<h4>HVP_shuntAuxCurrentDbg: " + String(HVP_shuntAuxCurrentDbg) + " A</h4>";
content += "<h4>HVP_shuntBarTempDbg: " + String(HVP_shuntBarTempDbg) + " DegC</h4>";
content += "<h4>HVP_shuntAsicTempDbg: " + String(HVP_shuntAsicTempDbg) + " DegC</h4>";
content +=
"<h4>HVP_shuntAuxCurrentStatus: " + String(HVP_status[datalayer_extended.tesla.HVP_shuntAuxCurrentStatus]) +
"</h4>";
content +=
"<h4>HVP_shuntBarTempStatus: " + String(HVP_status[datalayer_extended.tesla.HVP_shuntBarTempStatus]) + "</h4>";
content += "<h4>HVP_shuntAsicTempStatus: " + String(HVP_status[datalayer_extended.tesla.HVP_shuntAsicTempStatus]) +
"</h4>";
#endif #endif
#ifdef NISSAN_LEAF_BATTERY #ifdef NISSAN_LEAF_BATTERY

View file

@ -6,7 +6,7 @@
#include "../../include.h" #include "../../include.h"
#include "../../lib/YiannisBourkelis-Uptime-Library/src/uptime_formatter.h" #include "../../lib/YiannisBourkelis-Uptime-Library/src/uptime_formatter.h"
#include "../../lib/ayushsharma82-ElegantOTA/src/ElegantOTA.h" #include "../../lib/ayushsharma82-ElegantOTA/src/ElegantOTA.h"
#include "../../lib/mathieucarbou-AsyncTCP/src/AsyncTCP.h" #include "../../lib/me-no-dev-AsyncTCP/src/AsyncTCP.h"
#include "../../lib/me-no-dev-ESPAsyncWebServer/src/ESPAsyncWebServer.h" #include "../../lib/me-no-dev-ESPAsyncWebServer/src/ESPAsyncWebServer.h"
#include "../../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" #include "../../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"

View file

@ -29,12 +29,8 @@ static bool connected_once = false;
void init_WiFi() { void init_WiFi() {
#ifdef WIFIAP #ifdef WIFIAP
if (AccessPointEnabled) {
WiFi.mode(WIFI_AP_STA); // Simultaneous WiFi AP and Router connection WiFi.mode(WIFI_AP_STA); // Simultaneous WiFi AP and Router connection
init_WiFi_AP(); init_WiFi_AP();
} else {
WiFi.mode(WIFI_STA); // Only Router connection
}
#else #else
WiFi.mode(WIFI_STA); // Only Router connection WiFi.mode(WIFI_STA); // Only Router connection
#endif // WIFIAP #endif // WIFIAP

View file

@ -130,10 +130,18 @@ void update_values_can_inverter() { //This function maps all the values fetched
} }
//Error bits //Error bits
if (!datalayer.system.status.inverter_allows_contactor_closing) { if (datalayer.system.status.inverter_allows_contactor_closing) {
SMA_158.data.u8[2] = 0x6A;
} else {
SMA_158.data.u8[2] = 0xAA; SMA_158.data.u8[2] = 0xAA;
#ifdef INVERTER_CONTACTOR_ENABLE_LED_PIN
digitalWrite(INVERTER_CONTACTOR_ENABLE_LED_PIN,
HIGH); // Turn on LED to indicate that SMA inverter allows contactor closing
#endif // INVERTER_CONTACTOR_ENABLE_LED_PIN
} else {
SMA_158.data.u8[2] = 0x6A;
#ifdef INVERTER_CONTACTOR_ENABLE_LED_PIN
digitalWrite(INVERTER_CONTACTOR_ENABLE_LED_PIN,
LOW); // Turn off LED to indicate that SMA inverter allows contactor closing
#endif // INVERTER_CONTACTOR_ENABLE_LED_PIN
} }
/* /*
@ -251,10 +259,15 @@ void send_can_inverter() {
} }
} }
} }
void setup_inverter(void) { // Performs one time setup at startup over CAN bus void setup_inverter(void) { // Performs one time setup at startup over CAN bus
strncpy(datalayer.system.info.inverter_protocol, "BYD Battery-Box HVS over SMA CAN", 63); strncpy(datalayer.system.info.inverter_protocol, "BYD Battery-Box HVS over SMA CAN", 63);
datalayer.system.info.inverter_protocol[63] = '\0'; datalayer.system.info.inverter_protocol[63] = '\0';
datalayer.system.status.inverter_allows_contactor_closing = false; // The inverter needs to allow first datalayer.system.status.inverter_allows_contactor_closing = false; // The inverter needs to allow first
pinMode(INVERTER_CONTACTOR_ENABLE_PIN, INPUT); pinMode(INVERTER_CONTACTOR_ENABLE_PIN, INPUT);
#ifdef INVERTER_CONTACTOR_ENABLE_LED_PIN
pinMode(INVERTER_CONTACTOR_ENABLE_LED_PIN, OUTPUT);
digitalWrite(INVERTER_CONTACTOR_ENABLE_LED_PIN, LOW); // Turn LED off, until inverter allows contactor closing
#endif // INVERTER_CONTACTOR_ENABLE_LED_PIN
} }
#endif #endif

View file

@ -127,10 +127,18 @@ void update_values_can_inverter() { //This function maps all the values fetched
} }
//Error bits //Error bits
if (!datalayer.system.status.inverter_allows_contactor_closing) { if (datalayer.system.status.inverter_allows_contactor_closing) {
SMA_158.data.u8[2] = 0x6A;
} else {
SMA_158.data.u8[2] = 0xAA; SMA_158.data.u8[2] = 0xAA;
#ifdef INVERTER_CONTACTOR_ENABLE_LED_PIN
digitalWrite(INVERTER_CONTACTOR_ENABLE_LED_PIN,
HIGH); // Turn on LED to indicate that SMA inverter allows contactor closing
#endif // INVERTER_CONTACTOR_ENABLE_LED_PIN
} else {
SMA_158.data.u8[2] = 0x6A;
#ifdef INVERTER_CONTACTOR_ENABLE_LED_PIN
digitalWrite(INVERTER_CONTACTOR_ENABLE_LED_PIN,
LOW); // Turn off LED to indicate that SMA inverter allows contactor closing
#endif // INVERTER_CONTACTOR_ENABLE_LED_PIN
} }
/* /*
@ -253,5 +261,9 @@ void send_can_inverter() {
void setup_inverter(void) { // Performs one time setup at startup over CAN bus void setup_inverter(void) { // Performs one time setup at startup over CAN bus
strncpy(datalayer.system.info.inverter_protocol, "SMA CAN", 63); strncpy(datalayer.system.info.inverter_protocol, "SMA CAN", 63);
datalayer.system.info.inverter_protocol[63] = '\0'; datalayer.system.info.inverter_protocol[63] = '\0';
#ifdef INVERTER_CONTACTOR_ENABLE_LED_PIN
pinMode(INVERTER_CONTACTOR_ENABLE_LED_PIN, OUTPUT);
digitalWrite(INVERTER_CONTACTOR_ENABLE_LED_PIN, LOW); // Turn LED off, until inverter allows contactor closing
#endif // INVERTER_CONTACTOR_ENABLE_LED_PIN
} }
#endif #endif

View file

@ -12,317 +12,248 @@
*/ */
/* Do not change code below unless you are sure what you are doing */ /* Do not change code below unless you are sure what you are doing */
static unsigned long previousMillis500ms = 0; // will store last time a 100ms CAN Message was send static unsigned long previousMillis250ms = 0; // will store last time a 250ms CAN Message was send
static unsigned long previousMillis500ms = 0; // will store last time a 500ms CAN Message was send
static unsigned long previousMillis2s = 0; // will store last time a 2s CAN Message was send
static unsigned long previousMillis10s = 0; // will store last time a 10s CAN Message was send
static unsigned long previousMillis60s = 0; // will store last time a 60s CAN Message was send
//Actual content messages typedef struct {
CAN_frame SMA_00D = {.FD = false, CAN_frame* frame;
.ext_ID = false, void (*callback)();
.DLC = 8, } Frame;
.ID = 0x00D,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame SMA_00F = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x00F,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame SMA_011 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x011,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame SMA_013 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x013,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame SMA_014 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x014,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame SMA_005 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x005,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame SMA_007 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x007,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame SMA_006 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x006,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame SMA_008 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x008,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame SMA_015 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x015,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame SMA_016 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x016,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame SMA_017 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x017,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame SMA_018 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x018,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
static unsigned short listLength = 0;
static Frame framesToSend[20];
static uint32_t inverter_time = 0;
static uint16_t inverter_voltage = 0;
static int16_t inverter_current = 0;
static bool pairing_completed = false;
static int16_t temperature_average = 0; static int16_t temperature_average = 0;
static uint16_t ampere_hours_remaining = 0; static uint16_t ampere_hours_remaining = 0;
static uint16_t ampere_hours_max = 0;
static bool batteryAlarm = false;
static bool BMSevent = false;
enum BatteryState { NA, INIT, BAT_STANDBY, OPERATE, WARNING, FAULTED, UPDATE, BAT_UPDATE }; //Actual content messages
BatteryState batteryState = OPERATE; CAN_frame SMA_558 = {.FD = false, //Pairing first message
enum InverterControlFlags { .ext_ID = false,
EMG_CHARGE_REQUEST, .DLC = 8,
EMG_DISCHARGE_REQUEST, .ID = 0x558, // BYD HVS 10.2 kWh (0x66 might be kWh)
NOT_ENOUGH_ENERGY_FOR_START, .data = {0x03, 0x24, 0x00, 0x04, 0x00, 0x66, 0x04, 0x09}}; //Amount of modules? Vendor ID?
INVERTER_STAY_ON, CAN_frame SMA_598 = {.FD = false,
FORCED_BATTERY_SHUTDOWN, .ext_ID = false,
RESERVED, .DLC = 8,
BATTERY_UPDATE_AVAILABLE, .ID = 0x598,
NO_BATTERY_UPDATED_BY_INV .data = {0x12, 0xD6, 0x43, 0xA4, 0x00, 0x00, 0x00, 0x00}}; //B0-4 Serial 301100932
}; CAN_frame SMA_5D8 = {.FD = false,
InverterControlFlags inverterControlFlags = BATTERY_UPDATE_AVAILABLE; .ext_ID = false,
enum Events0 { .DLC = 8,
START_SOC_CALIBRATE, .ID = 0x5D8,
STOP_SOC_CALIBRATE, .data = {0x00, 0x42, 0x59, 0x44, 0x00, 0x00, 0x00, 0x00}}; //B Y D
START_POWERLIMIT, CAN_frame SMA_618_0 = {.FD = false,
STOP_POWERLIMIT, .ext_ID = false,
PREVENTATIVE_BAT_SHUTDOWN, .DLC = 8,
THERMAL_MANAGEMENT, .ID = 0x618,
START_BALANCING, .data = {0x00, 0x42, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79}}; //BATTERY
STOP_BALANCING CAN_frame SMA_618_1 = {.FD = false,
}; .ext_ID = false,
Events0 events0 = START_BALANCING; .DLC = 8,
enum Events1 { START_BATTERY_SELFTEST, STOP_BATTERY_SELFTEST }; .ID = 0x618,
Events1 events1 = START_BATTERY_SELFTEST; .data = {0x01, 0x2D, 0x42, 0x6F, 0x78, 0x20, 0x50, 0x72}}; //-Box Pr
enum Command2Battery { IDLE, RUN, NOT_USED1, NOT_USED2, SHUTDOWN, FIRMWARE_UPDATE, BATSELFUPDATE, NOT_USED3 }; CAN_frame SMA_618_2 = {.FD = false,
Command2Battery command2Battery = RUN; .ext_ID = false,
enum InvInitState { SYSTEM_FREQUENCY, XPHASE_SYSTEM, BLACKSTART_OPERATION }; .DLC = 8,
InvInitState invInitState = SYSTEM_FREQUENCY; .ID = 0x618,
.data = {0x02, 0x65, 0x6D, 0x69, 0x75, 0x6D, 0x20, 0x48}}; //emium H
CAN_frame SMA_618_3 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x618,
.data = {0x03, 0x56, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00}}; //VS
CAN_frame SMA_358 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x358,
.data = {0x12, 0x40, 0x0C, 0x80, 0x01, 0x00, 0x01, 0x00}};
CAN_frame SMA_3D8 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x3D8,
.data = {0x04, 0x06, 0x27, 0x10, 0x00, 0x19, 0x00, 0xFA}};
CAN_frame SMA_458 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x458,
.data = {0x00, 0x00, 0x73, 0xAE, 0x00, 0x00, 0x64, 0x64}};
CAN_frame SMA_4D8 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x4D8,
.data = {0x10, 0x62, 0x00, 0x00, 0x00, 0x78, 0x02, 0x08}};
CAN_frame SMA_518 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x518,
.data = {0x00, 0x96, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00}};
void update_values_can_inverter() { //This function maps all the values fetched from battery CAN to the inverter CAN void update_values_can_inverter() { //This function maps all the values fetched from battery CAN to the inverter CAN
//Calculate values // Update values
temperature_average = temperature_average =
((datalayer.battery.status.temperature_max_dC + datalayer.battery.status.temperature_min_dC) / 2); ((datalayer.battery.status.temperature_max_dC + datalayer.battery.status.temperature_min_dC) / 2);
if (datalayer.battery.status.voltage_dV > 10) { // Only update value when we have voltage available to avoid div0
ampere_hours_remaining = ampere_hours_remaining =
((datalayer.battery.status.reported_remaining_capacity_Wh / datalayer.battery.status.voltage_dV) * ((datalayer.battery.status.reported_remaining_capacity_Wh / datalayer.battery.status.voltage_dV) *
100); //(WH[10000] * V+1[3600])*100 = 270 (27.0Ah) 100); //(WH[10000] * V+1[3600])*100 = 270 (27.0Ah)
ampere_hours_max = ((datalayer.battery.info.total_capacity_Wh / datalayer.battery.status.voltage_dV) * }
100); //(WH[10000] * V+1[3600])*100 = 270 (27.0Ah)
batteryState = OPERATE;
inverterControlFlags = INVERTER_STAY_ON;
//Map values to CAN messages //Map values to CAN messages
// Battery Limits
//Battery Max Charge Voltage (eg 400.0V = 4000 , 16bits long) //Maxvoltage (eg 400.0V = 4000 , 16bits long)
SMA_00D.data.u8[0] = (datalayer.battery.info.max_design_voltage_dV >> 8); SMA_358.data.u8[0] = (datalayer.battery.info.max_design_voltage_dV >> 8);
SMA_00D.data.u8[1] = (datalayer.battery.info.max_design_voltage_dV & 0x00FF); SMA_358.data.u8[1] = (datalayer.battery.info.max_design_voltage_dV & 0x00FF);
//Battery Min Discharge Voltage (eg 300.0V = 3000 , 16bits long) //Minvoltage (eg 300.0V = 3000 , 16bits long)
SMA_00D.data.u8[2] = (datalayer.battery.info.min_design_voltage_dV >> 8); SMA_358.data.u8[2] = (datalayer.battery.info.min_design_voltage_dV >> 8);
SMA_00D.data.u8[3] = (datalayer.battery.info.min_design_voltage_dV & 0x00FF); SMA_358.data.u8[3] = (datalayer.battery.info.min_design_voltage_dV & 0x00FF);
//Discharge limited current, 500 = 50A, (0.1, A) //Discharge limited current, 500 = 50A, (0.1, A)
SMA_00D.data.u8[4] = (datalayer.battery.status.max_discharge_current_dA >> 8); SMA_358.data.u8[4] = (datalayer.battery.status.max_discharge_current_dA >> 8);
SMA_00D.data.u8[5] = (datalayer.battery.status.max_discharge_current_dA & 0x00FF); SMA_358.data.u8[5] = (datalayer.battery.status.max_discharge_current_dA & 0x00FF);
//Charge limited current, 125 =12.5A (0.1, A) //Charge limited current, 125 =12.5A (0.1, A)
SMA_00D.data.u8[6] = (datalayer.battery.status.max_charge_current_dA >> 8); SMA_358.data.u8[6] = (datalayer.battery.status.max_charge_current_dA >> 8);
SMA_00D.data.u8[7] = (datalayer.battery.status.max_charge_current_dA & 0x00FF); SMA_358.data.u8[7] = (datalayer.battery.status.max_charge_current_dA & 0x00FF);
// Battery State
//SOC (100.00%) //SOC (100.00%)
SMA_00F.data.u8[0] = (datalayer.battery.status.reported_soc >> 8); SMA_3D8.data.u8[0] = (datalayer.battery.status.reported_soc >> 8);
SMA_00F.data.u8[1] = (datalayer.battery.status.reported_soc & 0x00FF); SMA_3D8.data.u8[1] = (datalayer.battery.status.reported_soc & 0x00FF);
//StateOfHealth (100.00%) //StateOfHealth (100.00%)
SMA_00F.data.u8[2] = (datalayer.battery.status.soh_pptt >> 8); SMA_3D8.data.u8[2] = (datalayer.battery.status.soh_pptt >> 8);
SMA_00F.data.u8[3] = (datalayer.battery.status.soh_pptt & 0x00FF); SMA_3D8.data.u8[3] = (datalayer.battery.status.soh_pptt & 0x00FF);
//State of charge (AH, 0.1) //State of charge (AH, 0.1)
SMA_00F.data.u8[4] = (ampere_hours_remaining >> 8); SMA_3D8.data.u8[4] = (ampere_hours_remaining >> 8);
SMA_00F.data.u8[5] = (ampere_hours_remaining & 0x00FF); SMA_3D8.data.u8[5] = (ampere_hours_remaining & 0x00FF);
//Fully charged (AH, 0.1)
SMA_00F.data.u8[6] = (ampere_hours_max >> 8);
SMA_00F.data.u8[7] = (ampere_hours_max & 0x00FF);
// Battery Energy
//Charged Energy Counter TODO: are these needed?
//SMA_011.data.u8[0] = (X >> 8);
//SMA_011.data.u8[1] = (X & 0x00FF);
//SMA_011.data.u8[2] = (X >> 8);
//SMA_011.data.u8[3] = (X & 0x00FF);
//Discharged Energy Counter TODO: are these needed?
//SMA_011.data.u8[4] = (X >> 8);
//SMA_011.data.u8[5] = (X & 0x00FF);
//SMA_011.data.u8[6] = (X >> 8);
//SMA_011.data.u8[7] = (X & 0x00FF);
// Battery Measurements
//Voltage (370.0) //Voltage (370.0)
SMA_013.data.u8[0] = (datalayer.battery.status.voltage_dV >> 8); SMA_4D8.data.u8[0] = (datalayer.battery.status.voltage_dV >> 8);
SMA_013.data.u8[1] = (datalayer.battery.status.voltage_dV & 0x00FF); SMA_4D8.data.u8[1] = (datalayer.battery.status.voltage_dV & 0x00FF);
//Current (TODO: signed OK?) //Current (TODO: signed OK?)
SMA_013.data.u8[2] = (datalayer.battery.status.current_dA >> 8); SMA_4D8.data.u8[2] = (datalayer.battery.status.current_dA >> 8);
SMA_013.data.u8[3] = (datalayer.battery.status.current_dA & 0x00FF); SMA_4D8.data.u8[3] = (datalayer.battery.status.current_dA & 0x00FF);
//Temperature average //Temperature average
SMA_013.data.u8[4] = (temperature_average >> 8); SMA_4D8.data.u8[4] = (temperature_average >> 8);
SMA_013.data.u8[5] = (temperature_average & 0x00FF); SMA_4D8.data.u8[5] = (temperature_average & 0x00FF);
//Battery state //Battery ready
SMA_013.data.u8[6] = batteryState; if (datalayer.battery.status.bms_status == FAULT) {
SMA_013.data.u8[6] = inverterControlFlags; SMA_4D8.data.u8[6] = STOP_STATE;
} else {
// Battery Temperature and Cellvoltages SMA_4D8.data.u8[6] = READY_STATE;
// Battery max temperature }
SMA_014.data.u8[0] = (datalayer.battery.status.temperature_max_dC >> 8);
SMA_014.data.u8[1] = (datalayer.battery.status.temperature_max_dC & 0x00FF);
// Battery min temperature
SMA_014.data.u8[2] = (datalayer.battery.status.temperature_min_dC >> 8);
SMA_014.data.u8[3] = (datalayer.battery.status.temperature_min_dC & 0x00FF);
// Battery Cell Voltage (sum)
//SMA_014.data.u8[4] = (??? >> 8); //TODO scaling?
//SMA_014.data.u8[5] = (??? & 0x00FF); //TODO scaling?
// Cell voltage min
//SMA_014.data.u8[6] = (??? >> 8); //TODO scaling? 0-255
// Cell voltage max
//SMA_014.data.u8[7] = (??? >> 8); //TODO scaling? 0-255
//SMA_006.data.u8[0] = (ErrorCode >> 8);
//SMA_006.data.u8[1] = (ErrorCode & 0x00FF);
//SMA_006.data.u8[2] = ModuleNumber;
//SMA_006.data.u8[3] = ErrorLevel;
//SMA_008.data.u8[0] = Events0;
//SMA_008.data.u8[1] = Events1;
//SMA_005.data.u8[0] = BMSalarms0;
//SMA_005.data.u8[1] = BMSalarms1;
//SMA_005.data.u8[2] = BMSalarms2;
//SMA_005.data.u8[3] = BMSalarms3;
//SMA_005.data.u8[4] = BMSalarms4;
//SMA_005.data.u8[5] = BMSalarms5;
//SMA_005.data.u8[6] = BMSalarms6;
//SMA_005.data.u8[7] = BMSalarms7;
//SMA_007.data.u8[0] = DCDCalarms0;
//SMA_007.data.u8[1] = DCDCalarms1;
//SMA_007.data.u8[2] = DCDCalarms2;
//SMA_007.data.u8[3] = DCDCalarms3;
//SMA_007.data.u8[4] = DCDCwarnings0;
//SMA_007.data.u8[5] = DCDCwarnings1;
//SMA_007.data.u8[6] = DCDCwarnings2;
//SMA_007.data.u8[7] = DCDCwarnings3;
//SMA_015.data.u8[0] = BatterySystemVersion;
//SMA_015.data.u8[1] = BatterySystemVersion;
//SMA_015.data.u8[2] = BatterySystemVersion;
//SMA_015.data.u8[3] = BatterySystemVersion;
//SMA_015.data.u8[4] = BatteryCapacity;
//SMA_015.data.u8[5] = BatteryCapacity;
//SMA_015.data.u8[6] = NumberOfModules;
//SMA_015.data.u8[7] = BatteryManufacturerID;
//SMA_016.data.u8[0] = SerialNumber;
//SMA_016.data.u8[1] = SerialNumber;
//SMA_016.data.u8[2] = SerialNumber;
//SMA_016.data.u8[3] = SerialNumber;
//SMA_016.data.u8[4] = ManufacturingDate;
//SMA_016.data.u8[5] = ManufacturingDate;
//SMA_016.data.u8[6] = ManufacturingDate;
//SMA_016.data.u8[7] = ManufacturingDate;
//SMA_017.data.u8[0] = Multiplex;
//SMA_017.data.u8[1] = ManufacturerName;
//SMA_017.data.u8[2] = ManufacturerName;
//SMA_017.data.u8[3] = ManufacturerName;
//SMA_017.data.u8[4] = ManufacturerName;
//SMA_017.data.u8[5] = ManufacturerName;
//SMA_017.data.u8[6] = ManufacturerName;
//SMA_017.data.u8[7] = ManufacturerName;
//SMA_018.data.u8[0] = Multiplex;
//SMA_018.data.u8[1] = BatteryName;
//SMA_018.data.u8[2] = BatteryName;
//SMA_018.data.u8[3] = BatteryName;
//SMA_018.data.u8[4] = BatteryName;
//SMA_018.data.u8[5] = BatteryName;
//SMA_018.data.u8[6] = BatteryName;
//SMA_018.data.u8[7] = BatteryName;
} }
void receive_can_inverter(CAN_frame rx_frame) { void receive_can_inverter(CAN_frame rx_frame) {
switch (rx_frame.ID) { switch (rx_frame.ID) {
case 0x00D: //Inverter Measurements case 0x360: //Message originating from SMA inverter - Voltage and current
datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE;
inverter_voltage = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1];
inverter_current = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
break;
case 0x3E0: //Message originating from SMA inverter - ?
datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE;
break; break;
case 0x00F: //Inverter Feedback case 0x420: //Message originating from SMA inverter - Timestamp
datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE;
inverter_time =
(rx_frame.data.u8[0] << 24) | (rx_frame.data.u8[1] << 16) | (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
break;
case 0x560: //Message originating from SMA inverter - Init
datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE;
break; break;
case 0x010: //Time from inverter case 0x5E0: //Message originating from SMA inverter - String
datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE;
//Inverter brand (frame1-3 = 0x53 0x4D 0x41) = SMA
break; break;
case 0x015: //Initialization message from inverter case 0x660: //Message originating from SMA inverter - Pairing request
datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE;
send_tripower_init(); send_tripower_init();
break; break;
case 0x017: //Initialization message from inverter 2
datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE;
//send_tripower_init();
break;
default: default:
break; break;
} }
} }
void pushFrame(CAN_frame* frame, void (*callback)() = NULL) {
if (listLength >= 20) {
return; //TODO: scream.
}
framesToSend[listLength] = {
.frame = frame,
.callback = callback,
};
listLength++;
}
void send_can_inverter() { void send_can_inverter() {
unsigned long currentMillis = millis(); unsigned long currentMillis = millis();
// Send CAN Message every 500ms // Send CAN Message only if we're enabled by inverter
if (currentMillis - previousMillis500ms >= INTERVAL_500_MS) { if (!datalayer.system.status.inverter_allows_contactor_closing) {
previousMillis500ms = currentMillis; return;
transmit_can(&SMA_00D, can_config.inverter); //Battery limits
transmit_can(&SMA_00F, can_config.inverter); // Battery state
transmit_can(&SMA_011, can_config.inverter); // Battery Energy
transmit_can(&SMA_013, can_config.inverter); // Battery Measurements
transmit_can(&SMA_014, can_config.inverter); // Battery Temperatures and cellvoltages
} }
if (batteryAlarm) { //Non-cyclic if (listLength > 0 && currentMillis - previousMillis250ms >= INTERVAL_250_MS) {
transmit_can(&SMA_005, can_config.inverter); // Battery Alarms 1 previousMillis250ms = currentMillis;
transmit_can(&SMA_007, can_config.inverter); // Battery Alarms 2 // Send next frame.
Frame frame = framesToSend[0];
transmit_can(frame.frame, can_config.inverter);
if (frame.callback != NULL) {
frame.callback();
}
for (int i = 0; i < listLength - 1; i++) {
framesToSend[i] = framesToSend[i + 1];
}
listLength--;
} }
if (BMSevent) { //Non-cyclic if (!pairing_completed) {
transmit_can(&SMA_006, can_config.inverter); // Battery Errorcode return;
transmit_can(&SMA_008, can_config.inverter); // Battery Events }
// Send CAN Message every 2s
if (currentMillis - previousMillis2s >= INTERVAL_2_S) {
previousMillis2s = currentMillis;
pushFrame(&SMA_358);
}
// Send CAN Message every 10s
if (currentMillis - previousMillis10s >= INTERVAL_10_S) {
previousMillis10s = currentMillis;
pushFrame(&SMA_518);
pushFrame(&SMA_4D8);
pushFrame(&SMA_3D8);
} }
} }
void completePairing() {
pairing_completed = true;
}
void send_tripower_init() { void send_tripower_init() {
transmit_can(&SMA_015, can_config.inverter); // Battery Data 1 listLength = 0; // clear all frames
transmit_can(&SMA_016, can_config.inverter); // Battery Data 2
transmit_can(&SMA_017, can_config.inverter); // Battery Manufacturer pushFrame(&SMA_558); //Pairing start - Vendor
transmit_can(&SMA_018, can_config.inverter); // Battery Name pushFrame(&SMA_598); //Serial
pushFrame(&SMA_5D8); //BYD
pushFrame(&SMA_618_0); //BATTERY
pushFrame(&SMA_618_1); //-Box Pr
pushFrame(&SMA_618_2); //emium H
pushFrame(&SMA_618_3); //VS
pushFrame(&SMA_358);
pushFrame(&SMA_3D8);
pushFrame(&SMA_458);
pushFrame(&SMA_4D8);
pushFrame(&SMA_518, completePairing);
} }
void setup_inverter(void) { // Performs one time setup at startup over CAN bus void setup_inverter(void) { // Performs one time setup at startup over CAN bus
strncpy(datalayer.system.info.inverter_protocol, "SMA Tripower CAN", 63); strncpy(datalayer.system.info.inverter_protocol, "SMA Tripower CAN", 63);
datalayer.system.info.inverter_protocol[63] = '\0'; datalayer.system.info.inverter_protocol[63] = '\0';
datalayer.system.status.inverter_allows_contactor_closing = false; // The inverter needs to allow first
pinMode(INVERTER_CONTACTOR_ENABLE_PIN, INPUT);
} }
#endif #endif

View file

@ -4,6 +4,9 @@
#define CAN_INVERTER_SELECTED #define CAN_INVERTER_SELECTED
#define READY_STATE 0x03
#define STOP_STATE 0x02
void send_tripower_init(); void send_tripower_init();
void transmit_can(CAN_frame* tx_frame, int interface); void transmit_can(CAN_frame* tx_frame, int interface);
void setup_inverter(void); void setup_inverter(void);

View file

@ -68,7 +68,7 @@ CAN_frame SOLAX_187E = {.FD = false, //Needed for Ultra
.ext_ID = true, .ext_ID = true,
.DLC = 8, .DLC = 8,
.ID = 0x187E, .ID = 0x187E,
.data = {0x0, 0x2D, 0x0, 0x0, 0x0, 0x5F, 0x0, 0x0}}; .data = {0x60, 0xEA, 0x0, 0x0, 0x64, 0x0, 0x0, 0x0}};
CAN_frame SOLAX_187D = {.FD = false, //Needed for Ultra CAN_frame SOLAX_187D = {.FD = false, //Needed for Ultra
.ext_ID = true, .ext_ID = true,
.DLC = 8, .DLC = 8,
@ -88,7 +88,7 @@ CAN_frame SOLAX_187A = {.FD = false, //Needed for Ultra
.ext_ID = true, .ext_ID = true,
.DLC = 8, .DLC = 8,
.ID = 0x187A, .ID = 0x187A,
.data = {0x01, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; .data = {0x01, 0x50, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
CAN_frame SOLAX_1881 = {.FD = false, CAN_frame SOLAX_1881 = {.FD = false,
.ext_ID = true, .ext_ID = true,
.DLC = 8, .DLC = 8,
@ -190,6 +190,13 @@ void update_values_can_inverter() { //This function maps all the values fetched
SOLAX_1801.data.u8[0] = 2; SOLAX_1801.data.u8[0] = 2;
SOLAX_1801.data.u8[2] = 1; SOLAX_1801.data.u8[2] = 1;
SOLAX_1801.data.u8[4] = 1; SOLAX_1801.data.u8[4] = 1;
//Ultra messages
SOLAX_187E.data.u8[0] = (uint8_t)capped_remaining_capacity_Wh;
SOLAX_187E.data.u8[1] = (capped_remaining_capacity_Wh >> 8);
SOLAX_187E.data.u8[2] = 0;
SOLAX_187E.data.u8[3] = 0;
SOLAX_187E.data.u8[5] = (uint8_t)(datalayer.battery.status.reported_soc / 100);
} }
void send_can_inverter() { void send_can_inverter() {
@ -212,7 +219,9 @@ void receive_can_inverter(CAN_frame rx_frame) {
#endif #endif
datalayer.system.status.inverter_allows_contactor_closing = false; datalayer.system.status.inverter_allows_contactor_closing = false;
SOLAX_1875.data.u8[4] = (0x00); // Inform Inverter: Contactor 0=off, 1=on. SOLAX_1875.data.u8[4] = (0x00); // Inform Inverter: Contactor 0=off, 1=on.
for (int i = 0; i <= number_of_batteries; i++) { for (uint8_t i = 0; i <= number_of_batteries; i++) {
transmit_can(&SOLAX_187E, can_config.inverter);
transmit_can(&SOLAX_187A, can_config.inverter);
transmit_can(&SOLAX_1872, can_config.inverter); transmit_can(&SOLAX_1872, can_config.inverter);
transmit_can(&SOLAX_1873, can_config.inverter); transmit_can(&SOLAX_1873, can_config.inverter);
transmit_can(&SOLAX_1874, can_config.inverter); transmit_can(&SOLAX_1874, can_config.inverter);
@ -230,6 +239,8 @@ void receive_can_inverter(CAN_frame rx_frame) {
case (WAITING_FOR_CONTACTOR): case (WAITING_FOR_CONTACTOR):
SOLAX_1875.data.u8[4] = (0x00); // Inform Inverter: Contactor 0=off, 1=on. SOLAX_1875.data.u8[4] = (0x00); // Inform Inverter: Contactor 0=off, 1=on.
transmit_can(&SOLAX_187E, can_config.inverter);
transmit_can(&SOLAX_187A, can_config.inverter);
transmit_can(&SOLAX_1872, can_config.inverter); transmit_can(&SOLAX_1872, can_config.inverter);
transmit_can(&SOLAX_1873, can_config.inverter); transmit_can(&SOLAX_1873, can_config.inverter);
transmit_can(&SOLAX_1874, can_config.inverter); transmit_can(&SOLAX_1874, can_config.inverter);
@ -247,6 +258,8 @@ void receive_can_inverter(CAN_frame rx_frame) {
case (CONTACTOR_CLOSED): case (CONTACTOR_CLOSED):
datalayer.system.status.inverter_allows_contactor_closing = true; datalayer.system.status.inverter_allows_contactor_closing = true;
SOLAX_1875.data.u8[4] = (0x01); // Inform Inverter: Contactor 0=off, 1=on. SOLAX_1875.data.u8[4] = (0x01); // Inform Inverter: Contactor 0=off, 1=on.
transmit_can(&SOLAX_187E, can_config.inverter);
transmit_can(&SOLAX_187A, can_config.inverter);
transmit_can(&SOLAX_1872, can_config.inverter); transmit_can(&SOLAX_1872, can_config.inverter);
transmit_can(&SOLAX_1873, can_config.inverter); transmit_can(&SOLAX_1873, can_config.inverter);
transmit_can(&SOLAX_1874, can_config.inverter); transmit_can(&SOLAX_1874, can_config.inverter);
@ -281,12 +294,5 @@ void setup_inverter(void) { // Performs one time setup at startup
strncpy(datalayer.system.info.inverter_protocol, "SolaX Triple Power LFP over CAN bus", 63); strncpy(datalayer.system.info.inverter_protocol, "SolaX Triple Power LFP over CAN bus", 63);
datalayer.system.info.inverter_protocol[63] = '\0'; datalayer.system.info.inverter_protocol[63] = '\0';
datalayer.system.status.inverter_allows_contactor_closing = false; // The inverter needs to allow first datalayer.system.status.inverter_allows_contactor_closing = false; // The inverter needs to allow first
// Sending these messages once towards the inverter makes SOC% work on the Ultra variant
transmit_can(&SOLAX_187E, can_config.inverter);
transmit_can(&SOLAX_187D, can_config.inverter);
transmit_can(&SOLAX_187C, can_config.inverter);
transmit_can(&SOLAX_187B, can_config.inverter);
transmit_can(&SOLAX_187A, can_config.inverter);
} }
#endif #endif

View file

@ -64,7 +64,7 @@ _____ _ _ ___ _____ _
#include "Update.h" #include "Update.h"
#include "StreamString.h" #include "StreamString.h"
#if ELEGANTOTA_USE_ASYNC_WEBSERVER == 1 #if ELEGANTOTA_USE_ASYNC_WEBSERVER == 1
#include "../../mathieucarbou-AsyncTCP/src/AsyncTCP.h" #include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h"
#include "../../me-no-dev-ESPAsyncWebServer/src/ESPAsyncWebServer.h" #include "../../me-no-dev-ESPAsyncWebServer/src/ESPAsyncWebServer.h"
#define ELEGANTOTA_WEBSERVER AsyncWebServer #define ELEGANTOTA_WEBSERVER AsyncWebServer
#else #else

View file

@ -1,129 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
https://sidweb.nl/cms3/en/contact.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

View file

@ -1,62 +0,0 @@
# AsyncTCP
[![License: LGPL 3.0](https://img.shields.io/badge/License-LGPL%203.0-yellow.svg)](https://opensource.org/license/lgpl-3-0/)
[![Continuous Integration](https://github.com/mathieucarbou/AsyncTCP/actions/workflows/ci.yml/badge.svg)](https://github.com/mathieucarbou/AsyncTCP/actions/workflows/ci.yml)
[![PlatformIO Registry](https://badges.registry.platformio.org/packages/mathieucarbou/library/AsyncTCP.svg)](https://registry.platformio.org/libraries/mathieucarbou/AsyncTCP)
A fork of the [AsyncTCP](https://github.com/me-no-dev/AsyncTCP) library by [@me-no-dev](https://github.com/me-no-dev).
### Async TCP Library for ESP32 Arduino
This is a fully asynchronous TCP library, aimed at enabling trouble-free, multi-connection network environment for Espressif's ESP32 MCUs.
This library is the base for [ESPAsyncWebServer](https://github.com/mathieucarbou/ESPAsyncWebServer)
## AsyncClient and AsyncServer
The base classes on which everything else is built. They expose all possible scenarios, but are really raw and require more skills to use.
## Changes in this fork
- Based on [ESPHome fork](https://github.com/esphome/AsyncTCP)
- `library.properties` for Arduino IDE users
- Add `CONFIG_ASYNC_TCP_MAX_ACK_TIME`
- Add `CONFIG_ASYNC_TCP_PRIORITY`
- Add `CONFIG_ASYNC_TCP_QUEUE_SIZE`
- Add `setKeepAlive()`
- Arduino 3 / ESP-IDF 5 compatibility
- Better CI
- Better example
- Customizable macros
- Fix for "Required to lock TCPIP core functionality". Ref: https://github.com/mathieucarbou/AsyncTCP/issues/27 and https://github.com/espressif/arduino-esp32/issues/10526
- Fix for "ack timeout 4" client disconnects.
- Fix from https://github.com/me-no-dev/AsyncTCP/pull/173 (partially applied)
- Fix from https://github.com/me-no-dev/AsyncTCP/pull/184
- IPv6
- LIBRETINY support
- LibreTuya
- Reduce logging of non critical messages
- Use IPADDR6_INIT() macro to set connecting IPv6 address
- xTaskCreateUniversal function
## Coordinates
```
mathieucarbou/AsyncTCP @ ^3.3.1
```
## Important recommendations
Most of the crashes are caused by improper configuration of the library for the project.
Here are some recommendations to avoid them.
I personally use the following configuration in my projects:
```c++
-D CONFIG_ASYNC_TCP_MAX_ACK_TIME=5000 // (keep default)
-D CONFIG_ASYNC_TCP_PRIORITY=10 // (keep default)
-D CONFIG_ASYNC_TCP_QUEUE_SIZE=64 // (keep default)
-D CONFIG_ASYNC_TCP_RUNNING_CORE=1 // force async_tcp task to be on same core as the app (default is core 0)
-D CONFIG_ASYNC_TCP_STACK_SIZE=4096 // reduce the stack size (default is 16K)
```

View file

@ -1,38 +0,0 @@
{
"name": "AsyncTCP",
"version": "3.3.1",
"description": "Asynchronous TCP Library for ESP32",
"keywords": "async,tcp",
"repository": {
"type": "git",
"url": "https://github.com/mathieucarbou/AsyncTCP.git"
},
"authors": [
{
"name": "Hristo Gochkov"
},
{
"name": "Mathieu Carbou",
"maintainer": true
}
],
"license": "LGPL-3.0",
"frameworks": "arduino",
"platforms": [
"espressif32",
"libretiny"
],
"build": {
"libCompatMode": 2
},
"export": {
"include": [
"examples",
"src",
"library.json",
"library.properties",
"LICENSE",
"README.md"
]
}
}

View file

@ -1,10 +0,0 @@
name=Async TCP
includes=AsyncTCP.h
version=3.3.1
author=Me-No-Dev
maintainer=Mathieu Carbou <mathieu.carbou@gmail.com>
sentence=Async TCP Library for ESP32
paragraph=Async TCP Library for ESP32
category=Other
url=https://github.com/mathieucarbou/AsyncTCP.git
architectures=*

View file

@ -1,43 +0,0 @@
[platformio]
default_envs = arduino-2, arduino-3, arduino-310
lib_dir = .
src_dir = examples/Client
[env]
framework = arduino
build_flags =
-Wall -Wextra
-D CONFIG_ASYNC_TCP_MAX_ACK_TIME=5000
-D CONFIG_ASYNC_TCP_PRIORITY=10
-D CONFIG_ASYNC_TCP_QUEUE_SIZE=64
-D CONFIG_ASYNC_TCP_RUNNING_CORE=1
-D CONFIG_ASYNC_TCP_STACK_SIZE=4096
-D CONFIG_ARDUHAL_LOG_COLORS
-D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
upload_protocol = esptool
monitor_speed = 115200
monitor_filters = esp32_exception_decoder, log2file
board = esp32dev
[env:arduino-2]
platform = espressif32@6.9.0
[env:arduino-3]
platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.05/platform-espressif32.zip
[env:arduino-310]
platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.10-rc3/platform-espressif32.zip
; CI
[env:ci-arduino-2]
platform = espressif32@6.9.0
board = ${sysenv.PIO_BOARD}
[env:ci-arduino-3]
platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.05/platform-espressif32.zip
board = ${sysenv.PIO_BOARD}
[env:ci-arduino-310]
platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.10-rc3/platform-espressif32.zip
board = ${sysenv.PIO_BOARD}

File diff suppressed because it is too large Load diff

View file

@ -1,347 +0,0 @@
/*
Asynchronous TCP library for Espressif MCUs
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef ASYNCTCP_H_
#define ASYNCTCP_H_
#define ASYNCTCP_VERSION "3.3.1"
#define ASYNCTCP_VERSION_MAJOR 3
#define ASYNCTCP_VERSION_MINOR 3
#define ASYNCTCP_VERSION_REVISION 1
#define ASYNCTCP_FORK_mathieucarbou
#include "../../../devboard/hal/hal.h"
#include "../../../system_settings.h"
#include "IPAddress.h"
#if ESP_IDF_VERSION_MAJOR < 5
#include "IPv6Address.h"
#endif
#include "lwip/ip6_addr.h"
#include "lwip/ip_addr.h"
#include <functional>
#ifndef LIBRETINY
#include "sdkconfig.h"
extern "C" {
#include "freertos/semphr.h"
#include "lwip/pbuf.h"
}
#else
extern "C" {
#include <lwip/pbuf.h>
#include <semphr.h>
}
#define CONFIG_ASYNC_TCP_RUNNING_CORE WIFI_CORE
#endif
// If core is not defined, then we are running in Arduino or PIO
#ifndef CONFIG_ASYNC_TCP_RUNNING_CORE
#define CONFIG_ASYNC_TCP_RUNNING_CORE WIFI_CORE
#endif
// guard AsyncTCP task with watchdog
#ifndef CONFIG_ASYNC_TCP_USE_WDT
#define CONFIG_ASYNC_TCP_USE_WDT 0
#endif
#ifndef CONFIG_ASYNC_TCP_STACK_SIZE
#define CONFIG_ASYNC_TCP_STACK_SIZE 8192 * 2
#endif
#ifndef CONFIG_ASYNC_TCP_PRIORITY
#define CONFIG_ASYNC_TCP_PRIORITY 10
#endif
#ifndef CONFIG_ASYNC_TCP_QUEUE_SIZE
#define CONFIG_ASYNC_TCP_QUEUE_SIZE 64
#endif
#ifndef CONFIG_ASYNC_TCP_MAX_ACK_TIME
#define CONFIG_ASYNC_TCP_MAX_ACK_TIME 5000
#endif
class AsyncClient;
#define ASYNC_WRITE_FLAG_COPY 0x01 // will allocate new buffer to hold the data while sending (else will hold reference to the data given)
#define ASYNC_WRITE_FLAG_MORE 0x02 // will not send PSH flag, meaning that there should be more data to be sent before the application should react.
typedef std::function<void(void*, AsyncClient*)> AcConnectHandler;
typedef std::function<void(void*, AsyncClient*, size_t len, uint32_t time)> AcAckHandler;
typedef std::function<void(void*, AsyncClient*, int8_t error)> AcErrorHandler;
typedef std::function<void(void*, AsyncClient*, void* data, size_t len)> AcDataHandler;
typedef std::function<void(void*, AsyncClient*, struct pbuf* pb)> AcPacketHandler;
typedef std::function<void(void*, AsyncClient*, uint32_t time)> AcTimeoutHandler;
struct tcp_pcb;
struct ip_addr;
class AsyncClient {
public:
AsyncClient(tcp_pcb* pcb = 0);
~AsyncClient();
AsyncClient& operator=(const AsyncClient& other);
AsyncClient& operator+=(const AsyncClient& other);
bool operator==(const AsyncClient& other);
bool operator!=(const AsyncClient& other) {
return !(*this == other);
}
bool connect(const IPAddress& ip, uint16_t port);
#if ESP_IDF_VERSION_MAJOR < 5
bool connect(const IPv6Address& ip, uint16_t port);
#endif
bool connect(const char* host, uint16_t port);
/**
* @brief close connection
*
* @param now - ignored
*/
void close(bool now = false);
// same as close()
void stop() { close(false); };
int8_t abort();
bool free();
// ack is not pending
bool canSend();
// TCP buffer space available
size_t space();
/**
* @brief add data to be send (but do not send yet)
* @note add() would call lwip's tcp_write()
By default apiflags=ASYNC_WRITE_FLAG_COPY
You could try to use apiflags with this flag unset to pass data by reference and avoid copy to socket buffer,
but looks like it does not work for Arduino's lwip in ESP32/IDF at least
it is enforced in https://github.com/espressif/esp-lwip/blob/0606eed9d8b98a797514fdf6eabb4daf1c8c8cd9/src/core/tcp_out.c#L422C5-L422C30
if LWIP_NETIF_TX_SINGLE_PBUF is set, and it is set indeed in IDF
https://github.com/espressif/esp-idf/blob/a0f798cfc4bbd624aab52b2c194d219e242d80c1/components/lwip/port/include/lwipopts.h#L744
*
* @param data
* @param size
* @param apiflags
* @return size_t amount of data that has been copied
*/
size_t add(const char* data, size_t size, uint8_t apiflags = ASYNC_WRITE_FLAG_COPY);
/**
* @brief send data previously add()'ed
*
* @return true on success
* @return false on error
*/
bool send();
/**
* @brief add and enqueue data for sending
* @note it is same as add() + send()
* @note only make sense when canSend() == true
*
* @param data
* @param size
* @param apiflags
* @return size_t
*/
size_t write(const char* data, size_t size, uint8_t apiflags = ASYNC_WRITE_FLAG_COPY);
/**
* @brief add and enque data for sending
* @note treats data as null-terminated string
*
* @param data
* @return size_t
*/
size_t write(const char* data) { return data == NULL ? 0 : write(data, strlen(data)); };
uint8_t state();
bool connecting();
bool connected();
bool disconnecting();
bool disconnected();
// disconnected or disconnecting
bool freeable();
uint16_t getMss();
uint32_t getRxTimeout();
// no RX data timeout for the connection in seconds
void setRxTimeout(uint32_t timeout);
uint32_t getAckTimeout();
// no ACK timeout for the last sent packet in milliseconds
void setAckTimeout(uint32_t timeout);
void setNoDelay(bool nodelay);
bool getNoDelay();
void setKeepAlive(uint32_t ms, uint8_t cnt);
uint32_t getRemoteAddress();
uint16_t getRemotePort();
uint32_t getLocalAddress();
uint16_t getLocalPort();
#if LWIP_IPV6
ip6_addr_t getRemoteAddress6();
ip6_addr_t getLocalAddress6();
#if ESP_IDF_VERSION_MAJOR < 5
IPv6Address remoteIP6();
IPv6Address localIP6();
#else
IPAddress remoteIP6();
IPAddress localIP6();
#endif
#endif
// compatibility
IPAddress remoteIP();
uint16_t remotePort();
IPAddress localIP();
uint16_t localPort();
// set callback - on successful connect
void onConnect(AcConnectHandler cb, void* arg = 0);
// set callback - disconnected
void onDisconnect(AcConnectHandler cb, void* arg = 0);
// set callback - ack received
void onAck(AcAckHandler cb, void* arg = 0);
// set callback - unsuccessful connect or error
void onError(AcErrorHandler cb, void* arg = 0);
// set callback - data received (called if onPacket is not used)
void onData(AcDataHandler cb, void* arg = 0);
// set callback - data received
void onPacket(AcPacketHandler cb, void* arg = 0);
// set callback - ack timeout
void onTimeout(AcTimeoutHandler cb, void* arg = 0);
// set callback - every 125ms when connected
void onPoll(AcConnectHandler cb, void* arg = 0);
// ack pbuf from onPacket
void ackPacket(struct pbuf* pb);
// ack data that you have not acked using the method below
size_t ack(size_t len);
// will not ack the current packet. Call from onData
void ackLater() { _ack_pcb = false; }
static const char* errorToString(int8_t error);
const char* stateToString();
// internal callbacks - Do NOT call any of the functions below in user code!
static int8_t _s_poll(void* arg, struct tcp_pcb* tpcb);
static int8_t _s_recv(void* arg, struct tcp_pcb* tpcb, struct pbuf* pb, int8_t err);
static int8_t _s_fin(void* arg, struct tcp_pcb* tpcb, int8_t err);
static int8_t _s_lwip_fin(void* arg, struct tcp_pcb* tpcb, int8_t err);
static void _s_error(void* arg, int8_t err);
static int8_t _s_sent(void* arg, struct tcp_pcb* tpcb, uint16_t len);
static int8_t _s_connected(void* arg, struct tcp_pcb* tpcb, int8_t err);
static void _s_dns_found(const char* name, struct ip_addr* ipaddr, void* arg);
int8_t _recv(tcp_pcb* pcb, pbuf* pb, int8_t err);
tcp_pcb* pcb() { return _pcb; }
protected:
bool _connect(ip_addr_t addr, uint16_t port);
tcp_pcb* _pcb;
int8_t _closed_slot;
AcConnectHandler _connect_cb;
void* _connect_cb_arg;
AcConnectHandler _discard_cb;
void* _discard_cb_arg;
AcAckHandler _sent_cb;
void* _sent_cb_arg;
AcErrorHandler _error_cb;
void* _error_cb_arg;
AcDataHandler _recv_cb;
void* _recv_cb_arg;
AcPacketHandler _pb_cb;
void* _pb_cb_arg;
AcTimeoutHandler _timeout_cb;
void* _timeout_cb_arg;
AcConnectHandler _poll_cb;
void* _poll_cb_arg;
bool _ack_pcb;
uint32_t _tx_last_packet;
uint32_t _rx_ack_len;
uint32_t _rx_last_packet;
uint32_t _rx_timeout;
uint32_t _rx_last_ack;
uint32_t _ack_timeout;
uint16_t _connect_port;
int8_t _close();
void _free_closed_slot();
bool _allocate_closed_slot();
int8_t _connected(tcp_pcb* pcb, int8_t err);
void _error(int8_t err);
int8_t _poll(tcp_pcb* pcb);
int8_t _sent(tcp_pcb* pcb, uint16_t len);
int8_t _fin(tcp_pcb* pcb, int8_t err);
int8_t _lwip_fin(tcp_pcb* pcb, int8_t err);
void _dns_found(struct ip_addr* ipaddr);
public:
AsyncClient* prev;
AsyncClient* next;
};
class AsyncServer {
public:
AsyncServer(IPAddress addr, uint16_t port);
#if ESP_IDF_VERSION_MAJOR < 5
AsyncServer(IPv6Address addr, uint16_t port);
#endif
AsyncServer(uint16_t port);
~AsyncServer();
void onClient(AcConnectHandler cb, void* arg);
void begin();
void end();
void setNoDelay(bool nodelay);
bool getNoDelay();
uint8_t status();
// Do not use any of the functions below!
static int8_t _s_accept(void* arg, tcp_pcb* newpcb, int8_t err);
static int8_t _s_accepted(void* arg, AsyncClient* client);
protected:
uint16_t _port;
bool _bind4 = false;
bool _bind6 = false;
IPAddress _addr;
#if ESP_IDF_VERSION_MAJOR < 5
IPv6Address _addr6;
#endif
bool _noDelay;
tcp_pcb* _pcb;
AcConnectHandler _connect_cb;
void* _connect_cb_arg;
int8_t _accept(tcp_pcb* newpcb, int8_t err);
int8_t _accepted(AsyncClient* client);
};
#endif /* ASYNCTCP_H_ */

View file

@ -0,0 +1,2 @@
.DS_Store

View file

@ -0,0 +1,34 @@
sudo: false
language: python
os:
- linux
git:
depth: false
stages:
- build
jobs:
include:
- name: "Arduino Build"
if: tag IS blank AND (type = pull_request OR (type = push AND branch = master))
stage: build
script: bash $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh
- name: "PlatformIO Build"
if: tag IS blank AND (type = pull_request OR (type = push AND branch = master))
stage: build
script: bash $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh 1 1
notifications:
email:
on_success: change
on_failure: change
webhooks:
urls:
- https://webhooks.gitter.im/e/60e65d0c78ea0a920347
on_success: change # options: [always|never|change] default: always
on_failure: always # options: [always|never|change] default: always
on_start: false # default: false

View file

@ -0,0 +1,30 @@
menu "AsyncTCP Configuration"
choice ASYNC_TCP_RUNNING_CORE
bool "Core on which AsyncTCP's thread is running"
default ASYNC_TCP_RUN_CORE1
help
Select on which core AsyncTCP is running
config ASYNC_TCP_RUN_CORE0
bool "CORE 0"
config ASYNC_TCP_RUN_CORE1
bool "CORE 1"
config ASYNC_TCP_RUN_NO_AFFINITY
bool "BOTH"
endchoice
config ASYNC_TCP_RUNNING_CORE
int
default 0 if ASYNC_TCP_RUN_CORE0
default 1 if ASYNC_TCP_RUN_CORE1
default -1 if ASYNC_TCP_RUN_NO_AFFINITY
config ASYNC_TCP_USE_WDT
bool "Enable WDT for the AsyncTCP task"
default "y"
help
Enable WDT for the AsyncTCP task, so it will trigger if a handler is locking the thread.
endmenu

View file

@ -0,0 +1,15 @@
This is commit ca8ac5f from https://github.com/me-no-dev/AsyncTCP
# AsyncTCP
[![Build Status](https://travis-ci.org/me-no-dev/AsyncTCP.svg?branch=master)](https://travis-ci.org/me-no-dev/AsyncTCP) ![](https://github.com/me-no-dev/AsyncTCP/workflows/Async%20TCP%20CI/badge.svg) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/2f7e4d1df8b446d192cbfec6dc174d2d)](https://www.codacy.com/manual/me-no-dev/AsyncTCP?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=me-no-dev/AsyncTCP&amp;utm_campaign=Badge_Grade)
### Async TCP Library for ESP32 Arduino
[![Join the chat at https://gitter.im/me-no-dev/ESPAsyncWebServer](https://badges.gitter.im/me-no-dev/ESPAsyncWebServer.svg)](https://gitter.im/me-no-dev/ESPAsyncWebServer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
This is a fully asynchronous TCP library, aimed at enabling trouble-free, multi-connection network environment for Espressif's ESP32 MCUs.
This library is the base for [ESPAsyncWebServer](https://github.com/me-no-dev/ESPAsyncWebServer)
## AsyncClient and AsyncServer
The base classes on which everything else is built. They expose all possible scenarios, but are really raw and require more skills to use.

View file

@ -0,0 +1,22 @@
{
"name":"AsyncTCP",
"description":"Asynchronous TCP Library for ESP32",
"keywords":"async,tcp",
"authors":
{
"name": "Hristo Gochkov",
"maintainer": true
},
"repository":
{
"type": "git",
"url": "https://github.com/me-no-dev/AsyncTCP.git"
},
"version": "1.1.1",
"license": "LGPL-3.0",
"frameworks": "arduino",
"platforms": "espressif32",
"build": {
"libCompatMode": 2
}
}

View file

@ -0,0 +1,9 @@
name=AsyncTCP
version=1.1.1
author=Me-No-Dev
maintainer=Me-No-Dev
sentence=Async TCP Library for ESP32
paragraph=Async TCP Library for ESP32
category=Other
url=https://github.com/me-no-dev/AsyncTCP
architectures=*

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,220 @@
/*
Asynchronous TCP library for Espressif MCUs
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef ASYNCTCP_H_
#define ASYNCTCP_H_
#include "IPAddress.h"
#include "sdkconfig.h"
#include <functional>
extern "C" {
#include "freertos/semphr.h"
#include "lwip/pbuf.h"
}
#include "../../../system_settings.h"
#include "../../../devboard/hal/hal.h"
//If core is not defined, then we are running in Arduino or PIO
#ifndef CONFIG_ASYNC_TCP_RUNNING_CORE
#define CONFIG_ASYNC_TCP_RUNNING_CORE WIFI_CORE //any available core
#define CONFIG_ASYNC_TCP_USE_WDT 0 //if enabled, adds between 33us and 200us per event
#endif
class AsyncClient;
#define ASYNC_MAX_ACK_TIME 5000
#define ASYNC_WRITE_FLAG_COPY 0x01 //will allocate new buffer to hold the data while sending (else will hold reference to the data given)
#define ASYNC_WRITE_FLAG_MORE 0x02 //will not send PSH flag, meaning that there should be more data to be sent before the application should react.
typedef std::function<void(void*, AsyncClient*)> AcConnectHandler;
typedef std::function<void(void*, AsyncClient*, size_t len, uint32_t time)> AcAckHandler;
typedef std::function<void(void*, AsyncClient*, int8_t error)> AcErrorHandler;
typedef std::function<void(void*, AsyncClient*, void *data, size_t len)> AcDataHandler;
typedef std::function<void(void*, AsyncClient*, struct pbuf *pb)> AcPacketHandler;
typedef std::function<void(void*, AsyncClient*, uint32_t time)> AcTimeoutHandler;
struct tcp_pcb;
struct ip_addr;
class AsyncClient {
public:
AsyncClient(tcp_pcb* pcb = 0);
~AsyncClient();
AsyncClient & operator=(const AsyncClient &other);
AsyncClient & operator+=(const AsyncClient &other);
bool operator==(const AsyncClient &other);
bool operator!=(const AsyncClient &other) {
return !(*this == other);
}
bool connect(IPAddress ip, uint16_t port);
bool connect(const char* host, uint16_t port);
void close(bool now = false);
void stop();
int8_t abort();
bool free();
bool canSend();//ack is not pending
size_t space();//space available in the TCP window
size_t add(const char* data, size_t size, uint8_t apiflags=ASYNC_WRITE_FLAG_COPY);//add for sending
bool send();//send all data added with the method above
//write equals add()+send()
size_t write(const char* data);
size_t write(const char* data, size_t size, uint8_t apiflags=ASYNC_WRITE_FLAG_COPY); //only when canSend() == true
uint8_t state();
bool connecting();
bool connected();
bool disconnecting();
bool disconnected();
bool freeable();//disconnected or disconnecting
uint16_t getMss();
uint32_t getRxTimeout();
void setRxTimeout(uint32_t timeout);//no RX data timeout for the connection in seconds
uint32_t getAckTimeout();
void setAckTimeout(uint32_t timeout);//no ACK timeout for the last sent packet in milliseconds
void setNoDelay(bool nodelay);
bool getNoDelay();
uint32_t getRemoteAddress();
uint16_t getRemotePort();
uint32_t getLocalAddress();
uint16_t getLocalPort();
//compatibility
IPAddress remoteIP();
uint16_t remotePort();
IPAddress localIP();
uint16_t localPort();
void onConnect(AcConnectHandler cb, void* arg = 0); //on successful connect
void onDisconnect(AcConnectHandler cb, void* arg = 0); //disconnected
void onAck(AcAckHandler cb, void* arg = 0); //ack received
void onError(AcErrorHandler cb, void* arg = 0); //unsuccessful connect or error
void onData(AcDataHandler cb, void* arg = 0); //data received (called if onPacket is not used)
void onPacket(AcPacketHandler cb, void* arg = 0); //data received
void onTimeout(AcTimeoutHandler cb, void* arg = 0); //ack timeout
void onPoll(AcConnectHandler cb, void* arg = 0); //every 125ms when connected
void ackPacket(struct pbuf * pb);//ack pbuf from onPacket
size_t ack(size_t len); //ack data that you have not acked using the method below
void ackLater(){ _ack_pcb = false; } //will not ack the current packet. Call from onData
const char * errorToString(int8_t error);
const char * stateToString();
//Do not use any of the functions below!
static int8_t _s_poll(void *arg, struct tcp_pcb *tpcb);
static int8_t _s_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *pb, int8_t err);
static int8_t _s_fin(void *arg, struct tcp_pcb *tpcb, int8_t err);
static int8_t _s_lwip_fin(void *arg, struct tcp_pcb *tpcb, int8_t err);
static void _s_error(void *arg, int8_t err);
static int8_t _s_sent(void *arg, struct tcp_pcb *tpcb, uint16_t len);
static int8_t _s_connected(void* arg, void* tpcb, int8_t err);
static void _s_dns_found(const char *name, struct ip_addr *ipaddr, void *arg);
int8_t _recv(tcp_pcb* pcb, pbuf* pb, int8_t err);
tcp_pcb * pcb(){ return _pcb; }
protected:
tcp_pcb* _pcb;
int8_t _closed_slot;
AcConnectHandler _connect_cb;
void* _connect_cb_arg;
AcConnectHandler _discard_cb;
void* _discard_cb_arg;
AcAckHandler _sent_cb;
void* _sent_cb_arg;
AcErrorHandler _error_cb;
void* _error_cb_arg;
AcDataHandler _recv_cb;
void* _recv_cb_arg;
AcPacketHandler _pb_cb;
void* _pb_cb_arg;
AcTimeoutHandler _timeout_cb;
void* _timeout_cb_arg;
AcConnectHandler _poll_cb;
void* _poll_cb_arg;
bool _pcb_busy;
uint32_t _pcb_sent_at;
bool _ack_pcb;
uint32_t _rx_ack_len;
uint32_t _rx_last_packet;
uint32_t _rx_since_timeout;
uint32_t _ack_timeout;
uint16_t _connect_port;
int8_t _close();
void _free_closed_slot();
void _allocate_closed_slot();
int8_t _connected(void* pcb, int8_t err);
void _error(int8_t err);
int8_t _poll(tcp_pcb* pcb);
int8_t _sent(tcp_pcb* pcb, uint16_t len);
int8_t _fin(tcp_pcb* pcb, int8_t err);
int8_t _lwip_fin(tcp_pcb* pcb, int8_t err);
void _dns_found(struct ip_addr *ipaddr);
public:
AsyncClient* prev;
AsyncClient* next;
};
class AsyncServer {
public:
AsyncServer(IPAddress addr, uint16_t port);
AsyncServer(uint16_t port);
~AsyncServer();
void onClient(AcConnectHandler cb, void* arg);
void begin();
void end();
void setNoDelay(bool nodelay);
bool getNoDelay();
uint8_t status();
//Do not use any of the functions below!
static int8_t _s_accept(void *arg, tcp_pcb* newpcb, int8_t err);
static int8_t _s_accepted(void *arg, AsyncClient* client);
protected:
uint16_t _port;
IPAddress _addr;
bool _noDelay;
tcp_pcb* _pcb;
AcConnectHandler _connect_cb;
void* _connect_cb_arg;
int8_t _accept(tcp_pcb* newpcb, int8_t err);
int8_t _accepted(AsyncClient* client);
};
#endif /* ASYNCTCP_H_ */

View file

@ -22,7 +22,7 @@
#include <Arduino.h> #include <Arduino.h>
#ifdef ESP32 #ifdef ESP32
#include "../../mathieucarbou-AsyncTCP/src/AsyncTCP.h" #include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h"
#define SSE_MAX_QUEUED_MESSAGES 32 #define SSE_MAX_QUEUED_MESSAGES 32
#else #else
#include <ESPAsyncTCP.h> #include <ESPAsyncTCP.h>

View file

@ -23,7 +23,7 @@
#include <Arduino.h> #include <Arduino.h>
#ifdef ESP32 #ifdef ESP32
#include "../../mathieucarbou-AsyncTCP/src/AsyncTCP.h" #include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h"
#define WS_MAX_QUEUED_MESSAGES 32 #define WS_MAX_QUEUED_MESSAGES 32
#else #else
#include <ESPAsyncTCP.h> #include <ESPAsyncTCP.h>

View file

@ -30,10 +30,10 @@
#ifdef ESP32 #ifdef ESP32
#include <WiFi.h> #include <WiFi.h>
#include "../../mathieucarbou-AsyncTCP/src/AsyncTCP.h" #include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h"
#elif defined(ESP8266) #elif defined(ESP8266)
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include "../../mathieucarbou-AsyncTCP/src/AsyncTCP.h" #include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h"
#else #else
#error Platform not supported #error Platform not supported
#endif #endif