Skip to content

Commit

Permalink
Initial implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
jamiejones85 committed Mar 26, 2023
0 parents commit 6a54c44
Show file tree
Hide file tree
Showing 26 changed files with 3,338 additions and 0 deletions.
621 changes: 621 additions & 0 deletions ESP32-Chademo/Chademo.cpp

Large diffs are not rendered by default.

145 changes: 145 additions & 0 deletions ESP32-Chademo/Chademo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
#ifndef CHADEMO_H_
#define CHADEMO_H_
#include <Arduino.h>
#include "Globals.h"
#include <ACAN_ESP32.h>

enum CHADEMOSTATE
{
STARTUP,
SEND_INITIAL_PARAMS,
WAIT_FOR_EVSE_PARAMS,
SET_CHARGE_BEGIN,
WAIT_FOR_BEGIN_CONFIRMATION,
CLOSE_CONTACTORS,
WAIT_FOR_PRECHARGE,
RUNNING,
CEASE_CURRENT,
WAIT_FOR_ZERO_CURRENT,
OPEN_CONTACTOR,
FAULTED,
STOPPED,
LIMBO
};

typedef struct
{
uint8_t supportWeldCheck;
uint16_t availVoltage;
uint8_t availCurrent;
uint16_t thresholdVoltage; //evse calculates this. It is the voltage at which it'll abort charging to save the battery pack in case we asked for something stupid
} EVSE_PARAMS;

typedef struct
{
uint16_t presentVoltage;
uint8_t presentCurrent;
uint8_t status;
uint16_t remainingChargeSeconds;
} EVSE_STATUS;

typedef struct
{
uint16_t targetVoltage; //what voltage we want the EVSE to put out
uint8_t targetCurrent; //what current we'd like the EVSE to provide
uint8_t remainingKWH; //report # of KWh in the battery pack (charge level)
uint8_t battOverVolt : 1; //we signal that battery or a cell is too high of a voltage
uint8_t battUnderVolt : 1; //we signal that battery is too low
uint8_t currDeviation : 1; //we signal that measured current is not the same as EVSE is reporting
uint8_t battOverTemp : 1; //we signal that battery is too hot
uint8_t voltDeviation : 1; //we signal that we measure a different voltage than EVSE reports
uint8_t chargingEnabled : 1; //ask EVSE to enable charging
uint8_t notParked : 1; //advise EVSE that we're not in park.
uint8_t chargingFault : 1; //signal EVSE that we found a fault
uint8_t contactorOpen : 1; //tell EVSE whether we've closed the charging contactor
uint8_t stopRequest : 1; //request that the charger cease operation before we really get going
} CARSIDE_STATUS;

//The IDs for chademo comm - both carside and EVSE side so we know what to listen for
//as well.
#define CARSIDE_BATT_ID 0x100
#define CARSIDE_CHARGETIME_ID 0x101
#define CARSIDE_CONTROL_ID 0x102

#define EVSE_PARAMS_ID 0x108
#define EVSE_STATUS_ID 0x109

#define CARSIDE_FAULT_OVERV 1 //over voltage
#define CARSIDE_FAULT_UNDERV 2 //Under voltage
#define CARSIDE_FAULT_CURR 4 //current mismatch
#define CARSIDE_FAULT_OVERT 8 //over temperature
#define CARSIDE_FAULT_VOLTM 16 //voltage mismatch

#define CARSIDE_STATUS_CHARGE 1 //charging enabled
#define CARSIDE_STATUS_NOTPARK 2 //shifter not in safe state
#define CARSIDE_STATUS_MALFUN 4 //vehicle did something dumb
#define CARSIDE_STATUS_CONTOP 8 //main contactor open
#define CARSIDE_STATUS_CHSTOP 16 //charger stop before even charging

#define EVSE_STATUS_CHARGE 1 //charger is active
#define EVSE_STATUS_ERR 2 //something went wrong
#define EVSE_STATUS_CONNLOCK 4 //connector is currently locked
#define EVSE_STATUS_INCOMPAT 8 //parameters between vehicle and charger not compatible
#define EVSE_STATUS_BATTERR 16 //something wrong with battery?!
#define EVSE_STATUS_STOPPED 32 //charger is stopped

