源码

老习惯,先抛源码,老司机可以直接读源码

动机

  • 近期公司有一个有趣的项目,希望用乐高玩具式的可视化编程工具来操控硬件(在网页中)
    • 所以想把硬件的响应包装为服务
      • 于是得到可以用微信操作树莓派这个副产品
  • 树莓派操控硬件需要有root权限,作为服务之后则没有限制
  • 解耦

想法

  • 将微信视为控制界面(interface), 获得联网能力(远程操作)
  • 将树莓派视为连接代码和物理世界的介质

架构设计

  • 初期效用flask作为web框架
  • 把led_server视为下位机,api视为指令集

树莓派与GPIO

关于如何使用树莓派的引脚操作外部设备,推荐阅读mango同学的树莓派GPIO入门01-使用GPIO接口控制发光二极管闪烁,写得十分清楚

通过RPi.GPIO库,我们几乎不需要硬件的知识,就能轻易地用python代码操控硬件

接口定义

我们接下来led为例,演示如何将硬件功能暴露为api,可通过http请求,操控硬件(暂不考虑操作权限/安全问题,如果你愿意可以简单定义一个秘钥:?key=xx),对细节感情兴趣的小伙伴可以跟进我的源码库,我有计划把它做得完备。

目前我们定义三个功能:

  • 点亮led灯
  • 熄灭led灯
  • 使led灯闪烁几次

接下来使用flask将其暴露出去,成为web api

代码读起来很容易:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 点亮led灯
@app.route('/led_up')
def led_up():
    # 让GPIO14输出高电平(LED灯亮)
    RPi.GPIO.output(14, True)
    return 'ok'

# 熄灭led灯
@app.route('/led_down')
def led_down():
    # 让GPIO14输出低电平(LED灯灭)
    RPi.GPIO.output(14, False)
    return 'ok'

# 使led灯闪烁几次
@app.route('/led_up_down')
def led_up_down():
    for i in range(0, 5):
        RPi.GPIO.output(14, True)
        # 持续一段时间
        time.sleep(0.5)
        RPi.GPIO.output(14, False)
        time.sleep(0.5)
    return 'ok'

完整的源码参考led_server.py

现在我们可以把服务跑起来了:sudo python led_server.py

ps: websocket版本参考这里:led_websocket.py

测试接口

我的树莓派当前ip为:192.168.0.106

我们对这些api进行测试:

  • 点亮红灯: curl 192.168.0.106/led_up
  • 熄灭红灯: curl 192.168.0.106/led_down
  • 闪啊闪 : curl 192.168.0.106/led_up_down

你也可以在浏览器里控制这些灯(使用js):

1
2
3
xmlhttp=new XMLHttpRequest();
xmlhttp.open("GET","http://192.168.0.106/led_up_down",true); //闪烁
xmlhttp.send();

如此一来我们可以在浏览器里操控硬件了

对接微信

对接微信这步很简单,如果你读过我之前的文章:把聊天机器人接入微信,直接看源码就好了。没读过前文也没关系,代码很好理解,我把核心部分列下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from wxbot import WXBot
import requests
led_server = 'http://127.0.0.1:5000/'

class MyWXBot(WXBot):
    def _led(self,msg,user_input,action):
        response = '正在{}'.format(user_input)
        self.send_msg_by_uid(response, msg['user']['id'])
        url = led_server+action
        requests.get(url)
        response = '完成{}'.format(user_input)
        self.send_msg_by_uid(response, msg['user']['id'])


    def handle_msg_all(self, msg):
        if msg['msg_type_id'] == 4 and msg['content']['type'] == 0:
            user_input = msg["content"]["data"]
            #payload={"user_input":user_input}
            if '关' in user_input:
                self._led(msg,user_input,'led_down')
            if '开' in user_input:
                self._led(msg,user_input,'led_up')
            if '闪' in user_input:
                self._led(msg,user_input,'led_up_down')

源码在这里:wechat_pi.py

跑起来就好:python wechat_pi.py,由于需要微信扫码,所以先把你的树莓派连到屏幕上(使用图形界面),我使用VNC,之后有空把二维码弄到命令行里

脑洞

因为微信能在广域网中使用,所以你可以在任何能联网的地方控制树莓派了,进行远程控制,我最近的一个脑洞是在下班路上用微信给树莓派发一个打开空调的消息,就可以提前打开空调啦

原理也很简单使用红外接收器学习空调遥控器的指令集(目前只要开关机的指令),然后使用红外发射器伪造成遥控器控制空调。最后对接到微信即可

目前采集红外信号部分已经完成了