diff --git a/.github/workflows/all-branches.yml b/.github/workflows/all-branches.yml index 0e1552a..9b93e21 100644 --- a/.github/workflows/all-branches.yml +++ b/.github/workflows/all-branches.yml @@ -27,7 +27,7 @@ jobs: - name: Test compile for Arduino uses: ArminJo/arduino-test-compile@v3 with: - arduino-board-fqbn: esp8266:esp8266:nodemcu:xtal=80,vt=flash,exception=legacy,ssl=all,eesz=4M2M,ip=lm2f,dbg=Disabled,lvl=None____,wipe=none,baud=115200 + arduino-board-fqbn: esp8266:esp8266:nodemcu:xtal=80,vt=flash,ssl=all,eesz=4M2M,ip=lm2f,dbg=Disabled,lvl=None____,wipe=none,baud=115200 platform-url: https://arduino.esp8266.com/stable/package_esp8266com_index.json required-libraries: ArduinoJson,Adafruit BME280 Library,Nova Fitness Sds dust sensors library sketch-names: "*.ino" diff --git a/.gitignore b/.gitignore index d65a637..d8f10c5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.iml +.idea/ .python-version diff --git a/testing/anemometer/anemometer.ino b/testing/anemometer/anemometer.ino index 11326e6..be574c8 100644 --- a/testing/anemometer/anemometer.ino +++ b/testing/anemometer/anemometer.ino @@ -57,6 +57,7 @@ void loop() { } else { // todo debounce based on change time < 10 millis, maybe not needed if (windState != anemometerState) { + Serial.println("count"); wind_ct++; // corresponds to 1/4 rotation windState = anemometerState; } diff --git a/weather-station.ino b/weather-station.ino index 9952f3a..917e54b 100644 --- a/weather-station.ino +++ b/weather-station.ino @@ -14,18 +14,24 @@ /** * Network Configuration */ -#define IP_1 192 -#define IP_2 168 -#define IP_3 178 -#define IP_4 29 -#define IP_PORT 8080 #define WIFI_CONNECT_TIMEOUT_SECONDS 30 /** - * Network hostname for the system + * Data logging server configuration */ -const String HOST_NAME = "weather-station"; +#define SERVER_ADDRESS "http://192.168.178.29:8080" +#define URL_PATH "/weather-station/balcony" +#define HOSTNAME "weather-station" + +/** + * String defaults + */ +#define SEPARATOR_LINE "---" +#define HTTP_CONTENT_TYPE_HEADER "Content-Type" +#define HTTP_CONTENT_LENGTH_HEADER "Content-Length" +#define HTTP_JSON_CONTENT_TYPE "application/json" +#define EMPTY_STRING "" /** * System properties @@ -53,7 +59,7 @@ const String HOST_NAME = "weather-station"; #include #include "SdsDustSensor.h" #include - +#include /** * Instruments @@ -64,10 +70,8 @@ SdsDustSensor sds(SDS_DUST_RX, SDS_DUST_TX); /** * Network messages */ -const int dataFieldsCapacity = JSON_OBJECT_SIZE(8); -StaticJsonDocument dataJson; -WiFiClient client; -IPAddress server(IP_1, IP_2, IP_3, IP_4); +WiFiClient WIFI_CLIENT; +HTTPClient HTTP_CLIENT; /** * Runtime parameters @@ -76,24 +80,22 @@ uint64_t previousTime = 0; float ultravioletDarknessVoltage = 1.07; float ultravioletMaxVoltage = 2.8; float maxUltravioletIntensityLevelAtLocation = 8.0; -int sdsInhalationSeconds = 30; -int windMeasurementSeconds = 10; -int cycleIntervalSeconds = 60; +int airMeasurementSeconds = 30; +int cycleIntervalSeconds = 80; // Runs a bit more than every 2 minutes void setup() { - Serial.begin(9600); + Serial.begin(115200); Serial.println("Booting"); delay(REBOOT_DELAY_MS); // Allow a moment for some sensors to initialise previousTime = millis(); - connectToWifi(); setupMultiplexer(); setupInstruments(); Serial.println("Setup complete!"); - Serial.println(""); + Serial.println(EMPTY_STRING); } void loop() { @@ -103,31 +105,36 @@ void loop() { getBme280data(&temperature, &pressure, &humidity); - double rainfallLevel; - getRainfallData(&rainfallLevel); - double uvIntensity; getUvSensorData(&uvIntensity); + startParticulateMeasurement(); + double windSpeed; getWindSpeedKmPerHr(&windSpeed); double pm25level; double pm10level; - getParticulateData(&pm25level, &pm10level); + endParticulateMeasurement(&pm25level, &pm10level); - sendData(temperature, humidity, pressure, uvIntensity, rainfallLevel, - windSpeed, pm25level, pm10level); + if (connectToWifi()) { + sendData(temperature, humidity, pressure, uvIntensity, + windSpeed, pm25level, pm10level); + } + + WiFi.disconnect(); + WiFi.forceSleepBegin(); sleepUntilNext(); } void sleepUntilNext() { Serial.println("Cycle complete."); - Serial.println("---"); + Serial.println(SEPARATOR_LINE); Serial.println("Sleeping for " + String(cycleIntervalSeconds) + " seconds..."); - Serial.println(""); + Serial.println(EMPTY_STRING); + Serial.flush(); delay(cycleIntervalSeconds * 1000); } @@ -150,7 +157,7 @@ void setupInstruments() { Serial.println("Setup BME280..."); // Temp/humidity/pressure sensor bme.begin(0x76); - Serial.println(""); + Serial.println(EMPTY_STRING); Serial.println("Setup SDS011..."); // Dust sensor @@ -158,7 +165,7 @@ void setupInstruments() { Serial.println(sds.queryFirmwareVersion().toString()); Serial.println(sds.setQueryReportingMode().toString()); sds.sleep(); - Serial.println(""); + Serial.println(EMPTY_STRING); } void getBme280data(double*temperature, double*pressure, double*humidity) { @@ -167,38 +174,20 @@ void getBme280data(double*temperature, double*pressure, double*humidity) { double liveHumidity = bme.readHumidity(); Serial.println("BME280"); - Serial.println("---"); + Serial.println(SEPARATOR_LINE); Serial.println("Temperature: " + String(liveTemp)); Serial.println("Pressure: " + String(livePressure)); Serial.println("Humidity: " + String(liveHumidity)); - Serial.println(""); + Serial.println(EMPTY_STRING); *temperature = liveTemp; *pressure = livePressure; *humidity = liveHumidity; } -void getRainfallData(double*rainfallPercentage) { - setActiveMultiplexerChannel(1); - int sensorReading = analogRead(ANALOGUE_IN); - int maxValue = 1024; - int rawWetness = maxValue - sensorReading; - double rainPercent = mapDouble(static_cast(rawWetness), 0.0, 1024.0, - 0.0, 100.0); - - Serial.println("Rainfall Sensor"); - Serial.println("---"); - Serial.println("Sensor reading: " + String(sensorReading)); - Serial.println("Wetness: " + String(rawWetness) + " / " + String(maxValue)); - Serial.println("Wetness %: " + String(rainPercent)); - Serial.println(""); - - *rainfallPercentage = rainPercent; -} - void getUvSensorData(double*uvIntensity) { Serial.println("ML8511"); - Serial.println("---"); + Serial.println(SEPARATOR_LINE); setActiveMultiplexerChannel(0); int uvLevel = averageAnalogueRead(ANALOGUE_IN); int refLevel = averageAnalogueRead(REF_3V3); @@ -217,19 +206,17 @@ void getUvSensorData(double*uvIntensity) { Serial.println("UV Intensity (mW/cm^2): " + String(mapped)); Serial.println("Adjusted UV Intensity (mW/cm^2): " + String(adjustedIntensity)); - Serial.println(""); + Serial.println(EMPTY_STRING); } -void getParticulateData(double*pm25, double*pm10) { +void startParticulateMeasurement() { Serial.println("SDS011"); - Serial.println("---"); + Serial.println(SEPARATOR_LINE); Serial.println("Waking up..."); sds.wakeup(); - Serial.println("Inhaling for " + String(sdsInhalationSeconds) + - " seconds..."); - - delay(sdsInhalationSeconds * 1000); +} +void endParticulateMeasurement(double*pm25, double*pm10) { PmResult pm = sds.queryPm(); if (pm.isOk()) { double newPm25 = pm.pm25; @@ -251,26 +238,26 @@ void getParticulateData(double*pm25, double*pm10) { } else { Serial.println("Asleep"); } - Serial.println(""); + Serial.println(EMPTY_STRING); } void getWindSpeedKmPerHr(double*windSpeed) { Serial.println("Anemometer"); - Serial.println("---"); + Serial.println(SEPARATOR_LINE); setActiveMultiplexerChannel(2); uint64_t startTime = millis(); Serial.print("Start time: "); Serial.println(millis()); - Serial.println("Measure for: " + String(windMeasurementSeconds) + + Serial.println("Measure for: " + String(airMeasurementSeconds) + " seconds..."); int currentState = map(analogRead(ANALOGUE_IN), 0, 1024, 0, 1); int nextState = currentState; int stateChangeCount = 0; // One state change corresponds to 1/4 rotation - while ((uint64_t)(millis() - startTime) < windMeasurementSeconds * 1000) { + while ((uint64_t)(millis() - startTime) < airMeasurementSeconds * 1000) { nextState = map(analogRead(ANALOGUE_IN), 0, 1024, 0, 1); if (nextState != currentState) { stateChangeCount++; @@ -284,50 +271,43 @@ void getWindSpeedKmPerHr(double*windSpeed) { " state changes (1/4 rotations)"); double windSpeedKmHr = static_cast(stateChangeCount) / - static_cast(windMeasurementSeconds) * 1.2; + static_cast(airMeasurementSeconds) * 1.2; Serial.println("Wind Speed: " + String(windSpeedKmHr) + " km/hr"); - Serial.println(""); + Serial.println(EMPTY_STRING); *windSpeed = windSpeedKmHr; } void sendData(double temperature, double humidity, double pressure, - double uvIntensity, double rainfallLevel, double windSpeed, double pm25level, + double uvIntensity, double windSpeed, double pm25level, double pm10level) { + StaticJsonDocument dataJson; + dataJson["temperatureC"] = temperature; dataJson["airPressurePa"] = pressure; dataJson["humidityPercentage"] = humidity; dataJson["uvIntensityMilliwattsPerCmSq"] = uvIntensity; - dataJson["rainfallStrengthPercentage"] = rainfallLevel; dataJson["windSpeedKmPerHour"] = windSpeed; dataJson["pm25density"] = pm25level; dataJson["pm10density"] = pm10level; Serial.println("Sending data"); - Serial.println("---"); - String dataJsonOutput; - serializeJson(dataJson, dataJsonOutput); - - // todo: use the nicer http library - - if (client.connect(server, IP_PORT)) { - // Make a HTTP request: - client.println("POST /weather-station/balcony HTTP/1.0"); - client.println("Content-Type: application/json"); - client.print("Content-Length: "); - client.println(dataJsonOutput.length()); - client.println(); - client.println(dataJsonOutput); - client.println(); - client.stop(); - Serial.println("Sent."); - } else { - Serial.println("ERROR: Failed to connect"); - reboot(); - } + Serial.println(SEPARATOR_LINE); + String jsonString; + serializeJson(dataJson, jsonString); - Serial.println(""); + HTTP_CLIENT.begin(WIFI_CLIENT, String(SERVER_ADDRESS) + String(URL_PATH)); + + HTTP_CLIENT.addHeader(HTTP_CONTENT_TYPE_HEADER, HTTP_JSON_CONTENT_TYPE); + HTTP_CLIENT.addHeader(HTTP_CONTENT_LENGTH_HEADER, + String(jsonString.length())); + int result = HTTP_CLIENT.POST(jsonString); + + Serial.print("Completed with response code: "); + Serial.println(result); + + Serial.flush(); } /** @@ -357,23 +337,20 @@ int averageAnalogueRead(int pinToRead) { * System management functions */ -void reboot() { - delay(REBOOT_DELAY_MS); - Serial.println("Rebooting..."); - ESP.restart(); -} +boolean connectToWifi() { + Serial.println(SEPARATOR_LINE); -void connectToWifi() { - String wifiConnectionInfo = "Connecting to WiFi"; + WiFi.forceSleepWake(); if (WiFi.status() == WL_CONNECTED) { - return; + return true; } Serial.print("Connecting to "); Serial.println(WIFI_SSID); + + WiFi.hostname(HOSTNAME); WiFi.begin(WIFI_SSID, WIFI_PASSWORD); - WiFi.hostname(HOST_NAME); int connectAttempts = 0; int connectRetryInterval = 500; @@ -387,10 +364,13 @@ void connectToWifi() { rebootCountdown = rebootCountdown - connectRetryInterval; if (rebootCountdown < 0) { - reboot(); + Serial.println(EMPTY_STRING); + Serial.println("Failed to connect."); + return false; } } - Serial.println(""); + Serial.println(EMPTY_STRING); Serial.println("WiFi connected"); + return true; }