class CHADEMO
{
public:
CHADEMO();
void setDelayedState(int newstate, uint16_t delayTime);
CHADEMOSTATE getState();
EVSE_PARAMS getEVSEParams();
EVSE_STATUS getEVSEStatus();

void setTargetAmperage(uint8_t t_amp);
void setTargetVoltage(uint16_t t_volt);
void loop();
void doProcessing();
void handleCANFrame(CANMessage &frame);
void setChargingFault();
void setBattOverTemp();
void setStateOfCharge(uint8_t stateofcharge);

//these need to be accessed quickly in tight spots so they're public in an attempt at efficiency
uint8_t bChademoMode; //accessed but not modified in ISR so it should be OK non-volatile
uint8_t bChademoSendRequests; //should we be sending periodic status updates?
volatile uint8_t bChademoRequest; //is it time to send one of those updates?

protected:
private:
uint8_t bStartedCharge; //we have started a charge since the plug was inserted. Prevents attempts to restart charging if it stopped previously
uint8_t bChademo10Protocol; //can we use 1.0 protocol?
//target values are what we send with periodic frames and can be changed.
uint8_t askingAmps; //how many amps to ask for. Trends toward targetAmperage
uint8_t bListenEVSEStatus; //should we pay attention to stop requests and such yet?
uint8_t bDoMismatchChecks; //should we be checking for voltage and current mismatches?
uint8_t bConnectorLocked; //is the EVSE saying the connector is locked
uint8_t vMismatchCount; //count # of consecutive voltage mismatches. Don't trigger until we get enough
uint8_t cMismatchCount; //same but for current
uint8_t vCapCount; //# of EVSE voltage capacity checks that have failed in a row.
uint8_t vOverFault; //over volt fault counter like above.
uint8_t faultCount; //force faults to count up a bit before we actually fault.
uint32_t mismatchStart;
const uint16_t mismatchDelay = 10000; //don't start mismatch checks for 10 seconds
uint32_t stateMilli;
uint16_t stateDelay;
uint32_t insertionTime;
uint32_t lastCommTime;
const uint16_t lastCommTimeout = 1000; //allow up to 1 second of comm fault before getting angry
uint8_t soc; //BMS reported SoC

CHADEMOSTATE chademoState;
CHADEMOSTATE stateHolder;
EVSE_PARAMS evse_params;
EVSE_STATUS evse_status;
CARSIDE_STATUS carStatus;

void sendCANStatus();
void sendCANBattSpecs();
void sendCANChargingTime();
};

extern CHADEMO chademo;

#endif
151 changes: 151 additions & 0 deletions ESP32-Chademo/ChademoWebServer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
#include "ChademoWebServer.h"
#include <SPIFFS.h>
#include <EEPROM.h>

AsyncWebServer server(80);
AsyncWebSocket ws("/ws");
AsyncEventSource events("/events");

ChademoWebServer::ChademoWebServer(EESettings& s) : settings{ s } {
}

AsyncWebSocket& ChademoWebServer::getWebSocket() {
return ws;
}
void ChademoWebServer::execute() {
ws.cleanupClients();
}

void ChademoWebServer::broadcast(const char * message) {
ws.printfAll(message);
}

