Thin-Edge connection with generic MQTT broker

As it is written in the documentation, thin-edge provides the possibility to connect the edge gateway device with different IoT platforms such as Cumulocity, MS Azure and aws, performing the device enrolment/provisioning with client certificate and activating the proper Mapper component to translate platform specific messages.

My question is related to the connection (using thin-edge framework) with a generic MQTT broker.
Is it possible to connect the edge gateway to a generic MQTT broker (and not directly with a specific IoT platform) and activate a desired Mapper to convert messages?

This functionality could address the case in which there is an intermediate MQTT broker between and edge device (running thin-edge) and a specific IoT platform.

I have another question related the authentication method supported by thin-edge framework to the connection with Cumulocity .
Is it possible to use user/password authentication? or only authentication with client certificate is supported by Thin-edge?

Thanks in advance.

1 Like

Hi @Sid023 and welcome to the IoT Community,

thin-edge.io contains a local MQTT Broker already. So it is not directly connected to any specific IoT platform but leveraging the local MQTT Broker and Mapper in between.
For Cumulocity IoT for example it uses an MQTT Bridge to connect to the Cumulocity IoT MQTT endpoint with the local MQTT Broker bridging all the relevant messages which can be processed by Cumulocity IoT.

If you want to do the same for any other public MQTT Broker you need to extend the thin-edge.io e.g. to bridge to any other MQTT Broker of your choice and provide some custom mappings components to do the mapping in the format you want the data to be published in your broker.
I’m not 100% sure how easy this can be done but maybe @Reuben_Miller2 can give more insights or alternative suggestions.

To your 2nd question:
Currently only client certificates are supported for Cumulocity IoT.

1 Like

Writing a mapper is actually not very difficult, but it really depends on how much “mapping” is really required. If you are happy with the format of the thin-edge.io messages, then you could just manually configure a new mosquitto bridge configuration (e.g. under the /etc/tedge/mosquitto-conf/my-custom-bridge.conf) using mosquitto configuration (see here, mosquitto.conf man page | Eclipse Mosquitto).

If you have to do mapping, then it is just a matter of creating an MQTT client which subscribes to the thin-edge.io topics, and maps the messages to your external broker (either directly, or using the mosquitto bridge configuration).

2 Likes

@Stefan_Witschel , @Reuben_Miller2 thanks for your replies.

What i need to do is just to connect with a generic MQTT broker at transport level and at the same time exploit the c8y mapper in order to use same data and topic format of Cumulocity. No device enrollment/provisioning and other functionalities based on REST API are needed.

What is the best approach to do it? Working ad mosquitto configuration level?
Since i do not need to connect directly with Cumulocity, i would have the possibility to authenticate with a custom broker using both user/psw and certificates. Is it possible?

Thanks

1 Like

mosquitto can handle multiple bridge connections, and each bridge connection can also use independent settings (e.g. different authentication etc.)…

But reading the mosquitto docs should be enlightening, as it is standard mosquitto settings. As a reference you could look at the /etc/tedge/mosquitto-conf/c8y-bridge.conf file (if you have configured the c8y mapper)…

But here is an example of the aws bridge setting…but you could adjust the topics to only map the topics that you are interested in. Using the Cumulocity interface might not give you the expected results as it uses some SmartREST which is very c8y specific…so you’d have to decode the smart rest to actual json messages to do anything with the data.

file: /etc/tedge/mosquitto-conf/custom-bridge.conf (modified aws example)

### Bridge
connection edge_to_myborker
remote_username rpi5-d83add9f145a
address some.example.broker:8883
bridge_capath /etc/ssl/certs
remote_clientid rpi5-d83add9f145a
local_clientid Aws
remote_username myusername
remote_password mysecurepassword
try_private false
start_type automatic
cleansession false
notifications true
notifications_local_only true
notification_topic te/device/main/service/mosquitto-custom-bridge/status/health
bridge_attempt_unsubscribe false

### Topics
topic td/# out 1 aws/ thinedge/rpi5-d83add9f145a/

topic cmd/# in 1 aws/ thinedge/rpi5-d83add9f145a/
#topic cmd/# in 1 te/device/main/// thinedge/rpi5-d83add9f145a/

topic shadow/# both 1 aws/ $aws/things/rpi5-d83add9f145a/
topic "" out 1 aws/test-connection thinedge/devices/rpi5-d83add9f145a/test-connection
topic "" in 1 aws/connection-success thinedge/devices/rpi5-d83add9f145a/test-connection

