// Мониторинг влажности почвы и полив
#define my_definition "fin_yukka.ino.bin" //.ino.bin чтобы не мудрить с полным именем файла прошивки
#define my_version "версия 1.0"
/* Стартовая версия 1.0
- нет зависимости ESP32/8266
- введен режим обновления прошивки программы "по воздуху" (OTA) через чат
- меню управления:
mode - режим измерений с фильтром/без фильтра
start_now - принудительный полив
1_day_plus - Полив отложен на 1 сутки
limit_plus_50 - увеличение 1-й границы на 50 ед
limit_min_50 - уменьшение 1-й границы на 50 ед
limit_plus_100 - увеличение 1-й границы на 100 ед
limit_min_100 - уменьшение 1-й границы на 100 ед
*/
#define my_LED_BUILTIN 2 //встроенный светодиод
#if defined (ESP32)
//do one thing - работает на WokWi
#define CLK 22
#define DIO 23
#define sensor1 34 //датчик1
#define sensor1plus 33 //датчик1 (+)
#define M1plus 14 //насос 1 (+)
#define M1minus 4 //насос 1 (-)
#define ESP32_ true //модель
#define LED_BUILTIN_On 1 //прямая лампочка
#define LED_BUILTIN_Off 0 //
#elif defined(ARDUINO_ARCH_ESP8266)
//do another
#define CLK 14
#define DIO 16
#define sensor1 A0 //датчик1
#define sensor1plus 5 //D12 датчик1 (+)
#define M1plus 13 //D18 насос 1 (+)
#define M1minus 12 //D4 насос 1 (-)
#define ESP32_ false //модель
#define LED_BUILTIN_On 0 //инверсная лампочка
#define LED_BUILTIN_Off 1 //
#else
#error Architecture unrecognized by this code.
#endif
#define BOT_TOKEN "7583551780:AAFt8Veeb_0bCkVCWAmOevzaUCZBEIhBiKE"
int v1 = 500; //Для юкки требуется 500 мл
/* для боя
int efficiency1 = 12; //Производительность 1 насоса - 12 мл/сек
unsigned long PERIOD_1 = 20*1000; // 1 индикация период 20 сек
unsigned long PERIOD_2_1 = 3*24*60*60*1000; // 2_1 полив период 3 суток
unsigned long PERIOD_2_2 = 1*24*60*60*1000; // 2_2 полив период не ранее 1 суток (если по датчику влажности)
unsigned long PERIOD_3 = 5*60*1000; // 3 измерение период 5 мин
unsigned long PERIOD_4 = 60*60*1000; // 3 отправка период 60 мин (изменяется по команде бота)
*/
// для отладки
int efficiency1 = 50; //для теста - Производительность 1 насоса
unsigned long PERIOD_1 = 1*1000; // 1 индикация период 1 сек
unsigned long PERIOD_2_1 = 3*60*1000; // 2_1 полив период 3 минут
unsigned long PERIOD_2_2 = 1*60*1000; // 2_2 полив период не ранее 1 минуты (если по датчику влажности)
unsigned long PERIOD_3 = 2*1000; // 3 измерение период 2 сек
unsigned long PERIOD_4 = 65*1000; // 4 отправка период 65 сек
unsigned long PERIOD_2_3 = v1/efficiency1*1000; // 2_3 длительность полива
unsigned long timer_1, timer_2_1, timer_2_2, timer_3, timer_4;
if (ESP32_) {
int soilMoistureLimit1 = 3000; //предел для датчика 1 (ESP32 - 4096)
} else {
int soilMoistureLimit1 = 900; //предел для датчика 1 (ESP8266 - 1024)
}
int pompValue1 = soilMoistureLimit1 * 1.1; //начальное значение насоса 1 больше нормального (лимит) на 10%
int soilMoistureValue1 = soilMoistureLimit1 - 100; //начальное значение влажности почвы
bool work_flag = false; // переменая для интервала полива
bool mode_filt = true; // начинаем всегда с фильтром СС
bool MOTOR_ON = HIGH; //(драйвер насоса НЕ инвертирован)
bool MOTOR_OFF = LOW; //(драйвер насоса НЕ инвертирован)
//#include <ESP8266WiFi.h> - есть в фастботе?
//#include <WiFi.h>
#include <FastBot.h>
#include "GyverTM1637.h"
FastBot bot(BOT_TOKEN);
GyverTM1637 disp(CLK, DIO);
void setup() {
Serial.begin(115200);
pinMode(sensor1, INPUT); //Устанавливаем входы датчиков
pinMode(M1plus, OUTPUT); //насос 1 (+)
pinMode(M1minus, OUTPUT); //насос 1 (-)
pinMode(sensor1plus, OUTPUT); //датчик 1 (+)
pinMode(my_LED_BUILTIN, OUTPUT); //светодиод
digitalWrite(M1plus, MOTOR_OFF); //низкий сигнал на насос 1 (+)
digitalWrite(M1minus, MOTOR_OFF); //низкий сигнал на насоы 1 (-)
digitalWrite(my_LED_BUILTIN, LED_BUILTIN_Off); //низкий сигнал на светодиод
disp.brightness(7); // яркость, 0 - 7 (минимум - максимум)
disp.displayInt(8888);
WF_connect();
bot.setChatID("1336182390"); //это мой ID в Телеграмм
bot.attach(newMsg); // подключаем обработчик сообщений
Serial.println(my_definition);
Serial.println(my_version);
bot.sendMessage(my_definition);
bot.sendMessage(my_version);
//WF_disconnect(); //в конце вернуть!!!!!
}
void loop() {
indication(); // блок 1 индикация
irrigation(); // блок 2 полив
measuring(); // блок 3 измерение
sending(); // блок 4 отправка
}
//********************************************************************
void indication() {
if (millis() - timer_1 > PERIOD_1) { // условие таймера
timer_1 = millis(); // сброс таймера
int timeSecs = ((millis() / 1000ul) % 3600ul) % 60ul;
bool bool_1 = (timeSecs >= 0 && timeSecs < 5) || (timeSecs >= 15 && timeSecs < 20) || (timeSecs >= 30 && timeSecs < 35) || (timeSecs >= 45 && timeSecs < 50);
bool bool_2 = (timeSecs >= 5 && timeSecs < 10) || (timeSecs >= 20 && timeSecs < 25) || (timeSecs >= 35 && timeSecs < 40) || (timeSecs >= 50 && timeSecs < 55);
bool bool_3 = (timeSecs >= 10 && timeSecs < 15) || (timeSecs >= 25 && timeSecs < 30) || (timeSecs >= 40 && timeSecs < 45) || (timeSecs >= 55 && timeSecs < 60);
if (bool_1)
{
disp.point(false); // выкл точки
disp.displayInt(soilMoistureValue1);
} else if (bool_2)
{
disp.point(false); // выкл точки
disp.displayInt(soilMoistureLimit1);
} else if (bool_3)
{
uint32_t sec = (PERIOD_2_1 + timer_2_1 - millis()) / 1000ul;
int timeHours = (sec / 3600ul);
int timeMins = (sec % 3600ul) / 60ul;
disp.point(true); // вкл точки
disp.displayClock(timeHours, timeMins);
} else
{
}
}
}
//********************************************************************
void irrigation() {
if (millis() - timer_2_1 > PERIOD_2_1 || (millis() - timer_2_1 > PERIOD_2_2 && soilMoistureValue1 >= soilMoistureLimit1)) {
timer_2_1 = millis(); // сброс таймера периода
timer_2_2 = millis(); // сброс таймера выполнения
work_flag = true;
digitalWrite(my_LED_BUILTIN, LED_BUILTIN_On); // включили лампочку
digitalWrite(M1plus, MOTOR_ON); // высокий сигнал на насос 1
pompValue1 = soilMoistureLimit1 * 0.7; // индикация полива и нового начала отсчета на полив }
Serial.println("Полив начался");
}
if (((millis() - timer_2_2) > PERIOD_2_3) && work_flag) {
work_flag = false; // сбросить флаг на выполнение
digitalWrite(M1plus, MOTOR_OFF); // низкий сигнал на насос 1
digitalWrite(my_LED_BUILTIN, LED_BUILTIN_Off); // выключили лампочку
Serial.println("Полив завершен");
}
if (work_flag) {
//Serial.println(millis()); //постоянное выполнение "внутри" work_time - сейчас не требуется
}
}
void measuring() { //сделать запрет при wifi!
if (millis() - timer_3 > PERIOD_3) {
timer_3 = millis();
digitalWrite(my_LED_BUILTIN, LED_BUILTIN_On); //включили светодиод
digitalWrite(sensor1plus, 1); //включили питание датчика 1
delay(1000);
int newsoilMoistureValue1 = analogRead(sensor1); //Считываем данные с датчика 1
digitalWrite(sensor1plus, 0); //выключили питание датчика 1
if (mode_filt) {
soilMoistureValue1 += (newsoilMoistureValue1 - soilMoistureValue1) * 0.5; //скользящее среднее датчика 1
} else {
soilMoistureValue1 = newsoilMoistureValue1; //без скользящего среднего
}
digitalWrite(my_LED_BUILTIN, LED_BUILTIN_Off); //затушили светодиод
Serial.print(soilMoistureValue1);
Serial.print(" ");
Serial.print(soilMoistureLimit1);
Serial.print(" ");
Serial.print(int ((PERIOD_2_1 + timer_2_1 - millis()) / 1000ul));
Serial.print(" ");
Serial.println(int ((PERIOD_2_2 + timer_2_1 - millis()) / 1000ul));
}
}
//********************************************************************
void sending() {
if (millis() - timer_4 > PERIOD_4) {
timer_4 = millis();
//WF_connect(); вернуть включение/выключение
const char* host = "open-monitoring.online";
const char* streamId = "3734"; //ID
const char* privateKey = "I3BXVp"; //Ключ
Serial.print("connecting to ");
Serial.println(host);
WiFiClient client; // Use WiFiClient class to create TCP connections
int httpPort = 80;
while (!client.connect(host, httpPort)) {
delay(100);
Serial.print(".");
}
Serial.println("");
Serial.println("OK");
String url = "/get?cid="; // We now create a URI for the request
url += streamId;
url += "&key=";
url += privateKey;
url += "&p1="; // Добавляем в запрос данные 2-х датчиков
url += soilMoistureValue1;
url += "&p2=";
url += pompValue1;
if (pompValue1 != soilMoistureLimit1) pompValue1 = soilMoistureLimit1;
Serial.print("Requesting URL: ");
Serial.println(url);
client.print(String("GET ") + url + " HTTP/1.1\r\n" + // This will send the request to the server
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n");
unsigned long timeout = millis();
while (client.available() == 0) {
if (millis() - timeout > 5000) {
Serial.println(">>> Client Timeout !");
client.stop();
return;
}
}
// Read all the lines of the reply from server and print them to Serial
//while (client.available()) {
// String line = client.readStringUntil('\r');
// Serial.print(line);
// yield();
//}
Serial.println();
Serial.println("closing connection");
//WF_disconnect();
}
}
//********************************************************************
void WF_connect() {
/*
const String wf_ssid = "Guest"; // Точка доступа (!) или Giga-net1
const String wf_pass = "04121986"; // Пароль (!) или 19790613
*/
const String wf_ssid = "Wokwi-GUEST"; // Точка доступа (!)
const String wf_pass = ""; // Пароль (!)
digitalWrite(my_LED_BUILTIN, LED_BUILTIN_On); //светим пока не произойдет соединение
Serial.print("Connecting to ");
Serial.println(wf_ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(wf_ssid, wf_pass, 6);
while (WiFi.status() != WL_CONNECTED) {
delay(100);
Serial.print(".");
}
Serial.println("Wi-Fi connected");
digitalWrite(my_LED_BUILTIN, LED_BUILTIN_Off);
}
//********************************************************************
void WF_disconnect() {
WiFi.disconnect();
delay(10);
Serial.println("Wi-Fi disconnected");
}
//********************************************************************
void newMsg(FB_msg& msg) { //обработчик сообщений
FB_Time t(msg.unix, 3);
Serial.print(t.timeString());
Serial.print(' ');
Serial.print(t.dateString());
Serial.print(' ');
Serial.print(bot.lastUsrMsg());
Serial.print(", ");
Serial.print(msg.messageID);
Serial.print(", ");
Serial.print(msg.username); //выводим имя юзера и текст сообщения
Serial.print(", ");
Serial.println(msg.text);
if (msg.OTA && msg.fileName == "fin_humidity_ESP8266.ino.bin") {
bot.update(); //обновление прошивки
}
if (msg.text == "/mode") {
mode_filt = !mode_filt; //режим измерений изменен
if (mode_filt)
{
bot.sendMessage("Режим измерений с фильтром включен");
Serial.print("Режим измерений с фильтром включен");
} else
{
bot.sendMessage("Режим измерений с фильтром выключен");
Serial.print("Режим измерений с фильтром выключен");
}
}
if (msg.text == "/start_now") { //принудительный полив
timer_2_1 = millis() - PERIOD_2_1 - 100; //100 взято с запасом, достаточно 1
bot.sendMessage("Принудительный полив");
Serial.print("Принудительный полив");
}
if (msg.text == "/1_day_plus") {
timer_2_1 -= 24*60*60*1000; // задержка полива
bot.sendMessage("Полив отложен на 1 сутки");
Serial.print("Полив отложен на 1 сутки");
}
if (msg.text == "/limit_plus_50") {
soilMoistureLimit1 += 50; //изменение предела влажности для датчиков
bot.sendMessage("Лимит влажности для датчика увеличен на 50 ед.");
Serial.print("Лимит влажности для датчика увеличен на 5о ед.");
}
if (msg.text == "/limit_min_50") {
soilMoistureLimit1 -= 50;
bot.sendMessage("Лимит влажности для датчика уменьшен на 50 ед.");
Serial.print("Лимит влажности для датчика уменьшен на 50 ед.");
}
if (msg.text == "/limit_plus_100") {
soilMoistureLimit1 += 100; //изменение предела влажности для датчиков
bot.sendMessage("Лимит влажности для датчика увеличен на 100 ед.");
Serial.print("Лимит влажности для датчика уменьшен на 100 ед.");
}
if (msg.text == "/limit_min_100") {
soilMoistureLimit1 -= 100;
bot.sendMessage("Лимит влажности для датчика уменьшен на 100 ед.");
Serial.print("Лимит влажности для датчика уменьшен на 100 ед.");
}
}
//********************************************************************