miketeachman / micropython-rotary

MicroPython module to read a rotary encoder.
MIT License
269 stars 56 forks source link

Arguments to callback functions #18

Closed ilium007 closed 2 years ago

ilium007 commented 2 years ago

Hi - is there a way to pass an argument in the callback? When I attempt to do this the list shows a 'None' type.

>>> enc0._listener
[<function callback at 0x20007a90>, None]

I am sending CANbus messages when a rotary encoder is turned and a want to include the rotary encoder id. If I can't pass an argument I would need xx number of callback functions, one for each encoder.

ilium007 commented 2 years ago

I can't see any other way than doing this:

enc0_tsf = asyncio.ThreadSafeFlag()

def enc0_cb():
    enc0_tsf.set()

enc0 = RotaryIRQ(pin_c3, pin_c2, min_val=-10, max_val=10, range_mode=RotaryIRQ.RANGE_BOUNDED)
enc0.add_listener(enc0_cb)
enc0.set(value=0)

In the async def main():

while True:
        await enc0_tsf.wait()
        enc_send_msg(enc0.value(), 0x00)  # <-- pass encoder id here

        await asyncio.sleep_ms(0)       # keep the uasyncio loop alive
ilium007 commented 2 years ago

Reverted to the micropython-async class to get around this for now.

miketeachman commented 2 years ago

want to include the rotary encoder id

Would the technique described in these docs work? https://docs.micropython.org/en/latest/reference/isr_rules.html see heading "The use of object methods as callbacks"

Example:

# The MIT License (MIT)
# Copyright (c) 2021 Mike Teachman
# https://opensource.org/licenses/MIT

# example for MicroPython rotary encoder

from rotary_irq_esp import RotaryIRQ

class can_encoder():
    def __init__(self, rotary, ident):
        rotary.add_listener(self.cb)
        self.ident = ident

    def cb(self):
        print(self.ident)

r1 = RotaryIRQ(pin_num_clk=22,
              pin_num_dt=23,
              min_val=0,
              max_val=5,
              reverse=False,
              range_mode=RotaryIRQ.RANGE_WRAP)

r2 = RotaryIRQ(pin_num_clk=0,
              pin_num_dt=1,
              min_val=0,
              max_val=5,
              reverse=False,
              range_mode=RotaryIRQ.RANGE_WRAP)

e1 = can_encoder(r1, 1)
e2 = can_encoder(r2, 2)

turning r1 one step prints "1", turning r2 prints "2". Adapt the print as per your needs.