基于阿里云物联网平台--使用Python模拟设备上报参数

本文介绍如何使用Python在阿里云物联网平台上模拟设备数据上报,包括配置、连接、注册、回调函数等关键步骤,并展示了模拟设备属性上报的实现。
部署运行你感兴趣的模型镜像

一、前言

最近阿里云物联网平台改版,刚好利用此机会再次了解下MQTT相关内容,本文使用Python语言模拟设备进行数据上报,下一篇文章将介绍使用Python进行云端控制该模拟设备.

二、阿里物联网平台中定义产品

本文默认您已经在物联网平台创建了产品
新建产品
并在产品中定义了如下功能:
在这里插入图片描述
在设备中添加了一台设备:
在这里插入图片描述

三、Python模拟设备上报

A、启动配置

首先导入官方SK及相关需要使用的包

import configparser , time , hmac , hashlib , logging , os , sys , random
from linkkit import linkkit

进行基本的配置


LOG_FORMAT = "%(thread)d %(asctime)s  %(levelname)s %(filename)s %(lineno)d %(message)s"
DATE_FORMAT = "%m/%d/%Y-%H:%M:%S-%p"
logging.basicConfig(format=LOG_FORMAT , datefmt=DATE_FORMAT)
# 读取相关配置:HostName 、ProductKey 、DeviceName 、DeviceSecret 
conf = configparser.ConfigParser()
config_path = '../WIFI_GPRS_Config.cfg'    # 配置文件路径
conf.read(config_path)
HostName = conf.get('SETTINGS' , 'hostname')
ProductKey = conf.get('SETTINGS' , 'productkey')
DeviceName = conf.get('SETTINGS' , 'devicename')
ProductSecret = conf.get('SETTINGS' , 'productsecret')  # 一型一密
if conf.has_option('SETTINGS' , 'devicesecret'):
    DeviceSecret = conf.get('SETTINGS' , 'devicesecret')
else:
    DeviceSecret = ''

上述if else判断语句的目的:如果是一机一密,则直接获取配置文件的DeviceSecret ,否则DeviceSecret 置空,进行一型一密的设备注册获取设备密钥(具体见步骤C)
关于一机一密及一型一密,请见官方解释.。

B、初始化MQTT连接、配置物模型

lk = linkkit.LinkKit(
    host_name=HostName ,
    product_key=ProductKey ,
    device_name=DeviceName ,
    device_secret=DeviceSecret ,  # 一机一密 / 一型一密
    # product_secret = ProductSecret   #一型一密 若使用一型一密,增加此行 
)

lk.enable_logger(level=logging.DEBUG)
lk.thing_setup('../Resources/WIFI_GPRS_Data.json')   #物模型路径

注意:物模型需要使用完整物模型(在产品-功能定义-查看物模型-导出完整物模型)

C. 一型一密下注册设备

若使用一型一密,需要使用此方法(使用一机一密请跳过此步):

def on_device_dynamic_register(rc , value , userdata) :
    if rc == 0 :
        conf.set('SETTINGS' , 'DEVICESECRET' , value) #持久化device secret
        with open(config_path , 'w') as configfile :
            conf.write(configfile)
        logging.info("dynamic register device success, rc:%d, value:%s,userdata:%s" % (rc , value , userdata))
    else :
        logging.warning("dynamic register device fail,rc:%d, value:%s" % (rc , value))
  
#首次启动判断,若无DEVICESECRET,则调用如上注册函数
if not conf.has_option('SETTINGS' , 'DEVICESECRET'):
    lk.on_device_dynamic_register = on_device_dynamic_register         

一型一密 , 首次需要持久化device secret,首次之再次启动模拟设备只能使用持久化的devicesecret,否则会无法连接;
另外一型一密需要提前开启产品的动态注册接口

D、各类回调函数

@连接

def on_connect(session_flag , rc , userdata) :
    logging.info("on_connect:%d,rc:%d,userdata:" % (session_flag , rc))

@断开连接

def on_disconnect(rc , userdata) :
    logging.info("on_disconnect:rc:%d,userdata:" % rc)

@Topic消息

def on_topic_message(topic , payload , qos , userdata) :
    logging.info("on_topic_message:" + topic + " payload:" + str(payload) + " qos:" + str(qos))

@订阅

