Break out of loop if GPIO doesn't toggle in time - python

I'm changing some inputs to a device with relays, and I'm expecting at some point to break the firmware. The question is, when will this happen?
So, to determine if the firmware breaks, I'm monitoring some LEDs that normally blink during normal operation. I know that they will lock up in whatever state they're currently in when the firmware breaks. So, my bright idea was to simple feed that signal back into a Raspberry Pi and watch the that GPIO for a change-state. If I see the state change, then go ahead and flip the relays...Then look at the LEDs and make sure they're still blinking...rinse, repeat.
However, I would normally check this with an interrupt or something in C, but I'm writing this in Python...
What's the Python way for handling this? I know that if I don't see any blinking for 2 seconds or so, the test is over, but I'm not sure how to do this without invoking something like sleep...to which, I wouldn't be able to watch for pin changes.

From the gpio module, create a threaded callback function that fires every time a rising (or falling, etc...) edge is detected.
Then using signal within this function call signal.alarm() to reset an alarm whenever the pin changes.
Finally use signal.signal() to register a function for what should happen when the alarm is not reset in time (ie, firmware has broken)
this won't work if you're using windows unfortunately... you would need to implement your own alarm system with threading if you are

Related

How to implement "software interrupt"?

I am trying to create an "emergency stop" button that will immediately stop / break a linear code execution, but I am unable to come up with a solution. We have a GUI running in a browser and when a button is pushed an MQTT messages is received by the back end (which is written by me in Python).
There are different threads and the message is received, but when in another thread an if statement is running I am unable to figure out how to stop / break the linear code execution in that thread right away. Is there a good method for this?
It would be also OK if I could stop the entire thread and afterwards start it again (if another button is pushed). How could I do that?
I mean. I could probably solve this right away if I would be using a hardware switch and an interrupt (the code is running on a Raspberry Pi by the way). But I do not know how to "simulate" an interrupt and an interrupt service routing in a software. I most definitely can't be the only person facing the same problem.

wxPython & Pyserial - Continuous communication

I am a newbie to python and I am learning new things day by day. I have a question regarding integrating wxpython and pyserial. I am writing a GUI application to control a microprocessor through pyserial.
I have a wxpython script written - displays good - with buttons and text fields.
I tested communication with my microprocessor using small commands from pyserial - everything is in good place.
Problem:
I will be having a button (say Button A) on my GUI, which after clicked - checks if the serial communication is made (by sending and receiving data ofcourse). Once the communication is good, I have to make sure the communication stays good as long as I am using my GUI. So I decided to write an external function which continuously sends and reads data (probably a for loop). Based on the functions return value I will know if my serial communication is active or not (this might be a bad idea - but thats the best I got)
Now the problem is I have a lot of other features on my GUI, buttons, text fields etc.. So for example when another button (say button B) is pressed I want to send a specific command to the microprocessor. This requires I interrupt the serial communication which was going on in my Step 1, send data from button B click, then re-start the Step 1 communication again (to keep checking my serial communication is active). I dont know how I can interrupt the communication. The Step 1 serial communication (for loop) is bound to the Button A click. Once the Button A is clicked, it goes to a for loop and serial communication is checked continuously.
I have so many buttons and text fields like this - which are going to read and write data to the Microprocessor. Whenever I want to do an event, I have to stop the serial communication in step 1 and restart it again.
On top of all this, I can only check the serial communication (mentioned in Step 1) every 100ms. I cannot just write a for loop. I have to do some modifications - like time.delay(100ms) or something.
I dont know how to frame it, but may be I just require a good algorithm idea or implement this somehow with help of import sched or import thread
I am trying majorly to avoid import thread - because my microprocessor has very minimal RAM. Also using threading with wxPython is pain in the neck (what I read online)
One of my colleagues suggested using "timer service" from my Operating system. I dont think python have a feature like that. I have no clue what he is talking about, at the least. His argument is that, if I can use this, I can run the continuous serial communication check every 100ms very easily.
Any help would be greatly appreciated. I am not looking for any complicated solutions, I appreciate if you attach a piece of code, use very basic programming. I have the wxPython GUI in a single class.

Tkinter I/O Events

I'm new to Python as well as event-driven/GUI programming in general. As far as I can tell, all the event choices are things like mouse clicks and key presses.
I've written a set of functions in a separate library that read from an I2C device (on Raspberry Pi). The functions return -1 if nothing is read. So basically, I want to loop, calling the read function each time, until something besides -1 is returned.
My first instinct was to write something like:
readResult = -1
while (readResult == -1):
readResult = IO.read()
changeGUI()
This doesn't seem to work though in the tkinter structure. I get how to make a function get called on a button press, but I don't know how to do a custom event.
There are a few ways to go with this -- you could give up using Tkinter's mainloop(), and build your own event loop that polled for both types of events. Or, you could spawn a separate thread to monitor IO. Or, you could use the after() method from Tkinter.
For the first two cases, if IO.read() returns immediately, whether or not there's a result, then you probably want to throw a time.sleep() call in the loop, to avoid hogging the CPU.
If your call to IO.read() doesn't block, and doesn't take very long, it's very easy to set up a loop to poll the device every few milliseconds. All you need to do is something like this:
def read_one_result():
readResult = IO.read()
if readResult != -1:
changeGUI()
root.after(100, read_one_result)
This will read one result, update the GUI if anything was read, and the schedule itself to run again in 100ms.

