A big thanks to everyone who has chimed in. I think I’ve found a good software solution that will be ready in another day or so:
I’ve written a simple Python socket server that runs forever and acts as the controller/proxy for modifying valve status. It runs the station program in a thread and keeps a state chart of what valves are running.
If a request for a second operation comes in while a station is operating, the software sends a Queue message to the thread (basically saying, “wrap it up, new work is coming in”) and it stops the current run before starting the next operation. This solves that problem I had about the first job waking up and killing the second job.
I wrestled with doing this as a simple TCP server or as a web server, but decided on TCP. This gave greater flexibility for clients: You are free to write clients in any language that supports TCP sockets (any modern language should) and you aren’t forced to do anything else in Python if you choose not to.
This modular approach also keeps things simple and clean when writing advanced clients, schedulers, etc. If you want to write a pretty advanced web application, the low-level details of the hardware operation are abstracted away.
The other nice thing is that only this TCP server needs to run with superuser privileges.
Here are a couple example snippets that send a command to run station 1 for 2 minutes: (they immediately close after the command is sent, the client doesn’t stay connected during the run)
$fp = fsockopen("127.0.0.1", 9999, $errno, $errdesc);
s = TCPSocket.open('localhost', 9999)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)