Every time you call a function the location of where to return to is pushed onto a stack, when a function ends it takes that location off the stack and execution continues from there. If you never return from functions and have them endlessly calling each other then Python eventually objects because the stack becomes full. There's also overheads of variables and such local to each invocation of the functions.dkat wrote: ↑Fri Apr 12, 2019 8:15 pmThe continuous loop code finally works great in my updated RPi-based plant watering system but errors out when the maximum recursion depth is exceeded.
The logic requires taking different paths through the code, depending on tests along the way. Not having GOTOs in Python, I used functions to perform the tests and direct the program flow to other functions depending on the test results.
As written, the functions never return. They just point to other functions, which eventually result in an action (do nothing, turn a pump on, or turn a pump off). Before too many loops, the maximum recursion depth is exceeded.
Any ideas on resolving the recursion depth error would be greatly appreciated.
Especially if they're easy.
Calling functions to transfer program control from on place to another is not a replacement for GOTO. As pointed out above. So don't do that.Not having GOTOs in Python, I used functions to perform the tests and direct the program flow to other functions depending on the test results.
Is there such a thing as longjmp() in Python? I doubt it.
As noted above by the last two posts - that's the answer,
Not as far as I'm aware, the nearest would involve using exceptions to unwind the call stack but that would be a mess to manage especially if there's mutual recursion involved.
Code: Select all
state = 0 while True: if state == 0: print("Entering state 0") if something: doSomething() state = 1 elif state == 1: print("Entering state 1") if somethingElse: doSomethingElse() state = 2 elif state == 2: print("Entering state 2") if somethingOther: doSomethingOther() state = 3 elif state == 3: print("Entering state 0") if somethingMore: doSomethingMore() state = 0 else: print("Perhaps an error...")
Code: Select all
class Waterer: START = 0 PUMP = 1 SEEP = 2 def __init__(self, pump_io): self.pump_io = pump_io self.pump_state = False self._pump_off() self.state = START self.pump_time = 20 self.seep_time = 20 def _pump_off (self): GPIO.output(self.pump_io, True) def _pump_on (self): GPIO.output(self.pump_io, False) def set_pump_time(self, value): """ just an example how to modify the presets in the class""" self.pump_time = value def sensor(self, temp_value, moisture_value): self.temp_value = # remember different values .... def tick(self): if self.state == START: if self.moisture_value < self_moisture_threshold self._pump_on() self.state = self.PUMP self.tick_count = self.pump_time else: self.state = self.SEEP self.tick_count = seep_time elif self.state == self.PUMP: self.tick_count -= 1 if self.tick_count < 0: self._pump_off() self.state = self.SEEP self.tick_count = self.seep_time elif self.state == self.SEEP: self.tick_count -= 1 if self.tick_count < 0: self.state = self.START waterers = [ Waterer( 2 ), Waterer( 3 ), Waterer( 4 ), Waterer( 17), Waterer( 27), Waterer( 22), Waterer( 23), Waterer( 24), ] while True: sleep(1) for z in range(0,InstalledSensors): sensor = chirp_modbus.SoilMoistureSensor(address=z+i, serialport='/dev/ttyUSB0') temp = C2F(sensor.getTemperature()) moist = sensor.getMoisture() waterers[z].sensor( temp, moist) # send sensor values before tick waterers[z].tick()