【物联网iot】树莓派连接阿里云iot平台定时上传温湿度信息

前提

本文操作的前提是已经在树莓派上完成了DHT11温湿度传感器的安装和数据读取。

资料可以参考

  • 【树莓派】使用0.91寸显示屏SSD1306展示想要的内容
  • 【树莓派】使用DHT11连接树莓派读取传感器数字并通过0.96寸屏展示

设备

  • 树莓派3b+
  • DHT11

接入物联网平台

为什么是阿里云物联网平台

我选择使用阿里云的原因有以下几点

  • 阿里云作为国内比较完善云服务商,功能比较完善
  • 阿里云的iot已经完成产品探索阶段,开始正式商用,我之前的公司的产品也在一直使用,个人比较熟悉

创建产品

【物联网iot】树莓派连接阿里云iot平台定时上传温湿度信息_第1张图片
物联网平台启动商用之后,新增的设备品类,里面的选项很多,如果没有合适的还可以自定义。

在设备界面,我们就可以连接设备了。
【物联网iot】树莓派连接阿里云iot平台定时上传温湿度信息_第2张图片

注册设备

下载SDK

目前的SDK支持下面平台

  • Linux Ubuntu 16.04 64-bit

  • Windows Widows 7 64 bit

  • Mac High Sierra

支持下面语言

  • C SDK
  • Android SDK
  • NodeJS SDK
  • Java SDK
  • Python SDK
  • iOS SDK

我们的设备是通过python和传感器交互的,所以这里我们使用Python SDK 。

Python SDK

安装Python

这里使用的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

创建和激活 VirtualEnvironments

mkdir work_dir
cd work_dir
python3 -m venv test_env
source test_env/bin/activate

自动安装linkkit

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 动态获取deviceScret
  • mqtt_connect_TCP.py 通过TCP方式建立MQTT连接
  • mqtt_connect_TLS.py 通过TLS加密方式建立MQTT连接
  • mqtt_sub_pub_on.py 展示mqtt订阅,发布,接收消息
  • thing_alink.py 通过透传协议,展示物模型能力,进行属性上报,属性设置,事件上报,服务响应
  • tsl.json thing_alink.py使用的物模型文件
  • thing_custom.py 通过用户自定义协议进行展示属性设置及属性上报
  • model_raw.json thing_custom.py 使用的物模型文件
  • data_transfer.js thing_custom.py 对应云端的数据解析脚本

注册设备

通过dynamic_register.py注册设备,修改文件中的参数,对应参数去产品页面查找。

lk = linkkit.LinkKit(
    host_name="cn-shanghai",
    product_key="xxxxxxxxxxx",
    device_name="device-name",
    device_secret="",
    product_secret="yyyyyyyyyyyyyyyy")

device_name对应设备信息,需要我们先在平台注册设备。

【物联网iot】树莓派连接阿里云iot平台定时上传温湿度信息_第3张图片
【物联网iot】树莓派连接阿里云iot平台定时上传温湿度信息_第4张图片
修改之后的文件,执行

(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

再次刷新页面,看到设备已经被激活~

【物联网iot】树莓派连接阿里云iot平台定时上传温湿度信息_第5张图片

上传温湿度信息

获取物模型文件

在物联网平台上,你可以发现设备上面直接有温湿度数据的展示。

【物联网iot】树莓派连接阿里云iot平台定时上传温湿度信息_第6张图片
这个设置,是在产品上,有一个概念是物模型。

【物联网iot】树莓派连接阿里云iot平台定时上传温湿度信息_第7张图片
通过物模型,可以定义设备的字段,点击物模型TSL下载json文件。

【物联网iot】树莓派连接阿里云iot平台定时上传温湿度信息_第8张图片
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)


最终完成了设备通过屏幕展示温湿度信息并同步到物联网平台的功能。

参考资料

  • https://help.aliyun.com/document_detail/98292.html?spm=a2c4g.11186623.2.20.36132cf0M0u5Wm
  • https://www.blackmoreops.com/2014/02/21/kali-linux-add-ppa-repository-add-apt-repository/

你可能感兴趣的:(#,树莓派,#,服务器运维)