This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
technical:mqtt [2022/06/19 20:07] admin [Introduction] |
technical:mqtt [2022/06/19 21:48] (current) admin |
||
---|---|---|---|
Line 7: | Line 7: | ||
* It is ideal for hardware that is used in a IOT environment where you need immediate execution of commands. | * It is ideal for hardware that is used in a IOT environment where you need immediate execution of commands. | ||
===== Architecture ===== | ===== Architecture ===== | ||
+ | * Consider the following diagram and then the subsequent discussion of each of the components. | ||
{{: | {{: | ||
+ | |||
+ | ==== ExtJS GUI ==== | ||
+ | * The ExtJS GUI can be used to send commands to the mesh nodes and access points managed by MESHdesk and APdesk respectively. | ||
+ | * The communication between ExtJS and the CakePHP application consists of REST-like API calls using HTTP or HTTPS. | ||
+ | * This means essentially that these actions can easily be automated or done with another GUI should the need arise. | ||
+ | |||
+ | ==== CakePHP ==== | ||
+ | * If MQTT support is enabled on the system and someone initiate a command execution action from the GUI, the controller code handling this request will send the request to the API Gateway. | ||
+ | * This communication between the CakePHP controller and the API Gateway also consist of REST-like API calls using HTTP or HTTPS. | ||
+ | |||
+ | ==== API Gateway ==== | ||
+ | * The API Gateway is a Node.js based web service that acts as a middle man. | ||
+ | * The MQTT implementation uses a command and response principle. | ||
+ | * The API Gateway | ||
+ | * Receive instructions from CakePHP and translate them to MQTT **publish** actions (Command) which are published to the Mosquitto MQTT Broker. | ||
+ | * Subscribe to MQTT topics (Response) on the Mosquitto MQTT Broker which will get input from the mesh nodes and access points and translate them to HTTP/HTTPS based API calls to CakePHP. | ||
+ | |||
+ | ==== Mesh nodes and access points ==== | ||
+ | * The mesh nodes and access points communicate with the CakePHP back-end using HTTP/HTTPS to fetch its configuration and do reporting. | ||
+ | * If the system has MQTT support enabled the mesh node or access point will configure itself to publish and subscribe to certain topics on the Mosquitto MQTT Broker. | ||
+ | * The system works on a **command** and **response** principle. | ||
+ | * The mesh node or access point **subscribe** to a topic where it will expect **commands** from the API Gateway. | ||
+ | * The mesh node or access point will **publish** to a topic where the API Gateway expect **responses**. | ||
+ | * The API Gateway will **publish** to a topic where the mesh node or access point expect **commands**. | ||
+ | * The API Gateway will **subscribe** to a topic where the mesh node or access points **publish** their **responses**. | ||
+ | |||
+ | |||
+ | |||
+ | ===== Enable MQTT ===== | ||
+ | * There are two components of the MQTT setup that needs to be configured | ||
+ | * Configuration settings for mesh nodes and access points (MESHdesk and APdesk) | ||
+ | * Configuration settings for the MQTT API Gateway. | ||
+ | |||
===== Looking at the code ===== | ===== Looking at the code ===== | ||
+ | ==== Command -> CakePHP Controller ==== | ||
+ | * Lets look at the **/ | ||
+ | * When an action is added to a node and MQTT is enabled on the system this code is executed: | ||
+ | <code php> | ||
+ | if ($cfg[' | ||
+ | //Talk to MQTT Broker | ||
+ | $data = $this-> | ||
+ | | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ]; | ||
+ | |||
+ | | ||
+ | try { | ||
+ | | ||
+ | } catch (\Exception $e) { | ||
+ | // Do Nothing | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | ==== Command -> API Gateway ==== | ||
+ | * The API call to the API Gateway will execute this piece of code in the **/ | ||
+ | <code javascript> | ||
+ | router.post('/ | ||
+ | //var data = JSON.parse(req.body.message); | ||
+ | var data = req.body.message; | ||
+ | var message = JSON.stringify(data); | ||
+ | console.log(message); | ||
+ | client.publish('/ | ||
+ | console.log(" | ||
+ | res.json(message); | ||
+ | }); | ||
+ | </ | ||
+ | ==== Command -> mqtt.lua ==== | ||
+ | * Here is a snippet in **/ | ||
+ | * This is the command which it will then respond to. | ||
+ | <code lua> | ||
+ | client.ON_MESSAGE = function(mid, | ||
+ | -- Parse/ | ||
+ | local jsonStr | ||
+ | -- Check if message belongs to us (MAC Address) | ||
+ | </ | ||
+ | ==== Response -> mqtt.lua ==== | ||
+ | * Depending on the type of command the code in Lua will determine the correct response. | ||
+ | * Here is a snippet in **/ | ||
+ | * This is part of the code which are processing the command that the mesh node or access point received (inside the **ON_MESSAGE** event) | ||
+ | <code lua> | ||
+ | --Here depending on the value of jsonStr[' | ||
+ | if(jsonStr[' | ||
+ | print(" | ||
+ | if(mode == ' | ||
+ | message = luci_json.stringify({mode=mode, | ||
+ | end | ||
+ | if(mode == ' | ||
+ | message = luci_json.stringify({mode=mode, | ||
+ | end | ||
+ | | ||
+ | local cl_execute = mqtt.new(); | ||
+ | cl_execute: | ||
+ | cl_execute: | ||
+ | --Connected now publish | ||
+ | cl_execute.ON_CONNECT = function() | ||
+ | cl_execute: | ||
+ | end | ||
+ | --Done publishing - now execute command | ||
+ | cl_execute.ON_PUBLISH = function() | ||
+ | cl_execute: | ||
+ | os.execute(jsonStr[' | ||
+ | end | ||
+ | cl_execute: | ||
+ | end | ||
+ | |||
+ | </ | ||
+ | ==== Response -> API Gateway ==== | ||
+ | * The API Gateway subscribe to the topic which the mesh node or access point publishes to. | ||
+ | * Here is a snippet from the **/ | ||
+ | <code javascript> | ||
+ | default: | ||
+ | request.put({ | ||
+ | url: mesh_controller + '/ | ||
+ | form: data | ||
+ | }, | ||
+ | function (err, res, body) { | ||
+ | if (err) { | ||
+ | console.error(' | ||
+ | } | ||
+ | |||
+ | console.log(body); | ||
+ | } | ||
+ | ); | ||
+ | break; | ||
+ | </ | ||
+ | ==== Response -> CakePHP Controller ==== | ||
+ | * Finally we can look at the CakePHP code that process the response so our system know and can indicate the mesh node or access point did receive the instruction. | ||
+ | * Lets look at the **/ | ||
+ | <code php> | ||
+ | //--This comes from the NodeJS API Gateway Application in response to ' | ||
+ | //--This comes from the NodeJS API Gateway Application in FIRST response to ' | ||
+ | public function nodeCommand(){ | ||
+ | |||
+ | if($this-> | ||
+ | $data = $this-> | ||
+ | if((!empty($data[' | ||
+ | // update command status to fetched | ||
+ | $model = ' | ||
+ | if($data[' | ||
+ | $model = ' | ||
+ | } | ||
+ | | ||
+ | $entity | ||
+ | if($entity){ | ||
+ | $entity-> | ||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | $this-> | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | )); | ||
+ | } else { | ||
+ | $this-> | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | )); | ||
+ | } | ||
+ | |||
+ | } else { | ||
+ | $this-> | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | )); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | |||