Something went wrong on our end
-
Callum Inglis authoredCallum Inglis authored
ESP8266_Transmitter.ino 8.96 KiB
/* =========================================================================================
*
* CS408 Environmental Monitoring Independent of Existing Infrastructure
* Copyright (C) 2021 Callum Inglis
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Contact: Callum.Inglis.2018(at)uni.strath.ac.uk
*
* =========================================================================================
*
* Libraries Used
* ArduinoJson v6 Library - https://arduinojson.org/v6/doc/ (https://github.com/sandeepmistry/arduino-LoRa/blob/master/LICENSE)
* LoRa Library - https://github.com/sandeepmistry/arduino-LoRa/blob/master/API.md (https://github.com/bblanchon/ArduinoJson/blob/6.x/LICENSE.md)
* SHTSensor - https://github.com/Sensirion/arduino-sht (https://github.com/Sensirion/arduino-sht/blob/master/LICENSE)
*
* =========================================================================================
*/
#include <SPI.h>
#include <Wire.h>
#include <LoRa.h>
#include <SoftwareSerial.h>
#include <ArduinoJson.h>
#include "SHTSensor.h"
// Lora Config
#define ss 16 // Physical Pin 16 = D0 (Default is Physical Pin 5)
#define rst 0
#define dio0 15 // Physical Pin 15 = D8 (Default is Physical Pin 4)
static const int loraSpreadingFactor = 7;
static const int loraSignalBandwidth = 125E3;
static const int loraFrequency = 433E6;
// Serial PMS Config
static const int RXPin = 4, TXPin = 3;
static const int pollingFrequency = 2500; // ms
// Temp / Humidity Sensor
SHTSensor sht;
// Particle Sensor Serial
SoftwareSerial pmsSerial(2, 3);
// LoRa Message Tracking
byte localAddress = 0xBB;
byte destination = 0xFF;
byte msgCount = 0;
// Sensor Values - Temp / Humidity
double temperature;
double humidity;
double avgTemperature = 0;
double avgHumidity = 0;
// Sensor Values - Co2
byte co2;
double avgCo2 = 0;
// Sensor Values - Particles
uint32_t ppm10;
uint32_t ppm25;
uint32_t ppm100;
uint32_t avgPpm10 = 0;
uint32_t avgPpm25 = 0;
uint32_t avgPpm100 = 0;
// Partial Sensor Data
struct pms5003data {
uint16_t framelen;
uint16_t pm10_standard, pm25_standard, pm100_standard;
uint16_t pm10_env, pm25_env, pm100_env;
uint16_t particles_03um, particles_05um, particles_10um, particles_25um, particles_50um, particles_100um;
uint16_t unused;
uint16_t checksum;
};
struct pms5003data data;
int eventCount = 0; //counts the loop, which iterates every second
int secsToPost = 1; //number of seconds to wait - also the divisor for avg
/**
* Setup Humidity / Temperature Sensor
*/
bool setupSHT() {
Wire.begin();
if (!sht.init()) {
Serial.println("[-] SHT Init Failed");
return false;
}
sht.setAccuracy(SHTSensor::SHT_ACCURACY_MEDIUM);
return true;
}
double getTemperature() {
double t = -1;
if (sht.readSample()) {
t = sht.getTemperature();
temperature += t;
}
return t; // -1 on error TODO Make this better!
}
double getHumidity() {
double h = -1;
if (sht.readSample()) {
h = sht.getHumidity();
humidity += h;
}
return h; // -1 on error
}
bool setupLoRa() {
LoRa.setPins(ss, rst, dio0);
if (!LoRa.begin(loraFrequency)) {
Serial.println("[-] Fatal. Starting LoRa failed!");
return false;
}
LoRa.setSpreadingFactor(loraSpreadingFactor);
LoRa.setSignalBandwidth(loraSignalBandwidth);
Serial.println("[+] LoRa Initialized OK!");
return true;
}
/**
* Get data from PMS Partical Sensor
* @param Stream s PMS Serial Connection
* @modifies struct data PMS Sensor Data
* @returns boolean Data Read Success status
*/
boolean readPMSdata(Stream *s) {
if (!s->available()) {
return false;
}
// Read a byte at a time until we get to the special '0x42' start-byte
if (s->peek() != 0x42) {
s->read();
return false;
}
// Now read all 32 bytes
if (s->available() < 32) {
return false;
}
uint8_t buffer[32];
uint16_t sum = 0;
s->readBytes(buffer, 32);
// get checksum ready
for (uint8_t i=0; i<30; i++) {
sum += buffer[i];
}
// The data comes in endian'd, this solves it so it works on all platforms
uint16_t buffer_u16[15];
for (uint8_t i=0; i<15; i++) {
buffer_u16[i] = buffer[2 + i*2 + 1];
buffer_u16[i] += (buffer[2 + i*2] << 8);
}
// Struct it
memcpy((void *)&data, (void *)buffer_u16, 30);
if (sum != data.checksum) {
Serial.println("Checksum failure");
return false;
}
return true;
}
void setup() {
delay(1000);
Serial.begin(115200); // Console Debug
Serial.println("[+] Transmitter Node");
pmsSerial.begin(9600); // Partical Sensor
// Setup Sensors
if (!setupSHT()) { while(1); } // Temp/Humidity - Die on Error
// Setup LoRa
if (!setupLoRa()) { while(1); } // Die on error
}
void loop() {
// TODO Gather Sensor Data
if (readPMSdata(&pmsSerial)) {
Serial.println();
Serial.println("---------------------------------------");
Serial.println("Concentration Units (standard)");
Serial.print("PM 1.0: "); Serial.print(data.pm10_standard);
Serial.print("\t\tPM 2.5: "); Serial.print(data.pm25_standard);
Serial.print("\t\tPM 10: "); Serial.println(data.pm100_standard);
Serial.println("---------------------------------------");
Serial.println("Concentration Units (environmental)");
Serial.print("PM 1.0: "); Serial.print(data.pm10_env);
Serial.print("\t\tPM 2.5: "); Serial.print(data.pm25_env);
Serial.print("\t\tPM 10: "); Serial.println(data.pm100_env);
Serial.println("---------------------------------------");
Serial.print("Particles > 0.3um / 0.1L air:"); Serial.println(data.particles_03um);
Serial.print("Particles > 0.5um / 0.1L air:"); Serial.println(data.particles_05um);
Serial.print("Particles > 1.0um / 0.1L air:"); Serial.println(data.particles_10um);
Serial.print("Particles > 2.5um / 0.1L air:"); Serial.println(data.particles_25um);
Serial.print("Particles > 5.0um / 0.1L air:"); Serial.println(data.particles_50um);
Serial.print("Particles > 10.0 um / 0.1L air:"); Serial.println(data.particles_100um);
Serial.println("---------------------------------------");
Serial.print("Temperature: "); Serial.println(getTemperature());
Serial.print("Humidity: "); Serial.println(getHumidity());
eventCount++;
Serial.println("-------------------" + String(eventCount) + "--------------------");
// Choose Standard (_standard) or Environmental (_env)
ppm10 = ppm10 + data.pm10_standard;
ppm25 = ppm25 + data.pm25_standard;
ppm100 = ppm100 + data.pm100_standard;
//ppm10 = ppm10 + data.pm10_env;
//ppm25 = ppm25 + data.pm25_env;
//ppm100 = ppm100 + data.pm100_env;
if (eventCount == secsToPost) {
// Average Values over recording period
avgPpm10 = ppm10 / secsToPost;
avgPpm25 = ppm25 / secsToPost;
avgPpm100 = ppm100 / secsToPost;
avgTemperature = temperature / secsToPost;
avgHumidity = humidity / secsToPost;
// TODO Transmit Sensor Data
Serial.print("Avg ppm10: "); Serial.println(avgPpm10);
Serial.print("Avg ppm25: "); Serial.println(avgPpm25);
Serial.print("Avg ppm100: "); Serial.println(avgPpm100);
Serial.print("Avg Temperature: "); Serial.println(avgTemperature);
Serial.print("Avg Humidity: "); Serial.println(avgHumidity);
// LORA SEND
DynamicJsonDocument doc(1024);
doc["sensorID"] = "abc";
doc["samplePeriod"] = secsToPost;
JsonObject ppm = doc.createNestedObject("ppm");
ppm["10"] = avgPpm10;
ppm["25"] = avgPpm25;
ppm["100"] = avgPpm100;
doc["temperature"] = avgTemperature;
doc["humidity"] = avgHumidity;
LoRa.beginPacket();
//LoRa.print(avgPpm10); LoRa.print(',');
//LoRa.print(avgPpm25); LoRa.print(',');
//LoRa.print(avgPpm100); LoRa.print(',');
//LoRa.print(avgTemperature); LoRa.print(',');
//LoRa.print(avgHumidity);
//LoRa.write(localAddress);
// LoRa.write(msgCount);
//LoRa.write(outgoing.length());
//LoRa.print(outgoing);
serializeJson(doc, LoRa);
LoRa.endPacket();
Serial.println("Packet Sent\n");
// Reset Loop Values
ppm10 = 0;
ppm25 = 0;
ppm100 = 0;
temperature = 0;
humidity = 0;
eventCount = 0;
Serial.println("---------------+++++-------------------");
}
}
msgCount++;
//delay(pollingFrequency);
}