def on_subscribe_topic(mid , granted_qos , userdata) :
    logging.info("on_subscribe_topic mid:%d, granted_qos:%s" %
                 (mid , str(','.join('%s' % it for it in granted_qos))))

@取消订阅

def on_unsubscribe_topic(mid , userdata) :
    logging.info("on_unsubscribe_topic mid:%d" % mid)

@发布消息

def on_publish_topic(mid , userdata) :
    logging.info("on_publish_topic mid:%d" % mid)

@上报属性

def on_thing_prop_post(request_id , code , data , message , userdata) :
    logging.info("on_thing_prop_post request id:%s, code:%d message:%s, data:%s,userdata:%s" %
                 (request_id , code , message , data , userdata))

@云端设置属性

def on_thing_prop_changed(message , userdata) :
    if "PowerSwitch" in message.keys() :
        prop_data["PowerSwitch"] = message["PowerSwitch"]
    elif "WindSpeed" in message.keys() :
        prop_data["WindSpeed"] = message["WindSpeed"]
    elif "WorkMode" in message.keys() :
        prop_data["WorkMode"] = message["WorkMode"]
    else :
        logging.warning("wrong data:%s" % message)
    lk.thing_post_property(message)  # SDK不会主动上报属性变化,如需要修改后再次上报云端,需要调用thing_post_property()发送
    print('prop_data:' , prop_data)
    print('message:' , message)
    logging.info("on_thing_prop_changed  data:%s " % message)

== 注意SDK不会主动上报属性变化,如需要修改后再次上报云端,需要调用thing_post_property()发送==

@用户可以进行属性上报,事件上报,服务响应,此调用需要在连接前

def on_thing_enable(userdata) :
    logging.info("on_thing_enable")

E、SDK回调函数连接

SDK进行回调连接

lk.on_connect = on_connect
lk.on_disconnect = on_disconnect
lk.on_thing_enable = on_thing_enable
lk.on_subscribe_topic = on_subscribe_topic
lk.on_unsubscribe_topic = on_unsubscribe_topic
lk.on_topic_message = on_topic_message
lk.on_publish_topic = on_publish_topic
lk.on_thing_call_service = on_thing_call_service
lk.on_thing_event_post = on_thing_event_post
lk.on_thing_prop_changed = on_thing_prop_changed
lk.on_thing_prop_post = on_thing_prop_post
lk.connect_async()
lk.start_worker_loop()
time.sleep(2)  # 延时

在启动连接后增加2s的延时,否则会导致还没有连接成功就上报数据,然后报错

F、模拟设备属性

prop_data = {
    "PowerSwitch" : 1 ,
    "WindSpeed" : 1 ,
    "WorkMode" : 1 ,
    }
filter_data = {
    'CartridgesLife' : 5000.1 ,
    }

上述参数在功能定义中为:读写;故与属性上报(只读分开),便于云端设置模拟设备的参数使用
模拟循环上报100次数据(上报只读属性的参数):

counts = 100   # 模拟上报100while counts > 1 :
    pdata = {
        "MotorSpeed" : random.randint(8000 , 12000) ,
        "PM25" : random.randint(1 , 255) ,
        "CurrentPower" : round(random.uniform(2000 , 4000) , 2) ,
        "CurretWindSpeed" : round(random.uniform(0 , 450) , 1) ,
        "TVOC" : round(random.uniform(0 , 3) , 2) ,
        "CurrentTemperature" : round(random.uniform(-20 , 55) , 2) ,
        'Humidity' : random.randint(0 , 100) ,
        'GeoLocation' : {
                'Longitude' : round(random.uniform(-180 , 180) , 6) ,
                'Latitude' : round(random.uniform(-90 , 90) , 6) ,
                'Altitude' : random.randint(0 , 9999) ,
                'CoordinateSystem' : random.randint(1 , 2) ,
            }
        }
    rc , request_id = lk.thing_post_property({**prop_data , **pdata})
    if rc == 0 :
        logging.info("thing_post_property success:%r,mid:%r,\npost_data:%s" % (rc , request_id , prop_data))
    else :
        logging.warning("thing_post_property failed:%d" % rc)
    events = ("Error" , {"ErrorCode" : random.randint(0 , 5)})
    rc1 , request_id1 = lk.thing_trigger_event(events)
    if rc1 == 0 :
        logging.info("thing_trigger_event success:%r,mid:%r,\npost_data:%s" % (rc1 , request_id1 , events))
    else :
        logging.warning("thing_trigger_event failed:%d" % rc)
    time.sleep(60)
    counts -= 1

