#define ARDUINOJSON_ENABLE_COMMENTS 1 #include #include #include #include "LittleFS.h" #include #include #include #include #include #include #include #include #include DynamicJsonDocument settings(1024); #include FTPServer ftpServer(LittleFS); DNSServer dnsServer; AsyncWebServer httpServer(80); HX711 scale; time_t measure = 0; unsigned long measureStartMillis; File measureFile; struct measure { unsigned long millis; float scale; double pa; }; #define MEASURE_BUFFER_SIZE (1024) struct measure measureBuffer[MEASURE_BUFFER_SIZE]; /* buffer to store measured stuff before writing to littlefs */ #define A2VOLT(ar) (ar*3.3/1023) #define VOLT2A(vo) (vo*1023/3.3) #define A2PA(ar) ((A2VOLT(ar)-0.5)*1200000/4.5) #define TEXT_ENC "text/plain; charset=utf-8" int do_reload = 0; void reload (bool w = 0) { /* stop services unless they were never started, indicate this by w in for example setup() */ Serial.println("reload"); if (!w) { Serial.println("stopping services: ftp"); ftpServer.stop(); Serial.println("stopping services: http"); httpServer.reset(); Serial.println("stopping services: dns"); dnsServer.stop(); } /* reload settings */ Serial.println("loading settings"); load_settings(); /* configure pin modes */ pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, HIGH /* LED IS ON when pulled LOW */); long unsigned int mac; uint8_t macar[6]; /* bring up AP networking */ /* // setting fancy settings does not work, FUCK ESPRESSIF AND THEIR BLOB RTOS!!! IPAddress ap_ip(10, 82, 66, 1); ap_ip.fromString(settings["ap_ip"].as()); IPAddress ap_gateway(10, 82, 66, 1); ap_gateway.fromString(settings["ap_gw"].as()); IPAddress ap_subnet(255, 255, 255, 0); ap_subnet.fromString(settings["ap_nm"].as()); WiFi.softAPdisconnect(true); WiFi.softAPConfig(ap_ip, ap_gateway, ap_subnet); mac = strtoul(settings["ap_mac"].as().c_str(), NULL, 16); memcpy(macar, (char *) &mac, 6); if (strlen(settings["ap_mac"].as().c_str()) == 12) wifi_set_macaddr(SOFTAP_IF, macar); */ Serial.println("access point"); const char * ap_pass = settings["ap_pass"].as().c_str(); if (ap_pass && strlen(ap_pass) < 8) ap_pass = NULL; WiFi.mode(WIFI_AP); WiFi.softAP(settings["ap_ssid"].as().c_str(), ap_pass, settings["ap_ch"].as(), settings["ap_hidden"].as()); Serial.println("WiFi.softAPIP() = " + WiFi.softAPIP().toString()); /* bring up STA networking - if that's desired */ Serial.println("station networking"); const char * sta_ssid = settings["sta_ssid"].as().c_str(); if (strlen(settings["sta_ssid"].as().c_str())) { Serial.println("setting up wifi station mode"); IPAddress sta_ip(10, 69, 69, 82); sta_ip.fromString(settings["sta_ip"].as()); IPAddress sta_gw(10, 69, 69, 1); sta_ip.fromString(settings["sta_gw"].as()); IPAddress sta_nm(255, 255, 255, 0); sta_ip.fromString(settings["sta_nm"].as()); IPAddress sta_dns1(93, 103, 235, 126); sta_dns1.fromString(settings["sta_dns1"].as()); IPAddress sta_dns2(193, 2, 1, 66); sta_dns2.fromString(settings["sta_dns2"].as()); mac = strtoul(settings["sta_mac"].as().c_str(), NULL, 16); memcpy(macar, (char *) &mac, 6); if (strlen(settings["sta_mac"].as().c_str()) == 12) wifi_set_macaddr(STATION_IF, macar); WiFi.disconnect(true); WiFi.hostname(settings["sta_host"].as()); const char * sta_pass = settings["sta_pass"].as().c_str(); if (strlen(sta_pass) < 8) sta_pass = NULL; WiFi.begin(sta_ssid, sta_pass); if (settings["sta_static"].as()) if (!WiFi.config(sta_ip, sta_gw, sta_nm, sta_dns1, sta_dns2)) Serial.println("failed to wifi config"); Serial.println(String("wifi local ip: ")+WiFi.localIP().toString()); } else { WiFi.disconnect(); } /* start services */ dnsServer.start(53, settings["host"], WiFi.softAPIP()); ftpServer.begin(settings["ftp_user"], settings["ftp_pass"]); /* web server */ #define ADD_AUTH(h) h.setAuthentication(settings["http_user"], settings["http_pass"]); auto s = httpServer.serveStatic("/index.html", LittleFS, "/") .setDefaultFile("index.html"); ADD_AUTH(s); auto h = httpServer.on("/s", [](AsyncWebServerRequest * r) { r->send(201, TEXT_ENC, "OK"); ESP.restart(); }); ADD_AUTH(h); h = httpServer.on("/l", [](AsyncWebServerRequest * r) { r->send(201, TEXT_ENC, "OK"); do_reload = 1; }); h = httpServer.on("/m", [](AsyncWebServerRequest * r) { if (!r->hasParam("n")) r->send(400, TEXT_ENC, "Manjka parameter n - število sekund meritve"); else if (!measure) { measure = atoi(r->getParam("n")->value().c_str()); r->send(201, TEXT_ENC, String("OK")+measure); } else { r->send(400, TEXT_ENC, "Meritev že poteka!"); } }); ADD_AUTH(h); /* specifični ukazi za meritve: začetek loadcella, kalibracija, tara */ Serial.println(String("začenjam vago na pinih ")+str2pin(settings["scale_dout"].as().c_str())+String(" in ")+ str2pin(settings["scale_sck"].as().c_str())); scale.begin(str2pin(settings["scale_dout"].as().c_str()), str2pin(settings["scale_sck"].as().c_str())); Serial.println(String("kalibriram vago na vrednost ")+settings["scale_cal"].as()); scale.set_scale(settings["scale_cal"].as()); scale.set_offset(settings["scale_tar"].as()); if (scale.wait_ready_timeout(1000)) Serial.println(String("skala meri surovo: ")+scale.read_average(10)); else Serial.println(String("ne morem se povezati na skalo")); /* specifični http ukazi */ h = httpServer.on("/c", [](AsyncWebServerRequest * r) { if (!r->hasParam("t") && !r->hasParam("f")) { r->send(400, TEXT_ENC, "Manjka parameter t - teža na tehtnici ali parameter f - kalibracijski faktor"); } else if (scale.wait_ready_timeout(1000)) { float scaleCal; if (!r->hasParam("f")) { scale.set_scale(); scale.tare(); scaleCal = scale.get_units(10)/atof(r->getParam("t")->value().c_str()); scale.set_scale(scaleCal); r->send(200, TEXT_ENC, String("kalibracijski faktor: ")+String(scaleCal)); } else { scale.set_scale(atof(r->getParam("f")->value().c_str())); r->send(200, TEXT_ENC, String("teža: "+String(scale.get_units(10)))); } } else { r->send(500, TEXT_ENC, "Tehtnica ni najdena"); } }); ADD_AUTH(h); h = httpServer.on("/t", [](AsyncWebServerRequest * r) { if (scale.wait_ready_timeout(1000)) { scale.tare(); r->send(400, TEXT_ENC, String("razlika, ki jo odštejemo od surove vrednosti, je ")+scale.get_offset()); } else { r->send(500, TEXT_ENC, "Tehtnica ni najdena."); } }); ADD_AUTH(h); h = httpServer.on("/g", [](AsyncWebServerRequest * r) { float reading = -1; long readingraw = -1; if (scale.wait_ready_timeout(1000)) { reading = scale.get_units(5); readingraw = scale.read_average(5); } else Serial.println("/g: reading error"); double pa = analogRead(A0); pa = A2PA(pa); r->send(200, "application/json", String("{\"p\":")+pa+String(",\"s\":")+reading+String(",\"r\":")+readingraw+String("}")); }); ADD_AUTH(h); httpServer.begin(); } void handleMeasure() { /* ni časovno omejeno, zapiše se čim več meritev, recimo izvede se enkrat na 10 milisekund, to je idealno. */ /* ob desetsekundni meritvi je to 1000 zajemov, kar znese ob 100 bajtih na zajem 100 kilobajtov na flash. */ httpServer.end(); Serial.println(String("meritev loop started at ")+millis()); measure += time(NULL)+1; int i = 0; digitalWrite(LED_BUILTIN, LOW); /* glows in the dark1 */ ESP.wdtDisable(); while (measure >= time(NULL)) { Serial.println("meritev ..."); if (scale.wait_ready_timeout(1000)) { measureBuffer[i].millis = millis(); measureBuffer[i].scale = scale.get_units(1); /* zaradi konstantnega branja analognih vrednosti je pričakovano, da ob meritvi crkne WiFi */ measureBuffer[i].pa = analogRead(A0); measureBuffer[i].pa = A2PA(measureBuffer[i].pa); } else Serial.println("HX711 ni najden."); if (i >= MEASURE_BUFFER_SIZE) { Serial.println("zapolnjen measure buffer, dovolj bo"); break; } i++; } ESP.wdtEnable(2000); digitalWrite(LED_BUILTIN, HIGH); /* stops glowing */ if (!measureFile.isFile()) { char filename[32]; snprintf(filename, 32, "meritev%ld.csv", time(NULL)); Serial.println(String("starting measure into file ")+filename); measureFile = LittleFS.open(filename, "w"); scale.power_up(); measureStartMillis = millis(); } for (int j = 0; j < i; j++) measureFile.print(measureBuffer[j].millis+String(",")+measureBuffer[j].scale+String(",")+measureBuffer[j].pa+String("\n")); measure = 0; measureFile.close(); Serial.println(String("meritev loop done at ")+millis()); httpServer.begin(); } void setup () { Serial.begin(MONITOR_SPEED); Serial.println("Živ sem!"); LittleFS.begin(); reload(1); } void loop () { if (measure) handleMeasure(); else { ftpServer.handleFTP(); dnsServer.processNextRequest(); if (do_reload) { reload(); do_reload = 0; } } }