Compare commits

...

90 commits
v9.0.0 ... main

Author SHA1 Message Date
Daniel Öster
f3a6157080
Merge pull request #1592 from dalathegreat/improvement/stark-BMS-on-by-default
Stark CMR: Make BMS power on by default
2025-10-02 14:27:47 +03:00
Daniel Öster
867512eecd Make Stark BMS power on by default 2025-10-01 21:13:41 +03:00
Daniel Öster
f9109d0348
Merge pull request #1587 from dalathegreat/bugfix/passwords-dashes
Bugfix: Allow dash as special character in usernames/passwords
2025-10-01 20:08:27 +03:00
Daniel Öster
9943406836 Make Wifi use actual set SSID for AP 2025-09-30 23:29:08 +03:00
Daniel Öster
18ee9d6c27 Allow dash as special character in usernames/passwords 2025-09-30 22:16:05 +03:00
Daniel Öster
31ea1f0928
Update Software.cpp 2025-09-30 14:43:14 +03:00
Daniel Öster
dad97b36e1
Update Software.cpp 2025-09-30 14:37:22 +03:00
Daniel Öster
19a1634f4e
Merge pull request #1580 from jonny5532/fix/settings-validation
Fix hostname/MQTT settings validation
2025-09-28 14:08:04 +03:00
Jonny
aa375dc36a Fix broken hostname/MQTT settings validation 2025-09-28 09:05:30 +01:00
Jonny
a91f8ab4d4 Remove redundant ^$ on settings input patterns 2025-09-28 08:59:38 +01:00
Daniel Öster
7fbc9ffcc6
Merge pull request #1575 from greenoem/tesla-feature-events
Feature: Tesla - add initial/basic events
2025-09-27 23:15:05 +03:00
Daniel Öster
579e0e0bcc
Update Software.cpp 2025-09-27 22:09:42 +03:00
James Brookes
b26c451eaf Fix % in SOC_RECALIBRATION string 2025-09-27 19:27:15 +01:00
James Brookes
ee9e78e80b Merge branch 'tesla-feature-events' of https://github.com/greenoem/Battery-Emulator into tesla-feature-events 2025-09-27 18:04:10 +01:00
James Brookes
706b4a7cea Add contactor weld warning event, change events to native latch type 2025-09-27 18:03:56 +01:00
greenoem
f5ba607fa6
Merge branch 'dalathegreat:main' into tesla-feature-events 2025-09-26 21:21:46 +01:00
Daniel Öster
572867b7ad
Update Software.cpp 2025-09-26 21:33:04 +03:00
Daniel Öster
47e715ffe5
Merge pull request #1572 from dalathegreat/bugfix/chars-non-ascii
Improvement: Add more input field validation on Settings page
2025-09-26 21:31:38 +03:00
Daniel Öster
c445bd1869 Move factory reset to top of page, tweak password 2025-09-26 21:27:19 +03:00
Daniel Öster
28c0267cae Improve password/username entering 2025-09-26 19:29:50 +03:00
Daniel Öster
4058050423 Add more tooltips 2025-09-26 13:45:39 +03:00
James Brookes
04d9a36292 Add event and logging text for SOC Reset 2025-09-26 10:38:56 +01:00
Daniel Öster
29129037b0 Add more input field validation on Settings page 2025-09-25 23:44:46 +03:00
James Brookes
c6b7ff82c0 Alter BMS_a145_SW_SOC_Change event to once only 2025-09-25 19:09:46 +01:00
James Brookes
95ee6ff9ae Add events for BMS_a145_SW_SOC_Change, BMS reset and SOC reset 2025-09-25 19:03:54 +01:00
Daniel Öster
8cc10a1b71
Merge pull request #1568 from dalathegreat/bugfix/tesla-task-overrun-logging
Performance: Reduce likelyhood of TASK_OVERRUN when using Tesla
2025-09-25 16:04:01 +03:00
Daniel Öster
3ef3279527 Remove unused codeblocks 2025-09-25 15:49:50 +03:00
Daniel Öster
f48b4235c1 Simplify DigitalHVIL sending to increase performance 2025-09-25 15:30:52 +03:00
Daniel Öster
cdf6314bff
Merge pull request #1567 from dalathegreat/bugfix/egmp-cellvoltage-count
Kia E-GMP: Update valid cellvoltage filter
2025-09-25 14:36:39 +03:00
Daniel Öster
48411680c6 Raise limit further 2025-09-25 12:04:36 +03:00
Daniel Öster
132029169d Raise limit to 2500 for filtering 2025-09-25 11:09:56 +03:00
Daniel Öster
483d4300b1 Make sure user only enables one general logging method at once 2025-09-25 00:00:59 +03:00
Daniel Öster
397e8d03a1 Remove/shorten periodically logged items 2025-09-25 00:00:35 +03:00
Daniel Öster
d336b75f56 Update valid cellvoltage filter 2025-09-24 22:54:53 +03:00
Daniel Öster
a7af7cf938
Merge pull request #1563 from greenoem/tesla-fix-gtw
Tesla: Fix GTW 0x7FF frame incorrect value written
2025-09-23 20:32:10 +03:00
James Brookes
2ba937bd32 Fix incorrect user_selected_tesla_GTW_country value written to 7FF user_selected_tesla_GTW_rightHandDrive bit 2025-09-23 18:10:24 +01:00
Daniel Öster
48d416b5c4
Update Software.cpp 2025-09-23 10:28:46 +03:00
Daniel Öster
ed2ebb00fd
Update Software.cpp 2025-09-23 10:01:21 +03:00
Daniel Öster
0458267634
Merge pull request #1560 from dalathegreat/improvement/enable-qio-stark
Enable QIO and 80MHZ flash on Stark CMR
2025-09-23 09:43:21 +03:00
Daniel Öster
a0de6b092b Enable QIO and 80MHZ flash on Stark CMR 2025-09-23 09:38:28 +03:00
Daniel Öster
0f2cbe8f04
Merge pull request #1559 from jonny5532/feature/enable-qio
Enable QIO and 80mhz flash on Lilygo T-CAN485 build (50-80% more perf)
2025-09-23 09:32:08 +03:00
Jonny
983105ab6a Enable QIO and 80mhz flash on Lilygo T-CAN485 build (50-80% perf improvement) 2025-09-23 07:15:11 +01:00
Daniel Öster
5aa657e0b5
Merge pull request #1557 from dalathegreat/improvement/wifi-name-access
Improvement: Make AP name configurable
2025-09-23 09:12:33 +03:00
Daniel Öster
69ae0385fb Make AP name configurable 2025-09-22 15:36:41 +03:00
Daniel Öster
a8d74f5885
Merge pull request #1535 from korhojoa/zopfli
Repackage OTA html file with zopfli
2025-09-22 15:16:21 +03:00
Daniel Öster
20b6ea5e85
Merge pull request #1531 from dalathegreat/bugfix/reduce-flash
Improvement: Reduce flash usage
2025-09-22 14:53:54 +03:00
Daniel Öster
b8bbb02b20
Merge pull request #1540 from dalathegreat/bugfix/zoe1-voltage-limits
Bugfix: Tweak voltage limits for Zoe1
2025-09-22 12:29:44 +03:00
Daniel Öster
4896f3061a
Merge pull request #1491 from dalathegreat/improvement/stellantis-can-mappings
Improvement: Stellantis CAN mappings
2025-09-22 10:34:44 +03:00
Daniel Öster
0aaab6d4b7
Merge pull request #1548 from dalathegreat/improvement/volvo-low-12V
Volvo SPA: Add low 12V voltage safety
2025-09-22 10:34:22 +03:00
Daniel Öster
a12ea4b112
Update README.md 2025-09-21 21:02:45 +03:00
Daniel Öster
e023962bfc
Merge pull request #1555 from dalathegreat/improvement/SMA-naming
Rename protocol to make it more clear it is SMA
2025-09-20 23:56:23 +03:00
Daniel Öster
4df42e10b4 Rename protocol to make it more clear it is SMA 2025-09-20 23:49:47 +03:00
Daniel Öster
ee4981b6e1
Merge pull request #1554 from mbuhansen/main
Kostal revert startup counter.
2025-09-20 22:34:04 +03:00
mbuhansen
172e260167
Update GPIO pin assignments for contactor handling 2025-09-20 21:20:41 +02:00
mbuhansen
fd52c0e5e7
Uncomment contactor welded event checks 2025-09-20 21:19:08 +02:00
mbuhansen
6982476e89
Change contactor closing condition from 20 to 7 frames 2025-09-20 21:14:57 +02:00
mbuhansen
24c1ce73ae
Merge branch 'dalathegreat:main' into main 2025-09-20 21:13:04 +02:00
Daniel Öster
d8530a2b8b
Update README.md 2025-09-20 13:45:30 +03:00
Daniel Öster
7a5cd36e6d
Update README.md 2025-09-20 13:37:02 +03:00
Daniel Öster
3bfc350b65
Merge pull request #1546 from dalathegreat/bugfix/egmp-estimated-soc-configurable
Kia eGMP: Add configurable option for estimated SOC
2025-09-19 10:03:42 +03:00
Daniel Öster
b52bc7bfd4
Merge pull request #1545 from dalathegreat/bugfix/tesla-contactor-opening
Tesla: Make contactor opening take 9s instead of 60s
2025-09-19 10:03:29 +03:00
mbuhansen
89abc6a964
Update GPIO pin assignments for contactors 2025-09-19 08:45:19 +02:00
mbuhansen
45643237e4
Comment out contactor welded event checks 2025-09-19 08:42:19 +02:00
Daniel Öster
e66161176b Fix scaling on Rescaled SOC on More Battery Info page 2025-09-18 22:24:32 +03:00
Daniel Öster
269c655dc5 Add low 12V voltage safety to Volvo 2025-09-18 10:48:56 +03:00
Daniel Öster
15143d1384 Add configurable option for estimated SOC 2025-09-17 23:23:55 +03:00
Daniel Öster
0244468624 Make contactor opening take 9s instead of 60s 2025-09-17 23:06:30 +03:00
Daniel Öster
3ead4d12d4
Merge pull request #1543 from jonny5532/fix/allow-8char-wifi-passwords
Fix validation so that 8 character WiFi passwords work
2025-09-16 19:39:05 +03:00
Jonny
5277665dd1 Fix validation so that 8 character WiFi passwords work 2025-09-16 16:14:20 +01:00
Daniel Öster
79964a0601 Remove old method to disable webserver to save flash 2025-09-16 14:44:30 +03:00
Daniel Öster
e11843e4a0 Merge branch 'main' into bugfix/reduce-flash 2025-09-16 14:41:12 +03:00
Daniel Öster
df52d067e7
Update Software.cpp 2025-09-16 13:36:42 +03:00
Daniel Öster
1ea663c0b9
Merge pull request #1541 from jonny5532/fix/dont-error-if-ssid-pw-blank
Stop erroneous events when saving an empty SSID/pw
2025-09-15 23:11:37 +03:00
Jonny
73c6821a9a Stop erroneous events when saving an empty SSID/pw 2025-09-15 20:23:35 +01:00
Daniel Öster
26126bae1a Tweak voltage limits for Zoe1 2025-09-15 14:42:54 +03:00
korhojoa
6094a2c85b Add tool to easily replace OTA file 2025-09-13 17:28:56 +03:00
korhojoa
b5d14edb94 Repackage OTA gzip with zopfli 2025-09-13 17:28:47 +03:00
Daniel Öster
bf14553d77 Add notes on BYD messages 2025-09-13 10:53:11 +03:00
Daniel Öster
fdc1fb61ba Improve Afore writing of name 2025-09-12 22:39:01 +03:00
Daniel Öster
2546b6da21 Reduce CAN templates in BYD-CAN 2025-09-12 22:32:03 +03:00
Daniel Öster
7178e0376e Reduce CAN messages used by Kia PHEV 2025-09-12 22:19:44 +03:00
Daniel Öster
0aad11d9bc Add contactor state to more battery info 2025-09-11 23:27:15 +03:00
Daniel Öster
29e6f52c4c Add alerts to more battery info page 2025-09-11 23:05:06 +03:00
Daniel Öster
25393106b8 Merge branch 'main' into improvement/stellantis-can-mappings 2025-09-11 21:32:22 +03:00
Daniel Öster
fd2e5f2e52 Add start for MysteryVan More Info page 2025-09-11 21:30:56 +03:00
Daniel Öster
30a7b9d90e Add notes on CAN sending 2025-09-07 20:14:38 +03:00
Daniel Öster
e02cb61efc Add final CAN mappings for MysteryVan 2025-09-07 18:55:00 +03:00
Daniel Öster
64a3d5f5aa Add more CAN mappings 2025-09-07 00:01:35 +03:00
Daniel Öster
cfdc1a3130 Improve mappings 2025-09-06 21:21:53 +03:00
Daniel Öster
54f9cb49f3 Add mappings for 2D4, 3B4 and 2F4 2025-09-04 23:21:26 +03:00
36 changed files with 811 additions and 541 deletions

View file

@ -33,52 +33,18 @@ At the same time, EV manufacturers have been putting high capacity battery packs
For examples showing wiring, see each battery type's own Wiki page. For instance the [Nissan LEAF page](https://github.com/dalathegreat/Battery-Emulator/wiki/Battery:-Nissan-LEAF---e%E2%80%90NV200)
## How to compile the software 💻
## How to install the software 💻
Start by watching this [quickstart guide](https://www.youtube.com/watch?v=hcl2GdHc0Y0)
Start by watching this [quickstart guide](https://www.youtube.com/watch?v=sR3t7j0R9Z0)
[![IMAGE ALT TEXT HERE](https://img.youtube.com/vi/hcl2GdHc0Y0/0.jpg)](https://www.youtube.com/watch?v=hcl2GdHc0Y0)
[![IMAGE ALT TEXT HERE](https://img.youtube.com/vi/sR3t7j0R9Z0/0.jpg)](https://www.youtube.com/watch?v=sR3t7j0R9Z0)
1. Download the Arduino IDE: https://www.arduino.cc/en/software
2. Open the Arduino IDE.
3. Click `File` menu -> `Preferences` -> `Additional Development` -> `Additional Board Manager URLs` -> Enter the URL in the input box: `https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json` and click OK.
4. Click `Tools` menu -> `Board: "...."` -> `Boards Manager...`, install the `esp32` package by `Espressif Systems` (not `Arduino ESP32 Boards`), then press `Close`.
**NOTE: The ESP32 version depends on which release of Battery-Emulator you are running! See the [Release Notes](https://github.com/dalathegreat/Battery-Emulator/releases) for more info on which version to use with the current version (Suggested ESP32 version X.Y.Z)**
![bild](https://github.com/dalathegreat/Battery-Emulator/assets/26695010/6a2414b1-f2ca-4746-8e8d-9afd78bd9252)
5. The Arduino board should be set to `ESP32 Dev Module` and `Partition Scheme` to `Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS)` (under `Tools` -> `Board` -> `ESP32 Arduino`) with the following settings:
![ArduinoSettings](https://github.com/user-attachments/assets/74d36b07-cca4-4bf1-9eaf-1e7fa4e1effe)
6. Select which battery type you will use, along with other optional settings. This is done in the `USER_SETTINGS.h` file.
7. Copy the `USER_SECRETS.TEMPLATE.h` file to `USER_SECRETS.h` and update connectivity settings inside this file.
8. Press `Verify` and `Upload` to send the sketch to the board.
NOTE: In some cases, the LilyGo must be powered through the main power connector instead of USB-C
when performing the initial firmware upload.
NOTE: On Mac, the following USB driver may need to be installed: https://github.com/WCHSoftGroup/ch34xser_macos
NOTE: If you see garbled messages on the serial console, change the serial console to match the baud rate to the code, currently 115200.
NOTE: If you see the error `Sketch too big` then check you set the Partition Scheme above correctly.
This video explains all the above mentioned steps:
<https://youtu.be/_mH2AjnAjDk>
### Linux Development Environment Setup
In addition to the steps above, ESP32 requires a dependency for a Python module, pyserial install using the cli.\
```python3 -m pip install pyserial```
If you're using Ubuntu , use apt to manage the dependencies of arduino:\
pyserial install: ```sudo apt install python3-serial```
Arduino AppImage must be set as executable after downloading to run correctly\
example: ```chmod 775 arduino-ide_2.3.3_Linux_64bit.AppImage```
Also you might need to install FUSE to run appimages
```sudo apt install libfuse2```
1. Open the [webinstaller page](https://dalathegreat.github.io/BE-Web-Installer/)
2. Follow the instructions on that page to install the software
3. After successful installation, connect to the wireless network (Battery-Emulator , password: 123456789)
4. Go to setup page and configure component selection
5. (OPTIONAL, connect the board to your home Wifi)
6. Connect your battery and inverter to the board and you are done! 🔋⚡
## Dependencies 📖
This code uses the following excellent libraries:
@ -88,7 +54,7 @@ This code uses the following excellent libraries:
- [eModbus/eModbus](https://github.com/eModbus/eModbus) MIT-License
- [ESP32Async/AsyncTCP](https://github.com/ESP32Async/AsyncTCP) LGPL-3.0 license
- [ESP32Async/ESPAsyncWebServer](https://github.com/ESP32Async/ESPAsyncWebServer) LGPL-3.0 license
- [miwagner/ESP32-Arduino-CAN](https://github.com/miwagner/ESP32-Arduino-CAN/) MIT-License
- [pierremolinaro/acan-esp32](https://github.com/pierremolinaro/acan-esp32) MIT-License
- [pierremolinaro/acan2515](https://github.com/pierremolinaro/acan2515) MIT-License
- [pierremolinaro/acan2517FD](https://github.com/pierremolinaro/acan2517FD) MIT-License

View file

@ -34,7 +34,7 @@
#endif
// The current software version, shown on webserver
const char* version_number = "9.0.0";
const char* version_number = "9.2.dev";
// Interval timers
volatile unsigned long currentMillis = 0;
@ -86,9 +86,7 @@ void connectivity_loop(void*) {
// Init wifi
init_WiFi();
if (webserver_enabled) {
init_webserver();
}
if (mdns_enabled) {
init_mDNS();
@ -98,9 +96,7 @@ void connectivity_loop(void*) {
START_TIME_MEASUREMENT(wifi);
wifi_monitor();
if (webserver_enabled) {
ota_monitor();
}
END_TIME_MEASUREMENT_MAX(wifi, datalayer.system.status.wifi_task_10s_max_us);
@ -388,11 +384,9 @@ void core_loop(void*) {
END_TIME_MEASUREMENT_MAX(comm, datalayer.system.status.time_comm_us);
if (webserver_enabled) {
START_TIME_MEASUREMENT(ota);
ElegantOTA.loop();
END_TIME_MEASUREMENT_MAX(ota, datalayer.system.status.time_ota_us);
}
// Process
currentMillis = millis();

View file

@ -296,6 +296,8 @@ bool user_selected_tesla_GTW_rightHandDrive = true;
uint16_t user_selected_tesla_GTW_mapRegion = 2;
uint16_t user_selected_tesla_GTW_chassisType = 2;
uint16_t user_selected_tesla_GTW_packEnergy = 1;
/* User-selected EGMP+others settings */
bool user_selected_use_estimated_SOC = false;
// Use 0V for user selected cell/pack voltage defaults (On boot will be replaced with saved values from NVM)
uint16_t user_selected_max_pack_voltage_dV = 0;

View file

@ -62,7 +62,7 @@ extern uint16_t user_selected_max_pack_voltage_dV;
extern uint16_t user_selected_min_pack_voltage_dV;
extern uint16_t user_selected_max_cell_voltage_mV;
extern uint16_t user_selected_min_cell_voltage_mV;
extern bool user_selected_use_estimated_SOC;
extern bool user_selected_LEAF_interlock_mandatory;
extern bool user_selected_tesla_digital_HVIL;
extern uint16_t user_selected_tesla_GTW_country;

View file

@ -5,8 +5,27 @@
#include "../devboard/utils/events.h"
/* TODO:
This integration is still ongoing. Here is what still needs to be done in order to use this battery type
- Disable the isolation resistance requirement that opens contactors after 30s under load. Factory mode?
This integration is still ongoing. The same integration can be used on multiple variants of the Stellantis platforms
- eCMP: Disable the isolation resistance requirement that opens contactors after 30s under load. Factory mode?
- MysteryVan: Map more values from constantly transmitted instead of PID
- ADD CAN sending towards the battery (CAN-logs of full vehicle wanted!)
- Following CAN messages need to be sent towards it:
- VCU: 4C9 , 565 , 398, 448, 458, 4F1 , 342, 3E2 , 402 , 422 , 482 4D1
- CMM: 478 , 558, 1A8, 4B8 1F8 498 4E8
- OBC: 531 441 541 551 3C1
- BSIInfo_382
- VCU_BSI_Wakeup_27A
- V2_BSI_552
- CRASH_4C8
- EVSE plug in (optional): 108, 109, 119
- CRASH_4C8
- CRNT_SENS_095
- MCU 526
- JDD 55F NEW
- STLA medium: Everything missing
- ADD CAN sending towards the battery (CAN-logs of full vehicle wanted!)
*/
/* Do not change code below unless you are sure what you are doing */
@ -95,6 +114,8 @@ void EcmpBattery::update_values() {
datalayer.battery.status.cell_max_voltage_mV = pid_high_cell_voltage;
datalayer.battery.status.cell_min_voltage_mV = pid_low_cell_voltage;
}
datalayer.battery.info.number_of_cells = NUMBER_OF_CELL_MEASUREMENTS_IN_BATTERY; //50/75kWh sends valid cellcount
}
// Update extended datalayer (More Battery Info page)
@ -170,6 +191,28 @@ void EcmpBattery::update_values() {
datalayer_extended.stellantisECMP.pid_contactor_closing_counter = pid_contactor_closing_counter;
datalayer_extended.stellantisECMP.pid_date_of_manufacture = pid_date_of_manufacture;
datalayer_extended.stellantisECMP.pid_SOH_cell_1 = pid_SOH_cell_1;
// Update extended datalayer for MysteryVan
datalayer_extended.stellantisECMP.MysteryVan = MysteryVan;
datalayer_extended.stellantisECMP.CONTACTORS_STATE = CONTACTORS_STATE;
datalayer_extended.stellantisECMP.CrashMemorized = HV_BATT_CRASH_MEMORIZED;
datalayer_extended.stellantisECMP.CONTACTOR_OPENING_REASON = CONTACTOR_OPENING_REASON;
datalayer_extended.stellantisECMP.TBMU_FAULT_TYPE = TBMU_FAULT_TYPE;
datalayer_extended.stellantisECMP.HV_BATT_FC_INSU_MINUS_RES = HV_BATT_FC_INSU_MINUS_RES;
datalayer_extended.stellantisECMP.HV_BATT_FC_INSU_PLUS_RES = HV_BATT_FC_INSU_PLUS_RES;
datalayer_extended.stellantisECMP.HV_BATT_FC_VHL_INSU_PLUS_RES = HV_BATT_FC_VHL_INSU_PLUS_RES;
datalayer_extended.stellantisECMP.HV_BATT_ONLY_INSU_MINUS_RES = HV_BATT_ONLY_INSU_MINUS_RES;
datalayer_extended.stellantisECMP.HV_BATT_ONLY_INSU_MINUS_RES = HV_BATT_ONLY_INSU_MINUS_RES;
datalayer_extended.stellantisECMP.ALERT_CELL_POOR_CONSIST = ALERT_CELL_POOR_CONSIST;
datalayer_extended.stellantisECMP.ALERT_OVERCHARGE = ALERT_OVERCHARGE;
datalayer_extended.stellantisECMP.ALERT_BATT = ALERT_BATT;
datalayer_extended.stellantisECMP.ALERT_LOW_SOC = ALERT_LOW_SOC;
datalayer_extended.stellantisECMP.ALERT_HIGH_SOC = ALERT_HIGH_SOC;
datalayer_extended.stellantisECMP.ALERT_SOC_JUMP = ALERT_SOC_JUMP;
datalayer_extended.stellantisECMP.ALERT_TEMP_DIFF = ALERT_TEMP_DIFF;
datalayer_extended.stellantisECMP.ALERT_HIGH_TEMP = ALERT_HIGH_TEMP;
datalayer_extended.stellantisECMP.ALERT_OVERVOLTAGE = ALERT_OVERVOLTAGE;
datalayer_extended.stellantisECMP.ALERT_CELL_OVERVOLTAGE = ALERT_CELL_OVERVOLTAGE;
datalayer_extended.stellantisECMP.ALERT_CELL_UNDERVOLTAGE = ALERT_CELL_UNDERVOLTAGE;
if (battery_InterlockOpen) {
set_event(EVENT_HVIL_FAILURE, 0);
@ -192,56 +235,221 @@ void EcmpBattery::update_values() {
void EcmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
switch (rx_frame.ID) {
case 0x2D4: //MysteryVan 50/75kWh platform
case 0x2D4: //MysteryVan 50/75kWh platform (TBMU 100ms periodic)
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
MysteryVan = true;
SOE_MAX_CURRENT_TEMP = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; // (Wh, 0-200000)
FRONT_MACHINE_POWER_LIMIT = (rx_frame.data.u8[4] << 6) | ((rx_frame.data.u8[5] & 0xFC) >> 2); // (W 0-1000000)
REAR_MACHINE_POWER_LIMIT = ((rx_frame.data.u8[5] & 0x03) << 12) | (rx_frame.data.u8[6] << 4) |
((rx_frame.data.u8[7] & 0xF0) >> 4); // (W 0-1000000)
break;
case 0x3B4: //MysteryVan 50/75kWh platform
case 0x3B4: //MysteryVan 50/75kWh platform (TBMU 100ms periodic)
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
EVSE_INSTANT_DC_HV_CURRENT =
((rx_frame.data.u8[2] & 0x03) << 12) | (rx_frame.data.u8[3] << 2) | ((rx_frame.data.u8[4] & 0xC0) >> 6);
EVSE_STATE = ((rx_frame.data.u8[4] & 0x38) >> 3); /*Enumeration below
000: NOT CONNECTED
001: CONNECTED
010: INITIALISATION
011: READY
100: PRECHARGE IN PROGRESS
101: TRANSFER IN PROGRESS
110: NOT READY
111: Reserved */
HV_BATT_SOE_HD = ((rx_frame.data.u8[4] & 0x03) << 12) | (rx_frame.data.u8[5] << 4) |
((rx_frame.data.u8[6] & 0xF0) >> 4); // (Wh, 0-200000)
HV_BATT_SOE_MAX = ((rx_frame.data.u8[6] & 0x03) << 8) | rx_frame.data.u8[7]; // (Wh, 0-200000)
CHECKSUM_FRAME_3B4 = (rx_frame.data.u8[0] & 0xF0) >> 4;
COUNTER_3B4 = (rx_frame.data.u8[0] & 0x0F);
break;
case 0x2F4: //MysteryVan 50/75kWh platform
case 0x2F4: //MysteryVan 50/75kWh platform (Event triggered when charging)
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
//TBMU_EVSE_DC_MES_VOLTAGE = (rx_frame.data.u8[0] << 6) | (rx_frame.data.u8[1] >> 2); //V 0-1000 //Fastcharger info, not needed for BE
//TBMU_EVSE_DC_MIN_VOLTAGE = ((rx_frame.data.u8[1] & 0x03) << 8) | rx_frame.data.u8[2]; //V 0-1000 //Fastcharger info, not needed for BE
//TBMU_EVSE_DC_MES_CURRENT = (rx_frame.data.u8[3] << 4) | ((rx_frame.data.u8[4] & 0xF0) >> 4); //A -2000 - 2000 //Fastcharger info, not needed for BE
//TBMU_EVSE_CHRG_REQ = (rx_frame.data.u8[4] & 0x0C) >> 2; //00 No request, 01 Stop request //Fastcharger info, not needed for BE
//HV_STORAGE_MAX_I = ((rx_frame.data.u8[4] & 0x03) << 12) | (rx_frame.data.u8[5] << 2) | //Fastcharger info, not needed for BE
//((rx_frame.data.u8[6] & 0xC0) >> 6); //A -2000 - 2000
//TBMU_EVSE_DC_MAX_POWER = ((rx_frame.data.u8[6] & 0x3F) << 8) | rx_frame.data.u8[7]; //W -1000000 - 0 //Fastcharger info, not needed for BE
break;
case 0x3F4: //MysteryVan 50/75kWh platform
case 0x3F4: //MysteryVan 50/75kWh platform (Temperature sensors)
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
switch (((rx_frame.data.u8[0] & 0xE0) >> 5)) //Mux resides in top 3 bits of frame0
{
case 0:
BMS_PROBETEMP[0] = (rx_frame.data.u8[1] - 40);
BMS_PROBETEMP[1] = (rx_frame.data.u8[2] - 40);
BMS_PROBETEMP[2] = (rx_frame.data.u8[3] - 40);
BMS_PROBETEMP[3] = (rx_frame.data.u8[4] - 40);
BMS_PROBETEMP[4] = (rx_frame.data.u8[5] - 40);
BMS_PROBETEMP[5] = (rx_frame.data.u8[6] - 40);
BMS_PROBETEMP[6] = (rx_frame.data.u8[7] - 40);
break;
case 0x554: //MysteryVan 50/75kWh platform
default: //There are in total 64 temperature measurements in the BMS. We do not need to sample them all.
break; //For future, we could read them all if we want to.
}
break;
case 0x554: //MysteryVan 50/75kWh platform (Discharge/Charge limits)
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
HV_BATT_PEAK_DISCH_POWER_HD = (rx_frame.data.u8[1] << 6) | (rx_frame.data.u8[2] >> 2); //0-1000000 W
HV_BATT_PEAK_CH_POWER_HD = ((rx_frame.data.u8[2] & 0x03) << 12) | (rx_frame.data.u8[3] << 4) |
((rx_frame.data.u8[4] & 0xF0) >> 4); // -1000000 - 0 W
HV_BATT_NOM_CH_POWER_HD = ((rx_frame.data.u8[4] & 0x0F) << 12) | (rx_frame.data.u8[5] << 6) |
((rx_frame.data.u8[6] & 0xC0) >> 6); // -1000000 - 0 W
MAX_ALLOW_CHRG_CURRENT = ((rx_frame.data.u8[6] & 0x3F) << 8) | rx_frame.data.u8[7];
CHECKSUM_FRAME_554 = (rx_frame.data.u8[0] & 0xF0) >> 4; //Frame checksum 0xE
COUNTER_554 = (rx_frame.data.u8[0] & 0x0F);
break;
case 0x373: //MysteryVan 50/75kWh platform
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
REQ_CLEAR_DTC_TBMU = ((rx_frame.data.u8[3] & 0x40) >> 7);
TBCU_48V_WAKEUP = (rx_frame.data.u8[3] >> 7);
HV_BATT_MAX_REAL_CURR = (rx_frame.data.u8[5] << 7) | (rx_frame.data.u8[6] >> 1); //A -2000 - 2000 0.1 scaling
TBMU_FAULT_TYPE = (rx_frame.data.u8[7] & 0xE0) >> 5;
/*000: No fault
001: FirstLevelFault: Warning Lamp
010: SecondLevelFault: Stop Lamp
011: ThirdLevelFault: Stop Lamp + contactor opening (EPS shutdown)
100: FourthLevelFault: Stop Lamp + Active Discharge
101: Inhibition of powertrain activation
110: Reserved
111: Invalid*/
HV_BATT_REAL_VOLT_HD = ((rx_frame.data.u8[3] & 0x3F) << 8) | (rx_frame.data.u8[4]); //V 0-1000 * 0.1 scaling
HV_BATT_REAL_CURR_HD = (rx_frame.data.u8[1] << 8) | (rx_frame.data.u8[2]); //A -2000 - 2000 0.1 scaling
CHECKSUM_FRAME_373 = (rx_frame.data.u8[0] & 0xF0) >> 4; //Frame checksum 0xD
COUNTER_373 = (rx_frame.data.u8[0] & 0x0F);
break;
case 0x4F4: //MysteryVan 50/75kWh platform
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
HV_BATT_CRASH_MEMORIZED = ((rx_frame.data.u8[2] & 0x08) >> 3);
HV_BATT_COLD_CRANK_ACK = ((rx_frame.data.u8[2] & 0x04) >> 2);
HV_BATT_CHARGE_NEEDED_STATE = ((rx_frame.data.u8[2] & 0x02) >> 1);
HV_BATT_NOM_CH_VOLTAGE = ((rx_frame.data.u8[2] & 0x01) << 8) | (rx_frame.data.u8[3]); //V 0 - 500
HV_BATT_NOM_CH_CURRENT = rx_frame.data.u8[4]; // -120 - 0 0.5scaling
HV_BATT_GENERATED_HEAT_RATE = (rx_frame.data.u8[5] << 1) | (rx_frame.data.u8[6] >> 7); //W 0-50000
REQ_MIL_LAMP_CONTINOUS = (rx_frame.data.u8[7] & 0x04) >> 2;
REQ_BLINK_STOP_AND_SERVICE_LAMP = (rx_frame.data.u8[7] & 0x02) >> 1;
CMD_RESET_MIL = (rx_frame.data.u8[7] & 0x01);
HV_BATT_SOC = (rx_frame.data.u8[1] << 2) | (rx_frame.data.u8[2] >> 6);
CONTACTORS_STATE =
(rx_frame.data.u8[2] & 0x30) >> 4; //00 : contactor open 01 : pre-load contactor 10 : contactor close
HV_BATT_DISCONT_WARNING_OPEN = (rx_frame.data.u8[7] & 0x08) >> 3;
CHECKSUM_FRAME_4F4 = (rx_frame.data.u8[0] & 0xF0) >> 4;
COUNTER_4F4 = (rx_frame.data.u8[0] & 0x0F);
break;
case 0x414: //MysteryVan 50/75kWh platform
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
HV_BATT_REAL_POWER_HD = (rx_frame.data.u8[1] << 7) | (rx_frame.data.u8[2] >> 1);
MAX_ALLOW_CHRG_POWER =
((rx_frame.data.u8[2] & 0x01) << 13) | (rx_frame.data.u8[3] << 5) | ((rx_frame.data.u8[4] & 0xF8) >> 3);
MAX_ALLOW_DISCHRG_POWER =
((rx_frame.data.u8[5] & 0x07) << 11) | (rx_frame.data.u8[6] << 3) | ((rx_frame.data.u8[7] & 0xE0) >> 5);
CHECKSUM_FRAME_414 = (rx_frame.data.u8[0] & 0xF0) >> 4; //Frame checksum 0x9
COUNTER_414 = (rx_frame.data.u8[0] & 0x0F);
break;
case 0x353: //MysteryVan 50/75kWh platform
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
HV_BATT_COP_VOLTAGE =
(rx_frame.data.u8[1] << 5) | (rx_frame.data.u8[2] >> 3); //Real voltage HV battery (dV, 0-5000)
HV_BATT_COP_CURRENT =
(rx_frame.data.u8[3] << 5) | (rx_frame.data.u8[4] >> 3); //High resolution battery current (dA, -4000 - 4000)
CHECKSUM_FRAME_353 = (rx_frame.data.u8[0] & 0xF0) >> 4; //Frame checksum 0xB
COUNTER_353 = (rx_frame.data.u8[0] & 0x0F);
break;
case 0x474: //MysteryVan 50/75kWh platform
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
BMS_DC_RELAY_MES_EVSE_VOLTAGE = (rx_frame.data.u8[1] << 6) | (rx_frame.data.u8[2] >> 2); //V 0-1000
FAST_CHARGE_CONTACTOR_STATE = (rx_frame.data.u8[2] & 0x03);
/*00: Contactors Opened
01: Contactors Closed
10: No Request
11: WELDING TEST*/
BMS_FASTCHARGE_STATUS = (rx_frame.data.u8[4] & 0x03);
/*00 : not charging
01 : charging
10 : charging fault
11 : charging finished*/
CHECKSUM_FRAME_474 = (rx_frame.data.u8[0] & 0xF0) >> 4; //Frame checksum 0xF
COUNTER_474 = (rx_frame.data.u8[0] & 0x0F);
break;
case 0x574: //MysteryVan 50/75kWh platform
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
HV_BATT_FC_INSU_MINUS_RES = (rx_frame.data.u8[0] << 5) | (rx_frame.data.u8[1] >> 3); //kOhm (0-60000)
HV_BATT_FC_VHL_INSU_PLUS_RES =
((rx_frame.data.u8[1] & 0x07) << 10) | (rx_frame.data.u8[2] << 2) | ((rx_frame.data.u8[3] & 0xC0) >> 6);
HV_BATT_FC_INSU_PLUS_RES = (rx_frame.data.u8[5] << 4) | (rx_frame.data.u8[6] >> 4);
HV_BATT_ONLY_INSU_MINUS_RES = ((rx_frame.data.u8[3] & 0x3F) << 7) | (rx_frame.data.u8[4] >> 1);
break;
case 0x583: //MysteryVan 50/75kWh platform
case 0x583: //MysteryVan 50/75kWh platform (CAN-FD also?)
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
ALERT_OVERCHARGE = (rx_frame.data.u8[4] & 0x20) >> 5;
NUMBER_PROBE_TEMP_MAX = rx_frame.data.u8[0];
NUMBER_PROBE_TEMP_MIN = rx_frame.data.u8[1];
TEMPERATURE_MINIMUM_C = rx_frame.data.u8[2] - 40;
ALERT_BATT = (rx_frame.data.u8[3] & 0x80) >> 7;
ALERT_TEMP_DIFF = (rx_frame.data.u8[3] & 0x40) >> 6;
ALERT_HIGH_TEMP = (rx_frame.data.u8[3] & 0x20) >> 5;
ALERT_OVERVOLTAGE = (rx_frame.data.u8[3] & 0x10) >> 4;
ALERT_LOW_SOC = (rx_frame.data.u8[3] & 0x08) >> 3;
ALERT_HIGH_SOC = (rx_frame.data.u8[3] & 0x04) >> 2;
ALERT_CELL_OVERVOLTAGE = (rx_frame.data.u8[3] & 0x02) >> 1;
ALERT_CELL_UNDERVOLTAGE = (rx_frame.data.u8[3] & 0x01);
ALERT_SOC_JUMP = (rx_frame.data.u8[4] & 0x80) >> 7;
ALERT_CELL_POOR_CONSIST = (rx_frame.data.u8[4] & 0x40) >> 6;
CONTACTOR_OPENING_REASON = (rx_frame.data.u8[4] & 0x1C) >> 2;
/*
000 : Not error
001 : Crash
010 : 12V supply source undervoltage
011 : 12V supply source overvoltage
100 : Battery temperature
101 : interlock line open
110 : e-Service plug disconnected
111 : Not valid
*/
NUMBER_OF_TEMPERATURE_SENSORS_IN_BATTERY = rx_frame.data.u8[5];
NUMBER_OF_CELL_MEASUREMENTS_IN_BATTERY = rx_frame.data.u8[6];
break;
case 0x314: //MysteryVan 50/75kWh platform
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
MIN_ALLOW_DISCHRG_VOLTAGE = (rx_frame.data.u8[1] << 3) | (rx_frame.data.u8[2] >> 5); //V (0-1000)
//EVSE_DC_MAX_CURRENT = ((rx_frame.data.u8[2] & 0x1F) << 5) | (rx_frame.data.u8[3] >> 3); //Fastcharger info, not needed for BE
//TBMU_EVSE_DC_MAX_VOLTAGE //Fastcharger info, not needed for BE
//TBMU_MAX_CHRG_SCKT_TEMP //Fastcharger info, not needed for BE
//DC_CHARGE_MODE_AVAIL //Fastcharger info, not needed for BE
//BIDIR_V2HG_MODE_AVAIL //Fastcharger info, not needed for BE
//TBMU_CHRG_CONN_CONF //Fastcharger info, not needed for BE
//EVSE_GRID_FAULT //Fastcharger info, not needed for BE
CHECKSUM_FRAME_314 = (rx_frame.data.u8[0] & 0xF0) >> 4; //Frame checksum 0x8
COUNTER_314 = (rx_frame.data.u8[0] & 0x0F);
break;
case 0x254: //MysteryVan 50/75kWh platform
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
//HV_BATT_SOE_MAX_HR = frame6 & frame7 //Only on FD-CAN variant of the message. FD has length 7, non-fd 5
HV_BATT_NOMINAL_DISCH_CURR_HD = (rx_frame.data.u8[0] << 7) | (rx_frame.data.u8[1] >> 1); //dA (0-20000)
HV_BATT_PEAK_DISCH_CURR_HD = (rx_frame.data.u8[2] << 7) | (rx_frame.data.u8[3] >> 1); //dA (0-20000)
HV_BATT_STABLE_DISCH_CURR_HD = (rx_frame.data.u8[4] << 7) | (rx_frame.data.u8[5] >> 1); //dA (0-20000)
break;
case 0x2B4: //MysteryVan 50/75kWh platform
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
HV_BATT_NOMINAL_CHARGE_CURR_HD = (rx_frame.data.u8[0] << 7) | (rx_frame.data.u8[1] >> 1);
HV_BATT_PEAK_CHARGE_CURR_HD = (rx_frame.data.u8[2] << 7) | (rx_frame.data.u8[3] >> 1);
HV_BATT_STABLE_CHARGE_CURR_HD = (rx_frame.data.u8[4] << 7) | (rx_frame.data.u8[5] >> 1);
break;
case 0x4D4: //MysteryVan 50/75kWh platform
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
HV_BATT_STABLE_CHARGE_POWER_HD = (rx_frame.data.u8[0] << 6) | (rx_frame.data.u8[1] >> 2);
HV_BATT_STABLE_DISCH_POWER_HD =
((rx_frame.data.u8[2] & 0x03) << 12) | (rx_frame.data.u8[3] << 4) | ((rx_frame.data.u8[4] & 0xF0) >> 4);
HV_BATT_NOMINAL_DISCH_POWER_HD =
((rx_frame.data.u8[4] & 0x0F) << 10) | (rx_frame.data.u8[5] << 2) | ((rx_frame.data.u8[6] & 0xC0) >> 6);
MAX_ALLOW_DISCHRG_CURRENT = ((rx_frame.data.u8[6] & 0x3F) << 5) | (rx_frame.data.u8[7] >> 3);
RC01_PERM_SYNTH_TBMU = (rx_frame.data.u8[7] & 0x04) >> 2; //TBMU Readiness Code synthesis
CHECKSUM_FRAME_4D4 = (rx_frame.data.u8[0] & 0xF0) >> 4; //Frame checksum 0x5
COUNTER_4D4 = (rx_frame.data.u8[0] & 0x0F);
break;
case 0x125: //Common
case 0x125: //Common eCMP
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
battery_soc = (rx_frame.data.u8[0] << 2) |
(rx_frame.data.u8[1] >> 6); // Byte1, bit 7 length 10 (0x3FE when abnormal) (0-1000 ppt)

View file

@ -133,7 +133,68 @@ class EcmpBattery : public CanBattery {
uint32_t pid_date_of_manufacture = NOT_SAMPLED_YET;
uint16_t pid_SOH_cell_1 = NOT_SAMPLED_YET;
unsigned long previousMillis10 = 0; // will store last time a 10ms CAN Message was sent
//MysteryVan platform (allcaps to make code easer to co-exist)
uint16_t SOE_MAX_CURRENT_TEMP = 0;
uint16_t FRONT_MACHINE_POWER_LIMIT = 0;
uint16_t REAR_MACHINE_POWER_LIMIT = 0;
uint16_t EVSE_INSTANT_DC_HV_CURRENT = 0;
uint8_t EVSE_STATE = 0;
uint16_t HV_BATT_SOE_HD = 0;
uint16_t HV_BATT_SOE_MAX = 0;
uint8_t CHECKSUM_FRAME_314, CHECKSUM_FRAME_3B4, CHECKSUM_FRAME_554, CHECKSUM_FRAME_373, CHECKSUM_FRAME_4F4,
CHECKSUM_FRAME_414, CHECKSUM_FRAME_353, CHECKSUM_FRAME_474, CHECKSUM_FRAME_4D4 = 0;
uint16_t HV_STORAGE_MAX_I = 0;
int8_t BMS_PROBETEMP[7] = {0};
uint8_t COUNTER_314, COUNTER_554, COUNTER_373, COUNTER_3B4, COUNTER_4F4, COUNTER_414, COUNTER_353, COUNTER_474,
COUNTER_4D4 = 0;
uint16_t HV_BATT_PEAK_DISCH_POWER_HD = 0;
uint16_t HV_BATT_PEAK_CH_POWER_HD = 0;
uint16_t HV_BATT_NOM_CH_POWER_HD = 0;
uint16_t MAX_ALLOW_CHRG_CURRENT = 0;
int16_t HV_BATT_REAL_CURR_HD = 0;
uint16_t HV_BATT_REAL_VOLT_HD = 0;
uint8_t TBMU_FAULT_TYPE = 0;
int16_t HV_BATT_MAX_REAL_CURR = 0;
bool TBCU_48V_WAKEUP = false;
bool REQ_CLEAR_DTC_TBMU = false;
bool HV_BATT_DISCONT_WARNING_OPEN = false;
uint8_t CONTACTORS_STATE = 0;
uint16_t HV_BATT_SOC = 0;
bool CMD_RESET_MIL = 0;
bool REQ_BLINK_STOP_AND_SERVICE_LAMP = false;
bool REQ_MIL_LAMP_CONTINOUS = false;
uint16_t HV_BATT_GENERATED_HEAT_RATE = 0;
bool HV_BATT_CRASH_MEMORIZED = false;
bool HV_BATT_COLD_CRANK_ACK = false;
bool HV_BATT_CHARGE_NEEDED_STATE = false;
uint8_t HV_BATT_NOM_CH_CURRENT = 0;
uint16_t HV_BATT_NOM_CH_VOLTAGE = 0;
uint16_t HV_BATT_REAL_POWER_HD = 0;
uint16_t MAX_ALLOW_CHRG_POWER = 0;
uint16_t MAX_ALLOW_DISCHRG_POWER = 0;
bool ALERT_CELL_POOR_CONSIST, ALERT_OVERCHARGE, ALERT_BATT, ALERT_LOW_SOC, ALERT_HIGH_SOC, ALERT_SOC_JUMP,
ALERT_TEMP_DIFF, ALERT_HIGH_TEMP, ALERT_OVERVOLTAGE, ALERT_CELL_OVERVOLTAGE, ALERT_CELL_UNDERVOLTAGE = false;
uint8_t NUMBER_PROBE_TEMP_MAX, NUMBER_PROBE_TEMP_MIN = 0;
int8_t TEMPERATURE_MINIMUM_C = 0;
uint8_t CONTACTOR_OPENING_REASON = 0;
uint8_t NUMBER_OF_TEMPERATURE_SENSORS_IN_BATTERY, NUMBER_OF_CELL_MEASUREMENTS_IN_BATTERY = 0;
uint16_t HV_BATT_COP_VOLTAGE = 0;
int16_t HV_BATT_COP_CURRENT = 0;
uint16_t BMS_DC_RELAY_MES_EVSE_VOLTAGE = 0;
uint8_t FAST_CHARGE_CONTACTOR_STATE = 0;
uint8_t BMS_FASTCHARGE_STATUS = 0;
uint16_t HV_BATT_FC_INSU_MINUS_RES, HV_BATT_FC_INSU_PLUS_RES, HV_BATT_FC_VHL_INSU_PLUS_RES,
HV_BATT_ONLY_INSU_MINUS_RES = 0;
uint16_t MIN_ALLOW_DISCHRG_VOLTAGE = 0;
uint16_t HV_BATT_NOMINAL_DISCH_CURR_HD, HV_BATT_PEAK_DISCH_CURR_HD, HV_BATT_STABLE_DISCH_CURR_HD = 0;
uint16_t HV_BATT_NOMINAL_CHARGE_CURR_HD, HV_BATT_PEAK_CHARGE_CURR_HD, HV_BATT_STABLE_CHARGE_CURR_HD = 0;
bool RC01_PERM_SYNTH_TBMU = false;
uint16_t HV_BATT_STABLE_CHARGE_POWER_HD = 0;
uint16_t HV_BATT_STABLE_DISCH_POWER_HD = 0;
uint16_t HV_BATT_NOMINAL_DISCH_POWER_HD = 0;
uint16_t MAX_ALLOW_DISCHRG_CURRENT = 0;
unsigned long previousMillis10 = 0; //- will store last time a 10ms CAN Message was sent
unsigned long previousMillis20 = 0; // will store last time a 20ms CAN Message was sent
unsigned long previousMillis50 = 0; // will store last time a 50ms CAN Message was sent
unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was sent

View file

@ -383,6 +383,132 @@ class EcmpHtmlRenderer : public BatteryHtmlRenderer {
: String(datalayer_extended.stellantisECMP.pid_SOH_cell_1)) +
"</h4>";
if (datalayer_extended.stellantisECMP.MysteryVan) {
content += "<h3>MysteryVan platform detected!</h3>";
content += "<h4>Contactor State: ";
if (datalayer_extended.stellantisECMP.CONTACTORS_STATE == 0) {
content += "Open";
} else if (datalayer_extended.stellantisECMP.CONTACTORS_STATE == 1) {
content += "Precharge";
} else if (datalayer_extended.stellantisECMP.CONTACTORS_STATE == 2) {
content += "Closed";
}
content += "</h4>";
content += "<h4>Crash Memorized: ";
if (datalayer_extended.stellantisECMP.CrashMemorized) {
content += "Yes</h4>";
} else {
content += "No</h4>";
}
content += "<h4>Contactor Opening Reason: ";
if (datalayer_extended.stellantisECMP.CONTACTOR_OPENING_REASON == 0) {
content += "No error";
} else if (datalayer_extended.stellantisECMP.CONTACTOR_OPENING_REASON == 1) {
content += "Crash!";
} else if (datalayer_extended.stellantisECMP.CONTACTOR_OPENING_REASON == 2) {
content += "12V supply source undervoltage";
} else if (datalayer_extended.stellantisECMP.CONTACTOR_OPENING_REASON == 3) {
content += "12V supply source overvoltage";
} else if (datalayer_extended.stellantisECMP.CONTACTOR_OPENING_REASON == 4) {
content += "Battery temperature";
} else if (datalayer_extended.stellantisECMP.CONTACTOR_OPENING_REASON == 5) {
content += "Interlock line open";
} else if (datalayer_extended.stellantisECMP.CONTACTOR_OPENING_REASON == 6) {
content += "e-Service plug disconnected";
}
content += "</h4>";
content += "<h4>Battery fault type: ";
if (datalayer_extended.stellantisECMP.TBMU_FAULT_TYPE == 0) {
content += "No fault";
} else if (datalayer_extended.stellantisECMP.TBMU_FAULT_TYPE == 1) {
content += "FirstLevelFault: Warning Lamp";
} else if (datalayer_extended.stellantisECMP.TBMU_FAULT_TYPE == 2) {
content += "SecondLevelFault: Stop Lamp";
} else if (datalayer_extended.stellantisECMP.TBMU_FAULT_TYPE == 3) {
content += "ThirdLevelFault: Stop Lamp + contactor opening (EPS shutdown)";
} else if (datalayer_extended.stellantisECMP.TBMU_FAULT_TYPE == 4) {
content += "FourthLevelFault: Stop Lamp + Active Discharge";
} else if (datalayer_extended.stellantisECMP.TBMU_FAULT_TYPE == 5) {
content += "Inhibition of powertrain activation";
} else if (datalayer_extended.stellantisECMP.TBMU_FAULT_TYPE == 6) {
content += "Reserved";
}
content += "</h4>";
content += "<h4>FC insulation minus resistance " +
String(datalayer_extended.stellantisECMP.HV_BATT_FC_INSU_MINUS_RES) + " kOhm</h4>";
content += "<h4>FC insulation plus resistance " +
String(datalayer_extended.stellantisECMP.HV_BATT_FC_INSU_PLUS_RES) + " kOhm</h4>";
content += "<h4>FC vehicle insulation plus resistance " +
String(datalayer_extended.stellantisECMP.HV_BATT_FC_VHL_INSU_PLUS_RES) + " kOhm</h4>";
content += "<h4>FC vehicle insulation plus resistance " +
String(datalayer_extended.stellantisECMP.HV_BATT_ONLY_INSU_MINUS_RES) + " kOhm</h4>";
}
content += "<h4>Alert Battery: ";
if (datalayer_extended.stellantisECMP.ALERT_BATT) {
content += "Yes</h4>";
} else {
content += "No</h4>";
}
content += "<h4>Alert Low SOC: ";
if (datalayer_extended.stellantisECMP.ALERT_LOW_SOC) {
content += "Yes</h4>";
} else {
content += "No</h4>";
}
content += "<h4>Alert High SOC: ";
if (datalayer_extended.stellantisECMP.ALERT_HIGH_SOC) {
content += "Yes</h4>";
} else {
content += "No</h4>";
}
content += "<h4>Alert SOC Jump: ";
if (datalayer_extended.stellantisECMP.ALERT_SOC_JUMP) {
content += "Yes</h4>";
} else {
content += "No</h4>";
}
content += "<h4>Alert Overcharge: ";
if (datalayer_extended.stellantisECMP.ALERT_OVERCHARGE) {
content += "Yes</h4>";
} else {
content += "No</h4>";
}
content += "<h4>Alert Temp Diff: ";
if (datalayer_extended.stellantisECMP.ALERT_TEMP_DIFF) {
content += "Yes</h4>";
} else {
content += "No</h4>";
}
content += "<h4>Alert Temp High: ";
if (datalayer_extended.stellantisECMP.ALERT_HIGH_TEMP) {
content += "Yes</h4>";
} else {
content += "No</h4>";
}
content += "<h4>Alert Overvoltage: ";
if (datalayer_extended.stellantisECMP.ALERT_OVERVOLTAGE) {
content += "Yes</h4>";
} else {
content += "No</h4>";
}
content += "<h4>Alert Cell Overvoltage: ";
if (datalayer_extended.stellantisECMP.ALERT_CELL_OVERVOLTAGE) {
content += "Yes</h4>";
} else {
content += "No</h4>";
}
content += "<h4>Alert Cell Undervoltage: ";
if (datalayer_extended.stellantisECMP.ALERT_CELL_UNDERVOLTAGE) {
content += "Yes</h4>";
} else {
content += "No</h4>";
}
content += "<h4>Alert Cell Poor Consistency: ";
if (datalayer_extended.stellantisECMP.ALERT_CELL_POOR_CONSIST) {
content += "Yes</h4>";
} else {
content += "No</h4>";
}
return content;
}
};

View file

@ -72,7 +72,7 @@ uint16_t KiaEGmpBattery::selectSOC(uint16_t SOC_low, uint16_t SOC_high) {
void KiaEGmpBattery::set_cell_voltages(CAN_frame rx_frame, int start, int length, int startCell) {
for (size_t i = 0; i < length; i++) {
if ((rx_frame.data.u8[start + i] * 20) > 1000) {
if ((rx_frame.data.u8[start + i] * 20) > 2600) {
datalayer.battery.status.cell_voltages_mV[startCell + i] = (rx_frame.data.u8[start + i] * 20);
}
}
@ -114,16 +114,17 @@ uint8_t KiaEGmpBattery::calculateCRC(CAN_frame rx_frame, uint8_t length, uint8_t
void KiaEGmpBattery::update_values() {
#ifdef ESTIMATE_SOC_FROM_CELLVOLTAGE
if (user_selected_use_estimated_SOC) {
// Use the simplified pack-based SOC estimation with proper compensation
datalayer.battery.status.real_soc = estimateSOC(batteryVoltage, datalayer.battery.info.number_of_cells, batteryAmps);
datalayer.battery.status.real_soc =
estimateSOC(batteryVoltage, datalayer.battery.info.number_of_cells, batteryAmps);
// For comparison or fallback, we can still calculate from min/max cell voltages
SOC_estimated_lowest = estimateSOCFromCell(CellVoltMin_mV);
SOC_estimated_highest = estimateSOCFromCell(CellVoltMax_mV);
#else
} else {
datalayer.battery.status.real_soc = (SOC_Display * 10); //increase SOC range from 0-100.0 -> 100.00
#endif
}
datalayer.battery.status.soh_pptt = (batterySOH * 10); //Increase decimals from 100.0% -> 100.00%

View file

@ -3,7 +3,7 @@
#include "CanBattery.h"
#include "KIA-E-GMP-HTML.h"
#define ESTIMATE_SOC_FROM_CELLVOLTAGE
extern bool user_selected_use_estimated_SOC;
class KiaEGmpBattery : public CanBattery {
public:

View file

@ -201,15 +201,21 @@ void KiaHyundaiHybridBattery::transmit_can(unsigned long currentMillis) {
}
poll_data_pid++;
if (poll_data_pid == 1) {
transmit_can_frame(&KIA_7E4_id1);
KIA_7E4.data.u8[2] = 0x01;
KIA_7E4.data.u8[3] = 0x00;
transmit_can_frame(&KIA_7E4);
} else if (poll_data_pid == 2) {
transmit_can_frame(&KIA_7E4_id2);
KIA_7E4.data.u8[2] = 0x02;
transmit_can_frame(&KIA_7E4);
} else if (poll_data_pid == 3) {
transmit_can_frame(&KIA_7E4_id3);
KIA_7E4.data.u8[2] = 0x03;
transmit_can_frame(&KIA_7E4);
} else if (poll_data_pid == 4) {
//Group 4 not polled
} else if (poll_data_pid == 5) {
transmit_can_frame(&KIA_7E4_id5);
KIA_7E4.data.u8[2] = 0x05;
KIA_7E4.data.u8[3] = 0x04;
transmit_can_frame(&KIA_7E4);
}
}
}

View file

@ -34,26 +34,11 @@ class KiaHyundaiHybridBattery : public CanBattery {
uint16_t min_cell_voltage_mv = 3700;
uint16_t max_cell_voltage_mv = 3700;
CAN_frame KIA_7E4_id1 = {.FD = false,
CAN_frame KIA_7E4 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x7E4,
.data = {0x02, 0x21, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame KIA_7E4_id2 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x7E4,
.data = {0x02, 0x21, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame KIA_7E4_id3 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x7E4,
.data = {0x02, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame KIA_7E4_id5 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x7E4,
.data = {0x02, 0x21, 0x05, 0x04, 0x00, 0x00, 0x00, 0x00}};
CAN_frame KIA_7E4_ack = {.FD = false,
.ext_ID = false,
.DLC = 8,

View file

@ -34,10 +34,10 @@ class RenaultZoeGen1Battery : public CanBattery {
private:
RenaultZoeGen1HtmlRenderer renderer;
static const int MAX_PACK_VOLTAGE_DV = 4200; //5000 = 500.0V
static const int MAX_PACK_VOLTAGE_DV = 4040; //5000 = 500.0V
static const int MIN_PACK_VOLTAGE_DV = 3000;
static const int MAX_CELL_DEVIATION_MV = 150;
static const int MAX_CELL_VOLTAGE_MV = 4250; //Battery is put into emergency stop if one cell goes over this value
static const int MAX_CELL_VOLTAGE_MV = 4220; //Battery is put into emergency stop if one cell goes over this value
static const int MIN_CELL_VOLTAGE_MV = 2700; //Battery is put into emergency stop if one cell goes below this value
DATALAYER_BATTERY_TYPE* datalayer_battery;

View file

@ -113,33 +113,6 @@ inline const char* getHvilStatusState(int index) {
}
}
inline const char* getBMSState(int index) {
switch (index) {
case 0:
return "STANDBY";
case 1:
return "DRIVE";
case 2:
return "SUPPORT";
case 3:
return "CHARGE";
case 4:
return "FEIM";
case 5:
return "CLEAR_FAULT";
case 6:
return "FAULT";
case 7:
return "WELD";
case 8:
return "TEST";
case 9:
return "SNA";
default:
return "UNKNOWN";
}
}
inline const char* getBMSContactorState(int index) {
switch (index) {
case 0:
@ -161,174 +134,10 @@ inline const char* getBMSContactorState(int index) {
}
}
inline const char* getBMSHvState(int index) {
switch (index) {
case 0:
return "DOWN";
case 1:
return "COMING_UP";
case 2:
return "GOING_DOWN";
case 3:
return "UP_FOR_DRIVE";
case 4:
return "UP_FOR_CHARGE";
case 5:
return "UP_FOR_DC_CHARGE";
case 6:
return "UP";
default:
return "UNKNOWN";
}
}
inline const char* getBMSUiChargeStatus(int index) {
switch (index) {
case 0:
return "DISCONNECTED";
case 1:
return "NO_POWER";
case 2:
return "ABOUT_TO_CHARGE";
case 3:
return "CHARGING";
case 4:
return "CHARGE_COMPLETE";
case 5:
return "CHARGE_STOPPED";
default:
return "UNKNOWN";
}
}
inline const char* getPCS_DcdcStatus(int index) {
switch (index) {
case 0:
return "IDLE";
case 1:
return "ACTIVE";
case 2:
return "FAULTED";
default:
return "UNKNOWN";
}
}
inline const char* getPCS_DcdcMainState(int index) {
switch (index) {
case 0:
return "STANDBY";
case 1:
return "12V_SUPPORT_ACTIVE";
case 2:
return "PRECHARGE_STARTUP";
case 3:
return "PRECHARGE_ACTIVE";
case 4:
return "DIS_HVBUS_ACTIVE";
case 5:
return "SHUTDOWN";
case 6:
return "FAULTED";
default:
return "UNKNOWN";
}
}
inline const char* getPCS_DcdcSubState(int index) {
switch (index) {
case 0:
return "PWR_UP_INIT";
case 1:
return "STANDBY";
case 2:
return "12V_SUPPORT_ACTIVE";
case 3:
return "DIS_HVBUS";
case 4:
return "PCHG_FAST_DIS_HVBUS";
case 5:
return "PCHG_SLOW_DIS_HVBUS";
case 6:
return "PCHG_DWELL_CHARGE";
case 7:
return "PCHG_DWELL_WAIT";
case 8:
return "PCHG_DI_RECOVERY_WAIT";
case 9:
return "PCHG_ACTIVE";
case 10:
return "PCHG_FLT_FAST_DIS_HVBUS";
case 11:
return "SHUTDOWN";
case 12:
return "12V_SUPPORT_FAULTED";
case 13:
return "DIS_HVBUS_FAULTED";
case 14:
return "PCHG_FAULTED";
case 15:
return "CLEAR_FAULTS";
case 16:
return "FAULTED";
case 17:
return "NUM";
default:
return "UNKNOWN";
}
}
inline const char* getBMSPowerLimitState(int index) {
switch (index) {
case 0:
return "NOT_CALCULATED_FOR_DRIVE";
case 1:
return "CALCULATED_FOR_DRIVE";
default:
return "UNKNOWN";
}
}
inline const char* getHVPStatus(int index) {
switch (index) {
case 0:
return "INVALID";
case 1:
return "NOT_AVAILABLE";
case 2:
return "STALE";
case 3:
return "VALID";
default:
return "UNKNOWN";
}
}
inline const char* getHVPContactor(int index) {
switch (index) {
case 0:
return "NOT_ACTIVE";
case 1:
return "ACTIVE";
case 2:
return "COMPLETED";
default:
return "UNKNOWN";
}
}
inline const char* getFalseTrue(bool value) {
return value ? "True" : "False";
}
inline const char* getNoYes(bool value) {
return value ? "Yes" : "No";
}
inline const char* getFault(bool value) {
return value ? "ACTIVE" : "NOT_ACTIVE";
}
// Clamp DLC to 08 bytes for classic CAN
inline int getDataLen(uint8_t dlc) {
return std::min<int>(dlc, 8);
@ -660,8 +469,6 @@ void TeslaBattery::
datalayer.battery.status.cell_min_voltage_mV = battery_cell_min_v;
battery_cell_deviation_mV = (battery_cell_max_v - battery_cell_min_v);
/* Value mapping is completed. Start to check all safeties */
//INTERNAL_OPEN_FAULT - Someone disconnected a high voltage cable while battery was in use
@ -676,11 +483,24 @@ void TeslaBattery::
} else {
clear_event(EVENT_BATTERY_FUSE);
}
// Raise any Tesla BMS events in BE
// Events: Informational
if (BMS_a145_SW_SOC_Change) { // BMS has newly recalibrated pack SOC
set_event_latched(EVENT_BATTERY_SOC_RECALIBRATION, 0); // Latcched as BMS_a145 can be active for a while
} else if (!BMS_a145_SW_SOC_Change) {
clear_event(EVENT_BATTERY_SOC_RECALIBRATION);
}
// Events: Warning
if (BMS_contactorState == 5) { // BMS has detected welded contactor(s)
set_event_latched(EVENT_CONTACTOR_WELDED, 0);
} else if (BMS_contactorState != 5) {
clear_event(EVENT_CONTACTOR_WELDED);
}
if (user_selected_tesla_GTW_chassisType > 1) { //{{0, "Model S"}, {1, "Model X"}, {2, "Model 3"}, {3, "Model Y"}};
// Autodetect algoritm for chemistry on 3/Y packs.
// Autodetect algorithm for chemistry on 3/Y packs.
// NCM/A batteries have 96s, LFP has 102-108s
// Drawback with this check is that it takes 3-5minutes before all cells have been counted!
// Drawback with this check is that it takes 3-5 minutes before all cells have been counted!
if (datalayer.battery.info.number_of_cells > 101) {
datalayer.battery.info.chemistry = battery_chemistry_enum::LFP;
}
@ -721,23 +541,28 @@ void TeslaBattery::
//Start the BMS ECU reset statemachine, only if contactors are OPEN and BMS ECU allows it
stateMachineBMSReset = 0;
datalayer.battery.settings.user_requests_tesla_bms_reset = false;
logging.println("BMS reset requested");
logging.println("INFO: BMS reset requested");
} else {
logging.println("ERROR: BMS reset failed due to contactors not being open, or BMS ECU not allowing it");
stateMachineBMSReset = 0xFF;
datalayer.battery.settings.user_requests_tesla_bms_reset = false;
set_event(EVENT_BMS_RESET_REQ_FAIL, 0);
clear_event(EVENT_BMS_RESET_REQ_FAIL);
}
}
if (datalayer.battery.settings.user_requests_tesla_soc_reset) {
if (datalayer.battery.status.real_soc < 1500 || datalayer.battery.status.real_soc > 9000) {
//Start the SOC reset statemachine, only if SOC < 15% or > 90%
if ((datalayer.battery.status.real_soc < 1500 || datalayer.battery.status.real_soc > 9000) &&
battery_contactor == 1) {
//Start the SOC reset statemachine, only if SOC less than 15% or greater than 90%, and contactors open
stateMachineSOCReset = 0;
datalayer.battery.settings.user_requests_tesla_soc_reset = false;
logging.println("SOC reset requested");
logging.println("INFO: SOC reset requested");
} else {
logging.println("ERROR: SOC reset failed due to SOC not being less than 15 or greater than 90");
logging.println("ERROR: SOC reset failed, SOC not < 15 or > 90, or contactors not open");
stateMachineSOCReset = 0xFF;
datalayer.battery.settings.user_requests_tesla_soc_reset = false;
set_event(EVENT_BATTERY_SOC_RESET_FAIL, 0);
clear_event(EVENT_BATTERY_SOC_RESET_FAIL);
}
}
@ -972,42 +797,42 @@ void TeslaBattery::
datalayer_extended.tesla.HVP_shuntBarTempStatus = HVP_shuntBarTempStatus;
datalayer_extended.tesla.HVP_shuntAsicTempStatus = HVP_shuntAsicTempStatus;
//Safety checks for CAN message sesnding
//Safety checks for CAN message sending
if ((datalayer.system.status.inverter_allows_contactor_closing == true) &&
(datalayer.battery.status.bms_status != FAULT) && (!datalayer.system.settings.equipment_stop_active)) {
// Carry on: 0x221 DRIVE state & reset power down timer
vehicleState = 1;
powerDownTimer = 180; //0x221 50ms cyclic, 20 calls/second
vehicleState = CAR_DRIVE;
powerDownSeconds = 9;
} else {
// Faulted state, or inverter blocks contactor closing
// Shut down: 0x221 ACCESSORY state for 3 seconds, followed by GOING_DOWN, then OFF
if (powerDownTimer <= 180 && powerDownTimer > 120) {
vehicleState = 2; //ACCESSORY
powerDownTimer--;
if (powerDownSeconds <= 9 && powerDownSeconds > 6) {
vehicleState = ACCESSORY;
powerDownSeconds--;
}
if (powerDownTimer <= 120 && powerDownTimer > 60) {
vehicleState = 3; //GOING_DOWN
powerDownTimer--;
if (powerDownSeconds <= 6 && powerDownSeconds > 3) {
vehicleState = GOING_DOWN;
powerDownSeconds--;
}
if (powerDownTimer <= 60 && powerDownTimer > 0) {
vehicleState = 0; //OFF
powerDownTimer--;
if (powerDownSeconds <= 3 && powerDownSeconds > 0) {
vehicleState = CAR_OFF;
powerDownSeconds--;
}
}
printFaultCodesIfActive();
logging.printf("BMS Contactors State: ");
logging.printf("Contactor State: ");
logging.printf(getBMSContactorState(battery_contactor)); // Display what state the BMS thinks the contactors are in
logging.printf(", HVIL: ");
logging.printf(" HVIL: ");
logging.printf(getHvilStatusState(battery_hvil_status));
logging.printf(", NegativeState: ");
logging.printf(" NegState: ");
logging.printf(getContactorState(battery_packContNegativeState));
logging.printf(", PositiveState: ");
logging.printf(" PosState: ");
logging.println(getContactorState(battery_packContPositiveState));
logging.printf("HVP Contactors setState: ");
logging.printf("Cont. setState: ");
logging.printf(
getContactorText(battery_packContactorSetState)); // Display what state the HVP has set the contactors to be in
logging.printf(", Closing blocked: ");
logging.printf(" Closing blocked: ");
logging.printf(getNoYes(battery_packCtrsClosingBlocked));
if (battery_packContactorSetState == 5) {
logging.printf(" (already CLOSED)");
@ -1015,43 +840,8 @@ void TeslaBattery::
logging.printf(", Pyrotest: ");
logging.println(getNoYes(battery_pyroTestInProgress));
logging.printf("Battery values: ");
logging.printf("Real SOC: ");
logging.print(battery_soc_ui / 10.0, 1);
logging.printf(", Battery voltage: ");
logging.print(battery_volts / 10.0, 1);
logging.printf("V");
logging.printf(", Battery HV current: ");
logging.print(battery_amps / 10.0, 1);
logging.printf("A");
logging.printf(", Fully charged?: ");
if (battery_full_charge_complete)
logging.printf("YES, ");
else
logging.printf("NO, ");
if (datalayer.battery.info.chemistry == battery_chemistry_enum::LFP) {
logging.printf("LFP chemistry detected!");
}
logging.println("");
logging.printf("Cellstats, Max: ");
logging.print(battery_cell_max_v);
logging.printf("mV (cell ");
logging.print(battery_BrickVoltageMaxNum);
logging.printf("), Min: ");
logging.print(battery_cell_min_v);
logging.printf("mV (cell ");
logging.print(battery_BrickVoltageMinNum);
logging.printf("), Imbalance: ");
logging.print(battery_cell_deviation_mV);
logging.println("mV.");
logging.printf("High Voltage Output Pins: %.2f V, Low Voltage: %.2f V, DC/DC 12V current: %.2f A.\n",
(battery_dcdcHvBusVolt * 0.146484), (battery_dcdcLvBusVolt * 0.0390625),
(battery_dcdcLvOutputCurrent * 0.1));
logging.printf("PCS_ambientTemp: %.2f°C, DCDC_Temp: %.2f°C, ChgPhA: %.2f°C, ChgPhB: %.2f°C, ChgPhC: %.2f°C.\n",
PCS_ambientTemp * 0.1 + 40, PCS_dcdcTemp * 0.1 + 40, PCS_chgPhATemp * 0.1 + 40,
PCS_chgPhBTemp * 0.1 + 40, PCS_chgPhCTemp * 0.1 + 40);
logging.printf("HV: %.2f V, 12V: %.2f V, 12V current: %.2f A.\n", (battery_dcdcHvBusVolt * 0.146484),
(battery_dcdcLvBusVolt * 0.0390625), (battery_dcdcLvOutputCurrent * 0.1));
}
void TeslaBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
@ -1895,17 +1685,17 @@ void TeslaBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
}
*/
break;
case 0x612: // CAN UDSs for BMS
case 0x612: // CAN UDS responses for BMS
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
//BMS Query
if (stateMachineBMSQuery != 0xFF && stateMachineBMSReset == 0xFF) {
if (stateMachineBMSQuery != 0xFF && stateMachineBMSReset == 0xFF && stateMachineSOCReset == 0xFF) {
if (memcmp(rx_frame.data.u8, "\x02\x50\x03\xAA\xAA\xAA\xAA\xAA", 8) == 0) {
//Received initial response, proceed to actual query
logging.println("CAN UDS: Received BMS query initial handshake reply");
stateMachineBMSQuery = 1;
break;
}
if (memcmp(&rx_frame.data.u8[0], "\x10", 1) == 0) {
if (rx_frame.data.u8[0] == 0x10) {
//Received first data frame
battery_partNumber[0] = rx_frame.data.u8[5];
battery_partNumber[1] = rx_frame.data.u8[6];
@ -1914,7 +1704,7 @@ void TeslaBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
stateMachineBMSQuery = 2;
break;
}
if (memcmp(&rx_frame.data.u8[0], "\x21", 1) == 0) {
if (rx_frame.data.u8[0] == 0x21) {
//Second part of part number after flow control
battery_partNumber[3] = rx_frame.data.u8[1];
battery_partNumber[4] = rx_frame.data.u8[2];
@ -1926,7 +1716,7 @@ void TeslaBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
logging.println("CAN UDS: Received BMS query second data frame");
break;
}
if (memcmp(&rx_frame.data.u8[0], "\x22", 1) == 0) {
if (rx_frame.data.u8[0] == 0x22) {
//Final part of part number
battery_partNumber[10] = rx_frame.data.u8[1];
battery_partNumber[11] = rx_frame.data.u8[2];
@ -1941,15 +1731,28 @@ void TeslaBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
break;
}
}
//BMS Reset
if (stateMachineBMSQuery == 0xFF) { // Make sure this is reset request not query
//BMS ECU responses
if (memcmp(rx_frame.data.u8, "\x02\x67\x06\xAA\xAA\xAA\xAA\xAA", 8) == 0) {
logging.println("CAN UDS: ECU unlocked");
} else if (memcmp(rx_frame.data.u8, "\x03\x7F\x11\x78\xAA\xAA\xAA\xAA", 8) == 0) {
logging.println("CAN UDS: ECU reset request successful but ECU busy, response pending");
} else if (memcmp(rx_frame.data.u8, "\x02\x51\x01\xAA\xAA\xAA\xAA\xAA", 8) == 0) {
logging.println("CAN UDS: ECU reset positive response, 1 second downtime");
logging.println("CAN UDS: BMS ECU unlocked");
}
if (memcmp(rx_frame.data.u8, "\x03\x7F\x11\x78\xAA\xAA\xAA\xAA", 8) == 0) {
logging.println("CAN UDS: BMS ECU reset request successful but ECU busy, response pending");
}
if (memcmp(rx_frame.data.u8, "\x02\x51\x01\xAA\xAA\xAA\xAA\xAA", 8) == 0) {
logging.println("CAN UDS: BMS ECU reset positive response, 1 second downtime");
set_event(EVENT_BMS_RESET_REQ_SUCCESS, 0);
clear_event(EVENT_BMS_RESET_REQ_SUCCESS);
}
if (memcmp(rx_frame.data.u8, "\x05\x71\x01\x04\x07\x01\xAA\xAA", 8) == 0) {
logging.println("CAN UDS: BMS SOC reset accepted, resetting BMS ECU");
set_event(EVENT_BATTERY_SOC_RESET_SUCCESS, 0);
clear_event(EVENT_BATTERY_SOC_RESET_SUCCESS);
stateMachineBMSReset = 6; // BMS ECU already unlocked etc. so we jump straight to reset
}
if (memcmp(rx_frame.data.u8, "\x05\x71\x01\x04\x07\x00\xAA\xAA", 8) == 0) {
logging.println("CAN UDS: BMS SOC reset failed");
set_event(EVENT_BATTERY_SOC_RESET_FAIL, 0);
clear_event(EVENT_BATTERY_SOC_RESET_FAIL);
}
break;
default:
@ -1985,41 +1788,26 @@ CAN_frame can_msg_118[] = {
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x118, .data = {0x6F, 0x8E, 0x30, 0x10, 0x00, 0x08, 0x00, 0x80}},
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x118, .data = {0x70, 0x8F, 0x30, 0x10, 0x00, 0x08, 0x00, 0x80}}};
unsigned long lastSend1CF = 0;
unsigned long lastSend118 = 0;
int index_1CF = 0;
int index_118 = 0;
void TeslaBattery::transmit_can(unsigned long currentMillis) {
if (user_selected_tesla_digital_HVIL) { //Special S/X? mode for 2024+ batteries
if ((datalayer.system.status.inverter_allows_contactor_closing) && (datalayer.battery.status.bms_status != FAULT)) {
if (currentMillis - lastSend1CF >= 10) {
transmit_can_frame(&can_msg_1CF[index_1CF]);
index_1CF = (index_1CF + 1) % 8;
lastSend1CF = currentMillis;
}
if (currentMillis - lastSend118 >= 10) {
transmit_can_frame(&can_msg_118[index_118]);
index_118 = (index_118 + 1) % 16;
lastSend118 = currentMillis;
}
} else {
index_1CF = 0;
index_118 = 0;
}
}
//Send 10ms messages
if (currentMillis - previousMillis10 >= INTERVAL_10_MS) {
previousMillis10 = currentMillis;
if (user_selected_tesla_digital_HVIL) { //Special Digital HVIL mode for S/X 2024+ batteries
if ((datalayer.system.status.inverter_allows_contactor_closing) &&
(datalayer.battery.status.bms_status != FAULT)) {
transmit_can_frame(&can_msg_1CF[index_1CF]);
index_1CF = (index_1CF + 1) % 8;
transmit_can_frame(&can_msg_118[index_118]);
index_118 = (index_118 + 1) % 16;
}
} else { //Normal handling of 118 message (Non digital HVIL version)
//0x118 DI_systemStatus
transmit_can_frame(&TESLA_118);
index_1CF = 0; //Stop broadcasting Digital HVIL 1CF and 118 to keep contactors open
index_118 = 0;
}
//0x2E1 VCFRONT_status
switch (muxNumber_TESLA_2E1) {
@ -2059,7 +1847,7 @@ void TeslaBattery::transmit_can(unsigned long currentMillis) {
previousMillis50 = currentMillis;
//0x221 VCFRONT_LVPowerState
if (vehicleState == 1) { // Drive
if (vehicleState == CAR_DRIVE) {
switch (muxNumber_TESLA_221) {
case 0:
generateMuxFrameCounterChecksum(TESLA_221_DRIVE_Mux0, frameCounter_TESLA_221, 52, 4, 56, 8);
@ -2074,10 +1862,8 @@ void TeslaBattery::transmit_can(unsigned long currentMillis) {
default:
break;
}
//Generate next new frame
frameCounter_TESLA_221 = (frameCounter_TESLA_221 + 1) % 16;
}
if (vehicleState == 2) { // Accessory
if (vehicleState == ACCESSORY) {
switch (muxNumber_TESLA_221) {
case 0:
generateMuxFrameCounterChecksum(TESLA_221_ACCESSORY_Mux0, frameCounter_TESLA_221, 52, 4, 56, 8);
@ -2092,10 +1878,8 @@ void TeslaBattery::transmit_can(unsigned long currentMillis) {
default:
break;
}
//Generate next new frame
frameCounter_TESLA_221 = (frameCounter_TESLA_221 + 1) % 16;
}
if (vehicleState == 3) { // Going down
if (vehicleState == GOING_DOWN) {
switch (muxNumber_TESLA_221) {
case 0:
generateMuxFrameCounterChecksum(TESLA_221_GOING_DOWN_Mux0, frameCounter_TESLA_221, 52, 4, 56, 8);
@ -2110,10 +1894,8 @@ void TeslaBattery::transmit_can(unsigned long currentMillis) {
default:
break;
}
//Generate next new frame
frameCounter_TESLA_221 = (frameCounter_TESLA_221 + 1) % 16;
}
if (vehicleState == 0) { // Off
if (vehicleState == CAR_OFF) {
switch (muxNumber_TESLA_221) {
case 0:
generateMuxFrameCounterChecksum(TESLA_221_OFF_Mux0, frameCounter_TESLA_221, 52, 4, 56, 8);
@ -2128,23 +1910,13 @@ void TeslaBattery::transmit_can(unsigned long currentMillis) {
default:
break;
}
}
//Generate next new frame
frameCounter_TESLA_221 = (frameCounter_TESLA_221 + 1) % 16;
}
//0x3C2 VCLEFT_switchStatus
switch (muxNumber_TESLA_3C2) {
case 0:
transmit_can_frame(&TESLA_3C2_Mux0);
muxNumber_TESLA_3C2++;
break;
case 1:
transmit_can_frame(&TESLA_3C2_Mux1);
muxNumber_TESLA_3C2 = 0;
break;
default:
break;
}
transmit_can_frame(muxNumber_TESLA_3C2 == 0 ? &TESLA_3C2_Mux0 : &TESLA_3C2_Mux1);
muxNumber_TESLA_3C2 = !muxNumber_TESLA_3C2; // Flip between sending Mux0 and Mux1 on each pass
//0x39D IBST_status
transmit_can_frame(&TESLA_39D);
@ -2567,7 +2339,7 @@ void TeslaBattery::printFaultCodesIfActive() {
printDebugIfActive(BMS_a139_SW_DC_Link_V_Irrational, "ERROR: BMS_a139_SW_DC_Link_V_Irrational");
printDebugIfActive(BMS_a141_SW_BMB_Status_Warning, "ERROR: BMS_a141_SW_BMB_Status_Warning");
printDebugIfActive(BMS_a144_Hvp_Config_Mismatch, "ERROR: BMS_a144_Hvp_Config_Mismatch");
printDebugIfActive(BMS_a145_SW_SOC_Change, "ERROR: BMS_a145_SW_SOC_Change");
printDebugIfActive(BMS_a145_SW_SOC_Change, "INFO: BMS_a145_SW_SOC_Change");
printDebugIfActive(BMS_a146_SW_Brick_Overdischarged, "ERROR: BMS_a146_SW_Brick_Overdischarged");
printDebugIfActive(BMS_a149_SW_Missing_Config_Block, "ERROR: BMS_a149_SW_Missing_Config_Block");
printDebugIfActive(BMS_a151_SW_external_isolation, "ERROR: BMS_a151_SW_external_isolation");
@ -2601,7 +2373,7 @@ void TeslaModel3YBattery::setup(void) { // Performs one time setup at startup
//0x7FF GTW CAN frame values
//Mux1
write_signal_value(&TESLA_7FF_Mux1, 16, 16, user_selected_tesla_GTW_country, false);
write_signal_value(&TESLA_7FF_Mux1, 11, 1, user_selected_tesla_GTW_country, false);
write_signal_value(&TESLA_7FF_Mux1, 11, 1, user_selected_tesla_GTW_rightHandDrive, false);
//Mux3
write_signal_value(&TESLA_7FF_Mux3, 8, 4, user_selected_tesla_GTW_mapRegion, false);
write_signal_value(&TESLA_7FF_Mux3, 18, 3, user_selected_tesla_GTW_chassisType, false);

View file

@ -78,7 +78,11 @@ class TeslaBattery : public CanBattery {
uint8_t muxNumber_TESLA_221 = 0;
uint8_t frameCounter_TESLA_221 = 15; // Start at 15 for Mux 0
uint8_t vehicleState = 1; // "OFF": 0, "DRIVE": 1, "ACCESSORY": 2, "GOING_DOWN": 3
uint16_t powerDownTimer = 180; // Car power down (i.e. contactor open) tracking timer, 3 seconds per sendingState
static const uint8_t CAR_OFF = 0;
static const uint8_t CAR_DRIVE = 1;
static const uint8_t ACCESSORY = 2;
static const uint8_t GOING_DOWN = 3;
uint8_t powerDownSeconds = 9; // Car power down (i.e. contactor open) tracking timer, 3 seconds per sendingState
//0x2E1 VCFRONT_status, 6 mux tracker
uint8_t muxNumber_TESLA_2E1 = 0;
//0x334 UI
@ -457,15 +461,14 @@ class TeslaBattery : public CanBattery {
.DLC = 8,
.ID = 0x610,
.data = {0x02, 0x10, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}}; // Define initial UDS request
uint8_t index_1CF = 0;
uint8_t index_118 = 0;
uint8_t stateMachineClearIsolationFault = 0xFF;
uint8_t stateMachineBMSReset = 0xFF;
uint8_t stateMachineSOCReset = 0xFF;
uint8_t stateMachineBMSQuery = 0xFF;
uint16_t sendContactorClosingMessagesStill = 300;
uint16_t battery_cell_max_v = 3300;
uint16_t battery_cell_min_v = 3300;
uint16_t battery_cell_deviation_mV = 0; //contains the deviation between highest and lowest cell in mV
bool cellvoltagesRead = false;
//0x3d2: 978 BMS_kwhCounter
uint32_t battery_total_discharge = 0;

View file

@ -86,6 +86,13 @@ void VolvoSpaBattery::
datalayer.battery.info.total_capacity_Wh = 69511;
}
}
//Check safeties
if (datalayer_extended.VolvoPolestar.BECMsupplyVoltage < 10700) { //10.7V,
//If 12V voltage goes under this, latch battery OFF to prevent contactors from swinging between on/off
set_event(EVENT_12V_LOW, (datalayer_extended.VolvoPolestar.BECMsupplyVoltage / 100));
set_event(EVENT_BATTERY_CHG_DISCHG_STOP_REQ, 0);
}
}
void VolvoSpaBattery::handle_incoming_can_frame(CAN_frame rx_frame) {

View file

@ -12,7 +12,7 @@ class VolvoSpaHtmlRenderer : public BatteryHtmlRenderer {
content += "</h4><h4>BECM reported number of DTCs: " + String(datalayer_extended.VolvoPolestar.DTCcount) + "</h4>";
content += "<h4>BECM reported SOC: " + String(datalayer_extended.VolvoPolestar.soc_bms / 10.0) + " %</h4>";
content += "<h4>Calculated SOC: " + String(datalayer_extended.VolvoPolestar.soc_calc / 10.0) + " %</h4>";
content += "<h4>Rescaled SOC: " + String(datalayer_extended.VolvoPolestar.soc_rescaled / 10.0) + " %</h4>";
content += "<h4>Rescaled SOC: " + String(datalayer_extended.VolvoPolestar.soc_rescaled / 100.0) + " %</h4>";
content += "<h4>BECM reported SOH: " + String(datalayer_extended.VolvoPolestar.soh_bms / 100.0) + " %</h4>";
content += "<h4>BECM supply voltage: " + String(datalayer_extended.VolvoPolestar.BECMsupplyVoltage) + " mV</h4>";

View file

@ -104,6 +104,7 @@ void init_stored_settings() {
user_selected_can_addon_crystal_frequency_mhz = settings.getUInt("CANFREQ", 8);
user_selected_canfd_addon_crystal_frequency_mhz = settings.getUInt("CANFDFREQ", 40);
user_selected_LEAF_interlock_mandatory = settings.getBool("INTERLOCKREQ", false);
user_selected_use_estimated_SOC = settings.getBool("SOCESTIMATED", false);
user_selected_tesla_digital_HVIL = settings.getBool("DIGITALHVIL", false);
user_selected_tesla_GTW_country = settings.getUInt("GTWCOUNTRY", 0);
user_selected_tesla_GTW_rightHandDrive = settings.getBool("GTWRHD", false);
@ -164,6 +165,7 @@ void init_stored_settings() {
// WIFI AP is enabled by default unless disabled in the settings
wifiap_enabled = settings.getBool("WIFIAPENABLED", true);
wifi_channel = settings.getUInt("WIFICHANNEL", 0);
ssidAP = settings.getString("APNAME", "BatteryEmulator").c_str();
passwordAP = settings.getString("APPASSWORD", "123456789").c_str();
mqtt_enabled = settings.getBool("MQTTENABLED", false);
mqtt_timeout_ms = settings.getUInt("MQTTTIMEOUT", 2000);
@ -207,9 +209,11 @@ void store_settings() {
}
if (!settings.putString("SSID", String(ssid.c_str()))) {
if (ssid != "")
set_event(EVENT_PERSISTENT_SAVE_INFO, 1);
}
if (!settings.putString("PASSWORD", String(password.c_str()))) {
if (password != "")
set_event(EVENT_PERSISTENT_SAVE_INFO, 2);
}

View file

@ -235,6 +235,17 @@ struct DATALAYER_INFO_CMFAEV {
};
struct DATALAYER_INFO_ECMP {
//mysteryvan parameters
bool MysteryVan = false;
bool CrashMemorized = false;
uint8_t CONTACTOR_OPENING_REASON = 0;
uint8_t TBMU_FAULT_TYPE = 0;
uint8_t CONTACTORS_STATE = 0;
uint16_t HV_BATT_FC_INSU_MINUS_RES, HV_BATT_FC_INSU_PLUS_RES, HV_BATT_FC_VHL_INSU_PLUS_RES,
HV_BATT_ONLY_INSU_MINUS_RES = 0;
bool ALERT_CELL_POOR_CONSIST, ALERT_OVERCHARGE, ALERT_BATT, ALERT_LOW_SOC, ALERT_HIGH_SOC, ALERT_SOC_JUMP,
ALERT_TEMP_DIFF, ALERT_HIGH_TEMP, ALERT_OVERVOLTAGE, ALERT_CELL_OVERVOLTAGE, ALERT_CELL_UNDERVOLTAGE = false;
//ecmp below
uint8_t MainConnectorState = 0;
uint16_t InsulationResistance = 0;
uint8_t InsulationDiag = 0;
@ -766,7 +777,7 @@ struct DATALAYER_INFO_VOLVO_POLESTAR {
uint16_t soc_calc = 0;
uint16_t soc_rescaled = 0;
uint16_t soh_bms = 0;
uint16_t BECMsupplyVoltage = 0;
uint16_t BECMsupplyVoltage = 12000;
uint16_t BECMBatteryVoltage = 0;
int16_t BECMBatteryCurrent = 0;

View file

@ -21,6 +21,9 @@ class StarkHal : public Esp32Hal {
public:
const char* name() { return "Stark CMR Module"; }
//Always enable BMS power on Stark CMR, it does not collide with any pin definitions
virtual bool always_enable_bms_power() { return true; }
// Not needed, GPIO 16 has hardware pullup for PSRAM compatibility
virtual gpio_num_t PIN_5V_EN() { return GPIO_NUM_NC; }

View file

@ -67,6 +67,9 @@ void init_events(void) {
events.entries[EVENT_BATTERY_UNDERVOLTAGE].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_BATTERY_VALUE_UNAVAILABLE].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_BATTERY_ISOLATION].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_BATTERY_SOC_RECALIBRATION].level = EVENT_LEVEL_INFO;
events.entries[EVENT_BATTERY_SOC_RESET_SUCCESS].level = EVENT_LEVEL_INFO;
events.entries[EVENT_BATTERY_SOC_RESET_FAIL].level = EVENT_LEVEL_INFO;
events.entries[EVENT_VOLTAGE_DIFFERENCE].level = EVENT_LEVEL_INFO;
events.entries[EVENT_SOH_DIFFERENCE].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_SOH_LOW].level = EVENT_LEVEL_ERROR;
@ -124,6 +127,8 @@ void init_events(void) {
events.entries[EVENT_EQUIPMENT_STOP].level = EVENT_LEVEL_ERROR;
events.entries[EVENT_SD_INIT_FAILED].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_PERIODIC_BMS_RESET].level = EVENT_LEVEL_INFO;
events.entries[EVENT_BMS_RESET_REQ_SUCCESS].level = EVENT_LEVEL_INFO;
events.entries[EVENT_BMS_RESET_REQ_FAIL].level = EVENT_LEVEL_INFO;
events.entries[EVENT_BATTERY_TEMP_DEVIATION_HIGH].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_GPIO_CONFLICT].level = EVENT_LEVEL_ERROR;
events.entries[EVENT_GPIO_NOT_DEFINED].level = EVENT_LEVEL_ERROR;
@ -244,6 +249,12 @@ String get_event_message_string(EVENTS_ENUM_TYPE event) {
return "Battery measurement unavailable. Check 12V power supply and battery wiring!";
case EVENT_BATTERY_ISOLATION:
return "Battery reports isolation error. High voltage might be leaking to ground. Check battery!";
case EVENT_BATTERY_SOC_RECALIBRATION:
return "The BMS updated the HV battery State of Charge (SOC) by more than 3pct based on SocByOcv.";
case EVENT_BATTERY_SOC_RESET_SUCCESS:
return "SOC reset routine was successful.";
case EVENT_BATTERY_SOC_RESET_FAIL:
return "SOC reset routine failed - check SOC is < 15 or > 90, and contactors are open.";
case EVENT_VOLTAGE_DIFFERENCE:
return "Too large voltage diff between the batteries. Second battery cannot join the DC-link";
case EVENT_SOH_DIFFERENCE:
@ -361,7 +372,11 @@ String get_event_message_string(EVENTS_ENUM_TYPE event) {
case EVENT_SD_INIT_FAILED:
return "SD card initialization failed, check hardware. Power must be removed to reset the SD card.";
case EVENT_PERIODIC_BMS_RESET:
return "BMS Reset Event Completed.";
return "BMS reset event completed.";
case EVENT_BMS_RESET_REQ_SUCCESS:
return "BMS reset request completed successfully.";
case EVENT_BMS_RESET_REQ_FAIL:
return "BMS reset request failed - check contactors are open.";
case EVENT_GPIO_CONFLICT:
return "GPIO Pin Conflict: The pin used by '" + esp32hal->failed_allocator() + "' is already allocated by '" +
esp32hal->conflicting_allocator() + "'. Please check your configuration and assign different pins.";

View file

@ -49,6 +49,9 @@
XX(EVENT_BATTERY_ISOLATION) \
XX(EVENT_BATTERY_REQUESTS_HEAT) \
XX(EVENT_BATTERY_WARMED_UP) \
XX(EVENT_BATTERY_SOC_RECALIBRATION) \
XX(EVENT_BATTERY_SOC_RESET_SUCCESS) \
XX(EVENT_BATTERY_SOC_RESET_FAIL) \
XX(EVENT_VOLTAGE_DIFFERENCE) \
XX(EVENT_SOH_DIFFERENCE) \
XX(EVENT_SOH_LOW) \
@ -107,6 +110,8 @@
XX(EVENT_AUTOMATIC_PRECHARGE_FAILURE) \
XX(EVENT_SD_INIT_FAILED) \
XX(EVENT_PERIODIC_BMS_RESET) \
XX(EVENT_BMS_RESET_REQ_SUCCESS) \
XX(EVENT_BMS_RESET_REQ_FAIL) \
XX(EVENT_BATTERY_TEMP_DEVIATION_HIGH) \
XX(EVENT_GPIO_NOT_DEFINED) \
XX(EVENT_GPIO_CONFLICT) \

View file

@ -251,6 +251,10 @@ String settings_processor(const String& var, BatteryEmulatorSettingsStore& setti
return settings.getBool("DBLBTR") ? "checked" : "";
}
if (var == "SOCESTIMATED") {
return settings.getBool("SOCESTIMATED") ? "checked" : "";
}
if (var == "CNTCTRL") {
return settings.getBool("CNTCTRL") ? "checked" : "";
}
@ -295,6 +299,10 @@ String settings_processor(const String& var, BatteryEmulatorSettingsStore& setti
return settings.getString("APPASSWORD", "123456789");
}
if (var == "APNAME") {
return settings.getString("APNAME", "BatteryEmulator");
}
if (var == "STATICIP") {
return settings.getBool("STATICIP") ? "checked" : "";
}
@ -742,7 +750,7 @@ const char* getCANInterfaceName(CAN_Interface interface) {
function editError(){alert('Invalid input');}
function editSSID(){var value=prompt('Enter new SSID:');if(value!==null){var xhr=new
function editSSID(){var value=prompt('Which SSID to connect to. Enter new SSID:');if(value!==null){var xhr=new
XMLHttpRequest();xhr.onload=editComplete;xhr.onerror=editError;xhr.open('GET','/updateSSID?value='+encodeURIComponent(value),true);xhr.send();}}
function editPassword(){var value=prompt('Enter new password:');if(value!==null){var xhr=new
@ -912,6 +920,11 @@ const char* getCANInterfaceName(CAN_Interface interface) {
display: contents;
}
form .if-socestimated { display: none; } /* Integrations where you can turn on SOC estimation */
form[data-battery="16"] .if-socestimated {
display: contents;
}
form .if-dblbtr { display: none; }
form[data-dblbtr="true"] .if-dblbtr {
display: contents;
@ -968,6 +981,7 @@ const char* getCANInterfaceName(CAN_Interface interface) {
#define SETTINGS_HTML_BODY \
R"rawliteral(
<button onclick='goToMainPage()'>Back to main page</button>
<button onclick="askFactoryReset()">Factory reset</button>
<div style='background-color: #303E47; padding: 10px; margin-bottom: 10px; border-radius: 50px'>
<h4 style='color: white;'>SSID: <span id='SSID'>%SSID%</span><button onclick='editSSID()'>Edit</button></h4>
@ -1016,10 +1030,20 @@ const char* getCANInterfaceName(CAN_Interface interface) {
<div class="if-estimated">
<label>Manual charging power, watt: </label>
<input name='CHGPOWER' pattern="^[0-9]+$" type='text' value='%CHGPOWER%' />
<input type='number' name='CHGPOWER' value="%CHGPOWER%"
min="0" max="65000" step="1"
title="Continous max charge power. Used since CAN data not valid for this integration. Do not set too high!" />
<label>Manual discharge power, watt: </label>
<input name='DCHGPOWER' pattern="^[0-9]+$" type='text' value='%DCHGPOWER%' />
<input type='number' name='DCHGPOWER' value="%DCHGPOWER%"
min="0" max="65000" step="1"
title="Continous max discharge power. Used since CAN data not valid for this integration. Do not set too high!" />
</div>
<div class="if-socestimated">
<label>Use estimated SOC: </label>
<input type='checkbox' name='SOCESTIMATED' value='on' %SOCESTIMATED%
title="Switch to estimated State of Charge when accurate SOC data is not available from the battery" />
</div>
<div class="if-battery">
@ -1034,20 +1058,25 @@ const char* getCANInterfaceName(CAN_Interface interface) {
<div class="if-cbms">
<label>Battery max design voltage (V): </label>
<input name='BATTPVMAX' pattern="^[0-9]+(\.[0-9]+)?$" type='text' value='%BATTPVMAX%' />
<input name='BATTPVMAX' pattern="[0-9]+(\.[0-9]+)?" type='text' value='%BATTPVMAX%'
title="Maximum safe voltage for the entire battery pack in volts. Used as charge target and protection limits." />
<label>Battery min design voltage (V): </label>
<input name='BATTPVMIN' pattern="^[0-9]+(\.[0-9]+)?$" type='text' value='%BATTPVMIN%' />
<input name='BATTPVMIN' pattern="[0-9]+(\.[0-9]+)?" type='text' value='%BATTPVMIN%'
title="Minimum safe voltage for the entire battery pack in volts. Further discharge not possible below this limit." />
<label>Cell max design voltage (mV): </label>
<input name='BATTCVMAX' pattern="^[0-9]+$" type='text' value='%BATTCVMAX%' />
<input name='BATTCVMAX' pattern="[0-9]+" type='text' value='%BATTCVMAX%'
title="Maximum voltage per individual cell in millivolts. Charging stops if one cell reaches this voltage." />
<label>Cell min design voltage (mV): </label>
<input name='BATTCVMIN' pattern="^[0-9]+$" type='text' value='%BATTCVMIN%' />
<input name='BATTCVMIN' pattern="[0-9]+$" type='text' value='%BATTCVMIN%'
title="Minimum voltage per individual cell in millivolts. Discharge stops if one cell drops to this voltage." />
</div>
<label>Double battery: </label>
<input type='checkbox' name='DBLBTR' value='on' %DBLBTR% />
<input type='checkbox' name='DBLBTR' value='on' %DBLBTR%
title="Enable this option if you intend to run two batteries in parallel" />
<div class="if-dblbtr">
<label>Battery 2 interface: </label>
@ -1075,33 +1104,33 @@ const char* getCANInterfaceName(CAN_Interface interface) {
<div class="if-sofar">
<label>Sofar Battery ID (0-15): </label>
<input name='SOFAR_ID' type='text' value="%SOFAR_ID%" pattern="^[0-9]{1,2}$" />
<input name='SOFAR_ID' type='text' value="%SOFAR_ID%" pattern="[0-9]{1,2}" />
</div>
<div class="if-pylonish">
<label>Reported cell count (0 for default): </label>
<input name='INVCELLS' type='text' value="%INVCELLS%" pattern="^[0-9]+$" />
<input name='INVCELLS' type='text' value="%INVCELLS%" pattern="[0-9]+" />
</div>
<div class="if-pylonish if-solax">
<label>Reported module count (0 for default): </label>
<input name='INVMODULES' type='text' value="%INVMODULES%" pattern="^[0-9]+$" />
<input name='INVMODULES' type='text' value="%INVMODULES%" pattern="[0-9]+" />
</div>
<div class="if-pylonish">
<label>Reported cells per module (0 for default): </label>
<input name='INVCELLSPER' type='text' value="%INVCELLSPER%" pattern="^[0-9]+$" />
<input name='INVCELLSPER' type='text' value="%INVCELLSPER%" pattern="[0-9]+" />
<label>Reported voltage level (0 for default): </label>
<input name='INVVLEVEL' type='text' value="%INVVLEVEL%" pattern="^[0-9]+$" />
<input name='INVVLEVEL' type='text' value="%INVVLEVEL%" pattern="[0-9]+" />
<label>Reported Ah capacity (0 for default): </label>
<input name='INVCAPACITY' type='text' value="%INVCAPACITY%" pattern="^[0-9]+$" />
<input name='INVCAPACITY' type='text' value="%INVCAPACITY%" pattern="[0-9]+" />
</div>
<div class="if-solax">
<label>Reported battery type (in decimal): </label>
<input name='INVBTYPE' type='text' value="%INVBTYPE%" pattern="^[0-9]+$" />
<input name='INVBTYPE' type='text' value="%INVBTYPE%" pattern="[0-9]+" />
<label>Inverter should ignore contactors: </label>
<input type='checkbox' name='INVICNT' value='on' %INVICNT% />
@ -1142,13 +1171,18 @@ const char* getCANInterfaceName(CAN_Interface interface) {
<div style='display: grid; grid-template-columns: 1fr 1.5fr; gap: 10px; align-items: center;'>
<label>Use CanFD as classic CAN: </label>
<input type='checkbox' name='CANFDASCAN' value='on' %CANFDASCAN% />
<input type='checkbox' name='CANFDASCAN' value='on' %CANFDASCAN%
title="When enabled, CAN-FD channel will operate as normal 500kbps CAN" />
<label>CAN addon crystal (Mhz): </label>
<input name='CANFREQ' type='text' value="%CANFREQ%" pattern="^[0-9]+$" />
<input type='number' name='CANFREQ' value="%CANFREQ%"
min="0" max="1000" step="1"
title="Configure this if you are using a custom add-on CAN board. Integers only" />
<label>CAN-FD-addon crystal (Mhz): </label>
<input name='CANFDFREQ' type='text' value="%CANFDFREQ%" pattern="^[0-9]+$" />
<input type='number' name='CANFDFREQ' value="%CANFDFREQ%"
min="0" max="1000" step="1"
title="Configure this if you are using a custom add-on CAN board. Integers only" />
<label>Equipment stop button: </label><select name='EQSTOP'>
%EQSTOP%
@ -1164,17 +1198,23 @@ const char* getCANInterfaceName(CAN_Interface interface) {
<div class="if-cntctrl">
<label>Precharge time ms: </label>
<input name='PRECHGMS' type='text' value="%PRECHGMS%" pattern="^[0-9]+$" />
<input type='number' name='PRECHGMS' value="%PRECHGMS%"
min="1" max="65000" step="1"
title="Time in milliseconds the precharge should be active" />
<label>PWM contactor control: </label>
<input type='checkbox' name='PWMCNTCTRL' value='on' %PWMCNTCTRL% />
<div class="if-pwmcntctrl">
<label>PWM Frequency Hz: </label>
<input name='PWMFREQ' type='text' value="%PWMFREQ%" pattern="^[0-9]+$" />
<input name='PWMFREQ' type='text' value="%PWMFREQ%"
min="1" max="65000" step="1"
title="Frequency in Hz used for PWM" />
<label>PWM Hold 0-1023: </label>
<input name='PWMHOLD' type='text' value="%PWMHOLD%" pattern="^[0-9]+$" />
<label>PWM Hold 1-1023: </label>
<input type='number' name='PWMHOLD' value="%PWMHOLD%"
min="1" max="1023" step="1"
title="1-1023 , lower value = lower power consumption" />
</div>
</div>
@ -1187,7 +1227,7 @@ const char* getCANInterfaceName(CAN_Interface interface) {
<div class="if-extprecharge">
<label>Precharge, maximum ms before fault: </label>
<input name='MAXPRETIME' type='text' value="%MAXPRETIME%" pattern="^[0-9]+$" />
<input name='MAXPRETIME' type='text' value="%MAXPRETIME%" pattern="[0-9]+" />
<label>Normally Open (NO) inverter disconnect contactor: </label>
<input type='checkbox' name='NOINVDISC' value='on' %NOINVDISC% />
@ -1207,14 +1247,27 @@ const char* getCANInterfaceName(CAN_Interface interface) {
<label>Broadcast Wifi access point: </label>
<input type='checkbox' name='WIFIAPENABLED' value='on' %WIFIAPENABLED% />
<label>Access point name: </label>
<input type='text' name='APNAME' value="%APNAME%"
pattern="[A-Za-z0-9!#*-]{8,63}"
title="Name must be 8-63 characters long and may only contain letters, numbers and some special characters: !#*-"
required />
<label>Access point password: </label>
<input type='text' name='APPASSWORD' value="%APPASSWORD%" />
<input type='text' name='APPASSWORD' value="%APPASSWORD%"
pattern="[A-Za-z0-9!#*-]{8,63}"
title="Password must be 8-63 characters long and may only contain letters, numbers and some special characters: !#*-"
required />
<label>Wifi channel 0-14: </label>
<input name='WIFICHANNEL' type='text' value="%WIFICHANNEL%" pattern="^[0-9]+$" />
<input type='number' name='WIFICHANNEL' value="%WIFICHANNEL%"
min="0" max="14" step="1"
title="Force specific channel. Set to 0 for autodetect" required />
<label>Custom Wifi hostname: </label>
<input type='text' name='HOSTNAME' value="%HOSTNAME%" />
<input type='text' name='HOSTNAME' value="%HOSTNAME%"
pattern="[A-Za-z0-9!#*-]+"
title="Optional: Hostname may only contain letters, numbers and some special characters: !#*-" />
<label>Use static IP address: </label>
<input type='checkbox' name='STATICIP' value='on' %STATICIP% />
@ -1250,11 +1303,24 @@ const char* getCANInterfaceName(CAN_Interface interface) {
<input type='checkbox' name='MQTTENABLED' value='on' %MQTTENABLED% />
<div class='if-mqtt'>
<label>MQTT server: </label><input type='text' name='MQTTSERVER' value="%MQTTSERVER%" />
<label>MQTT port: </label><input type='text' name='MQTTPORT' value="%MQTTPORT%" />
<label>MQTT user: </label><input type='text' name='MQTTUSER' value="%MQTTUSER%" />
<label>MQTT password: </label><input type='password' name='MQTTPASSWORD' value="%MQTTPASSWORD%" />
<label>MQTT timeout ms: </label><input name='MQTTTIMEOUT' type='text' value="%MQTTTIMEOUT%" pattern="^[0-9]+$" />
<label>MQTT server: </label>
<input type='text' name='MQTTSERVER' value="%MQTTSERVER%"
pattern="[A-Za-z0-9.-]+"
title="Hostname (letters, numbers, dots, hyphens)" />
<label>MQTT port: </label>
<input type='number' name='MQTTPORT' value="%MQTTPORT%"
min="1" max="65535" step="1"
title="Port number (1-65535)" />
<label>MQTT user: </label><input type='text' name='MQTTUSER' value="%MQTTUSER%"
pattern="[A-Za-z0-9!#*-]+"
title="MQTT username can only contain letters, numbers and some special characters: !#*-" />
<label>MQTT password: </label><input type='password' name='MQTTPASSWORD' value="%MQTTPASSWORD%"
pattern="[A-Za-z0-9!#*-]+"
title="MQTT password can only contain letters, numbers and some special characters: !#*-" />
<label>MQTT timeout ms: </label>
<input name='MQTTTIMEOUT' type='number' value="%MQTTTIMEOUT%"
min="1" max="60000" step="1"
title="Timeout in milliseconds (1-60000)" />
<label>Send all cellvoltages via MQTT: </label><input type='checkbox' name='MQTTCELLV' value='on' %MQTTCELLV% />
<label>Remote BMS reset via MQTT allowed: </label>
<input type='checkbox' name='REMBMSRESET' value='on' %REMBMSRESET% />
@ -1283,22 +1349,46 @@ const char* getCANInterfaceName(CAN_Interface interface) {
<div style='display: grid; grid-template-columns: 1fr 1.5fr; gap: 10px; align-items: center;'>
<label>Enable performance profiling on main page: </label>
<input type='checkbox' name='PERFPROFILE' value='on' %PERFPROFILE% />
<input type='checkbox' name='PERFPROFILE' value='on' %PERFPROFILE%
title="For developers. Enable this to get detailed performance metrics on the front page" />
<label>Enable CAN message logging via USB serial: </label>
<input type='checkbox' name='CANLOGUSB' value='on' %CANLOGUSB% />
<input type='checkbox' name='CANLOGUSB' value='on' %CANLOGUSB%
title="WARNING: Causes performance issues. Enable this to get incoming/outgoing CAN messages logged via USB cable. Avoid if possible" />
<script> //Make sure user only uses one general logging method, improves performance
function handleCheckboxSelection(clickedCheckbox) {
const usbCheckbox = document.querySelector('input[name="USBENABLED"]');
const webCheckbox = document.querySelector('input[name="WEBENABLED"]');
if (clickedCheckbox.checked) {
// If the clicked checkbox is being checked, uncheck the other one
if (clickedCheckbox.name === 'USBENABLED') {
webCheckbox.checked = false;
} else {
usbCheckbox.checked = false;
}
}
// If unchecking, do nothing (allow both to be unchecked)
}
</script>
<label>Enable general logging via USB serial: </label>
<input type='checkbox' name='USBENABLED' value='on' %USBENABLED% />
<input type='checkbox' name='USBENABLED' value='on' %USBENABLED%
onclick="handleCheckboxSelection(this)"
title="WARNING: Causes performance issues. Enable this to get general logging via USB cable. Avoid if possible" />
<label>Enable general logging via Webserver: </label>
<input type='checkbox' name='WEBENABLED' value='on' %WEBENABLED% />
<input type='checkbox' name='WEBENABLED' value='on' %WEBENABLED%
onclick="handleCheckboxSelection(this)"
title="Enable this if you want general logging available in the Webserver" />
<label>Enable CAN message logging via SD card: </label>
<input type='checkbox' name='CANLOGSD' value='on' %CANLOGSD% />
<input type='checkbox' name='CANLOGSD' value='on' %CANLOGSD%
title="Enable this if you want incoming/outgoing CAN messages to be stored to an SD card. Only works on select hardware with SD-card slot" />
<label>Enable general logging via SD card: </label>
<input type='checkbox' name='SDLOGENABLED' value='on' %SDLOGENABLED% />
<input type='checkbox' name='SDLOGENABLED' value='on' %SDLOGENABLED%
title="Enable this if you want general logging to be stored to an SD card. Only works on select hardware with SD-card slot" />
</div>
</div>
@ -1391,8 +1481,6 @@ const char* getCANInterfaceName(CAN_Interface interface) {
</div>
<button onclick="askFactoryReset()">Factory reset</button>
</div>
)rawliteral"

View file

@ -23,9 +23,6 @@
extern std::string http_username;
extern std::string http_password;
bool webserver_enabled =
true; // Global flag to enable or disable the webserver //Old method to disable was with #ifdef WEBSERVER
bool webserver_auth = false;
// Create AsyncWebServer object on port 80
@ -400,7 +397,7 @@ void init_webserver() {
"DBLBTR", "CNTCTRL", "CNTCTRLDBL", "PWMCNTCTRL", "PERBMSRESET", "SDLOGENABLED", "STATICIP",
"REMBMSRESET", "EXTPRECHARGE", "USBENABLED", "CANLOGUSB", "WEBENABLED", "CANFDASCAN", "CANLOGSD",
"WIFIAPENABLED", "MQTTENABLED", "NOINVDISC", "HADISC", "MQTTTOPICS", "MQTTCELLV", "INVICNT",
"GTWRHD", "DIGITALHVIL", "PERFPROFILE", "INTERLOCKREQ",
"GTWRHD", "DIGITALHVIL", "PERFPROFILE", "INTERLOCKREQ", "SOCESTIMATED",
};
// Handles the form POST from UI to save settings of the common image
@ -509,6 +506,8 @@ void init_webserver() {
} else if (p->name() == "SUBNET4") {
auto type = atoi(p->value().c_str());
settings.saveUInt("SUBNET4", type);
} else if (p->name() == "APNAME") {
settings.saveString("APNAME", p->value().c_str());
} else if (p->name() == "APPASSWORD") {
settings.saveString("APPASSWORD", p->value().c_str());
} else if (p->name() == "HOSTNAME") {
@ -525,7 +524,8 @@ void init_webserver() {
} else if (p->name() == "MQTTTOPIC") {
settings.saveString("MQTTTOPIC", p->value().c_str());
} else if (p->name() == "MQTTTIMEOUT") {
settings.saveString("MQTTTIMEOUT", p->value().c_str());
auto port = atoi(p->value().c_str());
settings.saveUInt("MQTTTIMEOUT", port);
} else if (p->name() == "MQTTOBJIDPREFIX") {
settings.saveString("MQTTOBJIDPREFIX", p->value().c_str());
} else if (p->name() == "MQTTDEVICENAME") {
@ -621,7 +621,7 @@ void init_webserver() {
def_route_with_auth("/updatePassword", server, HTTP_GET, [](AsyncWebServerRequest* request) {
if (request->hasParam("value")) {
String value = request->getParam("value")->value();
if (value.length() > 8) { // Check if password is within the allowable length
if (value.length() >= 8) { // Password must be 8 characters or longer
password = value.c_str();
store_settings();
request->send(200, "text/plain", "Updated successfully");

View file

@ -7,8 +7,6 @@
#include "../../lib/ayushsharma82-ElegantOTA/src/ElegantOTA.h"
#include "../../lib/mathieucarbou-AsyncTCPSock/src/AsyncTCP.h"
extern bool webserver_enabled;
extern const char* version_number; // The current software version, shown on webserver
// Common charger parameters

View file

@ -54,7 +54,7 @@ static uint16_t current_check_interval = WIFI_CHECK_INTERVAL;
static bool connected_once = false;
void init_WiFi() {
DEBUG_PRINTF("init_Wifi enabled=%d, apå=%d, ssid=%s, password=%s\n", wifi_enabled, wifiap_enabled, ssid.c_str(),
DEBUG_PRINTF("init_Wifi enabled=%d, ap=%d, ssid=%s, password=%s\n", wifi_enabled, wifiap_enabled, ssid.c_str(),
password.c_str());
if (!custom_hostname.empty()) {
@ -108,7 +108,7 @@ void wifi_monitor() {
if ((hasConnectedBefore && (currentMillis - lastWiFiCheck > current_check_interval)) ||
(!hasConnectedBefore && (currentMillis - lastWiFiCheck > INIT_WIFI_FULL_RECONNECT_INTERVAL))) {
DEBUG_PRINTF("Time to monitor Wi-Fi status: %d, %d, %d, %d, %d\n", hasConnectedBefore, currentMillis, lastWiFiCheck,
DEBUG_PRINTF("Wi-Fi status: %d, %d, %d, %d, %d\n", hasConnectedBefore, currentMillis, lastWiFiCheck,
current_check_interval, INIT_WIFI_FULL_RECONNECT_INTERVAL);
lastWiFiCheck = currentMillis;
@ -240,7 +240,6 @@ void init_mDNS() {
}
void init_WiFi_AP() {
ssidAP = std::string("BatteryEmulator") + WiFi.macAddress().c_str();
DEBUG_PRINTF("Creating Access Point: %s\n", ssidAP.c_str());
DEBUG_PRINTF("With password: %s\n", passwordAP.c_str());

View file

@ -139,11 +139,10 @@ void AforeCanInverter::map_can_frame_to_variable(CAN_frame rx_frame) {
switch (rx_frame.ID) {
case 0x305: // Every 1s from inverter
datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE;
char0 = rx_frame.data.u8[0]; // A
char1 = rx_frame.data.u8[0]; // F
char2 = rx_frame.data.u8[0]; // O
char3 = rx_frame.data.u8[0]; // R
char4 = rx_frame.data.u8[0]; // E
for (uint8_t i = 0; i < 5; i++) {
datalayer.system.info.inverter_brand[i] = rx_frame.data.u8[i];
}
datalayer.system.info.inverter_brand[7] = '\0';
inverter_status = rx_frame.data.u8[7];
time_to_send_info = true;
break;

View file

@ -16,11 +16,6 @@ class AforeCanInverter : public CanInverterProtocol {
uint8_t inverter_status =
0; //0 = init, 1 = standby, 2 = starting, 3 = grid connected, 4 off-grid, 5 diesel generator, 6 grid connected, but disconnected, 7off grid and disconnected, 8 = power failure processing, 9 = power off, 10 = Failure
bool time_to_send_info = false;
uint8_t char0 = 0;
uint8_t char1 = 0;
uint8_t char2 = 0;
uint8_t char3 = 0;
uint8_t char4 = 0;
//Actual content messages
CAN_frame AFORE_350 = {.FD = false, // Operation information
.ext_ID = false,

View file

@ -69,6 +69,10 @@ void BydCanInverter::
BYD_150.data.u8[6] = (fully_charged_capacity_ah >> 8);
BYD_150.data.u8[7] = (fully_charged_capacity_ah & 0x00FF);
//Alarms
//TODO: BYD Alarms are not implemented yet. Investigation needed on the bits in this message
//BYD_190.data.u8[0] =
//Voltage (ex 370.0)
BYD_1D0.data.u8[0] = (datalayer.battery.status.voltage_dV >> 8);
BYD_1D0.data.u8[1] = (datalayer.battery.status.voltage_dV & 0x00FF);
@ -144,21 +148,21 @@ void BydCanInverter::transmit_can(unsigned long currentMillis) {
if (currentMillis - previousMillis2s >= INTERVAL_2_S) {
previousMillis2s = currentMillis;
transmit_can_frame(&BYD_110);
transmit_can_frame(&BYD_110); //Send Limits
}
// Send 10s CAN Message
if (currentMillis - previousMillis10s >= INTERVAL_10_S) {
previousMillis10s = currentMillis;
transmit_can_frame(&BYD_150);
transmit_can_frame(&BYD_1D0);
transmit_can_frame(&BYD_210);
transmit_can_frame(&BYD_150); //Send States
transmit_can_frame(&BYD_1D0); //Send Battery Info
transmit_can_frame(&BYD_210); //Send Cell Info
}
//Send 60s message
if (currentMillis - previousMillis60s >= INTERVAL_60_S) {
previousMillis60s = currentMillis;
transmit_can_frame(&BYD_190);
transmit_can_frame(&BYD_190); //Send Alarm
}
}
@ -166,8 +170,12 @@ void BydCanInverter::send_initial_data() {
transmit_can_frame(&BYD_250);
transmit_can_frame(&BYD_290);
transmit_can_frame(&BYD_2D0);
transmit_can_frame(&BYD_3D0_0);
transmit_can_frame(&BYD_3D0_1);
transmit_can_frame(&BYD_3D0_2);
transmit_can_frame(&BYD_3D0_3);
BYD_3D0.data = {0x00, 0x42, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79}; //Battery
transmit_can_frame(&BYD_3D0);
BYD_3D0.data = {0x01, 0x2D, 0x42, 0x6F, 0x78, 0x20, 0x50, 0x72}; //-Box Pr
transmit_can_frame(&BYD_3D0);
BYD_3D0.data = {0x02, 0x65, 0x6D, 0x69, 0x75, 0x6D, 0x20, 0x48}; //emium H
transmit_can_frame(&BYD_3D0);
BYD_3D0.data = {0x03, 0x56, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00}; //VS
transmit_can_frame(&BYD_3D0);
}

View file

@ -40,48 +40,33 @@ class BydCanInverter : public CanInverterProtocol {
.DLC = 8,
.ID = 0x2D0,
.data = {0x00, 0x42, 0x59, 0x44, 0x00, 0x00, 0x00, 0x00}}; //BYD
CAN_frame BYD_3D0_0 = {.FD = false,
CAN_frame BYD_3D0 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x3D0,
.data = {0x00, 0x42, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79}}; //Battery
CAN_frame BYD_3D0_1 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x3D0,
.data = {0x01, 0x2D, 0x42, 0x6F, 0x78, 0x20, 0x50, 0x72}}; //-Box Pr
CAN_frame BYD_3D0_2 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x3D0,
.data = {0x02, 0x65, 0x6D, 0x69, 0x75, 0x6D, 0x20, 0x48}}; //emium H
CAN_frame BYD_3D0_3 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x3D0,
.data = {0x03, 0x56, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00}}; //VS
//Actual content messages
CAN_frame BYD_110 = {.FD = false,
CAN_frame BYD_110 = {.FD = false, //Limits
.ext_ID = false,
.DLC = 8,
.ID = 0x110,
.data = {0x01, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame BYD_150 = {.FD = false,
CAN_frame BYD_150 = {.FD = false, //States
.ext_ID = false,
.DLC = 8,
.ID = 0x150,
.data = {0x00, 0x00, 0x00, 0x00, 0x10, 0x27, 0x00, 0x00}};
CAN_frame BYD_190 = {.FD = false,
CAN_frame BYD_190 = {.FD = false, //Alarm
.ext_ID = false,
.DLC = 8,
.ID = 0x190,
.data = {0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame BYD_1D0 = {.FD = false,
CAN_frame BYD_1D0 = {.FD = false, //Battery Info
.ext_ID = false,
.DLC = 8,
.ID = 0x1D0,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x08}};
CAN_frame BYD_210 = {.FD = false,
CAN_frame BYD_210 = {.FD = false, //Cell info
.ext_ID = false,
.DLC = 8,
.ID = 0x210,

View file

@ -136,8 +136,8 @@ void KostalInverterProtocol::update_values() {
float2frame(CYCLIC_DATA, (float)datalayer.battery.status.current_dA / 10, 18); // Last current
float2frame(CYCLIC_DATA, (float)datalayer.battery.status.current_dA / 10, 22); // Should be Avg current(1s)
// Close contactors after 20 battery info frames requested
if (f2_startup_count > 20) {
// Close contactors after 7 battery info frames requested
if (f2_startup_count > 7) {
datalayer.system.status.inverter_allows_contactor_closing = true;
dbg_message("inverter_allows_contactor_closing -> true (info frame)");
}

View file

@ -10,7 +10,7 @@ class SmaBydHInverter : public SmaInverterBase {
void update_values();
void transmit_can(unsigned long currentMillis);
void map_can_frame_to_variable(CAN_frame rx_frame);
static constexpr const char* Name = "BYD over SMA CAN";
static constexpr const char* Name = "SMA compatible BYD H";
virtual bool controls_contactor() { return true; }

View file

@ -10,7 +10,7 @@ class SmaBydHvsInverter : public SmaInverterBase {
void update_values();
void transmit_can(unsigned long currentMillis);
void map_can_frame_to_variable(CAN_frame rx_frame);
static constexpr const char* Name = "BYD Battery-Box HVS over SMA CAN";
static constexpr const char* Name = "SMA compatible BYD Battery-Box HVS";
virtual bool controls_contactor() { return true; }

File diff suppressed because one or more lines are too long

View file

@ -3,6 +3,6 @@
#include <Arduino.h>
extern const uint8_t ELEGANT_HTML[11640];
extern const uint8_t ELEGANT_HTML[10615];
#endif

View file

@ -0,0 +1,23 @@
import json
from pathlib import Path
libpath = Path("ayushsharma82-ElegantOTA")
gzipped=libpath/"CurrentPlainHTML.txt.gz"
header=libpath/"src/elop.h"
cpp=libpath/"src/elop.cpp"
if not gzipped.exists():
print(f"Please create {gzipped.resolve()} to replace OTA file.")
print(f"Example: zopfli -v --i10000 {libpath.resolve()}/CurrentPlainHTML.txt")
raise SystemExit(1)
gzipbytes=gzipped.read_bytes()
intlist = [int(one) for one in gzipbytes]
content = json.dumps(intlist).replace("[","{").replace("]","}").replace(" ", "")
headertext = header.read_text()
header.write_text(headertext[:1+headertext.find("[")]+str(len(gzipbytes))+headertext[headertext.find("]"):])
cpptext = cpp.read_text()
first_bracket = cpptext.find("[")
second_bracket = cpptext.find("]")
corrected_bytes = cpptext[:1+first_bracket]+str(len(gzipbytes))+cpptext[second_bracket:]
cppout = corrected_bytes[:corrected_bytes.find("{")]+content+corrected_bytes[corrected_bytes.find(";"):]+"\n"
cpp.write_text(cppout)
print("File content updated from", gzipped.resolve())
print("Bytes fixed:", cpptext[1+first_bracket:second_bracket], "to", len(gzipbytes))

View file

@ -26,6 +26,9 @@ platform = https://github.com/pioarduino/platform-espressif32/releases/download/
board = esp32dev
monitor_speed = 115200
monitor_filters = default, time, log2file
board_build.flash_mode = qio
board_build.f_flash = 80000000
board_build.arduino.memory_type = qio_qspi
board_build.partitions = min_spiffs.csv
framework = arduino
build_flags = -I include -DHW_LILYGO
@ -36,6 +39,9 @@ platform = https://github.com/pioarduino/platform-espressif32/releases/download/
board = esp32dev
monitor_speed = 115200
monitor_filters = default, time, log2file, esp32_exception_decoder
board_build.flash_mode = qio
board_build.f_flash = 80000000
board_build.arduino.memory_type = qio_qspi
board_build.partitions = min_spiffs.csv
framework = arduino
build_flags = -I include -DHW_STARK