void ChademoWebServer::setup()
{
// ws.onEvent(onWsEvent);
server.addHandler(&ws);

server.on("/wifi", [&] (AsyncWebServerRequest *request) {
bool updated = true;
if(request->hasParam("apSSID", true) && request->hasParam("apPW", true))
{
WiFi.softAP(request->arg("apSSID").c_str(), request->arg("apPW").c_str());
}
else if(request->hasParam("staSSID", true) && request->hasParam("staPW", true))
{
WiFi.mode(WIFI_AP_STA);
WiFi.begin(request->arg("staSSID").c_str(), request->arg("staPW").c_str());
}
else
{
File file = SPIFFS.open("/wifi.html", "r");
String html = file.readString();
file.close();
html.replace("%staSSID%", WiFi.SSID());
html.replace("%apSSID%", WiFi.softAPSSID());
html.replace("%staIP%", WiFi.localIP().toString());
request->send(200, "text/html", html);
updated = false;
}

if (updated)
{
request->send(SPIFFS, "/wifi-updated.html");
}
});

server.on("/settings", HTTP_GET, [&] (AsyncWebServerRequest *request) {
AsyncResponseStream *response = request->beginResponseStream("application/json");
DynamicJsonDocument json(2048);
toJson(settings, json);
serializeJson(json, *response);
request->send(response);
});

server.on(
"/settings",
HTTP_POST,
[](AsyncWebServerRequest * request){},
NULL,
[&](AsyncWebServerRequest * request, uint8_t *data, size_t len, size_t index, size_t total) {
Serial.println("settings POST");
const size_t JSON_DOC_SIZE = 1024U;
DynamicJsonDocument jsonDoc(JSON_DOC_SIZE);

if (DeserializationError::Ok == deserializeJson(jsonDoc, (const char*)data))
{
JsonObject obj = jsonDoc.as<JsonObject>();
fromJson(settings, obj);
EEPROM.put(0, settings);
EEPROM.commit();
request->send(200, "application/json", "success");

} else {
request->send(200, "application/json", "DeserializationError");
}
});

server.on("/edit",
HTTP_POST,
[](AsyncWebServerRequest * request){},
[&](AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) {
if (!index) {
// open the file on first call and store the file handle in the request object
request->_tempFile = SPIFFS.open("/" + filename, "w");

}

if (len) {
// stream the incoming chunk to the opened file
request->_tempFile.write(data, len);
}

if (final) {
// close the file handle as the upload is now done
request->_tempFile.close();

if (filename.substring(filename.lastIndexOf(".")).equals("bin")) {
Serial.println("Firmware uploaded, restarting");
request->send(200, "application/json", "restarting");
ESP.restart();
}
request->redirect("/");
}
}

);

server.serveStatic("/", SPIFFS, "/").setDefaultFile("index.html");


// Start server
Serial.println("Starting Web Server");

server.begin();
}

void ChademoWebServer::toJson(EESettings& settings, DynamicJsonDocument &root) {
root["useBms"] = settings.useBms;
root["ampHours"] = settings.ampHours;
root["packSizeKWH"] = settings.packSizeKWH;
root["maxChargeVoltage"] = settings.maxChargeVoltage;
root["targetChargeVoltage"] = settings.targetChargeVoltage;
root["maxChargeAmperage"] = settings.maxChargeAmperage;
root["minChargeAmperage"] = settings.minChargeAmperage;
root["capacity"] = settings.capacity;
root["debuggingLevel"] = settings.debuggingLevel;
}

void ChademoWebServer::fromJson(EESettings& settings, JsonObject &doc) {

settings.useBms = doc["useBms"];
settings.ampHours = doc["ampHours"];
settings.packSizeKWH = doc["packSizeKWH"];
settings.maxChargeVoltage = doc["maxChargeVoltage"];
settings.targetChargeVoltage = doc["targetChargeVoltage"];
settings.maxChargeAmperage = doc["maxChargeAmperage"];
settings.minChargeAmperage = doc["minChargeAmperage"];
settings.capacity = doc["capacity"];
settings.debuggingLevel = doc["debuggingLevel"];

}
21 changes: 21 additions & 0 deletions ESP32-Chademo/ChademoWebServer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ifndef CHADEMO_WEB_SERVER_H
#define CHADEMO_WEB_SERVER_H
#include <Arduino.h>
#include "Globals.h"
#include "ESPAsyncWebServer.h"
#include "ArduinoJson.h"

class ChademoWebServer
{
public:
ChademoWebServer(EESettings& settings);
void setup();
void execute();
void broadcast(const char * message);
AsyncWebSocket& getWebSocket();
private:
void toJson(EESettings& settings, DynamicJsonDocument &root);
void fromJson(EESettings& settings, JsonObject &doc);
EESettings& settings;
};
#endif
Loading

0 comments on commit 6a54c44

Please sign in to comment.