Création du module DolibarrClient avec ses différentes routes & création du module WarehouseGUI pour le LCD M5Stack #7

Merged
Clement merged 9 commits from feat/client_dolibarr into develop 2023-11-10 15:47:41 +00:00
16 changed files with 358 additions and 9 deletions

4
.env.example Normal file
View File

@ -0,0 +1,4 @@
TIME_ZONE='Europe/Paris'
DOLI_URL='http://0.0.0.0'
DB_NAME="dolibarr"
DB_PASS="password"

2
.gitignore vendored
View File

@ -7,6 +7,8 @@
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch
.idea/
# Aptatio/Platformio specifics
secrets.ini
.env

View File

@ -13,7 +13,4 @@ build_flags =
; DO NOT TOUCH --- START
-D MONITOR_SPEED=${config.monitor_speed}
; DO NOT TOUCH --- END
-D EXAMPLE_NUMBER=69
-D EXAMPLE_STRING=\"Pouet\"
-D WAITING_WIFI_DELAY=1000

10
config_api.ini Normal file
View File

@ -0,0 +1,10 @@
[config_api]
build_flags =
-D API_LOGIN_URL=\"/users/info\"
-D API_LIST_PRODUCT_URL=\"/products/\"
-D API_GET_PRODUCT_URL=\"/products/{id}/\"
-D API_GET_PRODUCT_STOCK_URL=\"/products/{id}/stock/\"
-D API_LIST_WAREHOUSE_URL=\"/warehouses/\"
-D API_LIST_STOCKS_MOVEMENTS_URL=\"/stockmovements/?sortfield=t.rowid\"
-D API_CREATE_STOCKS_MOVEMENTS_URL=\"/stockmovements/\"
-D API_MAX_JSON_SIZE=4096

27
docker-compose.yml Normal file
View File

@ -0,0 +1,27 @@
version: "3"
services:
mariadb:
image: mariadb:latest
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASS}
MYSQL_DATABASE: ${DB_NAME}
volumes:
- database:/var/lib/mysql
restart: always
web:
image: tuxgasy/dolibarr
environment:
DOLI_DB_HOST: mariadb
DOLI_DB_USER: root
DOLI_DB_PASSWORD: ${DB_PASS}
DOLI_DB_NAME: ${DB_NAME}
DOLI_URL_ROOT: ${DOLI_URL}
PHP_INI_DATE_TIMEZONE: ${TIME_ZONE}
restart: always
# ports:
# - "80:80"
depends_on:
- mariadb
volumes:
database:

View File

@ -2,6 +2,8 @@
#define PROGRAM_H
#include "Arduino.h"
#include "DolibarrClient.h"
#include <M5Stack.h>
class Program {
public:
@ -11,9 +13,11 @@ public:
Program();
/**
* Program main loop
* Program WarehouseGUI loop
*/
void loop();
private:
DolibarrClient *client;
};
#endif

View File

@ -0,0 +1,151 @@
#include "DolibarrClient.h"
#include <WiFi.h>
#include <ArduinoJson.h>
#include <iostream>
DolibarrClient::DolibarrClient(struct DolibarrConfig dolibarr_config) : dolibarr(dolibarr_config) {
#if defined(DEBUG)
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_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(API_LOGIN_URL);
int httpResponseCode = client->GET();
if (httpResponseCode > 0) {
StaticJsonDocument<API_MAX_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;
}
String replace_id(const char *str, const char *id) {
String url(str);
url.replace("{id}", id);
return url;
}
std::vector<models::Product> *DolibarrClient::list_products() const {
Nicolas marked this conversation as resolved
Review

utiliser les string d'Arduino

utiliser les string d'Arduino
HTTPClient *client = this->build_url(API_LIST_PRODUCT_URL);
if (client->GET() == HTTP_CODE_OK) {
}
return nullptr;
}
models::Product *DolibarrClient::get_product_by_id(const char* id_product) const {
HTTPClient *client = this->build_url(replace_id(API_GET_PRODUCT_URL, id_product).c_str());
if (client->GET() == HTTP_CODE_OK) {
StaticJsonDocument<API_MAX_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(API_LIST_WAREHOUSE_URL);
if (client->GET() == HTTP_CODE_OK) {
StaticJsonDocument<API_MAX_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("API_CREATE_STOCKS_MOVEMENTS_URL");
StaticJsonDocument<API_MAX_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()) == HTTP_CODE_OK) {
delete client;
return 0;
}
return -1;
}
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;
Nicolas marked this conversation as resolved
Review

faut pas faire sa dans le prog principal ?

faut pas faire sa dans le prog principal ?
}
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;
}