But looking at the mosquitto docs here: mosquitto.conf man page | Eclipse Mosquitto you will find all of the information about the “mapping” syntax where it can route messages in and out on specific topics. Here is a screenshot of it (since mosquitto don’t have nice anchor links to direct to the exact section)

I’m not sure if I understand your requirements.
Is the device data already available in a generic MQTT Broker but not in the format Cumulocity IoT expect it? If so, check out this:

This is a dynamic mapper that can connect to any generic MQTT Broker and map any data (preferrable JSON formatted data) to the Cumulocity IoT domain model using a graphical interface. It is deployed directly in Cumulocity IoT, so within it you can subscribe to your broker topics, do the mappings and deploy them so they will be executed each time a new message is received by the generic MQTT Broker.

If you want to forward any kind of device data to a generic MQTT Broker you can use thin-edge.io to do so but can decide if you want to do the mapping at thin-edge level or in the cloud (see above). If first option it’s like Reuben mentioned. This is just a simple MQTT client subscribing to your or thin-edge topics and publishing to the c8y topics. If you don’t make any mapping on thin-edge level it’s just the bridging on configuration level.

If the generic MQTT Broker allows user/pw authentication of course you can do so.

1 Like

MQTT Broker just need to act as a passthrough.
The edge device just need to connect to it, publish data (measurements, alarms…) and receive commands, using proper cumulocity topics and data format as it were directly connected with the IoT platform.

Does the c8y mapper is a binary that listen on all thin-edge local topics, proper convert data and then publish it to cumulocity topics to the remote endpoint? Am i right?

What i need is something like calling following command:

sudo tedge connect c8y

but instead to use default c8y settings for the connection, it should use the custom ones (those related to the broker).
I need theh c8y-mapper to be compliant within a cumulocity platform, the broker in this case just acts as a passthrough towards it.

Could the following command address my need?

tedge connect --config-dir <custom_dir> c8y

Does it activate the c8y-mapper and use the a file(containing mosquitto custom bridge configuration) stored into “custom_dir”??

I think I’m missing the point of what you are trying to do. If you are trying to connect to a Cumulocity compliant endpoint, then there is no customization required.

If the purpose is to try to workaround the lack of certificate support in your setup, then I would highly advise to address the issues why you can’t use certificates rather than hacking configuration settings as this will cause headaches in the future when you try to migrate from a non-cert based connection to a cert-based connection (as the Cumulocity IoT device user is not of the same type, so you can’t transition between the two authentication types, without getting into very awkward situations)

1 Like

First of all i just need to connect to a custom MQTT broker having the capability to set connection parameters.
I need to use c8y-mapper in order to use specific cumulocity topics and data format.

I would exploit the c8y-mapper functionalities without being directly connected the cumulocity endpoint.
The MQTT broker must be in the middle between edge device and IoT platform

But the local mosquitto broker is already sitting in the middle of the edge device and the Cumulocity Platform. So I’m a bit sceptical about the approach being take here. Can you expand a bit more on the “why”, because I think the design is going in the wrong direction, but it is a bit hard without having the full context.

Plus the MQTT connection is only one part of the Cumulocity IoT connection. There is also HTTP activity going on to support binary uploads/downloads…so doing some kind of man in the middle setup will most likely break some functionality.

1 Like

It is a constraint that i have, so i must connect to a generic MQTT broker and not directly to the Cumulocity endpoint.

This broker is connected to Cumulocity and it is in charge of the management of the HTTP parts.
For mqtt communication it acts just like a pass through between Cumulocity and the edge gateway where thin-edge is running.
The bridge config of the broker just forward data to and from the connected edge device, so topics and data are those of Cumulocity

For this reason i would know it thin-edge framework can handle this situation. I would know if it is possible to connect to a generic broker and at the same time having the facilities provided by the c8y-mapper

I’m still really confused how such as setup would work in practice…mostly because a broker can’t handle the “HTTP parts”, as those parts are actually called by the tedge-mapper-c8y service…so you can’t really intercept them unless if you also setup your own HTTP endpoint…but I think such a setup would be very fragile, so even if you get it to work now, it probably would break on future changes.

But ignoring the above disclaimer, then you really just want to create a customer bridge config.

