From a67a24fd55ab43d66590e0ff4c2a8e53afa2a0f2 Mon Sep 17 00:00:00 2001 From: Aaron Zielstorff Date: Thu, 17 Oct 2024 16:40:32 +0200 Subject: [PATCH] Adds example for the usage together with the Databridge (#491) * Adds example for the usage together with the Databridge * Fixes typo * Update examples/BaSyxDatabridge/README.md Co-authored-by: Mohammad Ghazanfar Ali Danish <62088117+mdanish98@users.noreply.github.com> --------- Co-authored-by: Mohammad Ghazanfar Ali Danish <62088117+mdanish98@users.noreply.github.com> --- examples/BaSyxDatabridge/README.md | 42 +++++++++ .../aas/SensorExampleComplete.aasx | Bin 0 -> 13176 bytes .../BaSyxDatabridge/basyx/aas-env.properties | 8 ++ .../BaSyxDatabridge/basyx/aas-registry.yml | 4 + .../BaSyxDatabridge/basyx/sm-registry.yml | 4 + .../databridge/AirQualityTransformer.jsonata | 1 + .../databridge/HumidityTransformer.jsonata | 1 + .../databridge/TemperatureTransformer.jsonata | 1 + .../BaSyxDatabridge/databridge/aasserver.json | 20 ++++ .../databridge/jsonatatransformer.json | 20 ++++ .../databridge/mqttconsumer.json | 8 ++ .../BaSyxDatabridge/databridge/routes.json | 22 +++++ examples/BaSyxDatabridge/docker-compose.yml | 89 ++++++++++++++++++ .../mosquitto/config/mosquitto.conf | 23 +++++ .../BaSyxDatabridge/mqtt-publisher/Dockerfile | 7 ++ .../mqtt-publisher/publisher.py | 47 +++++++++ 16 files changed, 297 insertions(+) create mode 100644 examples/BaSyxDatabridge/README.md create mode 100644 examples/BaSyxDatabridge/aas/SensorExampleComplete.aasx create mode 100644 examples/BaSyxDatabridge/basyx/aas-env.properties create mode 100644 examples/BaSyxDatabridge/basyx/aas-registry.yml create mode 100644 examples/BaSyxDatabridge/basyx/sm-registry.yml create mode 100644 examples/BaSyxDatabridge/databridge/AirQualityTransformer.jsonata create mode 100644 examples/BaSyxDatabridge/databridge/HumidityTransformer.jsonata create mode 100644 examples/BaSyxDatabridge/databridge/TemperatureTransformer.jsonata create mode 100644 examples/BaSyxDatabridge/databridge/aasserver.json create mode 100644 examples/BaSyxDatabridge/databridge/jsonatatransformer.json create mode 100644 examples/BaSyxDatabridge/databridge/mqttconsumer.json create mode 100644 examples/BaSyxDatabridge/databridge/routes.json create mode 100644 examples/BaSyxDatabridge/docker-compose.yml create mode 100644 examples/BaSyxDatabridge/mosquitto/config/mosquitto.conf create mode 100644 examples/BaSyxDatabridge/mqtt-publisher/Dockerfile create mode 100644 examples/BaSyxDatabridge/mqtt-publisher/publisher.py diff --git a/examples/BaSyxDatabridge/README.md b/examples/BaSyxDatabridge/README.md new file mode 100644 index 000000000..b73db0236 --- /dev/null +++ b/examples/BaSyxDatabridge/README.md @@ -0,0 +1,42 @@ +# BaSyx Databridge Example Setup + +This example showcases the usage of the BaSyx Databridge. The BaSyx Databridge is a service that allows the exchange of data between assets and the AAS. +Here, an example MQTT client for an environmental sensor is used to send data via the BaSyx Databridge to an AAS located in the BaSyx AAS Environment. + +## How to run the BaSyx Databridge Example + +1. Open a terminal in this folder +2. Run the following command to start the BaSyx containers: + +```bash +docker-compose up -d +``` + +> To run the example containers, you need to have Docker installed on your device. + +## View the working Example + +To see the working example, open the [BaSyx AAS Web UI](http://localhost:3000) and navigate to the `SensorExampleAAS`. You can see the data coming from the MQTT client in the `SensorData` submodel. +To see updates in real-time, active the `Auto-Sync` feature in the AAS Web UI (see top right corner of the UI). + +## Where to find the configuration + +### BaSyx Databridge + +The configuration for the BaSyx Databridge can be found in the `databridge` folder. There you can find the `routes.config` file, which defines the routes from the assets data source to the AAS data sink. +The data source configuration can be found in the `mqttconsumer.json` file, and the data sink configuration can be found in the `aasserver.json` file. +There are also data transformers defined for extracting the data from the MQTT message. +For more details on how to configure the BaSyx Databridge, please refer to the [BaSyx Databridge documentation](https://wiki.basyx.org/en/latest/content/user_documentation/basyx_components/databridge/index.html). + +### MQTT Client + +The configuration for the MQTT client can be found in the `mqtt-publisher` folder. It is a small Python script that publishes data to the MQTT broker. + +### MQTT Broker + +The MQTT brokers configuration can be found in the `mosquitto` folder. The configuration is defined in the `config/mosquitto.conf` file. + +### BaSyx Components + +The configuration for the BaSyx components can be found in the `basyx` folder. +The AAS used in this example is located in the `aas` folder. diff --git a/examples/BaSyxDatabridge/aas/SensorExampleComplete.aasx b/examples/BaSyxDatabridge/aas/SensorExampleComplete.aasx new file mode 100644 index 0000000000000000000000000000000000000000..33e68fe5046f9724df02a656c58ac297af6806b2 GIT binary patch literal 13176 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 literal 0 HcmV?d00001 diff --git a/examples/BaSyxDatabridge/basyx/aas-env.properties b/examples/BaSyxDatabridge/basyx/aas-env.properties new file mode 100644 index 000000000..3d3d08d9d --- /dev/null +++ b/examples/BaSyxDatabridge/basyx/aas-env.properties @@ -0,0 +1,8 @@ +server.port=8081 +basyx.backend=InMemory +basyx.environment=file:aas +basyx.cors.allowed-origins=* +basyx.cors.allowed-methods=GET,POST,PATCH,DELETE,PUT,OPTIONS,HEAD +basyx.aasrepository.feature.registryintegration=http://aas-registry:8080 +basyx.submodelrepository.feature.registryintegration=http://sm-registry:8080 +basyx.externalurl=http://localhost:8081 diff --git a/examples/BaSyxDatabridge/basyx/aas-registry.yml b/examples/BaSyxDatabridge/basyx/aas-registry.yml new file mode 100644 index 000000000..4fac8db3a --- /dev/null +++ b/examples/BaSyxDatabridge/basyx/aas-registry.yml @@ -0,0 +1,4 @@ +basyx: + cors: + allowed-origins: '*' + allowed-methods: GET,POST,PATCH,DELETE,PUT,OPTIONS,HEAD diff --git a/examples/BaSyxDatabridge/basyx/sm-registry.yml b/examples/BaSyxDatabridge/basyx/sm-registry.yml new file mode 100644 index 000000000..4fac8db3a --- /dev/null +++ b/examples/BaSyxDatabridge/basyx/sm-registry.yml @@ -0,0 +1,4 @@ +basyx: + cors: + allowed-origins: '*' + allowed-methods: GET,POST,PATCH,DELETE,PUT,OPTIONS,HEAD diff --git a/examples/BaSyxDatabridge/databridge/AirQualityTransformer.jsonata b/examples/BaSyxDatabridge/databridge/AirQualityTransformer.jsonata new file mode 100644 index 000000000..af93b795f --- /dev/null +++ b/examples/BaSyxDatabridge/databridge/AirQualityTransformer.jsonata @@ -0,0 +1 @@ +airQuality \ No newline at end of file diff --git a/examples/BaSyxDatabridge/databridge/HumidityTransformer.jsonata b/examples/BaSyxDatabridge/databridge/HumidityTransformer.jsonata new file mode 100644 index 000000000..6506bbd58 --- /dev/null +++ b/examples/BaSyxDatabridge/databridge/HumidityTransformer.jsonata @@ -0,0 +1 @@ +humidity \ No newline at end of file diff --git a/examples/BaSyxDatabridge/databridge/TemperatureTransformer.jsonata b/examples/BaSyxDatabridge/databridge/TemperatureTransformer.jsonata new file mode 100644 index 000000000..4d81bb0f8 --- /dev/null +++ b/examples/BaSyxDatabridge/databridge/TemperatureTransformer.jsonata @@ -0,0 +1 @@ +temperature \ No newline at end of file diff --git a/examples/BaSyxDatabridge/databridge/aasserver.json b/examples/BaSyxDatabridge/databridge/aasserver.json new file mode 100644 index 000000000..2d6509135 --- /dev/null +++ b/examples/BaSyxDatabridge/databridge/aasserver.json @@ -0,0 +1,20 @@ +[ + { + "uniqueId": "TemperatureAAS", + "submodelEndpoint": "http://host.docker.internal:8081/submodels/YjdlNTA2NzgtZGY3Mi00ODAxLWI3YzAtNzI2NTNkMmU0NzI0", + "idShortPath": "TemperatureValue", + "api": "DotAAS-V3" + }, + { + "uniqueId": "HumidityAAS", + "submodelEndpoint": "http://host.docker.internal:8081/submodels/YjdlNTA2NzgtZGY3Mi00ODAxLWI3YzAtNzI2NTNkMmU0NzI0", + "idShortPath": "HumidityValue", + "api": "DotAAS-V3" + }, + { + "uniqueId": "AirQualityAAS", + "submodelEndpoint": "http://host.docker.internal:8081/submodels/YjdlNTA2NzgtZGY3Mi00ODAxLWI3YzAtNzI2NTNkMmU0NzI0", + "idShortPath": "AirQualityValue", + "api": "DotAAS-V3" + } +] diff --git a/examples/BaSyxDatabridge/databridge/jsonatatransformer.json b/examples/BaSyxDatabridge/databridge/jsonatatransformer.json new file mode 100644 index 000000000..691253839 --- /dev/null +++ b/examples/BaSyxDatabridge/databridge/jsonatatransformer.json @@ -0,0 +1,20 @@ +[ + { + "uniqueId": "TemperatureTransformer", + "queryPath": "TemperatureTransformer.jsonata", + "inputType": "JsonString", + "outputType": "JsonString" + }, + { + "uniqueId": "HumidityTransformer", + "queryPath": "HumidityTransformer.jsonata", + "inputType": "JsonString", + "outputType": "JsonString" + }, + { + "uniqueId": "AirQualityTransformer", + "queryPath": "AirQualityTransformer.jsonata", + "inputType": "JsonString", + "outputType": "JsonString" + } +] \ No newline at end of file diff --git a/examples/BaSyxDatabridge/databridge/mqttconsumer.json b/examples/BaSyxDatabridge/databridge/mqttconsumer.json new file mode 100644 index 000000000..5a6f7c890 --- /dev/null +++ b/examples/BaSyxDatabridge/databridge/mqttconsumer.json @@ -0,0 +1,8 @@ +[ + { + "uniqueId": "EnvironmentalSensorMQTT", + "serverUrl": "mosquitto", + "serverPort": 1883, + "topic": "EnvironmentalSensor/CombinedData" + } +] diff --git a/examples/BaSyxDatabridge/databridge/routes.json b/examples/BaSyxDatabridge/databridge/routes.json new file mode 100644 index 000000000..887c84db5 --- /dev/null +++ b/examples/BaSyxDatabridge/databridge/routes.json @@ -0,0 +1,22 @@ +[ + { + "datasource": "EnvironmentalSensorMQTT", + "transformers": [ + "TemperatureTransformer", + "HumidityTransformer", + "AirQualityTransformer" + ], + "datasinks": [ + "TemperatureAAS", + "HumidityAAS", + "AirQualityAAS" + ], + "datasinkMappingConfiguration": + { + "TemperatureAAS": ["TemperatureTransformer"], + "HumidityAAS": ["HumidityTransformer"], + "AirQualityAAS": ["AirQualityTransformer"] + }, + "trigger": "event" + } +] diff --git a/examples/BaSyxDatabridge/docker-compose.yml b/examples/BaSyxDatabridge/docker-compose.yml new file mode 100644 index 000000000..01a180222 --- /dev/null +++ b/examples/BaSyxDatabridge/docker-compose.yml @@ -0,0 +1,89 @@ +services: + # AAS Environment + aas-env: + image: eclipsebasyx/aas-environment:2.0.0-SNAPSHOT + container_name: aas-env + volumes: + - ./aas:/application/aas + - ./basyx/aas-env.properties:/application/application.properties + ports: + - '8081:8081' + restart: always + depends_on: + aas-registry: + condition: service_healthy + sm-registry: + condition: service_healthy + + # AAS Registry + aas-registry: + image: eclipsebasyx/aas-registry-log-mem:2.0.0-SNAPSHOT + container_name: aas-registry + ports: + - '8082:8080' + volumes: + - ./basyx/aas-registry.yml:/workspace/config/application.yml + restart: always + + # Submodel Registry + sm-registry: + image: eclipsebasyx/submodel-registry-log-mem:2.0.0-SNAPSHOT + container_name: sm-registry + ports: + - '8083:8080' + volumes: + - ./basyx/sm-registry.yml:/workspace/config/application.yml + restart: always + + # AAS Web UI + aas-web-ui: + image: eclipsebasyx/aas-gui:v2-241006 + container_name: aas-ui + ports: + - '3000:3000' + environment: + AAS_REGISTRY_PATH: http://localhost:8082/shell-descriptors + SUBMODEL_REGISTRY_PATH: http://localhost:8083/submodel-descriptors + AAS_REPO_PATH: http://localhost:8081/shells + SUBMODEL_REPO_PATH: http://localhost:8081/submodels + CD_REPO_PATH: http://localhost:8081/concept-descriptions + restart: always + depends_on: + aas-env: + condition: service_healthy + + # MQTT Broker + mosquitto: + image: eclipse-mosquitto:2.0.15 + container_name: mosquitto + ports: + - 1883:1883 + volumes: + - ./mosquitto:/mosquitto + healthcheck: + test: ["CMD-SHELL", mosquitto_sub -p 1883 -t 'topic' -C 1 -E -i probe -W 3] + interval: 5s + retries: 3 + start_period: 1s + timeout: 10s + restart: always + + # MQTT Publisher (for testing) + mqtt-publisher: + build: ./mqtt-publisher + container_name: mqtt-publisher + depends_on: + - mosquitto + restart: always + + # DataBridge + databridge: + image: eclipsebasyx/databridge:1.0.0-SNAPSHOT + container_name: databridge + volumes: + - "./databridge:/usr/share/config" + depends_on: + - mosquitto + - aas-env + restart: always + diff --git a/examples/BaSyxDatabridge/mosquitto/config/mosquitto.conf b/examples/BaSyxDatabridge/mosquitto/config/mosquitto.conf new file mode 100644 index 000000000..d05bdebdb --- /dev/null +++ b/examples/BaSyxDatabridge/mosquitto/config/mosquitto.conf @@ -0,0 +1,23 @@ +# Default listener port for unencrypted connections (usually 1883) +listener 1883 0.0.0.0 + +# Path to the directory where persistence information is stored. +# Remove or comment out to disable persistence. +persistence true +persistence_location /mosquitto/data/ + +# Log settings +log_dest file /mosquitto/log/mosquitto.log +log_type all + +# Connection settings +# Setting for maximum concurrent connections. -1 means unlimited. +max_connections -1 + +# Security settings +# Uncomment and set these for enabling username-password authentication. +#allow_anonymous false +#password_file /mosquitto/config/mosquitto_passwd + +# Other settings like SSL/TLS, ACLs, etc., can also be configured as needed. +allow_anonymous true diff --git a/examples/BaSyxDatabridge/mqtt-publisher/Dockerfile b/examples/BaSyxDatabridge/mqtt-publisher/Dockerfile new file mode 100644 index 000000000..9883c13ca --- /dev/null +++ b/examples/BaSyxDatabridge/mqtt-publisher/Dockerfile @@ -0,0 +1,7 @@ +FROM python:3.8-slim + +RUN pip install paho-mqtt + +COPY publisher.py /publisher.py + +CMD ["python", "/publisher.py"] \ No newline at end of file diff --git a/examples/BaSyxDatabridge/mqtt-publisher/publisher.py b/examples/BaSyxDatabridge/mqtt-publisher/publisher.py new file mode 100644 index 000000000..9a56afbd5 --- /dev/null +++ b/examples/BaSyxDatabridge/mqtt-publisher/publisher.py @@ -0,0 +1,47 @@ +import time +import random +import json +import paho.mqtt.client as mqtt + +# MQTT settings +broker_address = "mosquitto" +port = 1883 +base_topic = "EnvironmentalSensor/" + +# Connect to MQTT Broker +client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, "Client") +client.connect(broker_address, port) + +# Start the network loop in a separate thread +client.loop_start() + +try: + + while True: + # Generate different types of dynamic data + temperatureValue = random.uniform(0, 30) + humidityValue = random.uniform(0.0, 100.0) + airQualityValue = random.uniform(0.0, 1000.0) + + # Create a dictionary with all values + data = { + "temperature": temperatureValue, + "humidity": humidityValue, + "airQuality": airQualityValue + } + + # Convert the dictionary to a JSON string + json_data = json.dumps(data) + + # Publish dynamic data to respective subtopics + client.publish(base_topic + "Temperature", temperatureValue) + client.publish(base_topic + "Humidity", humidityValue) + client.publish(base_topic + "AirQuality", airQualityValue) + client.publish(base_topic + "CombinedData", json_data) + + # Wait for a short period before publishing the next set of values + time.sleep(1) +except KeyboardInterrupt: + # Stop the network loop if the script is interrupted + client.loop_stop() + client.disconnect()