我使用覆盆子pi3和烧瓶进行家庭自动化项目。我希望能够发送将在网页上显示的实时信息(html + javascript)。为此,我使用扩展flask-socketio,但它似乎不起作用。以下是我的代码的摘录:
编辑:经过大量研究,我认为有必要创建一个线程,以便服务器在处理其他任务时向客户端发送消息。然后我修改了我的代码如下。但是我遇到了一个问题:当捕获到第一个移动时,客户端只收到一次通知。当捕获其他动作时它什么也没有收到,在我的控制台中我有一个错误:
返回self.greenlet.switch()超时:超时
#-*- coding:utf-8 -*-
import eventlet
eventlet.monkey_patch()
from flask import Flask, render_template, send_from_directory, jsonify, request
from flask_socketio import SocketIO, send, emit
import os
import sys
import threading
import time
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
PIN=4
GPIO.setup(PIN, GPIO.IN)
app = Flask(__name__, static_url_path='/static')
app.config['SECRET_KEY'] = 'secret'
async_mode = "eventlet"
socketio = SocketIO(app, async_mode = async_mode)
thread = threading.Thread()
thread_stop_event = threading.Event()
@app.route('/<path:path>')
def static_file(path):
return app.send_static_file(path)
class MotionThread(threading.Thread):
def __init__(self):
self.delay = 1
super(MotionThread, self).__init__()
def startMotion(self):
try:
mouv = False
while not thread_stop_event.isSet():
if GPIO.input(PIN):
if mouv == False:
socketio.emit('motion', "Motion detected", namespace='/test')
sleep(self.delay)
mouv = True
else:
mouv = False
except: pass
def run(self):
self.startMotion()
@socketio.on('connect', namespace='/test')
def test_connect():
global thread
print('Client connected')
if not thread.isAlive():
print "Starting Thread"
thread = RandomThread()
thread.start()
@app.route('/')
def index():
return render_template('index.html')
if __name__ == '__main__':
socketio.run(app, host='0.0.0.0', port= 5000, debug=True)
第一个代码:
from flask import Flask, render_template, send_from_directory, jsonify, request
from flask_socketio import SocketIO, emit, send
import time
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
PIN=4
GPIO.setup(PIN, GPIO.IN)
app = Flask(__name__, static_url_path='/static')
app.config['SECRET_KEY'] = 'secret'
socketio = SocketIO(app)
@app.route('/<path:path>')
def static_file(path):
return app.send_static_file(path)
@app.route('/')
def index():
return render_template ('index.html')
@app.route('/_startMotion')
def startMotion():
try:
motion = False
while True:
if GPIO.input(PIN):
if motion == False: test_message()
motion = True
else:
motion = False
time.sleep(.3)
except: pass
return 'ok'
@socketio.on('motion', namespace = '/motion-socket')
def test_message():
emit('motion detected', {'data': 'Motion detected'})
if __name__ == '__main__':
socketio.run(app, host='0.0.0.0', port=5000, debug=True)
EDIT2 :根据我的第一个代码,javascript代码现在看起来像这样:
<script type=text/javascript>
$(document).ready(function(){
var socket = io.connect('http://' + document.domain + ':' + location.port + '/test');
socket.on('motion', function(msg){
alert("Server message" + msg);
});
});
</script>
我希望能够在检测到移动时在我的网页上发布消息。然后想一想我的代码中什么不起作用?我需要帮助搞清楚为什么线程只运行一次。感谢
答案 0 :(得分:0)
我对SocketIO不太熟悉,但似乎您的JavaScript代码并未指定套接字应连接到的URL。
根据Miguel Grinberg's tutorial中的示例,以下是您的JavaScript应该是什么样子:
$(document).ready(function(){
var socket = io.connect('http://' + document.domain + ':' + location.port + '/motion-socket');
socket.on('motion', function(msg){
$('#message').text(msg.data);
$('#message').fadeIn().delay(3000).fadeOut();
});
});
此外,您的JavaScript似乎正在侦听名为&#34; motion&#34;的事件,但您的Python test_message()
套接字函数使用send()
函数发送事件,该函数不会&# 39; t允许指定事件名称,而不是使用{em> 允许指定事件名称的emit()
函数:
要发送事件,Flask服务器可以使用Flask-SocketIO提供的send()和emit()函数。 send()函数向客户端发送字符串或JSON类型的标准消息。 emit()函数在自定义事件名称下发送消息。
您似乎希望该功能看起来更像这样:
@socketio.on('motion', namespace='/motion-socket')
def test_message():
emit('motion detected', {'data': 'Motion Detected'})