Explorer Hat pro flickering light when I turn it on using Flask endpoint


#1

Hi, I am new to Python, Flask and Explorer Hat. I am having trouble when running simple program of controlling Explorer Hat using web requests.

@app.route("/on/")
def turnon(light = ‘None’):
if light == ‘yellow’:
resp = make_response(light + ’ is on’)
eh.light.yellow.on()
return resp

This light is not flickering when I do eh.light.yellow.on() in python shell


#2

Any chance you could bung the whole lot of code here, so that we can have a look? You can format code in forums posts by wrapping it in triple backticks.


#3

The whole code posted below:

from flask import Flask
from flask import make_response
import explorerhat as eh

app = Flask(__name__)

@app.route("/")
@app.route("/on/<light>")
def turnon(light = 'None'):
        if light == 'yellow':
                eh.light.yellow.on()
        return make_response(light + ' is on')
@app.route("/off/<light>")
def turnoff(light = 'None'):
        if light == 'yellow':
                eh.light.yellow.off()
        return light + ' is off'

if __name__ == "__main__":
        app.run(host='0.0.0.0', port=80, debug = True)

Thanks.


#4

Short answer: It’s appears to be a bug in RPi.GPIO

There’s quite a lot at play with this apparently simple problem, but the crux of it is that Flask is fighting Explorer HAT for system resources, and you’re seeing the result of that fight manifest itself as flicker.

I’ll try and explain why this happens- it dates back to an issue with the Explorer HAT library crashing randomly which used to happen when it attempted to switch an output pin from PWM to regular ON/OFF too quickly, or at the wrong time.

This was fixed some time ago by treating ON/OFF states as just another level of PWM- ON being 100% duty cycle, and OFF being 0% duty cycle.

PWM - or Pulse Width Modulation - is a method of generating a variable voltage from a digital pin by turning it ON/OFF (usually) quickly and varying the ratio of on to off time. In RPi.GPIO - the library we use to do GPIO access - any pin can be a PWM pin, and the library will run a very simple loop in C to handle turning that pin on and off at the right times. The loop looks like this:

    while (p->running)
    {

        if (p->dutycycle > 0.0)
        {
            output_gpio(p->gpio, 1);
            full_sleep(&p->req_on);
        }

        if (p->dutycycle < 100.0)
        {
            output_gpio(p->gpio, 0);
            full_sleep(&p->req_off);
        }
    }

Source: https://sourceforge.net/p/raspberry-gpio-python/code/ci/default/tree/source/soft_pwm.c

The duty cycle of a PWM signal is the amount of time the pin spends in its ON state. In this loop if the pin is at 100% duty cycle it will never be turned OFF but it will be turned ON repeatedly. This shouldn’t really do anything though, as it’s just writing the same value to the same register. I don’t know why it results in flicker.

I can rip Explorer HAT out of the equation and still get this same issue:

from flask import Flask
from flask import make_response

import RPi.GPIO as GPIO

YELLOW = 17

GPIO.setmode(GPIO.BCM)
GPIO.setup(YELLOW, GPIO.OUT)

pwm = GPIO.PWM(YELLOW, 1000)
pwm.start(0)

app = Flask(__name__)

@app.route("/on/<light>")
def turnon(light = 'None'):
        if light == 'yellow':
                pwm.ChangeDutyCycle(100)

        return make_response(light + ' is on')

@app.route("/off/<light>")
def turnoff(light = 'None'):
        if light == 'yellow':
                pwm.ChangeDutyCycle(0)

        return light + ' is off'

if __name__ == "__main__":
        app.run(host='0.0.0.0', port=80, debug = True)

Unfortunately this doesn’t really lead us to a fix- you could remotely toggle the LEDs and some other things on Explorer HAT by doing away with the explorerhat library altogether and using RPi.GPIO to just write the pin states directly, like so:

from flask import Flask
from flask import make_response

import RPi.GPIO as GPIO

YELLOW = 17

GPIO.setmode(GPIO.BCM)
GPIO.setup(YELLOW, GPIO.OUT)

app = Flask(__name__)

@app.route("/on/<light>")
def turnon(light = 'None'):
        if light == 'yellow':
                GPIO.output(YELLOW, 1)

        return make_response(light + ' is on')

@app.route("/off/<light>")
def turnoff(light = 'None'):
        if light == 'yellow':
                GPIO.output(YELLOW, 0)

        return light + ' is off'

if __name__ == "__main__":
        app.run(host='0.0.0.0', port=80, debug = True)

The above code will work because it sets the pin state precisely once- there’s no thread hanging around in the background making a nuisance of itself.

You can find the pins for the other LEDs here: https://pinout.xyz/pinout/explorer_hat

And maybe store them in a dictionary like so:

leds = {'yellow': 17, 'blue': 4}

Then you can get smart in your turnon and turnoff handlers, looking up the LED in the dictionary.


#5

Thanks a lot. I had a feeling that it is a threading issue. I like doing simple things using base library so I will try the approach you have mentioned and will let you know if it works.


#6

Good luck! And enjoy.

I’m now trying to get to the bottom of the bug to see if we can fix it somehow! It could be a problem with Flask itself quietly doing weird things with the Python app it’s initialised in.


Automation HAT ADC issue
#7

Looks like it’s “reloader” that might be causing the problem, although I have only the faintest notion why.

If you still have your with-Explorer-HAT code lying about, you could try:

app.run(host='0.0.0.0', port=8080, debug=True, use_reloader=False)

#8

Yes looks like debug was the culprit. Adding use_reloader=False or removing debug both are working. Also using GPIO library is working good.

Thanks.