From 6d7bd63630d9a372d9c7ab67da883787b121c74d Mon Sep 17 00:00:00 2001 From: medina5 Date: Fri, 9 Jan 2026 07:46:52 +0100 Subject: [PATCH] initial commit --- .devcontainer/Dockerfile | 55 +++ .devcontainer/compose.yml | 54 +++ .devcontainer/devcontainer.json | 22 ++ .devcontainer/nodered/Dockerfile | 7 + .devcontainer/nodered/flows.json | 571 +++++++++++++++++++++++++++++++ .gitignore | 1 + .vscode/launch.json | 25 ++ .vscode/settings.json | 5 + .vscode/tasks.json | 21 ++ CMakeLists.txt | 59 ++++ autom.cpp | 496 +++++++++++++++++++++++++++ main.cpp | 16 + main.hpp | 0 13 files changed, 1332 insertions(+) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/compose.yml create mode 100644 .devcontainer/devcontainer.json create mode 100644 .devcontainer/nodered/Dockerfile create mode 100644 .devcontainer/nodered/flows.json create mode 100644 .gitignore create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json create mode 100644 CMakeLists.txt create mode 100644 autom.cpp create mode 100644 main.cpp create mode 100644 main.hpp diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..cda779c --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,55 @@ +FROM debian:stable-slim + +ARG USERNAME=vscode +ARG USER_UID=1000 +ARG USER_GID=1000 + +RUN groupadd --gid $USER_GID $USERNAME \ + && useradd --uid $USER_UID --gid $USER_GID -m $USERNAME \ + && apt-get update && apt-get install -y sudo \ + && echo "$USERNAME ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers + +RUN RUN set -eux; \ + apt-get update; \ + apt-get install -y \ + git \ + build-essential \ + cmake \ + gdb; + +RUN set -eux; \ + apt-get update; \ + apt-get install -y \ + libncurses-dev \ + libmicrohttpd-dev \ + libcurl4-openssl-dev \ + zlib1g-dev \ + prometheus-cpp-dev \ + nlohmann-json3-dev + +RUN set -eux; \ + apt-get update; \ + apt-get install -y \ + libpaho-mqtt-dev + +RUN set -eux; \ + git clone https://github.com/eclipse/paho.mqtt.cpp.git; \ + cd paho.mqtt.cpp; \ + git submodule init; \ + git submodule update; \ + mkdir build && cd build; \ + cmake -DPAHO_WITH_MQTT_C=ON ..; \ + cmake --build . --target install; \ + ldconfig; + +RUN set -eux; \ + apt-get update; \ + apt-get install -y \ + librabbitmq4 \ + librabbitmq-dev;\ + apt-get clean + +USER $USERNAME +WORKDIR /workspace + +CMD ["sleep infinity"] diff --git a/.devcontainer/compose.yml b/.devcontainer/compose.yml new file mode 100644 index 0000000..ad065eb --- /dev/null +++ b/.devcontainer/compose.yml @@ -0,0 +1,54 @@ +services: + dev: + build: + context: . + dockerfile: Dockerfile + volumes: + - ..:/workspace:cached + command: sleep infinity + networks: + - dev_net + + nodered: + build: ./nodered + container_name: nodered + ports: + - "1880:1880" + networks: + - dev_net + environment: + TZ: Europe/Paris + volumes: + - nodered:/data + + rabbitmq: + image: rabbitmq:4.1.4-management + container_name: rabbitmq + environment: + RABBITMQ_DEFAULT_USER: "admin" + RABBITMQ_DEFAULT_PASS: "geii2025" + + # Activation MQTT sur le port 1883 + RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS: > + -rabbitmq_mqtt tcp_listeners [1883] + + ports: + - "5672:5672" # AMQP + - "1883:1883" # MQTT + - "15672:15672" # RabbitMQ Manager + networks: + - dev_net + volumes: + - rabbitmq:/var/lib/rabbitmq + + # Activation des plugins + démarrage serveur + command: > + sh -c "rabbitmq-plugins enable --offline rabbitmq_mqtt rabbitmq_management && + rabbitmq-server" + +networks: + dev_net: + +volumes: + nodered: + rabbitmq: diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..fcb5424 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,22 @@ +{ + "name": "sarii", + "dockerComposeFile": [ + "compose.yml" + ], + "service": "dev", + "workspaceFolder": "/workspace", + "postStartCommand": "cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", + "customizations": { + "vscode": { + "settings": { + "remote.downloadExtensionsLocally": true, + "telemetry.enableTelemetry": false, + "extensions.ignoreRecommendations": true, + "workbench.remoteIndicator.showExtensionRecommendations": false + }, + "extensions": [ + "ms-vscode.cpptools" + ] + } + } +} diff --git a/.devcontainer/nodered/Dockerfile b/.devcontainer/nodered/Dockerfile new file mode 100644 index 0000000..c9aeb6e --- /dev/null +++ b/.devcontainer/nodered/Dockerfile @@ -0,0 +1,7 @@ +FROM nodered/node-red:4.1 + +# Installer FlowFuse Dashboard +RUN npm install --unsafe-perm @flowfuse/node-red-dashboard + +# Copier votre flux si nécessaire +COPY flows.json /data/flows.json diff --git a/.devcontainer/nodered/flows.json b/.devcontainer/nodered/flows.json new file mode 100644 index 0000000..58231b4 --- /dev/null +++ b/.devcontainer/nodered/flows.json @@ -0,0 +1,571 @@ +[ + { + "id": "41526b8c80d5a5f7", + "type": "tab", + "label": "Flux 1", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "dc9d3b99eadb9b34", + "type": "ui-button", + "z": "41526b8c80d5a5f7", + "group": "5fe915fcd26e78ae", + "name": "", + "label": "B0", + "order": 2, + "width": 0, + "height": 0, + "emulateClick": false, + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "iconPosition": "left", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "buttonColor": "", + "textColor": "", + "iconColor": "", + "enableClick": true, + "enablePointerdown": false, + "pointerdownPayload": "", + "pointerdownPayloadType": "str", + "enablePointerup": false, + "pointerupPayload": "", + "pointerupPayloadType": "str", + "x": 130, + "y": 320, + "wires": [ + [ + "6444617c166984e0" + ] + ] + }, + { + "id": "9dcd1bf2a25f7371", + "type": "ui-button", + "z": "41526b8c80d5a5f7", + "group": "5fe915fcd26e78ae", + "name": "", + "label": "B1", + "order": 3, + "width": 0, + "height": 0, + "emulateClick": false, + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "iconPosition": "left", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "buttonColor": "", + "textColor": "", + "iconColor": "", + "enableClick": true, + "enablePointerdown": false, + "pointerdownPayload": "", + "pointerdownPayloadType": "str", + "enablePointerup": false, + "pointerupPayload": "", + "pointerupPayloadType": "str", + "x": 130, + "y": 360, + "wires": [ + [ + "4ee747c8012c58a1" + ] + ] + }, + { + "id": "143358afb510246e", + "type": "ui-button", + "z": "41526b8c80d5a5f7", + "group": "5fe915fcd26e78ae", + "name": "", + "label": "B2", + "order": 4, + "width": 0, + "height": 0, + "emulateClick": false, + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "iconPosition": "left", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "buttonColor": "", + "textColor": "", + "iconColor": "", + "enableClick": true, + "enablePointerdown": false, + "pointerdownPayload": "", + "pointerdownPayloadType": "str", + "enablePointerup": false, + "pointerupPayload": "", + "pointerupPayloadType": "str", + "x": 130, + "y": 400, + "wires": [ + [ + "d966ba0d813b7cb7" + ] + ] + }, + { + "id": "e863fe498c528076", + "type": "ui-button", + "z": "41526b8c80d5a5f7", + "group": "5fe915fcd26e78ae", + "name": "", + "label": "B3", + "order": 5, + "width": 0, + "height": 0, + "emulateClick": false, + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "iconPosition": "left", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "buttonColor": "", + "textColor": "", + "iconColor": "", + "enableClick": true, + "enablePointerdown": false, + "pointerdownPayload": "", + "pointerdownPayloadType": "str", + "enablePointerup": false, + "pointerupPayload": "", + "pointerupPayloadType": "str", + "x": 130, + "y": 440, + "wires": [ + [ + "501355b0c82cae08" + ] + ] + }, + { + "id": "04e097a5c78127cb", + "type": "mqtt out", + "z": "41526b8c80d5a5f7", + "name": "", + "topic": "geii/in", + "qos": "", + "retain": "", + "respTopic": "", + "contentType": "", + "userProps": "", + "correl": "", + "expiry": "", + "broker": "5bf949eb0a1b50a7", + "x": 730, + "y": 120, + "wires": [] + }, + { + "id": "d12767fc3e33bb20", + "type": "ui-button", + "z": "41526b8c80d5a5f7", + "group": "5fe915fcd26e78ae", + "name": "", + "label": "MARCHE", + "order": 1, + "width": 0, + "height": 0, + "emulateClick": false, + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "iconPosition": "left", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "buttonColor": "", + "textColor": "", + "iconColor": "", + "enableClick": true, + "enablePointerdown": false, + "pointerdownPayload": "", + "pointerdownPayloadType": "str", + "enablePointerup": false, + "pointerupPayload": "", + "pointerupPayloadType": "str", + "x": 140, + "y": 260, + "wires": [ + [ + "3e0c75aae8971dca" + ] + ] + }, + { + "id": "0ca8f4a10a6048af", + "type": "function", + "z": "41526b8c80d5a5f7", + "name": "format mqtt", + "func": "let marche = Number(flow.get(\"marche\") || 0);\nlet b0 = Number(flow.get(\"b0\") || 0);\nlet b1 = Number(flow.get(\"b1\") || 0);\nlet b2 = Number(flow.get(\"b2\") || 0);\n\nmsg.payload = {\n \"marche\": marche,\n \"b0\": b0,\n \"b1\": b1,\n \"b2\": b2\n};\n\nreturn msg;", + "outputs": 1, + "timeout": 0, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 570, + "y": 120, + "wires": [ + [ + "04e097a5c78127cb" + ] + ] + }, + { + "id": "a49263451d77f972", + "type": "inject", + "z": "41526b8c80d5a5f7", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 110, + "y": 40, + "wires": [ + [ + "d28f31d7c379f3d8" + ] + ] + }, + { + "id": "d28f31d7c379f3d8", + "type": "change", + "z": "41526b8c80d5a5f7", + "name": "", + "rules": [ + { + "t": "set", + "p": "marche", + "pt": "flow", + "to": "0", + "tot": "num" + }, + { + "t": "set", + "p": "b1", + "pt": "msg", + "to": "0", + "tot": "num" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 320, + "y": 40, + "wires": [ + [ + "0ca8f4a10a6048af" + ] + ] + }, + { + "id": "3e0c75aae8971dca", + "type": "function", + "z": "41526b8c80d5a5f7", + "name": "set marche", + "func": "flow.set(\"marche\", !Number(flow.get(\"marche\")));\n\nreturn msg;", + "outputs": 1, + "timeout": 0, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 310, + "y": 260, + "wires": [ + [ + "0ca8f4a10a6048af" + ] + ] + }, + { + "id": "6444617c166984e0", + "type": "function", + "z": "41526b8c80d5a5f7", + "name": "set marche", + "func": "flow.set(\"b0\", !Number(flow.get(\"b0\")));\n\nreturn msg;", + "outputs": 1, + "timeout": 0, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 310, + "y": 320, + "wires": [ + [ + "0ca8f4a10a6048af" + ] + ] + }, + { + "id": "4ee747c8012c58a1", + "type": "function", + "z": "41526b8c80d5a5f7", + "name": "set marche", + "func": "flow.set(\"b1\", !Number(flow.get(\"b1\")));\n\nreturn msg;", + "outputs": 1, + "timeout": 0, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 310, + "y": 360, + "wires": [ + [ + "0ca8f4a10a6048af" + ] + ] + }, + { + "id": "d966ba0d813b7cb7", + "type": "function", + "z": "41526b8c80d5a5f7", + "name": "set marche", + "func": "flow.set(\"b2\", !Number(flow.get(\"b2\")));\n\nreturn msg;", + "outputs": 1, + "timeout": 0, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 310, + "y": 400, + "wires": [ + [ + "0ca8f4a10a6048af" + ] + ] + }, + { + "id": "501355b0c82cae08", + "type": "function", + "z": "41526b8c80d5a5f7", + "name": "set marche", + "func": "flow.set(\"b3\", !Number(flow.get(\"b3\")));\n\nreturn msg;", + "outputs": 1, + "timeout": 0, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 310, + "y": 440, + "wires": [ + [ + "0ca8f4a10a6048af" + ] + ] + }, + { + "id": "1dfea06c14d2732c", + "type": "mqtt in", + "z": "41526b8c80d5a5f7", + "name": "", + "topic": "geii/out", + "qos": "2", + "datatype": "auto-detect", + "broker": "5bf949eb0a1b50a7", + "nl": false, + "rap": true, + "rh": 0, + "inputs": 0, + "x": 130, + "y": 580, + "wires": [ + [ + "31ef90b8227cd6cb" + ] + ] + }, + { + "id": "31ef90b8227cd6cb", + "type": "debug", + "z": "41526b8c80d5a5f7", + "name": "debug 1", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "false", + "statusVal": "", + "statusType": "auto", + "x": 380, + "y": 580, + "wires": [] + }, + { + "id": "5fe915fcd26e78ae", + "type": "ui-group", + "name": "Pupitre", + "page": "bb436fe040268d40", + "width": "2", + "height": 1, + "order": 1, + "showTitle": true, + "className": "", + "visible": "true", + "disabled": "false", + "groupType": "default" + }, + { + "id": "5bf949eb0a1b50a7", + "type": "mqtt-broker", + "name": "", + "broker": "rabbitmq", + "port": 1883, + "clientid": "", + "autoConnect": true, + "usetls": false, + "protocolVersion": 4, + "keepalive": 60, + "cleansession": true, + "autoUnsubscribe": true, + "birthTopic": "", + "birthQos": "0", + "birthRetain": "false", + "birthPayload": "", + "birthMsg": {}, + "closeTopic": "", + "closeQos": "0", + "closeRetain": "false", + "closePayload": "", + "closeMsg": {}, + "willTopic": "", + "willQos": "0", + "willRetain": "false", + "willPayload": "", + "willMsg": {}, + "userProps": "", + "sessionExpiry": "" + }, + { + "id": "bb436fe040268d40", + "type": "ui-page", + "name": "LP SARII", + "ui": "92537b03143c5e06", + "path": "/page1", + "icon": "home", + "layout": "grid", + "theme": "ea2bf5532fa513eb", + "breakpoints": [ + { + "name": "Default", + "px": "0", + "cols": "3" + }, + { + "name": "Tablet", + "px": "576", + "cols": "6" + }, + { + "name": "Small Desktop", + "px": "768", + "cols": "9" + }, + { + "name": "Desktop", + "px": "1024", + "cols": "12" + } + ], + "order": 1, + "className": "", + "visible": "true", + "disabled": "false" + }, + { + "id": "92537b03143c5e06", + "type": "ui-base", + "name": "My Dashboard", + "path": "/dashboard", + "appIcon": "", + "includeClientData": true, + "acceptsClientConfig": [ + "ui-notification", + "ui-control" + ], + "showPathInSidebar": false, + "headerContent": "page", + "navigationStyle": "default", + "titleBarStyle": "default", + "showReconnectNotification": true, + "notificationDisplayTime": 1, + "showDisconnectNotification": true, + "allowInstall": false + }, + { + "id": "ea2bf5532fa513eb", + "type": "ui-theme", + "name": "Default Theme", + "colors": { + "surface": "#ffffff", + "primary": "#0094CE", + "bgPage": "#eeeeee", + "groupBg": "#ffffff", + "groupOutline": "#cccccc" + }, + "sizes": { + "density": "default", + "pagePadding": "12px", + "groupGap": "12px", + "groupBorderRadius": "4px", + "widgetGap": "12px" + } + }, + { + "id": "925a608e1a2d82a3", + "type": "global-config", + "env": [], + "modules": { + "@flowfuse/node-red-dashboard": "1.29.0" + } + } +] \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..84c048a --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/build/ diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..463e2c5 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,25 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug pompes", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/pompes", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Activer les pretty-printers pour gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "preLaunchTask": "CMake: build" + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..ab56e49 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.insertFinalNewline": true, + "files.trimTrailingWhitespace": true, + "files.trimFinalNewlines": true +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..ca1bc1f --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,21 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "CMake: build", + "type": "shell", + "command": "cmake --build build --config Debug", + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": ["$gcc"] + }, + { + "label": "CMake: configure", + "type": "shell", + "command": "cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", + "problemMatcher": ["$gcc"] + } + ] +} diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..866dc7f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,59 @@ +cmake_minimum_required(VERSION 3.15) +project(pompes LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +# Activer warnings utiles +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic") + +# Executable principal +add_executable(pompes + main.cpp +) + +# ------------------------------- +# Librairies systèmes +# ------------------------------- + +# CURL +find_package(CURL REQUIRED) + +# Microhttpd +find_library(MICROHTTPD_LIB microhttpd REQUIRED) + +# Threads et compression +find_package(Threads REQUIRED) +find_library(Z_LIB z REQUIRED) + +# ncursesw +find_library(NCURSESW_LIB ncursesw REQUIRED) + +# RabbitMQ C client +find_library(RABBITMQ_LIB rabbitmq REQUIRED) + +# Paho MQTT C client +find_library(PAHO_MQTTPP3_LIB paho-mqttpp3 REQUIRED) +find_library(PAHO_MQTT3C_LIB paho-mqtt3c REQUIRED) + +# ------------------------------- +# Prometheus C++ +# ------------------------------- +find_package(prometheus-cpp REQUIRED) + +# ------------------------------- +# Lien des bibliothèques +# ------------------------------- +target_link_libraries(pompes + prometheus-cpp::core + prometheus-cpp::pull + ${CURL_LIBRARIES} + ${MICROHTTPD_LIB} + Threads::Threads + ${Z_LIB} + ${NCURSESW_LIB} + ${RABBITMQ_LIB} + ${PAHO_MQTT3C_LIB} # dépendance C + ${PAHO_MQTTPP3_LIB} # lib C++ +) diff --git a/autom.cpp b/autom.cpp new file mode 100644 index 0000000..a55f5e1 --- /dev/null +++ b/autom.cpp @@ -0,0 +1,496 @@ +#include +#include +#include + +#undef timeout +#include "mqtt/async_client.h" + +#include +using json = nlohmann::json; + +#include + +/* From Arduino.h */ + +#define HIGH 0x1 +#define LOW 0x00 + +#define IO_INPUT 0x02 +#define IO_OUTPUT 0x04 + +#define DIGITAL 0x08 +#define ANALOG 0x10 + +#define PI 3.1415926535897932384626433832795 +#define HALF_PI 1.5707963267948966192313216916398 + +#define true 1 +#define false 0 + +/* Configuration MQTT */ +const std::string ADDRESS = "tcp://rabbitmq:1883"; +const std::string CLIENTID = "CppClientTP"; +const std::string TOPIC = "geii/in/#"; +const int QOS = 1; + +int s0, s1; + +// Temps + +// Timestamp unix en millisecondes +// t_start : timestamp de départ +// t_backup : timestamp de la précédente itération +// t_elapsed : temps écoulé en secondes depuis le départ +// dt (delta t) : temps écoulé en secondes depuis la dernière itération +unsigned long t_start, t_backup; +double t_elapsed, dt; + +unsigned long millis() +{ + struct timespec now; + clock_gettime(CLOCK_REALTIME, &now); + return ((unsigned long)now.tv_sec) * 1000 + ((unsigned long)now.tv_nsec) / 1000000; +} + +#define OP_DIGITAL_READ 0 +#define OP_DIGITAL_WRITE 1 +#define OP_ANALOG_READ 2 +#define OP_ANALOG_WRITE 3 +#define OP_PIN_MODE 4 + +typedef struct PinIO +{ + unsigned char mode; + int ivalue; + double dvalue; + int error; // % = 1 /error ex 1 / 20 = 5 % + double efficacite; // 0 - 100% + unsigned long start; + unsigned long time; + double duration; + unsigned int nb; // compteur d'activation + int memory; + unsigned char raising; + unsigned char falling; +} PinIO; + +PinIO _digital[256]; + +void pinMode(unsigned char p, unsigned char mode) +{ + _digital[p].mode = 0x01 | mode; + + _digital[p].ivalue = 0; + _digital[p].dvalue = 0.0; + + _digital[p].nb = 0; + _digital[p].time = 0.0; + _digital[p].duration = 0.0; + _digital[p].start = 0; + _digital[p].raising = 0; + _digital[p].memory = 0; +} + +// Réception des messages MQTT +// ************************************************************ +class callback : public virtual mqtt::callback +{ +public: + void message_arrived(mqtt::const_message_ptr msg) override + { + std::string payload = msg->to_string(); + + std::cout << "MQTT IN : "; + + try + { + json j = json::parse(payload); + + // Ne rien faire si l'objet JSON est vide + if (j.empty()) + return; + + if (j.contains("b0")) + s0 = j["b0"].get() != 0; + + std::cout << "boutons : " << s0 << std::endl; + } + catch (const json::parse_error &e) + { + std::cerr << "Erreur JSON : " << e.what() << "\n"; + } + } +}; +// ************************************************************ + +mqtt::async_client client(ADDRESS, CLIENTID); + +void open() { + + callback cb; + client.set_callback(cb); + + mqtt::connect_options connOpts; + connOpts.set_clean_session(true); + connOpts.set_user_name("admin"); + connOpts.set_password("geii2025"); + + try + { + client.connect(connOpts)->wait(); + client.start_consuming(); + client.subscribe(TOPIC, QOS)->wait(); + } + catch (const mqtt::exception &exc) + { + std::cerr << "Erreur MQTT: " << exc.what() << "\n"; + return; + } +} + +void close() { + try + { + client.unsubscribe(TOPIC)->wait(); + client.stop_consuming(); + client.disconnect()->wait(); + } + catch (const mqtt::exception &exc) + { + std::cerr << "Erreur déconnexion MQTT: " << exc.what() << std::endl; + } + + std::cout << "Fin du programme" << std::endl; +} + +void send() +{ + json obj = { + {"s0", s0}, + {"s1", s1}, + {"s2", 0}, + {"s3", 1}, + {"s4", 1}, + }; + + std::string payload = obj.dump(); + auto msg = mqtt::make_message("geii/out", payload); + msg->set_qos(0); + client.publish(msg); + + std::cout << s0 << std::endl; + + usleep(100000); +} + + +/* ******************************************************** + * TEMPORISATION RETARD A LA MONTEE * + * La sortie passe à 1 au bout de la tempo * + ******************************************************** */ + +class TemporisationRetardMontee +{ + // methodes + public : + // Contructeur qui prend la duree souhaitee de la temporisation + TemporisationRetardMontee(unsigned long duree) + { + this->duree = duree; + sortie = false; + captureTemps = false; + } + // Activation de la temporisation. Doit etre fait tout le temps de la duree de la tempo + void activation() + { + // Capture du temps de reference + if(!captureTemps) + { + debut = millis(); + captureTemps = true; + } + // Calcul du temps ecoule depuis le temps de reference + tempsEcoule = millis() - debut; + // Mise a 1 de la fin de tempo + if (tempsEcoule >= duree) + { + sortie = true; + captureTemps = false; + } + else + { + sortie = false; + } + } + // Precharge de la temporisation + void setDuree(unsigned long majduree) + { + duree = majduree; + sortie = false; + captureTemps = false; + } + // Interrogation du bit de fin de tempo + bool getSortie() + { + return(sortie); + } + // Recuperation du temps ecoule depuis le debut si necessaire + unsigned long getTempsEcoule() + { + return(tempsEcoule); + } + + // Attributs + private: + unsigned long duree; + unsigned long debut; + unsigned long tempsEcoule; + bool captureTemps; + bool sortie; +}; + +/******************************************************** +* TEMPORISATION RETARD A LA DESCENTE * +* La sortie passe à 0 au bout de la tempo * +*********************************************************/ +class TemporisationRetardDescente +{ + public : + // Contructeur qui prend la duree souhaitee de la temporisation + TemporisationRetardDescente(unsigned long duree) + { + this->duree = duree; + sortie = false; + captureTemps = false; + } + // Activation de la temporisation. Doit etre fait tout le temps de la duree de la tempo + void activation() + { + // Capture du temps de reference + if(!captureTemps) + { + debut = millis(); + captureTemps = true; + sortie = true; + } + // Calcul du temps ecoule depuis le temps de reference + tempsEcoule = millis() - debut; + // Mise a 0 de la fin de tempo + if (tempsEcoule >= duree) + { + sortie = false; + captureTemps = false; + } + } + // Precharge de la temporisation + void setDuree(unsigned long majduree) + { + duree = majduree; + sortie = false; + captureTemps = false; + } + // Interrogration du bit de fin de tempo + bool getSortie() + { + return(sortie); + } + // Recuperation du temps ecoule depuis le debut si necessaire + unsigned long getTempsEcoule() + { + return(tempsEcoule); + } + + private: + unsigned long duree; + unsigned long debut; + unsigned long tempsEcoule; + bool captureTemps; + bool sortie; +}; + +/******************************************************** +**** CLIGNOTEUR ************************************* +*********************************************************/ +class Clignoteur +{ + // methodes + public : + // Construteur qui prend en parametre le temps haut ou bas souhaitee + Clignoteur(int baseDeTemps) + { + this->baseDeTemps = baseDeTemps; + } + // Fonction qui renvoie true si le clignoteur est ├á l'├®tat haut et false s'il est ├á l'├®tat bas + bool statut() + { + return ((millis() / baseDeTemps) % 2 == 1); + } + + // Attributs + private: + int baseDeTemps; +}; + +/******************************************************** +**** COMPTEUR ************************************* +**** ATTENTION : Il faut gerer le front montant dans le programme +*********************************************************/ +class Compteur +{ + // methodes + public : + // Constructeur qui prend en parametre la valeur de preselection + Compteur(int valeurPreselection) + { + this->valeurPreselection = valeurPreselection; + valeur = 0; + } + // Incrementation du compteur + void incrementer() + { + valeur++; + } + // Decrementation du compteur + void decrementer() + { + valeur--; + } + // remise a zero du compteur + void remettreAZero() + { + valeur = 0; + } + // recuperation de la valeur courante + int getValeurCourante() + { + return(valeur); + } + // est-ce que la preselection est atteinte (sortie Q compteur Siemens ou Schnieder) + bool getSortie() + { + return(valeur == valeurPreselection); + } + + // Attributs + private: + int valeur; + int valeurPreselection; +}; + +/******************************************************** +**** MISE A L'ECHELLE DE VALEUR ************************ +*********************************************************/ +class MiseAEchelle +{ + public : + // Constructeur qui ne prend en parametre la plage d'entree et la plage de sortie + MiseAEchelle(float minEntree,float maxEntree,float minSortie,float maxSortie) + { + this->minEntree = minEntree; + this->maxEntree = maxEntree; + this->minSortie = minSortie; + this->maxSortie = maxSortie; + } + // fonction de conversion qui prend la valeur a convertir et renvoie la valeur convertie + float convertir(float valeurAConvertir) + { + if(valeurAConvertir >= minEntree && valeurAConvertir <= maxEntree) + { + float norm = (1 / (maxEntree - minEntree)) * (valeurAConvertir - minEntree); + float scale = (maxSortie - minSortie) * norm + minSortie; + return(scale); + } + return(-1000); + } + + // Attributs + private: + float minEntree; + float minSortie; + float maxEntree; + float maxSortie; +}; + +/* READ */ + +int digitalRead(int p) +{ + return ((_digital[p].mode & IO_INPUT) && (_digital[p].mode & DIGITAL) && (_digital[p].mode & 0x01)) ? _digital[p].ivalue : 0; +} + +double analogRead(int p) +{ + return ((_digital[p].mode & IO_INPUT) && (_digital[p].mode & ANALOG) && (_digital[p].mode & 0x01)) ? _digital[p].dvalue : 0.0; +} + +/* WRITE */ + +void digitalWrite(unsigned int p, int value) +{ + if (p > 255) + { + printf("Pin %d is out of Range.", p); + return; + } + + // En panne ! + if (!(_digital[p].mode & 0x01)) + { + return; + } + + if (!(_digital[p].mode & IO_OUTPUT && _digital[p].mode & DIGITAL)) + { + printf("Pin %d is not a digital input.", p); + return; + } + + unsigned long m = millis(); + + if (value != _digital[p].ivalue) + { + _digital[p].time = _digital[p].time > 5000 ? 0 : 5000 - _digital[p].time; + } + else + { + _digital[p].time += m - _digital[p].start; + } + + if (value && !_digital[p].ivalue) + { + _digital[p].start = m; + _digital[p].nb += 1; + } + else if (value) + { + _digital[p].duration += dt; + } + + _digital[p].raising = (_digital[p].memory < _digital[p].ivalue); + _digital[p].falling = (_digital[p].memory > _digital[p].ivalue); + _digital[p].memory = _digital[p].ivalue; + _digital[p].ivalue = value; +} + +void analogWrite(unsigned int p, double value) +{ + if (p > 31) + { + printf("Pin %d is out of Range.", p); + return; + } + + // En panne + if (!(_digital[p].mode & 0x01)) + { + return; + } + + if (!(_digital[p].mode & IO_OUTPUT) || !(_digital[p].mode & ANALOG)) + { + printf("Pin %d is not a analog input.", p); + return; + } + + _digital[p].dvalue = value; +} diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..1317bd7 --- /dev/null +++ b/main.cpp @@ -0,0 +1,16 @@ +#include +#include "main.hpp" +#include "autom.cpp" + +int main() +{ + open(); + + while (1) + { + send(); + } + + close(); + return 0; +} diff --git a/main.hpp b/main.hpp new file mode 100644 index 0000000..e69de29