View File

@ -0,0 +1,35 @@
#ifndef DOLIBARR_CLIENT_H
#define DOLIBARR_CLIENT_H
#include <WiFi.h>
#include <HTTPClient.h>
#include <vector>
#include "DolibarrModels.h"
struct WifiConfig {
const char* ssid;
const char* password;
};
Nicolas marked this conversation as resolved
Review

tout les constexpr les mettre dans les fichiers ini (env et config)

tout les constexpr les mettre dans les fichiers ini (env et config)
struct DolibarrConfig {
const char* url;
const char* api_key;
};
class DolibarrClient {
public:
DolibarrClient(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 DolibarrConfig dolibarr;
int initialize_http_client();
HTTPClient *build_url(const String& url) const;
};
#endif //DOLIBARR_CLIENT_H

View File

@ -0,0 +1,40 @@
#ifndef T_IOT_901_CONVOYOR_DOLIBARRMODELS_H
#define T_IOT_901_CONVOYOR_DOLIBARRMODELS_H
namespace models {
Nicolas marked this conversation as resolved
Review

je suis chaud que tu m'explique les namesapce j'ai jamais utiliser ;)

je suis chaud que tu m'explique les namesapce j'ai jamais utiliser ;)
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

View File

@ -17,13 +17,14 @@ extra_configs =
secrets.ini
config.ini
envs.ini
config_api.ini
; Cache folder
build_cache_dir = ./.pio/cache
[env]
; build Envs
build_flags = ${config.build_flags} ${secrets.build_flags}
build_flags = ${config.build_flags} ${secrets.build_flags} ${config_api.build_flags}
; Add scripts for more functionnalities
; see individual scripts for more informations
@ -50,6 +51,9 @@ upload_speed = 921600
; librairies (make sure to fix versions where possible!)
lib_deps =
bblanchon/ArduinoJson@^6.21.3 ; JSON serializer et deserializer
m5stack/M5Stack@^0.4.5 ; M5 Lib
m5stack/M5GFX@^0.1.9 ; M5 Lib pour le LCD
; example:
; erropix/ESP32 AnalogWrite@0.2

View File

@ -4,3 +4,8 @@
[secrets]
build_flags =
-D WIFI_SSID=\"test\"
-D WIFI_PASSWORD=\"abcd1234\"
-D DOLIBARR_API_TOKEN=\"monapitokendedolibarr\"
-D DOLIBARR_URL=\"http://0.0.0.0/api/index.php\"
-D DEBUG=true

View File

@ -1,10 +1,29 @@
#include "Program.h"
#include "Arduino.h"
#include "DolibarrClient.h"
int initialize_wifi(WifiConfig wifi) {
WiFiClass::mode(WIFI_STA); //Optional
WiFi.setSleep(false);
WiFi.begin(wifi.ssid, 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;
}
Program::Program() {
// Startup
Serial.begin(MONITOR_SPEED);
struct WifiConfig wifi_c = {WIFI_SSID, WIFI_PASSWORD};
struct DolibarrConfig dolibarr = {DOLIBARR_URL, DOLIBARR_API_TOKEN};
initialize_wifi(wifi_c);
this->client = new DolibarrClient(dolibarr);
}
void Program::loop() {
// Loop
}

View File

@ -1,5 +1,4 @@
#include "Program.h"
Program* program;
void setup() {

10
test/dolibarr.cpp Normal file
View File

@ -0,0 +1,10 @@
#include <unity.h>
#include "DolibarrClient.h"
void test_construct_dolibarr_client() {
return;
}
void test_destroy_basic_state() {
return;
}

36
test/test.cpp Normal file
View File

@ -0,0 +1,36 @@
#include <M5Stack.h>
#include <unity.h>
#include "test.h"
void setUp(void) {
// set stuff up here
}
void tearDown(void) {
// clean stuff up here
}
int runUnityTests(void) {
UNITY_BEGIN();
RUN_TEST(test_construct_dolibarr_client);
return UNITY_END();
}
int main(void) {
return runUnityTests();
}
// For Arduino framework
void setup() {
// Wait ~2 seconds before the Unity test runner
// establishes connection with a board Serial interface
runUnityTests();
}
// For Arduino framework
void loop() {}
// For ESP-IDF framework
void app_main() {
runUnityTests();
}

6
test/test.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef T_IOT_901_CONVOYOR_TEST_H
#define T_IOT_901_CONVOYOR_TEST_H
void test_construct_dolibarr_client();
#endif //T_IOT_901_CONVOYOR_TEST_H