More configuration options

- wifi provisioning
- auto start/stop of sessions
This commit is contained in:
Martin Bauer
2020-09-03 14:10:52 +02:00
parent 92e7399fe4
commit 041031709f
12 changed files with 547 additions and 157 deletions

View File

@@ -3,10 +3,14 @@
#include "Dtypes.h"
#include "SwimTrackerConfig.h"
#include <WiFi.h>
#include <ArduinoJson.h>
#include <HTTPClient.h>
#include "esp_https_ota.h"
#include "ESPmDNS.h"
// Own libs
#include "WifiManager.h"
#include "MockScale.h"
#include "Scale.h"
#include "MeasurementSession.h"
@@ -17,15 +21,14 @@
#include "WebDAV.h"
#include "WebsocketServer.h"
#include "esp_https_ota.h"
#include "ESPmDNS.h"
using Session_T = SimpleMeasurementSession<MeasurementT, CONFIG_SESSION_MAX_SIZE>;
SessionManager<Session_T> sessionManager(CONFIG_SCALE_DOUT_PIN, CONFIG_SCALE_SCK_PIN, CONFIG_TARE_AVG_COUNT);
SessionManager<Session_T> sessionManager;
EspHttp espHttpServer;
WebsocketServer<Session_T> webSocketServer(sessionManager, 81);
WifiManager wifiManager;
extern const uint8_t certificate_pem[] asm("_binary_certificate_pem_start");
bool firmwareUpdate()
@@ -33,7 +36,7 @@ bool firmwareUpdate()
esp_http_client_config_t config;
Serial.println((char *)certificate_pem);
memset(&config, 0, sizeof(esp_http_client_config_t));
config.url = "https://swimtracker-update.bauer.tech/firmware.bin";
config.url = UPDATE_URL;
config.cert_pem = (char *)certificate_pem;
Serial.println("Starting firmware upgrade");
esp_err_t ret = esp_https_ota(&config);
@@ -51,7 +54,7 @@ bool firmwareUpdate()
}
template <typename SessionT>
void httpSetup(SessionManager<SessionT> *sessionManager)
void httpSetup(SessionManager<SessionT> *sessionManager, WifiManager *wifiManager)
{
auto cbStartSession = [sessionManager](httpd_req_t *req) {
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
@@ -79,63 +82,58 @@ void httpSetup(SessionManager<SessionT> *sessionManager)
firmwareUpdate();
};
auto cbStatus = [sessionManager](httpd_req_t *req) {
String result;
result.reserve(512);
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
httpd_resp_set_hdr(req, "Content-Type", "application/json");
StaticJsonDocument<1024> json;
// session
{
result += "{ \"session\": ";
JsonObject sessionObj = json.createNestedObject("session");
if (sessionManager->isMeasuring())
{
const auto &session = sessionManager->session();
result += "{ \"started\":" + String(session.getStartTime()) + ", ";
result += "\"num_measurements\":" + String(session.numMeasurements()) + "},\n";
sessionObj["started"] = session.getStartTime();
sessionObj["num_measurements"] = session.numMeasurements();
}
else
result += "{},\n";
}
// scale
{
const String tareOffset(sessionManager->tareOffset());
const String divider(CONFIG_VALUE_DIVIDER);
result += "\"scale\": { \"tare_offset\": " + tareOffset + ", \"divider\":" + divider + "},\n";
JsonObject scaleObj = json.createNestedObject("scale");
scaleObj["tare_offset"] = sessionManager->tareOffset();
scaleObj["value_right_shift"] = sessionManager->valueRightShift();
}
// flash
{
const String usedBytes(portablefs::usedBytes());
const String freeBytes(portablefs::totalBytes() - portablefs::usedBytes());
result += "\"file_system\": { \"used\": " + usedBytes + ", \"free\":" + freeBytes + "},\n";
JsonObject fsObj = json.createNestedObject("flash");
fsObj["used"] = portablefs::usedBytes();
fsObj["free"] = portablefs::totalBytes() - portablefs::usedBytes();
}
// RAM
{
const String freeBytes(ESP.getFreeHeap());
const String usedBytes(ESP.getHeapSize() - ESP.getFreeHeap());
result += "\"ram\": { \"used\": " + usedBytes + ", \"free\":" + freeBytes + "},\n";
JsonObject ramObj = json.createNestedObject("ram");
ramObj["used"] = ESP.getHeapSize() - ESP.getFreeHeap();
ramObj["free"] = ESP.getFreeHeap();
}
// PSRAM
{
const String freeBytes(ESP.getFreePsram());
const String usedBytes(ESP.getPsramSize() - ESP.getFreePsram());
result += "\"psram\": { \"used\": " + usedBytes + ", \"free\":" + freeBytes + "},\n";
JsonObject psramObj = json.createNestedObject("psram");
psramObj["used"] = ESP.getPsramSize() - ESP.getFreePsram();
psramObj["free"] = ESP.getFreePsram();
}
// firmware
{
auto descr = esp_ota_get_app_description();
const String projectName(descr->project_name);
const String versionStr(descr->version);
const String idfVersion(descr->idf_ver);
const String compileDate(descr->date);
const String compileTime(descr->time);
result += "\"firmware\": { \"name\" : \"" +
projectName + "\", \"version\": \"" +
versionStr + "\", \"idfVersion\": \"" +
idfVersion + "\", \"compile_date\": \"" +
compileDate + +"\", \"compile_time\": \"" +
compileTime + "\" }\n";
JsonObject firmware = json.createNestedObject("firmware");
firmware["name"] = descr->project_name;
firmware["version"] = descr->version;
firmware["idf_version"] = descr->idf_ver;
firmware["compile_date"] = descr->date;
firmware["compile_time"] = descr->time;
}
result += "}";
httpd_resp_send(req, result.c_str(), result.length());
char jsonText[512];
auto bytesWritten = serializeJson(json, jsonText);
httpd_resp_send(req, jsonText, bytesWritten);
};
auto cbGetData = [sessionManager](httpd_req_t *req) {
auto sessionId = sessionManager->session().getStartTime();
@@ -166,36 +164,88 @@ void httpSetup(SessionManager<SessionT> *sessionManager)
httpd_resp_send(req, buf, totalSize);
free(buf);
};
auto cbWifiGet = [wifiManager](httpd_req_t *req) {
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
StaticJsonDocument<128> json;
json["state"] = wifiManager->stateStr();
char jsonText[128];
auto bytesWritten = serializeJson(json, jsonText);
httpd_resp_send(req, jsonText, bytesWritten);
};
auto cbWifiPost = [wifiManager](httpd_req_t *req) {
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
StaticJsonDocument<1024> json;
char content[512];
size_t recvSize = min(req->content_len, sizeof(content)); //truncate if too long
int ret = httpd_req_recv(req, content, recvSize);
if (ret <= 0)
{
if (ret == HTTPD_SOCK_ERR_TIMEOUT)
httpd_resp_send_408(req);
return;
}
DeserializationError err = deserializeJson(json, content);
if (err)
{
httpd_resp_set_status(req, "400 Bad Request");
httpd_resp_send(req, "JSON parse error", -1);
return;
}
if (json.containsKey("reset_to_provisioning") && json["reset_to_provisioning"].as<bool>())
{
wifiManager->resetToApProvisioning();
httpd_resp_send(req, "OK", -1);
ESP.restart();
return;
}
if (json.containsKey("ap_password"))
{
httpd_resp_send(req, "OK", -1);
wifiManager->setApCredentials(json["ap_password"].as<const char *>());
ESP.restart();
return;
}
if (json.containsKey("sta_ssid") && json.containsKey("sta_password"))
{
wifiManager->setStaCredentials(json["sta_ssid"].as<const char *>(), //
json["sta_password"].as<const char *>());
httpd_resp_send(req, "OK", -1);
ESP.restart();
return;
}
httpd_resp_set_status(req, "400 Bad Request");
httpd_resp_send(req, "Invalid keys in JSON", -1);
};
espHttpServer.start();
espHttpServer.on("/api/session/start", HTTP_GET, cbStartSession);
espHttpServer.on("/api/session/start", HTTP_POST, cbStartSession);
espHttpServer.on("/api/session/stop", HTTP_GET, cbStopSession);
espHttpServer.on("/api/session/stop", HTTP_POST, cbStopSession);
espHttpServer.on("/api/session/data", HTTP_GET, cbGetData);
espHttpServer.on("/api/status", HTTP_GET, cbStatus);
espHttpServer.on("/api/tare", HTTP_GET, cbTare);
espHttpServer.on("/api/wifi", HTTP_GET, cbWifiGet);
espHttpServer.on("/api/wifi", HTTP_POST, cbWifiPost);
espHttpServer.on("/api/restart", HTTP_GET, cbRestart);
espHttpServer.on("/api/firmwareupdate", HTTP_GET, cbFirmwareUpdate);
auto webdav = webdavHandler("/webdav/", "/dat");
espHttpServer.on("/webdav/*?", HTTP_GET, webdav);
espHttpServer.on("/webdav/*?", HTTP_PROPFIND, webdav);
espHttpServer.on("/webdav/*?", HTTP_DELETE, webdav);
espHttpServer.on("/webdav/*?", HTTP_OPTIONS, webdav);
Serial.println("HTTP setup done");
}
void checkWifi()
{
while (WiFi.status() != WL_CONNECTED)
if (!wifiManager->inProvisioningMode())
{
Serial.println("WiFi disconnected. Try to reconnect");
WiFi.reconnect();
delay(2000);
espHttpServer.on("/api/session/start", HTTP_GET, cbStartSession);
espHttpServer.on("/api/session/start", HTTP_POST, cbStartSession);
espHttpServer.on("/api/session/stop", HTTP_GET, cbStopSession);
espHttpServer.on("/api/session/stop", HTTP_POST, cbStopSession);
espHttpServer.on("/api/session/data", HTTP_GET, cbGetData);
espHttpServer.on("/api/status", HTTP_GET, cbStatus);
espHttpServer.on("/api/tare", HTTP_GET, cbTare);
espHttpServer.on("/api/firmwareupdate", HTTP_GET, cbFirmwareUpdate);
auto webdav = webdavHandler("/webdav/", "/dat");
espHttpServer.on("/webdav/*?", HTTP_GET, webdav);
espHttpServer.on("/webdav/*?", HTTP_PROPFIND, webdav);
espHttpServer.on("/webdav/*?", HTTP_DELETE, webdav);
espHttpServer.on("/webdav/*?", HTTP_OPTIONS, webdav);
Serial.println("HTTP setup done");
}
else
{
Serial.println("HTTP setup with limited API in provisioning mode");
}
}
@@ -213,25 +263,13 @@ void mdnsSetup(const String &fullHostname)
if (!MDNS.begin(fullHostname.c_str()))
{
Serial.println("Error setting up MDNS responder!");
while (1)
while (true)
{
delay(1000);
}
}
Serial.printf("mDNS started %s\n", fullHostname.c_str());
MDNS.addService("_swimtracker", "tcp", 80);
/*
// mDNS
esp_err_t err = mdns_init();
if (err)
Serial.printf("MDNS Init failed: %d\n", err);
else {
Serial.printf("Setting up zeroconf hostname %s\n", fullHostname.c_str());
mdns_hostname_set(fullHostname.c_str());
mdns_service_add(NULL, "_swimtracker", "_tcp", 81, NULL, 0);
mdns_instance_name_set("SwimTracker by bauer.tech");
}
*/
MDNS.addService("swimtracker", "tcp", 81);
}
void setup()
@@ -241,7 +279,6 @@ void setup()
while (!Serial)
{
}
Serial.printf("Starting SwimTracker Firmware - connecting to %s\n", CONFIG_WIFI_SSID);
// File system
bool spiffsResult = SPIFFS.begin(true);
@@ -251,41 +288,40 @@ void setup()
ESP_ERROR_CHECK(esp_event_loop_create_default());
// WiFi
WiFi.disconnect();
WiFi.mode(WIFI_STA);
WiFi.begin(CONFIG_WIFI_SSID, CONFIG_WIFI_PASSWORD);
String fullHostname = String(CONFIG_HOSTNAME) + getIdSuffix();
WiFi.setHostname(fullHostname.c_str());
Serial.println(F("Waiting for WIFI connection..."));
int connectCounter = 0;
while (WiFi.status() != WL_CONNECTED)
{
delay(1000);
connectCounter += 1;
if (connectCounter > 5)
{
Serial.println("Couldn't obtain WIFI - retrying..");
WiFi.begin(CONFIG_WIFI_SSID, CONFIG_WIFI_PASSWORD);
}
}
wifiManager.begin(fullHostname);
Serial.print("Connected to WiFi. IP:");
Serial.println(WiFi.localIP());
Serial.printf("WIFI state: %s\n", wifiManager.stateStr());
mdnsSetup(fullHostname);
Preferences scalePrefs;
scalePrefs.begin("st_prefs");
int valueRightShift = scalePrefs.getInt("valueRightShift", CONFIG_VALUE_RIGHT_SHIFT);
uint8_t tareAvgCount = scalePrefs.getUInt("tareAvgCount", CONFIG_TARE_AVG_COUNT);
MeasurementT autoStartMinThreshold = scalePrefs.getUInt("autoStartMinThreshold", CONFIG_AUTO_START_MIN_THRESHOLD);
MeasurementT autoStartMaxThreshold = scalePrefs.getUInt("autoStartMinThreshold", CONFIG_AUTO_START_MAX_THRESHOLD);
uint32_t autoStartMaxMeasurementsBetweenPeaks = scalePrefs.getUInt("autoStartMaxMeasurementsBetweenPeaks", CONFIG_AUTO_START_MAX_MEASUREMENTS_BETWEEN_PEAKS);
MeasurementT autoStopThreshold = scalePrefs.getUInt("autoStopThreshold", CONFIG_AUTO_STOP_THRESHOLD);
uint32_t autoStopNumMeasurements = scalePrefs.getUInt("autoStopNumMeasurements", CONFIG_AUTO_STOP_NUM_MEASUREMENTS);
// Session
sessionManager.begin();
sessionManager.begin(CONFIG_SCALE_DOUT_PIN, CONFIG_SCALE_SCK_PIN,
tareAvgCount, valueRightShift,
autoStartMinThreshold, autoStartMaxThreshold, autoStartMaxMeasurementsBetweenPeaks,
autoStopThreshold, autoStopNumMeasurements);
// HTTP & Websocket server
httpSetup(&sessionManager);
webSocketServer.begin();
httpSetup(&sessionManager, &wifiManager);
if (!wifiManager.inProvisioningMode())
webSocketServer.begin();
}
int measurementsSent = 0;
void loop()
{
sessionManager.iteration();
webSocketServer.iteration();
checkWifi();
wifiManager.wifiWatchdog();
}