Création du module DolibarrClient avec ses différentes routes & création du module WarehouseGUI pour le LCD M5Stack
This commit is contained in:
170
lib/DolibarrClient/src/DolibarrClient.cpp
Normal file
170
lib/DolibarrClient/src/DolibarrClient.cpp
Normal file
@ -0,0 +1,170 @@
|
||||
#include "DolibarrClient.h"
|
||||
#include <WiFi.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <iostream>
|
||||
|
||||
#define WAITING_WIFI_DELAY 1000
|
||||
|
||||
DolibarrClient::DolibarrClient(struct WifiConfig wifi_config, struct DolibarrConfig dolibarr_config) : wifi(wifi_config), dolibarr(dolibarr_config) {
|
||||
#if defined(DEBUG)
|
||||
Serial.println(" --- Wifi configuration --- ");
|
||||
Serial.println((std::string("SSID: ") + std::string(wifi_config.ssid)).c_str());
|
||||
Serial.println((std::string("Password: ") + std::string(wifi_config.password)).c_str());
|
||||
Serial.println(" --- Dolibarr configuration --- ");
|
||||
Serial.println((std::string("Base URL: ") + std::string(dolibarr_config.url)).c_str());
|
||||
Serial.println((std::string("Token: ") + std::string(dolibarr_config.api_key)).c_str());
|
||||
#endif
|
||||
this->initialize_wifi();
|
||||
this->initialize_http_client();
|
||||
}
|
||||
|
||||
HTTPClient *DolibarrClient::build_url(const String& url) const {
|
||||
auto *client = new HTTPClient();
|
||||
String clientUrl = this->dolibarr.url + url;
|
||||
client->begin(clientUrl);
|
||||
client->addHeader("Content-Type", "application/json");
|
||||
client->addHeader("DOLAPIKEY", this->dolibarr.api_key);
|
||||
#if defined(DEBUG)
|
||||
Serial.println("URL Request: " + clientUrl);
|
||||
#endif
|
||||
return client;
|
||||
}
|
||||
|
||||
|
||||
int DolibarrClient::login() const {
|
||||
HTTPClient *client = this->build_url(LOGIN_URL);
|
||||
int httpResponseCode = client->GET();
|
||||
if (httpResponseCode > 0) {
|
||||
StaticJsonDocument<LOGIN_JSON_SIZE> doc;
|
||||
DeserializationError error = deserializeJson(doc, client->getString().c_str());
|
||||
if (error) {
|
||||
delete client;
|
||||
return -1;
|
||||
}
|
||||
delete client;
|
||||
return 0;
|
||||
}
|
||||
delete client;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string replace_id(const char *str, const char *id) {
|
||||
std::string url(str);
|
||||
url.replace(url.find("{id}"), 4, id);
|
||||
return url;
|
||||
}
|
||||
|
||||
std::vector<models::Product> *DolibarrClient::list_products() const {
|
||||
HTTPClient *client = this->build_url(LIST_PRODUCT_URL);
|
||||
if (client->GET() == OK_RESPONSE) {
|
||||
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
models::Product *DolibarrClient::get_product_by_id(const char* id_product) const {
|
||||
HTTPClient *client = this->build_url(replace_id(GET_PRODUCT_URL, id_product).c_str());
|
||||
if (client->GET() == OK_RESPONSE) {
|
||||
StaticJsonDocument<GET_PRODUCT_JSON_SIZE> doc;
|
||||
DeserializationError error = deserializeJson(doc, client->getString().c_str());
|
||||
if (error) {
|
||||
Serial.println("ERROR: ");
|
||||
Serial.println(error.c_str());
|
||||
delete client;
|
||||
return nullptr;
|
||||
}
|
||||
auto *product = new models::Product();
|
||||
product->date_creation = doc["date_creation"];
|
||||
product->id = doc["id"];
|
||||
product->entity = doc["entity"];
|
||||
product->stock_reel = doc["stock_reel"];
|
||||
product->label = doc["label"];
|
||||
delete client;
|
||||
return product;
|
||||
}
|
||||
delete client;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<models::Warehouse> *DolibarrClient::list_warehouse() const {
|
||||
HTTPClient *client = this->build_url(LIST_WAREHOUSE_URL);
|
||||
if (client->GET() == OK_RESPONSE) {
|
||||
StaticJsonDocument<LIST_WAREHOUSE_JSON_SIZE> doc;
|
||||
DeserializationError error = deserializeJson(doc, client->getString().c_str());
|
||||
if (error) {
|
||||
Serial.println("ERROR: ");
|
||||
Serial.println(error.c_str());
|
||||
delete client;
|
||||
return nullptr;
|
||||
}
|
||||
auto *warehouses = new std::vector<models::Warehouse>();
|
||||
for (auto obj : doc.as<JsonArray>()) {
|
||||
models::Warehouse warehouse = {};
|
||||
warehouse.id = obj["id"];
|
||||
warehouses->push_back(warehouse);
|
||||
}
|
||||
delete client;
|
||||
return warehouses;
|
||||
}
|
||||
delete client;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int DolibarrClient::create_movement(models::CreateProductStock &stock) const {
|
||||
HTTPClient *client = this->build_url(CREATE_STOCKS_MOVEMENTS_URL);
|
||||
StaticJsonDocument<CREATE_STOCKS_MOVEMENTS_JSON_SIZE> doc;
|
||||
std::string result;
|
||||
doc["product_id"] = stock.product_id;
|
||||
doc["warehouse_id"] = stock.warehouse_id;
|
||||
doc["qty"] = stock.qty;
|
||||
serializeJson(doc, result);
|
||||
Serial.println(result.c_str());
|
||||
if (client->POST(result.c_str()) == OK_RESPONSE) {
|
||||
delete client;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int DolibarrClient::initialize_wifi() const {
|
||||
WiFiClass::mode(WIFI_STA); //Optional
|
||||
WiFi.setSleep(false);
|
||||
WiFi.begin(this->wifi.ssid, this->wifi.password);
|
||||
Serial.print("Connecting ");
|
||||
while(WiFiClass::status() != WL_CONNECTED){
|
||||
delay(WAITING_WIFI_DELAY);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println("Connected to the WiFi network");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DolibarrClient::initialize_http_client() {
|
||||
this->httpClient = new HTTPClient();
|
||||
if (this->login() == 0) {
|
||||
auto* product = this->get_product_by_id("1");
|
||||
if (product == nullptr) {
|
||||
Serial.println("Product is nullptr !");
|
||||
return -1;
|
||||
}
|
||||
Serial.println("Product label: ");
|
||||
Serial.println(product->label);
|
||||
auto* warehouses = this->list_warehouse();
|
||||
if (warehouses == nullptr) {
|
||||
delete product;
|
||||
Serial.println("Warehouse is nullptr !");
|
||||
return -1;
|
||||
}
|
||||
Serial.println("Warehouses: ");
|
||||
models::CreateProductStock product_stock = {product->id, warehouses->at(0).id, "1"};
|
||||
this->create_movement(product_stock);
|
||||
for (auto warehouse : *warehouses) {
|
||||
Serial.println(warehouse.id);
|
||||
}
|
||||
delete product;
|
||||
delete warehouses;
|
||||
} else {
|
||||
Serial.println("An Error has occurred while trying to login");
|
||||
}
|
||||
return 0;
|
||||
}
|
56
lib/DolibarrClient/src/DolibarrClient.h
Normal file
56
lib/DolibarrClient/src/DolibarrClient.h
Normal file
@ -0,0 +1,56 @@
|
||||
#ifndef DOLIBARR_CLIENT_H
|
||||
#define DOLIBARR_CLIENT_H
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <HTTPClient.h>
|
||||
#include <vector>
|
||||
#include "DolibarrModels.h"
|
||||
|
||||
constexpr u_int32_t OK_RESPONSE = 200;
|
||||
constexpr u_int32_t CREATED_RESPONSE = 201;
|
||||
constexpr u_int32_t NO_CONTENT_RESPONSE = 204;
|
||||
|
||||
constexpr u_int32_t LOGIN_JSON_SIZE = 4096;
|
||||
constexpr const char* LOGIN_URL = "/users/info";
|
||||
constexpr u_int32_t LIST_PRODUCT_JSON_SIZE = 4096;
|
||||
constexpr const char* LIST_PRODUCT_URL = "/products/";
|
||||
constexpr u_int32_t GET_PRODUCT_JSON_SIZE = 4096;
|
||||
constexpr const char* GET_PRODUCT_URL = "/products/{id}/";
|
||||
constexpr u_int32_t GET_PRODUCT_STOCK_JSON_SIZE = 4096;
|
||||
constexpr const char* GET_PRODUCT_STOCK_URL = "/products/{id}/stock/";
|
||||
constexpr u_int32_t LIST_WAREHOUSE_JSON_SIZE = 4096;
|
||||
constexpr const char* LIST_WAREHOUSE_URL = "/warehouses/";
|
||||
constexpr u_int32_t LIST_STOCKS_MOVEMENTS_JSON_SIZE = 4096;
|
||||
constexpr const char* LIST_STOCKS_MOVEMENTS_URL = "/stockmovements/?sortfield=t.rowid&sortorder=ASC&limit=100";
|
||||
constexpr u_int32_t CREATE_STOCKS_MOVEMENTS_JSON_SIZE = 4096;
|
||||
constexpr const char* CREATE_STOCKS_MOVEMENTS_URL = "/stockmovements/";
|
||||
|
||||
struct WifiConfig {
|
||||
const char* ssid;
|
||||
const char* password;
|
||||
};
|
||||
|
||||
struct DolibarrConfig {
|
||||
const char* url;
|
||||
const char* api_key;
|
||||
};
|
||||
|
||||
class DolibarrClient {
|
||||
public:
|
||||
DolibarrClient(WifiConfig wifi_config, DolibarrConfig dolibarr_config);
|
||||
~DolibarrClient() = default;
|
||||
int login() const;
|
||||
std::vector<models::Warehouse> *list_warehouse() const;
|
||||
std::vector<models::Product> *list_products() const;
|
||||
models::Product *get_product_by_id(const char* id_product) const;
|
||||
int create_movement(models::CreateProductStock &stock) const;
|
||||
private:
|
||||
HTTPClient* httpClient{};
|
||||
struct WifiConfig wifi;
|
||||
struct DolibarrConfig dolibarr;
|
||||
int initialize_wifi() const;
|
||||
int initialize_http_client();
|
||||
HTTPClient *build_url(const String& url) const;
|
||||
};
|
||||
|
||||
#endif //DOLIBARR_CLIENT_H
|
5
lib/DolibarrClient/src/DolibarrModels.cpp
Normal file
5
lib/DolibarrClient/src/DolibarrModels.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
//
|
||||
// Created by nico on 15/09/23.
|
||||
//
|
||||
|
||||
#include "DolibarrModels.h"
|
40
lib/DolibarrClient/src/DolibarrModels.h
Normal file
40
lib/DolibarrClient/src/DolibarrModels.h
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef T_IOT_901_CONVOYOR_DOLIBARRMODELS_H
|
||||
#define T_IOT_901_CONVOYOR_DOLIBARRMODELS_H
|
||||
|
||||
namespace models {
|
||||
|
||||
struct Product {
|
||||
const char* id;
|
||||
const char* entity;
|
||||
const char* ref;
|
||||
const char* status;
|
||||
const char* date_creation;
|
||||
const char* date_modification;
|
||||
const char* label;
|
||||
const char* description;
|
||||
const char* type;
|
||||
const char* price;
|
||||
const char* stock_reel;
|
||||
const char* seuil_stock_alerte;
|
||||
const char* desiredstock;
|
||||
};
|
||||
|
||||
struct ProductStock {
|
||||
const char* id;
|
||||
const char* product_id;
|
||||
const char* quantity;
|
||||
};
|
||||
|
||||
struct CreateProductStock {
|
||||
const char* product_id;
|
||||
const char* warehouse_id;
|
||||
const char* qty;
|
||||
};
|
||||
|
||||
struct Warehouse {
|
||||
const char* id;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //T_IOT_901_CONVOYOR_DOLIBARRMODELS_H
|
56
lib/WarehouseGUI/src/GUIScreen.cpp
Normal file
56
lib/WarehouseGUI/src/GUIScreen.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include "GUIScreen.h"
|
||||
|
||||
// Abstract AGuiScreen definition
|
||||
|
||||
gui::AGUIScreen::AGUIScreen() {
|
||||
std::cout << "Hello form AGUIScreen" << "\n";
|
||||
this->widgets = std::vector<AGUIWidget*>();
|
||||
}
|
||||
|
||||
int gui::AGUIScreen::update() {
|
||||
std::sort(widgets.begin(), widgets.end(), [](AGUIWidget* aWidget, AGUIWidget* bWidget) {
|
||||
return aWidget->getLayer() < bWidget->getLayer();
|
||||
});
|
||||
for (auto *widget: widgets) {
|
||||
widget->update();
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int gui::AGUIScreen::addWidget(gui::AGUIWidget *widget) {
|
||||
this->widgets.push_back(widget);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gui::AGUIScreen::removeWidget(gui::AGUIWidget *_widget) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gui::AGUIScreen::removeWidget(int _index) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gui::AGUIScreen::removeWidget(const char *_name) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<gui::AGUIWidget*> gui::AGUIScreen::getWidgets() const {
|
||||
return this->widgets;
|
||||
}
|
||||
|
||||
|
||||
// DefaultGuiScreen definition
|
||||
|
||||
gui::DefaultGuiScreen::DefaultGuiScreen() {
|
||||
std::cout << "Hello form DefaultGuiScreen" << "\n";
|
||||
}
|
||||
|
||||
int gui::DefaultGuiScreen::setup() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *gui::DefaultGuiScreen::getName() const {
|
||||
return "DefaultGuiScreen";
|
||||
}
|
35
lib/WarehouseGUI/src/GUIScreen.h
Normal file
35
lib/WarehouseGUI/src/GUIScreen.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef T_IOT_901_CONVOYOR_GUICONTAINER_H
|
||||
#define T_IOT_901_CONVOYOR_GUICONTAINER_H
|
||||
|
||||
#include <vector>
|
||||
#include "GUIWidget.h"
|
||||
|
||||
namespace gui {
|
||||
|
||||
class AGUIScreen {
|
||||
public:
|
||||
AGUIScreen();
|
||||
~AGUIScreen() = default;
|
||||
virtual const char* getName() const = 0;
|
||||
virtual int setup() = 0;
|
||||
int update();
|
||||
int addWidget(AGUIWidget* widget);
|
||||
int removeWidget(AGUIWidget* widget);
|
||||
int removeWidget(int index);
|
||||
int removeWidget(const char* name);
|
||||
std::vector<AGUIWidget*> getWidgets() const;
|
||||
protected:
|
||||
std::vector<AGUIWidget*> widgets;
|
||||
};
|
||||
|
||||
class DefaultGuiScreen : public AGUIScreen {
|
||||
public:
|
||||
DefaultGuiScreen();
|
||||
~DefaultGuiScreen() = default;
|
||||
const char* getName() const override;
|
||||
int setup() override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //T_IOT_901_CONVOYOR_GUICONTAINER_H
|
33
lib/WarehouseGUI/src/GUIWidget.cpp
Normal file
33
lib/WarehouseGUI/src/GUIWidget.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
#include "GUIWidget.h"
|
||||
|
||||
gui::AGUIWidget::AGUIWidget(int x, int y, int width, int height, int layer) : layer(layer) {
|
||||
this->position.x = x;
|
||||
this->position.y = y;
|
||||
this->size.width = width;
|
||||
this->size.height = height;
|
||||
}
|
||||
|
||||
int gui::AGUIWidget::getLayer() const {
|
||||
return this->layer;
|
||||
}
|
||||
|
||||
void gui::AGUIWidget::setLayer(int newLayer) {
|
||||
this->layer = newLayer;
|
||||
}
|
||||
|
||||
GuiWidgetPosition gui::AGUIWidget::getPosition() const {
|
||||
return this->position;
|
||||
}
|
||||
|
||||
void gui::AGUIWidget::setPosition(GuiWidgetPosition pos) {
|
||||
this->position = pos;
|
||||
}
|
||||
|
||||
GuiWidgetSize gui::AGUIWidget::getSize() const {
|
||||
return this->size;
|
||||
}
|
||||
|
||||
void gui::AGUIWidget::setSize(GuiWidgetSize newSize) {
|
||||
this->size = newSize;
|
||||
}
|
||||
|
35
lib/WarehouseGUI/src/GUIWidget.h
Normal file
35
lib/WarehouseGUI/src/GUIWidget.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef T_IOT_901_CONVOYOR_GUIWIDGET_H
|
||||
#define T_IOT_901_CONVOYOR_GUIWIDGET_H
|
||||
|
||||
struct GuiWidgetPosition {
|
||||
int x;
|
||||
int y;
|
||||
};
|
||||
|
||||
struct GuiWidgetSize {
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
namespace gui {
|
||||
class AGUIWidget {
|
||||
public:
|
||||
AGUIWidget(int x, int y, int width, int height, int layer = 0);
|
||||
~AGUIWidget() = default;
|
||||
virtual const char* getName() const = 0;
|
||||
virtual void setup() = 0;
|
||||
virtual void update() = 0;
|
||||
int getLayer() const;
|
||||
void setLayer(int layer);
|
||||
GuiWidgetPosition getPosition() const;
|
||||
void setPosition(GuiWidgetPosition position);
|
||||
GuiWidgetSize getSize() const;
|
||||
void setSize(GuiWidgetSize size);
|
||||
private:
|
||||
GuiWidgetPosition position{};
|
||||
GuiWidgetSize size{};
|
||||
int layer;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //T_IOT_901_CONVOYOR_GUIWIDGET_H
|
82
lib/WarehouseGUI/src/WarehouseGUI.cpp
Normal file
82
lib/WarehouseGUI/src/WarehouseGUI.cpp
Normal file
@ -0,0 +1,82 @@
|
||||
#include "WarehouseGUI.h"
|
||||
#include "M5Stack.h"
|
||||
|
||||
using namespace gui;
|
||||
|
||||
WarehouseGUI::WarehouseGUI() {
|
||||
this->screens = std::vector<AGUIScreen*>();
|
||||
}
|
||||
|
||||
WarehouseGUI::~WarehouseGUI() = default;
|
||||
|
||||
int WarehouseGUI::addScreens(gui::AGUIScreen *screen) {
|
||||
this->screens.push_back(screen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WarehouseGUI::removeScreens(gui::AGUIScreen *screen) {
|
||||
for (int i = 0; i < this->screens.size(); ++i) {
|
||||
if (this->screens[i] == screen) {
|
||||
this->screens.erase(this->screens.begin() + i);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int WarehouseGUI::removeScreens(int index) {
|
||||
if (index < 0 || index >= this->screens.size()) {
|
||||
return -1;
|
||||
}
|
||||
this->screens.erase(this->screens.begin() + index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WarehouseGUI::removeScreens(const char *name) {
|
||||
for (int i = 0; i < this->screens.size(); ++i) {
|
||||
if (this->screens[i]->getName() == name) {
|
||||
this->screens.erase(this->screens.begin() + i);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int WarehouseGUI::update() {
|
||||
return this->current_screen->update();
|
||||
}
|
||||
|
||||
int WarehouseGUI::setup() {
|
||||
if (this->current_screen == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
return this->current_screen->setup();
|
||||
}
|
||||
|
||||
int WarehouseGUI::changeCurrentScreen(const char *name) {
|
||||
for (auto *screen : this->screens) {
|
||||
if (screen->getName() == name) {
|
||||
this->current_screen = screen;
|
||||
this->current_screen->setup();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int WarehouseGUI::changeCurrentScreen(int index) {
|
||||
if (index < 0 || index >= this->screens.size()) {
|
||||
return -1;
|
||||
}
|
||||
this->current_screen = this->screens[index];
|
||||
this->current_screen->setup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<AGUIScreen *> gui::WarehouseGUI::getAllScreens() {
|
||||
return this->screens;
|
||||
}
|
||||
|
||||
AGUIScreen *gui::WarehouseGUI::getCurrentScreen() {
|
||||
return this->current_screen;
|
||||
}
|
29
lib/WarehouseGUI/src/WarehouseGUI.h
Normal file
29
lib/WarehouseGUI/src/WarehouseGUI.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef T_IOT_901_CONVOYOR_WAREHOUSEGUI_H
|
||||
#define T_IOT_901_CONVOYOR_WAREHOUSEGUI_H
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include "GUIScreen.h"
|
||||
|
||||
namespace gui {
|
||||
class WarehouseGUI {
|
||||
public:
|
||||
WarehouseGUI();
|
||||
~WarehouseGUI();
|
||||
int addScreens(AGUIScreen* screen);
|
||||
int removeScreens(AGUIScreen* screen);
|
||||
int removeScreens(int index);
|
||||
int removeScreens(const char *name);
|
||||
int changeCurrentScreen(const char* name);
|
||||
int changeCurrentScreen(int index);
|
||||
std::vector<AGUIScreen*> getAllScreens();
|
||||
AGUIScreen* getCurrentScreen();
|
||||
int setup();
|
||||
int update();
|
||||
private:
|
||||
std::vector<AGUIScreen*> screens;
|
||||
AGUIScreen *current_screen{nullptr};
|
||||
};
|
||||
} // namespace gui
|
||||
|
||||
#endif //T_IOT_901_CONVOYOR_WAREHOUSEGUI_H
|
Reference in New Issue
Block a user