本文操作的前提是已经在树莓派上完成了DHT11温湿度传感器的安装和数据读取。
资料可以参考
我选择使用阿里云的原因有以下几点
物联网平台启动商用之后,新增的设备品类,里面的选项很多,如果没有合适的还可以自定义。
目前的SDK支持下面平台
Linux Ubuntu 16.04 64-bit
Windows Widows 7 64 bit
Mac High Sierra
支持下面语言
我们的设备是通过python和传感器交互的,所以这里我们使用Python SDK 。
这里使用的python版本最低为3.6,没有环境的需要安装环境,之前我们已经完成了和传感器的交互,所以这部分直接跳过。
wget https://bootstrap.pypa.io/get-pip.py
sudo python3 get-pip.py
sudo python3 -m pip install --upgrade pip setuptools wheel
sudo apt-get install python3-venv
下面是官方给的安装方式。
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt-get update
sudo apt-get install python3.6
wget https://bootstrap.pypa.io/get-pip.py
sudo python3.6 get-pip.py
python3.6 -m pip install --upgrade pip setuptools wheel
sudo apt-get install python3.6-venv
mkdir work_dir
cd work_dir
python3 -m venv test_env
source test_env/bin/activate
pip install aliyun-iot-linkkit
文件位置为 http://iotx-pop-quickstart-shanghai.oss-cn-shanghai.aliyuncs.com/linkkit/sdk/python/python-linkkit-1.0.0-example.tar.gz?spm=a2c4g.11186623.2.26.756756bbr9vPXW&file=python-linkkit-1.0.0-example.tar.gz
解压后得到文件
通过dynamic_register.py
注册设备,修改文件中的参数,对应参数去产品页面查找。
lk = linkkit.LinkKit(
host_name="cn-shanghai",
product_key="xxxxxxxxxxx",
device_name="device-name",
device_secret="",
product_secret="yyyyyyyyyyyyyyyy")
device_name
对应设备信息,需要我们先在平台注册设备。
(test_env) pi@raspberrypi:~/work_dir/examples $ python3 dynamic_register.py
2020-03-01 19:18:32,104-1308-1996303056 - linkkit:linkkit:debug - DEBUG - connect_async
2020-03-01 19:18:32,106-1308-1968174176 - linkkit:linkkit:debug - DEBUG - LoopThread thread enter
2020-03-01 19:18:32,107-1308-1968174176 - linkkit:linkkit:debug - DEBUG - enter
2020-03-01 19:18:32,108-1308-1968174176 - linkkit:linkkit:info - INFO - start connect
2020-03-01 19:18:32,111-1308-1968174176 - linkkit:linkkit:debug - DEBUG - current working directory:/home/pi/work_dir/examples
2020-03-01 19:18:37,337-1308-1968174176 - Paho:client:_easy_log - DEBUG - Sending CONNECT (u1, p1, wr0, wq0, wf0, c1, k60) client_id=b'a1Gb6Hee6D8&dht11|securemode=2,signmethod=hmacsha1,ext=1,lan=Python,_v=1.2.0,timestamp=1583061512|'
2020-03-01 19:18:37,448-1308-1968174176 - Paho:client:_easy_log - DEBUG - Received CONNACK (0, 0)
2020-03-01 19:18:37,449-1308-1968174176 - linkkit:linkkit:info - INFO - __on_internal_connect
2020-03-01 19:18:37,450-1308-1968174176 - Paho:client:_easy_log - DEBUG - Sending SUBSCRIBE (d0, m1) [(b'/sys/a1Gb6Hee6D8/dht11/thing/deviceinfo/update_reply', 0)]
2020-03-01 19:18:37,451-1308-1968174176 - linkkit:linkkit:debug - DEBUG - post_message :'on_connect'
2020-03-01 19:18:37,451-1308-1968174176 - linkkit:linkkit:debug - DEBUG - post_message success
2020-03-01 19:18:37,452-1308-1978537056 - linkkit:linkkit:debug - DEBUG - thread runnable pop cmd:'on_connect'
2020-03-01 19:18:37,453-1308-1978537056 - linkkit:linkkit:info - INFO - __on_internal_connect enter
2020-03-01 19:18:37,454-1308-1978537056 - linkkit:linkkit:debug - DEBUG - session:0, return code:0
on_connect:0,rc:0,userdata:
2020-03-01 19:18:37,502-1308-1968174176 - Paho:client:_easy_log - DEBUG - Received SUBACK
2020-03-01 19:18:37,502-1308-1968174176 - linkkit:linkkit:debug - DEBUG - post_message :'on_subscribe'
2020-03-01 19:18:37,503-1308-1968174176 - linkkit:linkkit:debug - DEBUG - post_message success
2020-03-01 19:18:37,504-1308-1978537056 - linkkit:linkkit:debug - DEBUG - thread runnable pop cmd:'on_subscribe'
2020-03-01 19:18:37,505-1308-1978537056 - linkkit:linkkit:debug - DEBUG - __on_internal_subscribe mid:1 granted_qos:1
2020-03-01 19:19:37,560-1308-1968174176 - Paho:client:_easy_log - DEBUG - Sending PINGREQ
2020-03-01 19:19:37,597-1308-1968174176 - Paho:client:_easy_log - DEBUG - Received PINGRESP
再次刷新页面,看到设备已经被激活~
在物联网平台上,你可以发现设备上面直接有温湿度数据的展示。
通过物模型,可以定义设备的字段,点击物模型TSL下载json文件。
{
"schema":"https://iotx-tsl.oss-ap-southeast-1.aliyuncs.com/schema.json",
"profile":{
"productKey":"a1Gb6Hee6D8"
},
"properties":[
{
"identifier":"CurrentTemperature",
"name":"当前温度",
"accessMode":"r",
"required":true,
"dataType":{
"type":"float",
"specs":{
"min":"-40",
"max":"120",
"unit":"°C",
"unitName":"摄氏度",
"step":"0.1"
}
}
},
{
"identifier":"CurrentHumidity",
"name":"当前湿度",
"accessMode":"r",
"required":true,
"dataType":{
"type":"float",
"specs":{
"min":"0",
"max":"100",
"unit":"%",
"unitName":"百分比",
"step":"0.1"
}
}
},
{
"identifier":"GeoLocation",
"name":"地理位置",
"accessMode":"r",
"required":true,
"dataType":{
"type":"struct",
"specs":[
{
"identifier":"Longitude",
"name":"经度",
"dataType":{
"type":"double",
"specs":{
"min":"-180",
"max":"180",
"unit":"°",
"unitName":"度",
"step":"0.01"
}
}
},
{
"identifier":"Latitude",
"name":"纬度",
"dataType":{
"type":"double",
"specs":{
"min":"-90",
"max":"90",
"unit":"°",
"unitName":"度",
"step":"0.01"
}
}
},
{
"identifier":"Altitude",
"name":"海拔",
"dataType":{
"type":"double",
"specs":{
"min":"0",
"max":"9999",
"unit":"m",
"unitName":"米",
"step":"0.01"
}
}
},
{
"identifier":"CoordinateSystem",
"name":"坐标系统",
"dataType":{
"type":"enum",
"specs":{
"1":"WGS_84",
"2":"GCJ_02"
}
}
}
]
}
}
],
"events":[
{
"identifier":"post",
"name":"post",
"type":"info",
"required":true,
"desc":"属性上报",
"method":"thing.event.property.post",
"outputData":[
{
"identifier":"CurrentTemperature",
"name":"当前温度",
"dataType":{
"type":"float",
"specs":{
"min":"-40",
"max":"120",
"unit":"°C",
"unitName":"摄氏度",
"step":"0.1"
}
}
},
{
"identifier":"CurrentHumidity",
"name":"当前湿度",
"dataType":{
"type":"float",
"specs":{
"min":"0",
"max":"100",
"unit":"%",
"unitName":"百分比",
"step":"0.1"
}
}
},
{
"identifier":"GeoLocation",
"name":"地理位置",
"dataType":{
"type":"struct",
"specs":[
{
"identifier":"Longitude",
"name":"经度",
"dataType":{
"type":"double",
"specs":{
"min":"-180",
"max":"180",
"unit":"°",
"unitName":"度",
"step":"0.01"
}
}
},
{
"identifier":"Latitude",
"name":"纬度",
"dataType":{
"type":"double",
"specs":{
"min":"-90",
"max":"90",
"unit":"°",
"unitName":"度",
"step":"0.01"
}
}
},
{
"identifier":"Altitude",
"name":"海拔",
"dataType":{
"type":"double",
"specs":{
"min":"0",
"max":"9999",
"unit":"m",
"unitName":"米",
"step":"0.01"
}
}
},
{
"identifier":"CoordinateSystem",
"name":"坐标系统",
"dataType":{
"type":"enum",
"specs":{
"1":"WGS_84",
"2":"GCJ_02"
}
}
}
]
}
}
]
}
],
"services":[
{
"identifier":"set",
"name":"set",
"required":true,
"callType":"async",
"desc":"属性设置",
"method":"thing.service.property.set",
"inputData":[
],
"outputData":[
]
},
{
"identifier":"get",
"name":"get",
"required":true,
"callType":"async",
"desc":"属性获取",
"method":"thing.service.property.get",
"inputData":[
"CurrentTemperature",
"CurrentHumidity",
"GeoLocation"
],
"outputData":[
{
"identifier":"CurrentTemperature",
"name":"当前温度",
"dataType":{
"type":"float",
"specs":{
"min":"-40",
"max":"120",
"unit":"°C",
"unitName":"摄氏度",
"step":"0.1"
}
}
},
{
"identifier":"CurrentHumidity",
"name":"当前湿度",
"dataType":{
"type":"float",
"specs":{
"min":"0",
"max":"100",
"unit":"%",
"unitName":"百分比",
"step":"0.1"
}
}
},
{
"identifier":"GeoLocation",
"name":"地理位置",
"dataType":{
"type":"struct",
"specs":[
{
"identifier":"Longitude",
"name":"经度",
"dataType":{
"type":"double",
"specs":{
"min":"-180",
"max":"180",
"unit":"°",
"unitName":"度",
"step":"0.01"
}
}
},
{
"identifier":"Latitude",
"name":"纬度",
"dataType":{
"type":"double",
"specs":{
"min":"-90",
"max":"90",
"unit":"°",
"unitName":"度",
"step":"0.01"
}
}
},
{
"identifier":"Altitude",
"name":"海拔",
"dataType":{
"type":"double",
"specs":{
"min":"0",
"max":"9999",
"unit":"m",
"unitName":"米",
"step":"0.01"
}
}
},
{
"identifier":"CoordinateSystem",
"name":"坐标系统",
"dataType":{
"type":"enum",
"specs":{
"1":"WGS_84",
"2":"GCJ_02"
}
}
}
]
}
}
]
}
]
}
我们可以根据自己的需求增减里面的字段,我在这里删掉了地理位置。
配置模型文件
lk.thing_setup("tsl.json"
上传数据
event_data = {
"power": 10,
"power_style": 1
}
rc, request_id = lk.thing_trigger_event(("power_state", event_data))
我们可以直接参考事例文件中的,thing_alink.py
,修改加载的模型文件
参考文章 https://blog.csdn.net/diandianxiyu_geek/article/details/104547804
这里要注意的是,设备连接需要时间,如果直接调用会提示未连接状态。
最终实现效果的python代码如下
import time
import Adafruit_GPIO.SPI as SPI
import Adafruit_SSD1306
import Adafruit_DHT
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
import subprocess
import sys
from linkkit import linkkit
import threading
import traceback
import inspect
import time
import logging
# Raspberry Pi pin configuration:
RST = None # on the PiOLED this pin isnt used
# Note the following are only used with SPI:
DC = 23
SPI_PORT = 0
SPI_DEVICE = 0
disp = Adafruit_SSD1306.SSD1306_128_32(rst=RST)
# Initialize library.
disp.begin()
# Clear display.
disp.clear()
disp.display()
# Create blank image for drawing.
# Make sure to create image with mode '1' for 1-bit color.
width = disp.width
height = disp.height
image = Image.new('1', (width, height))
# Get drawing object to draw on image.
draw = ImageDraw.Draw(image)
# Draw a black filled box to clear the image.
draw.rectangle((0,0,width,height), outline=0, fill=0)
# Draw some shapes.
# First define some constants to allow easy resizing of shapes.
padding = -2
top = padding
bottom = height-padding
# Move left to right keeping track of the current x position for drawing shapes.
x = 0
# Load default font.
font = ImageFont.load_default()
# Alternatively load a TTF font. Make sure the .ttf font file is in the same directory as the python script!
# Some other nice fonts to try: http://www.dafont.com/bitmap.php
# font = ImageFont.truetype('Minecraftia.ttf', 8)
# config log
__log_format = '%(asctime)s-%(process)d-%(thread)d - %(name)s:%(module)s:%(funcName)s - %(levelname)s - %(message)s'
logging.basicConfig(format=__log_format)
class CustomerThing(object):
def __init__(self):
self.__linkkit = linkkit.LinkKit(
host_name="cn-shanghai",
product_key="*****",
device_name="*****",
device_secret="********")
self.__linkkit.enable_logger(logging.DEBUG)
self.__linkkit.on_device_dynamic_register = self.on_device_dynamic_register
self.__linkkit.on_connect = self.on_connect
self.__linkkit.on_disconnect = self.on_disconnect
self.__linkkit.on_topic_message = self.on_topic_message
self.__linkkit.on_subscribe_topic = self.on_subscribe_topic
self.__linkkit.on_unsubscribe_topic = self.on_unsubscribe_topic
self.__linkkit.on_publish_topic = self.on_publish_topic
self.__linkkit.on_thing_enable = self.on_thing_enable
self.__linkkit.on_thing_disable = self.on_thing_disable
self.__linkkit.on_thing_event_post = self.on_thing_event_post
self.__linkkit.on_thing_prop_post = self.on_thing_prop_post
self.__linkkit.on_thing_prop_changed = self.on_thing_prop_changed
self.__linkkit.on_thing_call_service = self.on_thing_call_service
self.__linkkit.on_thing_raw_data_post = self.on_thing_raw_data_post
self.__linkkit.on_thing_raw_data_arrived = self.on_thing_raw_data_arrived
self.__linkkit.thing_setup("model.json")
self.__linkkit.config_device_info("Eth|03ACDEFF0032|Eth|03ACDEFF0031")
self.__call_service_request_id = 0
self.__linkkit.connect_async()
def on_device_dynamic_register(self, rc, value, userdata):
if rc == 0:
print("dynamic register device success, value:" + value)
else:
print("dynamic register device fail, message:" + value)
def on_connect(self, session_flag, rc, userdata):
print("on_connect:%d,rc:%d,userdata:" % (session_flag, rc))
def on_disconnect(self, rc, userdata):
print("on_disconnect:rc:%d,userdata:" % rc)
def on_topic_message(self, topic, payload, qos, userdata):
print("on_topic_message:" + topic + " payload:" + str(payload) + " qos:" + str(qos))
pass
def on_subscribe_topic(self, mid, granted_qos, userdata):
print("on_subscribe_topic mid:%d, granted_qos:%s" %
(mid, str(','.join('%s' % it for it in granted_qos))))
pass
def on_unsubscribe_topic(self, mid, userdata):
print("on_unsubscribe_topic mid:%d" % mid)
pass
def on_publish_topic(self, mid, userdata):
print("on_publish_topic mid:%d" % mid)
def on_thing_prop_changed(self, params, userdata):
print("on_thing_prop_changed params:" + str(params))
def on_thing_enable(self, userdata):
print("on_thing_enable")
def on_thing_disable(self, userdata):
print("on_thing_disable")
def on_thing_event_post(self, event, request_id, code, data, message, userdata):
print("on_thing_event_post event:%s,request id:%s, code:%d, data:%s, message:%s" %
(event, request_id, code, str(data), message))
pass
def on_thing_prop_post(self, request_id, code, data, message,userdata):
print("on_thing_prop_post request id:%s, code:%d, data:%s message:%s" %
(request_id, code, str(data), message))
def on_thing_raw_data_arrived(self, payload, userdata):
print("on_thing_raw_data_arrived:%s" % str(payload))
def on_thing_raw_data_post(self, payload, userdata):
print("on_thing_raw_data_post: %s" % str(payload))
def on_thing_call_service(self, identifier, request_id, params, userdata):
print("on_thing_call_service identifier:%s, request id:%s, params:%s" %
(identifier, request_id, params))
self.__call_service_request_id = request_id
pass
def update(self,CurrentTemperature,CurrentHumidity):
prop_data = {
"CurrentTemperature": float(CurrentTemperature),
"CurrentHumidity": float(CurrentHumidity)
}
self.__linkkit.thing_post_property(prop_data)
if __name__ == "__main__":
custom_thing = CustomerThing()
time.sleep(1)
while True:
# Draw a black filled box to clear the image.
draw.rectangle((0,0,width,height), outline=0, fill=0)
sensor = 11 # 传感器型号
pin = 22 # 针脚
humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)
if humidity is not None and temperature is not None:
Temp = '{0:0.1f}'.format(temperature)
H = '{0:0.1f}'.format(humidity)
now = time.strftime("%Y-%m-%d-%H:%M:%S", time.localtime())
draw.text((x, top), str(now), font=font, fill=255)
draw.text((x, top+8), str("Temp="+Temp), font=font, fill=255)
draw.text((x, top+16), str("Humidity="+H+"%"), font=font, fill=255)
custom_thing.update(Temp,H)
# Display image.
disp.image(image)
disp.display()
time.sleep(3)
最终完成了设备通过屏幕展示温湿度信息并同步到物联网平台的功能。