Compare commits
62 Commits
feat/docum
...
master
Author | SHA1 | Date | |
---|---|---|---|
c270a764f2 | |||
26b1185bca | |||
627509a2d7 | |||
01728a2499 | |||
57cf250a03 | |||
9c11f62019 | |||
7b975bd9a9 | |||
35ecce7d5d | |||
a105387c21 | |||
3f77acd600 | |||
23258e2682 | |||
f64264631e | |||
68a4ab9755 | |||
69db4ba2b7 | |||
45cef130ca | |||
2c22e0a538 | |||
c498489cbb | |||
c3e50c79b5 | |||
fe671182cd | |||
4f3a5bda03 | |||
15bd7c7741 | |||
dea01d3e84 | |||
9a8a84a59e | |||
027015b33b | |||
f3dc069f3b | |||
1e59d9dc46 | |||
b3ef581d28 | |||
6e9a59bb00 | |||
4023cfcb3d | |||
0e14688f85 | |||
032960c168 | |||
81c9ececf6 | |||
4e8e916e5e | |||
a66882e877 | |||
29c41b6ccc | |||
04474bfb94 | |||
463e71fe10 | |||
76ebc00763 | |||
8bdd4a9be2 | |||
f947fc7e5f | |||
b96088c4eb | |||
d8f0bb07be | |||
cada4d6e02 | |||
b7fe429508 | |||
fe529b4f57 | |||
a924d6c534 | |||
cfffa667b6 | |||
3c7aea15a9 | |||
caa5b0ceb7 | |||
0a43f65ce2 | |||
38415c2da5 | |||
d077deb960 | |||
07528f75f2 | |||
eb3a6426cd | |||
844cbf817c | |||
8e8df97e68 | |||
7cf9e88995 | |||
01b99d9716 | |||
88077f284e | |||
e4f009b63e | |||
258725e8c9 | |||
884a181f04 |
4
.env.example
Normal file
4
.env.example
Normal 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
3
.gitignore
vendored
@ -7,7 +7,8 @@
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
||||
.idea/
|
||||
|
||||
# Aptatio/Platformio specifics
|
||||
secrets.ini
|
||||
.idea
|
||||
.env
|
||||
|
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"new": "cpp"
|
||||
}
|
||||
}
|
28
config.ini
28
config.ini
@ -13,7 +13,31 @@ build_flags =
|
||||
; DO NOT TOUCH --- START
|
||||
-D MONITOR_SPEED=${config.monitor_speed}
|
||||
; 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
11
config_api.ini
Normal 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
|
@ -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
27
docker-compose.yml
Normal 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
64
docs/Doc_Dolibarr.md
Normal 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
|
||||
}
|
77
docs/Schématics/Class.puml
Normal file
77
docs/Schématics/Class.puml
Normal 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
|
22
docs/Schématics/Hardware.puml
Normal file
22
docs/Schématics/Hardware.puml
Normal 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
|
@ -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:
|
||||
|
||||

|
||||
|
||||
|
||||
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 |
@ -1,7 +1,12 @@
|
||||
#ifndef 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 {
|
||||
public:
|
||||
@ -11,9 +16,19 @@ public:
|
||||
Program();
|
||||
|
||||
/**
|
||||
* Program main loop
|
||||
* Program WarehouseGUI loop
|
||||
*/
|
||||
void loop();
|
||||
void checkNfc();
|
||||
void checkServo();
|
||||
void checkWifi();
|
||||
private:
|
||||
DolibarrClient *client;
|
||||
ServoMotorComponent *servo;
|
||||
NfcReader *nfcReader;
|
||||
GRBL *grbl;
|
||||
BigNfcReader* outputReader;
|
||||
int grblUpdateTime;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
163
lib/DolibarrClient/src/DolibarrClient.cpp
Normal file
163
lib/DolibarrClient/src/DolibarrClient.cpp
Normal 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;
|
||||
}
|
36
lib/DolibarrClient/src/DolibarrClient.h
Normal file
36
lib/DolibarrClient/src/DolibarrClient.h
Normal 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
|
44
lib/DolibarrClient/src/DolibarrModels.h
Normal file
44
lib/DolibarrClient/src/DolibarrModels.h
Normal 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
24
lib/GRBL/include/GRBL.h
Normal 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
44
lib/GRBL/src/GRBL.cpp
Normal 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
224
lib/M5LCD/src/M5LCD.cpp
Normal 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
84
lib/M5LCD/src/M5LCD.h
Normal 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
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
472
lib/NFC/src/MFRC522_I2C.h
Normal 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
32
lib/NFC/src/NfcReader.cpp
Normal 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
22
lib/NFC/src/NfcReader.h
Normal 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 */
|
67
lib/NfcReader/include/BigNfcReader.h
Normal file
67
lib/NfcReader/include/BigNfcReader.h
Normal 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
|
29
lib/NfcReader/include/TrameList.h
Normal file
29
lib/NfcReader/include/TrameList.h
Normal 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
|
75
lib/NfcReader/src/BigNfcReader.cpp
Normal file
75
lib/NfcReader/src/BigNfcReader.cpp
Normal 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);
|
||||
}
|
63
lib/ServoMotorComponent/src/ServoMotorComponent.cpp
Normal file
63
lib/ServoMotorComponent/src/ServoMotorComponent.cpp
Normal 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;
|
||||
}
|
34
lib/ServoMotorComponent/src/ServoMotorComponent.h
Normal file
34
lib/ServoMotorComponent/src/ServoMotorComponent.h
Normal 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
|
1
lib/WorldTime/src/WorldTime.cpp
Normal file
1
lib/WorldTime/src/WorldTime.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "WorldTime.h"
|
6
lib/WorldTime/src/WorldTime.h
Normal file
6
lib/WorldTime/src/WorldTime.h
Normal 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
|
@ -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
|
||||
@ -31,7 +32,7 @@ extra_scripts = pre:scripts/get_additionnal_envs.py
|
||||
|
||||
; Device Settings (make sure to fix versions where possible!)
|
||||
platform = espressif32@4.2.0
|
||||
board = esp32dev
|
||||
board = m5stack-core-esp32
|
||||
framework = arduino
|
||||
|
||||
; Monitoring settings
|
||||
@ -50,6 +51,11 @@ 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
|
||||
m5stack/Module_GRBL_13.2@^0.0.3 ; M5 Lib pour Stepper (GRBL)
|
||||
dlloydev/ESP32 ESP32S2 AnalogWrite ; Lib pour le Servo Motor
|
||||
; example:
|
||||
; erropix/ESP32 AnalogWrite@0.2
|
||||
|
||||
|
@ -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
|
169
src/Program.cpp
169
src/Program.cpp
@ -1,10 +1,175 @@
|
||||
#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() {
|
||||
// Startup
|
||||
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() {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
#include "Program.h"
|
||||
|
||||
Program* program;
|
||||
|
||||
void setup() {
|
||||
|
10
test/dolibarr.cpp
Normal file
10
test/dolibarr.cpp
Normal 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
36
test/test.cpp
Normal 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
6
test/test.h
Normal 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
|
Loading…
x
Reference in New Issue
Block a user