diff --git a/firmware/remote_sensors_esp32/platformio.ini b/firmware/remote_sensors_esp32/platformio.ini --- a/firmware/remote_sensors_esp32/platformio.ini +++ b/firmware/remote_sensors_esp32/platformio.ini @@ -1,27 +1,27 @@ ; PlatformIO Project Configuration File ; ; Build options: build flags, source filter ; Upload options: custom upload port, speed and extra flags ; Library options: dependencies, extra library storages ; Advanced options: extra scripting ; ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html [env:nodemcuv2] upload_protocol = espota upload_port = 192.168.5.73 -upload_flags = --auth=0681 +upload_flags = --auth=7648 platform = espressif8266 platform_packages = platformio/framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git board = nodemcuv2 framework = arduino lib_deps = + https://github.com/hww3/WiFiManager/#0.16.0-with-hostname beegee-tokyo/SHT1x-ESP@^1.0.0 - tzapu/WiFiManager https://github.com/esp8266/ESPWebServer.git bblanchon/ArduinoJson@^6.18.4 arduino-libraries/NTPClient@^3.1.0 mathertel/OneButton@^2.0.2 jwrw/ESP_EEPROM@^2.1.1 diff --git a/firmware/remote_sensors_esp32/src/main.cpp b/firmware/remote_sensors_esp32/src/main.cpp --- a/firmware/remote_sensors_esp32/src/main.cpp +++ b/firmware/remote_sensors_esp32/src/main.cpp @@ -1,319 +1,381 @@ #include //this needs to be first, or it all crashes and burns... +#include "config.h" +#include //https://github.com/esp8266/Arduino +#ifdef WANT_MDNS +#include +#endif /* WANT_MDNS */ -#include //https://github.com/esp8266/Arduino -#include #include #include //https://github.com/tzapu/WiFiManager +#ifdef WANT_NTP #include +#endif /* WANT_NTP */ +#ifdef WANT_OTA #include +#endif /* WANT_OTA */ #include #include #include #include #include /* * This is a simple ESP8266/Arduino based firmware that presents * SHT1x temperature and relative humidity data via UDP broadcast * based on the Weatherflow Smartweather protocol. Integrations * that process the Smartweather UDP feed will see a device * running this firmware as a combined Smartweather Hub/Air. * * The wifi configuration and serial numbers are configured via * a custom wireless network/captive portal. Connect to its * ssid to provide the configuration information. Holding the * flash button down for 1 second will cause the configuration * to be reset and the device to enter access point mode. */ +#ifdef WANT_OTA +#define OTA_PASSWORD "7648" +#endif /* WANT_OTA */ + #define DEBUG(X...) do{if(Serial)Serial.println(X);}while(0) #define DEBUGCHAR(X...) do{if(Serial)Serial.print(X);}while(0) -#define FIRMWARE_REVISION 1024 + +/* by default, the value of PROJECTNAME will be used as the prefix of the devices's + * hostname and the configuration access point ssid. + */ +#define PROJECTNAME "ENVSENSOR" + +/* when storing data in the pseudo-eeprom of the ESP, you must specify how much space + * will be needed for the data stored. changing this value will likely cause existing + * data to be lost, so best over-estimate before going live. + */ +#define EEPROM_BYTES_NEEDED 50 + #define SLOW 250 #define MEDIUM 100 #define FAST 50 #define sleep(X) delay(X) #define ON 1 #define OFF 0 WiFiClient wifiClient; #define dataPin D6 #define clockPin D5 #define SMARTWEATHER_PORT 50222 // if 3.3v board is used SHT1x sht1x(dataPin, clockPin, SHT1x::Voltage::DC_3_3v); IPAddress br_adr; WiFiUDP udp; -WiFiUDP ntpUdp; String hubsn; String airsn; int reportfreq = 60; +#ifdef WANT_NTP +WiFiUDP ntpUdp; + NTPClient timeClient(ntpUdp); +#endif /* WANT_NTP */ // 'flash' button is pin 0 #define BUTTON_PIN 0 OneButton btn = OneButton( BUTTON_PIN, // Input pin for the button true, // Button is active LOW true // Enable internal pull-up resistor ); long ts; int reportcnt = 0; int lastobservation = 0; int lastreport = 0; void blink(int speed, int count) { pinMode(16, OUTPUT); for(; count > 0; count--) { digitalWrite(16, ON); sleep(speed); digitalWrite(16, OFF); sleep(speed); } digitalWrite(16, ON); } +WiFiManagerParameter hub_serial_number("hubsn", "HubSerialNumber", "10010", 7); +WiFiManagerParameter air_serial_number("airsn", "AirSerialNumber", "10012", 7); +WiFiManagerParameter report_frequency("reportfreq", "ReportFreq (seconds)", "60", 4); +void wifi_register_custom_params(WiFiManager * myWifiManager) { + + myWifiManager->addParameter(&hub_serial_number); + + myWifiManager->addParameter(&air_serial_number); + + myWifiManager->addParameter(&report_frequency); + +} //! clear the wifi configuration and restart the device in AP mode. void resetEverything() { WiFi.enableSTA(true); WiFi.persistent(true); WiFi.disconnect(true); WiFi.persistent(false); delay(250); ESP.reset(); delay(5000); } bool shouldSaveConfig = false; bool enteredConfigMode = false; void configModeCallback (WiFiManager *myWiFiManager) { Serial.println("config mode"); enteredConfigMode = true; } void saveConfigCallback () { Serial.println("Should save config now"); if(enteredConfigMode) shouldSaveConfig = true; } void writeStringToEEPROM(int addrOffset, const String &strToWrite) { uint8_t len = strToWrite.length(); EEPROM.write(addrOffset, len); for (int i = 0; i < len; i++) { EEPROM.write(addrOffset + 1 + i, strToWrite[i]); } } String readStringFromEEPROM(int addrOffset) { - uint8_t newStrLen; + uint8_t newStrLen = 0; Serial.println("reading a string from eeprom"); EEPROM.get(addrOffset, newStrLen); char data[newStrLen + 1]; for (int i = 0; i < newStrLen; i++) { data[i] = EEPROM.read(addrOffset + 1 + i); } data[newStrLen] = '\0'; return String(data); } + +String wifi_get_mac_subset() { + uint8_t mac[6]; + char macStr[7] = { 0 }; + wifi_get_macaddr(STATION_IF, mac); + sprintf(macStr, "%02X%02X%02X", mac[3], mac[4], mac[5]); + return String(macStr); +} //*********************************************** void setup() { blink(MEDIUM, 10); // put your setup code here, to run once: if(Serial) Serial.begin(115200); DEBUG("Welcome\n"); delay(100); // resetEverything(); //WiFiManager //Local intialization. Once its business is done, there is no need to keep it around WiFiManager wifiManager; - WiFiManagerParameter hub_serial_number("hubsn", "HubSerialNumber", "10010", 7); - wifiManager.addParameter(&hub_serial_number); + // wifiManager.setDebugOutput(true); + String ssid = PROJECTNAME + String("-"); + ssid += wifi_get_mac_subset(); + wifi_register_custom_params(&wifiManager); + wifiManager.setHostname(ssid.c_str()); - WiFiManagerParameter air_serial_number("airsn", "AirSerialNumber", "10012", 7); - wifiManager.addParameter(&air_serial_number); - - WiFiManagerParameter report_frequency("reportfreq", "ReportFreq (seconds)", "60", 4); - wifiManager.addParameter(&report_frequency); //exit after config instead of connecting wifiManager.setBreakAfterConfig(true); wifiManager.setAPCallback(configModeCallback); wifiManager.setSaveConfigCallback(saveConfigCallback); //reset settings - for testing - seems broken, see resetEverything() //wifiManager.resetSettings(); //tries to connect to last known settings //if it does not connect it starts an access point with the specified name //here "AutoConnectAP" with password "password" //and goes into a blocking loop awaiting configuration if (!wifiManager.autoConnect()) { DEBUG("WifiManager: failed to connect, we should reset as see if it connects"); delay(3000); ESP.reset(); delay(5000); } blink(MEDIUM, 2); - - ArduinoOTA.onStart([]() { +#ifdef WANT_OTA + ArduinoOTA.onStart([]() { DEBUG("OTA Start"); }); ArduinoOTA.onEnd([]() { DEBUG("\nOTA End"); }); ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { if(Serial) Serial.printf("OTA: Progress: %u%%\r", (progress / (total / 100))); }); ArduinoOTA.onError([](ota_error_t error) { if(Serial) Serial.printf("OTA Error[%u]: ", error); if (error == OTA_AUTH_ERROR) DEBUG("OTA: Auth Failed"); else if (error == OTA_BEGIN_ERROR) DEBUG("OTA: Begin Failed"); else if (error == OTA_CONNECT_ERROR) DEBUG("OTA: Connect Failed"); else if (error == OTA_RECEIVE_ERROR) DEBUG("OTA: Receive Failed"); else if (error == OTA_END_ERROR) DEBUG("OTA: End Failed"); }); - ArduinoOTA.setPassword((const char *)"0681"); - + ArduinoOTA.setPassword((const char *)OTA_PASSWORD); +#endif /* WANT_OTA */ //if you get here you have connected to the WiFi DEBUG("connected...yay :)"); + +#ifdef WANT_OTA ArduinoOTA.begin(); +#endif /* WANT_OTA */ DEBUG("local ip: "); DEBUG(WiFi.localIP()); br_adr = WiFi.localIP(); br_adr[3] = 255; - EEPROM.begin(50); + EEPROM.begin(EEPROM_BYTES_NEEDED); if (shouldSaveConfig) { String hs ="HB-"; hs = hs + (hub_serial_number.getValue()); hubsn = hs; String as = "AR-"; as = as + (air_serial_number.getValue()); airsn = as; String frq = String(report_frequency.getValue()); reportfreq = (frq).toInt(); writeStringToEEPROM(0, hubsn); // 7 bytes max writeStringToEEPROM(15, airsn); // 7 bytes max writeStringToEEPROM(30, frq); // 4 bytes max if(!EEPROM.commit()) resetEverything(); delay(100); } else if(1){ hubsn = readStringFromEEPROM(0); airsn = readStringFromEEPROM(15); reportfreq = (readStringFromEEPROM(30)).toInt(); } if(reportfreq < 30) reportfreq = 30; udp.begin(SMARTWEATHER_PORT); - timeClient.begin(); +#ifdef WANT_MDNS + MDNS.begin(ssid); +#endif /* WANT_MDNS */ - delay(1000); +#ifdef WANT_NTP + timeClient.begin(); +#endif /* WANT_NTP */ + + delay(100); Serial.println("ready to read"); btn.attachLongPressStart(resetEverything); } void loop() { +#ifdef WANT_NTP timeClient.update(); + // don't update this every loop else you'll waste cpu + ts = timeClient.getEpochTime(); +#endif /* WANT_NTP */ + +#ifdef WANT_OTA ArduinoOTA.handle(); +#endif /* WANT_OTA */ long tsm = millis(); btn.tick(); if((tsm/1000) > (lastreport + 30)) { lastreport = millis() / 1000; +#ifdef WANT_NTP ts = timeClient.getEpochTime(); - +#endif /* WANT_NTP */ blink(SLOW, 3); if (1) { StaticJsonDocument<200> doc; doc["serial_number"] = hubsn; doc["type"] = "hub_status"; doc["firmware_revision"] = FIRMWARE_REVISION; doc["uptime"] = millis() / 1000; doc["rssi"] = WiFi.RSSI(); doc["timestamp"] = ts; udp.beginPacket(br_adr, SMARTWEATHER_PORT); serializeJson(doc, udp); udp.println(); udp.endPacket(); reportcnt++; } if (1) { StaticJsonDocument<200> doc; doc["serial_number"] = airsn; doc["hub_sn"] = hubsn; doc["type"] = "device_status"; doc["firmware_revision"] = FIRMWARE_REVISION; doc["uptime"] = millis() / 1000; doc["rssi"] = WiFi.RSSI(); doc["hub_rssi"] = WiFi.RSSI(); doc["voltage"] = 0.0; doc["timestamp"] = ts; udp.beginPacket(br_adr, SMARTWEATHER_PORT); serializeJson(doc, udp); udp.println(); udp.endPacket(); } } if((tsm/1000) > (lastobservation + reportfreq)) { StaticJsonDocument<250> doc; blink(FAST, 2); +#ifdef WANT_NTP ts = timeClient.getEpochTime(); +#endif /* WANT_NTP */ lastobservation = (tsm/1000); doc["serial_number"] = airsn; doc["hub_sn"] = hubsn; doc["type"] = "obs_air"; doc["firmware_revision"] = FIRMWARE_REVISION; JsonArray obs = doc.createNestedArray("obs"); JsonArray obsValues = obs.createNestedArray(); obsValues.add(ts); obsValues.add(0.0); obsValues.add(sht1x.readTemperatureC()); obsValues.add(sht1x.readHumidity()); obsValues.add(0); obsValues.add(0); obsValues.add(0.0); obsValues.add((reportfreq/60)); udp.beginPacket(br_adr, SMARTWEATHER_PORT); serializeJson(doc, udp); udp.println(); udp.endPacket(); } delay(100); }