Implement MQTT client for react system

The purpose of MQTT-Reactive is to provide a portable and non-blocking MQTT client written in C for use in reactive embedded systems. First, this article explains what a reactive system is. It then describes how to design suitable software structures for such systems. Finally, the article shows how to use the MQTT-Reactive library in a reactive system by using the state machine and event-driven paradigm. To this end, this article uses a real IoT device as a demonstration example, from which its software structure and state-based behavior are explained by using UML diagrams such as state machines, interactions, and structures. This article also provides a guideline for implementing an MQTT-Reactive client for IoT devices using C language.

Many embedded systems are reactive, meaning they react to internal or external events. After these reactions are complete, the software returns to wait for the next event. This is why event-driven systems are called reactive systems.

Event-driven programming or reactive programming is one of the most suitable programming paradigms to achieve flexible, predictable and maintainable software for reactive systems. In this paradigm, the flow of the program is determined by events. Typically, the structure of reactive software consists of several concurrent units (called active objects) that wait for and process various events. Each active object has a thread of control and an event queue through which its incoming events are processed. In reactive systems, active objects typically have state-based behavior defined in a state diagram.

To explore how to use the MQTT-Reactive library in a reactive system with multiple concurrent tasks, using both state machine and event-driven paradigms, we take an IoT device as an example.

The idea of ​​using the MQTT protocol was born while developing IoT devices for railway companies. The device is a clear response system capable of:

Detect and store changes to several numeric inputs

Acquire, filter and store multiple analog signals

Periodically send stored information to a remote server

Send and receive information via MQTT protocol on GSM network

MQTT was chosen because it is a lightweight publisher-subscriber based messaging protocol commonly used in IoT and network applications that require high latency and low data rate links, such as GSM networks.

By using a modified version of LiamBindle's MQTT-C, the MQTT functionality of the above IoT devices can be implemented. Since the device's software is designed to be reactive software, MQTT-C must be modified to communicate it with the rest of the system by exchanging asynchronous events. These events are used to receive and send traffic over the network, as well as connect and publish sensitive information to the server. The resulting software library is called MQTT-Reactive.

state machine

As shown in Figure 1, MQTT-Reactive is used through a state machine that models the basic behavior of an MQTT-Reactive client. It is an active object called MqttMgr (MQTT Manager). The state machine operation in Figure 1 demonstrates how to use the MQTT-Reactive library from a state machine. Even though C language is used as the operating language in Figure 1, any computer or formal language can be used.

Figure 1. State machine of MQTT-Reactive client

The state machine in Figure 1 starts in the WaitingForNetConnection state. After establishing a network connection with the server, WaitingForNetConnection receives the Activate event, and then the state machine transitions to the WaitingForSync state. Only in this state can the state machine pass MQTT messages to the broker, such as CONNECT or PUBLISH via the Connect and Publish events respectively. The Sync state uses UML's special mechanism to defer the Publish event, which is specified by the defer keyword in the internal compartment of the Sync state. If a Publish event occurs while Sync is in the current state, it will be saved (delayed) for future processing until the SM enters a state where the Publish event is not in its list of deferred events (such as WaitingForSync or WaitingForNetConnection). Upon entering such a state, the state machine will automatically invoke any saved Publish event and then use or discard this event depending on the transition target state.

Every SyncTime milliseconds, the state machine transitions to the Sync composite state, which actually sends and receives traffic from the network by publishing Receive and Send events to the network manager. It is a concurrent entity that handles network issues.

Even though the introduced MqttMgr only supports CONNECT and PUBLISH packets, it can also support SUBSCRIBE packets with a simple change.

The state machine uses the params keyword to operate access to the parameters of the consumer event. For example, in the following transformation, the Connect event contains two parameters clientId and keepAlive, whose values ​​are used to update the properties of the corresponding MqttMgr object:

In this example, the Connect(clientId, keepAlive) event is the trigger for the transition, and the mqtt_connect() call is part of the operation performed by this. In other words, when the MqttMgr object receives the Connect(clientId, keepAlive) event, Connect("publishing_client", 400) with parameters 'publishing_client' and '400', the MqttMgr's clientId and keepAlive properties will be updated with the values ​​'Hence, "publishing_client" and "400".

To create and send events, state machine actions use the GEN() macro. For example, the following statement sends the Receive event to the Collector object, which is referenced by the Collector pointer as a property of the MqttMgr object:

The first parameter of the GEN() statement is the object to receive the event, while the second parameter is the event to be sent, including the event parameters (if any). Parameters must match event parameters. For example, the following statement generates a ConnRefused(code) event and passes it as an event parameter to the Broker return and sends it to the Collector object:

The idea of ​​using the params keyword to access the parameters of a consumed event and using the GEN() macro to generate events from an action was adopted from Rational Rhapsody Developer's code generator and is used for illustration purposes only.

