为什么我的Flask-SocketIO服务器没有成功地将消息发送到我的客户端JavaScript?

时间:2021-11-07 15:29:58

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类型的标准消息。函数的作用是:发送一个自定义事件名称的消息。

Source

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类型的标准消息。函数的作用是:发送一个自定义事件名称的消息。

Source

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'})