Next disclaimer: I have no idea if this works, but it is just to show you how it could be done theoretically…no promises (as I still think this is very much the wrong approach)

  1. Stop the tedge-mapper-c8y service if it is already running

    systemctl stop tedge-mapper-c8y
    
  2. Create your own mosquitto mapper file and place it in /etc/tedge/mosquitto-conf/

    For example, create the following file:

    /etc/tedge/mosquitto-conf/proxy-bridge.conf
    

    And add your “proxy” bridge configuration settings to it. You will have to add your own mapping (following the mosquitto configuration bridge mapping rules), but basically you only need to map messages going in and out of c8y/# to your configured external “proxy” broker.

    The file should be readable by the mosquitto user (this should be enough: chmod 755 /etc/tedge/mosquitto-conf/proxy-bridge.conf).

  3. Delete existing c8y-bridge.conf file (so that mosquitto does not try to connect to the real Cumulocity IoT instance)

    sudo rm -f /etc/tedge/mosquitto-conf/c8y-bridge.conf
    
  4. Restart the mosquitto broker (so the new bridge configurations are re-read from disk)

    sudo systemctl restart mosquitto
    
  5. Start the tedge-mapper-c8y service again

    sudo systemctl start tedge-mapper-c8y
    

    When talking about MQTT messages, the tedge-mapper-c8y service does not talk to the Cumulocity IoT MQTT broker directly, it does it via the mosquitto bridge, so technically if the c8y-bridge.conf file no longer exists, then the mapper will still only publish and subscribe to c8y/# topics.

Good luck.

@Reuben_Miller2 I agree with you: it is bad design choice, but unfortunately it is a constraint that i have, so it is not possible to directly connect to the Cumulocity.

I did what you suggested me, and it is ok. Setting-up mosquitto bridge configuration on topics c8y/# it’s a good starting point, i can use desired authentication within the mqtt broker and communicate with it. (i don’t know why, but i had not the file /etc/tedge/c8y-bridge.conf)

I tried to the following command to test the c8y-mapper:

mosquitto_pub -t 'tedge/measurements' -m '{
  "temperature": 25
}'

but unfortunately the mapper didn’t do its job, it didn’t convert the message and topics converted in the Cumulocity formats.
Anyway, i use the same command with topic starting from c8y/# the mosquitto bridge correcly does its job forwarding the local message to the broker.

When i run the tedge-mapper-c8y service i got some errors related to the JWT token for HTTP parts, so i think it is not possible use this mapper to only manage mqtt communication.

ERROR c8y_api::http_proxy: Fail to retrieve JWT token after 3 attempts
DEBUG C8YJwtRetriever: send (0, Err(NoJwtReceived))
DEBUG C8Y-REST => JWT: recv Some(Err(NoJwtReceived))
DEBUG rumqttc::state: Disconnect
ERROR c8y_http_proxy::actor: An error occurred while retrieving internal Id, operation will retry in 20 seconds
             Error: CustomError("JWT token not available")
2023-12-18T14:14:30.007831806Z  INFO mqtt_channel::connection: MQTT connection closed

every 20 seconds the mqtt connection is closed due to the error related to obtaining the JWT token.

What are the HTTP parts the mapper currently handles?
Is it possible to have a c8y-mapper that simply handles only mqtt parts?
Does make sense to reimplement the c8y-mapper keeping it as simple as possible? (just to convert topics and data format)

What are the HTTP parts the mapper currently handles?

I would not recommend reimplementing the tedge-mapper-c8y. The mapper is responsible for providing an interface to Cumulocity over both HTTP and MQTT. As this is part of the Cumulocity IoT communication to offer the Device Management features. A JWT is required by the HTTP component for authorization, and the JWT is retrieved via MQTT which is only possible when using a certificate based MQTT connection with Cumulocity IoT.

But I want to take a step back because I still think we’re diving in too quickly to a solution without having the whole picture.

It would be helpful to have a more complete view of the problem, and the reasoning behind why the constraint exists in the first place as I don’t think you’ve alluded to the “why” about the constraint, rather that it just exists. Constraints may have a limited validity, so it is always worthwhile evaluating the whole picture before jumping into very high cost, unreliable solutions.

  • What is the reasoning behind the constraint (is it technical, strategic, political reasons etc.?)
  • How long is the constraint valid for? (e.g. will the constraint be lifted in 6 months, if so then the effort to develop a solution?)
  • Do you need to consider an upgrade path after the constraint is lifted? (if it will ever be lifted)
  • Is the “non-optimal” solution less effort than reevaluating/lifting/living without the constraint?
  • Is the constraint solely based on the fact that you are trying to connect thin-edge.io to a Cumulocity tenant that does not support Certificate based communication?

It would also be helpful to have a simple diagram showing the desired setup.

1 Like