最近公司有个物联网项目,想试试由自有平台切换到阿里云物联网平台,于是花了点时间对阿里云物联网平台小探了下,这里做个小结,给有同样需求的朋友提供一个参考。
因能力有限,以及考虑到实际业务逻辑,我只是研究了一下我所需要的东西,不敢保证能有多深入,只求能将我所了解了的东西表达出来。
项目前提
起源是公司有个项目,硬件设备后期可能会全国各地都有部署,需要通过2G/3G/4G/5G/WiFi网络及MQTT协议连接到平台服务器,考虑到实际业务需求,所使用的平台必须要能提供保证如下功能:
- 能保证稳定在线,且能在所能考虑的将来容纳需要接入的设备
- 支持与PHP后端系统对接
- 因涉及到用户交互控制,系统上报的消息必须在100ms左右到达后端系统
- 数据可控,不会出现数据拿不到的情况
我们有一套自己开发的平台,但是想试试利用阿里云物模型,实现快速开发部署,以及借鉴阿里云这种大平台的实现方式,想体验一下阿里云物联网平台,于是有了这篇文章。
阿里云物联网数据流传过程
和自建平台差不多,据我的了解,阿里云物联网平台的数据流传过程包含如下几个步骤:
- 新建产品、设备,获取相应的ProductKey、DeviceName、DeviceSecret等信息并通过SDK等接入物联网平台
- 设备上传心跳包、业务数据及报警数据等到物联网平台
- 服务端订阅,通过HTTP/2或者MNS拿到数据
- 服务端处理数据
- 服务端将指令推送到物联网平台
- 设备执行相应的指令
下面是详细步骤。
设备接入阿里云物联网平台
打开阿里云物联网平台:https://iot.console.aliyun.com ,忘了第一次进入要不要进行注册了,如果要的话注册或者购买一下就好了。
因为终端设备在阿里云物联网平台是依附于产品的,所以在设备接入之前,需要先创建一个产品,然后才能添加设备。
然后点击左侧的产品,进入页面之后,点击右上角的创建产品,打开产品创建页面,截图如下:
嗯….忽略上述某个单词拼写错误。
产品名称需要唯一,后面创建设备需要用到。而所属分类,阿里云已经针对目前常见的很多设备做了分类,比如家电、安防等,但是因为我们项目所属的设备都不包含在阿里云预定分类里,我这选的是自定义分类。至于是终端设备还是网关以及是否接入网关,根据需求确定。
而至于联网方式,阿里云物联网平台提供WiFi、2G/3G/4G、以太网也就是网线以及一个LoRaWAN接入,这个貌似有点不便,我们购买的DTU都是支持不止一种接入方式的,比如同时支持蜂窝及WiFi。而数据接入方式,因为想体验一下阿里云的物模型,我这里选择Alink JSON格式。
创建成功之后,进入设备页面,创建相应的设备信息:
创建成功之后,阿里云会立即给出设备的相关连接信息,如图:
这个保不保存都可以,后续可以在设备详情页面找到。
设备关联物模型
创建好产品之后,其实就应该关联物模型,阿里云关于物模型的解释如下:
物模型是对设备在云端的功能描述,包括设备的属性、服务和事件。物联网平台通过定义一种物的描述语言来描述物模型,称之为 TSL (即Thing Specification Language),采用JSON格式,您可以根据TSL组装上报设备的数据。您可以导出完整物模型,用于云端应用开发;您也可以只导出精简物模型,配合设备端SDK实现设备开发。
这个概念用我的理解说人话就是,定义设备能干啥、能执行什么命令等,定义好物模型可以更好地处理设备传来的数据。
根据选择的设备类型的不通,阿里云已经预定义了一些物模型,如图,添加一个示例物模型:
连接设备到阿里云物联网平台
由于是测试,我这里选择使用直接运行阿里云提供的设备SDK的方式连接到阿里云,相关C语言SDK下载地址:
https://code.aliyun.com/linkkit/c-sdk/repository/archive.zip
使用阿里云提供的SDK只需要将设备的相关账号key之类填上直接编译就能运行。
根据阿里云文档,这个SDK需要在Linux下运行,官方推荐是在Ubuntu 16.04,我在Ubuntu 18.04下编译运行也没问题,相关命令如下:
apt-get install -y build-essential make git gcc unzip
wget https://code.aliyun.com/linkkit/c-sdk/repository/archive.zip
unzip archive.zip
然后编辑对应的文件,将对应的设备连接信息加入就行,命令如下:
vim wrappers/os/ubuntu/HAL_OS_linux.c
#ifdef DEVICE_MODEL_ENABLED
char _product_key[IOTX_PRODUCT_KEY_LEN + 1] = "a1RIsMLz2BJ";
char _product_secret[IOTX_PRODUCT_SECRET_LEN + 1] = "fSAF0hle6xL0oRWd";
char _device_name[IOTX_DEVICE_NAME_LEN + 1] = "example1";
char _device_secret[IOTX_DEVICE_SECRET_LEN + 1] = "RDXf67itLqZCwdMCRrw0N5FHbv5D7jrE";
对应的ProductKey、ProductSecret、DeviceName、DeviceSecret可在阿里云的控制面板的产品及设备详情页面找到,对应修改之后,就可以开始编译了:
make distclean
make
1分钟不到即可编译好,成功之后运行如下命令运行编译之后的可执行程序:
./output/release/bin/linkkit-example-solo
执行之后控制台会有输出:
user_initialized.81: Device Initialized
user_connected_event_handler.63: Cloud Connected
> {
> "id": "2",
> "version": "1.0",
> "params": {
> "Counter": 0
> },
> "method": "thing.event.property.post"
> }
user_post_property.231: Post Property Message ID: 2
> {
> "id": "3",
> "version": "1.0",
> "params": {
> "ErrorCode": 0
> },
> "method": "thing.event.HardwareError.post"
> }
user_post_event.242: Post Event Message ID: 3
< {
< "code": 200,
< "data": {
< "Counter": "tsl parse: params not exist"
< },
< "id": "2",
< "message": "success",
< "method": "thing.event.property.post",
< "version": "1.0"
< }
< {
< "code": 460,
< "data": {
< },
< "id": "3",
< "message": "event not exist",
< "method": "thing.event.HardwareError.post",
< "version": "1.0"
< }
user_report_reply_event_handler.93: Message Post Reply Received, Message ID: 2, Code: 200, Reply: {"Counter":"tsl parse: params not exist"}
user_trigger_event_reply_event_handler.104: Trigger Event Reply Received, Message ID: 3, Code: 460, EventID: HardwareError, Message: event not exist
阿里云控制台能看到终端已经在线了:
虽然有报错,但是至少连接到了阿里云。这个报错也诡异,竟然在Google都搜索不到是因为什么报错的。下一步就是通过阿里云物联网平台拿到设备上报的数据了。
服务端订阅阿里云物联网平台数据
阿里云物联网平台提供了两种方式供我们开发者获取设备的数据,分别是HTTP/2推送以及MNS消息服务,两种都可以获取数据,其中HTTP/2是物联网平台原生支持的,MNS相当于通过了一层中转,数据可能有一定的延迟,如果可以,当然推荐使用HTTP/2了。
但是这里有个问题就是,HTTP/2推送SDK目前(2019.08)只支持Java和.Net两种开发语言的SDK(来源),如果后端是Java和.Net,可以考虑使用HTTP/2,但是因为我们是PHP,所以只能选择使用MNS推送的方式进行获取数据。
要通过MNS获取数据,还需要在物联网后台设置一下,让阿里云将设备上传的数据转发到MNS服务。
将物联网数据转发到MNS
点击阿里云控制台左侧的产品连接,从产品列表进入对应的产品详情页面,然后切换到服务端订阅选项卡,如图:
然后点击服务端订阅(推送MNS)右侧的设置按钮,在弹出的窗口选择需要的消息类型,然后保存,如图:
保存完毕之后会给出对应的区域及队列名称,这个在后面使用MNS服务的时候用到,如图:
通过阿里云MNS获取物联网设备数据
设置好了之后,我们即可以通过MNS获取到我们设备上传的数据,于此同时,我们也能在MNS控制板看到我们创建的MNS队列信息,MNS控制面板地址:
https://mns.console.aliyun.com
进去之后,可能会提示创建一个子账户,为了安全,根据提示创建一个就好。
而MNS的SDK就比较多了,PHP版的相关下载地址:https://github.com/aliyun/aliyun-mns-php-sdk
下载之后,解压,其中有个Samples文件夹,里面有几个示例文件,其中的大部分功能我们用不到,如果只是拿数据,只需新建一个文件,然后贴入如下代码即可:
<?php
require_once(dirname(dirname(dirname(__FILE__))).'/mns-autoloader.php');
use AliyunMNS\Client;
use AliyunMNS\Requests\SendMessageRequest;
use AliyunMNS\Requests\CreateQueueRequest;
use AliyunMNS\Exception\MnsException;
class CreateQueueAndSendMessage
{
private $accessId;
private $accessKey;
private $endPoint;
private $client;
public function __construct($accessId, $accessKey, $endPoint)
{
$this->accessId = $accessId;
$this->accessKey = $accessKey;
$this->endPoint = $endPoint;
}
public function run()
{
$queueName = "aliyun-iot-a1Wxxxxxx";
$this->client = new Client($this->endPoint, $this->accessId, $this->accessKey);
$queue = $this->client->getQueueRef($queueName);
// receive message
$receiptHandle = NULL;
try
{
// when receiving messages, it's always a good practice to set the waitSeconds to be 30.
// it means to send one http-long-polling request which lasts 30 seconds at most.
// $res = $queue->receiveMessage(30);
$res = $queue->batchReceiveMessage(new \AliyunMNS\Requests\BatchReceiveMessageRequest(16,30) );;
print_r($res);
}
catch (MnsException $e)
{
echo "ReceiveMessage Failed: " . $e;
return;
}
}
}
$accessId = "LTAIU7YoxxxxxxxxUCy";
$accessKey = "XzcKWzfzOuxxxxxxxxxxxxxxxxxxx9Vzr";
$endPoint = "https://xxxxx.mns.cn-shanghai.aliyuncs.com/";
if (empty($accessId) || empty($accessKey) || empty($endPoint))
{
echo "Must Provide AccessId/AccessKey/EndPoint to Run the Example. \n";
return;
}
$instance = new CreateQueueAndSendMessage($accessId, $accessKey, $endPoint);
$instance->run();
?>
上面的queueName就是物联网控制台中的队列字段,也就是上一张截图的队列字段,accessId和accessKey字段是新建的子账户信息,至于endPoint字段,是在MNS控制面板的右上角,如图:
如果一切没问题的话,应该能拿到数据了,示例输出如下:
➜ Queue php GetMessage.php
AliyunMNS\Responses\BatchReceiveMessageResponse Object
(
[messages:protected] => Array
(
[0] => AliyunMNS\Model\Message Object
(
[receiptHandle:protected] => 8-0zumy92qPzZzxxxxxxx31jdjfqb
[messageBody:protected] => {"payload":"eyJsYXN0VGltZSI6IjIwMTktMDgtMDEgMjA6NTI6MzxxxxdXRjTGFzdFRpbWUiOiIyMDE5LTA4LTAxVDEyOjUyOjMyLjM5NloiLCJjbGllbnRJcCI6IjEwNi4xxxx0LjIwMCIsInV0Y1RpbWUiOiIyMDE5LTA4LTAxVDEyOjUyOjMyLjQwNVoiLCJ0aW1lIjoixxxxxxxMjozMi40MDUiLCJwcm9kdWN0S2V5IjoiYTF2WDBSV3dLYjQiLCJkZXZpY2VOYW1lIjoiTm9kZUVkZ2VQcm9kdWN0MURldmljZTEiLCJzdGF0dXMiOiJvbmxpbmUifQ==","messagetype":"status","topic":"/as/mqtt/status/a1vX0Rxxxb4/cloudboolProduct1Device1","messageid":1156910584684348928,"timestamp":1564663952}
[enqueueTime:protected] => 1564663952534
[nextVisibleTime:protected] => 1564665219953
[firstDequeueTime:protected] => 1564665159953
[dequeueCount:protected] => 1
[priority:protected] => 8
[messageId:protected] => 367C78D83BAxxxx8047ABC959695
[messageBodyMD5:protected] => 43E3411F1828xxxxF155B9014C2833
)
)
[base64:protected] => 1
[succeed:protected] => 1
[statusCode:protected] => 200
)
进一步操作的话,解析其中的messageBody字段下面的payload字段,将其base64解码之后能得到如下json数据:
{
"lastTime": "2019-08-01 20:52:32.396",
"utcLastTime": "2019-08-01T12:52:32.396Z",
"clientIp": "106.xx6.xxx.200",
"utcTime": "2019-08-01T12:52:32.405Z",
"time": "2019-08-01 20:52:32.405",
"productKey": "a1vX0xxxxb4",
"deviceName": "cloudboolProduct1Device1",
"status": "online"
}
到这一步,我们设备连接和获取设备数据就算完成了,还剩一步就是通过阿里云物联网云端平台给终端发送指令,但这一步我并没有去研究,原因参考下面的总结。
阿里云物联网平台总结
阿里云物联网平台是否可用?
可用,但是就目前来说,对我们不是很友好,因为HTTP/2没有PHP版本的SDK,只能通过MNS定时获取数据,然后业务处理,再调用阿里云物联网平台API将指令发送到设备,这对我们有用户交互的物联网项目设备来说,延迟太高,无法接受。
MNS是否有缺陷?
对我们来说,有的。可能上面的例子没有说明,其实MNS服务一次只能批量获取到16条数据,报错举例:
ReceiveMessage Failed: Code: 400 Message: The value of numofmessages should between 1 and 16 MnsErrorCode: InvalidArgument RequestId: 5D42E946433xxxxE25F11DC6 HostId: http://xxxxxxxx.mns.cn-shanghai.aliyuncs.com
考虑到后期设备太多,这对我们来说完全不够,可能一秒1600条数据都不不止,再考虑到物联网到MNS服务,以及加上期间网络本身开销,还有HTTPS握手等步骤,延迟实在是太高,业务会受此影响。
当然,这部分只是对于我们的实际情况而言,如果后端是用的Java或者.Net,还是可以考虑走HTTP/2降低延迟的。
所以,考虑到如上这些问题,我并没有测试从我们的用户UI再到我们的服务端给设备终端发送指令,因为到获取数据这一步就放弃了阿里云物联网平台,最终还是选择了自建MQTT服务器直接进行业务逻辑处理。
相关文档:
https://help.aliyun.com/product/30520.html
https://help.aliyun.com/product/27412.html