G、 通讯DEMO

为方便演示通讯及接收云端数据,将循环按步骤区分见下:

while True :

    try :
        print('''Please input operation code:
            Code example: 
            '1':disconnect,
            '2':connect,
            '3':subcribe topic,
            '4':unsubcribe topic,
            '5':publish topic,
            '6':thing_post
            ''')
        msg = input()
    except KeyboardInterrupt :
        sys.exit()
    else :
        if msg == '1' :
            lk.disconnect()
        elif msg == '2' :
            lk.connect_async()
        elif msg == '3' :
            rc , mid = lk.subscribe_topic(lk.to_full_topic("user/get"))

            if rc == 0 :
                logging.info("subcribe topic success:%r,mid:%r" % (rc , mid))
            else :
                logging.warning("subcribe topic failed:%d" % rc)
        elif msg == '4' :
            rc , mid = lk.unsubscribe_topic(lk.to_full_topic("user/get"))
            if rc == 0 :
                logging.info("unsubcribe topic success:%r,mid:%r" % (rc , mid))
            else :
                logging.warning("unsubcribe topic failed:%d" % rc)

        elif msg == '5' :
            rc , mid = lk.publish_topic(lk.to_full_topic("user/update") , '"WorkingStatus":3')
            if rc == 0 :
                logging.info("publish topic success:%r,mid:%r" % (rc , mid))
            else :
                logging.warning("publish topic failed:%d" % rc)
        elif msg == '6' :
            # 此处内容见步骤E
            pass
            # 此处内容见步骤E
        else :
            logging.warning("Error Code!!!!!!!!!!!!! ")
            continue

第六步循环上报属性见步骤E

四、上报结果

在这里插入图片描述

在这里插入图片描述
空间数据可视化:
在这里插入图片描述
结语:
本文只是简单介绍设备的模拟使用;
下一篇文章介绍使用Python云端控制模拟设备进行参数设置

参考
[1]: https://help.aliyun.com/document_detail/42648.html?spm=a2c4g.11174283.6.641.3a8b1668A6pEm6
[2]: https://help.aliyun.com/document_detail/108675.html?spm=a2c4g.11174283.6.556.2d835523OO5lpo

您可能感兴趣的与本文相关的镜像

Python3.11

Python3.11

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

