Accessing blinkt from 2 different processes


#1

Hello guys,

I am using 2 different processes (2 different python scripts) running simultaneously and accessing the blinkt leds. when 1 process dies, it switches off all leds upon failure, catching this event, other process will switch on an led for indicating failure of 1st process. This is not working as expected. When I debugged, it is entering the set_pixel function, setting all rgb and brightness values correctly. but led light is not coming up. could you please help me with this.


Blinkt get_pixel
#2

Could you share some code? A minimum basic example of the two scripts to reproduce would help. It’s difficult to guess what might be going wrong otherwise.


#3

Keep the below code in 1st script (led_show.py). This will switch on the 1st led and after 10 seconds it will switch on the 2nd led.

import blinkt
import time
blinkt.set_pixel(0, 255, 0, 0, brightness=255)
blinkt.show()
time.sleep(10)
print(‘next led’)
blinkt.set_pixel(1, 255, 0, 0, brightness=255)
blinkt.show()

Keep the below code in the 2nd script (clear.py).

import blinkt
blinkt.set_pixel(0, 0, 0, 0, brightness=0)
blinkt.show()

Run the 1st script in one terminal and before 10 seconds(before 2nd led comes up) run the 2nd script from different terminal. 2nd clears all leds instead of not just 1st led. And after 10 seconds 2nd led will not turn on from the 1st script which will be still running.


#4

Blinkt! is driven in such a way that attempting to drive it from two scripts simultaneously is only ever likely to result in weirdness of varying degrees. While you can probably solve your particular problem with something like:

blinkt.set_clear_on_exit(False)

You will probably run into further issues if these scripts ever try to access Blinkt! at the same time.

There’s currently a work-in-progress project to create a pretty fully featured MQTT server for Blinkt! which you can see the progress of here: https://github.com/pimoroni/blinkt/pull/64

This is one program which runs and becomes the gateway to accessing Blinkt!- then setting/changing pixels is done by multiple client programs which send MQTT messages. This sounds complicated, but it’s one of a few good ways to solve the simultaneous access problem.


#5

I guess in blinkt.show(), you reset all leds and show things newly. Is it not possible to make show() function with respect to only 1 led.


#6

It’s not possible:

  1. You’re always toggling the same GPIO pins, so any two programs running together would just blend their output into an unpredictable mess

  2. The pixels are a contiguous chain from 0 to 7, you must clock out the value of every single pixel and latch the whole chain in order to update. They are not addressable- IE: the hardware doesn’t physically support setting a single pixel.

Additional problems are caused by the fact that Program A and Program B both have their own idea of what’s currently displaying on Blinkt! - their “Buffer.”

The buffer of Program A might light LED1, and the buffer of Program B might light LED2, but these programs have no idea the other one exists so all of the other LEDs in their buffer are set to off, or 0 0 0. So Program B will always turn off Program A’s LED when it activates.


#7

So we cannot use blinkt for applications like what we are using. :(


#8

You can- you just must approach the problem properly. See the MQTT server in progress that I linked above as an example.

You need one Python program to interface with Blinkt!, and then your other programs talk via that. This could be achieved via MQTT, sockets, maybe even SIGUSR signals, HTTP and maybe even using 8 unused GPIO pins as “registers”.

Here’s a really quick and dirty example of the latter (possibly the simplest) way to accomplish this.

It uses GPIO pins 5, 6, 7, 8, 9, 10, 11, 12 as 8-bits of shared memory, that’s 8 distinct on/off states which can be shared between multiple Python applications.

To provide this functionality, we’ll start with pins.py:

import RPi.GPIO as GPIO

PINS = [5,6,7,8,9,10,11,12]

GPIO.setmode(GPIO.BCM)

GPIO.setup(PINS, GPIO.OUT, pull_up_down=GPIO.PUD_OFF)

def write_single(index, value):
    GPIO.output(PINS[index], value)

def read_single(index):
    return GPIO.input(PINS[index])

def read():
    value = 0
    for pin in PINS:
        value <<= 1
        value |= GPIO.input(pin)
    return value

def write(value):
    value &= 0xff
    for pin in PINS:
        GPIO.output(pin, value & 0b10000000)
        value <<= 1

Now we need to read these 8-bits and do something meaningful with them, here’s server.py. This server runs constantly and updates Blinkt! by lighting the pixels that correspond to each set bit:

import time
import blinkt
import pins

FPS = 1.0 / 60

while True:
    blinkt.clear()
    value = pins.read() # Read BCM 5, 6, 7 etc
    for x in range(8):
        if value & 1:
            blinkt.set_pixel(x,128,0,0)
        value >>= 1
    blinkt.show()
    time.sleep(FPS)

And finally we want some clients to set these bits so the server has something to do, here’s client.py setting just one bit:

import pins
import time

while True:
    pins.write_single(0, 1) # Write bit 0 high, this sets BCM5 high
    time.sleep(0.5)
    pins.write_single(0, 0) # Write bit 0 low, this sets BCM5 low
    time.sleep(0.5)

If you run server.py in one Terminal session, and client.py in another the result should be one blinking red LED on your Blinkt!


#9

Thank you so much for the wonderful example. I will try this and get back to you soon :)