RADIUSdesk

logo

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
technical:mqtt [2022/06/19 21:07]
admin [COMMAND -> API Gateway]
technical:mqtt [2022/06/19 21:48] (current)
admin
Line 43: Line 43:
  
 ===== Looking at the code ===== ===== Looking at the code =====
-==== COMMAND -> CakePHP Controller ==== +==== Command -> CakePHP Controller ==== 
-==== COMMAND -> API Gateway ==== +  * Lets look at the **/var/www/html/cake3/rd_cake/src/Controller/NodeActionsController.php** file. 
-===COMMAND -> mqtt.lua ==== +  * When an action is added to a node and MQTT is enabled on the system this code is executed: 
-==== RESPONSE -> mqtt.lua ====+<code php> 
 +if ($cfg['api_mqtt_enabled'== "1"){ 
 +    //Talk to MQTT Broker 
 +     $data $this->_get_node_mac_mesh_id($formData['node_id']); 
 +     $payload 
 +         'mode'     => 'mesh', 
 +         'node_id'  => $formData['node_id'], 
 +         'mac'      => strtoupper($data['mac']), 
 +         'mesh_id'  => strtoupper($data['ssid']), 
 +         'cmd_id'   => $entity->id, 
 +         'cmd'      => $formData['command'], 
 +         'action'   => $formData['action'], 
 +     ]; 
 + 
 +     if($this->_check_server($client, $cfg['api_gateway_url'], 5)){ 
 +         try { 
 +             $client->request('POST', $cfg['api_gateway_url'] . '/rd/mesh/command', ['json' => ['message' => $payload]]); 
 +         } catch (\Exception $e) { 
 +             // Do Nothing 
 +         } 
 +     } 
 +
 +</code> 
 +==== Command -> API Gateway ==== 
 +  * The API call to the API Gateway will execute this piece of code in the **/opt/Rdcore-API-Gateway/routes/rdmesh.js** file 
 +<code javascript> 
 +router.post('/mesh/command', function(req, res){ 
 +    //var data JSON.parse(req.body.message); 
 +    var data req.body.message; 
 +    var message JSON.stringify(data); 
 + console.log(message); 
 +    client.publish('/RD/MESH/' + data.node_id + '/COMMAND', message); 
 +    console.log("Published command to Mesh node: " + data.mac + " MODE "+data.mode); 
 +    res.json(message); 
 +}); 
 +</code> 
 +==== Command -> mqtt.lua ==== 
 +  * Here is a snippet in **/etc/MESHdesk/mqtt.lua** which shows what it will do when a message is published from the API Gateway. 
 +  * This is the command which it will then respond to. 
 +<code lua> 
 +client.ON_MESSAGE = function(mid, topic, payload) 
 +    -- Parse/Decode JSON Payload 
 +    local jsonStr           = luci_json.parse(payload) 
 +    -- Check if message belongs to us (MAC Address) 
 +</code> 
 +==== Response -> mqtt.lua ==== 
 +  * Depending on the type of command the code in Lua will determine the correct response. 
 +  * Here is a snippet in **/etc/MESHdesk/mqtt.lua** which respond to the **execute** action. 
 +  * 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['action'] we will either just execute the command or execute and report the output 
 +if(jsonStr['action'] == 'execute')then 
 +    print("MODE IS "..mode); 
 +    if(mode == 'mesh')then 
 +        message = luci_json.stringify({mode=mode,node_id=nodeId,mesh_id=meshId,mac=macAddr,cmd_id=cmdId,status='os_command'}); 
 +    end 
 +    if(mode == 'ap')then 
 +        message = luci_json.stringify({mode=mode,ap_id=apId,mac=macAddr,cmd_id=cmdId,status='os_command'}); 
 +    end 
 +     
 +    local cl_execute = mqtt.new(); 
 +    cl_execute:login_set(MQTT_USER, MQTT_PASS) 
 +    cl_execute:connect(MQTT_HOST) 
 +    --Connected now publish 
 +    cl_execute.ON_CONNECT = function() 
 +        cl_execute:publish(cmdTopic, message, qos, retain); 
 +    end 
 +    --Done publishing - now execute command  
 +    cl_execute.ON_PUBLISH = function() 
 +        cl_execute:disconnect(); 
 +        os.execute(jsonStr['cmd']); 
 +    end 
 +    cl_execute:loop_forever();                 
 +end 
 + 
 +</code>
 ==== Response -> API Gateway ==== ==== Response -> API Gateway ====
-==== COMMAND -> CakePHP Controller ====+  * The API Gateway subscribe to the topic which the mesh node or access point publishes to. 
 +  * Here is a snippet from the **/opt/Rdcore-API-Gateway/routes/rdmesh.js** file that execute some code when a message is received on that topic 
 +<code javascript> 
 +default: 
 +    request.put({ 
 +            url: mesh_controller + '/cake3/rd_cake/node-actions/node-command.json', 
 +            form: data 
 +        }, 
 +        function (err, res, body) { 
 +            if (err) { 
 +                console.error('Error Occurred: ' + err); 
 +            } 
 + 
 +            console.log(body); 
 +        } 
 +    ); 
 +    break; 
 +</code> 
 +==== 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 **/var/www/html/cake3/rd_cake/src/Controller/NodeActionsController.php** file. 
 +<code php> 
 +//--This comes from the NodeJS API Gateway Application in response to 'execute' type node_actions 
 +//--This comes from the NodeJS API Gateway Application in FIRST response to 'execute_and_reply' type node_actions 
 +public function nodeCommand(){ 
 + 
 +    if($this->request->is('put')){ 
 +        $data = $this->request->data; 
 +        if((!empty($data['node_id']))||(!empty($data['ap_id']))){ 
 +            // update command status to fetched 
 +            $model = 'NodeActions'; 
 +            if($data['mode'] == 'ap'){ 
 +                $model = 'ApActions'; 
 +            } 
 +             
 +            $entity  = $this->{$model}->find()->where(['id' => $data['cmd_id']])->first(); 
 +            if($entity){ 
 +                $entity->status = 'fetched'; 
 +                $this->{$model}->save($entity); 
 +            } 
 + 
 +            $this->set(array( 
 +                'data'          => $data, 
 +                'success'       => true, 
 +                '_serialize'    => array('data','success'
 +            )); 
 +        } else { 
 +            $this->set(array( 
 +                'message'     => 'Node ID not found', 
 +                'success'       => false, 
 +                '_serialize'    => array('message','success'
 +            )); 
 +        } 
 + 
 +    } else { 
 +        $this->set(array( 
 +            'message'         => 'Send only PUT request', 
 +            'success'       => false, 
 +            '_serialize'    => array('message','success'
 +        )); 
 +    } 
 +
 +</code>