Hardware components | ||||||
| × | 3 | ||||
| × | 3 | ||||
| × | 3 | ||||
| × | 3 | ||||
| × | 3 | ||||
| × | 3 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 5 | ||||
| × | 1 | ||||
Software apps and online services | ||||||
| ||||||
| ||||||
| ||||||
| ||||||
Hand tools and fabrication machines | ||||||
|
As we all know, North Carolina’s weather can be pretty unpredictable. Especially in the Piedmont region. With all 3 of our group members living in the Piedmont region near the Blue Ridge Mountains, it is very common to see The Weather Channel say “Thunderstorms” when, in reality, it is beautiful and sunny outside. Given the crazy circumstances regarding weather in this region, our group came up with the idea to get information about the weather at the touch of your fingertips. The project included the use of three sensors; a temperature sensor, a fluid sensor, and a light sensor. So by simply mashing a button you could have access to what the temperature outside is, has it rained or how much has it rained, and if it’s night or day outside.
For the project's sake we made it to where the temperature and fluid sensors communicate with the Light sensor. Once the light sensor has processed the data it will send a signal back to each of the other sensors making their LEDs flash. All three argons have been programmed to sleep 57 minutes every hour while the remaining three minutes are used to record any changes in data. To ensure the sleep cycle remains continuous, the sleep command is sent by the light Argon to the other two Argons. This drastically increases the battery life of the argons as shown in the power calculations below.
PowerCalculations
Argon- 90 mA/hr draw
With Sleep Mode: 4.5 mA/hr
Total Run Time off Battery: 1000mA/4.5mA = 222.22 hours of runtime = 9.26 days
Solar Panel Recharges @ : 200 mA; 5V
Therefore, as long as solar panel receives bright sunshine for 1/9 days, battery will recharge and keep up
Battery- 1 amp/hour
Full battery will run argon for 11.11 hours
WebhooksWebhooks were utilized to send data from the Particle cloud to outside sources. For Thingspeak Live Graphing, Web Format type. However, for Amazon Web Services, JSON format type was used for interpretation of data on their end.
ArgonCommunication
Argon1:FluidSensor
Argon2:TemperatureSensor
Argon3:LightSensor
VideoDemonstration
LiveData
https://thingspeak.com/channels/1705506
***Dashboard***For a centralized view of all data including live graphing from Thingspeak, please use the link below! Please note, all timestamps in the dashboard have been converted to UTC time for future use.
https://soliant-fmsdev.soliant.cloud/fmi/webd/qweather
Username: guest
Password: qguest
Light Sensor
C/C++//Quintin Heizer Sunlight Sensor Code MEGR 3171 Spring 2022
//Last Updated April 20, 2022
int ledIndicator = D6; //Power Indicator
int onBoardled = D7;
int photoresistor = A3;
//int VPower = D2; //Power supplied to photoresistor
//int detectDay;
//int detectNight;
int lightState = 5;
//int solarInput = A5; //Possibly substitute as analogRead in future depnding on values. UPDATE: NOT NECESSARY 3/23/22 -QH
int transmissionLightFluid = D3;
int transmissionLightTemp = D8;
int i = 1;
int sleepMode = 0;
//NOTE THAT 3.7 V LIPO USED CONTAINS A CHARGING PROTECTION CIRCUIT. ALLOWS BATTERY TO RECEIVE 3.7-5V AND CHARGE SAFELY. THEREFORE, SOLAR PANEL CHARGING CIRCUIT W/ VOLTAGE REGULATOR IS VALID
//
// * +----------| USB |---------+
// * | O +-----+ O |
// * | [ ] RESET |
// * /--------------------| [+] 3V3 Bat[-] |------3.7 V Lipo [-]
// * [+] | [ ] MODE Bat[+] |------3.7 V Lipo [+] ---------------------------------
// * PHOTOCELL /-----| [*] GND | / \
// * [-] [S] | | [ ] A0 Lipo [+] |----------------------- L7805CV 5V Regulator |
// * | | | | [ ] A1 +-------+ EN [ ] | | | | |
// * | \ | | [ ] A2 | * | VIN[ ] | | | | |
// * | ---------/|\-----| [-] A3 | ARGON | D8 [+] |-220R-LED(GREEN,TEMP SUBSCR)\ | | | /
// * | | | [ ] A4 | | D7 [ ] | | Input GND Output[+]-
// * \ | | [ ] A5 +-------+ D6 [+] |---220R--RED_LED_INDICATOR | | |
// * \ | | [ ] D13 D5 [+] | \ / [+] [-]-------------
// * ---------------| | [ ] D12 D4 [ ] | | | | \
// * | | [ ] D11 D3 [+] |---220 OHM RESISTOR | | | \
// * | | [ ] D10 D2 [ ] | | | | | |
// * | | [ ] D9 D1 [ ] | | | SOLAR PANEL (6V MAX) |
// * | | [ ] NC D0 [ ] | LED (BLUE,SUBSCRIBE FLUID)| /
// * | | WIFI[ON] 0NFC | | | /
// * | |O O| \ | /
// * | +--------------------------+ COMMON GND | /
// * | | | /
// * \-----------------------------------------------------------------------------------
// *
//PHOTORESISTOR DATA
// CLOUDY = Analog Read of 3845 (TOO HIGH)
//CONSIDER UV SENSOR IN ADDITION||| UPDATE: Utilizing the SolarPanel as a means of detecting sunlight vs cloudy and photocell as night vs day. Easy and Clever!
void setup() {
pinMode(ledIndicator,OUTPUT); // Our LED pin is output (lighting up the LED)
pinMode(onBoardled,OUTPUT); // Our on-board LED is output as well
pinMode(photoresistor,INPUT); // Our photoresistor pin is input (reading the photoresistor)
//pinMode(VPower,OUTPUT); // The pin powering the photoresistor is output (sending out consistent power)
pinMode(transmissionLightFluid,OUTPUT);
pinMode(transmissionLightTemp,OUTPUT);
// Next, write the power of the photoresistor to be the maximum possible, which is 4095 in analog.
//digitalWrite(VPower,HIGH);
digitalWrite(onBoardled,HIGH);
delay(2000);
digitalWrite(ledIndicator,HIGH);
delay(2000);
digitalWrite(transmissionLightFluid,HIGH);
delay(2000);
digitalWrite(transmissionLightTemp,HIGH);
delay(2000);
digitalWrite(onBoardled,LOW);
delay(2000);
//digitalWrite(ledIndicator,LOW);
//delay(2000);
digitalWrite(transmissionLightFluid,LOW);
delay(2000);
digitalWrite(transmissionLightTemp,LOW);
delay(2000);
//Logan's S/N: ARNKAD132LHR9M3 DEVICE ID: e0Ofce6865bd8302f67b1c82
//UPDATE 3/23/22: I THINK THIS SUBSCRIBE CODE WORKS. NOT VERIFIED YET. UTILIZED SPECIFIC PRODUCT ID THROUGH UNCC'S PRIVATE PROXY RELAY PORT NUMBER
//Update 3/27/22: AS OF AUG 2020, ONE CAN NO LONGER PARICLE.PUBLISH PUBLICALLY. NO KNOWN WAY TO COMMUNICATE BETWEEN DIFFERENTLY OWNED/ACCOUNT LINKED DEVICES. ASK MCALPINE
}
void loop() {
digitalWrite(ledIndicator,HIGH);
delay(2000);
digitalWrite(transmissionLightFluid,HIGH);
delay(2000);
digitalWrite(transmissionLightTemp,HIGH);
delay(2000);
digitalWrite(onBoardled,LOW);
delay(2000);
//digitalWrite(ledIndicator,LOW);
//delay(2000);
digitalWrite(transmissionLightFluid,LOW);
delay(2000);
digitalWrite(transmissionLightTemp,LOW);
delay(2000);
while (i < 3) {
Particle.subscribe("rainStatus", myHandlerFLUID);
Particle.subscribe("tempData", myHandlerTEMP);
digitalWrite(ledIndicator,LOW);
delay(500);
digitalWrite(ledIndicator,HIGH);
delay(500);
//digitalWrite(onBoardled,HIGH);
//delay(100);
//digitalWrite(onBoardled,LOW);
//delay(100);
delay(15000);
int lightValue = analogRead(photoresistor);
if (lightValue>3000) {
//if (lightState!=1) {
//Particle.publish("lightStatus","Night");
//String data = String(1);
Particle.publish("lightValue", "1", PRIVATE);
lightState = 1;
//}
}
if (lightValue<500) {
//if (lightState!=2) {
//Particle.publish("lightStatus","Sunny & Clear");
//String data = String(2);
Particle.publish("lightValue", "3", PRIVATE);
lightState = 2;
//}
}
if (lightValue>500) {
if (lightValue<3000) {
//if (lightState!=3) {
//Particle.publish("lightStatus","Cloud Cover Experienced");
//String data = String(3);
Particle.publish("lightValue", "2", PRIVATE);
lightState = 3;
//The above Particle.Publish statements are publishing an event to the particle cloud with the event name "lightStatus" with the char (character-based) data "Night/Sunnny & Clear..."
//}
}
}
delay(19000);
i=i+1;
}
i=1;
lightState = 5;
if (sleepMode >= 2) {
Particle.publish("sleepMode","YES");
delay(2000);
sleepMode = 0;
delay(3000);
digitalWrite(ledIndicator,LOW);
SystemSleepConfiguration config;
config.mode(SystemSleepMode::STOP)
//.gpio(WKP, RISING)
.duration(58min);
System.sleep(config);
}
//Particle.publish("testSleepMode", String(sleepMode)); USED ONLY TO TEST FEASIBILITY OF SLEEP MODE FUNCTIONALITY
//digitalWrite(ledIndicator,LOW);
}
void myHandlerFLUID(const char *event, const char *data)
{
/* Particle.subscribe handlers are void functions, which means they don't return anything.
They take two variables-- the name of your event, and any data that goes along with your event.
In this case, the event will be "buddy_unique_event_name" and the data will be "intact" or "broken"
Since the input here is a char, we can't do
data=="intact"
or
data=="broken"
chars just don't play that way. Instead we're going to strcmp(), which compares two chars.
If they are the same, strcmp will return 0.
*/
//if (strcmp(data,"fluidLevel")=="3") {
// if Holden's ARGON outputs this data, execute the following
digitalWrite(transmissionLightFluid,HIGH);
delay(4000);
digitalWrite(transmissionLightFluid,LOW);
Particle.publish("fluidReceived","YES");
//}
sleepMode = sleepMode + 1;
}
void myHandlerTEMP(const char *event, const char *data)
{
/* Particle.subscribe handlers are void functions, which means they don't return anything.
They take two variables-- the name of your event, and any data that goes along with your event.
In this case, the event will be "buddy_unique_event_name" and the data will be "intact" or "broken"
Since the input here is a char, we can't do
data=="intact"
or
data=="broken"
chars just don't play that way. Instead we're going to strcmp(), which compares two chars.
If they are the same, strcmp will return 0.
*/
//if (strcmp(data,"fluidLevel")=="3") {
// if Logan's ARGON outputs this data, execute the following
digitalWrite(transmissionLightTemp,HIGH);
delay(4000);
digitalWrite(transmissionLightTemp,LOW);
Particle.publish("tempReceived","YES");
sleepMode = sleepMode + 1;
//}
}
int ledIndicator = D3;
int onBoardled = D7;
int FluidSensor = A3;
//int VPower = 3V3; //Power supplied to FluidSensor
//int detectFluid;
//int detectNoFluid;
//bool condition = true;
int fluidCheck = 10;
int i = 1;
//
// * +----------| USB |---------+
// * | O +-----+ O |
// * | [ ] RESET |
// * /--------------------| [+] 3V3 Bat[-] |------3.7 V Lipo [-]
// * [+] | [ ] MODE Bat[+] |------3.7 V Lipo [+] ---------------------------------
// * FLUIDSENSOR /-----| [*] GND | / \
// * [-] [S] | | [ ] A0 Lipo [+] |----------------------- L7805CV 5V Regulator |
// * | | | | [ ] A1 +-------+ EN [ ] | | | | |
// * | \ | | [ ] A2 | * | VIN[ ] | | | | |
// * | ---------/|\-----| [-] A3 | ARGON | D8 [ ] | | | | /
// * | | | [ ] A4 | | D7 [ ] | Input GND Output[+]-
// * \ | | [ ] A5 +-------+ D6 [ ] | | |
// * \ | | [ ] D13 D5 [+] | [+] [-]-------------
// * ---------------| | [ ] D12 D4 [ ] | | | \
// * | | [ ] D11 D3 [+] |---220 OHM RESISTOR | | \
// * | | [ ] D10 D2 [ ] | | | | |
// * | | [ ] D9 D1 [ ] | | SOLAR PANEL (6V MAX) |
// * | | [ ] NC D0 [ ] | LED (GREEN) /
// * | | WIFI[ON] 0NFC | | /
// * | |O O| \ /
// * | +--------------------------+ COMMON GND /
// * | | /
// * \-----------------------------------------------------------------------------------
// *
//FluidSensor DATA
// 0 inches = analog read (0)
// 0-1/4 inches = analog read (0-550)
// 1/4-1/2 inches = analog read (550-690)
// 1/2-3/4 inches = analog read (690-750)
// 3/4-1 inches = analog read (750-790)
// 1-1 1/4 inches = analog read (790-830)
// 1 1/4-1 1/2 inches = analog read (830-850)
//NOTE: 7 ITERATIONS OF FLUID SENSOR
void setup() {
pinMode(ledIndicator,OUTPUT); // Our LED pin is output (lighting up the LED)
pinMode(onBoardled,OUTPUT); // Our on-board LED is output as well
pinMode(FluidSensor,INPUT); // Our FluidSensor pin is input (reading the FluidSensor)
//pinMode(VPower,OUTPUT); // The pin powering the FluidSensor is output (sending out consistent power)
// Next, write the power of the FluidSensor to be the maximum possible, which is 4095 in analog.
//digitalWrite(VPower,HIGH);
digitalWrite(ledIndicator,HIGH);
delay(2000);
digitalWrite(ledIndicator,LOW);
delay(2000);
digitalWrite(ledIndicator,HIGH);
delay(10000);
//digitalWrite(onBoardled,LOW);
//delay(2000);
//digitalWrite(ledIndicator,LOW);
//delay(2000);
}
void loop() {
digitalWrite(ledIndicator,HIGH);
delay(12000);
while (i < 3) {
//digitalWrite(onBoardled,HIGH);
//delay(100);
//digitalWrite(onBoardled,LOW);
// delay(100);
Particle.subscribe("fluidReceived",myHandler);
int fluidValue = analogRead(FluidSensor);
delay(15000);
delay(15000); //Sync line up
//Particle.publish("testValue", String(fluidValue));
if (fluidValue == 0) {
//if (fluidCheck != 1) {
Particle.publish("rainStatus","0 inches");
fluidCheck = 1;
//}
}
if (fluidValue > 0) {
if (fluidValue < 550) {
//if (fluidCheck != 2) {
Particle.publish("rainStatus","0.25");
fluidCheck = 2;
//}
}
}
if (fluidValue > 550) {
if (fluidValue < 690) {
//if (fluidCheck != 3) {
Particle.publish("rainStatus","0.5");
fluidCheck = 3;
//}
}
}
if (fluidValue > 690) {
if (fluidValue < 750) {
//if (fluidCheck != 4) {
Particle.publish("rainStatus","0.75");
fluidCheck = 4;
//}
}
}
if (fluidValue > 750) {
if (fluidValue < 790) {
//if (fluidCheck != 5) {
Particle.publish("rainStatus","1");
fluidCheck = 5;
//}
}
}
if (fluidValue > 790) {
if (fluidValue < 830) {
//if (fluidCheck != 6) {
Particle.publish("rainStatus","1.25");
fluidCheck = 6;
//}
}
}
if (fluidValue > 830) {
if (fluidValue < 850) {
//if (fluidCheck != 7) {
Particle.publish("rainStatus","1.5");
fluidCheck = 7;
//}
}
}
i = i + 1;
delay(5000);
}
fluidCheck = 10;
i = 1;
Particle.subscribe("sleepMode",sleepHandler);
}
void myHandler(const char *event, const char *data)
{
/* Particle.subscribe handlers are void functions, which means they don't return anything.
They take two variables-- the name of your event, and any data that goes along with your event.
In this case, the event will be "buddy_unique_event_name" and the data will be "intact" or "broken"
Since the input here is a char, we can't do
data=="intact"
or
data=="broken"
chars just don't play that way. Instead we're going to strcmp(), which compares two chars.
If they are the same, strcmp will return 0.
*/
//if (strcmp(data,"fluidLevel")=="3") {
// if Logan's ARGON outputs this data, execute the following
digitalWrite(ledIndicator,HIGH);
delay(1000);
digitalWrite(ledIndicator,LOW);
delay(1000);
digitalWrite(ledIndicator,HIGH);
delay(1000);
digitalWrite(ledIndicator,LOW);
delay(1000);
digitalWrite(ledIndicator,HIGH);
}
void sleepHandler(const char *event, const char *data)
{
/* Particle.subscribe handlers are void functions, which means they don't return anything.
They take two variables-- the name of your event, and any data that goes along with your event.
In this case, the event will be "buddy_unique_event_name" and the data will be "intact" or "broken"
Since the input here is a char, we can't do
data=="intact"
or
data=="broken"
chars just don't play that way. Instead we're going to strcmp(), which compares two chars.
If they are the same, strcmp will return 0.
*/
//if (strcmp(data,"fluidLevel")=="3") {
// if Logan's ARGON outputs this data, execute the following
delay(5000);
digitalWrite(ledIndicator,LOW);
SystemSleepConfiguration config;
config.mode(SystemSleepMode::STOP)
//.gpio(WKP, RISING)
.duration(58min);
System.sleep(config);
}
// This #include statement was automatically added by the Particle IDE.
#include <Adafruit_DHT.h>
#include "Adafruit_DHT.h"
// Example testing sketch for various DHT humidity/temperature sensors
// Written by ladyada, public domain
#define DHTPIN D6 // what pin we're connected to
// Uncomment whatever type you're using!
#define DHTTYPE DHT11 // DHT 11
//#define DHTTYPE DHT22 // DHT 22 (AM2302)
//#define DHTTYPE DHT21 // DHT 21 (AM2301)
// Connect pin 1 (on the left) of the sensor to +5V
// Connect pin 2 of the sensor to whatever your DHTPIN is
// Connect pin 4 (on the right) of the sensor to GROUND
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor
//
// * +----------| USB |---------+
// * | O +-----+ O |
// * | [ ] RESET |
// * /--------------------| [+] 3V3 Bat[-] |------3.7 V Lipo [-]
// * [+] | [ ] MODE Bat[+] |------3.7 V Lipo [+] ---------------------------------
// * DHT111 /-----| [*] GND | / \
// * [-] [S] | | [ ] A0 Lipo [+] |----------------------- L7805CV 5V Regulator |
// * | | | | [ ] A1 +-------+ EN [ ] | | | | |
// * | D6 | | [ ] A2 | * | VIN[ ] | | | | |
// * | | | [-] A3 | ARGON | D8 [ ] | | | | /
// * | | | [ ] A4 | | D7 [ ] | Input GND Output[+]-
// * \ | | [ ] A5 +-------+ D6 [+] |---[S,DHT11] | |
// * \ | | [ ] D13 D5 [ ] | [+] [-]-------------
// * ---------------| | [ ] D12 D4 [ ] | | | \
// * | | [ ] D11 D3 [+] |---220 OHM RESISTOR | | \
// * | | [ ] D10 D2 [ ] | | | | |
// * | | [ ] D9 D1 [ ] | | SOLAR PANEL (6V MAX) |
// * | | [ ] NC D0 [ ] | LED (GREEN) /
// * | | WIFI[ON] 0NFC | | /
// * | |O O| \ /
// * | +--------------------------+ COMMON GND /
// * | | /
// * \-----------------------------------------------------------------------------------
// *
DHT dht(DHTPIN, DHTTYPE);
int ledIndicator = D2;
void setup() {
pinMode(ledIndicator,OUTPUT);
Serial.begin(9600);
Serial.println("DHTxx test!");
dht.begin();
digitalWrite(ledIndicator,HIGH);
delay(2000);
digitalWrite(ledIndicator,LOW);
delay(2000);
digitalWrite(ledIndicator,HIGH);
delay(10000);
}
void loop() {
int i = 1;
//digitalWrite(ledIndicator,LOW);
digitalWrite(ledIndicator,HIGH);
delay(12000);
while (i < 3) {
Particle.subscribe("tempReceived",myHandler);
int temperatureData = 0;
int humidityData = 0;
// Wait a few seconds between measurements.
delay(5000);
// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a
// very slow sensor)
float h = dht.getHumidity();
// Read temperature as Celsius
float t = dht.getTempCelcius();
// Read temperature as Farenheit
float f = dht.getTempFarenheit();
// Check if any reads failed and exit early (to try again).
if (isnan(h) || isnan(t) || isnan(f)) {
Serial.println("Failed to read from DHT sensor!");
//Particle.publish("ERROR","DHT11 Read Error"); //Solved possible error reading via while loop
return;
}
delay(5000);
//f = f-20;
temperatureData = round((f*100)/100);
humidityData = round((h*100)/100);
Particle.publish("tempData", String(temperatureData), PRIVATE);
delay(15000);
Particle.publish("humidityData", String(humidityData) , PRIVATE);
// Compute heat index
// Must send in temp in Fahrenheit!
float hi = dht.getHeatIndex();
float dp = dht.getDewPoint();
float k = dht.getTempKelvin();
Serial.print("Humid: ");
Serial.print(h);
Serial.print("% - ");
Serial.print("Temp: ");
Serial.print(t);
Serial.print("*C ");
Serial.print(f);
Serial.print("*F ");
Serial.print(k);
Serial.print("*K - ");
Serial.print("DewP: ");
Serial.print(dp);
Serial.print("*C - ");
Serial.print("HeatI: ");
Serial.print(hi);
Serial.println("*C");
Serial.println(Time.timeStr());
delay(10000);
i = i + 1;
}
i = 1;
Particle.subscribe("sleepMode",sleepHandler);
}
void myHandler(const char *event, const char *data)
{
/* Particle.subscribe handlers are void functions, which means they don't return anything.
They take two variables-- the name of your event, and any data that goes along with your event.
In this case, the event will be "buddy_unique_event_name" and the data will be "intact" or "broken"
Since the input here is a char, we can't do
data=="intact"
or
data=="broken"
chars just don't play that way. Instead we're going to strcmp(), which compares two chars.
If they are the same, strcmp will return 0.
*/
//if (strcmp(data,"fluidLevel")=="3") {
// if Logan's ARGON outputs this data, execute the following
digitalWrite(ledIndicator,HIGH);
delay(1000);
digitalWrite(ledIndicator,LOW);
delay(1000);
digitalWrite(ledIndicator,HIGH);
delay(1000);
digitalWrite(ledIndicator,LOW);
delay(1000);
digitalWrite(ledIndicator,HIGH);
}
void sleepHandler(const char *event, const char *data)
{
/* Particle.subscribe handlers are void functions, which means they don't return anything.
They take two variables-- the name of your event, and any data that goes along with your event.
In this case, the event will be "buddy_unique_event_name" and the data will be "intact" or "broken"
Since the input here is a char, we can't do
data=="intact"
or
data=="broken"
chars just don't play that way. Instead we're going to strcmp(), which compares two chars.
If they are the same, strcmp will return 0.
*/
//if (strcmp(data,"fluidLevel")=="3") {
// if Logan's ARGON outputs this data, execute the following
delay(5000);
digitalWrite(ledIndicator,LOW);
SystemSleepConfiguration config;
config.mode(SystemSleepMode::STOP)
//.gpio(WKP, RISING)
.duration(58min);
System.sleep(config);
}
Comments