craftbeerpi4-pione/cbpi/api/timer.py
avollkopf 28f4113f2f Fix to improve accuracy of timer
Timer was not accurate as it was depending on the asyncio.sleep function which is most liklely not exactly one second depending on other functions running in parallel.

Now the timer is comparable to cbpi3 where it runs until an end time is reached.

This is to address issue #66 and has been tested
2021-04-08 14:40:47 +02:00

71 lines
2.1 KiB
Python

import time
import asyncio
import math
class Timer(object):
def __init__(self, timeout, on_done = None, on_update = None) -> None:
super().__init__()
self.timeout = timeout
self._timemout = self.timeout
self._task = None
self._callback = on_done
self._update = on_update
self.start_time = None
self.end_time = None
def done(self, task):
if self._callback is not None:
asyncio.create_task(self._callback(self))
async def _job(self):
self.start_time = int(time.time())
self.end_time = self.start_time + int(round(self._timemout, 0))
self.count = self.end_time - self.start_time
try:
while self.count > 0:
self.count = (self.end_time - int(time.time()))
if self._update is not None:
await self._update(self,self.count)
await asyncio.sleep(1)
except asyncio.CancelledError:
end = int(time.time())
duration = end - self.start_time
self._timemout = self._timemout - duration
async def add(self, seconds):
self.end_time = self.end_time + seconds
def start(self):
self._task = asyncio.create_task(self._job())
self._task.add_done_callback(self.done)
async def stop(self):
if self._task and self._task.done() is False:
self._task.cancel()
await self._task
def reset(self):
if self.is_running is True:
return
self._timemout = self.timeout
def is_running(self):
return not self._task.done()
def set_time(self,timeout):
if self.is_running is True:
return
self.timeout = timeout
def get_time(self):
return self.format_time(int(round(self._timemout,0)))
@classmethod
def format_time(cls, time):
pattern = '{0:02d}:{1:02d}:{2:02d}'
seconds = time % 60
minutes = math.floor(time / 60) % 60
hours = math.floor(time / 3600)
return pattern.format(hours, minutes, seconds)