阿里云物联网平台为设备提供安全可靠的连接通信能力,支撑设备数据采集上云,我们这里认为阿里云物联网平台是MQTT服务端,那么我们自己的设备作为客户端,应该如何实现消息订阅?
阿里云没有提供PHP的SDK,而MQTT是一个通用协议,我们可以使用PHP实现MQTT协议解析相关代码,同时也可以使用 Swoole 作为 MQTT 服务端或客户端
Simps框架基于Swoole的TCP Server
和Co\Client
集成了MQTT服务端和客户端
这篇文章就以Simps框架作为演示,实现MQTT客户端连接阿里云物联网平台设备进行消息订阅
创建产品/设备
使用物联网平台的第一步是在云端创建产品和对应设备,我们需要前往阿里云物联网平台创建产品和设备,具体操作请参考文档
创建完成后分别在产品详情和设备详情中获取设备证书(ProductKey
、ProductSecret
、DeviceName
和DeviceSecret
),后面连接时需要用到
代码实现
示例代码放在了GitHub上:simps-cloud/aliyun-iot,可以使用composer进行安装或者直接使用git clone源码
composer create-project simps-cloud/aliyun-iot
git clone [email protected]:simps-cloud/aliyun-iot.git
实现说明
下面我们分别来说明一下对应的代码实现,使用Swoole作为客户端可以保证我们recv
到一个完整的MQTT包,然后解析对应的数据包即可
配置文件
创建config/aliyuniot.php
配置文件
client_id
是MQTT建立连接时需要指定的ClientID,保证全局唯一就可以
将我们刚才获取的设备证书信息,写入到对应的配置文件中
return [
// 连接域名
'host' => "{$YourProductKey}.iot-as-mqtt.{$region}.aliyuncs.com",
// 端口默认1883
'port' => 1883,
// 心跳
'keepalive' => 300,
// clientID
'client_id' => "d812edc1-18da-2085-0edf-a4a588c296d1",
'device_name' => "",
'device_secret' => "",
'product_key' => "",
'product_secret' => "",
];
连接密码
MQTT建立连接时需要指定的Password,而这个密码有阿里云的要求:需要把提交给服务器的参数(ProductKey、DeviceName、timestamp和clientId)按字典排序并拼接后,使用hmacsha256
方法和设备的DeviceSecret
,加签生成Password
文档中解释了一下clientId、securemode等参数,其实是说连接时的参数,而不是Password的生成,不要被误导了,实际上只需要关注content的值就可以…
而对于的签名算法类型,PHP可以使用hash_hmac
函数来实现,所以密码生成可以封装为:
/**
* @param $config
* @param string $signmethod 签名算法类型。支持hmacmd5,hmacsha1和hmacsha256,默认为hmacmd5
*/
function signAliIot($config, $signmethod = "hmacmd5")
{
$sign_config = [
'clientId' => $config['client_id'],
'productKey' => $config['product_key'],
'deviceName' => $config['device_name'],
];
ksort($sign_config);
$data = "";
foreach ($sign_config as $key => $item) {
$data .= $key . $item;
}
switch ($signmethod){
case "hmacmd5":
$sign = hash_hmac('md5', $data, $config['device_secret']);
break;
case "hmacsha1":
$sign = hash_hmac('sha1', $data, $config['device_secret']);
break;
case "hmacsha256":
$sign = hash_hmac('sha256', $data, $config['device_secret']);
break;
}
return strtoupper($sign);
}
Password生成没有加时间戳参数,我测试的时候加上时间戳会导致连接失败,返回错误码是4,username或password格式错误
连接
Password我们搞定之后就可以开始连接了,参考代码bin/subscribe.php
使用Simps\Client\MQTTClient
进行连接操作
我们收到消息时,如果QoS是1,根据MQTT协议我们需要回复ACK,否则它会推送多次
$buffer = $client->recv();
var_dump($buffer);
if (is_array($buffer)) {
switch ($buffer['cmd']) {
case 9:
echo "收到订阅确认消息\r\n";
break;
case 3:
echo "收到订阅消息:{$buffer['content']}\r\n";
// 收到消息如果是qos 1 需要回复
if ($buffer['qos'] === 1) {
$client->sendBuffer(['cmd' => MQTT::PUBACK, 'message_id' => $buffer['message_id']], false); // 4
}
break;
}
}
执行命令启动订阅
php bin/subscribe.php
这个时候我们去访问阿里云控制台中的设备详情,会发现DeviceName旁边的在线
标识
可以测试一下延迟,测试网络延迟时将会向设备发送一条QoS1的空消息,会看到网络延迟,表示我们客户端是正常的
但这样还不够,如何发送指定消息到客户端呢?
依旧在设备详情中点击Topic列表
->自定义 Topic
,就可以看到发布消息的按钮,我们可以点击进入填写发布消息内容并选择对应的QoS等级,阿里云暂不支持QoS2,所以只有0和1
我们来发一个Hello,Simps.
Simps的MQTTClient也支持发布功能,这里简单说明一下,执行命令启动并访问一次
php bin/simps.php http:start
curl http://127.0.0.1:9501/
这里需要查看阿里云日志服务,会看到一条设备到云消息
的记录,我们查看一下
以上就是基于Swoole使用MQTT协议进行TCP连接通信,支持请前往点个Star:Simps、Swoole
当然也可以使用Swoole来实现一个MQTT服务端,Simps也提供了相应的封装,参考Simps文档
我之前项目中用的是EMQ X的MQTT broker,插件生态十分丰富,倒是没具体了解过阿里云的
一脸懵逼进来,然后膜拜一下,再一脸懵逼出去