Alright, so I think I understand your control flow. Please correct me where I’m wrong.
You have two entirely separate subprojects here - one in Python, one in PHP - which communicate via a socket. (As a side point, I would strongly recommend simplifying down by removing that distinction, if possible. You could have a web server inside Python, either to do the entire job directly, or to be proxied to from something like nginx rather than having it run PHP. That would save you a bit of trouble.)
Inside Python, you currently have two subprocesses, and a bit of a weirdness strikes me right from the start: you initialize the Pi, then spawn two subprocesses, and then let the original process terminate. Maybe that’s not a problem, but it seems unnecessary and might cause confusion as to which process owns which resources.
But it definitely looks like this is a relatively low-traffic system. It doesn’t need to be multiprocessed. There are, if I’m understanding correctly, two core loops:
- com_loop listens (btw, you shouldn’t need to call listen() inside the loop - just call it once, then call accept() repeatedly) for a socket, reads from it, handles a command, and then responds and closes the socket
- temp_loop constantly checks the temperature of the pit, and reacts according to the parameters it’s been given, which can be set by commands.
(BTW, listtostring should be able to be replaced with a simple join() call - ";".join(stuff)
will be just like you’re doing, only without the trailing semicolon, which you can add back at the end if needed.)
There is one small issue I’m seeing here, which is that the temp_loop never seems to block at any time - it’s permanently spinning. The temperature check (check_pit_temp) won’t take long, and then heat() makes its decisions, also not taking long, and then it’s back to checking the temperature. You could insert a sleep into that loop without materially changing the behaviour (time.sleep(1)
for an entire second, or more or less time than that depending on your needs), and it’ll mean your Pi isn’t trying to spin constantly, so it’ll use less power.
Importantly, once you have both loops spending most of their time waiting (the command loop waiting for another socket, the temperature loop waiting for the next check), you can make them into threads without changing any of the rest of your code. Just replace the bit at the end with:
Thread(target=com_loop).start()
temp_loop()
Now you have a main loop and a spun-off thread, running inside the same process, and all your globals really will be shared.
That’s the easiest change to make. If you want to think about some other changes, though, here’s what I would recommend considering:
- As mentioned above, roll the web server into this script. That’ll save you some hassle.
- The socket loop will get “stuck” if ever the other end breaks. It’ll eventually time out but it will be unable to handle commands until then. One solution would be to have each incoming socket handled independently, as its own task (potentially its own thread).
- But threads aren’t strictly necessary here! What you REALLY need is just independence of tasks, all of them mostly waiting. That’s a perfect job for asyncio.
In a rather cool coincidence, my brother is currently working on his Raspberry Pi project called BioBox. It’s built around an asyncio event loop, and it manages a motor slider (so it’s repeatedly checking the resistance and also sending signals to the motor), with other messages coming from a GUI, a websocket, a plain TCP socket, and an SSH subprocess. The architecture is very similar to a threaded program, and fairly similar to what you’re doing here with subprocesses, but it’s all done in a single thread for efficiency. Feel free to check out his code (I’m also sending him yours), and if you’re curious, you can swing by his Twitch stream to talk about it - he works on this project once a week.
Gotta say, your project looks very very cool. Looks fun.