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

时间:2017-07-06 08:47:33

标签: javascript python flask

我使用覆盆子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>

我希望能够在检测到移动时在我的网页上发布消息。然后想一想我的代码中什么不起作用?我需要帮助搞清楚为什么线程只运行一次。感谢

1 个答案:

答案 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()函数在自定义事件名称下发送消息。

Source

您似乎希望该功能看起来更像这样:

@socketio.on('motion', namespace='/motion-socket')
def test_message():
    emit('motion detected', {'data': 'Motion Detected'})