Skip to content

Commit 18f1470

Browse files
committed
Merge remote-tracking branch 'upstream/master'
2 parents 5db64cc + 11824ee commit 18f1470

25 files changed

+650
-147
lines changed

readme.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
55
- *For the older WiFi V2.x ESP8266 version (pre June 2020), see the [v2 firmware repository](https://github.com/openevse/ESP8266_WiFi_v2.x/)*
66

7+
- **For latest API documentation see the new [Spotlight.io OpenEVSE WiFi documentation page](https://openevse.stoplight.io/docs/openevse-wifi-v4/ZG9jOjQyMjE5ODI-open-evse-wi-fi-esp-32-gateway-v4)**
78

89
![main](docs/main2.png)
910

@@ -104,6 +105,8 @@ The WiFi gateway uses an **ESP32** which communicates with the OpenEVSE controll
104105

105106
# Hardware
106107

108+
## WiFi Hardware
109+
107110
Most ESP32 boards can be used (see platfromio.ini for full list of supported boards), however the boards which is best supported is the OpenEVSE WiFi V1.
108111

109112
**Be sure to correctly identify your WiFi hardware before updating the firmware**
@@ -115,6 +118,13 @@ Most ESP32 boards can be used (see platfromio.ini for full list of supported boa
115118
- OpenEVSE V1 - designed for V4.x firmware
116119
- [Olimex ESP32 Gateway (Wired Ethernet)](docs/wired-ethernet.md) - can run V3.x and V4.x firmware
117120

121+
### Temperature sensors
122+
123+
- Temp 1 RTC temperature sensor (old LCD module with RTC)
124+
- Temp 2 MCP9808 temperature sensor (new LCD module )
125+
- Temp 3 IR sensor (not used)
126+
- Temp 4 is the sensor on the OpenEVSE V1 module (not currently used for throttling)
127+
118128
## WiFi Setup
119129

120130
On first boot, OpenEVSE should broadcast a WiFi access point (AP) `OpenEVSE_XXXX`. Connect your browser device to this AP (default password: `openevse`) and the [captive portal](https://en.wikipedia.org/wiki/Captive_portal) should forward you to the log-in page. If this does not happen, navigate to [http://openevse](http://openevse), [http://openevse.local](http://openevse.local) or [http://192.168.4.1](http://192.168.4.1)
@@ -235,6 +245,8 @@ MQTT can also be used to control the OpenEVSE, see RAPI MQTT below.
235245

236246
### RAPI API (Not Recommended)
237247

248+
**For latest API documentation see the new [Spotlight.io OpenEVSE WiFi documentation page](https://openevse.stoplight.io/docs/openevse-wifi-v4/ZG9jOjQyMjE5ODI-open-evse-wi-fi-esp-32-gateway-v4)**
249+
238250
RAPI commands can be used to control and check the status of all OpenEVSE functions. RAPI commands can be issued via the direct serial, web-interface, HTTP and MQTT. We recommend using RAPI over MQTT.
239251

240252
**IMPORTANT: It is no longer recommended to use RAPI API if EVSE also had a WiFi module fitted, since use of the RAPI API will conflict with the WiFi module, instead the HTTP API should be used to control the WiFi module instead of the controller via RAPI. User RAPI API will be disabled in future releases**

src/emonesp.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,16 @@
8585
#define DEFAULT_TIME_ZONE "Europe/London|GMT0BST,M3.5.0/1,M10.5.0"
8686
#endif
8787

88-
#ifndef DEFAULT_VOLTAGE
89-
#define DEFAULT_VOLTAGE 240
88+
#ifndef VOLTAGE_DEFAULT
89+
#define VOLTAGE_DEFAULT 240
90+
#endif
91+
92+
#ifndef VOLTAGE_MINIMUM
93+
#define VOLTAGE_MINIMUM 60.0
94+
#endif
95+
96+
#ifndef VOLTAGE_MAXIMUM
97+
#define VOLTAGE_MAXIMUM 300.0
9098
#endif
9199

92100
#ifdef NO_SENSOR_SCALING

src/event_log.cpp

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
#if defined(ENABLE_DEBUG) && !defined(ENABLE_DEBUG_EVENT_LOG)
2+
#undef ENABLE_DEBUG
3+
#endif
4+
5+
#include <LITTLEFS.h>
6+
#include <ArduinoJson.h>
7+
8+
#include "debug.h"
9+
#include "emonesp.h"
10+
#include "event_log.h"
11+
12+
EventLog::EventLog() :
13+
_min_log_index(0),
14+
_max_log_index(0)
15+
{
16+
}
17+
18+
EventLog::~EventLog()
19+
{
20+
}
21+
22+
String EventLog::filenameFromIndex(uint32_t index)
23+
{
24+
String filename = EVENTLOG_BASE_DIRECTORY;
25+
filename += "/" + String(index);
26+
return filename;
27+
}
28+
29+
uint32_t EventLog::indexFromFilename(String &path)
30+
{
31+
DBUGVAR(path);
32+
33+
int lastSeparator = path.lastIndexOf('/');
34+
String name = lastSeparator >= 0 ? path.substring(lastSeparator + 1) : path;
35+
DBUGVAR(name);
36+
37+
return atol(name.c_str());
38+
}
39+
40+
// Scan our base directory for existing log files and workout the min/max index files
41+
void EventLog::begin()
42+
{
43+
File eventLog = LittleFS.open(EVENTLOG_BASE_DIRECTORY);
44+
if(eventLog && eventLog.isDirectory())
45+
{
46+
_min_log_index = UINT32_MAX;
47+
_max_log_index = 0;
48+
49+
File file = eventLog.openNextFile();
50+
while(file)
51+
{
52+
if(!file.isDirectory())
53+
{
54+
String name = file.name();
55+
long chunk = indexFromFilename(name);
56+
DBUGVAR(chunk);
57+
if(chunk > _max_log_index) {
58+
_max_log_index = chunk;
59+
DBUGVAR(_max_log_index);
60+
}
61+
if(chunk < _min_log_index) {
62+
_min_log_index = chunk;
63+
DBUGVAR(_min_log_index);
64+
}
65+
}
66+
67+
file = eventLog.openNextFile();
68+
}
69+
70+
if(UINT32_MAX == _min_log_index) {
71+
_min_log_index = 0;
72+
}
73+
}
74+
else
75+
{
76+
LittleFS.mkdir(EVENTLOG_BASE_DIRECTORY);
77+
}
78+
}
79+
80+
void EventLog::log(EventType type, EvseState managerState, uint8_t evseState, uint32_t evseFlags, uint32_t pilot, double energy, uint32_t elapsed, double temperature, double temperatureMax, uint8_t divertMode)
81+
{
82+
time_t now = time(NULL);
83+
struct tm timeinfo;
84+
gmtime_r(&now, &timeinfo);
85+
86+
// Check if we have a reasonable time, don't want to be logging events from 1970
87+
if(timeinfo.tm_year < (2021 - 1900)) {
88+
return;
89+
}
90+
91+
String eventFilename = filenameFromIndex(_max_log_index);
92+
File eventFile = LittleFS.open(eventFilename, FILE_APPEND);
93+
if(eventFile && eventFile.size() > EVENTLOG_ROTATE_SIZE)
94+
{
95+
DBUGLN("Rotating log file");
96+
eventFile.close();
97+
98+
_max_log_index ++;
99+
eventFilename = filenameFromIndex(_max_log_index);
100+
eventFile = LittleFS.open(eventFilename, FILE_APPEND);
101+
102+
// _max_log_index is inclusive, so we need to increment it here
103+
while((_max_log_index + 1) - _min_log_index > EVENTLOG_MAX_ROTATE_COUNT) {
104+
LittleFS.remove(filenameFromIndex(_min_log_index));
105+
_min_log_index++;
106+
}
107+
}
108+
109+
if(eventFile)
110+
{
111+
StaticJsonDocument<256> line;
112+
char output[80];
113+
strftime(output, 80, "%FT%TZ", &timeinfo);
114+
115+
line["t"] = output;
116+
line["ty"] = type.toInt();
117+
line["ms"] = managerState.toString();
118+
line["es"] = evseState;
119+
line["ef"] = evseFlags;
120+
line["p"] = pilot;
121+
line["e"] = energy;
122+
line["el"] = elapsed;
123+
line["tp"] = temperature;
124+
line["tm"] = temperatureMax;
125+
line["dm"] = divertMode;
126+
127+
serializeJson(line, eventFile);
128+
eventFile.println("");
129+
130+
#ifdef ENABLE_DEBUG
131+
serializeJson(line, DEBUG_PORT);
132+
DBUGLN("");
133+
#endif
134+
135+
eventFile.close();
136+
}
137+
}
138+
139+
void EventLog::enumerate(uint32_t index, std::function<void(String time, EventType type, EvseState managerState, uint8_t evseState, uint32_t evseFlags, uint32_t pilot, double energy, uint32_t elapsed, double temperature, double temperatureMax, uint8_t divertMode)> callback)
140+
{
141+
String filename = filenameFromIndex(index);
142+
File eventFile = LittleFS.open(filename);
143+
if(eventFile)
144+
{
145+
while(eventFile.available())
146+
{
147+
String line = eventFile.readStringUntil('\n');
148+
if(line.length() > 0)
149+
{
150+
StaticJsonDocument<256> json;
151+
DeserializationError error = deserializeJson(json, line);
152+
if(error)
153+
{
154+
DBUGF("Error parsing line: %s", error.c_str());
155+
break;
156+
}
157+
158+
String time = json["t"];
159+
EventType type = EventType::Information;
160+
type.fromInt(json["ty"]);
161+
EvseState managerState = EvseState::None;
162+
managerState.fromString(json["ms"]);
163+
uint8_t evseState = json["es"];
164+
uint32_t evseFlags = json["ef"];
165+
uint32_t pilot = json["p"];
166+
double energy = json["e"];
167+
uint32_t elapsed = json["el"];
168+
double temperature = json["tp"];
169+
double temperatureMax = json["tm"];
170+
uint8_t divertMode = json["dm"];
171+
172+
callback(time, type, managerState, evseState, evseFlags, pilot, energy, elapsed, temperature, temperatureMax, divertMode);
173+
}
174+
}
175+
eventFile.close();
176+
}
177+
}

src/event_log.h

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
#ifndef __EVENT_LOG_H
2+
#define __EVENT_LOG_H
3+
4+
#include <Arduino.h>
5+
#include "evse_state.h"
6+
7+
#ifndef EVENTLOG_ROTATE_SIZE
8+
#define EVENTLOG_ROTATE_SIZE 1024
9+
#endif
10+
11+
#ifndef EVENTLOG_MAX_ROTATE_COUNT
12+
#define EVENTLOG_MAX_ROTATE_COUNT 10
13+
#endif
14+
15+
#ifndef EVENTLOG_BASE_DIRECTORY
16+
#define EVENTLOG_BASE_DIRECTORY "/eventlog"
17+
#endif
18+
19+
class EventType
20+
{
21+
public:
22+
enum Value : uint8_t
23+
{
24+
Information,
25+
Notification,
26+
Warning
27+
};
28+
29+
EventType() = default;
30+
constexpr EventType(Value value) : _value(value) { }
31+
32+
const char *toString()
33+
{
34+
return EventType::Information == _value ? "information" :
35+
EventType::Notification == _value ? "notification" :
36+
EventType::Warning == _value ? "warning" :
37+
"unknown";
38+
}
39+
40+
uint8_t toInt() {
41+
return _value;
42+
}
43+
bool fromInt(uint8_t value)
44+
{
45+
if (value <= Value::Warning) {
46+
_value = (EventType::Value)value;
47+
return true;
48+
}
49+
50+
return false;
51+
}
52+
53+
operator Value() const { return _value; }
54+
explicit operator bool() = delete; // Prevent usage: if(state)
55+
EventType operator= (const Value val) {
56+
_value = val;
57+
return *this;
58+
}
59+
60+
private:
61+
Value _value;
62+
};
63+
64+
class EventLog
65+
{
66+
private:
67+
uint32_t _min_log_index;
68+
uint32_t _max_log_index;
69+
70+
String filenameFromIndex(uint32_t index);
71+
uint32_t indexFromFilename(String &filename);
72+
73+
public:
74+
EventLog();
75+
~EventLog();
76+
77+
void begin();
78+
79+
uint32_t getMinIndex() {
80+
return _min_log_index;
81+
}
82+
83+
uint32_t getMaxIndex() {
84+
return _max_log_index;
85+
}
86+
87+
void log(EventType type, EvseState managerState, uint8_t evseState, uint32_t evseFlags, uint32_t pilot, double energy, uint32_t elapsed, double temperature, double temperatureMax, uint8_t divertMode);
88+
void enumerate(uint32_t index, std::function<void(String time, EventType type, EvseState managerState, uint8_t evseState, uint32_t evseFlags, uint32_t pilot, double energy, uint32_t elapsed, double temperature, double temperatureMax, uint8_t divertMode)> callback);
89+
};
90+
91+
92+
#endif // !__EVENT_LOG_H

src/evse_man.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
#include "evse_man.h"
88
#include "debug.h"
99

10+
#include "event_log.h"
11+
#include "divert.h"
12+
1013
static EvseProperties nullProperties;
1114

1215
EvseProperties::EvseProperties() :
@@ -129,10 +132,11 @@ void EvseManager::Claim::release()
129132
_client = EvseClient_NULL;
130133
}
131134

132-
EvseManager::EvseManager(Stream &port) :
135+
EvseManager::EvseManager(Stream &port, EventLog &eventLog) :
133136
MicroTasks::Task(),
134137
_sender(&port),
135138
_monitor(OpenEVSE),
139+
_eventLog(eventLog),
136140
_clients(),
137141
_evseStateListener(this),
138142
_sessionCompleteListener(this),
@@ -339,6 +343,17 @@ unsigned long EvseManager::loop(MicroTasks::WakeReason reason)
339343
_evaluateTargetState = true;
340344
_waitingForEvent--;
341345
}
346+
347+
_eventLog.log(_monitor.isError() ? EventType::Warning : EventType::Information,
348+
getState(),
349+
_monitor.getEvseState(),
350+
_monitor.getFlags(),
351+
_monitor.getPilot(),
352+
_monitor.getSessionEnergy(),
353+
_monitor.getSessionElapsed(),
354+
_monitor.getTemperature(EVSE_MONITOR_TEMP_MONITOR),
355+
_monitor.getTemperature(EVSE_MONITOR_TEMP_MAX),
356+
divertmode);
342357
}
343358

344359
DBUGVAR(_sessionCompleteListener.IsTriggered());
@@ -492,7 +507,7 @@ uint8_t EvseManager::getStateColour()
492507
return OPENEVSE_LCD_YELLOW;
493508

494509
case OPENEVSE_STATE_CHARGING:
495-
// TODO: Colour should also take into account the tempurature, >60 YELLOW
510+
// TODO: Colour should also take into account the temperature, >60 YELLOW
496511
return OPENEVSE_LCD_TEAL;
497512

498513
case OPENEVSE_STATE_VENT_REQUIRED:

0 commit comments

Comments
 (0)