Table of Contents

RADIUSdesk MQTT Implementation

Introduction

Architecture

ExtJS GUI

CakePHP

API Gateway

Mesh nodes and access points

Enable MQTT

Looking at the code

Command -> CakePHP Controller

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
         }
     }
}

Command -> API Gateway

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);
});

Command -> mqtt.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)

Response -> mqtt.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

Response -> API Gateway

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;

Response -> CakePHP Controller

//--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')
        ));
    }
}