I am making a smart nightstand using a Raspberry Pi and Python. It should be able to:
- Have settings being controlled by a mobile app communicating through TCP requests to the Raspberry Pi
- Have an alarm go off at a given time. The alarm will play a sound/music and turn on an LED strip gradually increasing the brightness.
- Utilise buttons to either snooze/turn off the alarm or turn the LED strip on or off, depending on whether the alarm is currently on or not. The LEDs and buttons are controlled through the GPIO pins on the Raspberry Pi.
To keep the code clear I am trying to do some of the work in separate classes, so one class for managing the alarm, one for controlling the buttons, one for controlling the LED strip etc. The solution will be headless, all controlling done through TCP requests from the mobile app.
To control the buttons I do something like this:
import RPi.GPIO as GPIO # Import Raspberry Pi GPIO library from enum import Enum class TouchButton(Enum): DISABLE = 0 ONOFF = 1 MORE = 2 LESS = 3 class ButtonHandler(): disable_pin = #to be defined on_off_pin = #to be defined more_pin = #to be defined less_pin = #to be defined init(): GPIO.setmode(GPIO.BOARD) # Use physical pin numbering GPIO.add_event_detect(disable_pin,GPIO.RISING,callback=lambda x: button_callback(DISABLE), bouncetime=500) GPIO.add_event_detect(on_off_pin,GPIO.RISING,callback=lambda x: button_callback(ONOFF)), bouncetime=500) GPIO.add_event_detect(more_pin,GPIO.RISING,callback=lambda x: button_callback(MORE), bouncetime=20) GPIO.add_event_detect(less_pin,GPIO.RISING,callback=lambda x: button_callback(LESS), bouncetime=20) def button_callback(button): instance_of_another_class.some_function(button) #Somehow call back to an instance of another class
In the main class I would have something like this:
class MainApplicationClass(): def config(): ButtonHandler() while(1): pass #loop forever to keep script from stopping? #Or use sleep(forever?). The main point is: What do I do if the main code is just waiting for input from the alarm, button or LED control class instance and has no code to execute in the meantime? def some_function(): pass #Expecting the call back when a button is pressed here
In addition to the above I would need to have code to handle the other tasks, such as monitoring for TCP requests, controlling the lights etc. These would all need to work in parallell, as a web request could be made while the alarm is going off, the buttons should be able to turn the alarm off while the sound is playing etc.
PS: The code above won't run, it is only meant to show the idea of what to do.
So, my issues/challenges are:
- The various features of the nightstand must be checked and controlled from a common object. For instance, when a button is pressed, I need to check if the alarm is active to determine if it should be turned off, or if the LEDs should be changed instead. How can for instance the button class "talk back" to the main class and tell it to take action based on a button press?
- Most/all of these tasks would probably need to be run in a separate thread (for instance, playing sound with pygame uses a while loop as long as the sound is playing, preventing any other code from being executed on the same thread like responding to TCP requests). If doing so, when the function is called in the main class instance again, is it thread safe or what would I have to do to make it so? I guess this one depends a bit on the solution for the first question.
- A lot of waiting for input in Python and when using Raspberry Pi seems to be based on infinite while loops. Is there really no better way of doing this? When running several background tasks this while loop waiting would probably require huge amount of unnecessary computing? For instance, if I offload the tasks (alarm, buttons etc) to other threads and the main thread is done executing the code in
MainApplicationClass, will it terminate the application while waiting for callback from the other tasks since it has reached the end of the code?
I am completely new to Python and may approach this very badly. There might also be an obvious answer, but as I'm not very familiar with the syntax of Python I'm struggling to search for the right keywords. That being said, I've programmed in Objective-C and Swift for years, so the concept of programming is not unfamiliar, just the way of doing it in Python.