mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-04 02:09:30 +02:00
Merge branch 'enhancement/tesla-safety-check' of https://github.com/josiahhiggs/Battery-Emulator into enhancement/tesla-safety-check
This commit is contained in:
commit
a91e4845c9
46 changed files with 4764 additions and 2944 deletions
1
.github/workflows/compile-all-batteries.yml
vendored
1
.github/workflows/compile-all-batteries.yml
vendored
|
@ -70,6 +70,7 @@ jobs:
|
|||
- RENAULT_ZOE_GEN1_BATTERY
|
||||
- RENAULT_ZOE_GEN2_BATTERY
|
||||
- SANTA_FE_PHEV_BATTERY
|
||||
- STELLANTIS_ECMP_BATTERY
|
||||
- TESLA_MODEL_3Y_BATTERY
|
||||
- TESLA_MODEL_SX_BATTERY
|
||||
- VOLVO_SPA_BATTERY
|
||||
|
|
|
@ -63,6 +63,7 @@ jobs:
|
|||
- RENAULT_ZOE_GEN1_BATTERY
|
||||
- RENAULT_ZOE_GEN2_BATTERY
|
||||
- SANTA_FE_PHEV_BATTERY
|
||||
- STELLANTIS_ECMP_BATTERY
|
||||
- TESLA_MODEL_3Y_BATTERY
|
||||
- TESLA_MODEL_SX_BATTERY
|
||||
- VOLVO_SPA_BATTERY
|
||||
|
|
|
@ -85,7 +85,7 @@ This code uses the following excellent libraries:
|
|||
- [eModbus/eModbus](https://github.com/eModbus/eModbus) MIT-License
|
||||
- [knolleary/pubsubclient](https://github.com/knolleary/pubsubclient) MIT-License
|
||||
- [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)
|
||||
- [miwagner/ESP32-Arduino-CAN](https://github.com/miwagner/ESP32-Arduino-CAN/) MIT-License
|
||||
- [pierremolinaro/acan2515](https://github.com/pierremolinaro/acan2515) MIT-License
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
/* 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" */
|
||||
|
||||
#include "src/include.h"
|
||||
|
||||
#include "HardwareSerial.h"
|
||||
#include "USER_SECRETS.h"
|
||||
#include "USER_SETTINGS.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_task_wdt.h"
|
||||
#include "esp_timer.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "src/charger/CHARGERS.h"
|
||||
#include "src/communication/can/comm_can.h"
|
||||
#include "src/communication/contactorcontrol/comm_contactorcontrol.h"
|
||||
#include "src/communication/equipmentstopbutton/comm_equipmentstopbutton.h"
|
||||
|
@ -22,6 +19,7 @@
|
|||
#include "src/devboard/utils/led_handler.h"
|
||||
#include "src/devboard/utils/logging.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_formatter.h"
|
||||
#include "src/lib/bblanchon-ArduinoJson/ArduinoJson.h"
|
||||
|
@ -30,7 +28,10 @@
|
|||
#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/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
|
||||
#include "src/devboard/wifi/wifi.h"
|
||||
#ifdef WEBSERVER
|
||||
|
@ -233,9 +234,6 @@ void core_loop(void* task_time_us) {
|
|||
update_machineryprotection(); // Check safeties (Not on serial link reciever board)
|
||||
#endif // SERIAL_LINK_RECEIVER
|
||||
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);
|
||||
|
||||
|
|
|
@ -1,13 +1,20 @@
|
|||
#define WIFI_SSID "REPLACE_WITH_YOUR_SSID" // Maximum of 63 characters
|
||||
#define WIFI_PASSWORD "REPLACE_WITH_YOUR_PASSWORD" // Minimum of 8 characters
|
||||
/* This file should be renamed to USER_SECRETS.h to be able to use the software!
|
||||
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 WEBSERVER_AUTH_REQUIRED \
|
||||
false //Set this line to true to activate webserver authentication (this line must not be commented).
|
||||
#define HTTP_USERNAME "admin" // username to webserver authentication;
|
||||
#define HTTP_PASSWORD "admin" // password to webserver authentication;
|
||||
//Name and password of Wifi network you want the emulator to connect to
|
||||
#define WIFI_SSID "REPLACE_WITH_YOUR_SSID" // Maximum of 63 characters
|
||||
#define WIFI_PASSWORD "REPLACE_WITH_YOUR_PASSWORD" // Minimum of 8 characters
|
||||
|
||||
#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
|
||||
//Set WEBSERVER_AUTH_REQUIRED to true to require a password when accessing the webserver homepage. Improves cybersecurity.
|
||||
#define WEBSERVER_AUTH_REQUIRED false
|
||||
#define HTTP_USERNAME "admin" // Username for webserver 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
|
||||
|
|
|
@ -20,28 +20,21 @@ volatile CAN_Configuration can_config = {
|
|||
.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 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* passwordAP = AP_PASSWORD; // Set in USER_SECRETS.h
|
||||
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
|
||||
const char* http_username = HTTP_USERNAME; // 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
|
||||
|
||||
// MQTT
|
||||
#ifdef MQTT
|
||||
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"
|
||||
#endif // MQTT_MANUAL_TOPIC_OBJECT_NAME
|
||||
#endif // USE_MQTT
|
||||
#endif // WIFI
|
||||
|
||||
#ifdef EQUIPMENT_STOP_BUTTON
|
||||
// Equipment stop button behavior. Use NC button for safety reasons.
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
//#define RENAULT_ZOE_GEN1_BATTERY
|
||||
//#define RENAULT_ZOE_GEN2_BATTERY
|
||||
//#define SANTA_FE_PHEV_BATTERY
|
||||
//#define STELLANTIS_ECMP_BATTERY
|
||||
//#define TESLA_MODEL_3Y_BATTERY
|
||||
//#define TESLA_MODEL_SX_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 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
|
||||
#ifdef CANFD_ADDON // CANFD_ADDON additional options if enabled
|
||||
#define CANFD_ADDON_CRYSTAL_FREQUENCY_MHZ \
|
||||
ACAN2517FDSettings:: \
|
||||
OSC_40MHz //CANFD_ADDON option, what is your MCP2518 add-on boards crystal frequency? (Default OSC_40MHz)
|
||||
#endif // CANFD_ADDON
|
||||
ACAN2517FDSettings::OSC_40MHz //CANFD_ADDON option, what is your MCP2518 add-on boards crystal frequency?
|
||||
//#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_TRANSMITTER //Enable this line to send battery data over RS485 pins to another Lilygo (This LilyGo interfaces with battery)
|
||||
#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 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 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 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 */
|
||||
#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) */
|
||||
//#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
|
||||
|
@ -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
|
||||
#define BATTERY_MAX_DISCHARGE_VOLTAGE 3000
|
||||
|
||||
/* 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" */
|
||||
/* Do not change any code below this line */
|
||||
/* 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 struct {
|
||||
CAN_Interface battery;
|
||||
|
@ -169,9 +164,7 @@ extern volatile STOP_BUTTON_BEHAVIOR equipment_stop_behavior;
|
|||
|
||||
#ifdef WIFICONFIG
|
||||
extern IPAddress local_IP;
|
||||
// Set your Gateway IP address
|
||||
extern IPAddress gateway;
|
||||
// Set your Subnet IP address
|
||||
extern IPAddress subnet;
|
||||
#endif
|
||||
|
||||
|
|
|
@ -27,6 +27,10 @@
|
|||
#include "CHADEMO-SHUNTS.h"
|
||||
#endif
|
||||
|
||||
#ifdef STELLANTIS_ECMP_BATTERY
|
||||
#include "ECMP-BATTERY.h"
|
||||
#endif
|
||||
|
||||
#ifdef IMIEV_CZERO_ION_BATTERY
|
||||
#include "IMIEV-CZERO-ION-BATTERY.h"
|
||||
#endif
|
||||
|
|
308
Software/src/battery/ECMP-BATTERY.cpp
Normal file
308
Software/src/battery/ECMP-BATTERY.cpp
Normal 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
|
12
Software/src/battery/ECMP-BATTERY.h
Normal file
12
Software/src/battery/ECMP-BATTERY.h
Normal 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
|
@ -9,11 +9,13 @@ volatile bool send_ok = 0;
|
|||
|
||||
#ifdef CAN_ADDON
|
||||
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;
|
||||
#endif //CAN_ADDON
|
||||
#ifdef CANFD_ADDON
|
||||
ACAN2517FD canfd(MCP2517_CS, SPI, MCP2517_INT);
|
||||
SPIClass SPI2517;
|
||||
ACAN2517FD canfd(MCP2517_CS, SPI2517, MCP2517_INT);
|
||||
#endif //CANFD_ADDON
|
||||
|
||||
// Initialization functions
|
||||
|
@ -39,20 +41,20 @@ void init_CAN() {
|
|||
logging.println("Dual CAN Bus (ESP32+MCP2515) selected");
|
||||
#endif // DEBUG_LOG
|
||||
gBuffer.initWithSize(25);
|
||||
SPI.begin(MCP2515_SCK, MCP2515_MISO, MCP2515_MOSI);
|
||||
ACAN2515Settings settings(QUARTZ_FREQUENCY, 500UL * 1000UL); // CAN bit rate 500 kb/s
|
||||
settings.mRequestedMode = ACAN2515Settings::NormalMode;
|
||||
const uint16_t errorCodeMCP = can.begin(settings, [] { can.isr(); });
|
||||
if (errorCodeMCP == 0) {
|
||||
SPI2515.begin(MCP2515_SCK, MCP2515_MISO, MCP2515_MOSI);
|
||||
ACAN2515Settings settings2515(QUARTZ_FREQUENCY, 500UL * 1000UL); // CAN bit rate 500 kb/s
|
||||
settings2515.mRequestedMode = ACAN2515Settings::NormalMode;
|
||||
const uint16_t errorCode2515 = can.begin(settings2515, [] { can.isr(); });
|
||||
if (errorCode2515 == 0) {
|
||||
#ifdef DEBUG_LOG
|
||||
logging.println("Can ok");
|
||||
#endif // DEBUG_LOG
|
||||
} else {
|
||||
#ifdef DEBUG_LOG
|
||||
logging.print("Error Can: 0x");
|
||||
logging.println(errorCodeMCP, HEX);
|
||||
logging.println(errorCode2515, HEX);
|
||||
#endif // DEBUG_LOG
|
||||
set_event(EVENT_CANMCP_INIT_FAILURE, (uint8_t)errorCodeMCP);
|
||||
set_event(EVENT_CANMCP2515_INIT_FAILURE, (uint8_t)errorCode2515);
|
||||
}
|
||||
#endif // CAN_ADDON
|
||||
|
||||
|
@ -60,41 +62,41 @@ void init_CAN() {
|
|||
#ifdef DEBUG_LOG
|
||||
logging.println("CAN FD add-on (ESP32+MCP2517) selected");
|
||||
#endif // DEBUG_LOG
|
||||
SPI.begin(MCP2517_SCK, MCP2517_SDO, MCP2517_SDI);
|
||||
ACAN2517FDSettings settings(CANFD_ADDON_CRYSTAL_FREQUENCY_MHZ, 500 * 1000,
|
||||
SPI2517.begin(MCP2517_SCK, MCP2517_SDO, MCP2517_SDI);
|
||||
ACAN2517FDSettings settings2517(CANFD_ADDON_CRYSTAL_FREQUENCY_MHZ, 500 * 1000,
|
||||
DataBitRateFactor::x4); // Arbitration bit rate: 500 kbit/s, data bit rate: 2 Mbit/s
|
||||
#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
|
||||
settings.mRequestedMode = ACAN2517FDSettings::NormalFD; // ListenOnly / Normal20B / NormalFD
|
||||
settings2517.mRequestedMode = ACAN2517FDSettings::NormalFD; // ListenOnly / Normal20B / NormalFD
|
||||
#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();
|
||||
if (errorCode == 0) {
|
||||
if (errorCode2517 == 0) {
|
||||
#ifdef DEBUG_LOG
|
||||
logging.print("Bit Rate prescaler: ");
|
||||
logging.println(settings.mBitRatePrescaler);
|
||||
logging.println(settings2517.mBitRatePrescaler);
|
||||
logging.print("Arbitration Phase segment 1: ");
|
||||
logging.print(settings.mArbitrationPhaseSegment1);
|
||||
logging.print(settings2517.mArbitrationPhaseSegment1);
|
||||
logging.print(" segment 2: ");
|
||||
logging.print(settings.mArbitrationPhaseSegment2);
|
||||
logging.print(settings2517.mArbitrationPhaseSegment2);
|
||||
logging.print(" SJW: ");
|
||||
logging.println(settings.mArbitrationSJW);
|
||||
logging.println(settings2517.mArbitrationSJW);
|
||||
logging.print("Actual Arbitration Bit Rate: ");
|
||||
logging.print(settings.actualArbitrationBitRate());
|
||||
logging.print(settings2517.actualArbitrationBitRate());
|
||||
logging.print(" bit/s");
|
||||
logging.print(" (Exact:");
|
||||
logging.println(settings.exactArbitrationBitRate() ? "yes)" : "no)");
|
||||
logging.println(settings2517.exactArbitrationBitRate() ? "yes)" : "no)");
|
||||
logging.print("Arbitration Sample point: ");
|
||||
logging.print(settings.arbitrationSamplePointFromBitStart());
|
||||
logging.print(settings2517.arbitrationSamplePointFromBitStart());
|
||||
logging.println("%");
|
||||
#endif // DEBUG_LOG
|
||||
} else {
|
||||
#ifdef DEBUG_LOG
|
||||
logging.print("CAN-FD Configuration error 0x");
|
||||
logging.println(errorCode, HEX);
|
||||
logging.println(errorCode2517, HEX);
|
||||
#endif // DEBUG_LOG
|
||||
set_event(EVENT_CANFD_INIT_FAILURE, (uint8_t)errorCode);
|
||||
set_event(EVENT_CANMCP2517FD_INIT_FAILURE, (uint8_t)errorCode2517);
|
||||
}
|
||||
#endif // CANFD_ADDON
|
||||
}
|
||||
|
|
|
@ -90,9 +90,9 @@ void init_contactors() {
|
|||
|
||||
// Main functions
|
||||
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);
|
||||
#endif // BYD_SMA
|
||||
#endif
|
||||
|
||||
#ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY
|
||||
handle_contactors_battery2();
|
||||
|
|
|
@ -215,7 +215,12 @@ typedef struct {
|
|||
uint8_t packCtrsClosingAllowed = 0;
|
||||
/** uint8_t */
|
||||
/** 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_battTempPct = 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_buffer = 0;
|
||||
uint16_t battery_energy_buffer_m1 = 0;
|
||||
uint16_t battery_full_charge_complete = 0;
|
||||
uint8_t battery_fully_charged = 0;
|
||||
uint16_t battery_expected_energy_remaining = 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_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_moduleType = 0;
|
||||
uint16_t battery_reservedConfig = 0;
|
||||
|
@ -248,6 +263,123 @@ typedef struct {
|
|||
uint32_t battery_soc_max = 0;
|
||||
uint32_t battery_soc_ave = 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;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -140,8 +140,8 @@ void init_events(void) {
|
|||
events.entries[i].MQTTpublished = false; // Not published by default
|
||||
}
|
||||
|
||||
events.entries[EVENT_CANFD_INIT_FAILURE].level = EVENT_LEVEL_WARNING;
|
||||
events.entries[EVENT_CANMCP_INIT_FAILURE].level = EVENT_LEVEL_WARNING;
|
||||
events.entries[EVENT_CANMCP2517FD_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_CAN_OVERRUN].level = EVENT_LEVEL_INFO;
|
||||
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) {
|
||||
switch (event) {
|
||||
case EVENT_CANFD_INIT_FAILURE:
|
||||
case EVENT_CANMCP2517FD_INIT_FAILURE:
|
||||
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";
|
||||
case EVENT_CANFD_BUFFER_FULL:
|
||||
return "CAN-FD buffer overflowed. Some CAN messages were not sent. Contact developers.";
|
||||
|
|
|
@ -26,8 +26,8 @@
|
|||
*/
|
||||
|
||||
#define EVENTS_ENUM_TYPE(XX) \
|
||||
XX(EVENT_CANFD_INIT_FAILURE) \
|
||||
XX(EVENT_CANMCP_INIT_FAILURE) \
|
||||
XX(EVENT_CANMCP2517FD_INIT_FAILURE) \
|
||||
XX(EVENT_CANMCP2515_INIT_FAILURE) \
|
||||
XX(EVENT_CANFD_BUFFER_FULL) \
|
||||
XX(EVENT_CAN_OVERRUN) \
|
||||
XX(EVENT_CANFD_RX_OVERRUN) \
|
||||
|
|
|
@ -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;
|
||||
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 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_charge = static_cast<float>(datalayer_extended.tesla.battery_total_charge);
|
||||
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_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;
|
||||
|
||||
// Comment what data you would like to dislay, order can be changed.
|
||||
content += "<h4>Battery Beginning of Life: " + String(beginning_of_life) + " kWh</h4>";
|
||||
content += "<h4>BattTempPct: " + String(battTempPct) + " </h4>";
|
||||
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>";
|
||||
|
||||
//if using older BMS <2021 and comment 0x352 without MUX
|
||||
//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>";
|
||||
|
||||
//if using newer BMS >2021 and comment 0x352 with MUX
|
||||
content += "<h4>Nominal Full Pack Energy m0: " + String(nominal_full_pack_energy_m0) + " kWh</h4>";
|
||||
content += "<h4>Nominal Energy Remaining m0: " + String(nominal_energy_remaining_m0) + " kWh</h4>";
|
||||
content += "<h4>Ideal Energy Remaining m0: " + String(ideal_energy_remaining_m0) + " kWh</h4>";
|
||||
content += "<h4>Energy to Charge Complete m1: " + String(energy_to_charge_complete_m1) + " kWh</h4>";
|
||||
content += "<h4>Energy Buffer m1: " + String(energy_buffer_m1) + " kWh</h4>";
|
||||
|
||||
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>Full Charge Complete: " + String(datalayer_extended.tesla.battery_full_charge_complete) + "</h4>";
|
||||
content += "<h4>Total Discharge: " + String(total_discharge) + " kWh</h4>";
|
||||
content += "<h4>Total Charge: " + String(total_charge) + " kWh</h4>";
|
||||
content += "<h4>Battery Pack Mass: " + String(packMass) + " KG</h4>";
|
||||
content += "<h4>Platform Max Bus Voltage: " + String(platformMaxBusVoltage) + " V</h4>";
|
||||
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>";
|
||||
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>";
|
||||
float BrickVoltageMax = static_cast<float>(datalayer_extended.tesla.battery_BrickVoltageMax) * 0.002;
|
||||
float BrickVoltageMin = static_cast<float>(datalayer_extended.tesla.battery_BrickVoltageMin) * 0.002;
|
||||
float BrickModelTMax = static_cast<float>(datalayer_extended.tesla.battery_BrickTempMinNum) * 0.5 - 40;
|
||||
float BrickModelTMin = static_cast<float>(datalayer_extended.tesla.battery_BrickModelTMin) * 0.5 - 40;
|
||||
float isolationResistance = static_cast<float>(datalayer_extended.tesla.battery_BMS_isolationResistance) * 10;
|
||||
float PCS_dcdcMaxOutputCurrentAllowed =
|
||||
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;
|
||||
float PCS_ambientTemp = static_cast<float>(datalayer_extended.tesla.PCS_ambientTemp) * 0.1 - 40;
|
||||
float BMS_maxRegenPower = static_cast<float>(datalayer_extended.tesla.BMS_maxRegenPower) * 0.01;
|
||||
float BMS_maxDischargePower = static_cast<float>(datalayer_extended.tesla.BMS_maxDischargePower) * 0.013;
|
||||
float BMS_maxStationaryHeatPower = static_cast<float>(datalayer_extended.tesla.BMS_maxStationaryHeatPower) * 0.01;
|
||||
float BMS_hvacPowerBudget = static_cast<float>(datalayer_extended.tesla.BMS_hvacPowerBudget) * 0.02;
|
||||
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;
|
||||
float BMS_inletActiveCoolTargetT =
|
||||
static_cast<float>(datalayer_extended.tesla.BMS_inletActiveCoolTargetT) * 0.25 - 25;
|
||||
float BMS_inletPassiveTargetT = static_cast<float>(datalayer_extended.tesla.BMS_inletPassiveTargetT) * 0.25 - 25;
|
||||
float BMS_inletActiveHeatTargetT =
|
||||
static_cast<float>(datalayer_extended.tesla.BMS_inletActiveHeatTargetT) * 0.25 - 25;
|
||||
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;
|
||||
float PCS_dcdcMaxLvOutputCurrent = static_cast<float>(datalayer_extended.tesla.PCS_dcdcMaxLvOutputCurrent) * 0.1;
|
||||
float PCS_dcdcCurrentLimit = static_cast<float>(datalayer_extended.tesla.PCS_dcdcCurrentLimit) * 0.1;
|
||||
float PCS_dcdcLvOutputCurrentTempLimit =
|
||||
static_cast<float>(datalayer_extended.tesla.PCS_dcdcLvOutputCurrentTempLimit) * 0.1;
|
||||
float PCS_dcdcUnifiedCommand = static_cast<float>(datalayer_extended.tesla.PCS_dcdcUnifiedCommand) * 0.001;
|
||||
float PCS_dcdcCLAControllerOutput =
|
||||
static_cast<float>(datalayer_extended.tesla.PCS_dcdcCLAControllerOutput * 0.001);
|
||||
float PCS_dcdcTankVoltage = static_cast<float>(datalayer_extended.tesla.PCS_dcdcTankVoltage);
|
||||
float PCS_dcdcTankVoltageTarget = static_cast<float>(datalayer_extended.tesla.PCS_dcdcTankVoltageTarget);
|
||||
float PCS_dcdcClaCurrentFreq = static_cast<float>(datalayer_extended.tesla.PCS_dcdcClaCurrentFreq) * 0.0976563;
|
||||
float PCS_dcdcTCommMeasured = static_cast<float>(datalayer_extended.tesla.PCS_dcdcTCommMeasured) * 0.00195313;
|
||||
float PCS_dcdcShortTimeUs = static_cast<float>(datalayer_extended.tesla.PCS_dcdcShortTimeUs) * 0.000488281;
|
||||
float PCS_dcdcHalfPeriodUs = static_cast<float>(datalayer_extended.tesla.PCS_dcdcHalfPeriodUs) * 0.000488281;
|
||||
float PCS_dcdcIntervalMaxFrequency = static_cast<float>(datalayer_extended.tesla.PCS_dcdcIntervalMaxFrequency);
|
||||
float PCS_dcdcIntervalMaxHvBusVolt =
|
||||
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",
|
||||
"CLOSED", "UNKNOWN(6)", "WELDED", "POS_CL", "NEG_CL",
|
||||
"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",
|
||||
"CURRENT_SOURCE_FAULT",
|
||||
"INTERNAL_OPEN_FAULT",
|
||||
|
@ -421,17 +458,292 @@ String advanced_battery_processor(const String& var) {
|
|||
"UNKNOWN(13)",
|
||||
"UNKNOWN(14)",
|
||||
"UNKNOWN(15)"};
|
||||
content += "<h4>HVIL: " + String(hvilStatusState[datalayer_extended.tesla.hvil_status]) + "</h4>";
|
||||
static const char* contactorState[] = {"SNA", "OPEN", "PRECHARGE", "BLOCKED",
|
||||
"PULLED_IN", "OPENING", "ECONOMIZED", "WELDED",
|
||||
"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 +=
|
||||
"<h4>Negative contactor: " + String(contactorState[datalayer_extended.tesla.packContNegativeState]) + "</h4>";
|
||||
content +=
|
||||
"<h4>Positive contactor: " + String(contactorState[datalayer_extended.tesla.packContPositiveState]) + "</h4>";
|
||||
static const char* falseTrue[] = {"False", "True"};
|
||||
content += "<h4>Closing allowed?: " + String(falseTrue[datalayer_extended.tesla.packCtrsClosingAllowed]) + "</h4>";
|
||||
content += "<h4>Pyrotest: " + String(falseTrue[datalayer_extended.tesla.pyroTestInProgress]) + "</h4>";
|
||||
content +=
|
||||
"<h4>Closing allowed?: " + String(noYes[datalayer_extended.tesla.packCtrsClosingAllowed]) + "</h4>"; //bool
|
||||
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
|
||||
|
||||
#ifdef NISSAN_LEAF_BATTERY
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "../../include.h"
|
||||
#include "../../lib/YiannisBourkelis-Uptime-Library/src/uptime_formatter.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/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
||||
|
|
|
@ -29,12 +29,8 @@ static bool connected_once = false;
|
|||
void init_WiFi() {
|
||||
|
||||
#ifdef WIFIAP
|
||||
if (AccessPointEnabled) {
|
||||
WiFi.mode(WIFI_AP_STA); // Simultaneous WiFi AP and Router connection
|
||||
init_WiFi_AP();
|
||||
} else {
|
||||
WiFi.mode(WIFI_STA); // Only Router connection
|
||||
}
|
||||
#else
|
||||
WiFi.mode(WIFI_STA); // Only Router connection
|
||||
#endif // WIFIAP
|
||||
|
|
|
@ -130,10 +130,18 @@ void update_values_can_inverter() { //This function maps all the values fetched
|
|||
}
|
||||
|
||||
//Error bits
|
||||
if (!datalayer.system.status.inverter_allows_contactor_closing) {
|
||||
SMA_158.data.u8[2] = 0x6A;
|
||||
} else {
|
||||
if (datalayer.system.status.inverter_allows_contactor_closing) {
|
||||
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
|
||||
strncpy(datalayer.system.info.inverter_protocol, "BYD Battery-Box HVS over SMA CAN", 63);
|
||||
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);
|
||||
#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
|
||||
|
|
|
@ -127,10 +127,18 @@ void update_values_can_inverter() { //This function maps all the values fetched
|
|||
}
|
||||
|
||||
//Error bits
|
||||
if (!datalayer.system.status.inverter_allows_contactor_closing) {
|
||||
SMA_158.data.u8[2] = 0x6A;
|
||||
} else {
|
||||
if (datalayer.system.status.inverter_allows_contactor_closing) {
|
||||
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
|
||||
strncpy(datalayer.system.info.inverter_protocol, "SMA CAN", 63);
|
||||
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
|
||||
|
|
|
@ -12,317 +12,248 @@
|
|||
*/
|
||||
|
||||
/* 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
|
||||
CAN_frame SMA_00D = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.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}};
|
||||
typedef struct {
|
||||
CAN_frame* frame;
|
||||
void (*callback)();
|
||||
} Frame;
|
||||
|
||||
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 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 };
|
||||
BatteryState batteryState = OPERATE;
|
||||
enum InverterControlFlags {
|
||||
EMG_CHARGE_REQUEST,
|
||||
EMG_DISCHARGE_REQUEST,
|
||||
NOT_ENOUGH_ENERGY_FOR_START,
|
||||
INVERTER_STAY_ON,
|
||||
FORCED_BATTERY_SHUTDOWN,
|
||||
RESERVED,
|
||||
BATTERY_UPDATE_AVAILABLE,
|
||||
NO_BATTERY_UPDATED_BY_INV
|
||||
};
|
||||
InverterControlFlags inverterControlFlags = BATTERY_UPDATE_AVAILABLE;
|
||||
enum Events0 {
|
||||
START_SOC_CALIBRATE,
|
||||
STOP_SOC_CALIBRATE,
|
||||
START_POWERLIMIT,
|
||||
STOP_POWERLIMIT,
|
||||
PREVENTATIVE_BAT_SHUTDOWN,
|
||||
THERMAL_MANAGEMENT,
|
||||
START_BALANCING,
|
||||
STOP_BALANCING
|
||||
};
|
||||
Events0 events0 = START_BALANCING;
|
||||
enum Events1 { START_BATTERY_SELFTEST, STOP_BATTERY_SELFTEST };
|
||||
Events1 events1 = START_BATTERY_SELFTEST;
|
||||
enum Command2Battery { IDLE, RUN, NOT_USED1, NOT_USED2, SHUTDOWN, FIRMWARE_UPDATE, BATSELFUPDATE, NOT_USED3 };
|
||||
Command2Battery command2Battery = RUN;
|
||||
enum InvInitState { SYSTEM_FREQUENCY, XPHASE_SYSTEM, BLACKSTART_OPERATION };
|
||||
InvInitState invInitState = SYSTEM_FREQUENCY;
|
||||
//Actual content messages
|
||||
CAN_frame SMA_558 = {.FD = false, //Pairing first message
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x558, // BYD HVS 10.2 kWh (0x66 might be kWh)
|
||||
.data = {0x03, 0x24, 0x00, 0x04, 0x00, 0x66, 0x04, 0x09}}; //Amount of modules? Vendor ID?
|
||||
CAN_frame SMA_598 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x598,
|
||||
.data = {0x12, 0xD6, 0x43, 0xA4, 0x00, 0x00, 0x00, 0x00}}; //B0-4 Serial 301100932
|
||||
CAN_frame SMA_5D8 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x5D8,
|
||||
.data = {0x00, 0x42, 0x59, 0x44, 0x00, 0x00, 0x00, 0x00}}; //B Y D
|
||||
CAN_frame SMA_618_0 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x618,
|
||||
.data = {0x00, 0x42, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79}}; //BATTERY
|
||||
CAN_frame SMA_618_1 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x618,
|
||||
.data = {0x01, 0x2D, 0x42, 0x6F, 0x78, 0x20, 0x50, 0x72}}; //-Box Pr
|
||||
CAN_frame SMA_618_2 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.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
|
||||
//Calculate values
|
||||
|
||||
// Update values
|
||||
temperature_average =
|
||||
((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 =
|
||||
((datalayer.battery.status.reported_remaining_capacity_Wh / datalayer.battery.status.voltage_dV) *
|
||||
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
|
||||
// Battery Limits
|
||||
//Battery Max Charge Voltage (eg 400.0V = 4000 , 16bits long)
|
||||
SMA_00D.data.u8[0] = (datalayer.battery.info.max_design_voltage_dV >> 8);
|
||||
SMA_00D.data.u8[1] = (datalayer.battery.info.max_design_voltage_dV & 0x00FF);
|
||||
//Battery Min Discharge Voltage (eg 300.0V = 3000 , 16bits long)
|
||||
SMA_00D.data.u8[2] = (datalayer.battery.info.min_design_voltage_dV >> 8);
|
||||
SMA_00D.data.u8[3] = (datalayer.battery.info.min_design_voltage_dV & 0x00FF);
|
||||
|
||||
//Maxvoltage (eg 400.0V = 4000 , 16bits long)
|
||||
SMA_358.data.u8[0] = (datalayer.battery.info.max_design_voltage_dV >> 8);
|
||||
SMA_358.data.u8[1] = (datalayer.battery.info.max_design_voltage_dV & 0x00FF);
|
||||
//Minvoltage (eg 300.0V = 3000 , 16bits long)
|
||||
SMA_358.data.u8[2] = (datalayer.battery.info.min_design_voltage_dV >> 8);
|
||||
SMA_358.data.u8[3] = (datalayer.battery.info.min_design_voltage_dV & 0x00FF);
|
||||
//Discharge limited current, 500 = 50A, (0.1, A)
|
||||
SMA_00D.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[4] = (datalayer.battery.status.max_discharge_current_dA >> 8);
|
||||
SMA_358.data.u8[5] = (datalayer.battery.status.max_discharge_current_dA & 0x00FF);
|
||||
//Charge limited current, 125 =12.5A (0.1, A)
|
||||
SMA_00D.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[6] = (datalayer.battery.status.max_charge_current_dA >> 8);
|
||||
SMA_358.data.u8[7] = (datalayer.battery.status.max_charge_current_dA & 0x00FF);
|
||||
|
||||
// Battery State
|
||||
//SOC (100.00%)
|
||||
SMA_00F.data.u8[0] = (datalayer.battery.status.reported_soc >> 8);
|
||||
SMA_00F.data.u8[1] = (datalayer.battery.status.reported_soc & 0x00FF);
|
||||
SMA_3D8.data.u8[0] = (datalayer.battery.status.reported_soc >> 8);
|
||||
SMA_3D8.data.u8[1] = (datalayer.battery.status.reported_soc & 0x00FF);
|
||||
//StateOfHealth (100.00%)
|
||||
SMA_00F.data.u8[2] = (datalayer.battery.status.soh_pptt >> 8);
|
||||
SMA_00F.data.u8[3] = (datalayer.battery.status.soh_pptt & 0x00FF);
|
||||
SMA_3D8.data.u8[2] = (datalayer.battery.status.soh_pptt >> 8);
|
||||
SMA_3D8.data.u8[3] = (datalayer.battery.status.soh_pptt & 0x00FF);
|
||||
//State of charge (AH, 0.1)
|
||||
SMA_00F.data.u8[4] = (ampere_hours_remaining >> 8);
|
||||
SMA_00F.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);
|
||||
SMA_3D8.data.u8[4] = (ampere_hours_remaining >> 8);
|
||||
SMA_3D8.data.u8[5] = (ampere_hours_remaining & 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)
|
||||
SMA_013.data.u8[0] = (datalayer.battery.status.voltage_dV >> 8);
|
||||
SMA_013.data.u8[1] = (datalayer.battery.status.voltage_dV & 0x00FF);
|
||||
SMA_4D8.data.u8[0] = (datalayer.battery.status.voltage_dV >> 8);
|
||||
SMA_4D8.data.u8[1] = (datalayer.battery.status.voltage_dV & 0x00FF);
|
||||
//Current (TODO: signed OK?)
|
||||
SMA_013.data.u8[2] = (datalayer.battery.status.current_dA >> 8);
|
||||
SMA_013.data.u8[3] = (datalayer.battery.status.current_dA & 0x00FF);
|
||||
SMA_4D8.data.u8[2] = (datalayer.battery.status.current_dA >> 8);
|
||||
SMA_4D8.data.u8[3] = (datalayer.battery.status.current_dA & 0x00FF);
|
||||
//Temperature average
|
||||
SMA_013.data.u8[4] = (temperature_average >> 8);
|
||||
SMA_013.data.u8[5] = (temperature_average & 0x00FF);
|
||||
//Battery state
|
||||
SMA_013.data.u8[6] = batteryState;
|
||||
SMA_013.data.u8[6] = inverterControlFlags;
|
||||
|
||||
// Battery Temperature and Cellvoltages
|
||||
// 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;
|
||||
SMA_4D8.data.u8[4] = (temperature_average >> 8);
|
||||
SMA_4D8.data.u8[5] = (temperature_average & 0x00FF);
|
||||
//Battery ready
|
||||
if (datalayer.battery.status.bms_status == FAULT) {
|
||||
SMA_4D8.data.u8[6] = STOP_STATE;
|
||||
} else {
|
||||
SMA_4D8.data.u8[6] = READY_STATE;
|
||||
}
|
||||
}
|
||||
|
||||
void receive_can_inverter(CAN_frame rx_frame) {
|
||||
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;
|
||||
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;
|
||||
break;
|
||||
case 0x010: //Time from inverter
|
||||
case 0x5E0: //Message originating from SMA inverter - String
|
||||
datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE;
|
||||
//Inverter brand (frame1-3 = 0x53 0x4D 0x41) = SMA
|
||||
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;
|
||||
send_tripower_init();
|
||||
break;
|
||||
case 0x017: //Initialization message from inverter 2
|
||||
datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE;
|
||||
//send_tripower_init();
|
||||
break;
|
||||
default:
|
||||
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() {
|
||||
unsigned long currentMillis = millis();
|
||||
|
||||
// Send CAN Message every 500ms
|
||||
if (currentMillis - previousMillis500ms >= INTERVAL_500_MS) {
|
||||
previousMillis500ms = currentMillis;
|
||||
|
||||
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
|
||||
// Send CAN Message only if we're enabled by inverter
|
||||
if (!datalayer.system.status.inverter_allows_contactor_closing) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (batteryAlarm) { //Non-cyclic
|
||||
transmit_can(&SMA_005, can_config.inverter); // Battery Alarms 1
|
||||
transmit_can(&SMA_007, can_config.inverter); // Battery Alarms 2
|
||||
if (listLength > 0 && currentMillis - previousMillis250ms >= INTERVAL_250_MS) {
|
||||
previousMillis250ms = currentMillis;
|
||||
// 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
|
||||
transmit_can(&SMA_006, can_config.inverter); // Battery Errorcode
|
||||
transmit_can(&SMA_008, can_config.inverter); // Battery Events
|
||||
if (!pairing_completed) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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() {
|
||||
transmit_can(&SMA_015, can_config.inverter); // Battery Data 1
|
||||
transmit_can(&SMA_016, can_config.inverter); // Battery Data 2
|
||||
transmit_can(&SMA_017, can_config.inverter); // Battery Manufacturer
|
||||
transmit_can(&SMA_018, can_config.inverter); // Battery Name
|
||||
listLength = 0; // clear all frames
|
||||
|
||||
pushFrame(&SMA_558); //Pairing start - Vendor
|
||||
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
|
||||
strncpy(datalayer.system.info.inverter_protocol, "SMA Tripower CAN", 63);
|
||||
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
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
|
||||
#define CAN_INVERTER_SELECTED
|
||||
|
||||
#define READY_STATE 0x03
|
||||
#define STOP_STATE 0x02
|
||||
|
||||
void send_tripower_init();
|
||||
void transmit_can(CAN_frame* tx_frame, int interface);
|
||||
void setup_inverter(void);
|
||||
|
|
|
@ -68,7 +68,7 @@ CAN_frame SOLAX_187E = {.FD = false, //Needed for Ultra
|
|||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.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
|
||||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
|
@ -88,7 +88,7 @@ CAN_frame SOLAX_187A = {.FD = false, //Needed for Ultra
|
|||
.ext_ID = true,
|
||||
.DLC = 8,
|
||||
.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,
|
||||
.ext_ID = true,
|
||||
.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[2] = 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() {
|
||||
|
@ -212,7 +219,9 @@ void receive_can_inverter(CAN_frame rx_frame) {
|
|||
#endif
|
||||
datalayer.system.status.inverter_allows_contactor_closing = false;
|
||||
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_1873, 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):
|
||||
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_1873, 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):
|
||||
datalayer.system.status.inverter_allows_contactor_closing = true;
|
||||
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_1873, 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);
|
||||
datalayer.system.info.inverter_protocol[63] = '\0';
|
||||
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
|
||||
|
|
|
@ -64,7 +64,7 @@ _____ _ _ ___ _____ _
|
|||
#include "Update.h"
|
||||
#include "StreamString.h"
|
||||
#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"
|
||||
#define ELEGANTOTA_WEBSERVER AsyncWebServer
|
||||
#else
|
||||
|
|
|
@ -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.
|
|
@ -1,62 +0,0 @@
|
|||
# AsyncTCP
|
||||
|
||||
[](https://opensource.org/license/lgpl-3-0/)
|
||||
[](https://github.com/mathieucarbou/AsyncTCP/actions/workflows/ci.yml)
|
||||
[](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)
|
||||
```
|
|
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -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=*
|
|
@ -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
|
@ -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_ */
|
2
Software/src/lib/me-no-dev-AsyncTCP/.gitignore
vendored
Normal file
2
Software/src/lib/me-no-dev-AsyncTCP/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
|
||||
.DS_Store
|
34
Software/src/lib/me-no-dev-AsyncTCP/.travis.yml
Normal file
34
Software/src/lib/me-no-dev-AsyncTCP/.travis.yml
Normal 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
|
30
Software/src/lib/me-no-dev-AsyncTCP/Kconfig.projbuild
Normal file
30
Software/src/lib/me-no-dev-AsyncTCP/Kconfig.projbuild
Normal 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
|
15
Software/src/lib/me-no-dev-AsyncTCP/README.md
Normal file
15
Software/src/lib/me-no-dev-AsyncTCP/README.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
This is commit ca8ac5f from https://github.com/me-no-dev/AsyncTCP
|
||||
|
||||
# AsyncTCP
|
||||
[](https://travis-ci.org/me-no-dev/AsyncTCP)  [](https://www.codacy.com/manual/me-no-dev/AsyncTCP?utm_source=github.com&utm_medium=referral&utm_content=me-no-dev/AsyncTCP&utm_campaign=Badge_Grade)
|
||||
|
||||
### Async TCP Library for ESP32 Arduino
|
||||
|
||||
[](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.
|
22
Software/src/lib/me-no-dev-AsyncTCP/library.json
Normal file
22
Software/src/lib/me-no-dev-AsyncTCP/library.json
Normal 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
|
||||
}
|
||||
}
|
9
Software/src/lib/me-no-dev-AsyncTCP/library.properties
Normal file
9
Software/src/lib/me-no-dev-AsyncTCP/library.properties
Normal 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=*
|
1387
Software/src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.cpp
Normal file
1387
Software/src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.cpp
Normal file
File diff suppressed because it is too large
Load diff
220
Software/src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.h
Normal file
220
Software/src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.h
Normal 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_ */
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#include <Arduino.h>
|
||||
#ifdef ESP32
|
||||
#include "../../mathieucarbou-AsyncTCP/src/AsyncTCP.h"
|
||||
#include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h"
|
||||
#define SSE_MAX_QUEUED_MESSAGES 32
|
||||
#else
|
||||
#include <ESPAsyncTCP.h>
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
#include <Arduino.h>
|
||||
#ifdef ESP32
|
||||
#include "../../mathieucarbou-AsyncTCP/src/AsyncTCP.h"
|
||||
#include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h"
|
||||
#define WS_MAX_QUEUED_MESSAGES 32
|
||||
#else
|
||||
#include <ESPAsyncTCP.h>
|
||||
|
|
|
@ -30,10 +30,10 @@
|
|||
|
||||
#ifdef ESP32
|
||||
#include <WiFi.h>
|
||||
#include "../../mathieucarbou-AsyncTCP/src/AsyncTCP.h"
|
||||
#include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h"
|
||||
#elif defined(ESP8266)
|
||||
#include <ESP8266WiFi.h>
|
||||
#include "../../mathieucarbou-AsyncTCP/src/AsyncTCP.h"
|
||||
#include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h"
|
||||
#else
|
||||
#error Platform not supported
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue