Merge pull request #265 from dalathegreat/feature/Pylon-battery-input

New battery: Pylon 🔋
This commit is contained in:
Daniel Öster 2024-04-25 20:23:44 +03:00 committed by GitHub
commit d4a50689a1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 243 additions and 13 deletions

View file

@ -38,6 +38,7 @@ jobs:
- IMIEV_CZERO_ION_BATTERY
- KIA_HYUNDAI_64_BATTERY
- NISSAN_LEAF_BATTERY
- PYLON_BATTERY
- RENAULT_KANGOO_BATTERY
- RENAULT_ZOE_BATTERY
- TESLA_MODEL_3_BATTERY

View file

@ -41,6 +41,7 @@ jobs:
- IMIEV_CZERO_ION_BATTERY
- KIA_HYUNDAI_64_BATTERY
- NISSAN_LEAF_BATTERY
- PYLON_BATTERY
- RENAULT_KANGOO_BATTERY
- RENAULT_ZOE_BATTERY
- TESLA_MODEL_3_BATTERY

View file

@ -14,6 +14,7 @@
//#define KIA_HYUNDAI_64_BATTERY
//#define KIA_E_GMP_BATTERY
//#define NISSAN_LEAF_BATTERY
//#define PYLON_BATTERY
//#define RENAULT_KANGOO_BATTERY
//#define RENAULT_ZOE_BATTERY
//#define SANTA_FE_PHEV_BATTERY

View file

@ -4,55 +4,59 @@
#include "../../USER_SETTINGS.h"
#ifdef BMW_I3_BATTERY
#include "BMW-I3-BATTERY.h" //See this file for more i3 battery settings
#include "BMW-I3-BATTERY.h"
#endif
#ifdef CHADEMO_BATTERY
#include "CHADEMO-BATTERY.h" //See this file for more Chademo settings
#include "CHADEMO-BATTERY.h"
#endif
#ifdef IMIEV_CZERO_ION_BATTERY
#include "IMIEV-CZERO-ION-BATTERY.h" //See this file for more triplet battery settings
#include "IMIEV-CZERO-ION-BATTERY.h"
#endif
#ifdef KIA_E_GMP_BATTERY
#include "KIA-E-GMP-BATTERY.h" //See this file for more GMP battery settings
#include "KIA-E-GMP-BATTERY.h"
#endif
#ifdef KIA_HYUNDAI_64_BATTERY
#include "KIA-HYUNDAI-64-BATTERY.h" //See this file for more 64kWh battery settings
#include "KIA-HYUNDAI-64-BATTERY.h"
#endif
#ifdef NISSAN_LEAF_BATTERY
#include "NISSAN-LEAF-BATTERY.h" //See this file for more LEAF battery settings
#include "NISSAN-LEAF-BATTERY.h"
#endif
#ifdef PYLON_BATTERY
#include "PYLON-BATTERY.h"
#endif
#ifdef RENAULT_KANGOO_BATTERY
#include "RENAULT-KANGOO-BATTERY.h" //See this file for more Kangoo battery settings
#include "RENAULT-KANGOO-BATTERY.h"
#endif
#ifdef RENAULT_ZOE_BATTERY
#include "RENAULT-ZOE-BATTERY.h" //See this file for more Zoe battery settings
#include "RENAULT-ZOE-BATTERY.h"
#endif
#ifdef SANTA_FE_PHEV_BATTERY
#include "SANTA-FE-PHEV-BATTERY.h" //See this file for more Santa Fe PHEV battery settings
#include "SANTA-FE-PHEV-BATTERY.h"
#endif
#ifdef TESLA_MODEL_3_BATTERY
#include "TESLA-MODEL-3-BATTERY.h" //See this file for more Tesla battery settings
#include "TESLA-MODEL-3-BATTERY.h"
#endif
#ifdef TEST_FAKE_BATTERY
#include "TEST-FAKE-BATTERY.h" //See this file for more Fake battery settings
#include "TEST-FAKE-BATTERY.h"
#endif
#ifdef VOLVO_SPA_BATTERY
#include "VOLVO-SPA-BATTERY.h" //See this file for more XC40 Recharge/Polestar2 settings
#include "VOLVO-SPA-BATTERY.h"
#endif
#ifdef SERIAL_LINK_RECEIVER
#include "SERIAL-LINK-RECEIVER-FROM-BATTERY.h" //See this file for more Serial-battery settings
#include "SERIAL-LINK-RECEIVER-FROM-BATTERY.h"
#endif
#ifdef SERIAL_LINK_RECEIVER // The serial thing does its thing

