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


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


    准备工作:

    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!
  • 相关阅读:
    SQL集合函数中case when then 使用技巧
    appium -- 页面出现弹窗,关闭后,无法识别页面元素
    SQLite3中dos命令下退出"...>"状态的方法
    android SharedPreferences 浅析
    BigDecimal简单说
    appium-手势密码实现-automationName 是Appium的情况
    Android color颜色-色号总结
    adb启动和关闭
    DesiredCapabilities的作用
    Android 使用intent传递返回值:startActivityForResult()与onActivityResult()与setResult()参数分析,activity带参数的返回
  • 原文地址:https://www.cnblogs.com/FanMLei/p/10501041.html
Copyright © 2020-2023  润新知