diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 89cc49c..0000000 --- a/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -.pio -.vscode/.browse.c_cpp.db* -.vscode/c_cpp_properties.json -.vscode/launch.json -.vscode/ipch diff --git a/.vscode/extensions.json b/.vscode/extensions.json deleted file mode 100644 index 080e70d..0000000 --- a/.vscode/extensions.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - // See http://go.microsoft.com/fwlink/?LinkId=827846 - // for the documentation about the extensions.json format - "recommendations": [ - "platformio.platformio-ide" - ], - "unwantedRecommendations": [ - "ms-vscode.cpptools-extension-pack" - ] -} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index d8cb326..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "files.associations": { - "string": "cpp" - } -} \ No newline at end of file diff --git a/app/.gitkeep b/app/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/embedded/.gitignore b/embedded/.gitignore new file mode 100644 index 0000000..59fcd8c --- /dev/null +++ b/embedded/.gitignore @@ -0,0 +1,3 @@ +.pio +.vscode/ +.env \ No newline at end of file diff --git a/include/README b/embedded/include/README similarity index 100% rename from include/README rename to embedded/include/README diff --git a/embedded/lib/Component/Component.cpp b/embedded/lib/Component/Component.cpp new file mode 100644 index 0000000..98b84c9 --- /dev/null +++ b/embedded/lib/Component/Component.cpp @@ -0,0 +1,27 @@ +#include "Component.hpp" + +Component::Component(ComponentType ct, uint8_t p) +: _type(ct), _pin(p) +{} + +std::any Component::getValue(void){ + switch(_type) + { + case ComponentType::Digital: + return digitalRead(_pin); + case ComponentType::Analog: + return analogRead(_pin); + default: + return 0; + } +} + +void Component::sendValue(std::any data) +{ + switch(_type) { + case ComponentType::Digital: + digitalWrite(_pin, std::any_cast(data)); + case ComponentType::Analog: + analogWrite(_pin, std::any_cast(data)); + } +} \ No newline at end of file diff --git a/embedded/lib/Component/Component.hpp b/embedded/lib/Component/Component.hpp new file mode 100644 index 0000000..344d781 --- /dev/null +++ b/embedded/lib/Component/Component.hpp @@ -0,0 +1,23 @@ +#ifndef _HEADER_COMPONENT +#define _HEADER_COMPONENT +#include +#include + +enum class ComponentType { + Digital, + Analog, + I2C, + Serial +}; + +class Component{ + public: + Component(ComponentType ct, uint8_t p); + std::any getValue(); + void sendValue(std::any data); + private: + ComponentType _type; + const uint8_t _pin; +}; + +#endif //_HEADER_COMPONENT \ No newline at end of file diff --git a/embedded/lib/DataHandler/DataHandler.cpp b/embedded/lib/DataHandler/DataHandler.cpp new file mode 100644 index 0000000..46bd849 --- /dev/null +++ b/embedded/lib/DataHandler/DataHandler.cpp @@ -0,0 +1,26 @@ +#include "DataHandler.hpp" + +DataHandler::DataHandler() {} + +DataHandler::~DataHandler() {} + +void DataHandler::updatePlantHumidityData(float humidity) { plantHumidity = humidity; } +void DataHandler::updateAirTemperatureData(float temperature) { airTemperature = temperature; } +void DataHandler::updateAirHumidityData(float humidity) { airHumidity = humidity; } +void DataHandler::updateLightData(float light) { this->light = light; } + +String DataHandler::getJsonData() { + return buildJson(); +} + +String DataHandler::buildJson() { + StaticJsonDocument<200> document; // Taille = 200 + document["plantHumidity"] = plantHumidity; + document["airTemperature"] = airTemperature; + document["airHumidity"] = airHumidity; + document["light"] = light; + + String jsonFormattedData; + serializeJson(document, jsonFormattedData); + return jsonFormattedData; +} \ No newline at end of file diff --git a/embedded/lib/DataHandler/DataHandler.hpp b/embedded/lib/DataHandler/DataHandler.hpp new file mode 100644 index 0000000..be89006 --- /dev/null +++ b/embedded/lib/DataHandler/DataHandler.hpp @@ -0,0 +1,38 @@ +#ifndef DATAHANDLER_HPP +#define DATAHANDLER_HPP + +#include + +class DataHandler { +public: + // Singleton + static DataHandler& GetInstance() + { + static DataHandler instance; + return instance; + } + // Public functions + String getJsonData(); + void updatePlantHumidityData(float humidity); + void updateAirTemperatureData(float temperature); + void updateAirHumidityData(float humidity); + void updateLightData(float light); + +private: + // Singleton + DataHandler(); + ~DataHandler(); + DataHandler(const DataHandler&) = delete; + DataHandler& operator=(const DataHandler&) = delete; + + // Variables + float plantHumidity; + float airTemperature; + float airHumidity; + float light; + + // Fonctions + String buildJson(); +}; + +#endif \ No newline at end of file diff --git a/embedded/lib/Display/Components/Box.hpp b/embedded/lib/Display/Components/Box.hpp new file mode 100644 index 0000000..ffc029d --- /dev/null +++ b/embedded/lib/Display/Components/Box.hpp @@ -0,0 +1,99 @@ +#ifndef _HEADER_DISPLAY_BOX +#define _HEADER_DISPLAY_BOX +#include +#include + +namespace Display +{ + /** + * @brief Where each Box element is centered on the x axis. + */ + enum class StyleWidth + { + UNDEFINED, + LEFT, + CENTERED, + RIGHT + }; + + /** + * @brief Each Box element can be ordered into heights. + * Each height is independent from another and is placed differently on the screen. + * TOP starts on x=0, CENTERED on x=height/2 and TOP x=height + */ + enum class StyleHeight + { + UNDEFINED, + TOP, + CENTERED, + BOTTOM, + FORCE_CENTERED + }; + + /** + * @brief Box is an abstract class which can be derived into many box elements + * and will be used in the 'Components' object. + * It is composed of 4 functions which may or not be used. + * Each box should use the Screen Interface in the Display function, + * other functions can be modified to the developer's needs. + */ + class Box + { + public: + /** + * @brief Construct a new Box object, can be ignored. + */ + Box(StyleHeight sh, u8g2_uint_t h_padding, uint16_t height) + : _styleHeight(sh), _paddingHeight(h_padding), _height(height), _xOffset(0), _yOffset(0){}; + + /** + * @brief Used to display the element on the screen. + * Will be using any Display function from the U8g2lib. + * ! Maybe a font will be added to arguments next... + * + * @param size the total size of the elements from a styleheight + * @param size_pos all the above sizes from each components in a same style height plus its height padding + */ + virtual void Display(u8g2_uint_t size, u8g2_uint_t size_pos){}; + + /** + * @brief Will update by recalculating the 'Box' constants + * with the given argument. + * + * @param data the data to modify, depending on the Box type + */ + virtual void Update(std::any data){}; + + /** + * @brief Get the Style Height, logic can be changed. + * + * @return StyleHeight + */ + virtual StyleHeight getStyleHeight() { return _styleHeight; }; + + /** + * @brief Get the Padding object, logic can be changed. + * ? Only vertical/height padding + * + * @return u8g2_uint_t + */ + virtual u8g2_uint_t getPadding() { return _paddingHeight; }; + + virtual uint16_t getHeight() { return _height; } + + virtual void SetOffset(uint16_t xOffset, uint16_t yOffset=0) + { + _xOffset = xOffset; + _yOffset = yOffset; + } + + protected: + StyleHeight _styleHeight; + u8g2_uint_t _paddingHeight; + uint16_t _height; + uint16_t _xOffset; + uint16_t _yOffset; + }; +} + +#endif //_HEADER_DISPLAY_BOX \ No newline at end of file diff --git a/embedded/lib/Display/Components/Components.cpp b/embedded/lib/Display/Components/Components.cpp new file mode 100644 index 0000000..d13a3b4 --- /dev/null +++ b/embedded/lib/Display/Components/Components.cpp @@ -0,0 +1,52 @@ +#include "Components.hpp" + +using namespace Display; + +Components::Components() +{ +} + +void Components::Add(std::shared_ptr box) +{ + // When Added, boxes should be reordered by style. + _boxes.push_back(box); +} + +void Components::Add(std::vector> boxes) +{ + for (auto box : boxes) + { + _boxes.push_back(box); + } +} + +void Components::Update(size_t index, std::any modified) +{ + _boxes[index]->Update(modified); +} + +void Components::Display() +{ + u8g2_uint_t totalSize(0); + for (auto it = _boxes.begin(); it != _boxes.end(); it++) + { + const auto size_boxes = GetSize((*it)->getStyleHeight()); + (*it)->Display(size_boxes, totalSize); + + /* Index and verticalPadding only incrementing for the same style. (eg : it and it+1 as the same style.) + Plus, it has to not be FORCED to be incremented.*/ + if (it + 1 != _boxes.end() && ((*(it+1))->getStyleHeight() == (*it)->getStyleHeight()) && ((*it)->getStyleHeight() != StyleHeight::FORCE_CENTERED)) + totalSize += (*it)->getHeight() + (2*(*it)->getPadding()); + else + totalSize = 0; + } +} + +size_t Components::GetSize(StyleHeight sh) +{ + size_t returnSize(0); + // returnSize is equal to FONT_SIZE + vertical padding * boxes with style sh + for(auto& box : _boxes) + returnSize += (box->getStyleHeight() == sh ? (box->getHeight()+(2*box->getPadding())) : 0); + return returnSize; +} \ No newline at end of file diff --git a/embedded/lib/Display/Components/Components.hpp b/embedded/lib/Display/Components/Components.hpp new file mode 100644 index 0000000..d0c6212 --- /dev/null +++ b/embedded/lib/Display/Components/Components.hpp @@ -0,0 +1,24 @@ +#ifndef _HEADER_DISPLAY_COMPONENTS +#define _HEADER_DISPLAY_COMPONENTS +#include +#include +#include "Box.hpp" + +namespace Display +{ + class Components + { + public: + Components(); + void Add(std::shared_ptr box); + void Add(std::vector> boxes); + void Update(size_t index, std::any modified); + void Display(); + private: + size_t GetSize(StyleHeight sh); + // Boxes + std::vector> _boxes; + }; +}; + +#endif //_HEADER_DISPLAY_COMPONENTS \ No newline at end of file diff --git a/embedded/lib/Display/Components/SpriteBox.cpp b/embedded/lib/Display/Components/SpriteBox.cpp new file mode 100644 index 0000000..94c2400 --- /dev/null +++ b/embedded/lib/Display/Components/SpriteBox.cpp @@ -0,0 +1,63 @@ +#include "../Screen.hpp" +#include "SpriteBox.hpp" + +using namespace Display; + +SpriteBox::SpriteBox() + :Box(StyleHeight::UNDEFINED,0,0) +{} + +SpriteBox::SpriteBox(unsigned char *sprite, uint16_t width, uint16_t height, StyleWidth sw, StyleHeight sh) + :Box(sh,0,height) + , _sprite(sprite) + , _styleWidth(sw) + , _width(width) + , _height(height) +{ + Calculate(); +} + +void SpriteBox::Update(std::any data) +{ + const auto pic = std::any_cast(data); + _height = pic.height; + _width = pic.width; + _sprite = pic.data; + Calculate(); +} + +void SpriteBox::Calculate() +{ + const auto screenWidth = Screen::GetInstance().getWidth(); + switch (_styleWidth) + { + case StyleWidth::CENTERED: + _x = (screenWidth - _width) / 2; + break; + case StyleWidth::RIGHT: + _x = screenWidth - _width; + break; + default: + _x = 0; + } +} + +void SpriteBox::Display(u8g2_uint_t size, u8g2_uint_t size_pos) +{ + const auto centeredOffset = (Screen::GetInstance().getHeight() - size); + auto x = _x + this->_xOffset; + auto y = size_pos + this->_yOffset; + switch(this->_styleHeight) + { + case StyleHeight::CENTERED: + case StyleHeight::FORCE_CENTERED: + // idk must be the size of all the above + Screen::GetInstance().getScreen().drawXBM(x, static_cast((centeredOffset / 2)) + y,_width,_height,_sprite); + break; + case StyleHeight::BOTTOM: + Screen::GetInstance().getScreen().drawXBM(x, centeredOffset + y,_width,_height,_sprite); + break; + default: + Screen::GetInstance().getScreen().drawXBM(x, y,_width,_height,_sprite); + } +} \ No newline at end of file diff --git a/embedded/lib/Display/Components/SpriteBox.hpp b/embedded/lib/Display/Components/SpriteBox.hpp new file mode 100644 index 0000000..0aea01f --- /dev/null +++ b/embedded/lib/Display/Components/SpriteBox.hpp @@ -0,0 +1,42 @@ +#ifndef _HEADER_DISPLAY_SPRITEBOX +#define _HEADER_DISPLAY_SPRITEBOX +#include "Box.hpp" + +namespace Display +{ + struct Picture { + unsigned char* data; + uint16_t width; + uint16_t height; + }; + + class SpriteBox : public Box + { + public: + SpriteBox(); + /** + * @brief Construct a new Text Box object + * + * @param sprite array from an .xbm format + */ + SpriteBox(unsigned char *sprite, uint16_t width, uint16_t height, StyleWidth sw, StyleHeight sh); + void Display(u8g2_uint_t size, u8g2_uint_t size_pos) override; + + /** + * @brief Updates sprite + * + * @param data unsigned char* + */ + void Update(std::any data) override; + + private: + void Calculate(); + unsigned char* _sprite; + StyleWidth _styleWidth; + uint16_t _width; + uint16_t _height; + uint16_t _x; + }; +} + +#endif //_HEADER_DISPLAY_SPRITEBOX \ No newline at end of file diff --git a/embedded/lib/Display/Components/TextBox.cpp b/embedded/lib/Display/Components/TextBox.cpp new file mode 100644 index 0000000..b0eddfe --- /dev/null +++ b/embedded/lib/Display/Components/TextBox.cpp @@ -0,0 +1,60 @@ +#include "../Screen.hpp" +#include "TextBox.hpp" + +using namespace Display; + +TextBox::TextBox() + : Box(StyleHeight::UNDEFINED, 0, 0) +{ +} + +TextBox::TextBox(String str, StyleWidth sw, StyleHeight sh, u8g2_uint_t style, u8g2_uint_t w_padding, u8g2_uint_t h_padding, bool takeWholeLine) + : Box(sh, h_padding, FONT_SIZE), _text(str), _style(style), _paddingWidth(w_padding), _styleWidth(sw), _takeWholeLine(takeWholeLine) +{ + Calculate(); +} + +void TextBox::Update(std::any data) +{ + _text = std::any_cast(data); + Calculate(); +} + +void TextBox::Calculate() +{ + const auto width = Screen::GetInstance().getWidth(); + _textWidth = _takeWholeLine ? width : Screen::GetInstance().getTextWidth(_text.c_str()); + switch (_styleWidth) + { + case StyleWidth::LEFT: + _x = 0; + break; + case StyleWidth::CENTERED: + _x = (width - _textWidth) / 2; + break; + case StyleWidth::RIGHT: + _x = width - _textWidth; + break; + default: + _x = 0; + } +} + +void TextBox::Display(u8g2_uint_t size, u8g2_uint_t size_pos) +{ + const auto centeredOffset = (Screen::GetInstance().getHeight() - size); + const auto x = _paddingWidth + _x + this->_xOffset; + const auto y = size_pos + _height + this->_yOffset; + switch (this->_styleHeight) + { + case StyleHeight::CENTERED: + case StyleHeight::FORCE_CENTERED: + Screen::GetInstance().getScreen().drawButtonUTF8(x, static_cast((centeredOffset / 2)) + y, _style, _textWidth, this->_paddingHeight, _paddingWidth, _text.c_str()); + break; + case StyleHeight::BOTTOM: + Screen::GetInstance().getScreen().drawButtonUTF8(x, centeredOffset + y, _style, _textWidth, this->_paddingHeight, _paddingWidth, _text.c_str()); + break; + default: + Screen::GetInstance().getScreen().drawButtonUTF8(x, y, _style, _textWidth, this->_paddingHeight, _paddingWidth, _text.c_str()); + } +} \ No newline at end of file diff --git a/embedded/lib/Display/Components/TextBox.hpp b/embedded/lib/Display/Components/TextBox.hpp new file mode 100644 index 0000000..5955990 --- /dev/null +++ b/embedded/lib/Display/Components/TextBox.hpp @@ -0,0 +1,54 @@ +#ifndef _HEADER_DISPLAY_TEXTBOX +#define _HEADER_DISPLAY_TEXTBOX +#include "Box.hpp" + +namespace Display +{ + /** Size of the actual font from Screen. Used for many calculations + * ! Must be changed if the _font size is updated + */ + constexpr uint8_t FONT_SIZE = 8; + + class TextBox : public Box + { + public: + TextBox(); + /** + * @brief Construct a new Text Box object + * + * @param str the string to display + * @param sw style width (LEFT, CENTERED, RIGHT) + * @param sh style height (TOP, CENTERED, BOTTOM) + * @param style u8g2lib button style (see doc @ ) + * @param w_padding width padding (default: 0) + * @param h_padding height padding (default: 0) + * @param takeWholeLine if true, the button takes the whole line + */ + TextBox(String str, StyleWidth sw, StyleHeight sh, u8g2_uint_t style, u8g2_uint_t w_padding = 0, u8g2_uint_t h_padding = 0, bool takeWholeLine = false); + void Display(u8g2_uint_t size, u8g2_uint_t size_pos) override; + + /** + * @brief Updates String data + * + * @param data String + */ + void Update(std::any data) override; + + private: + /** + * @brief Called on constructor or Update(). + */ + void Calculate(); + + String _text; + uint8_t *_font; + u8g2_uint_t _style; + u8g2_uint_t _paddingWidth; + StyleWidth _styleWidth; + uint16_t _x; + uint16_t _textWidth; + bool _takeWholeLine; + }; +} + +#endif //_HEADER_DISPLAY_TEXTBOX \ No newline at end of file diff --git a/embedded/lib/Display/Screen.cpp b/embedded/lib/Display/Screen.cpp new file mode 100644 index 0000000..22af48d --- /dev/null +++ b/embedded/lib/Display/Screen.cpp @@ -0,0 +1,150 @@ +#include "Screen.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; + +Screen::Screen() : _bootFrame(0), _booted(0) +{ + _screen = new U8G2_SSD1306_128X64_NONAME_F_HW_I2C(U8G2_R0, U8X8_PIN_NONE, SCL, SDA); + _screen->begin(); + _width = _screen->getDisplayWidth(); + _height = _screen->getDisplayHeight(); + _loading = ""; +} + +Screen::~Screen() +{ +} + +void Screen::Setup(uint8_t *font) +{ + _font = font; + _screen->setFont(_font); + + // Creating Boxes + auto headerSetup = TextBox("Clover Setup", StyleWidth::LEFT, StyleHeight::TOP, U8G2_BTN_INV, 2, 5, true); + 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); + + // Config Boxes + plantHumidity.SetOffset(OFFSET_TEXT,12); + airTemperature.SetOffset(OFFSET_TEXT); + airHumidity.SetOffset(OFFSET_TEXT); + humidityPicture.SetOffset(OFFSET_ICONS); + thermometerPicture.SetOffset(OFFSET_ICONS); + airHumidityPicture.SetOffset(OFFSET_ICONS); + + // Static Components + connectingWindow.Add({std::make_shared(headerSetup), + std::make_shared(TextBox("connect", StyleWidth::CENTERED, StyleHeight::CENTERED, U8G2_BTN_BW0))}); + connectionfailedWindow.Add({std::make_shared(headerSetup), + std::make_shared(TextBox("Failed to connect.", StyleWidth::RIGHT, StyleHeight::CENTERED, U8G2_BTN_BW0,3)), + std::make_shared(SpriteBox(failed_bits,failed_height,failed_width,StyleWidth::LEFT,StyleHeight::FORCE_CENTERED))}); + connectedWindow.Add({std::make_shared(headerSetup), + std::make_shared(TextBox("Connected to Wi-Fi !", StyleWidth::LEFT, StyleHeight::CENTERED, U8G2_BTN_BW0, 0, 2)), + std::make_shared(TextBox("IP address: ", StyleWidth::LEFT, StyleHeight::CENTERED, U8G2_BTN_BW0, 0, 2)), + std::make_shared(TextBox("addr", StyleWidth::CENTERED, StyleHeight::CENTERED, U8G2_BTN_BW0, 0, 2))}); + bootWindow.Add(std::make_shared(SpriteBox(CLOVER_FRAMES[0].data, CLOVER_FRAMES[0].height, CLOVER_FRAMES[0].width, StyleWidth::CENTERED, StyleHeight::CENTERED))); + loopWindow.Add({std::make_shared(plantHumidity), + std::make_shared(airTemperature), + std::make_shared(airHumidity)}); + iconWindow.Add({std::make_shared(humidityPicture), + std::make_shared(thermometerPicture), + std::make_shared(airHumidityPicture)}); +} + +void Screen::connecting(uint8_t state) +{ + const size_t connectSize(16); + char connectText[connectSize]; + + // Connecting dot dot dot (depending on state) + strncpy(connectText, "Connecting", connectSize); + size_t currentLength = strlen(connectText); + for (uint8_t i = 0; i < state; i++) + { + // Checking space + if (currentLength + 1 < connectSize) + { + strncat(connectText, ".", currentLength + 1); + currentLength += 1; + } + } + + _screen->clearBuffer(); + // Component + connectingWindow.Update(1, String(connectText)); + connectingWindow.Display(); + // Displaying + _screen->sendBuffer(); +} + +void Screen::notConnected() +{ + _screen->clearBuffer(); + // Component + connectionfailedWindow.Display(); + // Displaying + _screen->sendBuffer(); +} + +void Screen::connected(const char *ipaddress, uint8_t timing) +{ + _screen->clearBuffer(); + // Component + connectedWindow.Update(3, String(ipaddress)); + + // Displaying + connectedWindow.Display(); + // Creating loading bar + if (timing != 0) + { + _screen->setFont(u8g2_font_3x3basic_tr); + _loading.concat(" "); + _screen->drawButtonUTF8(0, _screen->getDisplayHeight() - 5, U8G2_BTN_INV, _screen->getStrWidth(_loading.c_str()), 0, 0, _loading.c_str()); + _screen->setFont(_font); + } + _screen->sendBuffer(); +} + +void Screen::boot() +{ + _screen->clearBuffer(); + // Component + bootWindow.Display(); + _bootFrame++; + bootWindow.Update(0,CLOVER_FRAMES[(_bootFrame >= 10 ? 10 : _bootFrame)]); + _screen->sendBuffer(); +} + +void Screen::loop(const float plantHumidity, const float airTemperature, const float airHumidity, const float light) +{ + _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(); + // Displaying + _screen->sendBuffer(); +} + +uint16_t Screen::getHeight() { return _height; } +uint16_t Screen::getWidth() { return _width; } +U8G2_SSD1306_128X64_NONAME_F_HW_I2C &Screen::getScreen() { return *_screen; } +uint16_t Screen::getTextWidth(const char *str) { return _screen->getStrWidth(str); } +bool Screen::isBooting() { return (_bootFrame<=MAX_BOOT_FRAMES); } \ No newline at end of file diff --git a/embedded/lib/Display/Screen.hpp b/embedded/lib/Display/Screen.hpp new file mode 100644 index 0000000..c92c9c5 --- /dev/null +++ b/embedded/lib/Display/Screen.hpp @@ -0,0 +1,91 @@ +#ifndef _HEADER_SCREEN +#define _HEADER_SCREEN +#include +#include + +#include "Components/Components.hpp" +#include "Components/TextBox.hpp" +#include "Components/SpriteBox.hpp" + +// Frame for booting +#include "../Pictures/clover1.xbm" +#include "../Pictures/clover2.xbm" +#include "../Pictures/clover3.xbm" +#include "../Pictures/clover4.xbm" +#include "../Pictures/clover5.xbm" +#include "../Pictures/clover6.xbm" +#include "../Pictures/clover7.xbm" +#include "../Pictures/clover8.xbm" +#include "../Pictures/clover9.xbm" +#include "../Pictures/clover10.xbm" +#include "../Pictures/clover11.xbm" + +namespace Display +{ + constexpr Picture CLOVER_FRAMES[] = { + {clover1_bits, clover1_width, clover1_height}, + {clover2_bits, clover2_width, clover2_height}, + {clover3_bits, clover3_width, clover3_height}, + {clover4_bits, clover4_width, clover4_height}, + {clover5_bits, clover5_width, clover5_height}, + {clover6_bits, clover6_width, clover6_height}, + {clover7_bits, clover7_width, clover7_height}, + {clover8_bits, clover8_width, clover8_height}, + {clover9_bits, clover9_width, clover9_height}, + {clover10_bits, clover10_width, clover10_height}, + {clover11_bits, clover11_width, clover11_height}, + }; + constexpr uint8_t MAX_BOOT_FRAMES = 25; + constexpr uint8_t OFFSET_ICONS = 55; + constexpr uint8_t OFFSET_TEXT = 75; + + class Screen + { + public: + // Singleton + static Screen &GetInstance() + { + static Screen instance; + return instance; + } + // Public functions + void Setup(uint8_t *font); + void connecting(uint8_t state=0); + 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); + // Getters + uint16_t getHeight(); + uint16_t getWidth(); + U8G2_SSD1306_128X64_NONAME_F_HW_I2C& getScreen(); + uint16_t getTextWidth(const char * str); + bool isBooting(); + private: + // Singleton + Screen(); + ~Screen(); + Screen(const Screen &) = delete; + Screen &operator=(const Screen &) = delete; + + // Variables + U8G2_SSD1306_128X64_NONAME_F_HW_I2C *_screen; + uint8_t *_font; + uint16_t _width; + uint16_t _height; + String _loading; + // Extern + uint8_t _bootFrame; + bool _booted; + + // Static Components + Components connectingWindow; + Components connectionfailedWindow; + Components connectedWindow; + Components bootWindow; + Components loopWindow; + Components iconWindow; + }; +} + +#endif //_HEADER_SCREEN \ No newline at end of file diff --git a/embedded/lib/Pictures/air_humidity.xbm b/embedded/lib/Pictures/air_humidity.xbm new file mode 100644 index 0000000..1e05f61 --- /dev/null +++ b/embedded/lib/Pictures/air_humidity.xbm @@ -0,0 +1,6 @@ +#define air_humidity_width 16 +#define air_humidity_height 16 +static unsigned char air_humidity_bits[] = { + 0x60, 0x00, 0x90, 0x00, 0x18, 0x01, 0x24, 0x02, 0x42, 0x0a, 0x42, 0x0a, + 0x04, 0x19, 0xf8, 0x3c, 0x00, 0x3e, 0x00, 0x7f, 0xe0, 0x7f, 0xe0, 0x7f, + 0xc0, 0x3f, 0x80, 0x1f, 0x00, 0x0f, 0x00, 0x00 }; diff --git a/embedded/lib/Pictures/clover.xbm b/embedded/lib/Pictures/clover.xbm new file mode 100644 index 0000000..3e0cf08 --- /dev/null +++ b/embedded/lib/Pictures/clover.xbm @@ -0,0 +1,6 @@ +#define clover_width 16 +#define clover_height 16 +static unsigned char clover_bits[] = { + 0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, + 0xe0, 0x07, 0xe0, 0x07, 0xe3, 0xc7, 0xcf, 0xf3, 0x9f, 0xf9, 0x3e, 0x7c, + 0x3e, 0x7c, 0x7c, 0x3e, 0x78, 0x1e, 0xc0, 0x03 }; diff --git a/embedded/lib/Pictures/clover1.xbm b/embedded/lib/Pictures/clover1.xbm new file mode 100644 index 0000000..07243b1 --- /dev/null +++ b/embedded/lib/Pictures/clover1.xbm @@ -0,0 +1,14 @@ +#define clover1_width 26 +#define clover1_height 32 +static unsigned char clover1_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x60, 0xfc, 0x18, 0x00, 0xe0, 0x79, 0x1e, 0x00, + 0xe0, 0x33, 0x1f, 0x00, 0xc0, 0x87, 0x0f, 0x00, 0xc0, 0x87, 0x0f, 0x00, + 0x80, 0xcf, 0x07, 0x00, 0x00, 0xcf, 0x03, 0x00, 0x00, 0x78, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; diff --git a/embedded/lib/Pictures/clover10.xbm b/embedded/lib/Pictures/clover10.xbm new file mode 100644 index 0000000..607ec59 --- /dev/null +++ b/embedded/lib/Pictures/clover10.xbm @@ -0,0 +1,14 @@ +#define clover10_width 26 +#define clover10_height 32 +static unsigned char clover10_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x60, 0xfc, 0x18, 0x00, + 0xe0, 0x79, 0x1e, 0x00, 0xe0, 0x33, 0x1f, 0x00, 0xc0, 0x87, 0x0f, 0x00, + 0xc0, 0x87, 0x0f, 0x00, 0x80, 0xcf, 0x07, 0x00, 0x00, 0xcf, 0x03, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x44, 0x54, 0xa5, 0x00, 0x44, 0x54, 0x6d, 0x00, + 0x44, 0x54, 0xa5, 0x00, 0x98, 0x89, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; diff --git a/embedded/lib/Pictures/clover11.xbm b/embedded/lib/Pictures/clover11.xbm new file mode 100644 index 0000000..3671396 --- /dev/null +++ b/embedded/lib/Pictures/clover11.xbm @@ -0,0 +1,14 @@ +#define clover11_width 26 +#define clover11_height 32 +static unsigned char clover11_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x60, 0xfc, 0x18, 0x00, + 0xe0, 0x79, 0x1e, 0x00, 0xe0, 0x33, 0x1f, 0x00, 0xc0, 0x87, 0x0f, 0x00, + 0xc0, 0x87, 0x0f, 0x00, 0x80, 0xcf, 0x07, 0x00, 0x00, 0xcf, 0x03, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x58, 0x48, 0x6d, 0x00, 0x44, 0x54, 0xa5, 0x00, 0x44, 0x54, 0x6d, 0x00, + 0x44, 0x54, 0xa5, 0x00, 0x98, 0x89, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; diff --git a/embedded/lib/Pictures/clover2.xbm b/embedded/lib/Pictures/clover2.xbm new file mode 100644 index 0000000..65cb462 --- /dev/null +++ b/embedded/lib/Pictures/clover2.xbm @@ -0,0 +1,14 @@ +#define clover2_width 26 +#define clover2_height 32 +static unsigned char clover2_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, + 0x60, 0xfc, 0x00, 0x00, 0xe0, 0xfc, 0x1c, 0x00, 0xe0, 0x79, 0x1e, 0x00, + 0xe0, 0x03, 0x1f, 0x00, 0xc0, 0x87, 0x0f, 0x00, 0xc0, 0xcf, 0x0f, 0x00, + 0x80, 0xcf, 0x03, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; diff --git a/embedded/lib/Pictures/clover3.xbm b/embedded/lib/Pictures/clover3.xbm new file mode 100644 index 0000000..e340366 --- /dev/null +++ b/embedded/lib/Pictures/clover3.xbm @@ -0,0 +1,14 @@ +#define clover3_width 26 +#define clover3_height 32 +static unsigned char clover3_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, + 0xe0, 0xfc, 0x0c, 0x00, 0xe0, 0x79, 0x1e, 0x00, 0xe0, 0x03, 0x1f, 0x00, + 0xc0, 0x87, 0x1f, 0x00, 0x80, 0xcf, 0x07, 0x00, 0x00, 0xcf, 0x03, 0x00, + 0x00, 0xd8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; diff --git a/embedded/lib/Pictures/clover4.xbm b/embedded/lib/Pictures/clover4.xbm new file mode 100644 index 0000000..4777054 --- /dev/null +++ b/embedded/lib/Pictures/clover4.xbm @@ -0,0 +1,14 @@ +#define clover4_width 26 +#define clover4_height 32 +static unsigned char clover4_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, + 0xc0, 0x78, 0x0e, 0x00, 0xe0, 0x01, 0x1f, 0x00, 0xe0, 0x83, 0x1f, 0x00, + 0xe0, 0xcf, 0x1f, 0x00, 0x80, 0xcf, 0x07, 0x00, 0x00, 0xce, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; diff --git a/embedded/lib/Pictures/clover5.xbm b/embedded/lib/Pictures/clover5.xbm new file mode 100644 index 0000000..e4c1351 --- /dev/null +++ b/embedded/lib/Pictures/clover5.xbm @@ -0,0 +1,14 @@ +#define clover5_width 26 +#define clover5_height 32 +static unsigned char clover5_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, + 0xe0, 0x00, 0x0e, 0x00, 0xf0, 0x03, 0x1f, 0x00, 0xf0, 0x87, 0x1f, 0x00, + 0xe0, 0xcf, 0x0f, 0x00, 0x80, 0xcf, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; diff --git a/embedded/lib/Pictures/clover6.xbm b/embedded/lib/Pictures/clover6.xbm new file mode 100644 index 0000000..84e4383 --- /dev/null +++ b/embedded/lib/Pictures/clover6.xbm @@ -0,0 +1,14 @@ +#define clover6_width 26 +#define clover6_height 32 +static unsigned char clover6_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0xe0, 0x78, 0x0e, 0x00, 0xf0, 0x01, 0x1f, 0x00, + 0xf0, 0x83, 0x1f, 0x00, 0xe0, 0xc7, 0x0f, 0x00, 0xc0, 0xcf, 0x07, 0x00, + 0x00, 0xdf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; diff --git a/embedded/lib/Pictures/clover7.xbm b/embedded/lib/Pictures/clover7.xbm new file mode 100644 index 0000000..ff0324d --- /dev/null +++ b/embedded/lib/Pictures/clover7.xbm @@ -0,0 +1,14 @@ +#define clover7_width 26 +#define clover7_height 32 +static unsigned char clover7_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, + 0x30, 0xfc, 0x18, 0x00, 0xf0, 0x30, 0x1e, 0x00, 0xf0, 0x01, 0x1f, 0x00, + 0xf0, 0x83, 0x0f, 0x00, 0xe0, 0xc7, 0x07, 0x00, 0xc0, 0xcf, 0x03, 0x00, + 0x00, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x01, 0x00, 0x90, 0x89, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; diff --git a/embedded/lib/Pictures/clover8.xbm b/embedded/lib/Pictures/clover8.xbm new file mode 100644 index 0000000..4c66ade --- /dev/null +++ b/embedded/lib/Pictures/clover8.xbm @@ -0,0 +1,14 @@ +#define clover8_width 26 +#define clover8_height 32 +static unsigned char clover8_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, + 0x20, 0xfc, 0x18, 0x00, 0xe0, 0x30, 0x1e, 0x00, 0xe0, 0x03, 0x1f, 0x00, + 0xe0, 0x87, 0x0f, 0x00, 0xc0, 0xc7, 0x07, 0x00, 0x00, 0xcf, 0x03, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, + 0x44, 0x54, 0xa5, 0x00, 0x98, 0x89, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; diff --git a/embedded/lib/Pictures/clover9.xbm b/embedded/lib/Pictures/clover9.xbm new file mode 100644 index 0000000..b7e5c38 --- /dev/null +++ b/embedded/lib/Pictures/clover9.xbm @@ -0,0 +1,14 @@ +#define clover9_width 26 +#define clover9_height 32 +static unsigned char clover9_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, + 0xe0, 0xfc, 0x1c, 0x00, 0xe0, 0x33, 0x1f, 0x00, 0xc0, 0x87, 0x0f, 0x00, + 0xc0, 0x87, 0x0f, 0x00, 0x80, 0xcf, 0x07, 0x00, 0x00, 0xcf, 0x03, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x44, 0x54, 0x6d, 0x00, + 0x44, 0x54, 0xa5, 0x00, 0x98, 0x89, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; diff --git a/embedded/lib/Pictures/failed.xbm b/embedded/lib/Pictures/failed.xbm new file mode 100644 index 0000000..2a1ffec --- /dev/null +++ b/embedded/lib/Pictures/failed.xbm @@ -0,0 +1,6 @@ +#define failed_width 16 +#define failed_height 16 +static unsigned char failed_bits[] = { + 0x00, 0x00, 0x06, 0x60, 0x0e, 0x70, 0x1c, 0x38, 0x38, 0x1c, 0x70, 0x0e, + 0xe0, 0x07, 0xc0, 0x03, 0xc0, 0x03, 0xe0, 0x07, 0x70, 0x0e, 0x38, 0x1c, + 0x1c, 0x38, 0x0e, 0x70, 0x06, 0x60, 0x00, 0x00 }; diff --git a/embedded/lib/Pictures/humidity.xbm b/embedded/lib/Pictures/humidity.xbm new file mode 100644 index 0000000..1b8eed4 --- /dev/null +++ b/embedded/lib/Pictures/humidity.xbm @@ -0,0 +1,6 @@ +#define humidity_width 16 +#define humidity_height 16 +static unsigned char humidity_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0x40, 0x03, 0x40, 0x03, + 0xa0, 0x07, 0xd0, 0x0f, 0xf0, 0x0f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, + 0xf0, 0x0f, 0xe0, 0x07, 0xc0, 0x03, 0x00, 0x00 }; diff --git a/embedded/lib/Pictures/luminosity.xbm b/embedded/lib/Pictures/luminosity.xbm new file mode 100644 index 0000000..8894479 --- /dev/null +++ b/embedded/lib/Pictures/luminosity.xbm @@ -0,0 +1,6 @@ +#define luminosity_width 16 +#define luminosity_height 16 +static unsigned char luminosity_bits[] = { + 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0x18, 0x18, 0xc8, 0x13, 0xe0, 0x07, + 0xf4, 0x2f, 0xf6, 0x6f, 0xf6, 0x6f, 0xf4, 0x2f, 0xe0, 0x07, 0xc8, 0x13, + 0x18, 0x18, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00 }; diff --git a/embedded/lib/Pictures/thermometer.xbm b/embedded/lib/Pictures/thermometer.xbm new file mode 100644 index 0000000..2576f17 --- /dev/null +++ b/embedded/lib/Pictures/thermometer.xbm @@ -0,0 +1,6 @@ +#define thermometer_width 16 +#define thermometer_height 16 +static unsigned char thermometer_bits[] = { + 0x00, 0x00, 0x80, 0x01, 0x40, 0x02, 0xc0, 0x02, 0x40, 0x02, 0xc0, 0x02, + 0x40, 0x02, 0xc0, 0x02, 0x40, 0x02, 0x20, 0x04, 0x10, 0x08, 0xf0, 0x0f, + 0xf0, 0x0f, 0xe0, 0x07, 0xc0, 0x03, 0x00, 0x00 }; diff --git a/lib/README b/embedded/lib/README similarity index 100% rename from lib/README rename to embedded/lib/README diff --git a/embedded/lib/ServerHandler/ServerHandler.cpp b/embedded/lib/ServerHandler/ServerHandler.cpp new file mode 100644 index 0000000..1d9f55f --- /dev/null +++ b/embedded/lib/ServerHandler/ServerHandler.cpp @@ -0,0 +1,54 @@ +#include "ServerHandler.hpp" +#include "../Display/Screen.hpp" + +ServerHandler::ServerHandler() : server(80), display_time(0), _connected(false) +{ +} + +ServerHandler::~ServerHandler() {} + +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); + Serial.begin(9600); + WiFi.begin(ssid, password); + + // Testing connection + while ((WiFi.status() != WL_CONNECTED) && (tryConnection < MAX_CONNECT_TRIES)) + { + delay(500); + Display::Screen::GetInstance().connecting(state); + state >= 3 ? state = 0 : state++; + tryConnection++; + } + + if (tryConnection < MAX_CONNECT_TRIES) + { + _connected = true; + server.begin(); + server.on("/", [this]() + { this->handleRoot(); }); // fonction lamda pour gérer les requettes get + } +} + +void ServerHandler::loop() +{ + server.handleClient(); +} + +void ServerHandler::showIp() +{ + Display::Screen::GetInstance().connected(WiFi.localIP().toString().c_str(), display_time); + display_time++; +} + +bool ServerHandler::isConnected() { return _connected; } +bool ServerHandler::showBoot() { return (display_time >= MAX_TIME); } + +void ServerHandler::handleRoot() +{ + auto &dataHandler = DataHandler::GetInstance(); + String jsonFormattedData = dataHandler.getJsonData(); + server.send(200, "application/json", jsonFormattedData); +} diff --git a/embedded/lib/ServerHandler/ServerHandler.hpp b/embedded/lib/ServerHandler/ServerHandler.hpp new file mode 100644 index 0000000..f628550 --- /dev/null +++ b/embedded/lib/ServerHandler/ServerHandler.hpp @@ -0,0 +1,40 @@ +#ifndef SERVERHANDLER_HPP +#define SERVERHANDLER_HPP + +#include +#include + +#include "DataHandler.hpp" + +constexpr uint8_t MAX_TIME = 28; +constexpr uint16_t MAX_CONNECT_TRIES = 20; + +class ServerHandler { +public: + // Singleton + static ServerHandler& GetInstance() + { + static ServerHandler instance; + return instance; + } + // Public functions + void setup(const char* ssid, const char* password); + void showIp(); + void loop(); + bool isConnected(); + bool showBoot(); + +private: + // Singleton + ServerHandler(); + ~ServerHandler(); + ServerHandler(const ServerHandler&) = delete; + ServerHandler& operator=(const ServerHandler&) = delete; + // Private variables/functions + void handleRoot(); + ESP8266WebServer server; + uint8_t display_time; + bool _connected; +}; + +#endif diff --git a/platformio.ini b/embedded/platformio.ini similarity index 72% rename from platformio.ini rename to embedded/platformio.ini index 239547c..1f38097 100644 --- a/platformio.ini +++ b/embedded/platformio.ini @@ -11,7 +11,12 @@ [env:nodemcuv2] platform = espressif8266 board = nodemcuv2 +build_flags = -fexceptions framework = arduino -lib_deps = tzapu/WiFiManager@^0.16.0 - bbx10/DNSServer@^1.1.0 - ArduinoJson +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 diff --git a/embedded/readme.MD b/embedded/readme.MD new file mode 100644 index 0000000..0131bad --- /dev/null +++ b/embedded/readme.MD @@ -0,0 +1,6 @@ +# .env file + +``` +SSID_CLOVER='"SSID"' +PSWD_CLOVER='"PASSWORD"' +``` \ No newline at end of file diff --git a/embedded/scripts/dotenv-var.py b/embedded/scripts/dotenv-var.py new file mode 100644 index 0000000..f0f8134 --- /dev/null +++ b/embedded/scripts/dotenv-var.py @@ -0,0 +1,14 @@ +from os.path import isfile +Import("env") +assert isfile(".env") +try: + f = open(".env", "r") + lines = f.readlines() + envs = [] + for line in lines: + envs.append("-D{}".format(line.strip())) + env.Append(BUILD_FLAGS=envs) +except IOError: + print("File .env not accessible",) +finally: + f.close() \ No newline at end of file diff --git a/embedded/src/main.cpp b/embedded/src/main.cpp new file mode 100644 index 0000000..1a65f2b --- /dev/null +++ b/embedded/src/main.cpp @@ -0,0 +1,73 @@ +#include +#include +#include + +#include "ServerHandler.hpp" +#include "Component.hpp" +#include "Screen.hpp" + +#ifdef SSID_CLOVER + const char* ssid = SSID_CLOVER; +#endif +#ifdef PSWD_CLOVER + const char* pswd = PSWD_CLOVER; +#endif + +Component humidity(ComponentType::Analog, PIN_A0); + +void setup() +{ + Serial.begin(9600); + Display::Screen::GetInstance().Setup(const_cast(u8g2_font_busdisplay8x5_tr)); + ServerHandler::GetInstance().setup(ssid, pswd); +} + +void loop() +{ + // Creating variables to access singletons + auto& serverHandler = ServerHandler::GetInstance(); + auto& dataHandler = DataHandler::GetInstance(); + auto& screen = Display::Screen::GetInstance(); + + // Could not connect after setup: Showing screen failure + if(!serverHandler.isConnected()) + { + screen.notConnected(); + return; + } + + // Server showing IP + if(!serverHandler.showBoot()) + { + serverHandler.showIp(); + delay(250); + return; + } + + // When Screen can boot (isBooting) and Server finished showing IP (showBoot) + if(screen.isBooting() && serverHandler.showBoot()) + { + screen.boot(); + delay(100); + return; + } + + // Data gathered from various sensors + // 0 -> air(0), 0-300 -> dry(20), 300-700 -> humid (580), 700-950 -> water(940) + auto plantHumidityData = 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; + + // Updating the data handler + dataHandler.updatePlantHumidityData(plantHumidityData); + dataHandler.updateAirTemperatureData(airTemperatureData); + dataHandler.updateAirHumidityData(airHumidityData); + dataHandler.updateLightData(lightData); + // (debug) Printing to serial the data + Serial.println(dataHandler.getJsonData()); + // Screen showing + screen.loop(plantHumidityData,airTemperatureData,airHumidityData,lightData); + // Server sending data + serverHandler.loop(); +} \ No newline at end of file diff --git a/test/README b/embedded/test/README similarity index 100% rename from test/README rename to embedded/test/README diff --git a/lib/DataHandler/DataHandler.cpp b/lib/DataHandler/DataHandler.cpp deleted file mode 100644 index 40c891b..0000000 --- a/lib/DataHandler/DataHandler.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "DataHandler.hpp" - -DataHandler::DataHandler() {} - -void DataHandler::updateTemperatureData(float temp) { - temperature = temp; -} - -void DataHandler::updateHumidityData(float hum) { - humidity = hum; -} - -String DataHandler::getJsonData() { - return buildJson(); -} - -String DataHandler::buildJson() { - StaticJsonDocument<200> document; // Taille = 200 - document["temperature"] = temperature; - document["humidity"] = humidity; - - String jsonFormattedData; - serializeJson(document, jsonFormattedData); - return jsonFormattedData; -} \ No newline at end of file diff --git a/lib/DataHandler/DataHandler.hpp b/lib/DataHandler/DataHandler.hpp deleted file mode 100644 index 1bb29c6..0000000 --- a/lib/DataHandler/DataHandler.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef DATAHANDLER_HPP -#define DATAHANDLER_HPP - -#include - -class DataHandler { -public: - DataHandler(); - String getJsonData(); - - void updateTemperatureData(float temperature); - void updateHumidityData(float humidity); - -private: - float temperature; - float humidity; - - String buildJson(); -}; - -#endif \ No newline at end of file diff --git a/lib/ServerHandler/ServerHandler.cpp b/lib/ServerHandler/ServerHandler.cpp deleted file mode 100644 index b65eb5d..0000000 --- a/lib/ServerHandler/ServerHandler.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "ServerHandler.hpp" - -ServerHandler::ServerHandler(DataHandler * dataHandler) : server(80), dataHandler(dataHandler) { -} - -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 - Serial.begin(9600); - WiFi.begin(ssid, password); - - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - - Serial.println(""); - Serial.println("Connected to Wi-Fi. IP address: "); - Serial.println(WiFi.localIP()); - - server.begin(); - server.on("/", [this]() { this->handleRoot(); }); // fonction lamda pour gérer les requettes get -} - -void ServerHandler::loop() { - server.handleClient(); -} - -void ServerHandler::handleRoot() { - String jsonFormattedData = dataHandler->getJsonData(); - server.send(200, "application/json", jsonFormattedData); -} diff --git a/lib/ServerHandler/ServerHandler.hpp b/lib/ServerHandler/ServerHandler.hpp deleted file mode 100644 index ce6c9b0..0000000 --- a/lib/ServerHandler/ServerHandler.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef SERVERHANDLER_HPP -#define SERVERHANDLER_HPP - -#include -#include - -#include "DataHandler.hpp" - -class ServerHandler { -public: - ServerHandler(DataHandler * dataHandler); - void setup(const char* ssid, const char* password); - void loop(); - -private: - ESP8266WebServer server; - void handleRoot(); - DataHandler * dataHandler; // Pointeur vers dataHandler -}; - -#endif diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index dc97a3c..0000000 --- a/src/main.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include -#include - -#include "ServerHandler.hpp" -#include "DataHandler.hpp" - -DataHandler dataHandler; -ServerHandler serverHandler(&dataHandler); // Référence à dataHandler - - -void setup() { - Serial.begin(9600); - - dataHandler.updateTemperatureData(20.0); - dataHandler.updateHumidityData(3.141592); - - serverHandler.setup("Redmi Note 10", "bbooksdd"); -} - -void loop() { - Serial.println(dataHandler.getJsonData()); - - dataHandler.updateTemperatureData(random(1800, 2200)/100.0); - dataHandler.updateHumidityData(random(4400, 5000)/100.0); - delay(1000); - - - serverHandler.loop(); -}