View file

@ -0,0 +1,212 @@
#include "../include.h"
#ifdef PYLON_BATTERY
#include "../datalayer/datalayer.h"
#include "../devboard/utils/events.h"
#include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h"
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
#include "PYLON-BATTERY.h"
/* TODO:
- Test the protocol with a battery
- Check if values are scaled correctly in the Webserver
- Check if CAN sending towards the battery works OK. Tweak values from log file if needed
- If all looks good, try adding an inverter into the mix!
*/
/* Do not change code below unless you are sure what you are doing */
static unsigned long previousMillis1000 = 0; // will store last time a 1s CAN Message was sent
static uint8_t CANstillAlive = 12; //counter for checking if CAN is still alive
//Actual content messages
CAN_frame_t PYLON_3010 = {.FIR = {.B =
{
.DLC = 8,
.FF = CAN_frame_ext,
}},
.MsgID = 0x3010,
.data = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame_t PYLON_8200 = {.FIR = {.B =
{
.DLC = 8,
.FF = CAN_frame_ext,
}},
.MsgID = 0x8200,
.data = {0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame_t PYLON_8210 = {.FIR = {.B =
{
.DLC = 8,
.FF = CAN_frame_ext,
}},
.MsgID = 0x8210,
.data = {0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame_t PYLON_4200 = {.FIR = {.B =
{
.DLC = 8,
.FF = CAN_frame_ext,
}},
.MsgID = 0x4200,
.data = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
static int16_t celltemperature_max_dC = 0;
static int16_t celltemperature_min_dC = 0;
static int16_t current_dA = 0;
static uint16_t voltage_dV = 0;
static uint16_t cellvoltage_max_mV = 0;
static uint16_t cellvoltage_min_mV = 0;
static uint16_t charge_cutoff_voltage = 0;
static uint16_t discharge_cutoff_voltage = 0;
static int16_t max_charge_current = 0;
static int16_t max_discharge_current = 0;
static uint8_t ensemble_info_ack = 0;
static uint8_t battery_module_quantity = 0;
static uint8_t battery_modules_in_series = 0;
static uint8_t cell_quantity_in_module = 0;
static uint8_t voltage_level = 0;
static uint8_t ah_number = 0;
static uint8_t SOC = 0;
static uint8_t SOH = 0;
static uint8_t charge_forbidden = 0;
static uint8_t discharge_forbidden = 0;
void update_values_battery() {
datalayer.battery.status.real_soc = (SOC * 100); //increase SOC range from 0-100 -> 100.00
datalayer.battery.status.soh_pptt = (SOH * 100); //Increase decimals from 100% -> 100.00%
datalayer.battery.status.voltage_dV = voltage_dV; //value is *10 (3700 = 370.0)
datalayer.battery.status.current_dA = current_dA; //value is *10 (150 = 15.0) , invert the sign
datalayer.battery.status.active_power_W = //Power in watts, Negative = charging batt
((datalayer.battery.status.voltage_dV * datalayer.battery.status.current_dA) / 100);
datalayer.battery.status.max_charge_power_W = (max_charge_current * (voltage_dV / 10));
datalayer.battery.status.max_discharge_power_W = (max_discharge_current * (voltage_dV / 10));
datalayer.battery.status.cell_max_voltage_mV = cellvoltage_max_mV;
datalayer.battery.status.cell_min_voltage_mV = cellvoltage_min_mV;
datalayer.battery.status.temperature_min_dC = celltemperature_min_dC;
datalayer.battery.status.temperature_max_dC = celltemperature_max_dC;
datalayer.battery.info.max_design_voltage_dV = charge_cutoff_voltage;
datalayer.battery.info.min_design_voltage_dV = discharge_cutoff_voltage;
/* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/
if (!CANstillAlive) {
set_event(EVENT_CAN_RX_FAILURE, 0);
} else {
CANstillAlive--;
clear_event(EVENT_CAN_RX_FAILURE);
}
}
void receive_can_battery(CAN_frame_t rx_frame) {
CANstillAlive = 12;
switch (rx_frame.MsgID) {
case 0x7310:
case 0x7311:
ensemble_info_ack = true;
// This message contains software/hardware version info. No interest to us
break;
case 0x7320:
case 0x7321:
ensemble_info_ack = true;
battery_module_quantity = rx_frame.data.u8[0];
battery_modules_in_series = rx_frame.data.u8[2];
cell_quantity_in_module = rx_frame.data.u8[3];
voltage_level = rx_frame.data.u8[4];
ah_number = rx_frame.data.u8[6];
break;
case 0x4210:
case 0x4211:
voltage_dV = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]);
current_dA = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]);
SOC = rx_frame.data.u8[6];
SOH = rx_frame.data.u8[7];
break;
case 0x4220:
case 0x4221:
charge_cutoff_voltage = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]);
discharge_cutoff_voltage = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]);
max_charge_current = (((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]) * 0.1) - 3000;
max_discharge_current = (((rx_frame.data.u8[7] << 8) | rx_frame.data.u8[6]) * 0.1) - 3000;
break;
case 0x4230:
case 0x4231:
cellvoltage_max_mV = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]);
cellvoltage_min_mV = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]);
break;
case 0x4240:
case 0x4241:
celltemperature_max_dC = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) - 1000;
celltemperature_min_dC = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]) - 1000;
break;
case 0x4250:
case 0x4251:
//Byte0 Basic Status
//Byte1-2 Cycle Period
//Byte3 Error
//Byte4-5 Alarm
//Byte6-7 Protection
break;
case 0x4260:
case 0x4261:
//Byte0-1 Module Max Voltage
//Byte2-3 Module Min Voltage
//Byte4-5 Module Max. Voltage Number
//Byte6-7 Module Min. Voltage Number
break;
case 0x4270:
case 0x4271:
//Byte0-1 Module Max. Temperature
//Byte2-3 Module Min. Temperature
//Byte4-5 Module Max. Temperature Number
//Byte6-7 Module Min. Temperature Number
break;
case 0x4280:
case 0x4281:
charge_forbidden = rx_frame.data.u8[0];
discharge_forbidden = rx_frame.data.u8[1];
break;
case 0x4290:
case 0x4291:
break;
default:
break;
}
}
void send_can_battery() {
unsigned long currentMillis = millis();
// Send 1s CAN Message
if (currentMillis - previousMillis1000 >= INTERVAL_1_S) {
previousMillis1000 = currentMillis;
ESP32Can.CANWriteFrame(&PYLON_3010); // Heartbeat
ESP32Can.CANWriteFrame(&PYLON_4200); // Ensemble OR System equipment info, depends on frame0
ESP32Can.CANWriteFrame(&PYLON_8200); // Control device quit sleep status
ESP32Can.CANWriteFrame(&PYLON_8210); // Charge command
if (ensemble_info_ack) {
PYLON_4200.data.u8[0] = 0x00; //Request system equipment info
}
}
}
void setup_battery(void) { // Performs one time setup at startup
#ifdef DEBUG_VIA_USB
Serial.println("Pylon battery selected");
#endif
datalayer.battery.info.max_design_voltage_dV = 4040; // 404.0V, charging over this is not possible
datalayer.battery.info.min_design_voltage_dV = 3100; // 310.0V, under this, discharging further is disabled
}
#endif

View file

@ -0,0 +1,11 @@
#ifndef PYLON_BATTERY_H
#define PYLON_BATTERY_H
#include <Arduino.h>
#include "../include.h"
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
#define BATTERY_SELECTED
void setup_battery(void);
#endif