From 386f7e1a0e44f42ab4f0834383e566c9f9667bc8 Mon Sep 17 00:00:00 2001 From: Laurent Date: Mon, 29 Dec 2025 12:35:16 +0100 Subject: [PATCH] Configured customer broker --- api-customer/app.py | 11 +++- api-customer/docker-compose.yml | 18 +++++- api-customer/mosquitto/certs/mosquitto.crt | 25 ++++++++ api-customer/mosquitto/certs/mosquitto.key | 28 +++++++++ api-customer/mosquitto/config/mosquitto.conf | 16 +++++ api-customer/mosquitto/config/passwords | 0 api-customer/requirements.txt | 3 +- api-customer/src/__init__.py | 0 api-customer/src/controllers/__init__.py | 0 .../src/controllers/mqtt_forwarder.py | 43 ++++++++++++++ api-customer/src/services/__init__.py | 0 api-customer/src/services/mqtt_service.py | 55 ++++++++++++++++++ api/mosquitto/data/mosquitto.db | Bin 47 -> 47 bytes 13 files changed, 195 insertions(+), 4 deletions(-) create mode 100644 api-customer/mosquitto/certs/mosquitto.crt create mode 100644 api-customer/mosquitto/certs/mosquitto.key create mode 100644 api-customer/mosquitto/config/mosquitto.conf create mode 100644 api-customer/mosquitto/config/passwords create mode 100644 api-customer/src/__init__.py create mode 100644 api-customer/src/controllers/__init__.py create mode 100644 api-customer/src/controllers/mqtt_forwarder.py create mode 100644 api-customer/src/services/__init__.py create mode 100644 api-customer/src/services/mqtt_service.py diff --git a/api-customer/app.py b/api-customer/app.py index 4b059ec9..1512a2c1 100644 --- a/api-customer/app.py +++ b/api-customer/app.py @@ -1,5 +1,8 @@ from flask import Flask +from src.controllers.mqtt_forwarder import MQTTForwarder +from src.services.mqtt_service import MQTTService + app = Flask(__name__) @@ -9,4 +12,10 @@ def hello_world(): if __name__ == '__main__': - app.run() + + local_broker = MQTTService("127.0.0.1", 1883) + api_broker = MQTTService("192.168.15.120", 8883) + + forwarder = MQTTForwarder(local_broker, api_broker) + + app.run(host="0.0.0.0", port=5000, debug=False) diff --git a/api-customer/docker-compose.yml b/api-customer/docker-compose.yml index 792650ee..94cf8383 100644 --- a/api-customer/docker-compose.yml +++ b/api-customer/docker-compose.yml @@ -3,11 +3,12 @@ version: "3.8" services: customer-api: build: . - container_name: "Flask-API" + container_name: "customer-api" ports: - "5000:5000" depends_on: - mongo + - mosquitto environment: - MONGO_URI=mongodb://mongo:27017/mydb @@ -22,4 +23,17 @@ services: - "27017:27017" volumes: - ./mongo-data:/data/db - - ./mongo-init:/docker-entrypoint-initdb.d \ No newline at end of file + - ./mongo-init:/docker-entrypoint-initdb.d + + mosquitto: + image: eclipse-mosquitto:latest + container_name: "customer-broker" + ports: + - "1883:1883" + - "8883:8883" + volumes: + - ./mosquitto/config:/mosquitto/config + - ./mosquitto/data:/mosquitto/data + - ./mosquitto/log:/mosquitto/log + - ./mosquitto/certs:/mosquitto/certs + diff --git a/api-customer/mosquitto/certs/mosquitto.crt b/api-customer/mosquitto/certs/mosquitto.crt new file mode 100644 index 00000000..d93dd1bc --- /dev/null +++ b/api-customer/mosquitto/certs/mosquitto.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEMTCCAxmgAwIBAgIUSj7h3y4SaFxuD6AeIkuZytZf8uEwDQYJKoZIhvcNAQEL +BQAwgacxCzAJBgNVBAYTAkJFMREwDwYDVQQIDAhMacODwqhnZTERMA8GA1UEBwwI +TGnDg8KoZ2UxDTALBgNVBAoMBEhFUEwxHDAaBgNVBAsME0JvYXJkIG1hdGUgY3Vz +dG9tZXIxFzAVBgNVBAMMDjE5Mi4xNjguMTUuMTI1MSwwKgYJKoZIhvcNAQkBFh1s +YXVyZW50LmNyZW1hQHN0dWRlbnQuaGVwbC5iZTAeFw0yNTEyMjkxMTE5MDZaFw0y +NjEyMjkxMTE5MDZaMIGnMQswCQYDVQQGEwJCRTERMA8GA1UECAwITGnDg8KoZ2Ux +ETAPBgNVBAcMCExpw4PCqGdlMQ0wCwYDVQQKDARIRVBMMRwwGgYDVQQLDBNCb2Fy +ZCBtYXRlIGN1c3RvbWVyMRcwFQYDVQQDDA4xOTIuMTY4LjE1LjEyNTEsMCoGCSqG +SIb3DQEJARYdbGF1cmVudC5jcmVtYUBzdHVkZW50LmhlcGwuYmUwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDgRZbs1AKWZVdsytDagCRTtUrEasxzICMG +8yTAz71dqZR2FXgEHVLTpVp6cFBRB3EeRxFdo1S8te0SJ5L6aAvQIhQyUY3QF5f7 +83AbauhjXIzvvnN/2RJhgU5VxRg1BTze2W3Ek3KND/GNbi6Sd+gACscjef5qnpYO +xki4qZFB/tE5nRCtZy4/7AxKGDHwy89orWrEABOP54LyFppjjzItsUkZHb++jhU6 +lztKbjBydnEX3lusNw8jm1HdUaIJTuoD5az/tsQs+UjHTaFxt128YP+Bckpcegri +C7D+wRLsonVI6P0NcoGG+yzQz0w6i0PTgTNifKyl0jRau9y4VAh/AgMBAAGjUzBR +MB0GA1UdDgQWBBQcpMTyO6+JlsUUXDXTS/rFmO0ohzAfBgNVHSMEGDAWgBQcpMTy +O6+JlsUUXDXTS/rFmO0ohzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA +A4IBAQC5N6HhY4VMZp0gInSDZ1RrM08w3k4/3uqHa5MmRlYVb30KPy7T8wkARfiw +FCtVojYSBbIIZeSoXKLRlSvHQvKij1sajZeOtGyb6p6x+LMWGuNJ3h6HfAzjIu53 +f/V4agfBp7Ljxi4T71jxvGISH7UFJs3kldQ9K737w8Wvb85CqqalzM5zVzltpHb/ +nNIzKZbqxXCGhtJu8Y4gi2bW+QjxaVCtYxY6jgy5J7KhJtZDoExHCXKFOYm8u1Bd +N4J1o6M1udA4v3lHDr0dE5j7UvP7LIbhgCoGTOXaknm+UtqoKF2FKCPF2um5ral6 +Bxv7rANBb73Aw2g06OyHLq3Fc35k +-----END CERTIFICATE----- diff --git a/api-customer/mosquitto/certs/mosquitto.key b/api-customer/mosquitto/certs/mosquitto.key new file mode 100644 index 00000000..df7cdaac --- /dev/null +++ b/api-customer/mosquitto/certs/mosquitto.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDgRZbs1AKWZVds +ytDagCRTtUrEasxzICMG8yTAz71dqZR2FXgEHVLTpVp6cFBRB3EeRxFdo1S8te0S +J5L6aAvQIhQyUY3QF5f783AbauhjXIzvvnN/2RJhgU5VxRg1BTze2W3Ek3KND/GN +bi6Sd+gACscjef5qnpYOxki4qZFB/tE5nRCtZy4/7AxKGDHwy89orWrEABOP54Ly +FppjjzItsUkZHb++jhU6lztKbjBydnEX3lusNw8jm1HdUaIJTuoD5az/tsQs+UjH +TaFxt128YP+BckpcegriC7D+wRLsonVI6P0NcoGG+yzQz0w6i0PTgTNifKyl0jRa +u9y4VAh/AgMBAAECggEAINWvag8ELfa6XQA4obTfHK5POwCT3EsZNbxFZkFD7UGV +rdAo2Rld9gSggYqOB776Lb+j6DywfEx6YA0RNL4k9Jz4rgFIrO23X7jdcfYt/dYg +AD229UHXshTXXjFUAPc6WTomGwCnZcWuzNET2nfZrJ/nVedXe06qk5EuNnMFBE8/ +GsiSuULI32KtlTBhO5TS9PmJfj1+CByQLcYSTG8k8VN9NXEB3kjbCMKgl0BfuALj +Iwbbbz4ffrkzMkm0wXiq+Slad/50pIOPG1LU0KOmgaSv1sTI4hZqHJNRfig5IoP/ +8E/dNJCJOAVpgoQY+SbNmaGEQjB7Fvr/qDaH67BxsQKBgQD8aZ3czUbe7VUmlLJ7 +UavshgyGsox9O1Iwn2LAfP5IP441ODoqD8Wsup/P+c/zEboRlgAw/thPpVuXuXWj +3tO7OuKUSUp0PW3mqDakSzQggxff+OSbHvXzNgzG4OwwM7V2yKQdVml375ACkqB2 +jdhoy9Rq8IFJ6W3cPLa1TDLFGQKBgQDjdZXGMjVv8sqhuuT+vXxLGtuhBp6dn/Ck +Mlvo/QTwADcFO5IKZwT9wt0aUOLIbTub1ZdzbrWS1YCkn13EE98W7/T+DKgc8zG/ +KOIasy/U8sOFTr8o2ozCIl2umy833fRtB8IZQOaSa9UZb6Hr62do2i50FtJKSMGM +kMt+ZSgVVwKBgCwOh0ZV8ivRAw7T339U1wxWrXMJUSo+o27nMwZkCsIzja/OW6Ch +1h/7Bw/3C4viqTaOlwP2R21HcIBAF799kjlY4tl9HWjCnB8pdzggBD40g4NNXyGQ +Ot+zrHE+KxuSuva7uKGCRrBveRRp4WYwBfjssuvjhL2Q5+MMGdv1K9tpAoGAXtOU +n04rTQKRS5+Y/EKO4NjPm3AhDGGzdyCvhJCHUG8mgP32wnN0dz6X4vK5uQkhArSn +MS6EcDSmLvtpoecO6IcdQhSQuZEBukoXCT6OwF58+MR9mVCTwhOFrtdvdgEId7P2 +TYTrGzvtWW9at/op4GKlXyxsex+d4TY0P/t4HH0CgYEA/Bet4dUNzBaHI5mP/vLH +ntEkqXmV0KTiv1RlhrqqYVa9Ct9Dsl2L8TkzlObQ5B0vHVHsVLMSTiUFkE9HmEa9 +Tow0xmylB0PmOfXCwMBpsgh8iNqOrf8fsyIatTbG1nl3Qnbx+fFay8mnOIRZw59+ +Bc8O+xK3JTWZ9ybWbohZH7E= +-----END PRIVATE KEY----- diff --git a/api-customer/mosquitto/config/mosquitto.conf b/api-customer/mosquitto/config/mosquitto.conf new file mode 100644 index 00000000..84c3aa4e --- /dev/null +++ b/api-customer/mosquitto/config/mosquitto.conf @@ -0,0 +1,16 @@ +persistence true +persistence_location /mosquitto/data/ + +log_dest file /mosquitto/log/mosquitto.log + +listener 1883 + +allow_anonymous false +password_file /mosquitto/config/passwords + +listener 8883 +protocol mqtt + +certfile /mosquitto/certs/mosquitto.crt +keyfile /mosquitto/certs/mosquitto.key +tls_version tlsv1.2 diff --git a/api-customer/mosquitto/config/passwords b/api-customer/mosquitto/config/passwords new file mode 100644 index 00000000..e69de29b diff --git a/api-customer/requirements.txt b/api-customer/requirements.txt index 8ab6294c..ced1bfeb 100644 --- a/api-customer/requirements.txt +++ b/api-customer/requirements.txt @@ -1 +1,2 @@ -flask \ No newline at end of file +flask +paho-mqtt \ No newline at end of file diff --git a/api-customer/src/__init__.py b/api-customer/src/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/api-customer/src/controllers/__init__.py b/api-customer/src/controllers/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/api-customer/src/controllers/mqtt_forwarder.py b/api-customer/src/controllers/mqtt_forwarder.py new file mode 100644 index 00000000..1725cad3 --- /dev/null +++ b/api-customer/src/controllers/mqtt_forwarder.py @@ -0,0 +1,43 @@ +import json +import time + +from src.services.mqtt_service import MQTTService + + +class MQTTForwarder: + + client_id : str + local_broker : MQTTService + central_broker : MQTTService + + def __init__(self, client_id : str, local_mqtt: MQTTService, central_mqtt: MQTTService): + self.client_id = client_id + self.local_broker = local_mqtt + self.central_broker = central_mqtt + + def start(self): + self.local_broker.subscribe("board-mate/", self.__forward) + + def __forward(self, msg: str): + self.central_broker.publish(self.client_id, f"/board-mate/${self.client_id}/telemetry", msg) + + """def start(self): + self.local.subscribe("board-mate/+/telemetry", self.handle_message) + + def handle_message(self, topic: str, payload: str): + print(f"[FORWARD] {topic} -> central") + + message = json.loads(payload) + message["source"] = "client-server" + message["forwarded_at"] = int(time.time()) + + self.central.publish( + client_id="client-forwarder", + topic=f"clients/{self.extract_client_id(topic)}/telemetry", + data=json.dumps(message), + qos=1 + ) + + def extract_client_id(self, topic: str) -> str: + # ex: board-mate/pi-123/telemetry + return topic.split("/")[1]""" \ No newline at end of file diff --git a/api-customer/src/services/__init__.py b/api-customer/src/services/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/api-customer/src/services/mqtt_service.py b/api-customer/src/services/mqtt_service.py new file mode 100644 index 00000000..48f71825 --- /dev/null +++ b/api-customer/src/services/mqtt_service.py @@ -0,0 +1,55 @@ +import json +import time +from typing import Callable + +import paho.mqtt.client as mqtt +from paho.mqtt.client import Client + + +class MQTTService: + + client : Client + + def __init__(self, address: str, port: int): + self.address = address + self.port = port + self.client = mqtt.Client() + + def publish(self, client_id: str, topic: str, data: str, qos: int = 0): + + try: + self.__connect() + + payload = { + "timestamp": int(time.time()), + "data": data + } + result = self.client.publish(topic, json.dumps(payload), qos=qos) + result.wait_for_publish() + + except Exception as e: + print("MQTT error:", e) + self.__disconnect() + + def subscribe(self, topic: str, handler: Callable[[str], None]): + def on_message(client, userdata, msg): + handler(msg.payload.decode()) + + try: + self.__connect() + self.client.message_callback_add(topic, on_message) + self.client.subscribe(topic) + except Exception as e: + print("MQTT error:", e) + self.__disconnect() + + + def __connect(self): + if not self.client.is_connected(): + self.client.connect(self.address, self.port) + self.client.loop_start() + + def __disconnect(self): + if self.client.is_connected(): + self.client.disconnect() + self.client.loop_stop() \ No newline at end of file diff --git a/api/mosquitto/data/mosquitto.db b/api/mosquitto/data/mosquitto.db index 3ba16b63ca6ff6940c96c0049c8a267e88d60276..3e65b6bb24831363a1b44cd7281662aab15b9b5c 100644 GIT binary patch delta 21 UcmdPbpCB)APly2w7&#y`03^5q7XSbN delta 21 TcmdPbpCB&~!N&jr91scs925bJ