2019-2020上学期,终端与网关大作业
目的:用树莓派当网关,ZigBee协调器和路由器之间实现终端通信(无代码),采集终端温度数据,通过串口连接到树莓派上,树莓派与onenet之间实现数据的传输。
流程图:
1. 数据采集-路由器
路由器节点上电后触发发送温度事件
处理发送温度的事件函数
uint16 router_ProcessEvent( uint8 task_id, uint16 events )
{
(void)task_id; // Intentionally unreferenced parameter
................................
/* 自定义事件入口 */
if ( events & ROUTER_SEND_PERIODIC_MSG_EVT )
{
return (events ^ ROUTER_SEND_PERIODIC_MSG_EVT);
}
if(events & ROUTER_TPM_SEND_EVT)
{
unsigned char tmp[3];
gettmperval(tmp); /*采集温度*/
NodeSendRFDate(&router_epDesc, tmp, 3, 0, afAddr16Bit, NODE_TMP_SEND_CLUSTERID); /*温度发送*/
osal_start_timerEx( router_TaskID, ROUTER_TPM_SEND_EVT,
ROUTER_SEND_MSG_TIMEOUT );
return (events ^ ROUTER_TPM_SEND_EVT);
}
return 0;
}
#DS18B20GetTemperValue是采集DS18B20的数据
由路由器节点将温度传感器上的数据读出通过zigbee网络向协调器发送温度数据上,再由协调器将收到的数据打印到串口上。数据采集的代码烧到ZigBee实验箱上,路由器上插温度采集的硬件板子。其他代码烧到树莓派上。
2.数据采集-协调器
#协调器接收函数
static void _process_sys_event_wd_msg(afIncomingMSGPacket_t *msg_pack)
{
uint16_t cluster_id = 0;
uint8 *ReceiveData;
cluster_id = msg_pack->clusterId; /*簇号*/
if(cluster_id == NODE_TMP_SEND_CLUSTERID)
{
unsigned char buff[10];
ReceiveData = msg_pack->cmd.Data; /*数据包头指针*/
buff[0]=*ReceiveData;
buff[1]=*(ReceiveData+1);
buff[2]='.';
buff[3]=*(ReceiveData+2);
HalUARTWrite(0,buff,4);//将接收过来的温度数据通过串口发送
HalUARTWrite(0,"\r\n",2);
}
}
流程图
3.树莓派通过串口接收协调器发送的数据,采用队列方式进行线程间的通信,将获取到的数据保存到文件中。将如下代码烧到树莓派上,通过两个线程实现终端与网关之间的通信(包括数据格式的转换及储存)
import serial
import time
import json
import threading
from time import ctime,sleep
import queue
q = queue.Queue()
ser = serial.Serial("/dev/ttyUSB0",115200,timeout=0.5)
def Zigbee():
while True:
count = ser.inWaiting()
if count != 0:
recv = ser.readline()
ser.flushInput()
#q.put(recv.decode())
data = recv.decode('utf-8')
#data = recv
#humidity= float(data)
tmp_output = open("tmp_data1.txt",'r')
tmp_output.write(data)
tmp_output.flush()
#humidity = float(tmp_output.read())
tmp_output.close()
print(recv.decode())
sleep(0.1)
def Zigbee_json ():
global recv
i=2
while True:
if q.empty:
pass
else:
data = q.get()
humidity= float(data)
tmp_output = open("tmp_data2.txt",'w')
tmp_output.write('111')
tmp_output.flush()
humidity = float(tmp_output.read())
tmp_output.close()
print(data)
sleep(1)
threads = []
t1 = threading.Thread(target = Zigbee)
#t1 = threading.Thread(target = Lora,args = ('',))
threads.append(t1)
t2 = threading.Thread(target = Zigbee_json)
#t2 = threading.Thread(target = Lora,args = ('',))
threads.append(t2)
if __name__ == '__main__':
for t in threads:
t.start()
t1.join()
t2.join()
# while True:
# sleep(2)
4.将树莓派保存的数据上传到onenet上
#-*-coding:utf-8 -*-
from __future__ import print_function
import paho.mqtt.client as mqtt
import struct
import json
import datetime
# CONNECT 方式:
# client_id: DEV_ID
# username: PRO_ID
# password: AUTHINFO(鉴权信息)
# 可以连接上设备云,CONNECT 和 CONNACK握手成功
# temperature:已创建的一个数据流
#更多请查阅OneNet官方mqtt文档与paho-mqtt开发文档
#修改成自己的即可
DEV_ID = "************" #设备ID
PRO_ID = "***" #产品ID
AUTH_INFO = "******************" #APIKEY
#AUTH_INFO = "159635"
#file = open("/home/pi/ZB_data/tmp_data1.txt")
file = open("tmp_data1.txt")
humidity= float(file.read())
#humidity= float(20)
time = datetime.datetime.now().isoformat()
TYPE_JSON = 0x01
TYPE_FLOAT = 0x17
#定义上传数据的json格式 该格式是oneNET规定好的 按格式修改其中变量即可
body = {
"datastreams":[
{
"id":"humi", #对应OneNet的数据流名称
"datapoints":[
{
"at":time , #数据提交时间,这里可通过函数来获取实时时间
"value":humidity #数据值
}
]
}
]
}
def build_payload(type, payload):
datatype = type
packet = bytearray()
packet.extend(struct.pack("!B", datatype))
if isinstance(payload, str):
udata = payload.encode('utf-8')
length = len(udata)
packet.extend(struct.pack("!H" + str(length) + "s", length, udata))
return packet
# 当客户端收到来自服务器的CONNACK响应时的回调。也就是申请连接,服务器返回结果是否成功等
def on_connect(client, userdata, flags, rc):
print("连接结果:" + mqtt.connack_string(rc))
#上传数据
json_body = json.dumps(body)
packet = build_payload(TYPE_JSON, json_body)
client.publish("$dp", packet, qos=1) #qos代表服务质量
# 从服务器接收发布消息时的回调。
def on_message(client, userdata, msg):
print("湿度:"+str(msg.payload,'utf-8')+"%RH")
#当消息已经被发送给中间人,on_publish()回调将会被触发
def on_publish(client, userdata, mid):
print("mid:" + str(mid))
def main():
client = mqtt.Client(client_id=DEV_ID, protocol=mqtt.MQTTv311)
client.on_connect = on_connect
client.on_publish = on_publish
client.on_message = on_message
client.username_pw_set(username=PRO_ID, password=AUTH_INFO)
client.connect('183.230.40.39', port=6002, keepalive=120)
client.loop_forever()
if __name__ == '__main__':
main()