Python Forum
Problems with Interrupts/ callback functions in Python for an Alarm Clock project - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: Problems with Interrupts/ callback functions in Python for an Alarm Clock project (/thread-1229.html)



Problems with Interrupts/ callback functions in Python for an Alarm Clock project - Henry1 - Dec-15-2016

I recently started programming with Python and now I want to build an appliance with the raspberry pi which is basically an alarm clock. I have a pi, a small OLED display and a rotary encoder which can be turned left/ right or pushed.
Here's the library for the rotary encoder: https://github.com/joan2937/pigpio/blob/master/EXAMPLES/Python/ROTARY_ENCODER/rotary_encoder.py
Since there was no support for pushing the rotary encoder, I added the following code to the library:

def _push(self, gpio, level, tick):
    if not self.pushed:
        self.callback("push")
        self.pushed = 1  # debounce 
which works fine.
But when it comes to building my actual appliance and integrating all the things (rotary encoder, oled display, ...) somehow I screw up. Every method in my code should handle one "page" of my appliance, e.g. the methods would be home_menu, alarm_menu, settings_menu, ... I have the following problem: I can't get the navigation through the menus right. After a push from the rotary encoder is detected, I want to display the content of the specific menu element at which the push was detected
Here's an excerpt from my code:

def main_menu_callback(self, cursor, lines = ('Weckzeit: --:--', 'Einstellungen', '01.01.1970')):
        y = 0
        # draw text elements of the main menu
        for line in lines:
            self.draw.text((0,y), line, font = self.sans15, fill=255)
            y += self.textsize_addition(line)[1] + 10
        self.draw.line([0, 43, 128, 43], fill=255)

        # check if rotary encoder was pushed. If so, go to the
        # selected menu point. If it wasn't pushed but turned,
        # display the cursor on the right position.

        if isinstance(cursor, str):

            if self.pos == 0:
                # push detected. move on to the content of the first menu item, which is handled through another method (????)
            else:
                # push detected. move on to the content of the second menu item, which is handled through another method (????)

        elif cursor == -1:
            # rotary encoder was turned left
            self.pos = 0
            self.draw.polygon([(120, 9), (128, 1), (128, 17)], outline=255, fill=255)
            self.draw.polygon([(120, 33), (128, 25), (128, 41)], outline=0, fill=0)
        else:
            # rotary encoder was turned right
            self.pos = 1
            self.draw.polygon([(120, 33), (128, 25), (128, 41)], outline=255, fill=255)
            self.draw.polygon([(120, 9), (128, 1), (128, 17)], outline=0, fill=0)
        self.disp.image(self.image)
        self.disp.display()
To run the code, I called the decoder method of the rotary encoder library and added the above written method (main_menu_callback) to the call, so that main_menu_callback can be used for the callback and get's executed every time the rotary encoder is turned or pushed:


decoder = rotary_encoder.decoder(pi, rotary_CLK, rotary_DT, rotary_SWITCH, main_menu_callback)
print("Test")
One of my many open questions is: How can I make my program to wait until the decoder was canceled (with
decoder.cancel()
)?

Currently it does not wait and the
print("Test")
get's executed right at the start of the program.


RE: Problems with Interrupts/ callback functions in Python for an Alarm Clock project - nilamo - Dec-16-2016

The example uses time.sleep() to wait before cancelling it.
   pi = pigpio.pi()
   decoder = rotary_encoder.decoder(pi, 7, 8, callback)
   time.sleep(300)
   decoder.cancel()
   pi.stop()
It sounds like you don't actually want to call decoder.cancel(), though... it sounds like you want it to just run forever, while the callbacks get handled. So maybe...
decoder = rotary_encoder.decoder(#etc)
while True:
    # handle events

    # so the pi doesn't melt :)
    time.sleep(500)