#include "SIM800L_by_Murri.h"
SIM800L sim(10, 9); //RX, TX R4(8,9) Mega(10,9)
#define SIM_PIN 7
#include <U8g2lib.h>
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE);
//U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE);
#include <Wire.h> // must be included here so that Arduino library object file references work
#include <RtcDS3231.h>
RtcDS3231<TwoWire> Rtc(Wire);
RtcDateTime dt, now, from, to;
#include <SdFat.h>
#define SPI_SPEED SD_SCK_MHZ(2)
SdFat sd;
File file;
#include <OneWire.h>
#include <DallasTemperature.h>
OneWire oneWire(A0);
DallasTemperature DS18B20(&oneWire);
DeviceAddress DEVICEADDRESS;
#include <EEPROM.h>
#include "DFRobot_PH_by_Murri.h"
#define PH_PIN A1
DFRobot_PH PH;
#include "DFRobot_EC_by_Murri.h"
#define EC_PIN A2
DFRobot_EC EC;
#include "DFRobot_DO_by_Murri.h"
#define DO_PIN A3
DFRobot_DO DO;
#include "GravityTDS_by_Murri.h"
#define TDS_PIN A4
GravityTDS TDS;
#include "DTH_Turbidity.h"
#define TB_PIN A5
DTH_Turbidity turbSensor(TB_PIN);
float temperature = 25.0;
float sensor1_val, sensor2_val, sensor3_val, sensor4_val, sensor5_val, sensor6_val;
float sensor1_avg, sensor2_avg, sensor3_avg, sensor4_avg, sensor5_avg, sensor6_avg;
unsigned long counter_avg;
unsigned long calc_ms_avg;
bool sdmodul_err, datalog_err, rtclock_err;
bool sensor1_err, sensor2_err, sensor3_err, sensor4_err, sensor5_err, sensor6_err;
bool sensor1_sms, sensor2_sms, sensor3_sms, sensor4_sms, sensor5_sms, sensor6_sms;
bool average_sms;
int page = 0;
long countdown = 30;
bool displayOn = true;
char text[160];
bool send;
bool connected;
bool simPowrOn;
volatile bool interrupt_2 = false;
volatile unsigned long bounce_2 = 0;
volatile unsigned long lpress_2 = 0;
volatile bool interrupt_3 = false;
volatile unsigned long bounce_3 = 0;
volatile unsigned long lpress_3 = 0;
void buttons_interrupt_handler_2() {
interrupt_2 = true;
bounce_2 = millis();
lpress_2 = millis();
}
void buttons_interrupt_handler_3() {
interrupt_3 = true;
bounce_3 = millis();
lpress_3 = millis();
}
void setup() {
delay(1000);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
Serial.begin(115200);
Serial.println(" ");
sim.begin(4800); //300, 600, 1200, 2400, 4800, 9600, 14400, 19200
DS18B20.begin();
DS18B20.setWaitForConversion(false);
DS18B20.getAddress(DEVICEADDRESS, 0); // get deviceaddress for index 0;
//DS18B20.setResolution(DEVICEADDRESS, 9); // set Resolution to 9, 10, 11, 12 bits
PH.begin();
EC.begin();
DO.begin();
TDS.setPin(TDS_PIN);
TDS.begin();
sdmodul_err = !sd.begin(SS, SPI_SPEED);
if (sdmodul_err) sd.end(); //try reinitialization of sdmodul in datalog (10 attempts)
Rtc.Begin();
pinMode(2, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(2), buttons_interrupt_handler_2, FALLING);
pinMode(3, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(3), buttons_interrupt_handler_3, FALLING);
rtc_set();
pinMode(SIM_PIN, OUTPUT);
}
void loop() {
rtclock();
sensors();
sensor1_err = false;
sensor1_sms = false;
sensor2_err = false;
sensor2_sms = false;
sensor3_err = false;
sensor3_sms = false;
sensor4_err = false;
sensor4_sms = false;
sensor5_err = false;
sensor5_sms = false;
sensor6_err = false;
sensor6_sms = false;
buttons();
PowSave();
display();
if (calibrate()) {
digitalWrite(SIM_PIN, LOW);
return;
}
datalog();
average();
sendsms();
sim800L();
}
int pin2int() {
int impulse = 0;
static bool longpress = false;
noInterrupts();
if (digitalRead(2)) lpress_2 = millis();
else bounce_2 = millis();
if (interrupt_2) {
if (millis() - bounce_2 > 20) {
interrupt_2 = false;
impulse = !longpress; //impulse shortpress
longpress = false;
}
}
if (!longpress) {
if (millis() - lpress_2 > 750) {
longpress = true;
lpress_2 = millis();
impulse = 2; //impulse longpress(once)
}
}
if (longpress) {
if (millis() - lpress_2 > 500) {
lpress_2 = millis();
impulse = 3; //impulse longpress(repeat)
}
}
interrupts();
return impulse;
}
int pin3int() {
int impulse = 0;
static bool longpress = false;
noInterrupts();
if (digitalRead(3)) lpress_3 = millis();
else bounce_3 = millis();
if (interrupt_3) {
if (millis() - bounce_3 > 20) {
interrupt_3 = false;
impulse = !longpress; //impulse shortpress
longpress = false;
}
}
if (!longpress) {
if (millis() - lpress_3 > 750) {
longpress = true;
lpress_3 = millis();
impulse = 2; //impulse longpress(once)
}
}
if (longpress) {
if (millis() - lpress_3 > 500) {
lpress_3 = millis();
impulse = 3; //impulse longpress(repeat)
}
}
interrupts();
return impulse;
}
void rtc_set() {
RtcDateTime now = Rtc.GetDateTime();
u8g2.initDisplay();
u8g2.setContrast(30);
u8g2.setFlipMode(0);
u8g2.setPowerSave(0);
int Mon = now.Month();
int Day = now.Day();
int Yrs = now.Year();
int Hrs = now.Hour();
int Min = now.Minute();
int Sec = now.Second();
int cases = 8;
bool init = true;
unsigned long refresh = millis();
unsigned long timeout = millis() + 10000;
while (millis() < timeout) {
int m = pin3int();
int p = pin2int();
if (!m & !p & !init) {
if (millis() - refresh < 500)continue;
refresh = millis();
goto display;
}
if (!init) timeout = millis() + 99999;
init = false;
if (m >= 2) cases --;
if (p >= 2) cases ++;
if (cases < 1) cases = 8;
if (cases > 8) cases = 1;
switch (cases) {
case 1:
if (m == 1) Mon --;
if (p == 1) Mon ++;
break;
case 2:
if (m == 1) Day --;
if (p == 1) Day ++;
break;
case 3:
if (m == 1) Yrs --;
if (p == 1) Yrs ++;
break;
case 4:
if (m == 1) Hrs --;
if (p == 1) Hrs ++;
break;
case 5:
if (m == 1) Min --;
if (p == 1) Min ++;
break;
case 6:
if (m == 1) Sec --;
if (p == 1) Sec ++;
break;
case 7:
if (m == 1 | p == 1) {
Rtc.SetDateTime(RtcDateTime(Yrs, Mon, Day, Hrs, Min, Sec));
return;
}
break;
case 8:
if (m == 1 | p == 1) return;
break;
}
if (Yrs < 2000)Yrs = 2099;
if (Yrs > 2099)Yrs = 2000;
if (Mon < 1)Mon = 12;
if (Mon > 12)Mon = 1;
if (Day < 1)Day = 31;
if (Day > 31)Day = 1;
if (Hrs < 0)Hrs = 23;
if (Hrs > 23)Hrs = 0;
if (Min < 0)Min = 59;
if (Min > 59)Min = 0;
if (Sec < 0)Sec = 59;
if (Sec > 59)Sec = 0;
static char date[11], time[9];
snprintf(date, 11, "%02u-%02u-%04u", Mon, Day, Yrs);
snprintf(time, 9, "%02u:%02u:%02u", Hrs, Min, Sec);
display:
u8g2.clearBuffer();
u8g2.drawRFrame(0, 0, 128, 64, 5);
u8g2.setFont(u8g2_font_t0_22b_mf);
u8g2.drawStr(9, 18, date);
u8g2.drawStr(20, 38, time);
u8g2.drawStr(8, 58, "SET EXIT");
switch (cases) {
case 1:
u8g2.drawFrame(8, 3, 24, 17);
break;
case 2:
u8g2.drawFrame(41, 3, 24, 17);
break;
case 3:
u8g2.drawFrame(74, 3, 46, 17);
break;
case 4:
u8g2.drawFrame(19, 23, 24, 17);
break;
case 5:
u8g2.drawFrame(52, 23, 24, 17);
break;
case 6:
u8g2.drawFrame(85, 23, 24, 17);
break;
case 7:
u8g2.drawFrame(7, 43, 36, 17);
break;
case 8:
u8g2.drawFrame(73, 43, 47, 17);
break;
}
u8g2.sendBuffer();
}
}
void rtclock() {
static bool init = true;
static unsigned long elapse;
static float tolerance = 3.5 / 3600.0; // tolerance = 3.5 sec/hrs (Arduino R4 Wifi);
if (init) {
init = false;
dt = Rtc.GetDateTime();
elapse = millis();
rtclock_err = !Rtc.IsDateTimeValid();
}
if (rtclock_err) {
if (millis() - elapse > 1000) init = true;
} else if (millis() - elapse > 21600000) init = true; //read rtclock every 21600000ms (= 6 hrs)
now = dt + round((millis() - elapse) * (1.0 + tolerance) / 1000.0);
}
void sensors() {
sensor1(); //Temperature
sensor2(); //PH
sensor3(); //EC
sensor4(); //DO
sensor5(); //TDS
sensor6(); //Turbidity
}
void sensor1() {
//Temperature
static unsigned long reading = millis();
static unsigned long sendsms = millis();
static bool init = true;
if (init) {
init = false;
DS18B20.requestTemperatures(); // request Temperature for the first reading
delay(1000);
}
if (millis() - reading > 1000) {
reading = millis();
sensor1_val = DS18B20.getTempC(DEVICEADDRESS); // get Temperature without WaitForConversion after 1000ms
DS18B20.requestTemperatures(); // request Temperature for the next reading
temperature = sensor1_val;
sensor1_err = sensor1_val < 10.0 | sensor1_val > 30.0;
}
if (!sensor1_err) sendsms = millis();
sensor1_sms = millis() - sendsms > 99999;
}
void sensor2() {
//PH
static unsigned long reading = millis();
static unsigned long sendsms = millis();
if (millis() - reading > 1000) {
reading = millis();
float voltage = analogRead(PH_PIN) / 1024.0 * 5000;
sensor2_val = PH.readPH(voltage, temperature);
sensor2_err = sensor2_val < 6.5 | sensor2_val > 9.0;
}
if (!sensor2_err) sendsms = millis();
sensor2_sms = millis() - sendsms > 99999;
}
void sensor3() {
//EC
static unsigned long reading = millis();
static unsigned long sendsms = millis();
if (millis() - reading > 1000) {
reading = millis();
float voltage = analogRead(EC_PIN) / 1024.0 * 5000;
sensor3_val = EC.readEC(voltage, temperature);
sensor3_err = sensor3_val < 10.0 | sensor3_val > 20.0;
}
if (!sensor3_err) sendsms = millis();
sensor3_sms = millis() - sendsms > 99999;
}
void sensor4() {
//DO
static unsigned long reading = millis();
static unsigned long sendsms = millis();
if (millis() - reading > 1000) {
reading = millis();
float voltage = analogRead(DO_PIN) / 1024.0 * 5000;
sensor4_val = DO.readDO(voltage, temperature);
sensor4_err = sensor4_val < 3.0 | sensor4_val > 15.0;
}
if (!sensor4_err) sendsms = millis();
sensor4_sms = millis() - sendsms > 99999;
}
void sensor5() {
//TDS
static unsigned long reading = millis();
static unsigned long sendsms = millis();
if (millis() - reading > 1000) {
reading = millis();
float voltage = analogRead(TDS_PIN) / 1024.0 * 5000;
sensor5_val = TDS.readTDS(voltage, temperature);
sensor5_err = sensor5_val < 50.0 | sensor5_val > 400.0;
}
if (!sensor5_err) sendsms = millis();
sensor5_sms = millis() - sendsms > 99999;
}
void sensor6() {
//Turbidity
static unsigned long reading = millis();
static unsigned long sendsms = millis();
if (millis() - reading > 1000) {
reading = millis();
sensor6_val = turbSensor.readTurbidity();
sensor6_err = sensor6_val < 1.0 | sensor6_val > 500.0;
}
if (!sensor6_err) sendsms = millis();
sensor6_sms = millis() - sendsms > 99999;
}
void buttons() {
static unsigned long elapse = millis();
int m = pin3int();
int p = pin2int();
if (m == 1) {
if (displayOn) {
page--;
if (page < 0) page = 7;
} else displayOn = true;
elapse = millis();
}
if (p == 1) {
if (displayOn) {
page++;
if (page > 7) page = 0;
} else displayOn = true;
elapse = millis();
}
if (m == 2) displayOn = false;
if (p == 2) displayOn = false;
if (displayOn) {
if (millis() - elapse > 99999) {
displayOn = false;
}
}
}
void PowSave() {
static bool laststate = !displayOn;
if (laststate != displayOn) {
laststate = displayOn;
if (displayOn) {
u8g2.initDisplay();
u8g2.setContrast(30);
u8g2.setFlipMode(0);
u8g2.setPowerSave(0);
} else {
u8g2.initDisplay();
u8g2.setPowerSave(1);
}
}
// sometimes the display hangs and won't switch off,
// so we try to switch it off every 30 minutes.
static unsigned long elapse = millis();
if (displayOn) elapse = millis();
else if (millis() - elapse > 1800000) {
elapse = millis();
u8g2.initDisplay();
u8g2.setPowerSave(1);
}
}
void display() {
if (!displayOn) return;
static byte incr;
static unsigned long elapse = millis();
if (elapse <= millis()) {
elapse = millis() + 500;
bool blink = bitRead(incr++, 0);
switch (page) {
case 0:
page0(blink);
break;
case 1:
page1(blink);
break;
case 2:
page2(blink);
break;
case 3:
page3(blink);
break;
case 4:
page4(blink);
break;
case 5:
page5(blink);
break;
case 6:
page6(blink);
break;
case 7:
page7(blink);
break;
default:
page0(blink);
break;
}
}
}
void page0(bool blink) {
blink |= !sdmodul_err & !rtclock_err & !datalog_err;
static char date[11], time[9], logs[3];
snprintf(date, 11, "%02u-%02u-%04u", now.Month(), now.Day(), now.Year());
snprintf(time, 9, "%02u:%02u:%02u", now.Hour(), now.Minute(), now.Second());
snprintf(logs, 3, "%02u", countdown);
u8g2.clearBuffer();
u8g2.drawRFrame(0, 0, 128, 64, 5);
u8g2.setFont(u8g2_font_t0_22b_mf);
if (blink) {
u8g2.drawStr(9, 18, date);
u8g2.drawStr(20, 38, time);
if (countdown) u8g2.drawStr(53, 58, logs);
else u8g2.drawStr(26, 58, "datalog");
}
u8g2.sendBuffer();
}
void page1(bool blink) {
blink |= !sensor1_err;
static char strf[20];
dtostrf(sensor1_val, 4, 2, strf);
u8g2.clearBuffer();
u8g2.drawRFrame(0, 0, 128, 64, 5);
u8g2.setFont(u8g2_font_t0_22b_mf);
u8g2.drawStr(4, 18, "Temperature");
if (blink) u8g2.drawStr((128 - u8g2.getUTF8Width(strf)) / 2, 38, strf);
u8g2.drawGlyph(53, 58, 0xb0);
u8g2.drawStr(63, 58, "C");
u8g2.sendBuffer();
}
void page2(bool blink) {
blink |= !sensor2_err;
static char strf[20];
dtostrf(sensor2_val, 4, 2, strf);
u8g2.clearBuffer();
u8g2.drawRFrame(0, 0, 128, 64, 5);
u8g2.setFont(u8g2_font_t0_22b_mf);
u8g2.drawStr(53, 27, "PH");
if (blink) u8g2.drawStr((128 - u8g2.getUTF8Width(strf)) / 2, 53, strf);
u8g2.setFont(u8g2_font_emoticons21_tr);
u8g2.drawGlyph(3, 48, 0x30);
u8g2.sendBuffer();
}
void page3(bool blink) {
blink |= !sensor3_err;
static char strf[20];
dtostrf(sensor3_val, 4, 2, strf);
u8g2.clearBuffer();
u8g2.drawRFrame(0, 0, 128, 64, 5);
u8g2.setFont(u8g2_font_t0_22b_mf);
u8g2.drawStr(53, 18, "EC");
if (blink) u8g2.drawStr((128 - u8g2.getUTF8Width(strf)) / 2, 38, strf);
u8g2.drawStr(37, 58, "ms/cm");
u8g2.sendBuffer();
}
void page4(bool blink) {
blink |= !sensor4_err;
static char strf[20];
dtostrf(sensor4_val, 4, 2, strf);
u8g2.clearBuffer();
u8g2.drawRFrame(0, 0, 128, 64, 5);
u8g2.setFont(u8g2_font_t0_22b_mf);
u8g2.drawStr(53, 18, "DO");
if (blink) u8g2.drawStr((128 - u8g2.getUTF8Width(strf)) / 2, 38, strf);
u8g2.drawStr(42, 58, "mg/L");
u8g2.sendBuffer();
}
void page5(bool blink) {
blink |= !sensor5_err;
static char strf[20];
dtostrf(sensor5_val, 4, 2, strf);
u8g2.clearBuffer();
u8g2.drawRFrame(0, 0, 128, 64, 5);
u8g2.setFont(u8g2_font_t0_22b_mf);
u8g2.drawStr(48, 18, "TDS");
if (blink) u8g2.drawStr((128 - u8g2.getUTF8Width(strf)) / 2, 38, strf);
u8g2.drawStr(48, 58, "ppm");
u8g2.sendBuffer();
}
void page6(bool blink) {
blink |= !sensor6_err;
static char strf[20];
dtostrf(sensor6_val, 4, 2, strf);
u8g2.clearBuffer();
u8g2.drawRFrame(0, 0, 128, 64, 5);
u8g2.setFont(u8g2_font_t0_22b_mf);
u8g2.drawStr(15, 18, "Turbidity");
if (blink) u8g2.drawStr((128 - u8g2.getUTF8Width(strf)) / 2, 38, strf);
u8g2.drawStr(48, 58, "NTU");
u8g2.sendBuffer();
}
void page7(bool blink) {
u8g2.clearBuffer();
u8g2.drawRFrame(0, 0, 128, 64, 5);
u8g2.setFont(u8g2_font_t0_22b_mf);
if (sdmodul_err) u8g2.drawStr(9, 18, "sdmodul ER");
else u8g2.drawStr(9, 18, "sdmodul OK");
if (datalog_err) u8g2.drawStr(9, 38, "datalog ER");
else u8g2.drawStr(9, 38, "datalog OK");
if (rtclock_err) u8g2.drawStr(9, 58, "rtclock ER");
else u8g2.drawStr(9, 58, "rtclock OK");
u8g2.sendBuffer();
}
void datalog() {
static unsigned long elapse = millis() + countdown * 1000;
countdown = (elapse - millis()) / 1000;
if (elapse > millis()) return;
elapse = millis() + 60000;
countdown = 0;
if (rtclock_err) return;
static char time[9], col1[9], col2[9], col3[9], col4[9], col5[9], col6[9];
static char date[11];
static char head[66];
static char data[66];
static char FILE[15];
static char strf[20];
snprintf(date, 11, "%04u-%02u-%02u", now.Year(), now.Month(), now.Day());
snprintf(time, 9, "%02u:%02u:%02u", now.Hour(), now.Minute(), now.Second());
snprintf(col1, 9, "%s", dtostrf(sensor1_val, 8, 2, strf));
snprintf(col2, 9, "%s", dtostrf(sensor2_val, 8, 2, strf));
snprintf(col3, 9, "%s", dtostrf(sensor3_val, 8, 2, strf));
snprintf(col4, 9, "%s", dtostrf(sensor4_val, 8, 2, strf));
snprintf(col5, 9, "%s", dtostrf(sensor5_val, 8, 2, strf));
snprintf(col6, 9, "%s", dtostrf(sensor6_val, 8, 2, strf));
snprintf(head, 66, "hh:mm:ss,TEMP[*C],---PH---,EC ms/cm,DO[mg/L],TDS[ppm],TBD[NTU],\r\n");
snprintf(data, 66, "%s,%s,%s,%s,%s,%s,%s,\r\n", time, col1, col2, col3, col4, col5, col6);
snprintf(FILE, 15, "%s.txt", date);
Serial.println();
Serial.println(FILE);
Serial.print(head);
if (file.isOpen()) {
Serial.println(F("file is currently open, file must be closed at this point!"));
file.close();
}
if (!sd.exists(FILE)) {
file = sd.open(FILE, O_CREAT | O_WRITE);
delay(10);
if (file && file.position() == 0) {
file.write(head);
Serial.println(F("new file generated!"));
file.close();
delay(10);
} else datalog_err = true;
} else datalog_err = false;
if (sd.exists(FILE)) {
file = sd.open(FILE, O_WRITE | O_AT_END);
delay(10);
if (file && file.position() >= 0) {
file.write(data);
Serial.print(data);
file.close();
delay(10);
} else datalog_err = true;
} else datalog_err = true;
static byte sdmodulinit = 0;
if (datalog_err == false) {
sdmodulinit = 0;
sdmodul_err = false;
return;
}
sdmodulinit ++;
if (sdmodulinit <= 4) {
Serial.print(F("reinitialization of sdmodul because of datalog error! attemt:"));
Serial.println(sdmodulinit);
sd.end();
delay(10);
sdmodul_err = !sd.begin(SS, SPI_SPEED);
} else {
Serial.print(F("reinitialization of sdmodul because of datalog error! pausing:"));
Serial.println(sdmodulinit - 4);
}
if (sdmodulinit >= 16) sdmodulinit = 0;
}
int simulation(int *days) {
static int DAYS = 1;
static int simulate = 0;
unsigned long timer = millis();
static unsigned long buttonpress = timer;
bool pin2 = !digitalRead(2);
bool pin3 = !digitalRead(3);
if (!simulate & !pin2 & !pin3) buttonpress = timer;
if (timer - buttonpress > 10000) {
if (!simulate) {
if (pin2) DAYS = 31;
else DAYS = 1;
simulate = 1;
} else simulate = 2;
if (rtclock_err )simulate = 1;
}
if (timer - buttonpress > 99999) simulate = 0;
if (simulate) *days = DAYS;
return simulate;
}
void average() {
int days = 1;
int simulate = simulation(&days);
if (simulate == 1) goto m1;
if (simulate == 2) goto m2;
if (rtclock_err | now.Hour() != 12) {
m1:
average_sms = false;
return;
}
if (now.Day() == 1)days = 31;
m2:
if (sdmodul_err | datalog_err)return;
if (average_sms) return;
else average_sms = true;
counter_avg = 0;
sensor1_avg = 0.0f;
sensor2_avg = 0.0f;
sensor3_avg = 0.0f;
sensor4_avg = 0.0f;
sensor5_avg = 0.0f;
sensor6_avg = 0.0f;
static char date[11];
static char FILE[15];
static char data[66];
from = now;
calc_ms_avg = millis();
for (int i = 1; i <= days; i++) {
int j = from.Day();
from = from - 86400;
int k = from.Day();
if (i == 1) to = from;
if (k > j) i += abs(31 - k);
snprintf(date, 11, "%04u-%02u-%02u", from.Year(), from.Month(), from.Day());
snprintf(FILE, 15, "%s.txt", date);
if (sd.exists(FILE)) {
file = sd.open(FILE, O_READ);
if (file) {
file.seek(65);
while (file.available()) {
memset(data, 0, sizeof(data));
file.readBytes(data, 65);
if (data[ 2] != ':')continue;
if (data[ 5] != ':')continue;
if (data[ 8] != ',')continue;
if (data[17] != ',')continue;
if (data[26] != ',')continue;
if (data[35] != ',')continue;
if (data[44] != ',')continue;
if (data[53] != ',')continue;
if (data[62] != ',')continue;
counter_avg ++;
sensor1_avg += atof(data + 9);
sensor2_avg += atof(data + 18);
sensor3_avg += atof(data + 27);
sensor4_avg += atof(data + 36);
sensor5_avg += atof(data + 45);
sensor6_avg += atof(data + 54);
}
file.close();
}
}
}
calc_ms_avg = millis() - calc_ms_avg;
if (counter_avg) {
sensor1_avg /= counter_avg;
sensor2_avg /= counter_avg;
sensor3_avg /= counter_avg;
sensor4_avg /= counter_avg;
sensor5_avg /= counter_avg;
sensor6_avg /= counter_avg;
}
Serial.println();
Serial.println(F("averages"));
Serial.println(sensor1_avg);
Serial.println(sensor2_avg);
Serial.println(sensor3_avg);
Serial.println(sensor4_avg);
Serial.println(sensor5_avg);
Serial.println(sensor6_avg);
Serial.print(counter_avg);
Serial.println(F(" counts"));
Serial.print(calc_ms_avg);
Serial.println(F(" ms"));
}
void sendsms() {
static char strf[20];
static char strf1[20];
static char strf2[20];
static char strf3[20];
static char strf4[20];
static char strf5[20];
static char strf6[20];
static char range[30];
static int sms = 0x0000;
static int tmp = 0x03FF;
static int set = 0x03FF;
static unsigned long repeat = millis();
if (millis() - repeat > 3600000) {
repeat = millis();
tmp = 0x03FE;
}
bitWrite(sms, 0, average_sms);
bitWrite(sms, 1, sensor1_sms);
bitWrite(sms, 2, sensor2_sms);
bitWrite(sms, 3, sensor3_sms);
bitWrite(sms, 4, sensor4_sms);
bitWrite(sms, 5, sensor5_sms);
bitWrite(sms, 6, sensor6_sms);
bitWrite(sms, 7, sdmodul_err);
bitWrite(sms, 8, datalog_err);
bitWrite(sms, 9, rtclock_err);
for (int i = 0; i <= 9; i++) {
if bitRead (sms, i) {
if bitRead (tmp, i) {
simPowrOn = true;
}
} else if bitRead(set, i)
bitSet(tmp, i);
}
if (!connected | send) return;
if (bitRead(sms, 0) & bitRead(tmp, 0)) {
bitClear(tmp, 0);
dtostrf(sensor1_avg, 0, 2, strf1);
dtostrf(sensor2_avg, 0, 2, strf2);
dtostrf(sensor3_avg, 0, 2, strf3);
dtostrf(sensor4_avg, 0, 2, strf4);
dtostrf(sensor5_avg, 0, 2, strf5);
dtostrf(sensor6_avg, 0, 2, strf6);
if (from == to) {
snprintf(range, 30, "from %02u-%02u-%04u", from.Month(), from.Day(), from.Year());
} else {
snprintf(range, 30, "from %02u-%02u-%04u to %02u-%02u-%04u", from.Month(), from.Day(), from.Year(), to.Month(), to.Day(), to.Year());
}
snprintf(text, 160, "Averages!\r%s\r\rTEMP: %s *C\rPH: %s\rEC: %s ms/cm\rDO: %s mg/L\rTDS: %s ppm\rTBD: %s NTU\r\r%lu counts\r%lu ms", range, strf1, strf2, strf3, strf4, strf5, strf6, counter_avg, calc_ms_avg);
send = true;
return;
}
if (bitRead(sms, 1) & bitRead(tmp, 1)) {
bitClear(tmp, 1);
snprintf(text, 160, "Warning!\rTemperature: %s *C", dtostrf(sensor1_val, 0, 2, strf));
send = true;
return;
}
if (bitRead(sms, 2) & bitRead(tmp, 2)) {
bitClear(tmp, 2);
snprintf(text, 160, "Warning!\r PH: %s", dtostrf(sensor2_val, 0, 2, strf));
send = true;
return;
}
if (bitRead(sms, 3) & bitRead(tmp, 3)) {
bitClear(tmp, 3);
snprintf(text, 160, "Warning!\r EC: %s ms/cm", dtostrf(sensor3_val, 0, 2, strf));
send = true;
return;
}
if (bitRead(sms, 4) & bitRead(tmp, 4)) {
bitClear(tmp, 4);
snprintf(text, 160, "Warning!\r DO: %s mg/L", dtostrf(sensor4_val, 0, 2, strf));
send = true;
return;
}
if (bitRead(sms, 5) & bitRead(tmp, 5)) {
bitClear(tmp, 5);
snprintf(text, 160, "Warning!\rTDS: %s ppm", dtostrf(sensor5_val, 0, 2, strf));
send = true;
return;
}
if (bitRead(sms, 6) & bitRead(tmp, 6)) {
bitClear(tmp, 6);
snprintf(text, 160, "Warning!\rTurbidity: %s NTU", dtostrf(sensor6_val, 0, 2, strf));
send = true;
return;
}
if (bitRead(sms, 7) & bitRead(tmp, 7)) {
bitClear(tmp, 7);
snprintf(text, 160, "Error! sdmodul");
send = true;
return;
}
if (bitRead(sms, 8) & bitRead(tmp, 8)) {
bitClear(tmp, 8);
snprintf(text, 160, "Error! datalog");
send = true;
return;
}
if (bitRead(sms, 9) & bitRead(tmp, 9)) {
bitClear(tmp, 9);
snprintf(text, 160, "Error! rtclock");
send = true;
return;
}
}
void sim800L() {
static unsigned long powerOn = millis();
if (send | !connected) powerOn = millis();
else if (millis() - powerOn > 30000) simPowrOn = false;
digitalWrite(SIM_PIN, simPowrOn);
connected = sim.connect(simPowrOn, 60); //60 seconds (0-255)
sim.maxnr = 2;
sim.sendSms(1, &send, "+639497805263", text);
sim.sendSms(2, &send, "+639604270711", text);
}
//*************************** C A L I B R A T E ***************************
//*************************** C A L I B R A T E ***************************
//*************************** C A L I B R A T E ***************************
//*************************** C A L I B R A T E ***************************
//*************************** C A L I B R A T E ***************************
//*************************** C A L I B R A T E ***************************
//*************************** C A L I B R A T E ***************************
byte calibrate() {
/*
terminate
read ph eeprom
erase ph eeprom
read ec eeprom
erase ec eeprom
read do eeprom
erase do eeprom
read tds eeprom
erase tds eeprom
tsensor -> read temperature from sensor
tinput:val -> set temperature to val
PH Calibration:
enterph -> enter the calibration mode
calph -> calibrate with the standard buffer solution, two buffer solutions(4.0 and 7.0) will be automaticlly recognized
exitph -> save the calibrated parameters and exit from calibration mode
EC Calibration:
enterec -> enter the PH calibration mode
calec -> calibrate with the standard buffer solution, two buffer solutions(1413us/cm and 12.88ms/cm)
exitec -> save the calibrated parameters and exit from calibration mode
TDS Calibration:
enter -> enter the calibration mode
cal:tds value -> calibrate with the known tds value(25^c). e.g.cal:707
exit -> save the parameters and exit the calibration mode
DO Calibration:
enterdo -> enter the PH calibration mode
cal1do: -> voltage & temperature (read from sensors, high temperature point)
cal2do: -> voltage & temoperture (read from sensors, low temperature point)
exitdo -> save the calibrated parameters and exit from calibration mode
cal1_v:voltage[mv] -> high temperature point
cal1_t:temperature -> high temperature point
cal2_v:voltage(mv) -> low temperature point
cal2_t:temperature -> low temperature point
TB Calibration: (turbidity)
entertb -> show values only, no calibration !!!
*/
float tsensor = temperature;
static float voltage, temperature;
static int analog;
float value;
static char buff[100], strf1[20], strf2[20], strf3[20], strf4[20], cmd[20];
unsigned long timer = millis();
static unsigned long reading = timer;
static unsigned long timeout = timer;
static unsigned long counter = timer;
int ADDRESS, BYTES;
static byte calibrate = 0;
static byte tempinput = 0;
if (tempinput == 0) temperature = tsensor;
if (timer >= timeout) calibrate = 0;
if (timer - reading > 1000) { // time interval: 1s
reading = timer;
counter = (timeout - timer) / 1000;
switch (calibrate) {
case 0:
tempinput = 0;
break;
case 1:
analog = analogRead(PH_PIN);
voltage = analog / 1024.0 * 5000;
value = PH.readPH(voltage, temperature);
dtostrf(value, 0, 2, strf1);
dtostrf(analog, 0, 0, strf2);
dtostrf(voltage, 0, 2, strf3);
dtostrf(temperature, 0, 2, strf4);
snprintf(buff, 100, "pH:%s\t analog:%s\t voltage:%s[mv]\t temperature:%s[*C]\t timeout in %lu[sec]", strf1, strf2, strf3, strf4, counter);
Serial.println(buff);
break;
case 2:
analog = analogRead(EC_PIN);
voltage = analog / 1024.0 * 5000;
value = EC.readEC(voltage, temperature);
dtostrf(value, 0, 2, strf1);
dtostrf(analog, 0, 0, strf2);
dtostrf(voltage, 0, 2, strf3);
dtostrf(temperature, 0, 2, strf4);
snprintf(buff, 100, "EC:%s[ms/cm]\t analog:%s\t voltage:%s[mv]\t temperature:%s[*C]\t timeout in %lu[sec]", strf1, strf2, strf3, strf4, counter);
Serial.println(buff);
break;
case 3:
analog = analogRead(DO_PIN);
voltage = analog / 1024.0 * 5000;
value = DO.readDO(voltage, temperature);
dtostrf(value, 0, 2, strf1);
dtostrf(analog, 0, 0, strf2);
dtostrf(voltage, 0, 2, strf3);
dtostrf(temperature, 0, 2, strf4);
snprintf(buff, 100, "DO:%s[mg/L]\t analog:%s\t voltage:%s[mv]\t temperature:%s[*C]\t timeout in %lu[sec]", strf1, strf2, strf3, strf4, counter);
Serial.println(buff);
break;
case 4:
analog = analogRead(TDS_PIN);
voltage = analog / 1024.0 * 5000;
value = TDS.readTDS(voltage, temperature);
dtostrf(value, 0, 2, strf1);
dtostrf(analog, 0, 0, strf2);
dtostrf(voltage, 0, 2, strf3);
dtostrf(temperature, 0, 2, strf4);
snprintf(buff, 100, "TDS:%s[ppm]\t analog:%s\t voltage:%s[mv]\t temperature:%s[*C]\t timeout in %lu[sec]", strf1, strf2, strf3, strf4, counter);
Serial.println(buff);
break;
case 5:
analog = analogRead(TB_PIN);
voltage = analog / 1024.0 * 5000;
value = (-1120.4 * voltage / 1e3 * voltage / 1e3) + (5742.3 * voltage / 1e3) - 4352.9;
if (voltage < 2500.0) value = 3000;
if (value < 0) value = 0;
dtostrf(value, 0, 2, strf1);
dtostrf(analog, 0, 0, strf2);
dtostrf(voltage, 0, 2, strf3);
dtostrf(temperature, 0, 2, strf4);
snprintf(buff, 100, "TB:%s[NTU]\t analog:%s\t voltage:%s[mv]\t temperature:%s[*C]\t timeout in %lu[sec]", strf1, strf2, strf3, strf4, counter);
Serial.println(buff);
break;
}
}
if (readSerial(cmd)) {
timeout = timer + 180000;
for (int i = 0; cmd[i] != '\0'; i++) {
cmd[i] = toupper((unsigned char)cmd[i]); // convert cmd input to uppercase
}
if (!strcmp(cmd, "TERMINATE")) calibrate = 0;
if (!strcmp(cmd, "ENTERPH")) calibrate = 1;
if (!strcmp(cmd, "ENTEREC")) calibrate = 2;
if (!strcmp(cmd, "ENTERDO")) calibrate = 3;
if (!strcmp(cmd, "ENTER" )) calibrate = 4;
if (!strcmp(cmd, "ENTERTB")) calibrate = 5;
if (!strcmp(cmd, "TSENSOR")) goto TINPUT_0;
if (!memcmp(cmd, "TINPUT:", 7)) goto TINPUT_1;
ADDRESS = 0x00, BYTES = 8;
if (!strcmp(cmd, "READ PH EEPROM")) goto EEPROM_R;
if (!strcmp(cmd, "ERASE PH EEPROM")) goto EEPROM_W;
ADDRESS = 0x0A, BYTES = 8;
if (!strcmp(cmd, "READ EC EEPROM")) goto EEPROM_R;
if (!strcmp(cmd, "ERASE EC EEPROM")) goto EEPROM_W;
ADDRESS = 0x14, BYTES = 4;
if (!strcmp(cmd, "READ TDS EEPROM")) goto EEPROM_R;
if (!strcmp(cmd, "ERASE TDS EEPROM")) goto EEPROM_W;
ADDRESS = 0x1A, BYTES = 6;
if (!strcmp(cmd, "READ DO EEPROM")) goto EEPROM_R;
if (!strcmp(cmd, "ERASE DO EEPROM")) goto EEPROM_W;
switch (calibrate) {
case 1:
PH.calibration(voltage, temperature, cmd);
break;
case 2:
EC.calibration(voltage, temperature, cmd);
break;
case 3:
DO.calibration(voltage, temperature, cmd);
break;
case 4:
TDS.calibration(voltage, temperature, cmd);
break;
case 5:
// no calibration for turbidity sensor
break;
}
}
return calibrate;
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
TINPUT_0:
if (calibrate) {
tempinput = 0;
Serial.println(F("read temperature from sensor"));
}
return calibrate;
TINPUT_1:
if (calibrate) {
tempinput = 1;
temperature = atof(cmd + 7);
Serial.print(F("set temperature to : "));
Serial.println(temperature);
}
return calibrate;
EEPROM_W:
for (int i = ADDRESS; i < ADDRESS + BYTES; i++) {
EEPROM.write(0 + i, 0xFF);
delay(10);
}
EEPROM_R:
Serial.println();
for (int i = ADDRESS; i < ADDRESS + BYTES; i++) {
Serial.print(EEPROM.read(i), HEX); Serial.print("\t");
delay(10);
}
Serial.println();
float FLOAT;
uint8_t UINT8_T;
uint16_t UINT16_T;
switch (ADDRESS) {
case 0x00:
Serial.println(EEPROM.get(ADDRESS + 0, FLOAT));
Serial.println(EEPROM.get(ADDRESS + 4, FLOAT));
break;
case 0x0A:
Serial.println(EEPROM.get(ADDRESS + 0, FLOAT));
Serial.println(EEPROM.get(ADDRESS + 4, FLOAT));
break;
case 0x14:
Serial.println(EEPROM.get(ADDRESS + 0, FLOAT));
break;
case 0x1A:
Serial.println(EEPROM.get(ADDRESS + 0, UINT16_T));
Serial.println(EEPROM.get(ADDRESS + 2, UINT8_T));
Serial.println(EEPROM.get(ADDRESS + 3, UINT16_T));
Serial.println(EEPROM.get(ADDRESS + 5, UINT8_T));
break;
}
return calibrate;
}
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;
}
51 = MOSI (DI)
50 = MISO (DO)
52 = SCK
53 = CS (or SS)
PH
EC
TDS
TBD
DO