【问题标题】:Flask + Flask_SocketIO = RuntimeError: Working outside of request contextFlask + Flask_SocketIO = RuntimeError:在请求上下文之外工作
【发布时间】:2018-04-09 05:02:29
【问题描述】:

我有以下主文件。

from flask import Flask, render_template, request
from flask_socketio import SocketIO, emit, send
import gpio_control
from gevent import monkey
monkey.patch_all()


simplyfishy = Flask(__name__)
simplyfishy.config['SECRET_KEY'] = 'ARG'
socketio = SocketIO(simplyfishy, async_mode='gevent')

@simplyfishy.route('/')
def index():
    return render_template('home.html')


@socketio.on('message')
def handle_message(message):
    emit(message, {'data': 'main!'})


if __name__ == '__main__':
    socketio.run(simplyfishy, host='0.0.0.0')

这是gpio_control文件

import RPi.GPIO as GPIO
from pushbullet import Pushbullet
from flask_socketio import emit

# Set the GPIO mode to Broadcom
GPIO.setmode(GPIO.BCM)

# Create a dictionary for sensors ans their status
float_switches = {
    24: {'name': 'Float Switch 1', 'state': GPIO.LOW},
    25: {'name': 'Float Switch 2', 'state': GPIO.LOW}
}

# Setup float switches
for float_switch in float_switches:
    GPIO.setup(float_switch, GPIO.IN, pull_up_down=GPIO.PUD_UP)


# Define callback function for event detection
def floatsw(channel):
    from __main__ import simplyfishy
    with simplyfishy.app_context():
        if GPIO.input(channel):
            print(float_switches[channel]['name'] + " deactivated!")
            emit('float_sw', {'data': 'deactivated!'})
        else:
            print(float_switches[channel]['name'] + " activated!")
            # pb.push_note("Simply Fishy", "Sump water level is low")
            emit('float_sw', {'data': 'activated!'})


GPIO.add_event_detect(24, GPIO.BOTH, callback=floatsw, bouncetime=1000)
GPIO.add_event_detect(25, GPIO.BOTH, callback=floatsw, bouncetime=1000)

如您所见,我想做的是向烧瓶页面发送更新,显示开关已实时激活或停用。但是,当我触发浮动开关时,我得到以下信息

Float Switch 1 activated!
Traceback (most recent call last):
  File "/home/pi/simplyfishy/gpio_control.py", line 61, in floatsw
    emit('float_sw', {'data': 'activated!'})
  File "/home/pi/.local/lib/python2.7/site-packages/flask_socketio/__init__.py", line 688, in emit
    namespace = flask.request.namespace
  File "/home/pi/.local/lib/python2.7/site-packages/werkzeug/local.py", line 347, in __getattr__
    return getattr(self._get_current_object(), name)
  File "/home/pi/.local/lib/python2.7/site-packages/werkzeug/local.py", line 306, in _get_current_object
    return self.__local()
  File "/home/pi/.local/lib/python2.7/site-packages/flask/globals.py", line 37, in _lookup_req_object
    raise RuntimeError(_request_ctx_err_msg)
RuntimeError: Working outside of request context.

我已经用谷歌搜索并查看了其他示例,但我似乎无法找出问题所在。主文件中的 @socketio.on('message') 我认为甚至不需要,但也许它是需要的,我需要从我的 gpio_control 中触发它以便将其发送到页面?我觉得我错过了这个流程或一些简单的东西。非常感谢您的帮助!

编辑:以下代码已更新并已修复错误消息的发生。然而,这样做我确实有一个循环依赖。由于以下错误消息,我相信是这样。

ImportError: 无法在控制台中简单地导入名称。从谷歌向我展示的内容来看,这将是循环依赖问题。

【问题讨论】:

    标签: python flask flask-socketio


    【解决方案1】:

    问题是您的floatsw() 函数中的两个emit() 调用没有提供足够的信息,因此它们尝试从请求上下文中获取丢失的数据。由于该函数是在没有请求上下文的情况下调用的,因此您会收到错误消息。

    缺少的两个信息位是发射的接收者和命名空间。看起来您没有为此应用程序使用自定义命名空间,因此您可以通过在这两个发射中添加 namespace='/' 作为参数来解决缺少的命名空间。

    就收件人而言,您可以添加broadcast=True 以发送给所有连接的客户端,或者使用room=<sid>,其中<sid> 是您要将消息发送到的客户端的会话ID。您还可以使用您在此处创建的任何自定义房间的名称。

    总而言之,避免错误的快速而肮脏的方法是按如下方式更改您的发射:

    def floatsw(channel):
        with simplyfishy.app_context():
            if GPIO.input(channel):
                print(float_switches[channel]['name'] + " deactivated!")
                emit('float_sw', {'data': 'deactivated!'}, namespace='/', broadcast=True)
            else:
                print(float_switches[channel]['name'] + " activated!")
                # pb.push_note("Simply Fishy", "Sump water level is low")
                emit('float_sw', {'data': 'activated!'}, namespace='/', broadcast=True)
    

    然后,您可能需要制定策略来避免广播并仅针对特定客户。

    编辑:将应用上下文添加到示例中。

    【讨论】:

    • 谢谢,我已经尝试过了,我会得到以下结果。 gist.github.com/SimplySynced/5d7784d3d0e95865f5f799dfc52d137c 相同,但该行显示更新的信息。我是否需要将烧瓶信息以及 app.app_contex 添加到 gpio_control 文件中?
    • 抱歉,我告诉过你要消除请求上下文,但是是的,你仍然需要应用上下文。让我更新一下问题。
    • 谢谢,但是现在我得到了 Traceback(最近一次调用最后一次):文件“/home/pi/simplyfishy/gpio_control.py”,第 54 行,在 floatsw 中,带有 simplefishy.app_context():NameError:全局名称“simplyfishy”未定义 Traceback(最近一次调用最后):文件“/home/pi/simplyfishy/gpio_control.py”,第 54 行,在 floatsw 中使用 simplefishy.app_context():NameError:全局名称“simplyfishy”是未定义
    • 我相信这是因为我没有定义 SimplyFishy。它在我的 SimplyFishy.py 文件中定义,但不在 gpio_control.py 文件中。我需要将应用程序导入第二个文件吗?比如 from SimplyFishy import current_app as SimplyFishy?
    • 您想将其导入为from __main__ import simplyfishy。为避免循环依赖,您可能需要将此导入放在 floatsw() 函数中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-17
    • 2023-02-03
    • 1970-01-01
    • 1970-01-01
    • 2015-09-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多