Detecting computer/program shutdown in Python?

I have a Python script that runs in a loop regularly making adjustments to my lighting system. When I shut down my computer, I'd like my script to detect that, and turn off the lights altogether.
How do I detect my computer beginning to shut down in Python?
Or, assuming Windows sends Python a "time to shut down" notice, how do I intercept that to kill my lights and exit the loop?
This is the wrong way to go about performing action at system shutdown time. The job of the shutdown process is to stop running processes and then switch off power; if you try to detect this happening from within your program and react by getting some last action in, it's a race between the OS and your program who gets to go first. More likely than not your program will have been stopped before it managed to perform the necessary action.
Instead, you should hook into the normal protocol for doing things at shutdown. This will tell the shutdown utility to send an explicit signal to your program and wait for it to be acknowledged, which gives you enough time (within reason) to do what you have to do. How exactly to register to be notified varies with the OS, so this is more of an OS-specific question rather than a Python question.
You should react to the WM_ENDSESSION message.
This message is sent when the user logs off or the computer gets shut down.
If you want to react to Sleep/Hibernate as well, you'll need to handle WM_POWERBROADCAST with PBT_APMSUSPEND.
But I don't know how to do that in python. I guess it depends on your windowing framework since you need have a windows/a message loop to receive messages.

Interact with long running python process

I have a long running python process running headless on a raspberrypi (controlling a garden) like so:
from time import sleep
def run_garden():
while 1:
/* do work */
sleep(60)
if __name__ == "__main__":
run_garden()
The 60 second sleep period is plenty of time for any changes happening in my garden (humidity, air temp, turn on pump, turn off fan etc), BUT what if i want to manually override these things?
Currently, in my /* do work */ loop, i first call out to another server where I keep config variables, and I can update those config variables via a web console, but it lacks any sort of real time feel, because it relies on the 60 second loop (e.g. you might update the web console, and then wait 45 seconds for the desired effect to take effect)
The raspberryPi running run_garden() is dedicated to the garden and it is basically the only thing taking up resources. So i know i have room to do something, I just dont know what.
Once the loop picks up the fact that a config var has been updated, the loop could then do exponential backoff to keep checking for interaction, rather than wait 60 seconds, but it just doesnt feel like that is a whole lot better.
Is there a better way to basically jump into this long running process?
Listen on a socket in your main loop. Use a timeout (e.g. of 60 seconds, the time until the next garden update should be performed) on your socket read calls so you get back to your normal functionality at least every minute when there are no commands coming in.
If you need garden-tending updates to happen no faster than every minute you need to check the time since the last update, since read calls will complete significantly faster when there are commands coming in.
Python's select module sounds like it might be helpful.
If you've ever used the unix analog (for example in socket programming maybe?), then it'll be familiar.
If not, here is the select section of a C sockets reference I often recommend. And here is what looks like a nice writeup of the module.
Warning: the first reference is specifically about C, not Python, but the concept of the select system call is the same, so the discussion might be helpful.
Basically, it allows you to tell it what events you're interested in (for example, socket data arrival, keyboard event), and it'll block either forever, or until a timeout you specify elapses.
If you're using sockets, then adding the socket and stdin to the list of events you're interested in is easy. If you're just looking for a way to "conditionally sleep" for 60 seconds unless/until a keypress is detected, this would work just as well.
EDIT:
Another way to solve this would be to have your raspberry-pi "register" with the server running the web console. This could involve a little bit extra work, but it would give you the realtime effect you're looking for.
Basically, the raspberry-pi "registers" itself, by alerting the server about itself, and the server stores the address of the device. If using TCP, you could keep a connection open (which might be important if you have firewalls to deal with). If using UDP you could bind the port on the device before registering, allowing the server to respond to the source address of the "announcement".
Once announced, when config. options change on the server, one of two things usually happen:
A) You send a tiny "ping" (in the general sense, not the ICMP host detection protocol) to the device alerting it that config options have changed. At this point the host would immediately request the full config. set, acquiring the update with it.
B) You send the updated config. option (or maybe the entire config. set) back to the device. This decreases the number of messages between the device and server, but would probably take more work as it seems like more a deviation from your current setup.
Why not use an event based loop instead of sleeping for a certain amount of time.
That way your loop will only run when a change is detected, and it will always run when a change is detected (which is the point of your question?).
You can do such a thing by using:
python event objects
Just wait for one or all of your event objects to be triggered and run the loop. You can also wait for X events to be done, etc, depending if you expect one variable to be updated a lot.
Or even a system like:
broadcasting events

Categories