diff --git a/embedded/lib/Component/Component.hpp b/embedded/lib/Component/Component.hpp index 344d781..b730b9f 100644 --- a/embedded/lib/Component/Component.hpp +++ b/embedded/lib/Component/Component.hpp @@ -5,9 +5,7 @@ enum class ComponentType { Digital, - Analog, - I2C, - Serial + Analog }; class Component{ diff --git a/embedded/lib/Component/DHTComponent.cpp b/embedded/lib/Component/DHTComponent.cpp new file mode 100644 index 0000000..76e98ee --- /dev/null +++ b/embedded/lib/Component/DHTComponent.cpp @@ -0,0 +1,28 @@ +#include "DHTComponent.hpp" + +DHTComponent::DHTComponent(uint8_t type, byte pin) + : _pin(pin), _type(type), _dht(nullptr) +{} + +DHTComponent::~DHTComponent() +{ + delete _dht; +} + +void DHTComponent::setup() +{ + _dht = new DHT_Unified(_pin, _type); + _dht->begin(); +} + +float DHTComponent::getHumidity() +{ + _dht->humidity().getEvent(&_event); + return _event.relative_humidity; +} + +float DHTComponent::getTemperature() +{ + _dht->temperature().getEvent(&_event); + return _event.temperature; +} diff --git a/embedded/lib/Component/DHTComponent.hpp b/embedded/lib/Component/DHTComponent.hpp new file mode 100644 index 0000000..0421ecf --- /dev/null +++ b/embedded/lib/Component/DHTComponent.hpp @@ -0,0 +1,23 @@ +#ifndef _HEADER_COMPONENT_DHT +#define _HEADER_COMPONENT_DHT +#include +#include +#include + +class DHTComponent +{ +public: + DHTComponent(uint8_t type, byte pin); + ~DHTComponent(); + void setup(); + float getHumidity(); + float getTemperature(); + +private: + byte _pin; + uint8_t _type; + DHT_Unified* _dht; + sensors_event_t _event; +}; + +#endif // _HEADER_COMPONENT_LED \ No newline at end of file diff --git a/embedded/lib/Component/LedComponent.cpp b/embedded/lib/Component/LedComponent.cpp new file mode 100644 index 0000000..8d482dc --- /dev/null +++ b/embedded/lib/Component/LedComponent.cpp @@ -0,0 +1,42 @@ +#include "LedComponent.hpp" + +Color Color::operator-(byte value) +{ + byte nullbyte(0); + return {(this->red - value) < 0 ? nullbyte : static_cast(this->red - value), + (this->blue - value) < 0 ? nullbyte : static_cast(this->blue - value), + (this->green - value) < 0 ? nullbyte : static_cast(this->green - value)}; +} + +LedComponent::LedComponent(byte pin, byte pin_clock, uint8_t led_number) + : _pin(pin), _pinClock(pin_clock), _ledNumber(led_number), _led(nullptr) +{ +} + +LedComponent::~LedComponent() +{ + delete _led; +} + +void LedComponent::setup() +{ + _led = new ChainableLED(_pinClock, _pin, _ledNumber); +} + +void LedComponent::setColor(LedNumber led_number, Color color) +{ + _led->setColorRGB(static_cast(led_number), color.red, color.green, color.blue); +} + +void LedComponent::setColor(LedNumber led_number, Color color, uint16_t fading_time) +{ + const auto redFade = color.red / (static_cast(fading_time)); + const auto greenFade = color.green / (static_cast(fading_time)); + const auto blueFade = color.blue / (static_cast(fading_time)); + + for (uint16_t time(0); time < fading_time; time++) + { + _led->setColorRGB(static_cast(led_number), static_cast(redFade * time), static_cast(greenFade * time), static_cast(blueFade * time)); + delay(1); + } +} \ No newline at end of file diff --git a/embedded/lib/Component/LedComponent.hpp b/embedded/lib/Component/LedComponent.hpp new file mode 100644 index 0000000..6b5380c --- /dev/null +++ b/embedded/lib/Component/LedComponent.hpp @@ -0,0 +1,45 @@ +#ifndef _HEADER_COMPONENT_LED +#define _HEADER_COMPONENT_LED +#include "Component.hpp" +#include + +struct Color +{ + byte red; + byte green; + byte blue; + + Color operator-(byte value); +}; + +namespace LedColors +{ + constexpr Color LED_OFF = {0,0,0}; + constexpr Color WIFI_ON = {0x18,0x28,0x36}; + constexpr Color NO_WIFI = {0x64,0x04,0x0B}; + constexpr Color TOO_DRY = {0xB3,0x58,0x1B}; + constexpr Color TOO_WET = {0x1B,0x09,0x3F}; +} + +enum class LedNumber { + LED_HARDWARE = 0, + LED_PLANT = 1 +}; + +class LedComponent +{ +public: + LedComponent(byte pin, byte pin_clock, uint8_t led_number); + ~LedComponent(); + void setup(); + void setColor(LedNumber led_number, Color color); + void setColor(LedNumber led_number, Color color, uint16_t fading_time); + +private: + byte _pin; + byte _pinClock; + uint8_t _ledNumber; + ChainableLED* _led; +}; + +#endif // _HEADER_COMPONENT_LED \ No newline at end of file diff --git a/embedded/lib/Component/MainComponent.cpp b/embedded/lib/Component/MainComponent.cpp new file mode 100644 index 0000000..da5053c --- /dev/null +++ b/embedded/lib/Component/MainComponent.cpp @@ -0,0 +1,22 @@ +#include "MainComponent.hpp" + +MainComponent::MainComponent() + : _humidity(ComponentType::Analog, PIN_A0), _led(D8, D7, 2), _dht(DHT11, D3) +{ +} + +MainComponent::~MainComponent() +{} + +void MainComponent::setup() +{ + _led.setup(); + _dht.setup(); + // Lights are off when powered + _led.setColor(LedNumber::LED_HARDWARE,{0,0,0}); + _led.setColor(LedNumber::LED_PLANT,{0,0,0}); +} + +Component& MainComponent::getHumidity() { return _humidity; } +LedComponent& MainComponent::getLed() { return _led; } +DHTComponent& MainComponent::getDHT() { return _dht; } diff --git a/embedded/lib/Component/MainComponent.hpp b/embedded/lib/Component/MainComponent.hpp new file mode 100644 index 0000000..e7dfe87 --- /dev/null +++ b/embedded/lib/Component/MainComponent.hpp @@ -0,0 +1,34 @@ +#ifndef _HEADER_COMPONENT_MAIN +#define _HEADER_COMPONENT_MAIN + +#include "Component.hpp" +#include "LedComponent.hpp" +#include "DHTComponent.hpp" + +class MainComponent { +public: + // Singleton + static MainComponent& GetInstance() + { + static MainComponent instance; + return instance; + } + // Public functions + void setup(); + Component& getHumidity(); + LedComponent& getLed(); + DHTComponent& getDHT(); +private: + // Singleton + MainComponent(); + ~MainComponent(); + MainComponent(const MainComponent&) = delete; + MainComponent& operator=(const MainComponent&) = delete; + + // Components + Component _humidity; + LedComponent _led; + DHTComponent _dht; +}; + +#endif // \ No newline at end of file diff --git a/embedded/lib/Display/Screen.cpp b/embedded/lib/Display/Screen.cpp index 22af48d..7c00467 100644 --- a/embedded/lib/Display/Screen.cpp +++ b/embedded/lib/Display/Screen.cpp @@ -1,12 +1,11 @@ #include "Screen.hpp" + +#include "MainComponent.hpp" #include #include // XBM Files #include "../Pictures/failed.xbm" -#include "../Pictures/humidity.xbm" -#include "../Pictures/thermometer.xbm" -#include "../Pictures/air_humidity.xbm" using namespace Display; @@ -33,9 +32,9 @@ void Screen::Setup(uint8_t *font) auto plantHumidity = TextBox("plantHumidity", StyleWidth::LEFT, StyleHeight::TOP, U8G2_BTN_BW0, 0, 0); auto airTemperature = TextBox("airTemperature", StyleWidth::LEFT, StyleHeight::CENTERED, U8G2_BTN_BW0, 0, 0); auto airHumidity = TextBox("airHumidity", StyleWidth::LEFT, StyleHeight::BOTTOM, U8G2_BTN_BW0, 0, 6); - auto humidityPicture = SpriteBox(humidity_bits,humidity_width,humidity_height,StyleWidth::LEFT,StyleHeight::CENTERED); - auto thermometerPicture = SpriteBox(thermometer_bits,thermometer_width,thermometer_height,StyleWidth::LEFT,StyleHeight::CENTERED); - auto airHumidityPicture = SpriteBox(air_humidity_bits,air_humidity_width,air_humidity_height,StyleWidth::LEFT,StyleHeight::CENTERED); + auto humidityPicture = SpriteBox(ICONS[0].data,ICONS[0].width,ICONS[0].height,StyleWidth::LEFT,StyleHeight::CENTERED); + auto thermometerPicture = SpriteBox(ICONS[1].data,ICONS[1].width,ICONS[1].height,StyleWidth::LEFT,StyleHeight::CENTERED); + auto airHumidityPicture = SpriteBox(ICONS[2].data,ICONS[2].width,ICONS[2].height,StyleWidth::LEFT,StyleHeight::CENTERED); // Config Boxes plantHumidity.SetOffset(OFFSET_TEXT,12); @@ -126,16 +125,19 @@ void Screen::boot() _bootFrame++; bootWindow.Update(0,CLOVER_FRAMES[(_bootFrame >= 10 ? 10 : _bootFrame)]); _screen->sendBuffer(); + + // Shutting down led when finished booting + if(_bootFrame == MAX_BOOT_FRAMES) + MainComponent::GetInstance().getLed().setColor(LedNumber::LED_HARDWARE,LedColors::LED_OFF); } -void Screen::loop(const float plantHumidity, const float airTemperature, const float airHumidity, const float light) +void Screen::loop(const float plantHumidity, const float airTemperature, const float airHumidity) { _screen->clearBuffer(); // Updating with values loopWindow.Update(0,String("Hum: ")+String(plantHumidity,1)+String("%")); loopWindow.Update(1,String("Tem: ")+String(airTemperature,1)+String("°C")); loopWindow.Update(2,String("Hum: ")+String(airHumidity,1)+String("%")); - //loopWindow.Update(3,String("Light: ")+String(light,1)+String("%")); // Component loopWindow.Display(); iconWindow.Display(); @@ -143,6 +145,15 @@ void Screen::loop(const float plantHumidity, const float airTemperature, const f _screen->sendBuffer(); } +void Screen::setWarningIcon(Sensors sensorId, bool warning) +{ + const auto realId = static_cast(sensorId); + if(warning) + iconWindow.Update(realId,ICONS_WARNING[realId]); + else + iconWindow.Update(realId,ICONS[realId]); +} + uint16_t Screen::getHeight() { return _height; } uint16_t Screen::getWidth() { return _width; } U8G2_SSD1306_128X64_NONAME_F_HW_I2C &Screen::getScreen() { return *_screen; } diff --git a/embedded/lib/Display/Screen.hpp b/embedded/lib/Display/Screen.hpp index c92c9c5..d4ded26 100644 --- a/embedded/lib/Display/Screen.hpp +++ b/embedded/lib/Display/Screen.hpp @@ -20,6 +20,14 @@ #include "../Pictures/clover10.xbm" #include "../Pictures/clover11.xbm" +// Icons +#include "../Pictures/humidity.xbm" +#include "../Pictures/thermometer.xbm" +#include "../Pictures/air_humidity.xbm" +#include "../Pictures/humidity-warning.xbm" +#include "../Pictures/thermometer-warning.xbm" +#include "../Pictures/air_humidity-warning.xbm" + namespace Display { constexpr Picture CLOVER_FRAMES[] = { @@ -35,10 +43,26 @@ namespace Display {clover10_bits, clover10_width, clover10_height}, {clover11_bits, clover11_width, clover11_height}, }; + constexpr Picture ICONS[] = { + {humidity_bits,humidity_width,humidity_height}, + {thermometer_bits,thermometer_width,thermometer_height}, + {air_humidity_bits,air_humidity_width,air_humidity_height}, + }; + constexpr Picture ICONS_WARNING[] = { + {humidity_warning_bits,humidity_warning_width,humidity_warning_height}, + {thermometer_warning_bits,thermometer_warning_width,thermometer_warning_height}, + {air_humidity_warning_bits,air_humidity_warning_width,air_humidity_warning_height}, + }; constexpr uint8_t MAX_BOOT_FRAMES = 25; constexpr uint8_t OFFSET_ICONS = 55; constexpr uint8_t OFFSET_TEXT = 75; + enum class Sensors { + SOIL_MOISTURE = 0, + THERMOMETER, + AIR_HUMIDITY + }; + class Screen { public: @@ -54,7 +78,8 @@ namespace Display void notConnected(); void connected(const char *ipaddress, uint8_t timing); void boot(); - void loop(const float plantHumidity, const float airTemperature, const float airHumidity, const float light); + void loop(const float plantHumidity, const float airTemperature, const float airHumidity); + void setWarningIcon(Sensors sensorId, bool warning=true); // Getters uint16_t getHeight(); uint16_t getWidth(); diff --git a/embedded/lib/Pictures/air_humidity-warning.xbm b/embedded/lib/Pictures/air_humidity-warning.xbm new file mode 100644 index 0000000..6c0ab19 --- /dev/null +++ b/embedded/lib/Pictures/air_humidity-warning.xbm @@ -0,0 +1,6 @@ +#define air_humidity_warning_width 16 +#define air_humidity_warning_height 16 +static unsigned char air_humidity_warning_bits[] = { + 0x60, 0x00, 0x90, 0x00, 0x18, 0x01, 0x24, 0x02, 0x42, 0x0a, 0x42, 0x0a, + 0x04, 0x19, 0x90, 0x3c, 0x38, 0x3e, 0x28, 0x7f, 0x6c, 0x7f, 0x6c, 0x7e, + 0xfe, 0x3e, 0xee, 0x1e, 0xfe, 0x0e, 0x00, 0x00 }; diff --git a/embedded/lib/Pictures/humidity-warning.xbm b/embedded/lib/Pictures/humidity-warning.xbm new file mode 100644 index 0000000..6586a03 --- /dev/null +++ b/embedded/lib/Pictures/humidity-warning.xbm @@ -0,0 +1,6 @@ +#define humidity_warning_width 16 +#define humidity_warning_height 16 +static unsigned char humidity_warning_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0x40, 0x03, 0x40, 0x03, + 0x80, 0x07, 0x90, 0x0f, 0xb8, 0x0f, 0x28, 0x1f, 0x6c, 0x1f, 0x6c, 0x1e, + 0xfe, 0x0e, 0xee, 0x06, 0xfe, 0x02, 0x00, 0x00 }; diff --git a/embedded/lib/Pictures/thermometer-warning.xbm b/embedded/lib/Pictures/thermometer-warning.xbm new file mode 100644 index 0000000..70de2e1 --- /dev/null +++ b/embedded/lib/Pictures/thermometer-warning.xbm @@ -0,0 +1,6 @@ +#define thermometer_warning_width 16 +#define thermometer_warning_height 16 +static unsigned char thermometer_warning_bits[] = { + 0x00, 0x00, 0x80, 0x01, 0x40, 0x02, 0xc0, 0x02, 0x40, 0x02, 0xc0, 0x02, + 0x40, 0x02, 0x90, 0x02, 0x38, 0x02, 0x28, 0x04, 0x6c, 0x08, 0x6c, 0x0e, + 0xfe, 0x0e, 0xee, 0x06, 0xfe, 0x02, 0x00, 0x00 }; diff --git a/embedded/lib/ServerHandler/ServerException.hpp b/embedded/lib/ServerHandler/ServerException.hpp new file mode 100644 index 0000000..d9564a0 --- /dev/null +++ b/embedded/lib/ServerHandler/ServerException.hpp @@ -0,0 +1,22 @@ +#ifndef _HEADER_SERVER_EXCEPTION +#define _HEADER_SERVER_EXCEPTION +#include +#include +#include "ServerException.hpp" + +class ServerException : public std::exception +{ + public: + ServerException(const char* msg, uint8_t code) + : _msg(msg), _code(code) + { + } + + uint8_t code() { return _code; } + const char* what() { return _msg; } + private: + const char* _msg; + uint8_t _code; +}; + +#endif // _HEADER_SERVER_EXCEPTION \ No newline at end of file diff --git a/embedded/lib/ServerHandler/ServerHandler.cpp b/embedded/lib/ServerHandler/ServerHandler.cpp index 765a527..4fe00af 100644 --- a/embedded/lib/ServerHandler/ServerHandler.cpp +++ b/embedded/lib/ServerHandler/ServerHandler.cpp @@ -1,6 +1,15 @@ #include "ServerHandler.hpp" + +#include "MainComponent.hpp" #include "../Display/Screen.hpp" +inline void led_blink(LedComponent& led) +{ + led.setColor(LedNumber::LED_HARDWARE,LedColors::WIFI_ON); + delay(50); + led.setColor(LedNumber::LED_HARDWARE,LedColors::LED_OFF); +} + ServerHandler::ServerHandler() : server(80), display_time(0), _connected(false) { } @@ -11,13 +20,17 @@ void ServerHandler::setup(const char *ssid, const char *password) { // On utilise les scope resolution operator pour définir les méthodes la classe ServerHandle qui elle est dans hpp uint8_t state(0); uint16_t tryConnection(0); + auto& led = MainComponent::GetInstance().getLed(); Serial.begin(9600); WiFi.begin(ssid, password); // Testing connection while ((WiFi.status() != WL_CONNECTED) && (tryConnection < MAX_CONNECT_TRIES)) { - delay(500); + led_blink(led); + delay(50); + led_blink(led); + delay(350); Display::Screen::GetInstance().connecting(state); state >= 3 ? state = 0 : state++; tryConnection++; @@ -26,10 +39,15 @@ void ServerHandler::setup(const char *ssid, const char *password) if (tryConnection < MAX_CONNECT_TRIES) { _connected = true; + auto color = LedColors::WIFI_ON; + led.setColor(LedNumber::LED_HARDWARE,color-15,200); server.begin(); server.on("/", [this]() { this->handleRoot(); }); // fonction lamda pour gérer les requettes get } + else { + led.setColor(LedNumber::LED_HARDWARE,LedColors::NO_WIFI,200); + } } void ServerHandler::loop() diff --git a/embedded/platformio.ini b/embedded/platformio.ini index 1f38097..b4fe499 100644 --- a/embedded/platformio.ini +++ b/embedded/platformio.ini @@ -11,12 +11,15 @@ [env:nodemcuv2] platform = espressif8266 board = nodemcuv2 -build_flags = -fexceptions +build_flags = + -std=c++11 framework = arduino lib_deps = tzapu/WiFiManager@^0.16.0 bbx10/DNSServer@^1.1.0 ArduinoJson olikraus/U8g2@^2.35.7 -extra_scripts = - pre:scripts/dotenv-var.py \ No newline at end of file + seeed-studio/Grove - Chainable RGB LED@^1.0.0 + adafruit/DHT sensor library@^1.4.6 +extra_scripts = + pre:scripts/dotenv-var.py diff --git a/embedded/src/main.cpp b/embedded/src/main.cpp index 42de622..8ee2eac 100644 --- a/embedded/src/main.cpp +++ b/embedded/src/main.cpp @@ -3,47 +3,48 @@ #include #include "ServerHandler.hpp" -#include "Component.hpp" +#include "MainComponent.hpp" #include "Screen.hpp" +#include "warning.hpp" #ifdef SSID_CLOVER - const char* ssid = SSID_CLOVER; +const char *ssid = SSID_CLOVER; #endif #ifdef PSWD_CLOVER - const char* pswd = PSWD_CLOVER; +const char *pswd = PSWD_CLOVER; #endif -Component humidity(ComponentType::Analog, PIN_A0); - void setup() { + // Sensors/Acuators setup + MainComponent::GetInstance().setup(); + + // Setup for screen and server Serial.begin(9600); - Display::Screen::GetInstance().Setup(const_cast(u8g2_font_busdisplay8x5_tr)); + Display::Screen::GetInstance().Setup(const_cast(u8g2_font_busdisplay8x5_tr)); ServerHandler::GetInstance().setup(ssid, pswd); + // Printing server data Serial.print("Connected to WiFi. IP address: "); Serial.println(WiFi.localIP()); - - pinMode(D5, OUTPUT); - digitalWrite(D5, LOW); } void loop() { // Creating variables to access singletons - auto& serverHandler = ServerHandler::GetInstance(); - auto& dataHandler = DataHandler::GetInstance(); - auto& screen = Display::Screen::GetInstance(); + auto &serverHandler = ServerHandler::GetInstance(); + auto &dataHandler = DataHandler::GetInstance(); + auto &screen = Display::Screen::GetInstance(); // Could not connect after setup: Showing screen failure - if(!serverHandler.isConnected()) + if (!serverHandler.isConnected()) { screen.notConnected(); return; } // Server showing IP - if(!serverHandler.showBoot()) + if (!serverHandler.showBoot()) { serverHandler.showIp(); delay(250); @@ -51,7 +52,7 @@ void loop() } // When Screen can boot (isBooting) and Server finished showing IP (showBoot) - if(screen.isBooting() && serverHandler.showBoot()) + if (screen.isBooting() && serverHandler.showBoot()) { screen.boot(); delay(100); @@ -60,33 +61,19 @@ void loop() // Data gathered from various sensors // 0 -> air(0), 0-300 -> dry(20), 300-700 -> humid (580), 700-950 -> water(940) - auto soilHumidityData = static_cast(std::any_cast(humidity.getValue())); - auto airTemperatureData = random(150, 300) / 10.0; - auto airHumidityData = random(0, 1000) / 10.0; - auto lightData = random(0, 1000) / 10.0; + auto soilHumidityData = static_cast(std::any_cast(MainComponent::GetInstance().getHumidity().getValue())); + auto airTemperatureData = MainComponent::GetInstance().getDHT().getTemperature(); + auto airHumidityData = MainComponent::GetInstance().getDHT().getHumidity(); // Updating the data handler dataHandler.updateSoilMoistureData(soilHumidityData); dataHandler.updateAirTemperatureData(airTemperatureData); dataHandler.updateAirHumidityData(airHumidityData); - dataHandler.updateLightData(lightData); - // Screen showing - screen.loop(soilHumidityData,airTemperatureData,airHumidityData,lightData); - - if (soilHumidityData < 550) { - Serial.println("Soil humidity low. Please water the plant."); - digitalWrite(D5, HIGH); - } else if (soilHumidityData >= 550 && soilHumidityData <= 680) { - Serial.println("Idle..."); - digitalWrite(D5, LOW); - } else { - Serial.println("Soil too wet."); - digitalWrite(D5, LOW); - delay(400); - digitalWrite(D5, HIGH); - delay(400); - } + // Showing screen + screen.loop((soilHumidityData / 950.0f) * 100.0f, airTemperatureData, airHumidityData); + Warning::warningLedLoop(soilHumidityData); + Warning::warningScreenLoop(soilHumidityData,airTemperatureData,airHumidityData); serverHandler.loop(); } \ No newline at end of file diff --git a/embedded/src/warning.cpp b/embedded/src/warning.cpp new file mode 100644 index 0000000..9186f1d --- /dev/null +++ b/embedded/src/warning.cpp @@ -0,0 +1,52 @@ +#include "warning.hpp" + +#include "Screen.hpp" +#include "MainComponent.hpp" + +using namespace Warning; + +LedMoistureStatus moisture_status(LedMoistureStatus::IDLE); + +void Warning::warningLedLoop(const float soilHumidity) +{ + auto& led = MainComponent::GetInstance().getLed(); + + if ((soilHumidity < MoistureLevel::DRY) && (moisture_status != LedMoistureStatus::DRY)) + { + moisture_status = LedMoistureStatus::DRY; + led.setColor(LedNumber::LED_PLANT,LedColors::TOO_DRY,200); + } + else if (soilHumidity >= MoistureLevel::DRY && soilHumidity < MoistureLevel::HUMID) + { + led.setColor(LedNumber::LED_PLANT,LedColors::LED_OFF); + moisture_status = LedMoistureStatus::IDLE; + } + else if ((soilHumidity >= MoistureLevel::HUMID) && (moisture_status != LedMoistureStatus::WET)) + { + moisture_status = LedMoistureStatus::WET; + led.setColor(LedNumber::LED_PLANT,LedColors::TOO_WET,200); + } +} + +void Warning::warningScreenLoop(const float plantMoisture, const float airTemperature, const float airHumidity) +{ + auto& display = Display::Screen::GetInstance(); + + // Plant Moisture Warning + if(plantMoisture < MoistureLevel::DRY || plantMoisture > MoistureLevel::HUMID) + display.setWarningIcon(Display::Sensors::SOIL_MOISTURE); + else + display.setWarningIcon(Display::Sensors::SOIL_MOISTURE,false); + + // Temperature Warning + if(airTemperature >= AIR_TEMPERATURE_TOO_HOT || airTemperature <= AIR_TEMPERATURE_TOO_COLD) + display.setWarningIcon(Display::Sensors::THERMOMETER); + else + display.setWarningIcon(Display::Sensors::THERMOMETER,false); + + // Humidity Warning + if(airHumidity >= AIR_HUMIDITY_SATURATED) + display.setWarningIcon(Display::Sensors::AIR_HUMIDITY); + else + display.setWarningIcon(Display::Sensors::AIR_HUMIDITY,false); +} \ No newline at end of file diff --git a/embedded/src/warning.hpp b/embedded/src/warning.hpp new file mode 100644 index 0000000..8cb43c8 --- /dev/null +++ b/embedded/src/warning.hpp @@ -0,0 +1,33 @@ +#ifndef _HEADER_WARNING +#define _HEADER_WARNING + +#include + +namespace Warning { + /** + * @brief See the documentation on 'https://www.mouser.com/datasheet/2/744/Seeed_101020008-1217463.pdf' + */ + namespace MoistureLevel { + constexpr uint16_t AIR = 0; + constexpr uint16_t DRY = 300; + constexpr uint16_t HUMID = 700; + constexpr uint16_t WATER = 950; + } + constexpr float AIR_HUMIDITY_SATURATED = 95.0f; + /** + * @brief Source : 'https://extension.umd.edu/resource/temperature-and-humidity-indoor-plants/' + */ + constexpr float AIR_TEMPERATURE_TOO_HOT = 29.0f; + constexpr float AIR_TEMPERATURE_TOO_COLD = 14.0f; + + enum class LedMoistureStatus { + IDLE, + DRY, + WET + }; + + void warningLedLoop(const float soilHumidity); + void warningScreenLoop(const float plantMoisture, const float airTemperature, const float airHumidity); +} + +#endif // _HEADER_WARNING \ No newline at end of file