├── README.md
├── berrypi
└── mqtt.py
├── client
├── app.js
├── app.json
├── app.wxss
├── pages
│ ├── index
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ └── logs
│ │ ├── logs.js
│ │ ├── logs.json
│ │ ├── logs.wxml
│ │ └── logs.wxss
└── utils
│ └── util.js
└── server
└── berrypiServer.js
/README.md:
--------------------------------------------------------------------------------
1 | # 微信小程序-树莓派照片监控
2 |
3 | ### 说明:
4 |
5 | 实现树莓派照片监控功能,特色:
6 | - 小程序和服务器使用webSocket通信
7 | - 树莓派和服务器使用mqtt通信
8 |
9 | ### 数据接口:
10 |
11 | - wss://socket.getweapp.com
12 |
13 | ### 目录结构:
14 |
15 | client:
16 | - pages — 存放项目页面文件
17 | - utils — 存放格式化文件
18 |
19 | server:
20 | - berrypiServer.js — 服务器文件
21 |
22 | berrypi:
23 | - mqtt.js — 树莓派文件
24 |
25 | ### 开发环境:
26 |
27 | 微信web开发者工具 v0.11.122100
28 |
29 | ### 项目截图:
30 |
31 | https://www.getweapp.com/project?projectId=5899330e52e1e8733dc567fc
32 |
--------------------------------------------------------------------------------
/berrypi/mqtt.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # 树莓派照片监控
4 | # 作者:刘焱旺
5 | # 官网:www.getweapp.com
6 | # QQ群:499859691
7 | # 调试过程中有任何问题欢迎和我们联系
8 |
9 | import paho.mqtt.client as mqtt
10 | import json
11 |
12 | from qiniu import Auth, put_file, etag, urlsafe_base64_encode
13 | import qiniu.config
14 | import os, time
15 |
16 | #需要填写你的服务器IP
17 | ip = 'xxx'
18 |
19 | #需要填写你的 Access Key 和 Secret Key
20 | access_key = 'xxx'
21 | secret_key = 'xxx'
22 |
23 | #构建鉴权对象
24 | q = Auth(access_key, secret_key)
25 |
26 | #需要填写你的空间
27 | bucket_name = 'xxx'
28 |
29 | #需要填写你的空间域名
30 | base = 'http://xxx'
31 |
32 | #照片缓存
33 | cache = ''
34 | lastUpdated = 0
35 |
36 | #生成上传 Token,可以指定过期时间等
37 | token = q.upload_token(bucket_name, None, 3600)
38 |
39 | def upload(localfile):
40 | ret, info = put_file(token, None, localfile)
41 | return ret
42 |
43 | # 连接成功回调函数
44 | def on_connect(client, userdata, flags, rc):
45 | print("Connected with result code " + str(rc))
46 | client.subscribe("CAMERA/PHOTO")
47 |
48 | # 消息推送回调函数
49 | def on_message(client, userdata, msg):
50 | global base, cache, lastUpdated
51 | print(msg.topic+" "+str(msg.payload))
52 | if int(time.time()) < lastUpdated + 5:
53 | client.publish('CAMERA/PHOTO/BACK', '{"id":"'+str(msg.payload)+'", "path":"'+cache+'"}')
54 | return
55 | r = os.system('fswebcam -r 640*480 imagex01.jpg')
56 | ret = upload('./imagex01.jpg')
57 | print ret['hash']
58 | cache = base+ret['hash']
59 | lastUpdated = int(time.time())
60 | client.publish('CAMERA/PHOTO/BACK', '{"id":"'+str(msg.payload)+'", "path":"'+base+ret['hash']+'"}')
61 |
62 |
63 | if __name__ == '__main__':
64 | client = mqtt.Client()
65 | client.on_connect = on_connect
66 | client.on_message = on_message
67 |
68 | try:
69 | # 请根据实际情况改变MQTT代理服务器的IP地址
70 | global ip
71 | client.connect(ip, 1883, 60)
72 | client.loop_forever()
73 | except KeyboardInterrupt:
74 | client.disconnect()
75 |
--------------------------------------------------------------------------------
/client/app.js:
--------------------------------------------------------------------------------
1 | /*
2 | * 树莓派照片监控
3 | * 作者:刘焱旺
4 | * 官网:www.getweapp.com
5 | * QQ群:499859691
6 | * 调试过程中有任何问题欢迎和我们联系
7 | */
8 |
9 | App({
10 | onLaunch: function() {
11 | //调用API从本地缓存中获取数据
12 | var logs = wx.getStorageSync('logs') || []
13 | logs.unshift(Date.now())
14 | wx.setStorageSync('logs', logs)
15 | },
16 | getUserInfo: function(cb) {
17 | var that = this
18 | if (this.globalData.userInfo) {
19 | typeof cb == "function" && cb(this.globalData.userInfo)
20 | } else {
21 | //调用登录接口
22 | wx.login({
23 | success: function() {
24 | wx.getUserInfo({
25 | success: function(res) {
26 | that.globalData.userInfo = res.userInfo
27 | typeof cb == "function" && cb(that.globalData.userInfo)
28 | }
29 | })
30 | }
31 | })
32 | }
33 | },
34 | globalData: {
35 | userInfo: null
36 | }
37 | })
38 |
--------------------------------------------------------------------------------
/client/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "pages":[
3 | "pages/index/index",
4 | "pages/logs/logs"
5 | ],
6 | "window":{
7 | "backgroundTextStyle":"light",
8 | "navigationBarBackgroundColor": "#1AAD19",
9 | "navigationBarTitleText": "树莓派照片监控",
10 | "navigationBarTextStyle":"light"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/client/app.wxss:
--------------------------------------------------------------------------------
1 | /**app.wxss**/
2 | .container {
3 | height: 100%;
4 | display: flex;
5 | flex-direction: column;
6 | align-items: center;
7 | justify-content: space-between;
8 | padding: 200rpx 0;
9 | box-sizing: border-box;
10 | }
11 |
--------------------------------------------------------------------------------
/client/pages/index/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * 树莓派照片监控
3 | * 作者:刘焱旺
4 | * 官网:www.getweapp.com
5 | * QQ群:499859691
6 | * 调试过程中有任何问题欢迎和我们联系
7 | */
8 |
9 | Page({
10 | data: {
11 | photo: '',
12 | open: false
13 | },
14 | fetch: function() {
15 | if(!this.data.open){
16 | console.log('请稍后再试')
17 | return
18 | }
19 | wx.sendSocketMessage({
20 | data:JSON.stringify({
21 | cmd:'BERRY_PI'
22 | })
23 | })
24 | },
25 | onLoad: function() {
26 | wx.connectSocket({
27 | url: 'wss://socket.getweapp.com'
28 | })
29 |
30 | wx.onSocketOpen((res) => {
31 | console.log('连接服务器:成功')
32 | this.setData({
33 | open: true
34 | })
35 | })
36 |
37 | wx.onSocketMessage((res) => {
38 | console.log('receve:'+res.data)
39 | console.log(this)
40 | this.setData({
41 | photo: JSON.parse(res.data).path
42 | })
43 | })
44 |
45 | wx.onSocketClose((res) => {
46 | console.log('连接服务器:关闭')
47 | this.setData({
48 | open: false
49 | })
50 | wx.connectSocket({
51 | url: 'wss://socket.getweapp.com/test'
52 | })
53 | })
54 |
55 | wx.onSocketError((res) => {
56 | console.log('连接服务器:失败')
57 | this.setData({
58 | open: false
59 | })
60 | })
61 | }
62 | });
63 |
--------------------------------------------------------------------------------
/client/pages/index/index.json:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/client/pages/index/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/client/pages/index/index.wxss:
--------------------------------------------------------------------------------
1 | /**index.wxss**/
2 | page{
3 | background:black;
4 | }
5 | .container{
6 | display: block;
7 | }
8 | .container image{
9 | width: 100%;
10 | position: fixed;
11 | top: 0;
12 | height: 500px;
13 | }
14 |
15 | .container button{
16 | position: fixed;
17 | bottom: 0;
18 | border-radius: 0;
19 | width: 100%;
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/client/pages/logs/logs.js:
--------------------------------------------------------------------------------
1 | //logs.js
2 | var util = require('../../utils/util.js')
3 | Page({
4 | data: {
5 | logs: []
6 | },
7 | onLoad: function() {
8 | this.setData({
9 | logs: (wx.getStorageSync('logs') || []).map(function(log) {
10 | return util.formatTime(new Date(log))
11 | })
12 | })
13 | }
14 | })
15 |
--------------------------------------------------------------------------------
/client/pages/logs/logs.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "查看启动日志"
3 | }
--------------------------------------------------------------------------------
/client/pages/logs/logs.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{index + 1}}. {{log}}
5 |
6 |
7 |
--------------------------------------------------------------------------------
/client/pages/logs/logs.wxss:
--------------------------------------------------------------------------------
1 | .log-list {
2 | display: flex;
3 | flex-direction: column;
4 | padding: 40rpx;
5 | }
6 | .log-item {
7 | margin: 10rpx;
8 | }
9 |
--------------------------------------------------------------------------------
/client/utils/util.js:
--------------------------------------------------------------------------------
1 | function formatTime(date) {
2 | var year = date.getFullYear()
3 | var month = date.getMonth() + 1
4 | var day = date.getDate()
5 |
6 | var hour = date.getHours()
7 | var minute = date.getMinutes()
8 | var second = date.getSeconds()
9 |
10 |
11 | return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
12 | }
13 |
14 | function formatNumber(n) {
15 | n = n.toString()
16 | return n[1] ? n : '0' + n
17 | }
18 |
19 | module.exports = {
20 | formatTime: formatTime
21 | }
22 |
--------------------------------------------------------------------------------
/server/berrypiServer.js:
--------------------------------------------------------------------------------
1 | /*
2 | * 树莓派照片监控
3 | * 作者:刘焱旺
4 | * 官网:www.getweapp.com
5 | * QQ群:499859691
6 | * 调试过程中有任何问题欢迎和我们联系
7 | */
8 |
9 | import { Server } from 'ws'
10 | import uuid from 'uuid'
11 | import moment from 'moment'
12 |
13 | import mqtt from 'mqtt'
14 |
15 | const client = mqtt.connect('mqtt://127.0.0.1')
16 |
17 | client.on('connect', () => {
18 | console.log('connected')
19 | client.subscribe('CAMERA/PHOTO/BACK')
20 | })
21 |
22 | client.on('message', (topic, message) => {
23 | const data = JSON.parse(message.toString())
24 | console.log(topic, data)
25 | if(!(data.id in clients)){
26 | return
27 | }
28 | clients[data.id].send(JSON.stringify({
29 | cmd:"CAMERA/PHOTO",
30 | path: data.path
31 | }))
32 | })
33 |
34 | const wss = new Server({ port: 3000});
35 |
36 | const messages = []
37 |
38 | onst BERRY_PI = 'BERRY_PI'
39 | const clients = {}
40 |
41 |
42 | wss.on('connection', function connection(ws) {
43 | ws.clientId = uuid.v1()
44 | clients[ws.clientId] = ws
45 | console.log('client connected:'+ws.clientId)
46 |
47 | ws.on('message', (message) => {
48 | try{
49 | const data = JSON.parse(message)
50 | switch(data.cmd){
51 | case BERRY_PI:
52 | client.publish('CAMERA/PHOTO', ws.clientId)
53 | return
54 | default:
55 | return
56 | }
57 | }catch(e){
58 | console.log(e)
59 | }
60 | })
61 |
62 | ws.on('close', () => {
63 | if(ws.clientId)
64 | delete clients[ws.clientId]
65 | })
66 | })
67 |
68 |
--------------------------------------------------------------------------------