Compare commits

..

62 Commits

Author SHA1 Message Date
c270a764f2 Merge pull request 'patch' (#22) from develop into master
Reviewed-on: #22
2024-02-02 17:10:54 +01:00
26b1185bca Merge pull request 'fuc j'ai ouvlier un truc' (#21) from feat/output-reader into develop
Reviewed-on: #21
2024-02-02 17:10:31 +01:00
627509a2d7 fuc j'ai ouvlier un truc 2024-02-02 17:07:16 +01:00
01728a2499 Merge pull request 'feat:V1.0' (#8) from develop into master
Reviewed-on: #8
2024-02-02 17:03:23 +01:00
57cf250a03 Merge pull request 'feat/output-reader' (#20) from feat/output-reader into develop
Reviewed-on: #20
Reviewed-by: Nicolas <nicolas.sansd@gmail.com>
2024-02-02 16:43:13 +01:00
9c11f62019 add timer for stepper 2024-02-02 14:39:50 +01:00
7b975bd9a9 add to mutch colis error 2024-02-01 15:38:04 +01:00
35ecce7d5d sync 2024-02-01 11:53:19 +01:00
a105387c21 add nfc reader lib 2024-02-01 11:28:03 +01:00
3f77acd600 feat: 2nd in site test 2024-01-26 11:35:26 +01:00
23258e2682 Merge pull request 'feat: main-algo' (#16) from feat/main-algo into develop
Reviewed-on: #16
Reviewed-by: Nicolas <nicolas.sansd@gmail.com>
2024-01-26 09:47:25 +01:00
f64264631e Merge branch 'develop' of ssh://git.lab-ouest.org:8022/Epitech/T-IOT-901_convoyor into feat/main-algo
# Conflicts:
#	config.ini
#	include/Program.h
#	lib/NFC/src/NfcReader.cpp
#	src/Program.cpp
2024-01-26 09:46:49 +01:00
68a4ab9755 Merge pull request 'feat/m5_lcd' (#19) from feat/m5_lcd into develop
Reviewed-on: #19
2024-01-26 09:40:59 +01:00
69db4ba2b7 Ajout check connexion wifi 2024-01-26 09:39:15 +01:00
45cef130ca Ajout de l'algo 2024-01-25 14:29:08 +01:00
2c22e0a538 Merge remote-tracking branch 'origin/develop' into feat/m5_lcd
# Conflicts:
#	config.ini
#	src/Program.cpp
2024-01-19 16:48:08 +01:00
c498489cbb Merge pull request 'feature/servo_motor_component' (#17) from feature/servo_motor_component into develop
Reviewed-on: #17
Reviewed-by: Nicolas <nicolas.sansd@gmail.com>
2024-01-19 16:46:00 +01:00
c3e50c79b5 Rebase develop 2024-01-19 16:43:37 +01:00
fe671182cd add config.ini 2024-01-19 16:40:31 +01:00
4f3a5bda03 Création du composant LCD, rajout des écrans de logs et du dashboard 2024-01-19 16:40:28 +01:00
15bd7c7741 Retour Clement 2024-01-19 16:40:15 +01:00
dea01d3e84 Refacto servoMotor 2024-01-19 16:40:15 +01:00
9a8a84a59e [ServoMotor] - rework servoMotor for adding speed and easing for movement 2024-01-19 16:40:15 +01:00
027015b33b [feature/ServoMotor] - change servo librarie 2024-01-19 16:40:15 +01:00
f3dc069f3b [feature/Servo_Motor] - add ServoMotorComponent 2024-01-19 16:39:44 +01:00
1e59d9dc46 add config.ini 2024-01-19 16:37:35 +01:00
b3ef581d28 Merge remote-tracking branch 'origin/develop' into feat/main-algo 2024-01-19 12:05:17 +01:00
6e9a59bb00 Merge pull request 'feat: nfc-reader' (#15) from feat/nfc-reader into develop
Reviewed-on: #15
2024-01-19 12:01:17 +01:00
4023cfcb3d NFC: Removing delay function 2024-01-19 11:58:13 +01:00
0e14688f85 Merge branch 'develop' into feat/nfc-reader 2024-01-19 11:54:23 +01:00
032960c168 fix: Addr config 2024-01-19 11:51:59 +01:00
81c9ececf6 Retour Clement 2024-01-19 11:35:25 +01:00
4e8e916e5e NFC: Correcting bug & adding in config 2024-01-19 11:35:21 +01:00
a66882e877 Refacto servoMotor 2024-01-19 09:48:21 +01:00
29c41b6ccc add some affichage idea 2024-01-18 21:06:14 +01:00
04474bfb94 add main algo V1 with mock 2024-01-18 21:02:11 +01:00
463e71fe10 rename nfc reader 2024-01-18 21:01:53 +01:00
76ebc00763 add is idle condition on RGBL lib 2024-01-18 21:01:02 +01:00
8bdd4a9be2 add convoyer len and nfc i2C addr 2024-01-18 21:00:36 +01:00
f947fc7e5f Merge remote-tracking branch 'origin/feat/nfc-reader' into feat/main-algo 2024-01-18 19:53:23 +01:00
b96088c4eb cleanup 2024-01-18 19:32:02 +01:00
d8f0bb07be add idée d'algo 2024-01-18 19:16:23 +01:00
cada4d6e02 NFC: Adding NFC Reader 2024-01-18 16:57:26 +01:00
b7fe429508 Merge pull request 'feat: GRBL-stepper-motor' (#14) from feat/GRBL-stepper into develop
Reviewed-on: #14
2024-01-18 15:46:25 +01:00
fe529b4f57 reset main to initial state 2024-01-18 15:43:04 +01:00
a924d6c534 add stepper add config 2024-01-18 15:25:33 +01:00
cfffa667b6 fix grbl lib compile 2024-01-18 15:01:41 +01:00
3c7aea15a9 [ServoMotor] - rework servoMotor for adding speed and easing for movement 2023-12-08 09:45:07 +01:00
caa5b0ceb7 feat: gestion GRBL STEPPER 2023-11-23 12:55:08 +01:00
0a43f65ce2 gestion initialisation 2023-11-23 12:05:01 +01:00
38415c2da5 change config value 2023-11-23 12:04:37 +01:00
d077deb960 main test GRBL 2023-11-17 11:17:04 +01:00
07528f75f2 add file archi 2023-11-17 11:16:41 +01:00
eb3a6426cd add stepper config 2023-11-17 11:14:26 +01:00
844cbf817c [feature/ServoMotor] - change servo librarie 2023-11-17 09:59:15 +01:00
8e8df97e68 add init fonction 2023-11-16 16:07:29 +01:00
7cf9e88995 add test stepper 2023-11-16 15:42:54 +01:00
01b99d9716 [feature/Servo_Motor] - add ServoMotorComponent 2023-11-16 09:55:30 +01:00
88077f284e 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>
2023-11-10 16:47:39 +01:00
e4f009b63e docs: shematics (#12)
<!--
Bravo pour la PR, quelque note pour que tout se passe au mieux :D

- Lier la PR a une issue si elle existe!
- Assurez-vous que le nom de la PR respecte les règles (voir CONTRIBUTING.md)
- faites des rebase pour valider la PR
- Assurez-vous que le CI/CD est au vert
-->

Co-authored-by: Clement <c.boesmier@aptatio.com>
Reviewed-on: #12
2023-11-10 16:42:00 +01:00
258725e8c9 Feat: add doc for Dolibarr 2023-09-28 14:02:35 +02:00
884a181f04 fix: change board 2023-09-04 14:16:28 +02:00
38 changed files with 3966 additions and 90 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"

3
.gitignore vendored
View File

@ -7,7 +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
.idea .env

5
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,5 @@
{
"files.associations": {
"new": "cpp"
}
}

View File

@ -13,7 +13,31 @@ 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 TIMEZONE=\"Europe/Paris\"
;;;;;;;;;;;;;;;;;;;;;;
;;; stepper config ;;;
;;;;;;;;;;;;;;;;;;;;;;
-D STEPMOTOR_I2C_ADDR=0x70
-D STEPER_ACC=200
;-D STEPER_PAS=755.906 ; = 65mm
-D STEPER_PAS=58 ; = 5mm
-D STEPER_SPEED=2700 ;1000 ; 2500
-D GRBL_UPDATE=165 ;update time in ms
;;;;;;;;;;;;;;;;;;;;;;
;;; App config ;;;
;;;;;;;;;;;;;;;;;;;;;;
-D APP_TITLE=\"Warehouse\"
-D APP_VERSION=\"1.0\"
; nfc addr
-D NFC_ADDR=0x28
;;;;;;;;;;;;;;;;;;;;;;
;;; Servo config ;;;
;;;;;;;;;;;;;;;;;;;;;;
-D RIGHT_POS=14 ;18
-D MIDDLE_POS=30 ;32
-D LEFT_POS=52
-D EXAMPLE_NUMBER=69
-D EXAMPLE_STRING=\"Pouet\"
-D CONVOYER_LEN=80 ;mm

11
config_api.ini Normal file
View File

@ -0,0 +1,11 @@
[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_GET_PRODUCT_FACTORY_ID=\"/products\"
-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=6536

View File

@ -1,22 +0,0 @@
version: "3"
services:
mariadb:
image: mariadb:latest
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: dolibarr
web:
image: tuxgasy/dolibarr
environment:
DOLI_DB_HOST: mariadb
DOLI_DB_USER: root
DOLI_DB_PASSWORD: root
DOLI_DB_NAME: dolibarr
DOLI_URL_ROOT: 'http://0.0.0.0'
PHP_INI_DATE_TIMEZONE: 'Europe/Paris'
ports:
- "80:80"
links:
- mariadb

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:

64
docs/Doc_Dolibarr.md Normal file
View File

@ -0,0 +1,64 @@
# CRM Dolibarr
## Docker Image tuxgasy/dolibarr
### Description du composant
Dolibarr est le CRM utilisé pour gérer les stocks, les transactions et l'inventaire présents dans les entrepôts. Il est le pilier central du projet et nous servira d'interface pour gérer les transactions.
### Spécifications techniques
- **Image Docker**: [tuxgasy/dolibarr](https://hub.docker.com/r/tuxgasy/dolibarr/)
- **Plugins utilisés**: Stock, API REST
- **Utilisateur technique créé**: Technical User IoT
### Fonctionnalités principales
- Créer / Lister les différents entrepôts
- Créer / Lister les produits disponibles dans un entrepôt
- Créer un mouvement dans les stocks des produits disponibles dans chaque entrepôt
- Exposer différents webservices pour automatiser certaines tâches
### Guide d'utilisation
#### Créer une instance de développement
Pour créer une instance de développement, nous allons utiliser l'image Docker de Dolibarr: [tuxgasy/dolibarr](https://hub.docker.com/r/tuxgasy/dolibarr/)
Pour simplifier l'installation, un fichier docker-compose est disponible à la racine du projet: `./docker-compose-dolibarr.yml`
Pour lancer Dolibarr, exécutez la commande suivante :
```bash
$ docker compose -f docker-compose-dolibarr.yml up
```
#### Ensuite, il faut se rendre sur [http://0.0.0.0/](http://0.0.0.0/) puis se connecter avec les identifiants par défaut (admin, admin).
### Appel des différents webservices de Dolibarr
L'URL de base pour toutes nos requêtes HTTP (avec l'image Docker) est : `http://0.0.0.0/api/index.php`
Pour commencer, récupérez l'API token d'un utilisateur pour pouvoir effectuer des requêtes API. Assurez-vous que l'utilisateur dispose des autorisations nécessaires.
Ensuite, utilisez ce token pour chaque route API en l'ajoutant dans les en-têtes : `DOLAPIKEY = {{votre_api_token}}` de votre prochaine requête.
Pour récupérer le warehouse de base et vérifier son existence :
- **Méthode**: GET
- **URL**: `warehouses/{id}`
Pour récupérer les produits disponibles :
- **Méthode**: GET
- **URL**: `products?sortfield=t.ref&sortorder=ASC&limit=10000`
Pour créer un mouvement de stock :
- **Méthode**: POST
- **URL**: `stockmovements?sortfield=t.rowid&sortorder=ASC&limit=100`
- **Body (JSON)**:
```json
{
"product_id": "1", // string, - ID du produit à déplacer
"warehouse_id": "1", // string - ID de l'entrepôt
"qty": 60, // int - quantité à déplacer (1 pour positif ou -1 pour enlever un article)
"movementcode": "S-1", // string - code du mouvement
"movementlabel": "Abc" // string - libellé du mouvement
}

View File

@ -0,0 +1,77 @@
@startuml class
hide empty members
class Dolibarr {
+ String getDestination(String tagID)
+ String createStockMovement(String tagID, String warehouseId)
}
package "Managers" {
abstract AManager {
# ILCDScreen lcd
# IServoMotor servo
# IGRBL grbl
# INFCReader nfc
}
class WarehouseManager
WarehouseManager .|> AManager
}
package "Components" {
package "NFCReader" {
interface INFCReader {
{abstract} char* read()
{abstract} bool hasTag()
}
class RC522
RC522 .|> INFCReader
}
package "LCDScreen" {
interface ILCDScreen {
{abstract} void clearScreen()
{abstract} void draw(int x, int y, int h, int w)
{abstract} void drawRect(int x, int y, int h, int w)
}
class M5LCD
M5LCD .|> ILCDScreen
}
package "GRBL" {
interface IGRBL {
{abstract} drive(int x, int y, int z, int step)
{abstract} step(int s)
}
class M5GRBL
M5GRBL .|> IGRBL
}
package "ServoMotor" {
interface IServoMotor {
{abstract} goLeft()
{abstract} goRight()
{abstract} goMiddle()
}
class ServoMotor
ServoMotor .|> IServoMotor
}
}
class Program {
+ Program()
+ void loop
}
AManager <-- IServoMotor
AManager <-- IGRBL
AManager <-- ILCDScreen
AManager <-- INFCReader
Program <-- WarehouseManager
Program <-- Dolibarr
@enduml

View File

@ -0,0 +1,22 @@
@startuml hard wiring
cloud {
[Dolibarr]
}
package "Convoyeur"{
[M5 Core]
[Lecteur NFC] as nfc
[Servo Moteur] as servo
[GRBL]
[Stepper Moteur] as Stepper
}
[Dolibarr] <-- [M5 Core] : API
[M5 Core] --> servo : IO
[M5 Core] <-- nfc : IC2
[M5 Core] --> [GRBL] : SPI
[GRBL] --> Stepper
@enduml

View File

@ -1,58 +0,0 @@
# Dolbarr documentation
### Créer une instance de dev
Pour créer une instance de développement, nous allons utiliser l'image docker de dolibarr:
https://hub.docker.com/r/tuxgasy/dolibarr/
pour simplifier l'installation, un docker-compose est disponible a la racine du projet `./docker-compose-dolibarr.yml`
pour lancer dolibarr:
```shell
$ docker compose -f docker-compose-dolibarr.yml up
```
ensuite il faut se rendre sur http://0.0.0.0/ puis se login avec les credentials par défault (admin, admin)
### Api flow
Base url: http://0.0.0.0/api/index.php/
Pour commencer, il faut récupérer l'api token d'un utilisateur pour pouvoir faire des requêtes api, assurer vous bien que l'utilisateurs a bien les permissions nécéssaires:
![Api token user](../resources/image.png)
ensuite vous pouvez utiliser ce token pour chaque route API en ajoutant dans les headers:
DOLAPIKEY = {{votre_ap_token}}
Récupérer le warehouse de base et vérifier son existance :
```
Method: GET
Url: warehouses/{id}
```
Récupérer les produits disponibles:
```
Method: GET
Url: products?sortfield=t.ref&sortorder=ASC&limit=10000
```
Pour créer un mouvement de stock:
```
Method: POST
Url: stockmovements?sortfield=t.rowid&sortorder=ASC&limit=100
Body (JSON):
{
"product_id": "1", //string, - id of the product to move
"warehouse_id": "1", //string - id of the warehourse
"qty": 60, //int - quantity to move (1 for positive or -1 to remove one item)
"movementcode": "S-1", //string - code of the mouvement
"movementlabel": "Abc" //string - label of the mouvement
}
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

View File

@ -1,7 +1,12 @@
#ifndef PROGRAM_H #ifndef PROGRAM_H
#define PROGRAM_H #define PROGRAM_H
#include "Arduino.h" #include "DolibarrClient.h"
#include <M5Stack.h>
#include "ServoMotorComponent.h"
#include "NfcReader.h"
#include "GRBL.h"
#include "BigNfcReader.h"
class Program { class Program {
public: public:
@ -11,9 +16,19 @@ public:
Program(); Program();
/** /**
* Program main loop * Program WarehouseGUI loop
*/ */
void loop(); void loop();
void checkNfc();
void checkServo();
void checkWifi();
private:
DolibarrClient *client;
ServoMotorComponent *servo;
NfcReader *nfcReader;
GRBL *grbl;
BigNfcReader* outputReader;
int grblUpdateTime;
}; };
#endif #endif

View File

@ -0,0 +1,163 @@
#include "DolibarrClient.h"
#include <WiFi.h>
#include <ArduinoJson.h>
#include <iostream>
#include "M5LCD.h"
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) {
DynamicJsonDocument doc(384);
DeserializationError error = deserializeJson(doc, client->getString().c_str());
if (error) {
Serial.println("ERROR: ");
Serial.println(error.c_str());
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_factory_id(const char* factory_id) const {
HTTPClient *client = this->build_url(replace_id("/products?sortorder=ASC&limit=1&sqlfilters=(t.accountancy_code_sell:like:'{id}')", factory_id).c_str());
if (client->GET() == HTTP_CODE_OK) {
DynamicJsonDocument doc(6144);
DeserializationError error = deserializeJson(doc, client->getString().c_str());
if (error) {
Serial.println("ERROR: ");
Serial.println(error.c_str());
delete client;
return {};
}
for (auto obj : doc.as<JsonArray>()) {
models::Product product;
product.date_creation = obj["date_creation"].as<std::string>();
product.id = obj["id"].as<std::string>();
product.entity = obj["entity"].as<std::string>();
product.stock_reel = obj["stock_reel"].as<std::string>();
product.label = obj["label"].as<std::string>();
product.accountancy_code_sell = obj["accountancy_code_sell"].as<std::string>();
product.accountancy_code_sell_export = obj["accountancy_code_sell_export"].as<std::string>();
product.fk_default_warehouse = obj["fk_default_warehouse"].as<std::string>();
delete client;
return product;
}
delete client;
return {};
}
delete client;
return {};
}
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) {
DynamicJsonDocument doc(6144);
DeserializationError error = deserializeJson(doc, client->getString().c_str());
if (error) {
delete client;
return nullptr;
}
auto *product = new models::Product();
product->date_creation = doc["date_creation"].as<std::string>();
product->id = doc["id"].as<std::string>();
product->entity = doc["entity"].as<std::string>();
product->stock_reel = doc["stock_reel"].as<std::string>();
product->label = doc["label"].as<std::string>();
product->accountancy_code_sell = doc["accountancy_code_sell"].as<std::string>();
product->accountancy_code_sell_export = doc["accountancy_code_sell_export"].as<std::string>();
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) {
DynamicJsonDocument doc(8192);
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"].as<std::string>();
warehouse.label = obj["label"].as<std::string>();
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);
DynamicJsonDocument doc(4096);
std::string result;
doc["product_id"] = stock.product_id;
doc["warehouse_id"] = stock.warehouse_id;
doc["qty"] = stock.qty;
doc["movementlabel"] = "T-IOT - Warehouse GUI";
doc["movementcode"] = "M" + stock.product_id + "-W" + stock.warehouse_id;
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();
return 0;
}

View File

@ -0,0 +1,36 @@
#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;
models::Product get_product_by_factory_id(const char* uuid) 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,44 @@
#ifndef T_IOT_901_CONVOYOR_DOLIBARRMODELS_H
#define T_IOT_901_CONVOYOR_DOLIBARRMODELS_H
namespace models {
struct Product {
std::string id;
std::string entity;
std::string ref;
std::string status;
std::string date_creation;
std::string date_modification;
std::string label;
std::string description;
std::string type;
std::string accountancy_code_sell;
std::string accountancy_code_sell_export;
std::string fk_default_warehouse;
std::string price;
std::string stock_reel;
std::string seuil_stock_alerte;
std::string desiredstock;
};
struct ProductStock {
std::string id;
std::string product_id;
std::string quantity;
};
struct CreateProductStock {
std::string product_id;
std::string warehouse_id;
std::string qty;
};
struct Warehouse {
std::string id;
std::string label;
};
}
#endif //T_IOT_901_CONVOYOR_DOLIBARRMODELS_H

24
lib/GRBL/include/GRBL.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef GRBL_H
#define GRBL_H
#include <Arduino.h>
#include "Module_GRBL_13.2.h"
class iGRBL{
public:
virtual void init(int speed, double pas, int accel, String mode = "distance") = 0;
virtual void mouveForward(int mm) = 0;
virtual bool isIddle() = 0;
};
class GRBL : public iGRBL{
public:
GRBL(int grblAddr);
void init(int speed, double pas, int accel, String mode = "distance") override;
void mouveForward(int mm = 5) override;
bool isIddle() override;
private:
Module_GRBL* grbl;
};
#endif

44
lib/GRBL/src/GRBL.cpp Normal file
View File

@ -0,0 +1,44 @@
#include "../include/GRBL.h"
GRBL::GRBL(int grblAddr){
this->grbl = new Module_GRBL(grblAddr);
}
void GRBL::init(int speed, double pas, int accel, String mode){
char s[1024];
this->grbl->Init(&Wire);
this->grbl->setMode(mode);
sprintf(s,"$0=%f", pas); // step/mm
this->grbl->sendGcode(s);
Serial.println(s);
sprintf(s,"$4=%d", speed); // speed
this->grbl->sendGcode(s);
Serial.println(s);
sprintf(s,"$8=%d", accel); // acceleration, mm/sec^2
this->grbl->sendGcode(s);
Serial.println(s);
sprintf(s,"$3=%d", 500); // puse/µsec
this->grbl->sendGcode(s);
Serial.println(s);
}
void GRBL::mouveForward(int mm){
char s[1024];
sprintf(s, "G1 X%d", mm);
this->grbl->sendGcode(s);
}
bool GRBL::isIddle(){
bool sortie = false;
if(this->grbl->readStatus().indexOf("IDLE") != -1){
sortie = true;
}
return sortie;
}

224
lib/M5LCD/src/M5LCD.cpp Normal file
View File

@ -0,0 +1,224 @@
#include "M5LCD.h"
/*
* M5LCD classe
*/
M5LCD::M5LCD() : _current_page(0), _logs() , _debug_loc_y(0), _components_status({COMPONENT_KO, COMPONENT_KO, COMPONENT_KO, COMPONENT_KO, COMPONENT_KO}) {
this->_product_id = std::string("");
this->_product_label = std::string("");
this->_last_nfc = std::string("");
this->_servo_current_position = std::string("");
this->_dolibarr_msg = std::string("");
M5.begin();
M5.Power.begin();
M5.lcd.setBrightness(100);
this->update_page();
}
void M5LCD::update() {
M5.update();
if (M5.BtnB.wasReleased() != 0) {
this->_current_page = (this->_current_page + 1) % LCD_PAGES;
this->update_page();
}
if (this->_current_page == DEBUG_SCREEN && M5.BtnA.wasReleased() != 0 && this->_debug_loc_y < 0) {
this->_debug_loc_y++;
this->update_page();
}
if (this->_current_page == DEBUG_SCREEN && M5.BtnC.wasReleased() != 0) {
this->_debug_loc_y--;
this->update_page();
}
}
void M5LCD::update_page() const {
M5.Lcd.clear();
switch (this->_current_page) {
case 0:
this->show_dashboard();
break;
case 1:
this->show_debug();
break;
case 2:
this->show_config();
break;
}
this->update_pagination();
}
void M5LCD::display_error(const char *str) const {
M5.Lcd.setTextColor(WHITE, RED);
M5.Lcd.setTextSize(1);
M5.Lcd.setCursor(0, 40);
M5.Lcd.println(str);
}
void M5LCD::display_message(const char *str) const {
}
void M5LCD::display_warning(const char *str) const {
}
std::string get_status(AvailableComponentsStatus status) {
return status == COMPONENT_OK ? "OK" : "KO";
}
void draw_component_stats(int x, int y, int fx, int fy, int fw, int fh, const char *name, AvailableComponentsStatus status) {
M5.Lcd.setTextSize(2);
if (status == COMPONENT_OK) {
M5.Lcd.setTextColor(WHITE, GREEN);
} else {
M5.Lcd.setTextColor(WHITE, RED);
}
if (status == COMPONENT_OK) {
M5.Lcd.fillRect(fx, fy, fw, fh, GREEN);
} else {
M5.Lcd.fillRect(fx, fy, fw, fh, RED);
}
M5.Lcd.setCursor(x, y);
M5.Lcd.printf("%s %s", name, get_status(status).c_str());
}
void M5LCD::show_dashboard() const {
draw_component_stats(10, 18, 0, 0, 100, 50, "NFC", _components_status.nfc);
draw_component_stats(150, 18, 110, 0, 210, 50, "DOLIBARR", _components_status.dolibarr);
draw_component_stats(8, 78, 0, 60, 100, 50, "WIFI", _components_status.wifi);
draw_component_stats(112, 78, 110, 60, 100, 50, "SERVO", _components_status.servo);
draw_component_stats(230, 78, 220, 60, 100, 50, "GRBL", _components_status.grbl);
M5.Lcd.drawRect(0, 120, 320, 100, BLUE);
M5.Lcd.setTextColor(WHITE, BLACK);
M5.Lcd.setTextSize(2);
if (!this->_last_nfc.empty()) {
M5.Lcd.setCursor(10, 130);
M5.Lcd.printf("NFC: %s", this->_last_nfc.c_str());
}
if (!this->_product_id.empty() && !this->_product_label.empty()) {
M5.Lcd.setCursor(10, 150);
M5.Lcd.printf("Produit: %s - %s", this->_product_label.c_str(), this->_product_id.c_str());
}
if (!this->_dolibarr_msg.empty()) {
M5.Lcd.setCursor(10, 170);
M5.Lcd.printf("Produit: %s", this->_last_nfc.c_str());
}
if (!this->_servo_current_position.empty()) {
M5.Lcd.setCursor(10, 190);
M5.Lcd.printf("SERVO Posistion: %s", this->_servo_current_position.c_str());
}
M5.Lcd.setTextSize(1);
M5.Lcd.setCursor(0, 230);
M5.Lcd.printf("%s - %s", APP_TITLE, APP_VERSION);
}
void M5LCD::show_debug() const {
M5.Lcd.setTextColor(WHITE, BLACK);
M5.Lcd.setTextSize(1);
int i = 0;
for (auto val : this->_logs) {
M5.Lcd.setCursor(0, i + (this->_debug_loc_y * 10));
M5.Lcd.printf("[%s] - %s", val.get_datetime_format(), val.get_message().c_str());
i+=10;
}
}
void M5LCD::update_pagination() const {
M5.Lcd.setTextSize(1);
M5.Lcd.setTextColor(WHITE, BLACK);
M5.Lcd.setCursor(302, 230);
M5.Lcd.printf("%d/%d", this->_current_page+1, LCD_PAGES);
}
void M5LCD::add_log(const char* str) {
this->_logs.emplace_back(str);
if (this->_current_page == DEBUG_SCREEN) {
this->show_debug();
}
}
void M5LCD::show_config() const {
}
ComponentsStatus M5LCD::get_components() {
return this->_components_status;
}
void M5LCD::set_wifi_status(AvailableComponentsStatus status) {
this->_components_status.wifi = status;
this->update_dashboard();
}
void M5LCD::set_nfc_status(AvailableComponentsStatus status) {
this->_components_status.nfc = status;
this->update_dashboard();
}
void M5LCD::set_grbl_status(AvailableComponentsStatus status) {
this->_components_status.grbl = status;
this->update_dashboard();
}
void M5LCD::set_servo(AvailableComponentsStatus status) {
this->_components_status.servo = status;
this->update_dashboard();
}
void M5LCD::set_dolibarr_status(AvailableComponentsStatus status) {
this->_components_status.dolibarr = status;
this->update_dashboard();
}
void M5LCD::update_dashboard() const {
if (this->_current_page == DASHBOARD_SCREEN) {
this->show_dashboard();
}
}
void M5LCD::set_dolibarr_message(std::string str) {
this->_dolibarr_msg = str;
this->update_dashboard();
}
void M5LCD::set_nfc_message(std::string str) {
this->_last_nfc = str;
this->update_dashboard();
}
void M5LCD::set_product_id(std::string str) {
this->_product_id = str;
this->update_dashboard();
}
void M5LCD::set_servo_message(std::string str) {
this->_servo_current_position = str;
this->update_dashboard();
}
void M5LCD::set_product_label(std::string str) {
this->_product_label = str;
this->update_dashboard();
}
/*
* LogMessage classe
*/
LogMessage::LogMessage(std::string log) {
this->log = log;
this->datetime = time(nullptr);
}
std::string LogMessage::get_message() const {
return this->log;
}
const char *LogMessage::get_datetime_format() const {
void *buff = malloc(20 * sizeof(char));
strftime((char*) buff, 20, "%H:%M:%S", localtime(&this->datetime));
return (char*) buff;
}

84
lib/M5LCD/src/M5LCD.h Normal file
View File

@ -0,0 +1,84 @@
#ifndef T_IOT_901_CONVOYOR_M5LCD_H
#define T_IOT_901_CONVOYOR_M5LCD_H
#include <vector>
#include <ctime>
#include "M5Stack.h"
#define LCD_PAGES 3
#define DASHBOARD_SCREEN 0
#define DEBUG_SCREEN 1
#define CONFIG_SCREEN 2
enum AvailableComponentsStatus {
COMPONENT_OK,
COMPONENT_KO,
COMPONENT_MISSING,
UNKNOWN_ERROR,
};
typedef struct ComponentsStatus {
AvailableComponentsStatus nfc;
AvailableComponentsStatus wifi;
AvailableComponentsStatus dolibarr;
AvailableComponentsStatus servo;
AvailableComponentsStatus grbl;
} ComponentsStatus;
typedef struct MessageToShow {
const char* message;
int color;
} MessageToShow;
class LogMessage {
public:
LogMessage(std::string log);
std::string get_message() const;
const char* get_datetime_format() const;
private:
time_t datetime;
std::string log;
};
class M5LCD {
public:
M5LCD();
void display_message(const char* str) const;
void display_error(const char* str) const;
void display_warning(const char* str) const;
void add_log(const char *str);
void update();
ComponentsStatus get_components();
void set_wifi_status(AvailableComponentsStatus status);
void set_nfc_status(AvailableComponentsStatus status);
void set_grbl_status(AvailableComponentsStatus status);
void set_servo(AvailableComponentsStatus status);
void set_dolibarr_status(AvailableComponentsStatus status);
void set_nfc_message(std::string str);
void set_dolibarr_message(std::string str);
void set_product_label(std::string str);
void set_product_id(std::string str);
void set_servo_message(std::string str);
int _current_page;
private:
void update_page() const;
void show_debug() const;
void show_dashboard() const;
void show_config() const;
void update_pagination() const;
void update_dashboard() const;
int _debug_loc_y;
std::vector<LogMessage> _logs;
ComponentsStatus _components_status;
std::string _last_nfc;
std::string _product_label;
std::string _product_id;
std::string _dolibarr_msg;
std::string _servo_current_position;
};
inline M5LCD *lcdScreen;
#endif //T_IOT_901_CONVOYOR_M5LCD_H

2059
lib/NFC/src/MFRC522_I2C.cpp Normal file

File diff suppressed because it is too large Load Diff

472
lib/NFC/src/MFRC522_I2C.h Normal file
View File

@ -0,0 +1,472 @@
/**
* MFRC522_I2C.h - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS
*I2C BY AROZCAN MFRC522_I2C.h - Based on ARDUINO RFID MODULE KIT 13.56 MHZ WITH
*TAGS SPI Library BY COOQROBOT. Based on code Dr.Leong ( WWW.B2CQSHOP.COM )
* Created by Miguel Balboa (circuitito.com), Jan, 2012.
* Rewritten by Søren Thing Andersen (access.thing.dk), fall of 2013
*(Translation to English, refactored, comments, anti collision, cascade
*levels.) Extended by Tom Clement with functionality to write to sector 0 of
*UID changeable Mifare cards. Extended by Ahmet Remzi Ozcan with I2C
*functionality. Author: arozcan @
*https://github.com/arozcan/MFRC522-I2C-Library Released into the public
*domain.
*
* Please read this file for an overview and then MFRC522.cpp for comments on
*the specific functions. Search for "mf-rc522" on ebay.com to purchase the
*MF-RC522 board.
*
* There are three hardware components involved:
* 1) The micro controller: An Arduino
* 2) The PCD (short for Proximity Coupling Device): NXP MFRC522 Contactless
*Reader IC 3) The PICC (short for Proximity Integrated Circuit Card): A card or
*tag using the ISO 14443A interface, eg Mifare or NTAG203.
*
* The microcontroller and card reader uses I2C for communication.
* The protocol is described in the MFRC522 datasheet:
*http://www.nxp.com/documents/data_sheet/MFRC522.pdf
*
* The card reader and the tags communicate using a 13.56MHz electromagnetic
*field. The protocol is defined in ISO/IEC 14443-3 Identification cards --
*Contactless integrated circuit cards -- Proximity cards -- Part 3:
*Initialization and anticollision". A free version of the final draft can be
*found at http://wg8.de/wg8n1496_17n3613_Ballot_FCD14443-3.pdf Details are
*found in chapter 6, Type A Initialization and anticollision.
*
* If only the PICC UID is wanted, the above documents has all the needed
*information. To read and write from MIFARE PICCs, the MIFARE protocol is used
*after the PICC has been selected. The MIFARE Classic chips and protocol is
*described in the datasheets: 1K:
*http://www.nxp.com/documents/data_sheet/MF1S503x.pdf 4K:
*http://www.nxp.com/documents/data_sheet/MF1S703x.pdf Mini:
*http://www.idcardmarket.com/download/mifare_S20_datasheet.pdf The MIFARE
*Ultralight chip and protocol is described in the datasheets: Ultralight:
*http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf Ultralight C:
*http://www.nxp.com/documents/short_data_sheet/MF0ICU2_SDS.pdf
*
* MIFARE Classic 1K (MF1S503x):
* Has 16 sectors * 4 blocks/sector * 16 bytes/block = 1024 bytes.
* The blocks are numbered 0-63.
* Block 3 in each sector is the Sector Trailer. See
*http://www.nxp.com/documents/data_sheet/MF1S503x.pdf sections 8.6 and 8.7:
* Bytes 0-5: Key A
* Bytes 6-8: Access Bits
* Bytes 9: User data
* Bytes 10-15: Key B (or user data)
* Block 0 is read-only manufacturer data.
* To access a block, an authentication using a key from the block's sector
*must be performed first. Example: To read from block 10, first authenticate
*using a key from sector 3 (blocks 8-11). All keys are set to FFFFFFFFFFFFh at
*chip delivery. Warning: Please read section 8.7 "Memory Access". It includes
*this text: if the PICC detects a format violation the whole sector is
*irreversibly blocked. To use a block in "value block" mode (for
*Increment/Decrement operations) you need to change the sector trailer. Use
*PICC_SetAccessBits() to calculate the bit patterns. MIFARE Classic 4K
*(MF1S703x): Has (32 sectors * 4 blocks/sector + 8 sectors * 16 blocks/sector)
** 16 bytes/block = 4096 bytes. The blocks are numbered 0-255. The last block
*in each sector is the Sector Trailer like above. MIFARE Classic Mini (MF1 IC
*S20): Has 5 sectors * 4 blocks/sector * 16 bytes/block = 320 bytes. The blocks
*are numbered 0-19. The last block in each sector is the Sector Trailer like
*above.
*
* MIFARE Ultralight (MF0ICU1):
* Has 16 pages of 4 bytes = 64 bytes.
* Pages 0 + 1 is used for the 7-byte UID.
* Page 2 contains the last check digit for the UID, one byte manufacturer
*internal data, and the lock bytes (see
*http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf section 8.5.2) Page 3 is
*OTP, One Time Programmable bits. Once set to 1 they cannot revert to 0. Pages
*4-15 are read/write unless blocked by the lock bytes in page 2. MIFARE
*Ultralight C (MF0ICU2): Has 48 pages of 4 bytes = 192 bytes. Pages 0 + 1 is
*used for the 7-byte UID. Page 2 contains the last check digit for the UID, one
*byte manufacturer internal data, and the lock bytes (see
*http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf section 8.5.2) Page 3 is
*OTP, One Time Programmable bits. Once set to 1 they cannot revert to 0. Pages
*4-39 are read/write unless blocked by the lock bytes in page 2. Page 40 Lock
*bytes Page 41 16 bit one way counter Pages 42-43 Authentication configuration
* Pages 44-47 Authentication key
*/
#ifndef MFRC522_h
#define MFRC522_h
#include <Arduino.h>
#include <Wire.h>
// Firmware data for self-test
// Reference values based on firmware version
// Hint: if needed, you can remove unused self-test data to save flash memory
//
// Version 0.0 (0x90)
// Philips Semiconductors; Preliminary Specification Revision 2.0 - 01 August
// 2005; 16.1 Sefttest
const byte MFRC522_firmware_referenceV0_0[] PROGMEM = {
0x00, 0x87, 0x98, 0x0f, 0x49, 0xFF, 0x07, 0x19, 0xBF, 0x22, 0x30,
0x49, 0x59, 0x63, 0xAD, 0xCA, 0x7F, 0xE3, 0x4E, 0x03, 0x5C, 0x4E,
0x49, 0x50, 0x47, 0x9A, 0x37, 0x61, 0xE7, 0xE2, 0xC6, 0x2E, 0x75,
0x5A, 0xED, 0x04, 0x3D, 0x02, 0x4B, 0x78, 0x32, 0xFF, 0x58, 0x3B,
0x7C, 0xE9, 0x00, 0x94, 0xB4, 0x4A, 0x59, 0x5B, 0xFD, 0xC9, 0x29,
0xDF, 0x35, 0x96, 0x98, 0x9E, 0x4F, 0x30, 0x32, 0x8D};
// Version 1.0 (0x91)
// NXP Semiconductors; Rev. 3.8 - 17 September 2014; 16.1.1 Self test
const byte MFRC522_firmware_referenceV1_0[] PROGMEM = {
0x00, 0xC6, 0x37, 0xD5, 0x32, 0xB7, 0x57, 0x5C, 0xC2, 0xD8, 0x7C,
0x4D, 0xD9, 0x70, 0xC7, 0x73, 0x10, 0xE6, 0xD2, 0xAA, 0x5E, 0xA1,
0x3E, 0x5A, 0x14, 0xAF, 0x30, 0x61, 0xC9, 0x70, 0xDB, 0x2E, 0x64,
0x22, 0x72, 0xB5, 0xBD, 0x65, 0xF4, 0xEC, 0x22, 0xBC, 0xD3, 0x72,
0x35, 0xCD, 0xAA, 0x41, 0x1F, 0xA7, 0xF3, 0x53, 0x14, 0xDE, 0x7E,
0x02, 0xD9, 0x0F, 0xB5, 0x5E, 0x25, 0x1D, 0x29, 0x79};
// Version 2.0 (0x92)
// NXP Semiconductors; Rev. 3.8 - 17 September 2014; 16.1.1 Self test
const byte MFRC522_firmware_referenceV2_0[] PROGMEM = {
0x00, 0xEB, 0x66, 0xBA, 0x57, 0xBF, 0x23, 0x95, 0xD0, 0xE3, 0x0D,
0x3D, 0x27, 0x89, 0x5C, 0xDE, 0x9D, 0x3B, 0xA7, 0x00, 0x21, 0x5B,
0x89, 0x82, 0x51, 0x3A, 0xEB, 0x02, 0x0C, 0xA5, 0x00, 0x49, 0x7C,
0x84, 0x4D, 0xB3, 0xCC, 0xD2, 0x1B, 0x81, 0x5D, 0x48, 0x76, 0xD5,
0x71, 0x61, 0x21, 0xA9, 0x86, 0x96, 0x83, 0x38, 0xCF, 0x9D, 0x5B,
0x6D, 0xDC, 0x15, 0xBA, 0x3E, 0x7D, 0x95, 0x3B, 0x2F};
// Clone
// Fudan Semiconductor FM17522 (0x88)
const byte FM17522_firmware_reference[] PROGMEM = {
0x00, 0xD6, 0x78, 0x8C, 0xE2, 0xAA, 0x0C, 0x18, 0x2A, 0xB8, 0x7A,
0x7F, 0xD3, 0x6A, 0xCF, 0x0B, 0xB1, 0x37, 0x63, 0x4B, 0x69, 0xAE,
0x91, 0xC7, 0xC3, 0x97, 0xAE, 0x77, 0xF4, 0x37, 0xD7, 0x9B, 0x7C,
0xF5, 0x3C, 0x11, 0x8F, 0x15, 0xC3, 0xD7, 0xC1, 0x5B, 0x00, 0x2A,
0xD0, 0x75, 0xDE, 0x9E, 0x51, 0x64, 0xAB, 0x3E, 0xE9, 0x15, 0xB5,
0xAB, 0x56, 0x9A, 0x98, 0x82, 0x26, 0xEA, 0x2A, 0x62};
class MFRC522 {
public:
// MFRC522 registers. Described in chapter 9 of the datasheet.
enum PCD_Register {
// Page 0: Command and status
// 0x00 // reserved for future use
CommandReg = 0x01, // starts and stops command execution
ComIEnReg = 0x02, // enable and disable interrupt request control bits
DivIEnReg = 0x03, // enable and disable interrupt request control bits
ComIrqReg = 0x04, // interrupt request bits
DivIrqReg = 0x05, // interrupt request bits
ErrorReg = 0x06, // error bits showing the error status of the last
// command executed
Status1Reg = 0x07, // communication status bits
Status2Reg = 0x08, // receiver and transmitter status bits
FIFODataReg = 0x09, // input and output of 64 byte FIFO buffer
FIFOLevelReg = 0x0A, // number of bytes stored in the FIFO buffer
WaterLevelReg = 0x0B, // level for FIFO underflow and overflow warning
ControlReg = 0x0C, // miscellaneous control registers
BitFramingReg = 0x0D, // adjustments for bit-oriented frames
CollReg = 0x0E, // bit position of the first bit-collision detected on
// the RF interface
// 0x0F // reserved for future use
// Page 1: Command
// 0x10 // reserved for future use
ModeReg = 0x11, // defines general modes for transmitting and receiving
TxModeReg = 0x12, // defines transmission data rate and framing
RxModeReg = 0x13, // defines reception data rate and framing
TxControlReg = 0x14, // controls the logical behavior of the antenna
// driver pins TX1 and TX2
TxASKReg = 0x15, // controls the setting of the transmission modulation
TxSelReg = 0x16, // selects the internal sources for the antenna driver
RxSelReg = 0x17, // selects internal receiver settings
RxThresholdReg = 0x18, // selects thresholds for the bit decoder
DemodReg = 0x19, // defines demodulator settings
// 0x1A // reserved for future use
// 0x1B // reserved for future use
MfTxReg =
0x1C, // controls some MIFARE communication transmit parameters
MfRxReg =
0x1D, // controls some MIFARE communication receive parameters
// 0x1E // reserved for future use
SerialSpeedReg =
0x1F, // selects the speed of the serial UART interface
// Page 2: Configuration
// 0x20 // reserved for future use
CRCResultRegH =
0x21, // shows the MSB and LSB values of the CRC calculation
CRCResultRegL = 0x22,
// 0x23 // reserved for future use
ModWidthReg = 0x24, // controls the ModWidth setting?
// 0x25 // reserved for future use
RFCfgReg = 0x26, // configures the receiver gain
GsNReg = 0x27, // selects the conductance of the antenna driver pins
// TX1 and TX2 for modulation
CWGsPReg = 0x28, // defines the conductance of the p-driver output
// during periods of no modulation
ModGsPReg = 0x29, // defines the conductance of the p-driver output
// during periods of modulation
TModeReg = 0x2A, // defines settings for the internal timer
TPrescalerReg = 0x2B, // the lower 8 bits of the TPrescaler value. The
// 4 high bits are in TModeReg.
TReloadRegH = 0x2C, // defines the 16-bit timer reload value
TReloadRegL = 0x2D,
TCounterValueRegH = 0x2E, // shows the 16-bit timer value
TCounterValueRegL = 0x2F,
// Page 3: Test Registers
// 0x30 // reserved for future use
TestSel1Reg = 0x31, // general test signal configuration
TestSel2Reg = 0x32, // general test signal configuration
TestPinEnReg = 0x33, // enables pin output driver on pins D1 to D7
TestPinValueReg = 0x34, // defines the values for D1 to D7 when it is
// used as an I/O bus
TestBusReg = 0x35, // shows the status of the internal test bus
AutoTestReg = 0x36, // controls the digital self test
VersionReg = 0x37, // shows the software version
AnalogTestReg = 0x38, // controls the pins AUX1 and AUX2
TestDAC1Reg = 0x39, // defines the test value for TestDAC1
TestDAC2Reg = 0x3A, // defines the test value for TestDAC2
TestADCReg = 0x3B // shows the value of ADC I and Q channels
// 0x3C // reserved for production tests
// 0x3D // reserved for production tests
// 0x3E // reserved for production tests
// 0x3F // reserved for production tests
};
// MFRC522 commands. Described in chapter 10 of the datasheet.
enum PCD_Command {
PCD_Idle = 0x00, // no action, cancels current command execution
PCD_Mem = 0x01, // stores 25 bytes into the internal buffer
PCD_GenerateRandomID = 0x02, // generates a 10-byte random ID number
PCD_CalcCRC =
0x03, // activates the CRC coprocessor or performs a self test
PCD_Transmit = 0x04, // transmits data from the FIFO buffer
PCD_NoCmdChange = 0x07, // no command change, can be used to modify the
// CommandReg register bits without affecting
// the command, for example, the PowerDown bit
PCD_Receive = 0x08, // activates the receiver circuits
PCD_Transceive =
0x0C, // transmits data from FIFO buffer to antenna and
// automatically activates the receiver after transmission
PCD_MFAuthent =
0x0E, // performs the MIFARE standard authentication as a reader
PCD_SoftReset = 0x0F // resets the MFRC522
};
// MFRC522 RxGain[2:0] masks, defines the receiver's signal voltage gain
// factor (on the PCD). Described in 9.3.3.6 / table 98 of the datasheet at
// http://www.nxp.com/documents/data_sheet/MFRC522.pdf
enum PCD_RxGain {
RxGain_18dB = 0x00 << 4, // 000b - 18 dB, minimum
RxGain_23dB = 0x01 << 4, // 001b - 23 dB
RxGain_18dB_2 =
0x02 << 4, // 010b - 18 dB, it seems 010b is a duplicate for 000b
RxGain_23dB_2 =
0x03 << 4, // 011b - 23 dB, it seems 011b is a duplicate for 001b
RxGain_33dB = 0x04 << 4, // 100b - 33 dB, average, and typical default
RxGain_38dB = 0x05 << 4, // 101b - 38 dB
RxGain_43dB = 0x06 << 4, // 110b - 43 dB
RxGain_48dB = 0x07 << 4, // 111b - 48 dB, maximum
RxGain_min =
0x00 << 4, // 000b - 18 dB, minimum, convenience for RxGain_18dB
RxGain_avg =
0x04 << 4, // 100b - 33 dB, average, convenience for RxGain_33dB
RxGain_max =
0x07 << 4 // 111b - 48 dB, maximum, convenience for RxGain_48dB
};
// Commands sent to the PICC.
enum PICC_Command {
// The commands used by the PCD to manage communication with several
// PICCs (ISO 14443-3, Type A, section 6.4)
PICC_CMD_REQA = 0x26, // REQuest command, Type A. Invites PICCs in
// state IDLE to go to READY and prepare for
// anticollision or selection. 7 bit frame.
PICC_CMD_WUPA =
0x52, // Wake-UP command, Type A. Invites PICCs in state IDLE and
// HALT to go to READY(*) and prepare for anticollision or
// selection. 7 bit frame.
PICC_CMD_CT = 0x88, // Cascade Tag. Not really a command, but used
// during anti collision.
PICC_CMD_SEL_CL1 = 0x93, // Anti collision/Select, Cascade Level 1
PICC_CMD_SEL_CL2 = 0x95, // Anti collision/Select, Cascade Level 2
PICC_CMD_SEL_CL3 = 0x97, // Anti collision/Select, Cascade Level 3
PICC_CMD_HLTA = 0x50, // HaLT command, Type A. Instructs an ACTIVE PICC
// to go to state HALT.
// The commands used for MIFARE Classic (from
// http://www.nxp.com/documents/data_sheet/MF1S503x.pdf, Section 9)
// Use PCD_MFAuthent to authenticate access to a sector, then use these
// commands to read/write/modify the blocks on the sector.
// The read/write commands can also be used for MIFARE Ultralight.
PICC_CMD_MF_AUTH_KEY_A = 0x60, // Perform authentication with Key A
PICC_CMD_MF_AUTH_KEY_B = 0x61, // Perform authentication with Key B
PICC_CMD_MF_READ =
0x30, // Reads one 16 byte block from the authenticated sector of
// the PICC. Also used for MIFARE Ultralight.
PICC_CMD_MF_WRITE =
0xA0, // Writes one 16 byte block to the authenticated sector of
// the PICC. Called "COMPATIBILITY WRITE" for MIFARE
// Ultralight.
PICC_CMD_MF_DECREMENT =
0xC0, // Decrements the contents of a block and stores the result
// in the internal data register.
PICC_CMD_MF_INCREMENT =
0xC1, // Increments the contents of a block and stores the result
// in the internal data register.
PICC_CMD_MF_RESTORE = 0xC2, // Reads the contents of a block into the
// internal data register.
PICC_CMD_MF_TRANSFER = 0xB0, // Writes the contents of the internal
// data register to a block.
// The commands used for MIFARE Ultralight (from
// http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf, Section 8.6)
// The PICC_CMD_MF_READ and PICC_CMD_MF_WRITE can also be used for
// MIFARE Ultralight.
PICC_CMD_UL_WRITE = 0xA2 // Writes one 4 byte page to the PICC.
};
// MIFARE constants that does not fit anywhere else
enum MIFARE_Misc {
MF_ACK = 0xA, // The MIFARE Classic uses a 4 bit ACK/NAK. Any other
// value than 0xA is NAK.
MF_KEY_SIZE = 6 // A Mifare Crypto1 key is 6 bytes.
};
// PICC types we can detect. Remember to update PICC_GetTypeName() if you
// add more.
enum PICC_Type {
PICC_TYPE_UNKNOWN = 0,
PICC_TYPE_ISO_14443_4 = 1, // PICC compliant with ISO/IEC 14443-4
PICC_TYPE_ISO_18092 = 2, // PICC compliant with ISO/IEC 18092 (NFC)
PICC_TYPE_MIFARE_MINI = 3, // MIFARE Classic protocol, 320 bytes
PICC_TYPE_MIFARE_1K = 4, // MIFARE Classic protocol, 1KB
PICC_TYPE_MIFARE_4K = 5, // MIFARE Classic protocol, 4KB
PICC_TYPE_MIFARE_UL = 6, // MIFARE Ultralight or Ultralight C
PICC_TYPE_MIFARE_PLUS = 7, // MIFARE Plus
PICC_TYPE_TNP3XXX = 8, // Only mentioned in NXP AN 10833 MIFARE Type
// Identification Procedure
PICC_TYPE_NOT_COMPLETE = 255 // SAK indicates UID is not complete.
};
// Return codes from the functions in this class. Remember to update
// GetStatusCodeName() if you add more.
enum StatusCode {
STATUS_OK = 1, // Success
STATUS_ERROR = 2, // Error in communication
STATUS_COLLISION = 3, // Collission detected
STATUS_TIMEOUT = 4, // Timeout in communication.
STATUS_NO_ROOM = 5, // A buffer is not big enough.
STATUS_INTERNAL_ERROR =
6, // Internal error in the code. Should not happen ;-)
STATUS_INVALID = 7, // Invalid argument.
STATUS_CRC_WRONG = 8, // The CRC_A does not match
STATUS_MIFARE_NACK = 9 // A MIFARE PICC responded with NAK.
};
// A struct used for passing the UID of a PICC.
typedef struct {
byte size; // Number of bytes in the UID. 4, 7 or 10.
byte uidByte[10];
byte sak; // The SAK (Select acknowledge) byte returned from the PICC
// after successful selection.
} Uid;
// A struct used for passing a MIFARE Crypto1 key
typedef struct {
byte keyByte[MF_KEY_SIZE];
} MIFARE_Key;
// Member variables
Uid uid; // Used by PICC_ReadCardSerial().
// Size of the MFRC522 FIFO
static const byte FIFO_SIZE = 64; // The FIFO is 64 bytes.
/////////////////////////////////////////////////////////////////////////////////////
// Functions for setting up the Arduino
/////////////////////////////////////////////////////////////////////////////////////
MFRC522(byte chipAddress);
/////////////////////////////////////////////////////////////////////////////////////
// Basic interface functions for communicating with the MFRC522
/////////////////////////////////////////////////////////////////////////////////////
void PCD_WriteRegister(byte reg, byte value);
void PCD_WriteRegister(byte reg, byte count, byte *values);
byte PCD_ReadRegister(byte reg);
void PCD_ReadRegister(byte reg, byte count, byte *values, byte rxAlign = 0);
void setBitMask(unsigned char reg, unsigned char mask);
void PCD_SetRegisterBitMask(byte reg, byte mask);
void PCD_ClearRegisterBitMask(byte reg, byte mask);
byte PCD_CalculateCRC(byte *data, byte length, byte *result);
/////////////////////////////////////////////////////////////////////////////////////
// Functions for manipulating the MFRC522
/////////////////////////////////////////////////////////////////////////////////////
void PCD_Init();
void PCD_Reset();
void PCD_AntennaOn();
void PCD_AntennaOff();
byte PCD_GetAntennaGain();
void PCD_SetAntennaGain(byte mask);
bool PCD_PerformSelfTest();
/////////////////////////////////////////////////////////////////////////////////////
// Functions for communicating with PICCs
/////////////////////////////////////////////////////////////////////////////////////
byte PCD_TransceiveData(byte *sendData, byte sendLen, byte *backData,
byte *backLen, byte *validBits = NULL,
byte rxAlign = 0, bool checkCRC = false);
byte PCD_CommunicateWithPICC(byte command, byte waitIRq, byte *sendData,
byte sendLen, byte *backData = NULL,
byte *backLen = NULL, byte *validBits = NULL,
byte rxAlign = 0, bool checkCRC = false);
byte PICC_RequestA(byte *bufferATQA, byte *bufferSize);
byte PICC_WakeupA(byte *bufferATQA, byte *bufferSize);
byte PICC_REQA_or_WUPA(byte command, byte *bufferATQA, byte *bufferSize);
byte PICC_Select(Uid *uid, byte validBits = 0);
byte PICC_HaltA();
/////////////////////////////////////////////////////////////////////////////////////
// Functions for communicating with MIFARE PICCs
/////////////////////////////////////////////////////////////////////////////////////
byte PCD_Authenticate(byte command, byte blockAddr, MIFARE_Key *key,
Uid *uid);
void PCD_StopCrypto1();
byte MIFARE_Read(byte blockAddr, byte *buffer, byte *bufferSize);
byte MIFARE_Write(byte blockAddr, byte *buffer, byte bufferSize);
byte MIFARE_Decrement(byte blockAddr, long delta);
byte MIFARE_Increment(byte blockAddr, long delta);
byte MIFARE_Restore(byte blockAddr);
byte MIFARE_Transfer(byte blockAddr);
byte MIFARE_Ultralight_Write(byte page, byte *buffer, byte bufferSize);
byte MIFARE_GetValue(byte blockAddr, long *value);
byte MIFARE_SetValue(byte blockAddr, long value);
/////////////////////////////////////////////////////////////////////////////////////
// Support functions
/////////////////////////////////////////////////////////////////////////////////////
byte PCD_MIFARE_Transceive(byte *sendData, byte sendLen,
bool acceptTimeout = false);
// old function used too much memory, now name moved to flash; if you need
// char, copy from flash to memory
// const char *GetStatusCodeName(byte code);
const __FlashStringHelper *GetStatusCodeName(byte code);
byte PICC_GetType(byte sak);
// old function used too much memory, now name moved to flash; if you need
// char, copy from flash to memory
// const char *PICC_GetTypeName(byte type);
const __FlashStringHelper *PICC_GetTypeName(byte type);
void PICC_DumpToSerial(Uid *uid);
void PICC_DumpMifareClassicToSerial(Uid *uid, byte piccType,
MIFARE_Key *key);
void PICC_DumpMifareClassicSectorToSerial(Uid *uid, MIFARE_Key *key,
byte sector);
void PICC_DumpMifareUltralightToSerial();
void MIFARE_SetAccessBits(byte *accessBitBuffer, byte g0, byte g1, byte g2,
byte g3);
bool MIFARE_OpenUidBackdoor(bool logErrors);
bool MIFARE_SetUid(byte *newUid, byte uidSize, bool logErrors);
bool MIFARE_UnbrickUidSector(bool logErrors);
/////////////////////////////////////////////////////////////////////////////////////
// Convenience functions - does not add extra functionality
/////////////////////////////////////////////////////////////////////////////////////
bool PICC_IsNewCardPresent();
bool PICC_ReadCardSerial();
private:
byte _chipAddress;
byte _resetPowerDownPin; // Arduino pin connected to MFRC522's reset and
// power down input (Pin 6, NRSTPD, active low)
byte MIFARE_TwoStepHelper(byte command, byte blockAddr, long data);
};
#endif

32
lib/NFC/src/NfcReader.cpp Normal file
View File

@ -0,0 +1,32 @@
#include "NfcReader.h"
NfcReader::NfcReader(int i2c_adress)
{
this->mfrc522 = new MFRC522(i2c_adress);
this->mfrc522->PCD_Init();
}
String NfcReader::ReadNfc()
{
this->uid.clear();
if (!this->mfrc522->PICC_IsNewCardPresent() ||
!this->mfrc522->PICC_ReadCardSerial()) {
return "0";
}
for (unsigned int i = 0; i < this->mfrc522->uid.size; i++) {
if (this->mfrc522->uid.uidByte[i] < 0xF) {
this->uid += '0';
this->uid += String(this->mfrc522->uid.uidByte[i], HEX);
} else {
this->uid += String(this->mfrc522->uid.uidByte[i], HEX);
}
}
return (this->uid);
}
bool NfcReader::IsNfcConnected()
{
Wire.beginTransmission(NFC_ADDR);
byte error = Wire.endTransmission();
return error == 0;
}

22
lib/NFC/src/NfcReader.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef NFCREADER_H
#define NFCREADER_H
#include <M5Stack.h>
#include "MFRC522_I2C.h"
#include <string>
class NfcReader {
public:
NfcReader(int i2c_adress);
~NfcReader() = default;
bool IsNfcConnected();
String ReadNfc();
protected:
private:
MFRC522 *mfrc522;
String uid;
};
#endif /* !NFCREADER_H */

View File

@ -0,0 +1,67 @@
#ifndef BIG_NFC_READER_H
#define BIG_NFC_READER_H
#include <Arduino.h>
#include <vector>
#include "TrameList.h"
class BigNfcReader{
public:
BigNfcReader();
/**
* @brief initialise le lecteur NFC
*
* @return true le lecteur NFC est initialisé
* @return false le lecteur NFC n'est pas initialisé (erreur)
*/
bool init();
/**
* @brief rafraichit les données du lecteur NFC
*
*/
void refresh();
/**
* @brief affiche la dernière trame lue
*
*/
void printTrame();
/**
* @brief retourne le nombre de tags lus
*
* @return int nombre de tags lus
*/
int getNbTags();
private:
/**
* @brief convertit un nombre en hexadécimal (a 2 chiffres)
*
* @param number nombre à convertir
* @return String nombre converti
*/
String digitify(int number);
/**
* @brief variable pair/impair pour le type de trame
*
*/
bool pair;
/**
* @brief dernière trame lue
*
*/
std::vector<byte>* trame;
};
#endif

View File

@ -0,0 +1,29 @@
#ifndef TRAM_LIST_H
#define TRAM_LIST_H
#include <Arduino.h>
#include <vector>
const std::vector<byte> SEARCH_TRAM_0 = {0x05, 0x07, 0x01, 0x01, 0x01, 0x00, 0xEB, 0x5F};
const std::vector<byte> INIT_TRAM_0 = {0xFA, 0x05, 0x01, 0xC0, 0x5A, 0xDF};
const std::vector<byte> INIT_TRAM_1 = {0xFA, 0x08, 0x01, 0x00, 0x01, 0x01, 0x01, 0xE1, 0x70};
const std::vector<byte> INIT_TRAM_2 = {0xFA, 0x08, 0x01, 0x40, 0x01, 0x02, 0x01, 0x3E, 0x4C};
const std::vector<byte> INIT_TRAM_3 = {0xFA, 0x08, 0x01, 0x00, 0x01, 0x03, 0x01, 0x51, 0x43};
const std::vector<byte> INIT_TRAM_4 = {0xFA, 0x08, 0x01, 0x40, 0x01, 0x04, 0x01, 0xEE, 0x18};
const std::vector<byte> INIT_TRAM_5 = {0xFA, 0x08, 0x01, 0x00, 0x01, 0x05, 0x01, 0x81, 0x17};
const std::vector<byte> INIT_TRAM_6 = {0xFA, 0x08, 0x01, 0x40, 0x01, 0x06, 0x01, 0x5E, 0x2B};
const std::vector<byte> INIT_TRAM_7 = {0xFA, 0x08, 0x01, 0x00, 0x01, 0x07, 0x01, 0x31, 0x24};
const std::vector<byte> REP_TRAM_0 = {0xFA, 0x05, 0x01, 0xE0, 0x58, 0xFE};
const std::vector<byte> REP_TRAM_1 = {0xFA, 0x17, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x04, 0x00, 0x00, 0x03, 0x01, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x8A};
const std::vector<byte> REP_TRAM_2 = {0xFA, 0x17, 0x01, 0x40, 0x01, 0x00, 0x00, 0x01, 0x00, 0x09, 0x00, 0xFF, 0x00, 0x10, 0x07, 0x13, 0x01, 0x0E, 0x08, 0x09, 0x0B, 0x00, 0x2D, 0x98};
const std::vector<byte> REP_TRAM_3 = {0xFA, 0x17, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xE8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x43, 0x83, 0x00, 0x00, 0x00, 0x9A, 0xBF};
const std::vector<byte> REP_TRAM_4 = {0xFA, 0x17, 0x01, 0x40, 0x01, 0x00, 0x00, 0x01, 0x04, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD7, 0x15};
const std::vector<byte> REP_TRAM_5 = {0xFA, 0x17, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0A, 0x03, 0x0A, 0x00, 0xF6, 0xCD};
const std::vector<byte> REP_TRAM_6 = {0xFA, 0x17, 0x01, 0x40, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0xD4, 0x03};
const std::vector<byte> REP_TRAM_7 = {0xFA, 0x17, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0xF6};
const std::vector<byte> READ_TRAM_0 = {0xFA, 0x24, 0x01, 0x00, 0x31, 0x02, 0x07, 0x0E, 0x00, 0x00, 0x04, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0xFF, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x5D, 0x74};
const std::vector<byte> READ_TRAM_1 = {0xFA, 0x24, 0x01, 0x40, 0x31, 0x02, 0x07, 0x0E, 0x00, 0x00, 0x04, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0xFF, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x10, 0x45};
#endif

View File

@ -0,0 +1,75 @@
#include "../include/BigNfcReader.h"
BigNfcReader::BigNfcReader(){
Serial2.begin(115200, SERIAL_8N1, 16, 17);//TODO: mettre le port série en paramètre
this->pair = true;
this->trame = new std::vector<byte>();
}
bool BigNfcReader::init(){
const std::vector<std::vector<byte>> INIT_TRAMES = {INIT_TRAM_0, INIT_TRAM_1, INIT_TRAM_2, INIT_TRAM_3, INIT_TRAM_4, INIT_TRAM_5, INIT_TRAM_6, INIT_TRAM_7};
const std::vector<std::vector<byte>> REP_TRAMES = {REP_TRAM_0, REP_TRAM_1, REP_TRAM_2, REP_TRAM_3, REP_TRAM_4, REP_TRAM_5, REP_TRAM_6, REP_TRAM_7};
int repnb = 0;
for(std::vector<byte> i: INIT_TRAMES){
for(byte j: i){
Serial2.write(j);
}
while (Serial2.available() == 0);
while (Serial2.available() > 0){
for(byte j: REP_TRAMES[repnb]){
if(Serial2.read() != j){
Serial.println("NFC reader init failed");
return false;
}
}
}
repnb++;
}
return true;
}
void BigNfcReader::refresh(){
this->trame->clear();
std::vector<byte> trame = READ_TRAM_0;
if (this->pair){
trame = READ_TRAM_1;
}
this->pair = !this->pair;
for(byte i: trame){
Serial2.write(i);
}
while (Serial2.available() == 0);
while (Serial2.available() > 0){
this->trame->push_back(Serial2.read());
}
}
String BigNfcReader::digitify(int number){
String sortie = "";
if(number <= 0xF){
sortie += '0';
sortie += String(number,HEX);
}else{
sortie += String(number,HEX);
}
return sortie;
}
void BigNfcReader::printTrame(){
for(byte i: *this->trame){
Serial.print(this->digitify(i));
Serial.print(" ");
}
Serial.println();
}
int BigNfcReader::getNbTags(){
return this->trame->at(8);
}

View File

@ -0,0 +1,63 @@
#include "ServoMotorComponent.h"
/////////////////////////////////////////////////////////////////////////////////////
// Functions for setting up the ServoMotor
/////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor.
* Prepares the ServoMotor.
*/
ServoMotorComponent::ServoMotorComponent(int PIN, unsigned long updatePeriod, float step) {
this->PIN = PIN;
this->myservo.attach(PIN);
this->desiredposition = Position::MIDDLE;
this->currentPosition = MIDDLE_POS;
this->lastUpTime = millis();
this->updatePeriod = updatePeriod;
this->step = step;
this->myservo.write(this->PIN, this->currentPosition);
}
/**
* Set the desired position
* @desiredPosition: Give desired position
*/
void ServoMotorComponent::setDesiredPosition(Position desiredPosition) {
switch (desiredPosition) {
case Position::LEFT:
this->desiredposition = LEFT_POS;
break;
case Position::MIDDLE:
this->desiredposition = MIDDLE_POS;
break;
case Position::RIGHT:
this->desiredposition = RIGHT_POS;
break;
default:
break;
}
}
/**
* Write a new servoMotor position when it's necessary
*/
void ServoMotorComponent::refresh() {
if (this->desiredposition == this->currentPosition
|| millis() - this->lastUpTime <= this->updatePeriod) return;
if (this->currentPosition > this->desiredposition) {
this->currentPosition -= this->step;
}
if (this->currentPosition < this->desiredposition) {
this->currentPosition += this->step;
}
this->lastUpTime = millis();
this->myservo.write(this->PIN, this->currentPosition);
}
bool ServoMotorComponent::isConnected() {
return true;
}

View File

@ -0,0 +1,34 @@
#ifndef SERVOMOTOT_COMPONENT_H
#define SERVOMOTOT_COMPONENT_H
#include <Servo.h>
enum Position {
LEFT,
MIDDLE,
RIGHT
};
class ServoMotorComponent
{
public:
ServoMotorComponent(int PIN, unsigned long updatePeriod = 100, float step = 0.1);
void setDesiredPosition(Position desiredPosition);
bool isConnected();
void refresh();
private:
int PIN;
float currentPosition;
float desiredposition;
Servo myservo;
unsigned long lastUpTime;
unsigned long updatePeriod;
float step;
};
#endif //SERVOMOTOT_COMPONENT_H

View File

@ -0,0 +1 @@
#include "WorldTime.h"

View File

@ -0,0 +1,6 @@
#ifndef T_IOT_901_CONVOYOR_WORLDTIME_H
#define T_IOT_901_CONVOYOR_WORLDTIME_H
#endif //T_IOT_901_CONVOYOR_WORLDTIME_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
@ -31,7 +32,7 @@ extra_scripts = pre:scripts/get_additionnal_envs.py
; Device Settings (make sure to fix versions where possible!) ; Device Settings (make sure to fix versions where possible!)
platform = espressif32@4.2.0 platform = espressif32@4.2.0
board = esp32dev board = m5stack-core-esp32
framework = arduino framework = arduino
; Monitoring settings ; Monitoring settings
@ -50,6 +51,11 @@ 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
m5stack/Module_GRBL_13.2@^0.0.3 ; M5 Lib pour Stepper (GRBL)
dlloydev/ESP32 ESP32S2 AnalogWrite ; Lib pour le Servo Motor
; 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,175 @@
#include "Program.h" #include "Program.h"
#include "Arduino.h"
#include "M5LCD.h"
#include "DolibarrClient.h"
#include "ServoMotorComponent.h"
#include "NfcReader.h"
#include <Ticker.h>
uint32_t derniereExecution = 0;
const uint32_t intervalle = 1000;
std::vector<models::Warehouse> *warehouses;
int initialize_wifi(WifiConfig wifi) {
lcdScreen->add_log("Connecting to the WiFi network...");
WiFiClass::mode(WIFI_STA); //Optional
WiFi.setSleep(false);
WiFi.begin(wifi.ssid, wifi.password);
return 0;
}
void Program::checkNfc() {
if (this->nfcReader->IsNfcConnected() && lcdScreen->get_components().nfc != COMPONENT_OK) {
lcdScreen->set_nfc_status(COMPONENT_OK);
lcdScreen->add_log("NFC component connected !");
Serial.println("NFC IS CONNECTED !");
} else if (!this->nfcReader->IsNfcConnected() && lcdScreen->get_components().nfc == COMPONENT_OK) {
lcdScreen->set_nfc_status(COMPONENT_KO);
lcdScreen->add_log("NFC component disconnected !");
Serial.println("NFC NOT CONNECTED !");
}
}
void Program::checkServo() {
if (this->servo->isConnected() && lcdScreen->get_components().servo != COMPONENT_OK) {
lcdScreen->set_servo(COMPONENT_OK);
lcdScreen->add_log("SERVO component connected !");
Serial.println("SERVO IS CONNECTED !");
} else if (!this->servo->isConnected() && lcdScreen->get_components().servo == COMPONENT_OK) {
lcdScreen->set_servo(COMPONENT_KO);
lcdScreen->add_log("SERVO component disconnected !");
Serial.println("SERVO NOT CONNECTED !");
}
}
void Program::checkWifi() {
if (WiFiClass::status() == WL_CONNECTED && lcdScreen->get_components().wifi != COMPONENT_OK) {
lcdScreen->add_log("Connected to the WiFi network");
lcdScreen->set_wifi_status(COMPONENT_OK);
struct DolibarrConfig dolibarr = {DOLIBARR_URL, DOLIBARR_API_TOKEN};
this->client = new DolibarrClient(dolibarr);
warehouses = this->client->list_warehouse();
if (warehouses != nullptr) {
lcdScreen->add_log("Warehouses found !");
lcdScreen->set_dolibarr_status(COMPONENT_OK);
for (auto &ware : *warehouses) {
char buffer[50];
sprintf(buffer, "+ Warehouse '%s' (%s)", ware.label.c_str(), ware.id.c_str());
lcdScreen->add_log(buffer);
}
} else {
lcdScreen->add_log("Warehouse not found");
lcdScreen->set_dolibarr_status(COMPONENT_KO);
}
} else if (WiFiClass::status() != WL_CONNECTED && lcdScreen->get_components().wifi == COMPONENT_OK) {
lcdScreen->add_log("Wifi signal lost, reconnecting...");
lcdScreen->set_wifi_status(COMPONENT_KO);
lcdScreen->set_dolibarr_status(COMPONENT_KO);
struct WifiConfig wifi_c = {WIFI_SSID, WIFI_PASSWORD};
initialize_wifi(wifi_c);
}
}
Program::Program() { Program::Program() {
// Startup
Serial.begin(MONITOR_SPEED); Serial.begin(MONITOR_SPEED);
Wire.begin();
delay(1000);
lcdScreen = new M5LCD();
lcdScreen->add_log("Initialize M5LCD component....");
this->nfcReader = new NfcReader(NFC_ADDR);
this->servo = new ServoMotorComponent(2, 1, 1);
this->servo->setDesiredPosition(Position::MIDDLE);
this->grbl = new GRBL(STEPMOTOR_I2C_ADDR);
this->outputReader = new BigNfcReader();
this->outputReader->init();
this->grblUpdateTime = 0;
lcdScreen->set_grbl_status(COMPONENT_OK);
Wire.begin(21, 22);
grbl->init(STEPER_SPEED, STEPER_PAS, STEPER_ACC);
struct WifiConfig wifi_c = {WIFI_SSID, WIFI_PASSWORD};
initialize_wifi(wifi_c);
} }
void Program::loop() { void Program::loop() {
// Loop lcdScreen->update();
uint32_t maintenant = millis();
if (maintenant - derniereExecution >= intervalle) {
this->checkServo();
this->checkNfc();
this->checkWifi();
derniereExecution = maintenant;
}
this->servo->refresh();
this->outputReader->refresh();
// Serial.println(this->outputReader->getNbTags());
if(this->outputReader->getNbTags() >= 2){
lcdScreen->set_nfc_message("To mutch colis number detected");
lcdScreen->set_grbl_status(COMPONENT_KO);
}
String nfcId = this->nfcReader->ReadNfc();
//si qqc
if(nfcId != "0"){
if (lcdScreen->get_components().wifi != COMPONENT_OK) {
lcdScreen->add_log("Wifi not connected !");
lcdScreen->set_nfc_message("Cannot send wifi request !");
return;
}
//j'arrète le stepper
//this->grbl->stop(); //FIXME: implemente
//j'affiche le tag lue
Serial.print("new colis in comming : ");
lcdScreen->add_log("new colis detected: ");
lcdScreen->add_log(nfcId.c_str());
lcdScreen->set_nfc_message(nfcId.c_str());
auto product = this->client->get_product_by_factory_id(nfcId.c_str());
Serial.printf("Product: %s\n%s", product.label.c_str(), product.accountancy_code_sell_export.c_str());
lcdScreen->set_product_label(product.label);
lcdScreen->set_product_id(product.id);
/*if (product.fk_default_warehouse == product.accountancy_code_sell_export) {
Serial.printf("Product already in the good warehouse !\n");
return;
}*/
auto ware = std::find_if(warehouses->begin(), warehouses->end(), [&product](models::Warehouse w) {return w.id == product.accountancy_code_sell_export;});
if (ware.base() == nullptr) {
Serial.printf("Warehouse not found !\n");
return;
}
Serial.printf("Product need to go to warehouse %s\n", ware->label.c_str());
this->client->create_movement(models::CreateProductStock{
product.id,
product.fk_default_warehouse,
"-1"
});
if (this->client->create_movement(models::CreateProductStock{
product.id,
ware->id,
"1"
}) == 0) {
Serial.printf("Movement created !\n");
} else {
Serial.printf("Movement cannot be created !\n");
}
if (ware->id == "1") {
this->servo->setDesiredPosition(Position::RIGHT);
lcdScreen->set_servo_message("RIGHT");
} else if (ware->id == "2") {
this->servo->setDesiredPosition(Position::LEFT);
lcdScreen->set_servo_message("LEFT");
} else if (ware->id == "3") {
this->servo->setDesiredPosition(Position::MIDDLE);
lcdScreen->set_servo_message("MIDDLE");
}
this->grbl->mouveForward(CONVOYER_LEN);
} else {
if((this->grbl->isIddle() || (maintenant - this->grblUpdateTime >= GRBL_UPDATE)) && lcdScreen->get_components().grbl == COMPONENT_OK){
this->grblUpdateTime = maintenant;
this->grbl->mouveForward(5);
}
}
if(M5.BtnC.wasReleased() != 0 && lcdScreen->_current_page == DASHBOARD_SCREEN){
lcdScreen->set_grbl_status(COMPONENT_OK);
}
} }

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