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

Co-authored-by: Nicolas SANS <nicolas.sansd@gmail.com>
Co-authored-by: Clement <c.boesmier@aptatio.com>
Co-authored-by: Clement <clement@jo85.com>
Reviewed-on: #7
Co-authored-by: Nicolas <nicolas.sansd@gmail.com>
Co-committed-by: Nicolas <nicolas.sansd@gmail.com>
This commit is contained in:
Nicolas 2023-11-10 16:47:39 +01:00 committed by Clement
parent e4f009b63e
commit 88077f284e
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/c_cpp_properties.json
.vscode/launch.json .vscode/launch.json
.vscode/ipch .vscode/ipch
.idea/
# Aptatio/Platformio specifics # Aptatio/Platformio specifics
secrets.ini secrets.ini
.env

View File

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

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 #define PROGRAM_H
#include "Arduino.h" #include "Arduino.h"
#include "DolibarrClient.h"
#include <M5Stack.h>
class Program { class Program {
public: public:
@ -11,9 +13,11 @@ public:
Program(); Program();
/** /**
* Program main loop * Program WarehouseGUI loop
*/ */
void loop(); void loop();
private:
DolibarrClient *client;
}; };
#endif #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 {
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;
}
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;
};
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 {
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 secrets.ini
config.ini config.ini
envs.ini envs.ini
config_api.ini
; Cache folder ; Cache folder
build_cache_dir = ./.pio/cache build_cache_dir = ./.pio/cache
[env] [env]
; build Envs ; 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 ; Add scripts for more functionnalities
; see individual scripts for more informations ; see individual scripts for more informations
@ -50,6 +51,9 @@ upload_speed = 921600
; librairies (make sure to fix versions where possible!) ; librairies (make sure to fix versions where possible!)
lib_deps = 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: ; example:
; erropix/ESP32 AnalogWrite@0.2 ; erropix/ESP32 AnalogWrite@0.2

View File

@ -4,3 +4,8 @@
[secrets] [secrets]
build_flags = 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 "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() { Program::Program() {
// Startup
Serial.begin(MONITOR_SPEED); 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() { void Program::loop() {
// Loop
} }

View File

@ -1,5 +1,4 @@
#include "Program.h" #include "Program.h"
Program* program; Program* program;
void setup() { 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