微信公众号实现简易的物联网控制(一)

这篇主要说说如何通过微信公众号来查看室内传感器数据,至于硬件部分和物联网平台以后再详细说明。


准备工作:

1:申请微信公众号

2:搭建云服务器


首先说明一下整体流程:用户发送相应的指令到公众号后台,服务器根据指令的内容调用OneNET的API获取传感器数据在返回给用户


详细步骤:

申请公众号后我们需要启用服务器配置,具体步骤请看微信的开发者文档,这个地方需要注意一下在填写URL的时候不要添加端口号,这样会导致验证不通过的(开发者文档上这个是错误的)

在云服务器上安装运行环境:

安装pip
安装libxml2

安装lxml
  
安装web.py

我们使用的物联网平台是中国移动的OneNet,它提供了很多API接口可以让我们获取数据、发送指令,在GitHub上有人用python写了常用的API调用示例,这里我们拿来直接使用就好了https://github.com/jiangxiaobai1989/pythonOneNetAPI
首先呢我们需要能够接收用户发过来的消息,使用者发送消息后后台收到的为lxml格式
<xml>
<ToUserName><![CDATA[粉丝号]]></ToUserName>
<FromUserName><![CDATA[公众号]]></FromUserName>
<CreateTime>1460541339</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[test]]></Content>
</xml>

然后呢我们需要解析这些内容
# -*- coding: utf-8 -*-
# filename: receive.py
import xml.etree.ElementTree as ET

def parse_xml(web_data):
    if len(web_data) == 0:
        return None
    xmlData = ET.fromstring(web_data)
    msg_type = xmlData.find('MsgType').text
    if msg_type == 'text':
        return TextMsg(xmlData)
    elif msg_type == 'image':
        return ImageMsg(xmlData)
    elif msg_type == 'voice':
	return VoiceMsg(xmlData)

class Msg(object):
    def __init__(self, xmlData):
        self.ToUserName = xmlData.find('ToUserName').text
        self.FromUserName = xmlData.find('FromUserName').text
        self.CreateTime = xmlData.find('CreateTime').text
        self.MsgType = xmlData.find('MsgType').text
        self.MsgId = xmlData.find('MsgId').text
	

class TextMsg(Msg):
    def __init__(self, xmlData):
        Msg.__init__(self, xmlData)
        self.Content = xmlData.find('Content').text.encode("utf-8")

class VoiceMsg(Msg):
	def __init__(self, xmlData):
		Msg.__init__(self, xmlData)
		self.Recognition = xmlData.find('Recognition').text.encode("utf-8")

获取消息后我们需要服务器做出相应的反应,首先需要判断消息类型和消息内容,然后通过API获取数据后再返回个用户,例如下面这段获取室内温湿度的例子
# -*- coding: utf-8 -*-
# filename: handle.py
import hashlib
import reply
import receive
import web
from getData import *
class Handle(object):
    def POST(self):
        try:
            webData = web.data()
            print "Handle Post webdata is ", webData   #后台打日志
            recMsg = receive.parse_xml(webData)
            if isinstance(recMsg, receive.Msg):
                toUser = recMsg.FromUserName
                fromUser = recMsg.ToUserName
                if recMsg.MsgType == 'text':
                	if recMsg.Content == '温度':
				content = str(getData_time('temperature'))+'
室内温度为'+str(getData_value('temperature')) +'℃'
		  	elif recMsg.Content == '湿度':
				content = str(getData_time('humidity'))+'
室内湿度为'+str(getData_value('humidity')) +'%'
			else:
				content = '抱歉尚未开通这项指令功能,你可以尝试发送‘温度’、‘湿度’来查看最新的室内信息,或者发送相应的语音消息 '
                   	replyMsg = reply.TextMsg(toUser, fromUser, content)
                   	return replyMsg.send()
                if recMsg.MsgType == 'voice':
                    	if recMsg.Recognition =='温度。':
				content = str(getData_time('temperature'))+'
室内温度为'+str(getData_value('temperature')) +'℃'
			elif recMsg.Recognition =='湿度。':
				content = str(getData_time('humidity'))+'
室内湿度为'+str(getData_value('humidity')) +'%'
			else:
				content =recMsg.Recognition+'
无法识别这条语音消息'
                    	replyMsg = reply.TextMsg(toUser, fromUser, content)
                    	return replyMsg.send()
                else:
                    	return reply.Msg().send()
            else:
                print "暂且不处理"
                return reply.Msg().send()
        except Exception, Argment:
            return Argment

通过API调用我们获取到的json数据,这样是不能直接给用户发送过去的,还需要对json进行处理提取主要的数据,例如提取温湿度数据和数据节点时间
# -*- coding: UTF-8

from OneNetApi import *
import json

def getData_value(datastreamid):
    test = OneNetApi("***************************") #  your API
    datastream_id = datastreamid
    limit = 1
    res3 = test.datapoint_get(device_id = "6975064", limit = limit, datastream_id = datastream_id)
    data = json.loads(res3.content.replace(']',' ').replace('[',' '))
    value = data['data']['datastreams']['datapoints']['value']
    return value
	
	
def getData_time(datastreamid):
    test = OneNetApi("***************************") #  your API
    datastream_id = datastreamid
    limit = 1
    res3 = test.datapoint_get(device_id = "6975064", limit = limit, datastream_id = datastream_id)
    data = json.loads(res3.content.replace(']',' ').replace('[',' '))
    time = data['data']['datastreams']['datapoints']['at'][0:19]
    return time

至于返回用户消息呢,依然是按照lxml格式,将我们获取到的数据和需要返回的用户信息添加进去就可以了
class TextMsg(Msg):
    def __init__(self, toUserName, fromUserName, content):
        self.__dict = dict()
        self.__dict['ToUserName'] = toUserName
        self.__dict['FromUserName'] = fromUserName
        self.__dict['CreateTime'] = int(time.time())
        self.__dict['Content'] = content

    def send(self):
        XmlForm = """
        <xml>
        <ToUserName><![CDATA[{ToUserName}]]></ToUserName>
        <FromUserName><![CDATA[{FromUserName}]]></FromUserName>
        <CreateTime>{CreateTime}</CreateTime>
        <MsgType><![CDATA[text]]></MsgType>
        <Content><![CDATA[{Content}]]></Content>
        </xml>
        """
        return XmlForm.format(**self.__dict)

微信后天还提供了语音识别接口,默认是打开的,当用户发送的是语音命令的时候后台接收的lxml中会比text消息多出Recognition这项,把识别结果当做text一样处理就能让公众号处理语音消息了,再次不再赘述了。
至此整个流程就结束了,当编写所有的代码后使用 python main.py 80 即可打开这项服务了,下面是效果图


国际惯例:源码


努力成为一名GEEK!
原文地址:https://www.cnblogs.com/FanMLei/p/10501041.html