2

I have my following main file.

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

This is the gpio_control file

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)

What I would like to do is as you can see I want to send an update to the flask page showing that the switch is either activated or deactivated in real time. When I trigger the float switch however I am getting the following

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.

I've googled and looked at may other examples but I can not seem to find out what is wrong. The @socketio.on('message') in the main file I dont think is even needed but maybe it is and I need to trigger that from within my gpio_control in order to send that to the page? I feel I'm missing the flow or something simple with this one. Greatly appreciate the help!

EDIT: The following code is updated and has fixed the error message from occurring. However in doing so I do have a circular dependency. I believe so due to the following error message.

ImportError: cannot import name simplyfishy in the console. Which from what a google has shown me would be the circular dependency issue.

1 Answer 1

4

The problem is that the two emit() calls in your floatsw() function were not given enough information, so they try to obtain the missing data from the request context. Since that function is invoked without a request context, then you get the error.

The two missing bits of information are the recipient of the emit, and the namespace. It looks like you are not using a custom namespace for this application, so you can address the missing namespace by adding namespace='/' as an argument in those two emits.

As far as the recipient, you can add broadcast=True to send to all connected clients, or else use room=<sid>, where <sid> is the session id of the client you want to send the message to. You can also use the name of any custom room that you created here.

So to summarize, the quick and dirty way to avoid the error is to change your emits as follows:

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)

You may then need to figure out a strategy to avoid broadcasting and just targeting specific clients.

Edit: added the app context to the example.

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks, I've given that a try and I sitll get the following. gist.github.com/SimplySynced/5d7784d3d0e95865f5f799dfc52d137c its the same but the line shows updated information. Do I need to add the flask info as well as with app.app_contex to the gpio_control file?
Oh sorry, I told you to eliminate the request context, but yes, you still need the app context. Let me update the question.
Thanks, however now I get Traceback (most recent call last): File "/home/pi/simplyfishy/gpio_control.py", line 54, in floatsw with simplyfishy.app_context(): NameError: global name 'simplyfishy' is not defined Traceback (most recent call last): File "/home/pi/simplyfishy/gpio_control.py", line 54, in floatsw with simplyfishy.app_context(): NameError: global name 'simplyfishy' is not defined
I believe this is because I do not have SimplyFishy defined. It is defined in my SimplyFishy.py file but not the gpio_control.py file. Do I need to import the app into the 2nd file. Such as from SimplyFishy import current_app as SimplyFishy?
You want to import it as from __main__ import simplyfishy. To avoid circular dependencies you may need to put this import inside the floatsw() function.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.