peterhinch / micropython-mqtt

A 'resilient' asynchronous MQTT driver. Recovers from WiFi and broker outages.
MIT License
550 stars 117 forks source link

Implementing a WDT timer #16

Closed vigorem closed 2 years ago

vigorem commented 4 years ago

Hi,

after extensive reading, I've implemented your MQTT client with success, thanks so much.

However after few days my ESP8266 stopped working. I don't think it's because of wifi outage but I suspect, since the microchips are close to a pump inverter (which produce quite a powerfull magnetic field) that that could be the reason.

I was wondering how I could implement machine.wdt() with your code in presence of asyncio coroutines which I'm quite new to.

Should I just declare as in the docs :

from machine import WDT
wdt = WDT(timeout=300000) 

and then in the main loop simply add a wdt.feed() like the following ?

while True:
  try:
      ntptime.settime()
      rtc=machine.RTC()
  except:
      continue

  print('publishing temps')
  # If WiFi is down the following will pause for the duration.
  json_data = ujson.dumps(getTemps())
  await client.publish('VMS_TEMPS_198280198239', json_data , qos = 1)
  wdt.feed()
  await asyncio.sleep(300)

I thank you in advance,

Sébastien

peterhinch commented 4 years ago

The problem with that is that if the WiFi is down the WDT will trigger. The real aim of a WDT is to detect crashes. So I would implement a separate coroutine:

async def do_wdt():
    tim = 300000
    wdt = WDT(timeout=tim)
    while True:
        wdt.feed()
        await asyncio.sleep(tim // 10)  # Feed 10 times in timeout period (very conservative)

In your main code you have

import uasyncio as asyncio
from machine import WDT

Run the coro by executing the following once only when your code starts:

   loop = asyncio.get_event_loop()
   loop.create_task(do_wdt())

In general I recommend raising issues like this in the forum: you may get a quicker response from others if the program author is busy or unavailable.

vigorem commented 4 years ago

Peter, that's great, thank you for your answer. Will keep you updated and follow your advice about posting on the forum

vigorem commented 4 years ago

Hi, just in case someone uses the ESP8266, it seems that machine.WDT() is not fully implemented => function doesn't take keyword arguments

I'm using a custom WDT found on micropython instead :

class WDT:
    def __init__(self, id=0, timeout=120):
        self._timeout = timeout / 10
        self._counter = 0
        self._timer = machine.Timer(id)
        self.init()

    def _wdt(self, t):
        self._counter += self._timeout
        if self._counter >= self._timeout * 10:
            machine.reset()

    def feed(self):
        self._counter = 0

    def init(self, timeout=None):
        timeout = timeout or self._timeout
        self._timeout = timeout
        self._timer.init(period=int(self._timeout * 1000), mode=machine.Timer.PERIODIC, callback=self._wdt)

    def deinit(self):  # will not stop coroutine
        self._timer.deinit()

I'll have to wait few days to let you know if it's stable!