laravel9使用Mqtt

本文介绍了如何使用PHPLaravel框架创建自定义命令行工具MqttSubscribe,用于处理MQTT订阅并实现特定事件处理。涉及MqttServer类的创建、配置以及使用自定义指令进行测试。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、创建自定义指令控制器

php artisan make:command MqttSubscribe

该命令会在app/Console/Commands下生成一个MqttSubscribe.php的类

二、修改MqttSubscribe.php

<?php

namespace App\Console\Commands;

use App\extend\mqtt\MqttServer;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Cache;

//php artisan make:command MqttSubscribe

/**
 * 订阅MQTT消息
 * Class MqttSubscribe
 * @package App\Console\Commands
 */
class MqttSubscribe extends Command
{
    /**
     * The name and signature of the console command.
     * @var string
     */
    protected $signature = 'mqtt:sub';

    /**
     * The console command description.
     * @var string
     */
    protected $description = 'MQTT订阅消息';

    /**
     * 订阅事件
     * @var array
     */
    public $handleSubFun = [];

    /**
     * socket
     * @var
     */
    protected $socket;

    public function handle()
    {
        dump("开启订阅");
        $this->bindSubFun();
        $this->start();
    }

    protected function start()
    {
        $mqttServer = new MqttServer();

        $topics = [
            'server/v1' => $this->handleSubFun['server/v1'],
        ];

        $mqttServer->subscribe($topics, 0);
        while ($mqttServer->proc()) {
        }
        $mqttServer->close();
    }

    /**
     * 绑定事件
     */
    public function bindSubFun()
    {
        $this->handleSubFun["server/v1"] = ['qos' => 0, 'function' => function ($topic, $msg) {
            $msg = json_decode($msg, true);
            if($msg){
                try {
                    switch ($msg['event']){
                        case "event1":
//                    消息返回事件类型1
                            break;
                        case "event2":
//                    消息返回事件类型2
                            break;
                        default:
                            dump('其它消息',$msg);
                            break;
                    }

                }catch (\Exception $exception){
//代码报错信息
                    dump($exception->getMessage());
                }
            }
        }];
    }
}

三、在app/extend/mqtt/下创建MqttServer.php文件写入

<?php
namespace App\extend\mqtt;

use App\Traits\MqttHandle;
use Bluerhinos\phpMQTT;

/**
 * MQTT服务
 * Class MqttServer
 * @package App\extend\mqtt
 */
class MqttServer extends phpMQTT
{
    use MqttHandle;

    public function __construct()
    {
        $config = config('app.mqtt');
        $server = $config['server'];     // 你的mqtt地址
        $port = $config['port'];                     // 你的mqtt端口
        $username = $config['username'];                   // 账号
        $password = $config['password'];                   // 密码
        $client_id = 'phpMQTT_subscriber_' . uniqid(); // 生成连接唯一id
        $ca_crt_file = $config['ca_crt'];    // mqtt的ssl证书(不使用sll可不写)

        parent::__construct($server, $port, $client_id,$ca_crt_file);
//        $this->debug = true;
        if (!$this->connect(true, NULL, $username, $password)) {
            echo '连接失败';
            exit(1);
        }

    }

    /**
     * 设备开门
     * @param $imei
     * @param $lock_id string 1左边门 2右边门
     */
    public function openDoor($imei,$lock_id){
        $this->sendMsg('device/'.$imei,'server.openDoor',['lock_no'=>$lock_id]);
    }

    /**
     * 发送请求
     * @param $topic string 设备监听主题
     * @param $event string 事件
     * @param $extra_params array 参数
     */
    public function sendMsg($topic, $event, $extra_params = []){
        $arr = explode(' ', microtime());
        $client_id = 'server-' . (date('dHis', $arr[1]) . '' . str_replace('0.', '', $arr[0]) . rand(1000, 9999));
        $payload = [
            'uid' => $client_id,
            'msgid' => $event.'_'.uniqid(),
            'event' => $event,
            'time' => (string)time()
        ];
        $payload = array_merge($payload, $extra_params);
        $payload['sign'] = $this->MakeSign($payload);// 根据自己的签名规则修改

        $payload = json_encode($payload);
        $this->publish($topic,$payload,0,false);
    }

    /**
     * 生成签名
     * @param $arr
     * @return string
     */
    public function makeSign($arr)
    {
        //签名步骤一:按字典序排序参数
        ksort($arr);
        $string = $this->toUrlParams($arr);
        //签名步骤二:在string后加入KEY
        $string = $string . "&key=" . $this->mqtt_key;
        //签名步骤三:MD5加密
        $string = md5($string);
        //签名步骤四:所有字符转为大写
        return strtoupper($string);
    }

    public function toUrlParams($arr)
    {
        $buff = "";
        foreach ($arr as $k => $v) {
            if ($k != "sign" && $v != "" && !is_array($v)) {
                $buff .= $k . "=" . $v . "&";
            }
        }
        $buff = trim($buff, "&");
        return $buff;
    }

    /**
     * post请求
     * @param $url
     * @param $data
     * @return bool|mixed|string
     */
    public function curlPost($url,$data){
        $username = 'admin';
        $password = 'public';
        $data = json_encode($data);
        $ch = curl_init();
        //设置post方式提交
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_TIMEOUT, 2);// 异步
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
            'Content-Type: application/json',
        ));
        curl_setopt($ch, CURLOPT_USERPWD, "{$username}:{$password}");
        curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $return = curl_exec($ch);
        return json_decode($return, true);
    }
}

四、在app/Traits下创建MqttHandle.php文件(改写mqtt轮训的debug返回)

<?php

namespace App\Traits;

trait MqttHandle
{
    /**
     * 开启轮训处理
     * @param bool $loop
     * @return bool | string
     */
    public function proc($loop = true)
    {
        if (feof($this->socket)) {
            $this->_debugMessage('eof receive going to reconnect for good measure');
            fclose($this->socket);
            $this->connect_auto(false);
            if (count($this->topics)) {
                $this->subscribe($this->topics);
            }
        }

        $byte = $this->read(1, true);

        if ((string)$byte === '') {
            if ($loop === true) {
                usleep(100000);
            }
        } else {
            $cmd = (int)(ord($byte) / 16);
            $this->_debugMessage(
                sprintf(
                    'Received CMD: %d (%s)',
                    $cmd,
                    isset(static::$known_commands[$cmd]) === true ? static::$known_commands[$cmd] : 'Unknown'
                )
            );

            $multiplier = 1;
            $value = 0;
            do {
                $digit = ord($this->read(1));
                $value += ($digit & 127) * $multiplier;
                $multiplier *= 128;
            } while (($digit & 128) !== 0);

            $this->_debugMessage('Fetching: ' . $value . ' bytes');

            $string = $value > 0 ? $this->read($value) : '';

            if ($cmd) {
                switch ($cmd) {
                    case 3: //Publish MSG
                        $return = $this->message($string);
                        if (is_bool($return) === false) {
                            return $return;
                        }
                        break;
                }
            }
        }

        if ($this->timesinceping < (time() - $this->keepalive)) {
            $this->_debugMessage('not had something in a while so ping');
            $this->ping();
        }

        if ($this->timesinceping < (time() - ($this->keepalive * 2))) {
            $this->_debugMessage('not seen a packet in a while, disconnecting/reconnecting');
            fclose($this->socket);
            $this->connect_auto(false);
            if (count($this->topics)) {
                $this->subscribe($this->topics);
            }
        }

        return true;
    }
}

五、使用自定义指令测试

php artisan mqtt:sub

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值