I work on a home automation project with raspberry pi3 and flask. I would like to be able to send real-time info that will be displayed on a web page (html + javascript). For this I use the extension flask-socketio but it does not seem to work. Here is an excerpt of my code:
我在一个家庭自动化项目中使用raspberry pi3和flask。我希望能够发送实时信息,这些信息将显示在网页(html + javascript)上。为此,我使用了扩展flask-socketio,但它似乎不起作用。下面是我的代码摘录:
EDIT: After a lot of research, I thought it was necessary to create a thread so that the server sends messages to the client while it is processing other tasks. Then I modified my code as below. But I encounter a problem: the client receives a notification only once, when the first movement is captured. It receives nothing when other movements are captured and in my console I have an error of the kind:
编辑:经过大量研究之后,我认为有必要创建一个线程,以便服务器在处理其他任务时向客户机发送消息。然后我修改了下面的代码。但是我遇到了一个问题:当第一个动作被捕获时,客户机只接收一次通知。当其他动作被捕获时,它不会接收到任何东西,在我的控制台上,我有这样一个错误:
return self.greenlet.switch() timeout: timed out
返回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)
FIRST CODE:
第一个代码:
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: Depending on my first code, the javascript code now looks like this:
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>
I would like to be able to post a message on my web page, whenever a movement is detected. Then an idea of what does not work in my code? I need help figuring out why the thread runs only once. Thanks
我希望能够在我的网页上发布一条消息,无论何时检测到移动。那么在我的代码中,什么是不工作的呢?我需要帮助弄清楚为什么线程只运行一次。谢谢
1 个解决方案
#1
0
I'm not very familiar with SocketIO, but it seems your JavaScript code isn't specifying what URL the socket should connect to.
我对SocketIO不是很熟悉,但是似乎您的JavaScript代码没有指定套接字应该连接到哪个URL。
Here's what your JavaScript should maybe look like instead, based on the example in Miguel Grinberg's tutorial:
下面是你的JavaScript应该是什么样子的,基于Miguel Grinberg的教程中的例子:
$(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();
});
});
Also, your JavaScript seems to be listening for an event with name "motion", but your Python test_message()
socket function sends the event with the send()
function, which doesn't allow for specifying an event name, rather than using the emit()
function, which does allow specifying an event name:
另外,您的JavaScript似乎正在侦听名为“motion”的事件,但是您的Python test_message()套接字函数使用send()函数发送事件,该函数不允许指定事件名称,而不是使用emit()函数,该函数允许指定事件名称:
To send events a Flask server can use the send() and emit() functions provided by Flask-SocketIO. The send() function sends a standard message of string or JSON type to the client. The emit() function sends a message under a custom event name.
要发送事件,Flask服务器可以使用Flask- socketio提供的send()和emit()函数。send()函数向客户机发送字符串或JSON类型的标准消息。函数的作用是:发送一个自定义事件名称的消息。
源
It seems like you'll want the function to look more like this:
你会希望函数看起来更像这样:
@socketio.on('motion', namespace='/motion-socket')
def test_message():
emit('motion detected', {'data': 'Motion Detected'})
#1
0
I'm not very familiar with SocketIO, but it seems your JavaScript code isn't specifying what URL the socket should connect to.
我对SocketIO不是很熟悉,但是似乎您的JavaScript代码没有指定套接字应该连接到哪个URL。
Here's what your JavaScript should maybe look like instead, based on the example in Miguel Grinberg's tutorial:
下面是你的JavaScript应该是什么样子的,基于Miguel Grinberg的教程中的例子:
$(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();
});
});
Also, your JavaScript seems to be listening for an event with name "motion", but your Python test_message()
socket function sends the event with the send()
function, which doesn't allow for specifying an event name, rather than using the emit()
function, which does allow specifying an event name:
另外,您的JavaScript似乎正在侦听名为“motion”的事件,但是您的Python test_message()套接字函数使用send()函数发送事件,该函数不允许指定事件名称,而不是使用emit()函数,该函数允许指定事件名称:
To send events a Flask server can use the send() and emit() functions provided by Flask-SocketIO. The send() function sends a standard message of string or JSON type to the client. The emit() function sends a message under a custom event name.
要发送事件,Flask服务器可以使用Flask- socketio提供的send()和emit()函数。send()函数向客户机发送字符串或JSON类型的标准消息。函数的作用是:发送一个自定义事件名称的消息。
源
It seems like you'll want the function to look more like this:
你会希望函数看起来更像这样:
@socketio.on('motion', namespace='/motion-socket')
def test_message():
emit('motion detected', {'data': 'Motion Detected'})