#include <UltrasonicSensor.h>
#include <NTPClient.h>
#include <WiFi.h>
#include <WiFiUdp.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>
#include <ArduinoJson.h>
#include <LiquidCrystal_I2C.h>
QueueHandle_t xFila;
SemaphoreHandle_t xSerialSemaphore;
SemaphoreHandle_t xLcdSemaphore;
SemaphoreHandle_t xPumpTwoSemaphore;
static void Producer( void *pvParameters );
static void Consumer( void *pvParameters );
int tamFila = 1;
int num_mensagens_recebidas_telegram = 0;
String resposta_msg_recebida;
#define PIN_TRIGGER_U1 14
#define PIN_ECHO_U1 12
#define PIN_TRIGGER_U2 26
#define PIN_ECHO_U2 27
#define PIN_RELAY_1 33
#define PIN_RELAY_2 32
#define PIN_LED 15
#define TELEGRAM_DEBUG 1
#define HEIGHT 150
#define FILLED_TURNOFF_THRESHOLD 15
#define EMPTY_HEIGHT_PERCENT_THRESHOLD 90
#define EMPTY_TWO_HEIGHT_PERCENT_THRESHOLD 65
#define EMPTY_TURNOFF_PERCENT_THRESHOLD_FIRST 90
#define EMPTY_HEIGHT_THRESHOLD (HEIGHT*EMPTY_HEIGHT_PERCENT_THRESHOLD)/100
#define EMPTY_TWO_HEIGHT_THRESHOLD (HEIGHT*EMPTY_TWO_HEIGHT_PERCENT_THRESHOLD)/100
#define TURNOFF_THRESHOLD_FIRST (HEIGHT*EMPTY_TURNOFF_PERCENT_THRESHOLD_FIRST)/100
#define CMD_STATUS "STATUS"
#define token_acesso_telegram "5437214532:AAHUb7bKjy6r5PF5E6D0Ty_Phod_Uxnn5mg"
/* Credenciais wi-fi */
#define ssid_wifi "Wokwi-GUEST"
#define password_wifi ""
WiFiUDP ntpUDP;
const long utcOffsetInSeconds = 0;
NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds);
UltrasonicSensor ultrasonic1(PIN_TRIGGER_U1, PIN_ECHO_U1);
UltrasonicSensor ultrasonic2(PIN_TRIGGER_U2, PIN_ECHO_U2);
LiquidCrystal_I2C lcd(0x27,16,2);
WiFiClientSecure client;
UniversalTelegramBot bot(token_acesso_telegram, client);
int distancePumpOne = 0;
int distancePumpTwo = 0;
int hour = 0;
static void init_wifi(){
Serial.print("Conectando-se ao Wi-Fi");
WiFi.begin(ssid_wifi, password_wifi, 6);
while (WiFi.status() != WL_CONNECTED) {
delay(100);
Serial.print(".");
}
Serial.println(" Conectado!");
}
static void init_ultrasonics(){
int temperature = 22;
ultrasonic1.setTemperature(temperature);
ultrasonic2.setTemperature(temperature);
}
static void setup_pins(){
pinMode(PIN_RELAY_1, OUTPUT);
pinMode(PIN_RELAY_2, OUTPUT);
pinMode(PIN_LED, OUTPUT);
}
static void init_serial_semaphore(){
if ( xSerialSemaphore == NULL )
{
xSerialSemaphore = xSemaphoreCreateMutex();
if ( ( xSerialSemaphore ) != NULL )
xSemaphoreGive(( xSerialSemaphore ));
}
}
static void init_distance_lcd_semaphore(){
if ( xLcdSemaphore == NULL )
{
xLcdSemaphore = xSemaphoreCreateMutex();
if ( ( xLcdSemaphore ) != NULL )
xSemaphoreGive(( xLcdSemaphore ));
}
}
static void init_distance_pump_two_semaphore(){
if ( xPumpTwoSemaphore == NULL )
{
xPumpTwoSemaphore = xSemaphoreCreateMutex();
if ( ( xPumpTwoSemaphore ) != NULL )
xSemaphoreGive(( xPumpTwoSemaphore ));
}
}
static void init_queue(){
while(!Serial) ;
xFila = xQueueCreate( tamFila, sizeof( int ) );
if(xFila == NULL){
Serial.println("Erro criando fila");
}
}
static void init_lcd(){
lcd.init();
lcd.backlight();
}
void setup() {
Serial.begin(115200);
init_wifi();
init_ultrasonics();
setup_pins();
init_serial_semaphore();
init_queue();
timeClient.begin();
init_lcd();
xTaskCreate( updateDistanceWaterPumpOne, "updateDistanceWaterPumpOne", 1000, NULL, 5, NULL );
xTaskCreate( updateDistanceWaterPumpTwo, "updateDistanceWaterPumpTwo", 1000, NULL, 5, NULL );
xTaskCreate( waterPumpOne, "WaterPumpOne", 1000, NULL, 1, NULL );
xTaskCreate( waterPumpTwo, "WaterPumpTwo", 1000, NULL, 1, NULL );
xTaskCreate( showActiveLed, "ShowSystemActive", 1000, NULL, 1, NULL );
xTaskCreate( showStatusWaterPumpOne, "showStatusWaterPumpOne", 50000, NULL, 1, NULL );
xTaskCreate( showStatusWaterPumpTwo, "showStatusWaterPumpTwo", 50000, NULL, 2, NULL );
xTaskCreate( updateHour, "updateHour", 10000, NULL, 5, NULL );
//xTaskCreate( telegramTask, "telegramTask", 1000, NULL, 1, NULL );
}
void loop() {}
static void waterPumpOne( void *pvParameters ){
portTickType xLastWakeTime;
xLastWakeTime = xTaskGetTickCount();
for(;;){
int distance = distancePumpOne;
bool inTimeBox = hour >= 11 && hour <= 17; // a hora está em utc, br 8:00 as 14:000
if(inTimeBox && distance > EMPTY_HEIGHT_THRESHOLD ){
activateRelay(PIN_RELAY_1);
}
if(distance <= FILLED_TURNOFF_THRESHOLD){
deactivateRelay(PIN_RELAY_1);
}
xQueueSend(xFila, (void *)&distance, portMAX_DELAY);
vTaskDelayUntil( &xLastWakeTime, 2000 / portTICK_RATE_MS);
}
}
static void waterPumpTwo( void *pvParameters ){
portTickType xLastWakeTime;
xLastWakeTime = xTaskGetTickCount();
for(;;){
int distPumpOne;
xQueueReceive(xFila, (void *)&distPumpOne, portMAX_DELAY);
bool inTimeBox = hour >= 11 && hour <= 17; // a hora está em utc, br 8:00 as 14:000
if(distPumpOne <= FILLED_TURNOFF_THRESHOLD && distancePumpTwo > EMPTY_TWO_HEIGHT_THRESHOLD){
activateRelay(PIN_RELAY_2);
}
if(distancePumpOne > EMPTY_HEIGHT_THRESHOLD || distancePumpTwo < FILLED_TURNOFF_THRESHOLD){
deactivateRelay(PIN_RELAY_2);
}
vTaskDelayUntil( &xLastWakeTime, 1000 / portTICK_RATE_MS);
}
}
static String show_status(int pin_relay){
if(digitalRead(pin_relay) == HIGH){
return "ON";
}
return "OFF";
}
static void updateDistanceWaterPumpOne( void *pvParameters ){
portTickType xLastWakeTime;
xLastWakeTime = xTaskGetTickCount();
for(;;){
distancePumpOne = ultrasonic1.distanceInCentimeters();
vTaskDelayUntil( &xLastWakeTime, 1000 / portTICK_RATE_MS);
}
}
static void updateDistanceWaterPumpTwo( void *pvParameters ){
portTickType xLastWakeTime;
xLastWakeTime = xTaskGetTickCount();
for(;;){
distancePumpTwo = ultrasonic2.distanceInCentimeters();
vTaskDelayUntil( &xLastWakeTime, 1000 / portTICK_RATE_MS);
}
}
static void updateHour( void *pvParameters ){
portTickType xLastWakeTime;
xLastWakeTime = xTaskGetTickCount();
for(;;){
timeClient.update();
hour = timeClient.getHours();
vTaskDelayUntil( &xLastWakeTime, 60000 / portTICK_RATE_MS);
}
}
static void showStatusWaterPumpOne( void *pvParameters ){
portTickType xLastWakeTime;
xLastWakeTime = xTaskGetTickCount();
for(;;){
if ( xSemaphoreTake( xSerialSemaphore, ( TickType_t ) 5 ) == pdTRUE )
{
String message = "P-ONE--"
+ show_status(PIN_RELAY_1) + "-"
+ get_percentege_full(distancePumpOne)
+ "%";
lcd.clear();
lcd.setCursor(0,0);
lcd.print(message);
xSemaphoreGive( xSerialSemaphore );
}
vTaskDelayUntil( &xLastWakeTime, 1000 / portTICK_RATE_MS);
}
}
static void showStatusWaterPumpTwo( void *pvParameters ){
portTickType xLastWakeTime;
xLastWakeTime = xTaskGetTickCount();
vTaskDelay(500 / portTICK_RATE_MS);
for(;;){
if ( xSemaphoreTake( xSerialSemaphore, ( TickType_t ) 5 ) == pdTRUE )
{
String message = "P-TWO--"
+ show_status(PIN_RELAY_2) + "-"
+ get_percentege_full(distancePumpTwo)
+ "%";
lcd.setCursor(0,1);
lcd.print(message);
xSemaphoreGive( xSerialSemaphore );
}
vTaskDelayUntil( &xLastWakeTime, 1500 / portTICK_RATE_MS);
}
}
static String get_percentege_full(int cm){
int percent = 100 - (cm*100/HEIGHT);
if(percent < 0){
return "0";
}
if(percent > 100){
return "100";
}
return String(percent);
}
static void deactivateRelay(int pinRelay){
if(digitalRead(pinRelay) != LOW){
digitalWrite(pinRelay, LOW);
}
}
static void activateRelay(int pinRelay){
if(digitalRead(pinRelay) != HIGH ){
digitalWrite(pinRelay, HIGH);
}
}
static void showActiveLed( void *pvParameters ){
portTickType xLastWakeTime;
xLastWakeTime = xTaskGetTickCount();
for(;;){
digitalWrite(PIN_LED, !digitalRead(PIN_LED));
vTaskDelayUntil( &xLastWakeTime, 1000 / portTICK_RATE_MS);
}
}
/* Função: conecta-se a rede wi-fi
* Parametros: nenhum
* Retorno: nenhum
*/
void conecta_wifi(void)
{
/* Se ja estiver conectado, nada é feito. */
if (WiFi.status() == WL_CONNECTED)
return;
/* refaz a conexão */
WiFi.begin(ssid_wifi, password_wifi, 6);
while (WiFi.status() != WL_CONNECTED)
{
vTaskDelay( 100 / portTICK_PERIOD_MS );
Serial.print(".");
}
Serial.println();
Serial.print("Conectado com sucesso a rede wi-fi ");
Serial.println(ssid_wifi);
Serial.print("IP: ");
Serial.println(WiFi.localIP());
}
/* Função: verifica se a conexao wi-fi está ativa
* (e, em caso negativo, refaz a conexao)
* Parametros: nenhum
* Retorno: nenhum
*/
void verifica_conexao_wifi(void)
{
conecta_wifi();
}
/* Função: trata mensagens recebidas via Telegram
* Parametros: mensagem recebida
* Retorno: resposta da mensagem recebida
*/
String trata_mensagem_recebida(String msg_recebida)
{
String resposta = "";
bool comando_valido = false;
float temperatura_lida = 0.0;
float umidade_lida = 0.0;
/* Faz tratamento da mensagem recebida */
if (msg_recebida.equals(CMD_STATUS))
{
int distancePumpTwo = ultrasonic2.distanceInCentimeters();
int distancePumpOne = ultrasonic1.distanceInCentimeters();
resposta = "Status das bombas: 1 = "+
String(distancePumpOne)+
", 2 = "+
String(distancePumpTwo);
comando_valido = true;
}
if (comando_valido == false)
resposta = "Comando invalido: "+msg_recebida;
return resposta;
}
static void telegramTask( void *pvParameters ){
portTickType xLastWakeTime;
xLastWakeTime = xTaskGetTickCount();
int i;
for(;;){
verifica_conexao_wifi();
if ( xSemaphoreTake( xSerialSemaphore, ( TickType_t ) 5 ) == pdTRUE )
{
Serial.println("[BOT] Verificando ");
xSemaphoreGive( xSerialSemaphore );
}
/* Verifica se há mensagens a serem recebidas */
num_mensagens_recebidas_telegram = bot.getUpdates(bot.last_message_received + 1);
//if (num_mensagens_recebidas_telegram > 0)
//{
if ( xSemaphoreTake( xSerialSemaphore, ( TickType_t ) 5 ) == pdTRUE )
{
Serial.print("[BOT] Mensagens recebidas: ");
Serial.println(num_mensagens_recebidas_telegram);
xSemaphoreGive( xSerialSemaphore );
}
//}
/* Recebe mensagem a mensagem, faz tratamento e envia resposta */
while(num_mensagens_recebidas_telegram)
{
for (i=0; i<num_mensagens_recebidas_telegram; i++)
{
resposta_msg_recebida = "";
resposta_msg_recebida = trata_mensagem_recebida(bot.messages[i].text);
bot.sendMessage(bot.messages[i].chat_id, resposta_msg_recebida, "");
}
num_mensagens_recebidas_telegram = bot.getUpdates(bot.last_message_received + 1);
}
vTaskDelay( 1500 / portTICK_RATE_MS);
}
}
esp:VIN
esp:GND.2
esp:D13
esp:D12
esp:D14
esp:D27
esp:D26
esp:D25
esp:D33
esp:D32
esp:D35
esp:D34
esp:VN
esp:VP
esp:EN
esp:3V3
esp:GND.1
esp:D15
esp:D2
esp:D4
esp:RX2
esp:TX2
esp:D5
esp:D18
esp:D19
esp:D21
esp:RX0
esp:TX0
esp:D22
esp:D23
ultrasonic1:VCC
ultrasonic1:TRIG
ultrasonic1:ECHO
ultrasonic1:GND
ultrasonic2:VCC
ultrasonic2:TRIG
ultrasonic2:ECHO
ultrasonic2:GND
relay1:NO2
relay1:NC2
relay1:P2
relay1:COIL2
relay1:NO1
relay1:NC1
relay1:P1
relay1:COIL1
r1:1
r1:2
r2:1
r2:2
r3:1
r3:2
led1:A
led1:C
relay2:NO2
relay2:NC2
relay2:P2
relay2:COIL2
relay2:NO1
relay2:NC1
relay2:P1
relay2:COIL1
led2:A
led2:C
led3:A
led3:C
lcd1:GND
lcd1:VCC
lcd1:SDA
lcd1:SCL