The default action of the state machine in Figure 1 sets up a callback that is called by MQTT-Reactive when a connection accept is received from the broker. This callback should be implemented in the MqttMgr code. This callback must generate a ConnAccepted or ConnRefused(code) event to be sent to the Collector object as shown below.

Model implementation

The model in Figure 1 can be implemented in C or C++ by using your favorite software tool or simply using your own state machine implementation. There are many different tools available on the Internet to do this, such as RKH framework, QP framework, Yakindu Statechart tool or Rational Rhapsody Developer and many more. They both support Statecharts and C/C++ languages. Moreover, some of these tools include tools for drawing Statechart diagrams and generating code from them.

This state machine is executed from an active object called MqttMgr (MQTT Manager), which provides a strict encapsulation of the MQTT-Reactive code, and it is the only entity allowed to call any MQTT-Reactive function or access MQTT-Reactive data . Other concurrent entities in the system as well as all ISRs can only use MQTT-Reactive indirectly by exchanging events with MqttMgr. Using this mechanism to synchronize concurrent entities and share data between them avoids the dangers of dealing with traditional blocking mechanisms such as semaphores, mutexes, delays or event flags. These mechanisms can lead to tedious and unexpected failures that are difficult to diagnose and fix.

The MqttMgr activity object encapsulates its properties as a set of data items. A data item specifies a variable using a name and a type, where the type is actually the data type. The data items of the MqttMgr object are mapped to the members of the object structure. The members have the same name and type as the object's data. For example, the client attribute of the MqttMgr object type is embedded in the MqttMgr structure as a data member by value:

The data of an MqttMgr object can be accessed and modified directly without using accessor or mutator operations. For example, client and localRecv are accessible through the me pointer to the MqttMgr instance.

The attribute list of MqttMgr is shown in Table 1.

Table 1. MqttMgr properties

The structure in Figure 2 helps keep in mind the relationships between relevant actors. They are: the Collector object, which wants to send information to the broker; the NetMgr object, which handles the network; and the MqttMgr object.

Figure 2. Draft IoT system structure

The sequence diagram in Figure 3 shows how the MqttMgr object interacts with the rest of the system when a session to the MQTT server needs to be opened. In this diagram, the MqttMgr status and exchanged asynchronous messages are shown between the Collector, MqttMgr and NetMgr actors.

Figure 3. Connecting to the MQTT broker

After the NetMgr object establishes a network connection with the broker, the first packet sent from MqttMgr to the MQTT server must be a CONNECT packet. Therefore, the collector actor sends a Connect(clientId, keepAlive) event to the MqttMgr actor. This event must have a client identifier and a keep-alive interval. If the server accepts the connection request, the MqttMgr actor sends the ConnAccepted event to the Collector actor to notify this situation. From that point on, collector participants can publish informational messages to the broker.

If the server rejects the connection request, the MqttMgr actor sends the ConnRefused event to the Collector actor. This event carries a code that notifies the reason for the rejection, as shown in Figure 4. See MQTT v3.1.1 section 3.2.2.3.

Figure 4. The proxy rejects the connection request

Figure 5 shows the interaction flow when publishing a message. To do this, the collector actor sends a Publish(data, size, topic, qos) event that contains the information to be published (data), the length of the information in bytes (size), the topic name, the information The level of assurance that this message will be published (topic) and delivered (quality assurance). In the IoT device mentioned earlier, the published information is formatted using the JSON specification. It is an open standard format that contains data objects with attribute-value pairs in human-readable text. This formatting is done using jWrite, a simple and lightweight library written in C.

Figure 5. Publishing data to the broker

Figure 6 shows a scenario where the reception and delivery of MQTT messages to the network fails. If the network administrator cannot receive traffic from the network, it will send a ReceiveFail to the MqttMgr actor. Likewise, if the network manager cannot send data to the network, it will send SendFail to the MqttMgr actor.

Figure 6. Network failure

Table 2 summarizes the events involved in the scenarios shown.

Table 2. Events

in conclusion 

By avoiding the dangers of traditional blocking mechanisms such as semaphores, mutexes, delays or event flags, the MQTT-Reactive library, state machines and the software architecture proposed in this paper allow reactive embedded systems to implement MQTT clients in novel ways end. the way. This is achieved by encapsulating the MQTT-Reactive code in a concurrency unit (called an active object) whose state-based behavior is defined in the proposed state machine. This activity object communicates with the rest of the system through asynchronous events used by the exchange: not only for receiving and sending traffic over the network, but also for connecting and publishing information to the server of the IoT application.

There are really a lot of things to learn about the embedded Internet of Things. Don’t learn the wrong route and content, which will cause your salary to go up!

I would like to share with you a data package, which is almost 150 gigabytes. The learning content, interviews, and projects are relatively new and comprehensive! (Click to find an assistant to receive it)

Guess you like

Origin blog.csdn.net/m0_70911440/article/details/132668452