Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Battery powered #4

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/all-branches.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
*.iml
.idea/
.python-version
1 change: 1 addition & 0 deletions testing/anemometer/anemometer.ino
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
174 changes: 77 additions & 97 deletions weather-station.ino
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -53,7 +59,7 @@ const String HOST_NAME = "weather-station";
#include <Adafruit_BME280.h>
#include "SdsDustSensor.h"
#include <ArduinoJson.h>

#include <ESP8266HTTPClient.h>

/**
* Instruments
Expand All @@ -64,10 +70,8 @@ SdsDustSensor sds(SDS_DUST_RX, SDS_DUST_TX);
/**
* Network messages
*/
const int dataFieldsCapacity = JSON_OBJECT_SIZE(8);
StaticJsonDocument<dataFieldsCapacity> dataJson;
WiFiClient client;
IPAddress server(IP_1, IP_2, IP_3, IP_4);
WiFiClient WIFI_CLIENT;
HTTPClient HTTP_CLIENT;

/**
* Runtime parameters
Expand All @@ -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() {
Expand All @@ -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);
}
Expand All @@ -150,15 +157,15 @@ 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
sds.begin();
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) {
Expand All @@ -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<double>(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);
Expand All @@ -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;
Expand All @@ -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++;
Expand All @@ -284,50 +271,43 @@ void getWindSpeedKmPerHr(double*windSpeed) {
" state changes (1/4 rotations)");

double windSpeedKmHr = static_cast<double>(stateChangeCount) /
static_cast<double>(windMeasurementSeconds) * 1.2;
static_cast<double>(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<JSON_OBJECT_SIZE(8) + 1000> 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();
}

/**
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}