Commit e8460aba authored by Eric Duminil's avatar Eric Duminil
Browse files

Merge branch 'refactor/no_strings' into develop

parents 36bd5ec7 5b42b3c0
...@@ -87,8 +87,12 @@ void setup() { ...@@ -87,8 +87,12 @@ void setup() {
Serial.print(F("Board : ")); Serial.print(F("Board : "));
Serial.println(ampel.board); Serial.println(ampel.board);
#ifdef AMPEL_CSV
csv_writer::initialize(ampel.sensorId);
#endif
#ifdef AMPEL_WIFI #ifdef AMPEL_WIFI
WiFiConnect(ampel.sensorId); wifi::connect(ampel.sensorId);
Serial.print(F("WiFi - Status: ")); Serial.print(F("WiFi - Status: "));
Serial.println(WiFi.status()); Serial.println(WiFi.status());
...@@ -100,7 +104,7 @@ void setup() { ...@@ -100,7 +104,7 @@ void setup() {
ntp::initialize(); ntp::initialize();
if (MDNS.begin(ampel.sensorId.c_str())) { // Start the mDNS responder for SENSOR_ID.local if (MDNS.begin(ampel.sensorId)) { // Start the mDNS responder for SENSOR_ID.local
MDNS.addService("http", "tcp", 80); MDNS.addService("http", "tcp", 80);
Serial.println(F("mDNS responder started")); Serial.println(F("mDNS responder started"));
} else { } else {
...@@ -108,15 +112,11 @@ void setup() { ...@@ -108,15 +112,11 @@ void setup() {
} }
# ifdef AMPEL_MQTT # ifdef AMPEL_MQTT
mqtt::initialize("CO2sensors/" + ampel.sensorId); mqtt::initialize(ampel.sensorId);
# endif # endif
} }
#endif #endif
#ifdef AMPEL_CSV
csv_writer::initialize();
#endif
#if defined(AMPEL_LORAWAN) && defined(ESP32) #if defined(AMPEL_LORAWAN) && defined(ESP32)
lorawan::initialize(); lorawan::initialize();
#endif #endif
......
...@@ -22,7 +22,7 @@ namespace sensor { ...@@ -22,7 +22,7 @@ namespace sensor {
extern uint16_t co2; extern uint16_t co2;
extern float temperature; extern float temperature;
extern float humidity; extern float humidity;
extern char timestamp[23]; extern char timestamp[];
void initialize(); void initialize();
bool processData(); bool processData();
......
...@@ -78,13 +78,15 @@ namespace csv_writer { ...@@ -78,13 +78,15 @@ namespace csv_writer {
} }
#endif #endif
const String filename = "/" + ampel.sensorId + ".csv"; char filename[15]; // "/ESPxxxxxx.csv\0"
int getAvailableSpace() { int getAvailableSpace() {
return getTotalSpace() - getUsedSpace(); return getTotalSpace() - getUsedSpace();
} }
void initialize() { void initialize(const char *sensorId) {
snprintf(filename, sizeof(filename), "/%s.csv", sensorId);
Serial.print(F("Initializing FS...")); Serial.print(F("Initializing FS..."));
if (mountFS()) { if (mountFS()) {
Serial.println(F("done.")); Serial.println(F("done."));
...@@ -187,7 +189,7 @@ namespace csv_writer { ...@@ -187,7 +189,7 @@ namespace csv_writer {
} }
csv_file.close(); csv_file.close();
} }
Serial.println(F("################")); Serial.println(F("######################"));
} }
void formatFilesystem() { void formatFilesystem() {
......
...@@ -20,11 +20,11 @@ namespace config { ...@@ -20,11 +20,11 @@ namespace config {
extern uint16_t csv_interval; // [s] extern uint16_t csv_interval; // [s]
} }
namespace csv_writer { namespace csv_writer {
extern char last_successful_write[23]; extern char last_successful_write[];
void initialize(); void initialize(const char *sensorId);
void logIfTimeHasCome(const char* timestamp, const int16_t &co2, const float &temperature, const float &humidity); void logIfTimeHasCome(const char *timestamp, const int16_t &co2, const float &temperature, const float &humidity);
int getAvailableSpace(); int getAvailableSpace();
extern const String filename; extern char filename[];
void setCSVinterval(int32_t csv_interval); void setCSVinterval(int32_t csv_interval);
void showCSVContent(); void showCSVContent();
......
...@@ -23,13 +23,13 @@ namespace mqtt { ...@@ -23,13 +23,13 @@ namespace mqtt {
unsigned long last_failed_at = 0; unsigned long last_failed_at = 0;
bool connected = false; bool connected = false;
String publish_topic; char publish_topic[21]; // e.g. "CO2sensors/ESPxxxxxx\0"
const char *json_sensor_format; const char *json_sensor_format;
char last_successful_publish[23] = ""; char last_successful_publish[23] = "";
void initialize(String &topic) { void initialize(const char *sensorId) {
json_sensor_format = PSTR("{\"time\":\"%s\", \"co2\":%d, \"temp\":%.1f, \"rh\":%.1f}"); json_sensor_format = PSTR("{\"time\":\"%s\", \"co2\":%d, \"temp\":%.1f, \"rh\":%.1f}");
publish_topic = topic; snprintf(publish_topic, sizeof(publish_topic), "CO2sensors/%s", sensorId);
#if defined(ESP8266) #if defined(ESP8266)
espClient.setInsecure(); // Sorry, we don't want to flash the sensors every 3 months. espClient.setInsecure(); // Sorry, we don't want to flash the sensors every 3 months.
#endif #endif
...@@ -49,7 +49,7 @@ namespace mqtt { ...@@ -49,7 +49,7 @@ namespace mqtt {
char payload[75]; // Should be enough for json... char payload[75]; // Should be enough for json...
snprintf(payload, sizeof(payload), json_sensor_format, timestamp, co2, temperature, humidity); snprintf(payload, sizeof(payload), json_sensor_format, timestamp, co2, temperature, humidity);
// Topic is the same as clientID. e.g. 'CO2sensors/ESP3d03da' // Topic is the same as clientID. e.g. 'CO2sensors/ESP3d03da'
if (mqttClient.publish(publish_topic.c_str(), payload)) { if (mqttClient.publish(publish_topic, payload)) {
Serial.println(F("OK")); Serial.println(F("OK"));
ntp::getLocalTime(last_successful_publish); ntp::getLocalTime(last_successful_publish);
} else { } else {
...@@ -96,7 +96,7 @@ namespace mqtt { ...@@ -96,7 +96,7 @@ namespace mqtt {
led_effects::onBoardLEDOn(); led_effects::onBoardLEDOn();
// Wait for connection, at most 15s (default) // Wait for connection, at most 15s (default)
mqttClient.connect(publish_topic.c_str(), config::mqtt_user, config::mqtt_password); mqttClient.connect(publish_topic, config::mqtt_user, config::mqtt_password);
led_effects::onBoardLEDOff(); led_effects::onBoardLEDOff();
connected = mqttClient.connected(); connected = mqttClient.connected();
...@@ -104,7 +104,7 @@ namespace mqtt { ...@@ -104,7 +104,7 @@ namespace mqtt {
if (connected) { if (connected) {
if (config::allow_mqtt_commands) { if (config::allow_mqtt_commands) {
char control_topic[60]; // Should be enough for "CO2sensors/ESPd03cc5/control" char control_topic[60]; // Should be enough for "CO2sensors/ESPd03cc5/control"
snprintf(control_topic, sizeof(control_topic), "%s/control", publish_topic.c_str()); snprintf(control_topic, sizeof(control_topic), "%s/control", publish_topic);
mqttClient.subscribe(control_topic); mqttClient.subscribe(control_topic);
mqttClient.setCallback(controlSensorCallback); mqttClient.setCallback(controlSensorCallback);
} }
...@@ -153,11 +153,11 @@ namespace mqtt { ...@@ -153,11 +153,11 @@ namespace mqtt {
// The sensor will send the info to "CO2sensors/ESP123456/info". // The sensor will send the info to "CO2sensors/ESP123456/info".
void sendInfoAboutLocalNetwork() { void sendInfoAboutLocalNetwork() {
char info_topic[60]; // Should be enough for "CO2sensors/ESP123456/info" char info_topic[60]; // Should be enough for "CO2sensors/ESP123456/info"
snprintf(info_topic, sizeof(info_topic), "%s/info", publish_topic.c_str()); snprintf(info_topic, sizeof(info_topic), "%s/info", publish_topic);
char payload[75]; // Should be enough for info json... char payload[75]; // Should be enough for info json...
const char *json_info_format = PSTR("{\"local_ip\":\"%s\", \"ssid\":\"%s\"}"); const char *json_info_format = PSTR("{\"local_ip\":\"%s\", \"ssid\":\"%s\"}");
snprintf(payload, sizeof(payload), json_info_format, WiFi.localIP().toString().c_str(), WiFi.SSID().c_str()); snprintf(payload, sizeof(payload), json_info_format, wifi::local_ip, WIFI_SSID);
mqttClient.publish(info_topic, payload); mqttClient.publish(info_topic, payload);
} }
......
...@@ -13,7 +13,7 @@ namespace config { ...@@ -13,7 +13,7 @@ namespace config {
namespace mqtt { namespace mqtt {
extern char last_successful_publish[]; extern char last_successful_publish[];
extern bool connected; extern bool connected;
void initialize(String &topic); void initialize(const char *sensorId);
void keepConnection(); void keepConnection();
void publishIfTimeHasCome(const char *timestamp, const int16_t &co2, const float &temp, const float &hum); void publishIfTimeHasCome(const char *timestamp, const int16_t &co2, const float &temp, const float &hum);
......
...@@ -13,20 +13,6 @@ const char *current_board = "ESP32"; ...@@ -13,20 +13,6 @@ const char *current_board = "ESP32";
const char *current_board = "UNKNOWN"; const char *current_board = "UNKNOWN";
#endif #endif
// Get last 3 bytes of ESP MAC (worldwide unique)
String macToID() {
uint8_t mac[6];
WiFi.macAddress(mac);
String result;
for (int i = 3; i < 6; i++) {
if (mac[i] < 16)
result += '0';
result += String(mac[i], HEX);
}
result.toLowerCase();
return result;
}
//NOTE: ESP32 sometimes couldn't access the NTP server, and every loop would take +1000ms //NOTE: ESP32 sometimes couldn't access the NTP server, and every loop would take +1000ms
// ifdefs could be used to define functions specific to ESP32, e.g. with configTime // ifdefs could be used to define functions specific to ESP32, e.g. with configTime
namespace ntp { namespace ntp {
...@@ -70,8 +56,18 @@ void Ampel::showFreeSpace() { ...@@ -70,8 +56,18 @@ void Ampel::showFreeSpace() {
Serial.println(F(" bytes.")); Serial.println(F(" bytes."));
} }
char sensorId[10]; // e.g "ESPxxxxxx\0"
char* getSensorId() {
uint8_t mac[6];
WiFi.macAddress(mac);
// Get last 3 bytes of ESP MAC (worldwide unique)
snprintf(sensorId, sizeof(sensorId), "ESP%02x%02x%02x", mac[3], mac[4], mac[5]);
return sensorId;
}
Ampel::Ampel() : Ampel::Ampel() :
board(current_board), sensorId("ESP" + macToID()), max_loop_duration(0) { board(current_board), sensorId(getSensorId()), max_loop_duration(0) {
sensor_console::defineIntCommand("set_time", ntp::setLocalTime, F(" 1618829570 (Sets time to the given UNIX time)")); sensor_console::defineIntCommand("set_time", ntp::setLocalTime, F(" 1618829570 (Sets time to the given UNIX time)"));
sensor_console::defineCommand("free", Ampel::showFreeSpace, F(" (Displays available heap space)")); sensor_console::defineCommand("free", Ampel::showFreeSpace, F(" (Displays available heap space)"));
sensor_console::defineCommand("reset", []() { sensor_console::defineCommand("reset", []() {
......
...@@ -37,7 +37,7 @@ private: ...@@ -37,7 +37,7 @@ private:
static void showFreeSpace(); static void showFreeSpace();
public: public:
const char *board; const char *board;
const String sensorId; const char *sensorId;
uint32_t max_loop_duration; uint32_t max_loop_duration;
Ampel(); Ampel();
}; };
......
...@@ -65,7 +65,7 @@ namespace web_server { ...@@ -65,7 +65,7 @@ namespace web_server {
#ifdef AMPEL_CSV #ifdef AMPEL_CSV
"<li class='pure-menu-item'><a href='#graph' class='pure-menu-link'>Graph</a></li>\n" "<li class='pure-menu-item'><a href='#graph' class='pure-menu-link'>Graph</a></li>\n"
"<li class='pure-menu-item'><a href='#log' class='pure-menu-link'>Log</a></li>\n" "<li class='pure-menu-item'><a href='#log' class='pure-menu-link'>Log</a></li>\n"
"<li class='pure-menu-item'><a href='./%s' class='pure-menu-link'>Download CSV</a></li>\n" "<li class='pure-menu-item'><a href='%s' class='pure-menu-link'>Download CSV</a></li>\n"
#endif #endif
"<li class='pure-menu-item' id='led'>&#11044;</li>\n" // LED "<li class='pure-menu-item' id='led'>&#11044;</li>\n" // LED
"</ul></div></div>\n" "</ul></div></div>\n"
...@@ -132,7 +132,7 @@ namespace web_server { ...@@ -132,7 +132,7 @@ namespace web_server {
#ifdef AMPEL_CSV #ifdef AMPEL_CSV
"<script>\n" "<script>\n"
"document.body.style.cursor = 'default';\n" "document.body.style.cursor = 'default';\n"
"fetch('./%s',{credentials:'include'})\n" "fetch('%s',{credentials:'include'})\n"
".then(response=>response.text())\n" ".then(response=>response.text())\n"
".then(csvText=>csvToTable(csvText))\n" ".then(csvText=>csvToTable(csvText))\n"
".then(htmlTable=>addLogTableToPage(htmlTable))\n" ".then(htmlTable=>addLogTableToPage(htmlTable))\n"
...@@ -177,7 +177,7 @@ namespace web_server { ...@@ -177,7 +177,7 @@ namespace web_server {
http.on("/", handleWebServerRoot); http.on("/", handleWebServerRoot);
http.on("/command", handleWebServerCommand); http.on("/command", handleWebServerCommand);
#ifdef AMPEL_CSV #ifdef AMPEL_CSV
http.on("/" + csv_writer::filename, handleWebServerCSV); http.on(csv_writer::filename, handleWebServerCSV); //NOTE: csv_writer should have been initialized first.
http.on("/delete_csv", HTTP_POST, handleDeleteCSV); http.on("/delete_csv", HTTP_POST, handleDeleteCSV);
#endif #endif
http.onNotFound(handlePageNotFound); http.onNotFound(handlePageNotFound);
...@@ -212,10 +212,9 @@ namespace web_server { ...@@ -212,10 +212,9 @@ namespace web_server {
char content[2000]; // Update if needed char content[2000]; // Update if needed
// INFO - Header size : 1767 - Body size : 1812 - Script size : 1909 // INFO - Header size : 1767 - Body size : 1812 - Script size : 1909
snprintf_P(content, sizeof(content), header_template, sensor::co2, ampel.sensorId.c_str(), snprintf_P(content, sizeof(content), header_template, sensor::co2, ampel.sensorId, wifi::local_ip
WiFi.localIP().toString().c_str()
#ifdef AMPEL_CSV #ifdef AMPEL_CSV
, csv_writer::filename.c_str() , csv_writer::filename
#endif #endif
); );
...@@ -225,7 +224,7 @@ namespace web_server { ...@@ -225,7 +224,7 @@ namespace web_server {
http.send_P(200, PSTR("text/html"), content); http.send_P(200, PSTR("text/html"), content);
// Body // Body
snprintf_P(content, sizeof(content), body_template, ampel.sensorId.c_str(), sensor::co2, sensor::temperature, snprintf_P(content, sizeof(content), body_template, ampel.sensorId, sensor::co2, sensor::temperature,
sensor::humidity, sensor::timestamp, config::measurement_timestep, sensor::humidity, sensor::timestamp, config::measurement_timestep,
#ifdef AMPEL_CSV #ifdef AMPEL_CSV
csv_writer::last_successful_write, config::csv_interval, csv_writer::getAvailableSpace() / 1024, csv_writer::last_successful_write, config::csv_interval, csv_writer::getAvailableSpace() / 1024,
...@@ -237,9 +236,8 @@ namespace web_server { ...@@ -237,9 +236,8 @@ namespace web_server {
lorawan::connected ? "Yes" : "No", LMIC_FREQUENCY_PLAN, lorawan::last_transmission, lorawan::connected ? "Yes" : "No", LMIC_FREQUENCY_PLAN, lorawan::last_transmission,
config::lorawan_sending_interval, config::lorawan_sending_interval,
#endif #endif
config::temperature_offset, config::auto_calibrate_sensor ? "Yes" : "No", ampel.sensorId.c_str(), config::temperature_offset, config::auto_calibrate_sensor ? "Yes" : "No", ampel.sensorId, ampel.sensorId,
ampel.sensorId.c_str(), WiFi.localIP().toString().c_str(), WiFi.localIP().toString().c_str(), wifi::local_ip, wifi::local_ip, get_free_heap_size(), ampel.max_loop_duration, ampel.board, dd, hh, mm, ss);
get_free_heap_size(), ampel.max_loop_duration, ampel.board, dd, hh, mm, ss);
Serial.print(F(" - Body size : ")); Serial.print(F(" - Body size : "));
http.sendContent(content); http.sendContent(content);
...@@ -248,7 +246,7 @@ namespace web_server { ...@@ -248,7 +246,7 @@ namespace web_server {
// Script // Script
snprintf_P(content, sizeof(content), script_template snprintf_P(content, sizeof(content), script_template
#ifdef AMPEL_CSV #ifdef AMPEL_CSV
, csv_writer::filename.c_str(), ampel.sensorId.c_str() , csv_writer::filename, ampel.sensorId
#endif #endif
); );
...@@ -264,7 +262,9 @@ namespace web_server { ...@@ -264,7 +262,9 @@ namespace web_server {
} }
if (FS_LIB.exists(csv_writer::filename)) { if (FS_LIB.exists(csv_writer::filename)) {
fs::File csv_file = FS_LIB.open(csv_writer::filename, "r"); fs::File csv_file = FS_LIB.open(csv_writer::filename, "r");
http.sendHeader("Content-Length", String(csv_file.size())); char csv_size[10];
snprintf(csv_size, sizeof(csv_size), "%d", csv_file.size());
http.sendHeader("Content-Length", csv_size);
http.streamFile(csv_file, F("text/csv")); http.streamFile(csv_file, F("text/csv"));
csv_file.close(); csv_file.close();
} else { } else {
...@@ -276,9 +276,9 @@ namespace web_server { ...@@ -276,9 +276,9 @@ namespace web_server {
if (!shouldBeAllowed()) { if (!shouldBeAllowed()) {
return http.requestAuthentication(DIGEST_AUTH); return http.requestAuthentication(DIGEST_AUTH);
} }
Serial.print("Removing CSV file..."); Serial.print(F("Removing CSV file..."));
FS_LIB.remove(csv_writer::filename); FS_LIB.remove(csv_writer::filename);
Serial.println(" Done!"); Serial.println(F(" Done!"));
http.sendHeader("Location", "/"); http.sendHeader("Location", "/");
http.send(303); http.send(303);
} }
......
...@@ -12,34 +12,39 @@ namespace config { ...@@ -12,34 +12,39 @@ namespace config {
#endif #endif
} }
// Initialize Wi-Fi namespace wifi {
void WiFiConnect(const String &hostname) { char local_ip[16]; // "255.255.255.255\0"
//NOTE: WiFi Multi could allow multiple SSID and passwords. // Initialize Wi-Fi
WiFi.persistent(false); // Don't write user & password to Flash. void connect(const char *hostname) {
WiFi.mode(WIFI_STA); // Set ESP to be a WiFi-client only //NOTE: WiFi Multi could allow multiple SSID and passwords.
WiFi.persistent(false); // Don't write user & password to Flash.
WiFi.mode(WIFI_STA); // Set ESP to be a WiFi-client only
#if defined(ESP8266) #if defined(ESP8266)
WiFi.hostname(hostname); WiFi.hostname(hostname);
#elif defined(ESP32) #elif defined(ESP32)
WiFi.setHostname(hostname.c_str()); WiFi.setHostname(hostname);
#endif #endif
Serial.print(F("WiFi - Connecting to ")); Serial.print(F("WiFi - Connecting to "));
Serial.println(config::wifi_ssid); Serial.println(config::wifi_ssid);
WiFi.begin(config::wifi_ssid, config::wifi_password); WiFi.begin(config::wifi_ssid, config::wifi_password);
// Wait for connection, at most wifi_timeout seconds // Wait for connection, at most wifi_timeout seconds
for (int i = 0; i <= config::wifi_timeout && (WiFi.status() != WL_CONNECTED); i++) { for (int i = 0; i <= config::wifi_timeout && (WiFi.status() != WL_CONNECTED); i++) {
led_effects::showRainbowWheel(); led_effects::showRainbowWheel();
Serial.print("."); Serial.print(".");
} }
if (WiFi.status() == WL_CONNECTED) { if (WiFi.status() == WL_CONNECTED) {
led_effects::showKITTWheel(color::green); led_effects::showKITTWheel(color::green);
Serial.println(); Serial.println();
Serial.print(F("WiFi - Connected! IP address: ")); Serial.print(F("WiFi - Connected! IP address: "));
Serial.println(WiFi.localIP()); IPAddress address = WiFi.localIP();
} else { snprintf(local_ip, sizeof(local_ip), "%d.%d.%d.%d", address[0], address[1], address[2], address[3]);
//TODO: Allow sensor to work as an Access Point, in order to define SSID & password? Serial.println(local_ip);
led_effects::showKITTWheel(color::red); } else {
Serial.println(F("Connection to WiFi failed")); //TODO: Allow sensor to work as an Access Point, in order to define SSID & password?
led_effects::showKITTWheel(color::red);
Serial.println(F("Connection to WiFi failed"));
}
} }
} }
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
#include "util.h" #include "util.h"
#include "led_effects.h" #include "led_effects.h"
void WiFiConnect(const String &hostname); namespace wifi {
extern char local_ip[];
void connect(const char *hostname);
}
#endif #endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment