Search code examples
pythonclasscallbacktypeerroresp32

(Micro-) Python callback function inside class throws type error


I'm more or less new to Python and still struggling a bit with OOP (coming from C - not C++). I want reuse and extend a rotary encoder class and just wanted to add a switch with an interrupt callback routine. But it always throws an error:

from rotary_encoder.rotary_irq_esp import RotaryIRQ
from machine import Pin



class RotaryEncoder(RotaryIRQ):
  # rotary options
  RANGE_MODE = const(1) # 1->UNBOUNDED, 2->WRAP, 3->BOUNDED
  PIN_CLK = const(7)
  PIN_DT = const(8)
  PULL_UP = True

  # switch options
  PIN_SWITCH = const(6)
  PULL_UP_SWITCH = True
  
  def __init__(self, pin_num_clk=PIN_CLK, pin_num_dt=PIN_DT, min_val=0, max_val=10, incr=1,range_mode=RANGE_MODE, pull_up=PULL_UP,pin_switch=PIN_SWITCH,pull_up_switch=PULL_UP_SWITCH):
    super().__init__(pin_num_clk, pin_num_dt, min_val, max_val, incr, range_mode, pull_up)
    # add switch
    if pull_up_switch:
      self.switch = Pin(pin_switch,Pin.IN, Pin.PULL_UP)
      self.switch.irq(trigger=Pin.IRQ_FALLING, handler=self._rotary_switch_callback)
    else:
      self.switch = Pin(pin_switch,Pin.IN, Pin.PULL_DOWN)
      self.switch.irq(trigger=Pin.IRQ_RISING, handler=self._rotary_switch_callback)

  def _rotary_switch_callback(self):
    pass

Do you have any idea why it's not working??

The error is: TypeError: function takes 1 positional arguments but 2 were given

I tried several things but nothing worked. In another component I saw a callback function definition inside a class without (self) argument. This will also not work here (and by the way confuses me a lot why a function inside a class which is not a static method or class method is there without a (self) argument - but this is another topic :-)

I tried

handler=self._rotary_switch_callback)
handler=_rotary_switch_callback)

def _rotary_switch_callback(self):
def _rotary_switch_callback():

If I use the code outside a class it works but an additional argument is the instance itself. No idea how I should transfer this into the class.

def rotary_switch_callback(rotary_switch):
   pass 
rotary_switch = Pin(6,Pin.IN, Pin.PULL_UP)
rotary_switch.irq(trigger=Pin.IRQ_FALLING, handler=rotary_switch_callback)

If I do the following it (of course) does not work :-)

self.switch = Pin(pin_switch,Pin.IN, Pin.PULL_DOWN)
self.switch.irq(trigger=Pin.IRQ_RISING, handler=self._rotary_switch_callback)

def _rotary_switch_callback(self, self.switch):
  pass

I have no real idea why it does not work but I think I can't give an instance.instance as argument if the instance itself is the argument. Any idea how I can solve this the "correct" way without ugly tricks?


Solution

  • I don't know what is self.switch.irq() but it seems it executes your function with some extra parameters - e.g PIN - and you have to get it

    def _rotary_switch_callback(self, parameter):
    

    If you don't know how many parameters it will send and you don't know if it will positional arguments or named arguments then you can use popular *args, **kwargs

    def _rotary_switch_callback(self, *args, **kwargs):
        print('args:', args)
        print('kwargs:', kwargs)
    

    But you should have information about parameters in documentation.