diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..ec636a3 --- /dev/null +++ b/.env.example @@ -0,0 +1,4 @@ +TIME_ZONE='Europe/Paris' +DOLI_URL='http://0.0.0.0' +DB_NAME="dolibarr" +DB_PASS="password" diff --git a/.gitignore b/.gitignore index 53072ca..5df975e 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,8 @@ .vscode/c_cpp_properties.json .vscode/launch.json .vscode/ipch +.idea/ # Aptatio/Platformio specifics secrets.ini +.env diff --git a/config.ini b/config.ini index 11e4023..dff2d75 100644 --- a/config.ini +++ b/config.ini @@ -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 diff --git a/config_api.ini b/config_api.ini new file mode 100644 index 0000000..985e209 --- /dev/null +++ b/config_api.ini @@ -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 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..ee1200a --- /dev/null +++ b/docker-compose.yml @@ -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: diff --git a/include/Program.h b/include/Program.h index 66e4a79..b4f30bb 100644 --- a/include/Program.h +++ b/include/Program.h @@ -2,6 +2,8 @@ #define PROGRAM_H #include "Arduino.h" +#include "DolibarrClient.h" +#include class Program { public: @@ -11,9 +13,11 @@ public: Program(); /** - * Program main loop + * Program WarehouseGUI loop */ void loop(); +private: + DolibarrClient *client; }; #endif diff --git a/lib/DolibarrClient/src/DolibarrClient.cpp b/lib/DolibarrClient/src/DolibarrClient.cpp new file mode 100644 index 0000000..a07353d --- /dev/null +++ b/lib/DolibarrClient/src/DolibarrClient.cpp @@ -0,0 +1,151 @@ +#include "DolibarrClient.h" +#include +#include +#include + +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 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 *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 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 *DolibarrClient::list_warehouse() const { + HTTPClient *client = this->build_url(API_LIST_WAREHOUSE_URL); + if (client->GET() == HTTP_CODE_OK) { + StaticJsonDocument 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(); + for (auto obj : doc.as()) { + 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 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; +} \ No newline at end of file diff --git a/lib/DolibarrClient/src/DolibarrClient.h b/lib/DolibarrClient/src/DolibarrClient.h new file mode 100644 index 0000000..7579332 --- /dev/null +++ b/lib/DolibarrClient/src/DolibarrClient.h @@ -0,0 +1,35 @@ +#ifndef DOLIBARR_CLIENT_H +#define DOLIBARR_CLIENT_H + +#include +#include +#include +#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 *list_warehouse() const; + std::vector *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 diff --git a/lib/DolibarrClient/src/DolibarrModels.h b/lib/DolibarrClient/src/DolibarrModels.h new file mode 100644 index 0000000..1443119 --- /dev/null +++ b/lib/DolibarrClient/src/DolibarrModels.h @@ -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 diff --git a/platformio.ini b/platformio.ini index 95b9ed1..9724c56 100644 --- a/platformio.ini +++ b/platformio.ini @@ -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 diff --git a/secrets.ini.example b/secrets.ini.example index 90b9782..5df2d8a 100644 --- a/secrets.ini.example +++ b/secrets.ini.example @@ -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 \ No newline at end of file diff --git a/src/Program.cpp b/src/Program.cpp index e412959..8454899 100644 --- a/src/Program.cpp +++ b/src/Program.cpp @@ -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 } + + diff --git a/src/main.cpp b/src/main.cpp index 74bf5a7..bf9fbf6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,4 @@ #include "Program.h" - Program* program; void setup() { diff --git a/test/dolibarr.cpp b/test/dolibarr.cpp new file mode 100644 index 0000000..07a1edb --- /dev/null +++ b/test/dolibarr.cpp @@ -0,0 +1,10 @@ +#include +#include "DolibarrClient.h" + +void test_construct_dolibarr_client() { + return; +} + +void test_destroy_basic_state() { + return; +} diff --git a/test/test.cpp b/test/test.cpp new file mode 100644 index 0000000..ef919f7 --- /dev/null +++ b/test/test.cpp @@ -0,0 +1,36 @@ +#include +#include +#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(); +} diff --git a/test/test.h b/test/test.h new file mode 100644 index 0000000..95c9ea5 --- /dev/null +++ b/test/test.h @@ -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