<think>好的,我现在需要帮助用户了解如何在阿里云物联网平台中配置双向通信的Topic。用户之前已经询问过单向Topic的含义,现在转向双向通信的配置方法。首先,我得回顾之前的对话和提供的引用内容,确保信息准确且符合用户需求。 用户提供的引用中提到了阿里云物联网平台支持双向通信,设备与云端通过MQTT协议进行通信,并且提到了设备端SDK和云端API的使用。引用1和4提到云端可以通过APP发送控制指令,设备也能上传数据,这说明双向通信需要设备既能发布(Pub)也能订阅(Sub)Topic。引用3提到平台支持多种协议,但用户的问题集中在MQTT的Topic配置上。 接下来,我需要整理配置双向Topic的具体步骤。根据之前的回答,单向Topic的配置是通过权限策略限制Pub或Sub,而双向则需要同时允许两者。需要确定在阿里云控制台中如何创建产品、定义Topic类并设置权限。可能还需要涉及设备端的SDK配置,以及云端的规则引擎或API调用。 需要注意的是,用户可能需要具体的操作指南,比如如何在控制台中找到相关设置,如何编写Topic格式,以及如何测试双向通信是否成功。此外,用户可能关心权限设置、安全性和实际应用中的代码示例,比如设备端如何订阅Topic并接收指令,云端如何发布消息到设备。 需要确保回答结构清晰,分步骤说明,并引用之前的引用内容来支持说明,比如引用2提到的MQTT协议的重要性,引用3关于设备管理的部分。同时,应该提供配置示例和代码片段,比如设备端订阅和发布的代码,以及云端调用API的示例,这样用户能更直观地理解操作流程。 另外,用户可能遇到的问题包括权限配置错误、Topic格式不正确或网络连接问题,可以在注意事项部分提前说明,帮助用户避免常见错误。最后,相关问题部分需要引导用户深入探讨,比如优化通信效率或安全加固方法,这有助于用户进一步学习。</think>### 阿里云物联网平台双向通信 Topic 配置教程 在阿里云物联网平台中,**双向通信 Topic** 允许设备与云端互相发送和接收数据,需同时开放设备的 **发布(Pub)** 和 **订阅(Sub)** 权限。以下是具体配置步骤及技术实现细节: --- #### **一、配置双向通信 Topic 的核心步骤** 1. **创建产品并定义 Topic 类** - 登录 [阿里云物联网平台控制台](https://iot.console.aliyun.com/),进入 **产品管理** → **创建产品**。 - 在产品详情页的 **Topic 类列表** 中,点击 **自定义 Topic**,填写格式(如 `/${productKey}/${deviceName}/user/control`),并设置权限为 **发布和订阅**(即设备端可同时发布和订阅该 Topic)[^3]。 ```plaintext # 示例 Topic 格式 设备上报数据:/${productKey}/${deviceName}/user/data 云端下发指令:/${productKey}/${deviceName}/user/control ``` 2. **设备端权限配置** - 在设备证书(ProductKey、DeviceName、DeviceSecret)中,确保设备具备对应 Topic 的 **Pub/Sub 权限**(默认自定义 Topic 需手动配置权限)。 - 通过设备端 SDK(如 C-SDK 或 Python SDK)实现双向通信: - **设备发布数据**:向云端 Topic 发送消息(如传感器数据)。 - **设备订阅 Topic**:监听云端下发的指令(如控制指令)。 ```python # 示例:Python 设备端订阅云端指令 from aliyunIoT import Device def on_message(topic, payload): print(f"收到指令: {payload}") device = Device(productKey="PK", deviceName="DN", deviceSecret="DS") device.subscribe("/${productKey}/${deviceName}/user/control") # 订阅云端指令 Topic device.on("message", on_message) ``` 3. **云端服务配置** - **云端下发指令**:通过规则引擎或调用 [Pub API](https://help.aliyun.com/document_detail/69869.html) 向设备 Topic 发送消息。 - **云端订阅设备数据**:通过规则引擎将设备上报数据转发至其他服务(如数据库或消息队列)。 ```plaintext # 示例:云端调用 Pub API 下发指令 Topic: /${productKey}/${deviceName}/user/control Payload: {"cmd": "turn_on", "value": 1} ``` --- #### **二、双向通信的完整流程** 1. **设备端初始化** - 设备连接阿里云 IoT Hub(基于 MQTT 协议)并订阅云端指令 Topic[^2][^3]。 2. **数据上报与指令下发** - 设备通过 `/${productKey}/${deviceName}/user/data` 上报数据- 云端服务通过 `/${productKey}/${deviceName}/user/control` 下发指令,设备实时接收并响应[^4]。 3. **规则引擎联动** - 配置规则引擎将设备数据转发至其他阿里云服务(如 TSDB 存储或 Function Compute 处理)[^3]。 --- #### **三、注意事项** 1. **Topic 权限一致性** - 设备端和云端操作的 Topic 权限必须匹配(如设备订阅的 Topic 需在云端配置为可发布)。 2. **安全加固** - 使用 TLS/SSL 加密 MQTT 连接,避免敏感数据泄露[^3]。 3. **Topic 通配符限制** - 设备订阅时可用 `+` 或 `#` 通配符(如 `/${productKey}/+/user/control`),但需在权限策略中明确允许[^3]。 --- #### **四、测试验证** 1. **设备端测试** - 使用 MQTT 调试工具(如 MQTT.fx)模拟设备订阅和发布,验证双向通信是否正常。 2. **云端日志排查** -物联网平台 **日志服务** 中查看设备上下线状态及消息流转记录[^3]。 --- ### 相关问题 1. 如何通过阿里云规则引擎实现设备数据实时触发云端函数计算? 2. MQTT 协议在物联网场景中相比 HTTP 有哪些优势? 3. 如何为大规模设备配置动态 Topic 以实现分组控制? 通过以上配置,可灵活实现设备与云端的双向交互,满足远程控制、数据采集等复杂场景需求[^2][^3]。
评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值