I am not sure why this case happens, so I have attached my code and also the serial monitor output here for your guidance. Btw, I set set the time for getting sensors data for every 10s on MEGA, while every 30s on ESP for updating the parameters to the RainMaker.
Code for Bluno MEGA
Code: Select all
#include <OneWire.h>
#include <DallasTemperature.h>
#include "DFRobot_PH.h"
#include <EEPROM.h>
#include "DFRobot_EC.h"
#include <Arduino.h>
#define ONE_WIRE_BUS 2
#define echoPin 3
#define trigPin 4
#define EC_PIN A0
#define DO_PIN A1
#define PH_PIN A2
#define orpPin A3
//DO Sensor
#define VREF 5000
#define ADC_RES 1024
#define READ_TEMP (sensors.getTempCByIndex(0))
#define CAL1_V (2949) //mv
#define CAL1_T (26) //℃
#define CAL2_V (332) //mv
#define CAL2_T (15) //℃
//ORP Sensor
#define VOLTAGE 5.00
#define OFFSET 2
#define LED 13
//Temperature Sensor
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
//Water Level Sensor
long duration;
int distance;
int TankDepth = 31;
int WaterLevel;
//Soil Moisture Sensor
const int AirValue = 609;
const int WaterValue = 291;
int soilMoistureValue = 0;
int soilmoisturepercent = 0;
//pH & EC Sensor
float voltagePH,voltageEC,phValue,ecValue,temperature = 25;
DFRobot_PH ph;
DFRobot_EC ec;
//DO Sensor
const uint16_t DO_Table[41] = {
14460, 14220, 13820, 13440, 13090, 12740, 12420, 12110, 11810, 11530,
11260, 11010, 10770, 10530, 10300, 10080, 9860, 9660, 9460, 9270,
9080, 8900, 8730, 8570, 8410, 8250, 8110, 7960, 7820, 7690,
7560, 7430, 7300, 7180, 7070, 6950, 6840, 6730, 6630, 6530, 6410};
uint8_t Temperaturet;
uint16_t ADC_Raw;
uint16_t ADC_Voltage;
uint16_t DO;
int16_t readDO(uint32_t voltage_mv, uint8_t temperature_c)
{
#if TWO_POINT_CALIBRATION == 0
uint16_t V_saturation = (uint32_t)CAL1_V + (uint32_t)35 * temperature_c - (uint32_t)CAL1_T * 35;
return (voltage_mv * DO_Table[temperature_c] / V_saturation);
#else
uint16_t V_saturation = (int16_t)((int8_t)temperature_c - CAL2_T) * ((uint16_t)CAL1_V - CAL2_V) / ((uint8_t)CAL1_T - CAL2_T) + CAL2_V;
return (voltage_mv * DO_Table[temperature_c] / V_saturation);
#endif
}
//ORP Sensor
double orpValue;
#define ArrayLenth 40
int orpArray[ArrayLenth];
int orpArrayIndex=0;
double avergearray(int* arr, int number){
int i;
int max,min;
double avg;
long amount=0;
if(number<=0){
printf("Error number for the array to avraging!/n");
return 0;
}
if(number<5){ //less than 5, calculated directly statistics
for(i=0;i<number;i++){
amount+=arr[i];
}
avg = amount/number;
return avg;
}else{
if(arr[0]<arr[1]){
min = arr[0];max=arr[1];
}
else{
min=arr[1];max=arr[0];
}
for(i=2;i<number;i++){
if(arr[i]<min){
amount+=min; //arr<min
min=arr[i];
}else {
if(arr[i]>max){
amount+=max; //arr>max
max=arr[i];
}else{
amount+=arr[i]; //min<=arr<=max
}
}//if
}//for
avg = (double)amount/(number-2);
}//if
return avg;
}
void setup() {
Serial.begin(115200);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
pinMode(LED,OUTPUT);
ph.begin();
ec.begin();
sensors.begin();
}
void loop() {
Serial.println("System Condition:");
// Temperature Sensor
sensors.requestTemperatures();
Serial.print("Temperature is: ");
Serial.println(sensors.getTempCByIndex(0)+ String("℃"));
// Ultrasonic Sensor
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = duration * 0.034 / 2;
WaterLevel = TankDepth - distance;
Serial.print("Water level: ");
Serial.print(WaterLevel);
Serial.println(" cm");
// Soil Moisture Sensor
soilMoistureValue = analogRead(A4);
Serial.print("Soil Moisture Percent: ");
soilmoisturepercent = map(soilMoistureValue, AirValue, WaterValue, 0, 100);
if(soilmoisturepercent >= 100)
{
Serial.println("100 %");
}
else if(soilmoisturepercent <=0)
{
Serial.println("0 %");
}
else if(soilmoisturepercent >0 && soilmoisturepercent < 100)
{
Serial.print(soilmoisturepercent);
Serial.println("%");
}
//pH & EC Sensor
char cmd[10];
static unsigned long timepoint = millis();
if(millis()-timepoint>1000U){ //time interval: 1s
timepoint = millis();
//temperature = readTemperature(); // read your temperature sensor to execute temperature compensation
voltagePH = analogRead(PH_PIN)/1024.0*5000; // read the ph voltage
phValue = ph.readPH(voltagePH,temperature); // convert voltage to pH with temperature compensation
Serial.print("pH: ");
Serial.println(phValue,2);
voltageEC = analogRead(EC_PIN)/1024.0*5000;
ecValue = ec.readEC(voltageEC,temperature); // convert voltage to EC with temperature compensation
Serial.print("EC: ");
Serial.print(ecValue,2);
Serial.println(" ms/cm");
}
if(readSerial(cmd)){
strupr(cmd);
if(strstr(cmd,"PH")){
ph.calibration(voltagePH,temperature,cmd); //PH calibration process by Serail CMD
}
if(strstr(cmd,"EC")){
ec.calibration(voltageEC,temperature,cmd); //EC calibration process by Serail CMD
}
}
//DO Sensor
Temperaturet = (uint8_t)READ_TEMP;
ADC_Raw = analogRead(DO_PIN);
ADC_Voltage = uint32_t(VREF) * ADC_Raw / ADC_RES;
Serial.println("DO: " + String(readDO(ADC_Voltage, Temperaturet)) + " μg/L");
//ORP Sensor
static unsigned long orpTimer=millis(); //analog sampling interval
static unsigned long printTime=millis();
if(millis() >= orpTimer)
{
orpTimer=millis()+20;
orpArray[orpArrayIndex++]=analogRead(orpPin); //read an analog value every 20ms
if (orpArrayIndex==ArrayLenth) {
orpArrayIndex=0;
}
orpValue=((30*(double)VOLTAGE*1000)-(75*avergearray(orpArray, ArrayLenth)*VOLTAGE*1000/1024))/75-OFFSET;
//convert the analog value to orp according the circuit
}
if(millis() >= printTime) //Every 800 milliseconds, print a numerical, convert the state of the LED indicator
{
printTime=millis()+800;
Serial.print("ORP: ");
Serial.print((int)orpValue);
Serial.println(" mV");
digitalWrite(LED,1-digitalRead(LED));
}
Serial.println(" ");
delay(3000);
}
int i = 0;
bool readSerial(char result[]){
while(Serial.available() > 0){
char inChar = Serial.read();
if(inChar == '\n'){
result[i] = '\0';
Serial.flush();
i=0;
return true;
}
if(inChar != '\r'){
result[i] = inChar;
i++;
}
delay(1);
}
return false;
}
float readTemperature()
{
sensors.requestTemperatures();
}
Code for ESP32C3
Code: Select all
#include "RMaker.h"
#include "WiFi.h"
#include "WiFiProv.h"
#include <wifi_provisioning/manager.h>
//Data Transfer Pins
#define RXp 20
#define TXp 21
// Set Defalt Values
#define DEFAULT_RELAY_MODE true
#define DEFAULT_Temperature 0
#define DEFAULT_WaterLevel 10
#define DEFAULT_pH 7
#define DEFAULT_EC 0
#define DEFAULT_ORP 0
#define DEFAULT_DO 0
// BLE Credentils
const char *service_name = "AB_1";
const char *pop = "1234567";
// GPIO
static uint8_t gpio_reset = 9;
static uint8_t relay = 7;
bool relay_state = true;
bool wifi_connected = 0;
//Timer
volatile int interruptCounter;
int totalInterruptCounter;
hw_timer_t * timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
bool esp_rmaker_time_check();
void IRAM_ATTR onTimer() {
portENTER_CRITICAL_ISR(&timerMux);
interruptCounter++;
portEXIT_CRITICAL_ISR(&timerMux);
}
//------------------------------------------- Declaring Devices -----------------------------------------------------//
//The framework provides some standard device types like switch, lightbulb, fan, temperature sensor.
static TemperatureSensor temperature_sensor("Temperature");
static Device ultrasonic_sensor("Water Level");
static Device pH_sensor("pH");
static Device EC_sensor("Electro-Conductivity");
static Device ORP_sensor("Oxidation-Reduction-Potential");
static Device DO_sensor("Dissolved-Oxygen");
static Switch my_switch("Heater", &relay);
void sysProvEvent(arduino_event_t *sys_event)
{
switch (sys_event->event_id) {
case ARDUINO_EVENT_PROV_START:
#if CONFIG_IDF_TARGET_ESP32S2
Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on SoftAP\n", service_name, pop);
printQR(service_name, pop, "softap");
#else
Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on BLE\n", service_name, pop);
printQR(service_name, pop, "ble");
#endif
break;
case ARDUINO_EVENT_WIFI_STA_CONNECTED:
Serial.printf("\nConnected to Wi-Fi!\n");
wifi_connected = 1;
delay(500);
break;
case ARDUINO_EVENT_PROV_CRED_RECV: {
Serial.println("\nReceived Wi-Fi credentials");
Serial.print("\tSSID : ");
Serial.println((const char *) sys_event->event_info.prov_cred_recv.ssid);
Serial.print("\tPassword : ");
Serial.println((char const *) sys_event->event_info.prov_cred_recv.password);
break;
}
case ARDUINO_EVENT_PROV_INIT:
wifi_prov_mgr_disable_auto_stop(10000);
break;
case ARDUINO_EVENT_PROV_CRED_SUCCESS:
Serial.println("Stopping Provisioning!!!");
wifi_prov_mgr_stop_provisioning();
break;
}
}
void write_callback(Device *device, Param *param, const param_val_t val, void *priv_data, write_ctx_t *ctx)
{
const char *device_name = device->getDeviceName();
Serial.println(device_name);
const char *param_name = param->getParamName();
if (strcmp(device_name, "Heater") == 0)
{
if (strcmp(param_name, "Power") == 0)
{
Serial.printf("Received value = %s for %s - %s\n", val.val.b ? "true" : "false", device_name, param_name);
relay_state = val.val.b;
(relay_state == false) ? digitalWrite(relay, LOW) : digitalWrite(relay, HIGH);
param->updateAndReport(val);
}
}
}
void setup()
{
Serial.begin(115200);
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &onTimer, true);
timerAlarmWrite(timer, 30000000, true);
timerAlarmEnable(timer);
// Configure the input GPIOs
//pinMode(gpio_reset, INPUT);
pinMode(relay, OUTPUT);
digitalWrite(relay, DEFAULT_RELAY_MODE);
//------------------------------------------- Declaring Node -----------------------------------------------------//
Node my_node;
my_node = RMaker.initNode("Aquaponics_System");
//Standard switch device
my_switch.addCb(write_callback);
//Water Level Parameter
Param waterlevelParam("Water Level (cm)", "custom.param.waterlevel", value((float)DEFAULT_WaterLevel), PROP_FLAG_READ | PROP_FLAG_TIME_SERIES);
ultrasonic_sensor.addParam(waterlevelParam);
ultrasonic_sensor.assignPrimaryParam(ultrasonic_sensor.getParamByName("Water Level (cm)"));
//pH Parameter
Param pHParam("pH", "custom.param.pH", value((float)DEFAULT_pH), PROP_FLAG_READ | PROP_FLAG_TIME_SERIES);
pH_sensor.addParam(pHParam);
pH_sensor.assignPrimaryParam(pH_sensor.getParamByName("pH"));
//EC Parameter
Param ecParam("EC (ms/cm)", "custom.param.EC", value((float)DEFAULT_EC), PROP_FLAG_READ | PROP_FLAG_TIME_SERIES);
EC_sensor.addParam(ecParam);
EC_sensor.assignPrimaryParam(EC_sensor.getParamByName("EC (ms/cm)"));
//ORP Parameter
Param orpParam("ORP (mV)", "custom.param.orp", value((float)DEFAULT_ORP), PROP_FLAG_READ | PROP_FLAG_TIME_SERIES);
ORP_sensor.addParam(orpParam);
ORP_sensor.assignPrimaryParam(ORP_sensor.getParamByName("ORP (mV)"));
//DO Parameter
Param doParam("DO (μg/L)", "custom.param.do", value((float)DEFAULT_DO), PROP_FLAG_READ | PROP_FLAG_TIME_SERIES);
DO_sensor.addParam(doParam);
DO_sensor.assignPrimaryParam(DO_sensor.getParamByName("DO (μg/L)"));
//------------------------------------------- Adding Devices in Node -----------------------------------------------------//
my_node.addDevice(temperature_sensor);
my_node.addDevice(ultrasonic_sensor);
my_node.addDevice(pH_sensor);
my_node.addDevice(EC_sensor);
my_node.addDevice(ORP_sensor);
my_node.addDevice(DO_sensor);
my_node.addDevice(my_switch);
//This is optional
RMaker.enableOTA(OTA_USING_PARAMS);
//If you want to enable scheduling, set time zone for your region using setTimeZone().
//The list of available values are provided here https://rainmaker.espressif.com/docs/time-service.html
//RMaker.setTimeZone("Asia/Hong_Kong");
// Alternatively, enable the Timezone service and let the phone apps set the appropriate timezone
RMaker.enableTZService();
RMaker.enableSchedule();
RMaker.enableScenes();
Serial.printf("\nStarting ESP-RainMaker\n");
RMaker.start();
WiFi.onEvent(sysProvEvent);
#if CONFIG_IDF_TARGET_ESP32S2
WiFiProv.beginProvision(WIFI_PROV_SCHEME_SOFTAP, WIFI_PROV_SCHEME_HANDLER_NONE, WIFI_PROV_SECURITY_1, pop, service_name);
#else
WiFiProv.beginProvision(WIFI_PROV_SCHEME_BLE, WIFI_PROV_SCHEME_HANDLER_FREE_BTDM, WIFI_PROV_SECURITY_1, pop, service_name);
#endif
}
void loop()
{
if (interruptCounter > 0 && wifi_connected) {
Serial.println("Sending Sensor's Data");
portENTER_CRITICAL(&timerMux);
interruptCounter--;
portEXIT_CRITICAL(&timerMux);
totalInterruptCounter++;
Send_TempSensor();
Send_UltraSensor();
Send_pHSensor();
Send_ECSensor();
Send_ORPSensor();
Send_DOSensor();
}
//----------------------------------------------------------- Logic to Reset RainMaker
// Read GPIO0 (external button to reset device
if (digitalRead(gpio_reset) == LOW) { //Push button pressed
Serial.printf("Reset Button Pressed!\n");
// Key debounce handling
delay(100);
int startTime = millis();
while (digitalRead(gpio_reset) == LOW) delay(50);
int endTime = millis();
if ((endTime - startTime) > 10000) {
// If key pressed for more than 10secs, reset all
Serial.printf("Reset to factory.\n");
wifi_connected = 0;
RMakerFactoryReset(2);
} else if ((endTime - startTime) > 3000) {
Serial.printf("Reset Wi-Fi.\n");
wifi_connected = 0;
// If key pressed for more than 3secs, but less than 10, reset Wi-Fi
RMakerWiFiReset(2);
}
}
delay(100);
}
void Send_TempSensor(){
String msg = Serial.readStringUntil('\n');
Serial.print(msg);
if (msg = 'Temperature:')
{
String TemperatureS = Serial.readStringUntil('\n');
float t = TemperatureS.toFloat();
Serial.println(t);
temperature_sensor.updateAndReportParam("Temperature", t);
}
}
void Send_UltraSensor(){
String msg = Serial.readStringUntil('\n');
Serial.print(msg);
if (msg = 'Water Level:')
{
String WaterLevelS = Serial.readStringUntil('\n');
float w = WaterLevelS.toFloat();
Serial.println(w);
ultrasonic_sensor.updateAndReportParam("Water Level (cm)", w);
}
}
void Send_pHSensor(){
String msg = Serial.readStringUntil('\n');
Serial.print(msg);
if (msg = 'pH:')
{
String pHvalueS = Serial.readStringUntil('\n');
float c = pHvalueS.toFloat();
Serial.println(c);
pH_sensor.updateAndReportParam("pH", c);
}
}
void Send_ECSensor(){
String msg = Serial.readStringUntil('\n');
Serial.print(msg);
if (msg = 'EC:')
{
String ECvalueS = Serial.readStringUntil('\n');
float d = ECvalueS.toFloat();
Serial.println(d);
EC_sensor.updateAndReportParam("EC (ms/cm)", d);
}
}
void Send_ORPSensor(){
String msg = Serial.readStringUntil('\n');
Serial.print(msg);
if (msg = 'ORP:')
{
String ORPvalueS = Serial.readStringUntil('\n');
float e = ORPvalueS.toFloat();
Serial.println(e);
ORP_sensor.updateAndReportParam("ORP (mV)", e);
}
}
void Send_DOSensor(){
String msg = Serial.readStringUntil('\n');
Serial.print(msg);
if (msg = 'DO:')
{
String DOvalueS = Serial.readStringUntil('\n');
float f = DOvalueS.toFloat();
Serial.println(f);
DO_sensor.updateAndReportParam("DO (μg/L)", f);
}
}
Serial Monitor Output
Code: Select all
15:16:18.440 -> Sending Sensor's Data
15:16:18.440 -> Temperature: 23.87
15:16:18.440 -> Water Level: 24.00
15:16:18.440 -> pH:6.21
15:16:18.482 -> EC:2.40
15:16:18.482 -> DO:1352.00
15:16:18.482 -> ORP: 9.92
15:16:48.467 -> Sending Sensor's Data
15:16:48.467 -> Temperature: 23.87
15:16:48.467 -> Water Level: 24.00
15:16:48.467 -> pH: 4.74
15:16:48.467 -> EC: 3.98
15:16:48.467 -> DO: 2133.00
15:16:48.467 -> ORP: 10.44
15:17:48.442 -> Sending Sensor's Data
15:17:48.442 -> er Level: 25.00
15:17:48.488 -> pH: 6.15
15:17:48.488 -> EC: 2.14
15:17:48.488 -> DO: 1337.00
15:17:48.488 -> ORP: 1587.97
15:17:48.488 -> Temperature: 23.75
15:20:48.516 -> Sending Sensor's Data
15:20:48.516 -> 0.00
15:20:48.516 -> 2.140.00
15:20:48.516 -> 14100.00
15:20:48.516 -> 915.560.00
15:20:48.516 -> 23.810.00
15:20:48.516 -> 250.00