196 lines
5.6 KiB
C++
196 lines
5.6 KiB
C++
/*************************************************************
|
|
This is a DEMO sketch which works with Blynk myPlant app and
|
|
showcases how your app made with Blynk can work
|
|
|
|
You can download free app here:
|
|
iOS: https://itunes.apple.com/us/app/blynk-myplant/id1163620518?mt=8
|
|
Android: https://play.google.com/store/apps/details?id=cc.blynk.appexport.demo
|
|
|
|
If you would like to add these features to your product,
|
|
please contact Blynk for Businesses:
|
|
|
|
http://www.blynk.io/
|
|
|
|
*************************************************************/
|
|
|
|
#define USE_SPARKFUN_BLYNK_BOARD // Uncomment the board you are using
|
|
//#define USE_NODE_MCU_BOARD // Comment out the boards you are not using
|
|
//#define USE_WITTY_CLOUD_BOARD
|
|
//#define USE_CUSTOM_BOARD // For all other ESP8266-based boards -
|
|
// see "Custom board configuration" in Settings.h
|
|
|
|
#define APP_DEBUG // Comment this out to disable debug prints
|
|
|
|
#define BLYNK_PRINT Serial
|
|
|
|
#include "BlynkProvisioning.h"
|
|
|
|
void setup() {
|
|
delay(500);
|
|
Serial.begin(115200);
|
|
|
|
/**************************************************************
|
|
*
|
|
* Workflow to connect the device to WiFi network.
|
|
* Here is how it works:
|
|
* 1. At the first start hardware acts as an Access Point and
|
|
* broadcasts it's own WiFi.
|
|
* 2. myPlant smartphone app connects to this Access Point
|
|
* 3. myPlant smartphone app request new Auth Token and passes
|
|
* it together with user's WiFi SSID and password
|
|
* 4. Hardware saves this information to EEPROM
|
|
* 5. Hardware reboots and now connects to user's WiFi Network
|
|
* 6. Hardware connects to Blynk Cloud and is ready to work with app
|
|
*
|
|
* Next time the hardware reboots, it will use the same configuration
|
|
* to connect. User can RESET the board and re-initiate provisioning
|
|
*
|
|
* Explore the Settings.h for parameters
|
|
*
|
|
**************************************************************/
|
|
|
|
BlynkProvisioning.begin();
|
|
|
|
example_init(); // Initialize this example
|
|
}
|
|
|
|
void loop() {
|
|
// This handles the network and cloud connection
|
|
BlynkProvisioning.run();
|
|
|
|
// Run this example periodic actions
|
|
example_run();
|
|
}
|
|
|
|
|
|
/**************************************************************
|
|
*
|
|
* myPlant example App code
|
|
*
|
|
* The following code simulates plant watering system
|
|
*
|
|
**************************************************************/
|
|
|
|
BlynkTimer timer; // Initiating timer to perform repeating event
|
|
|
|
static int sensorSoilMoisture = 60;
|
|
static int sensorAirHumidity = 50;
|
|
static int wateringAmount = 5;
|
|
static int wateringTimer = -1;
|
|
static bool isNotificationSent = false;
|
|
|
|
// Getting data from "Set watering amount" slider
|
|
BLYNK_WRITE(V5) {
|
|
wateringAmount = param.asInt();
|
|
DEBUG_PRINT(String("Watering amount: ") + wateringAmount);
|
|
}
|
|
|
|
// Getting data from "Start Watering" button
|
|
BLYNK_WRITE(V6) {
|
|
if (param.asInt() == 1) {
|
|
// If watering started -> start simulating watering
|
|
timer.enable(wateringTimer);
|
|
DEBUG_PRINT("Watering started by user");
|
|
} else {
|
|
// If watering stopped -> stop simulating watering
|
|
timer.disable(wateringTimer);
|
|
DEBUG_PRINT("Watering stopped by user");
|
|
}
|
|
}
|
|
|
|
// When device starts ->
|
|
// sync watering switch button status
|
|
// and watering amount level from the cloud (last App value)
|
|
BLYNK_CONNECTED() {
|
|
Blynk.syncVirtual(V5, V6);
|
|
}
|
|
|
|
// This is a sinusoidal function used for simulations
|
|
float sinusoidal(float minv, float maxv, float period) {
|
|
float amp = (maxv - minv) / 2.0;
|
|
float med = minv + amp;
|
|
return med + amp * sin((M_PI * 2 * millis()) / period);
|
|
}
|
|
|
|
// Simulating values jittering
|
|
float randomize(float minv, float maxv) {
|
|
return float(random(minv * 1000, maxv * 1000)) / 1000;
|
|
}
|
|
|
|
|
|
void example_init() {
|
|
|
|
// Update sensors each 3 seconds
|
|
timer.setInterval(3000L, []() {
|
|
// Soil moisture
|
|
if (sensorSoilMoisture < 33) {
|
|
Blynk.virtualWrite(V1, "DRY");
|
|
} else if (sensorSoilMoisture > 33) {
|
|
Blynk.virtualWrite(V1, "MOIST");
|
|
} else {
|
|
Blynk.virtualWrite(V1, "WET");
|
|
}
|
|
|
|
float dayPeriod = 3.0 * 60 * 1000;
|
|
|
|
// Light level
|
|
int light = sinusoidal(5, 95, dayPeriod);
|
|
if (light < 33) {
|
|
Blynk.virtualWrite(V2, "LOW");
|
|
} else if (light > 33) {
|
|
Blynk.virtualWrite(V2, "GOOD");
|
|
} else {
|
|
Blynk.virtualWrite(V2, "MED");
|
|
}
|
|
|
|
// Temperature
|
|
Blynk.virtualWrite(V3, sinusoidal(18, 23, dayPeriod) + randomize(-1.0, 1.0));
|
|
});
|
|
|
|
// Humidity updates at a different rate (5s)
|
|
timer.setInterval(5000L, []() {
|
|
sensorAirHumidity += random (-5, +5);
|
|
sensorAirHumidity = constrain(sensorAirHumidity, 30, 90);
|
|
Blynk.virtualWrite(V4, sensorAirHumidity);
|
|
});
|
|
|
|
// Soil Moisture decreases 3% every second
|
|
timer.setInterval(1000L, []() {
|
|
sensorSoilMoisture -= 3;
|
|
sensorSoilMoisture = constrain(sensorSoilMoisture, 7, 85);
|
|
|
|
if (sensorSoilMoisture < 20) {
|
|
if (isNotificationSent == false) {
|
|
Blynk.email("myPlant notification", "Your plant is thirsty!");
|
|
isNotificationSent = true;
|
|
DEBUG_PRINT("Email notification sent");
|
|
}
|
|
}
|
|
});
|
|
|
|
// Simulate watering process
|
|
wateringTimer = timer.setInterval(1000L, []() {
|
|
sensorSoilMoisture += wateringAmount;
|
|
sensorSoilMoisture = constrain(sensorSoilMoisture, 7, 85);
|
|
|
|
if (sensorSoilMoisture > 30) {
|
|
isNotificationSent = false;
|
|
}
|
|
if (sensorSoilMoisture >= 85) {
|
|
// Stop watering
|
|
timer.disable(wateringTimer);
|
|
// Update "Start Watering" button widget state
|
|
Blynk.virtualWrite(V6, 0);
|
|
|
|
DEBUG_PRINT("Watering stopped automatically");
|
|
}
|
|
});
|
|
timer.disable(wateringTimer);
|
|
|
|
}
|
|
|
|
void example_run() {
|
|
timer.run();
|
|
}
|
|
|