diff --git a/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/0_ESP32TTGO_FIRESTORE_SMS.ino b/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/0_ESP32TTGO_FIRESTORE_SMS.ino new file mode 100644 index 0000000..1938b7c --- /dev/null +++ b/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/0_ESP32TTGO_FIRESTORE_SMS.ino @@ -0,0 +1,270 @@ +///////////////////////////////////////////////////////////////// +/* + Send an SMS from ESP32 (ft. Twilio) + https://youtu.be/SP4pvYCQAfc + Created by Eric N. (ThatProject) +*/ +///////////////////////////////////////////////////////////////// + +#include "DHTesp.h" // Click here to get the library: http://librarymanager/All#DHTesp +#include +#include "Display.h" +#include "Network.h" +#include "Messenger.h" + +#ifndef ESP32 +#pragma message(THIS EXAMPLE IS FOR ESP32 ONLY!) +#error Select ESP32 board. +#endif + +/**************************************************************/ +/* Example how to read DHT sensors from an ESP32 using multi- */ +/* tasking. */ +/* This example depends on the Ticker library to wake up */ +/* the task every 20 seconds */ +/**************************************************************/ + +Display *display; +Network *network; +Messenger *messenger; +DHTesp dht; + +void tempTask(void *pvParameters); +bool getTemperature(); +void triggerGetTemp(); + +/** Task handle for the light value read task */ +TaskHandle_t tempTaskHandle = NULL; +/** Ticker for temperature reading */ +Ticker tempTicker; +/** Comfort profile */ +ComfortState cf; +/** Flag if task should run */ +bool tasksEnabled = false; +/** Pin number for DHT11 data pin */ +int dhtPin = 21; + +/** + * initTemp + * Setup DHT library + * Setup task and timer for repeated measurement + * @return bool + * true if task and timer are started + * false if task or timer couldn't be started + */ +bool initTemp() { + byte resultValue = 0; + // Initialize temperature sensor + dht.setup(dhtPin, DHTesp::DHT11); + Serial.println("DHT initiated"); + + // Start task to get temperature + xTaskCreatePinnedToCore( + tempTask, /* Function to implement the task */ + "tempTask ", /* Name of the task */ + 10000, /* Stack size in words */ + NULL, /* Task input parameter */ + 5, /* Priority of the task */ + &tempTaskHandle, /* Task handle. */ + 1); /* Core where the task should run */ + + if (tempTaskHandle == NULL) { + Serial.println("Failed to start task for temperature update"); + return false; + } else { + // Start update of environment data every 20 seconds + tempTicker.attach(20, triggerGetTemp); + } + return true; +} + +/** + * triggerGetTemp + * Sets flag dhtUpdated to true for handling in loop() + * called by Ticker getTempTimer + */ +void triggerGetTemp() { + if (tempTaskHandle != NULL) { + xTaskResumeFromISR(tempTaskHandle); + } +} + +/** + * Task to reads temperature from DHT11 sensor + * @param pvParameters + * pointer to task parameters + */ +void tempTask(void *pvParameters) { + Serial.println("tempTask loop started"); + while (1) // tempTask loop + { + if (tasksEnabled) { + // Get temperature values + getTemperature(); + } + // Got sleep again + vTaskSuspend(NULL); + } +} + +/** + * getTemperature + * Reads temperature from DHT11 sensor + * @return bool + * true if temperature could be aquired + * false if aquisition failed +*/ +bool getTemperature() { + // Reading temperature for humidity takes about 250 milliseconds! + // Sensor readings may also be up to 2 seconds 'old' (it's a very slow sensor) + TempAndHumidity newValues = dht.getTempAndHumidity(); + // Check if any reads failed and exit early (to try again). + if (dht.getStatus() != 0) { + Serial.println("DHT11 error status: " + String(dht.getStatusString())); + return false; + } + + float heatIndex = dht.computeHeatIndex(newValues.temperature, newValues.humidity); + float dewPoint = dht.computeDewPoint(newValues.temperature, newValues.humidity); + float cr = dht.getComfortRatio(cf, newValues.temperature, newValues.humidity); + + String comfortStatus; + switch(cf) { + case Comfort_OK: + comfortStatus = "OK"; + break; + case Comfort_TooHot: + comfortStatus = "TooHot"; + break; + case Comfort_TooCold: + comfortStatus = "TooCold"; + break; + case Comfort_TooDry: + comfortStatus = "TooDry"; + break; + case Comfort_TooHumid: + comfortStatus = "TooHumid"; + break; + case Comfort_HotAndHumid: + comfortStatus = "Hot&Humid"; + break; + case Comfort_HotAndDry: + comfortStatus = "Hot&Dry"; + break; + case Comfort_ColdAndHumid: + comfortStatus = "Cold&Humid"; + break; + case Comfort_ColdAndDry: + comfortStatus = "Cold&Dry"; + break; + default: + comfortStatus = "Unknown"; + break; + }; + + Serial.println(" T:" + String(newValues.temperature) + " H:" + String(newValues.humidity) + " I:" + String(heatIndex) + " D:" + String(dewPoint) + " " + comfortStatus); + + display->tempUpdates("Temp " + String(newValues.temperature, 1) +"'C", + "Humidity " + String(newValues.humidity,0) + "%", + comfortStatus); + + network->firestoreDataUpdate(newValues.temperature, newValues.humidity); + + String msgBody = ""; + if (newValues.temperature >28 || newValues.temperature <18){ + msgBody += "Temperature: "; + msgBody += String(newValues.temperature, 1) +"'C\n"; + } + + if(newValues.humidity > 60 || newValues.humidity < 20){ + msgBody += "Humidity: "; + msgBody += String(newValues.humidity, 0) +"%\n"; + } + + if(msgBody.length() >0){ + msgBody += "From the House>Room 1"; + messenger->sendMessage(msgBody); + } + + return true; +} + +void setup() +{ + Serial.begin(115200); + Serial.println(); + Serial.println("DHT ESP32 example with tasks"); + + initDisplay(); + initNetwork(); + initMessenger(); + initTemp(); + // Signal end of setup() to tasks + tasksEnabled = true; +} + +void loop() { + if (!tasksEnabled) { + // Wait 2 seconds to let system settle down + delay(2000); + // Enable task that will read values from the DHT sensor + tasksEnabled = true; + if (tempTaskHandle != NULL) { + vTaskResume(tempTaskHandle); + } + } + yield(); +} + +void initDisplay(){ + display = new Display(); + display->initTFT(); + display->showWiFiIcon(false); + display->showFirebaseIcon(false); + display->centerMsg("System Init..."); +} + +void initNetwork(){ + void (*ptr)(Network_State_t) = &networkEvent; + network = new Network(ptr); + network->initWiFi(); +} + +void networkEvent(Network_State_t event){ + switch(event){ + case NETWORK_CONNECTED: + display->showWiFiIcon(true); + break; + case NETWORK_DISCONNECTED: + display->showWiFiIcon(false); + break; + case FIREBASE_CONNECTED: + display->showFirebaseIcon(true); + break; + case FIREBASE_DISCONNECTED: + display->showFirebaseIcon(false); + break; + default: break; + } +} + +void initMessenger(){ + messenger = new Messenger(); +} + + + + + + + + + + + + + + + + + diff --git a/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/Display.cpp b/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/Display.cpp new file mode 100644 index 0000000..4f5dfff --- /dev/null +++ b/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/Display.cpp @@ -0,0 +1,66 @@ +#include "Display.h" + +static Display* instance = NULL; + +Display::Display(){ + instance = this; + tft = new TFT_eSPI(); +} + +Display::~Display(){ + delete tft; +} + +bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t * bitmap){ + if (y >= instance->tft->height()) return 0; + instance->tft->pushImage(x, y, w, h, bitmap); + return 1; +} + +void Display::initTFT(){ + tft->init(); + tft->fillScreen(TFT_BLACK); + tft->setRotation(1); + tft->setTextColor(TFT_WHITE, TFT_BLACK); + tft->setTextDatum(MC_DATUM); + tft->setFreeFont(&Orbitron_Light_24); + + TJpgDec.setJpgScale(1); + TJpgDec.setSwapBytes(true); + TJpgDec.setCallback(tft_output); + + if(!SPIFFS.begin()){ + while(1) yield(); + } +} + +void Display::centerMsg(String text){ + tft->drawString(text, tft->width()/2, 60); +} + +void Display::tempUpdates(String temp, String hum, String status){ + tft->setTextPadding(tft->width()); + tft->drawString(temp, tft->width()/2, 40); + tft->drawString(hum, tft->width()/2, 70); + tft->drawString(status, tft->width()/2, 110); +} + +void Display::showWiFiIcon(bool isOn){ + tft->fillRect(tft->width() -30, 0, 30, 30, TFT_BLACK); + TJpgDec.drawFsJpg(tft->width() -30, 0, isOn ? "/icon_wifi_on.jpg" : "/icon_wifi_off.jpg"); +} + +void Display::showFirebaseIcon(bool isOn){ + tft->fillRect(tft->width() -60, 0, 30, 30, TFT_BLACK); + TJpgDec.drawFsJpg(tft->width() -60, 0, isOn ? "/icon_firebase_on.jpg" : "/icon_firebase_off.jpg"); +} + + + + + + + + + + diff --git a/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/Display.h b/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/Display.h new file mode 100644 index 0000000..19572f6 --- /dev/null +++ b/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/Display.h @@ -0,0 +1,25 @@ +#ifndef Display_H_ +#define Display_H_ + +#include +#include +#include "SPIFFS.h" + +class Display { +private: + TFT_eSPI* tft; + friend bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t * bitmap); + +public: + Display(); + ~Display(); + + void initTFT(); + void centerMsg(String text); + void tempUpdates(String temp, String hum, String status); + void showWiFiIcon(bool isOn); + void showFirebaseIcon(bool isOn); +}; + + +#endif \ No newline at end of file diff --git a/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/Messenger.cpp b/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/Messenger.cpp new file mode 100644 index 0000000..73d38a5 --- /dev/null +++ b/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/Messenger.cpp @@ -0,0 +1,32 @@ +#include "Messenger.h" + +// Values from Twilio (find them on the dashboard) +static const char *account_sid = ""; +static const char *auth_token = ""; +// Phone number should start with "+" +static const char *from_number = ""; + +// You choose! +// Phone number should start with "+" +static const char *to_number = ""; + +Messenger::Messenger() { + twilio = new Twilio(account_sid, auth_token); +} + +Messenger::~Messenger() { + delete twilio; +} + +void Messenger::sendMessage(String msg) { + + if (WiFi.status() != WL_CONNECTED) return; + + String response; + bool success = twilio->send_message(to_number, from_number, msg, response); + if (success) { + Serial.println("Sent message successfully!"); + } else { + Serial.println(response); + } +} \ No newline at end of file diff --git a/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/Messenger.h b/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/Messenger.h new file mode 100644 index 0000000..0525a94 --- /dev/null +++ b/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/Messenger.h @@ -0,0 +1,16 @@ +#ifndef Messenger_H_ +#define Messenger_H_ + +#include "twilio.hpp" + +class Messenger { +private: + Twilio *twilio; + +public: + Messenger(); + ~Messenger(); + void sendMessage(String msg); +}; + +#endif \ No newline at end of file diff --git a/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/Network.cpp b/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/Network.cpp new file mode 100644 index 0000000..ec69ec1 --- /dev/null +++ b/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/Network.cpp @@ -0,0 +1,102 @@ +#include "Network.h" +#include "addons/TokenHelper.h" + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +#define API_KEY "" +#define FIREBASE_PROJECT_ID "" +#define USER_EMAIL "" +#define USER_PASSWORD "" + +static Network *instance = NULL; + +Network::Network(){} + +Network::Network(FuncPtrInt f){ + instance = this; + callBackEvent = f; +} + +void WiFiEventConnected(WiFiEvent_t event, WiFiEventInfo_t info){ + Serial.println("WIFI CONNECTED! BUT WAIT FOR THE LOCAL IP ADDR"); +} + +void WiFiEventGotIP(WiFiEvent_t event, WiFiEventInfo_t info){ + Serial.print("LOCAL IP ADDRESS: "); + Serial.println(WiFi.localIP()); + instance->callBackEvent(NETWORK_CONNECTED); + instance->firebaseInit(); +} + +void WiFiEventDisconnected(WiFiEvent_t event, WiFiEventInfo_t info){ + Serial.println("WIFI DISCONNECTED!"); + instance->callBackEvent(NETWORK_DISCONNECTED); + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +} + +void FirestoreTokenStatusCallback(TokenInfo info){ + Serial.printf("Token Info: type = %s, status = %s\n", getTokenType(info).c_str(), getTokenStatus(info).c_str()); + if(info.status == token_status_ready){ + instance->callBackEvent(FIREBASE_CONNECTED); + }else{ + instance->callBackEvent(FIREBASE_DISCONNECTED); + } +} + +void Network::initWiFi(){ + WiFi.disconnect(); + WiFi.onEvent(WiFiEventConnected, SYSTEM_EVENT_STA_CONNECTED); + WiFi.onEvent(WiFiEventGotIP, SYSTEM_EVENT_STA_GOT_IP); + WiFi.onEvent(WiFiEventDisconnected, SYSTEM_EVENT_STA_DISCONNECTED); + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +} + +void Network::firebaseInit(){ + config.api_key = API_KEY; + + auth.user.email = USER_EMAIL; + auth.user.password = USER_PASSWORD; + + config.token_status_callback = FirestoreTokenStatusCallback; + + Firebase.begin(&config, &auth); +} + +void Network::firestoreDataUpdate(double temp, double humi){ + if(WiFi.status() == WL_CONNECTED && Firebase.ready()){ + String documentPath = "House/Room_1"; + + FirebaseJson content; + + content.set("fields/temperature/doubleValue", String(temp).c_str()); + content.set("fields/humidity/doubleValue", String(humi).c_str()); + + if(Firebase.Firestore.patchDocument(&fbdo, FIREBASE_PROJECT_ID, "", documentPath.c_str(), content.raw(), "temperature,humidity")){ + Serial.printf("ok\n%s\n\n", fbdo.payload().c_str()); + return; + }else{ + Serial.println(fbdo.errorReason()); + } + + if(Firebase.Firestore.createDocument(&fbdo, FIREBASE_PROJECT_ID, "", documentPath.c_str(), content.raw())){ + Serial.printf("ok\n%s\n\n", fbdo.payload().c_str()); + return; + }else{ + Serial.println(fbdo.errorReason()); + } + } +} + + + + + + + + + + + + + diff --git a/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/Network.h b/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/Network.h new file mode 100644 index 0000000..cd290b6 --- /dev/null +++ b/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/Network.h @@ -0,0 +1,37 @@ +#ifndef Network_H_ +#define Network_H_ + +#include +#include + +typedef enum { + NETWORK_CONNECTED, + NETWORK_DISCONNECTED, + FIREBASE_CONNECTED, + FIREBASE_DISCONNECTED +} Network_State_t; + +class Network{ +private: + FirebaseData fbdo; + FirebaseAuth auth; + FirebaseConfig config; + + typedef void (*FuncPtrInt)(Network_State_t); + + void firebaseInit(); + friend void WiFiEventConnected(WiFiEvent_t event, WiFiEventInfo_t info); + friend void WiFiEventGotIP(WiFiEvent_t event, WiFiEventInfo_t info); + friend void WiFiEventDisconnected(WiFiEvent_t event, WiFiEventInfo_t info); + friend void FirestoreTokenStatusCallback(TokenInfo info); + +public: + FuncPtrInt callBackEvent; + Network(); + Network(FuncPtrInt f); + void initWiFi(); + void firestoreDataUpdate(double temp, double humi); +}; + + +#endif \ No newline at end of file diff --git a/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/data/icon_firebase_off.jpg b/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/data/icon_firebase_off.jpg new file mode 100644 index 0000000..c4aeb65 Binary files /dev/null and b/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/data/icon_firebase_off.jpg differ diff --git a/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/data/icon_firebase_on.jpg b/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/data/icon_firebase_on.jpg new file mode 100644 index 0000000..3b19836 Binary files /dev/null and b/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/data/icon_firebase_on.jpg differ diff --git a/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/data/icon_wifi_off.jpg b/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/data/icon_wifi_off.jpg new file mode 100644 index 0000000..ec251de Binary files /dev/null and b/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/data/icon_wifi_off.jpg differ diff --git a/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/data/icon_wifi_on.jpg b/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/data/icon_wifi_on.jpg new file mode 100644 index 0000000..ef4b16e Binary files /dev/null and b/MESSAGE/Twilio/0_ESP32TTGO_FIRESTORE_SMS/data/icon_wifi_on.jpg differ