mirror of
https://github.com/Lemonochrme/clover.git
synced 2025-06-08 16:50:50 +02:00
Merge branch 'feature-led'
This commit is contained in:
commit
a9b456cef7
18 changed files with 413 additions and 52 deletions
|
@ -5,9 +5,7 @@
|
||||||
|
|
||||||
enum class ComponentType {
|
enum class ComponentType {
|
||||||
Digital,
|
Digital,
|
||||||
Analog,
|
Analog
|
||||||
I2C,
|
|
||||||
Serial
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Component{
|
class Component{
|
||||||
|
|
28
embedded/lib/Component/DHTComponent.cpp
Normal file
28
embedded/lib/Component/DHTComponent.cpp
Normal file
|
@ -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;
|
||||||
|
}
|
23
embedded/lib/Component/DHTComponent.hpp
Normal file
23
embedded/lib/Component/DHTComponent.hpp
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#ifndef _HEADER_COMPONENT_DHT
|
||||||
|
#define _HEADER_COMPONENT_DHT
|
||||||
|
#include <Adafruit_Sensor.h>
|
||||||
|
#include <DHT.h>
|
||||||
|
#include <DHT_U.h>
|
||||||
|
|
||||||
|
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
|
42
embedded/lib/Component/LedComponent.cpp
Normal file
42
embedded/lib/Component/LedComponent.cpp
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#include "LedComponent.hpp"
|
||||||
|
|
||||||
|
Color Color::operator-(byte value)
|
||||||
|
{
|
||||||
|
byte nullbyte(0);
|
||||||
|
return {(this->red - value) < 0 ? nullbyte : static_cast<byte>(this->red - value),
|
||||||
|
(this->blue - value) < 0 ? nullbyte : static_cast<byte>(this->blue - value),
|
||||||
|
(this->green - value) < 0 ? nullbyte : static_cast<byte>(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<byte>(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<float>(fading_time));
|
||||||
|
const auto greenFade = color.green / (static_cast<float>(fading_time));
|
||||||
|
const auto blueFade = color.blue / (static_cast<float>(fading_time));
|
||||||
|
|
||||||
|
for (uint16_t time(0); time < fading_time; time++)
|
||||||
|
{
|
||||||
|
_led->setColorRGB(static_cast<byte>(led_number), static_cast<byte>(redFade * time), static_cast<byte>(greenFade * time), static_cast<byte>(blueFade * time));
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
}
|
45
embedded/lib/Component/LedComponent.hpp
Normal file
45
embedded/lib/Component/LedComponent.hpp
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#ifndef _HEADER_COMPONENT_LED
|
||||||
|
#define _HEADER_COMPONENT_LED
|
||||||
|
#include "Component.hpp"
|
||||||
|
#include <ChainableLED.h>
|
||||||
|
|
||||||
|
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
|
22
embedded/lib/Component/MainComponent.cpp
Normal file
22
embedded/lib/Component/MainComponent.cpp
Normal file
|
@ -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; }
|
34
embedded/lib/Component/MainComponent.hpp
Normal file
34
embedded/lib/Component/MainComponent.hpp
Normal file
|
@ -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 //
|
|
@ -1,12 +1,11 @@
|
||||||
#include "Screen.hpp"
|
#include "Screen.hpp"
|
||||||
|
|
||||||
|
#include "MainComponent.hpp"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
// XBM Files
|
// XBM Files
|
||||||
#include "../Pictures/failed.xbm"
|
#include "../Pictures/failed.xbm"
|
||||||
#include "../Pictures/humidity.xbm"
|
|
||||||
#include "../Pictures/thermometer.xbm"
|
|
||||||
#include "../Pictures/air_humidity.xbm"
|
|
||||||
|
|
||||||
using namespace Display;
|
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 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 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 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 humidityPicture = SpriteBox(ICONS[0].data,ICONS[0].width,ICONS[0].height,StyleWidth::LEFT,StyleHeight::CENTERED);
|
||||||
auto thermometerPicture = SpriteBox(thermometer_bits,thermometer_width,thermometer_height,StyleWidth::LEFT,StyleHeight::CENTERED);
|
auto thermometerPicture = SpriteBox(ICONS[1].data,ICONS[1].width,ICONS[1].height,StyleWidth::LEFT,StyleHeight::CENTERED);
|
||||||
auto airHumidityPicture = SpriteBox(air_humidity_bits,air_humidity_width,air_humidity_height,StyleWidth::LEFT,StyleHeight::CENTERED);
|
auto airHumidityPicture = SpriteBox(ICONS[2].data,ICONS[2].width,ICONS[2].height,StyleWidth::LEFT,StyleHeight::CENTERED);
|
||||||
|
|
||||||
// Config Boxes
|
// Config Boxes
|
||||||
plantHumidity.SetOffset(OFFSET_TEXT,12);
|
plantHumidity.SetOffset(OFFSET_TEXT,12);
|
||||||
|
@ -126,16 +125,19 @@ void Screen::boot()
|
||||||
_bootFrame++;
|
_bootFrame++;
|
||||||
bootWindow.Update(0,CLOVER_FRAMES[(_bootFrame >= 10 ? 10 : _bootFrame)]);
|
bootWindow.Update(0,CLOVER_FRAMES[(_bootFrame >= 10 ? 10 : _bootFrame)]);
|
||||||
_screen->sendBuffer();
|
_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();
|
_screen->clearBuffer();
|
||||||
// Updating with values
|
// Updating with values
|
||||||
loopWindow.Update(0,String("Hum: ")+String(plantHumidity,1)+String("%"));
|
loopWindow.Update(0,String("Hum: ")+String(plantHumidity,1)+String("%"));
|
||||||
loopWindow.Update(1,String("Tem: ")+String(airTemperature,1)+String("°C"));
|
loopWindow.Update(1,String("Tem: ")+String(airTemperature,1)+String("°C"));
|
||||||
loopWindow.Update(2,String("Hum: ")+String(airHumidity,1)+String("%"));
|
loopWindow.Update(2,String("Hum: ")+String(airHumidity,1)+String("%"));
|
||||||
//loopWindow.Update(3,String("Light: ")+String(light,1)+String("%"));
|
|
||||||
// Component
|
// Component
|
||||||
loopWindow.Display();
|
loopWindow.Display();
|
||||||
iconWindow.Display();
|
iconWindow.Display();
|
||||||
|
@ -143,6 +145,15 @@ void Screen::loop(const float plantHumidity, const float airTemperature, const f
|
||||||
_screen->sendBuffer();
|
_screen->sendBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Screen::setWarningIcon(Sensors sensorId, bool warning)
|
||||||
|
{
|
||||||
|
const auto realId = static_cast<size_t>(sensorId);
|
||||||
|
if(warning)
|
||||||
|
iconWindow.Update(realId,ICONS_WARNING[realId]);
|
||||||
|
else
|
||||||
|
iconWindow.Update(realId,ICONS[realId]);
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t Screen::getHeight() { return _height; }
|
uint16_t Screen::getHeight() { return _height; }
|
||||||
uint16_t Screen::getWidth() { return _width; }
|
uint16_t Screen::getWidth() { return _width; }
|
||||||
U8G2_SSD1306_128X64_NONAME_F_HW_I2C &Screen::getScreen() { return *_screen; }
|
U8G2_SSD1306_128X64_NONAME_F_HW_I2C &Screen::getScreen() { return *_screen; }
|
||||||
|
|
|
@ -20,6 +20,14 @@
|
||||||
#include "../Pictures/clover10.xbm"
|
#include "../Pictures/clover10.xbm"
|
||||||
#include "../Pictures/clover11.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
|
namespace Display
|
||||||
{
|
{
|
||||||
constexpr Picture CLOVER_FRAMES[] = {
|
constexpr Picture CLOVER_FRAMES[] = {
|
||||||
|
@ -35,10 +43,26 @@ namespace Display
|
||||||
{clover10_bits, clover10_width, clover10_height},
|
{clover10_bits, clover10_width, clover10_height},
|
||||||
{clover11_bits, clover11_width, clover11_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 MAX_BOOT_FRAMES = 25;
|
||||||
constexpr uint8_t OFFSET_ICONS = 55;
|
constexpr uint8_t OFFSET_ICONS = 55;
|
||||||
constexpr uint8_t OFFSET_TEXT = 75;
|
constexpr uint8_t OFFSET_TEXT = 75;
|
||||||
|
|
||||||
|
enum class Sensors {
|
||||||
|
SOIL_MOISTURE = 0,
|
||||||
|
THERMOMETER,
|
||||||
|
AIR_HUMIDITY
|
||||||
|
};
|
||||||
|
|
||||||
class Screen
|
class Screen
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -54,7 +78,8 @@ namespace Display
|
||||||
void notConnected();
|
void notConnected();
|
||||||
void connected(const char *ipaddress, uint8_t timing);
|
void connected(const char *ipaddress, uint8_t timing);
|
||||||
void boot();
|
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
|
// Getters
|
||||||
uint16_t getHeight();
|
uint16_t getHeight();
|
||||||
uint16_t getWidth();
|
uint16_t getWidth();
|
||||||
|
|
6
embedded/lib/Pictures/air_humidity-warning.xbm
Normal file
6
embedded/lib/Pictures/air_humidity-warning.xbm
Normal file
|
@ -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 };
|
6
embedded/lib/Pictures/humidity-warning.xbm
Normal file
6
embedded/lib/Pictures/humidity-warning.xbm
Normal file
|
@ -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 };
|
6
embedded/lib/Pictures/thermometer-warning.xbm
Normal file
6
embedded/lib/Pictures/thermometer-warning.xbm
Normal file
|
@ -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 };
|
22
embedded/lib/ServerHandler/ServerException.hpp
Normal file
22
embedded/lib/ServerHandler/ServerException.hpp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef _HEADER_SERVER_EXCEPTION
|
||||||
|
#define _HEADER_SERVER_EXCEPTION
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <exception>
|
||||||
|
#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
|
|
@ -1,6 +1,15 @@
|
||||||
#include "ServerHandler.hpp"
|
#include "ServerHandler.hpp"
|
||||||
|
|
||||||
|
#include "MainComponent.hpp"
|
||||||
#include "../Display/Screen.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)
|
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
|
{ // On utilise les scope resolution operator pour définir les méthodes la classe ServerHandle qui elle est dans hpp
|
||||||
uint8_t state(0);
|
uint8_t state(0);
|
||||||
uint16_t tryConnection(0);
|
uint16_t tryConnection(0);
|
||||||
|
auto& led = MainComponent::GetInstance().getLed();
|
||||||
Serial.begin(9600);
|
Serial.begin(9600);
|
||||||
WiFi.begin(ssid, password);
|
WiFi.begin(ssid, password);
|
||||||
|
|
||||||
// Testing connection
|
// Testing connection
|
||||||
while ((WiFi.status() != WL_CONNECTED) && (tryConnection < MAX_CONNECT_TRIES))
|
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);
|
Display::Screen::GetInstance().connecting(state);
|
||||||
state >= 3 ? state = 0 : state++;
|
state >= 3 ? state = 0 : state++;
|
||||||
tryConnection++;
|
tryConnection++;
|
||||||
|
@ -26,10 +39,15 @@ void ServerHandler::setup(const char *ssid, const char *password)
|
||||||
if (tryConnection < MAX_CONNECT_TRIES)
|
if (tryConnection < MAX_CONNECT_TRIES)
|
||||||
{
|
{
|
||||||
_connected = true;
|
_connected = true;
|
||||||
|
auto color = LedColors::WIFI_ON;
|
||||||
|
led.setColor(LedNumber::LED_HARDWARE,color-15,200);
|
||||||
server.begin();
|
server.begin();
|
||||||
server.on("/", [this]()
|
server.on("/", [this]()
|
||||||
{ this->handleRoot(); }); // fonction lamda pour gérer les requettes get
|
{ this->handleRoot(); }); // fonction lamda pour gérer les requettes get
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
led.setColor(LedNumber::LED_HARDWARE,LedColors::NO_WIFI,200);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerHandler::loop()
|
void ServerHandler::loop()
|
||||||
|
|
|
@ -11,12 +11,15 @@
|
||||||
[env:nodemcuv2]
|
[env:nodemcuv2]
|
||||||
platform = espressif8266
|
platform = espressif8266
|
||||||
board = nodemcuv2
|
board = nodemcuv2
|
||||||
build_flags = -fexceptions
|
build_flags =
|
||||||
|
-std=c++11
|
||||||
framework = arduino
|
framework = arduino
|
||||||
lib_deps =
|
lib_deps =
|
||||||
tzapu/WiFiManager@^0.16.0
|
tzapu/WiFiManager@^0.16.0
|
||||||
bbx10/DNSServer@^1.1.0
|
bbx10/DNSServer@^1.1.0
|
||||||
ArduinoJson
|
ArduinoJson
|
||||||
olikraus/U8g2@^2.35.7
|
olikraus/U8g2@^2.35.7
|
||||||
|
seeed-studio/Grove - Chainable RGB LED@^1.0.0
|
||||||
|
adafruit/DHT sensor library@^1.4.6
|
||||||
extra_scripts =
|
extra_scripts =
|
||||||
pre:scripts/dotenv-var.py
|
pre:scripts/dotenv-var.py
|
||||||
|
|
|
@ -3,47 +3,48 @@
|
||||||
#include <ESP8266WebServer.h>
|
#include <ESP8266WebServer.h>
|
||||||
|
|
||||||
#include "ServerHandler.hpp"
|
#include "ServerHandler.hpp"
|
||||||
#include "Component.hpp"
|
#include "MainComponent.hpp"
|
||||||
#include "Screen.hpp"
|
#include "Screen.hpp"
|
||||||
|
#include "warning.hpp"
|
||||||
|
|
||||||
#ifdef SSID_CLOVER
|
#ifdef SSID_CLOVER
|
||||||
const char* ssid = SSID_CLOVER;
|
const char *ssid = SSID_CLOVER;
|
||||||
#endif
|
#endif
|
||||||
#ifdef PSWD_CLOVER
|
#ifdef PSWD_CLOVER
|
||||||
const char* pswd = PSWD_CLOVER;
|
const char *pswd = PSWD_CLOVER;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Component humidity(ComponentType::Analog, PIN_A0);
|
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
|
// Sensors/Acuators setup
|
||||||
|
MainComponent::GetInstance().setup();
|
||||||
|
|
||||||
|
// Setup for screen and server
|
||||||
Serial.begin(9600);
|
Serial.begin(9600);
|
||||||
Display::Screen::GetInstance().Setup(const_cast<uint8_t*>(u8g2_font_busdisplay8x5_tr));
|
Display::Screen::GetInstance().Setup(const_cast<uint8_t *>(u8g2_font_busdisplay8x5_tr));
|
||||||
ServerHandler::GetInstance().setup(ssid, pswd);
|
ServerHandler::GetInstance().setup(ssid, pswd);
|
||||||
|
|
||||||
|
// Printing server data
|
||||||
Serial.print("Connected to WiFi. IP address: ");
|
Serial.print("Connected to WiFi. IP address: ");
|
||||||
Serial.println(WiFi.localIP());
|
Serial.println(WiFi.localIP());
|
||||||
|
|
||||||
pinMode(D5, OUTPUT);
|
|
||||||
digitalWrite(D5, LOW);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
// Creating variables to access singletons
|
// Creating variables to access singletons
|
||||||
auto& serverHandler = ServerHandler::GetInstance();
|
auto &serverHandler = ServerHandler::GetInstance();
|
||||||
auto& dataHandler = DataHandler::GetInstance();
|
auto &dataHandler = DataHandler::GetInstance();
|
||||||
auto& screen = Display::Screen::GetInstance();
|
auto &screen = Display::Screen::GetInstance();
|
||||||
|
|
||||||
// Could not connect after setup: Showing screen failure
|
// Could not connect after setup: Showing screen failure
|
||||||
if(!serverHandler.isConnected())
|
if (!serverHandler.isConnected())
|
||||||
{
|
{
|
||||||
screen.notConnected();
|
screen.notConnected();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Server showing IP
|
// Server showing IP
|
||||||
if(!serverHandler.showBoot())
|
if (!serverHandler.showBoot())
|
||||||
{
|
{
|
||||||
serverHandler.showIp();
|
serverHandler.showIp();
|
||||||
delay(250);
|
delay(250);
|
||||||
|
@ -51,7 +52,7 @@ void loop()
|
||||||
}
|
}
|
||||||
|
|
||||||
// When Screen can boot (isBooting) and Server finished showing IP (showBoot)
|
// When Screen can boot (isBooting) and Server finished showing IP (showBoot)
|
||||||
if(screen.isBooting() && serverHandler.showBoot())
|
if (screen.isBooting() && serverHandler.showBoot())
|
||||||
{
|
{
|
||||||
screen.boot();
|
screen.boot();
|
||||||
delay(100);
|
delay(100);
|
||||||
|
@ -60,33 +61,19 @@ void loop()
|
||||||
|
|
||||||
// Data gathered from various sensors
|
// Data gathered from various sensors
|
||||||
// 0 -> air(0), 0-300 -> dry(20), 300-700 -> humid (580), 700-950 -> water(940)
|
// 0 -> air(0), 0-300 -> dry(20), 300-700 -> humid (580), 700-950 -> water(940)
|
||||||
auto soilHumidityData = static_cast<float>(std::any_cast<int>(humidity.getValue()));
|
auto soilHumidityData = static_cast<float>(std::any_cast<int>(MainComponent::GetInstance().getHumidity().getValue()));
|
||||||
auto airTemperatureData = random(150, 300) / 10.0;
|
auto airTemperatureData = MainComponent::GetInstance().getDHT().getTemperature();
|
||||||
auto airHumidityData = random(0, 1000) / 10.0;
|
auto airHumidityData = MainComponent::GetInstance().getDHT().getHumidity();
|
||||||
auto lightData = random(0, 1000) / 10.0;
|
|
||||||
|
|
||||||
// Updating the data handler
|
// Updating the data handler
|
||||||
dataHandler.updateSoilMoistureData(soilHumidityData);
|
dataHandler.updateSoilMoistureData(soilHumidityData);
|
||||||
dataHandler.updateAirTemperatureData(airTemperatureData);
|
dataHandler.updateAirTemperatureData(airTemperatureData);
|
||||||
dataHandler.updateAirHumidityData(airHumidityData);
|
dataHandler.updateAirHumidityData(airHumidityData);
|
||||||
dataHandler.updateLightData(lightData);
|
|
||||||
|
|
||||||
// Screen showing
|
// Showing screen
|
||||||
screen.loop(soilHumidityData,airTemperatureData,airHumidityData,lightData);
|
screen.loop((soilHumidityData / 950.0f) * 100.0f, airTemperatureData, airHumidityData);
|
||||||
|
Warning::warningLedLoop(soilHumidityData);
|
||||||
if (soilHumidityData < 550) {
|
Warning::warningScreenLoop(soilHumidityData,airTemperatureData,airHumidityData);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
serverHandler.loop();
|
serverHandler.loop();
|
||||||
}
|
}
|
52
embedded/src/warning.cpp
Normal file
52
embedded/src/warning.cpp
Normal file
|
@ -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);
|
||||||
|
}
|
33
embedded/src/warning.hpp
Normal file
33
embedded/src/warning.hpp
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef _HEADER_WARNING
|
||||||
|
#define _HEADER_WARNING
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
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
|
Loading…
Add table
Reference in a new issue