diff --git a/Vagrantfile b/Vagrantfile index 23b1689..694fcba 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -1,5 +1,5 @@ Vagrant.configure("2") do |config| - config.vm.box = "michael-slx/arch64-develop" + config.vm.box = "michael-slx/arch-develop" config.vm.hostname = "vm-weewx-wll-test" config.vm.network "public_network" diff --git a/bin/user/weatherlink_live/davis_http.py b/bin/user/weatherlink_live/davis_http.py index 5ec30e3..9db7160 100644 --- a/bin/user/weatherlink_live/davis_http.py +++ b/bin/user/weatherlink_live/davis_http.py @@ -37,11 +37,18 @@ def start_broadcast(host: str, duration, timeout: float = 5): try: r = requests.get("http://%s:80/v1/real_time?duration=%d" % (host, duration), timeout=timeout) json = r.json() - return WlHttpBroadcastStartRequestPacket.try_create(json, host) + broadcast_start_packet = WlHttpBroadcastStartRequestPacket.try_create(json, host) + + if i > 0: + log.error("Successfully sent broadcast start request after %d attempts" % (i + 1)) + else: + log.debug("Sent broadcast start request") + + return broadcast_start_packet except Exception as e: error = e log.error(e) - log.error("HTTP broadcast start request failed. Retry #%d follows shortly" % i) + log.error("HTTP broadcast start request failed. Retry #%d follows shortly" % (i + 1)) time.sleep(2.5) if error is not None: @@ -57,11 +64,18 @@ def request_current(host: str, timeout: float = 5): try: r = requests.get("http://%s:80/v1/current_conditions" % host, timeout=timeout) json = r.json() - return WlHttpConditionsRequestPacket.try_create(json, host) + conditions_packet = WlHttpConditionsRequestPacket.try_create(json, host) + + if i > 0: + log.error("Successfully sent conditions request after %d attempts" % (i + 1)) + else: + log.debug("Sent conditions request") + + return conditions_packet except Exception as e: error = e log.error(e) - log.error("HTTP conditions request failed. Retry #%d follows shortly" % i) + log.error("HTTP conditions request failed. Retry #%d follows shortly" % (i + 1)) time.sleep(2.5) if error is not None: diff --git a/bin/user/weatherlink_live/driver.py b/bin/user/weatherlink_live/driver.py index d716332..21e15bd 100644 --- a/bin/user/weatherlink_live/driver.py +++ b/bin/user/weatherlink_live/driver.py @@ -76,38 +76,43 @@ def genLoopPackets(self): # now resuming the driver. self._reset_data_count() - self._log_success("Entering driver loop") - while True: - self._check_no_data_count() - - try: - self.scheduler.raise_error() - self.poll_host.raise_error() - self.push_host.raise_error() - except Exception as e: - raise WeeWxIOError("Error while receiving or processing packets: %s" % repr(e)) from e - - log.debug("Waiting for new packet") - self.data_event.wait(5) # do a check every 5 secs - self.data_event.clear() - - emitted_poll_packet = False - emitted_push_packet = False - - while self.poll_host.packets: - self._log_success("Emitting poll packet", level=logging.INFO) - self._reset_data_count() - emitted_poll_packet = True - yield self.poll_host.packets.popleft() - - while self.push_host.packets: - self._log_success("Emitting push (broadcast) packet", level=logging.INFO) - self._reset_data_count() - emitted_push_packet = True - yield self.push_host.packets.popleft() - - if not emitted_poll_packet and not emitted_push_packet: - self._increase_no_data_count() + try: + self._log_success("Entering driver loop") + while True: + self._check_no_data_count() + + try: + self.scheduler.raise_error() + self.poll_host.raise_error() + self.push_host.raise_error() + except Exception as e: + raise WeeWxIOError("Error while receiving or processing packets: %s" % repr(e)) from e + + log.debug("Waiting for new packet") + self.data_event.wait(5) # do a check every 5 secs + self.data_event.clear() + + emitted_poll_packet = False + emitted_push_packet = False + + while self.poll_host.packets: + self._log_success("Emitting poll packet", level=logging.INFO) + self._reset_data_count() + emitted_poll_packet = True + yield self.poll_host.packets.popleft() + + while self.push_host.packets: + self._log_success("Emitting push (broadcast) packet", level=logging.INFO) + self._reset_data_count() + emitted_push_packet = True + yield self.push_host.packets.popleft() + + if not emitted_poll_packet and not emitted_push_packet: + self._increase_no_data_count() + + except WeeWxIOError as e: + self.closePort() + raise e def start(self): if self.is_running: diff --git a/bin/user/weatherlink_live/scheduler.py b/bin/user/weatherlink_live/scheduler.py index d09794f..041d332 100644 --- a/bin/user/weatherlink_live/scheduler.py +++ b/bin/user/weatherlink_live/scheduler.py @@ -126,7 +126,11 @@ def cancel(self): if self._tick_task_id is not None: log.debug("Cancelling tick task") - self._scheduler.cancel(self._tick_task_id) + try: + self._scheduler.cancel(self._tick_task_id) + except ValueError: + pass + self._tick_task_id = None if not self._scheduler.empty(): raise ValueError("Scheduler did not cancel all task") diff --git a/bin/user/weatherlink_live/static/version.py b/bin/user/weatherlink_live/static/version.py index 43c6a08..ae9cef1 100644 --- a/bin/user/weatherlink_live/static/version.py +++ b/bin/user/weatherlink_live/static/version.py @@ -20,4 +20,4 @@ DRIVER_NAME = "WeatherLinkLive" -DRIVER_VERSION = "1.1.4" +DRIVER_VERSION = "1.1.5" diff --git a/changes.md b/changes.md index a443cd5..e88c8d4 100644 --- a/changes.md +++ b/changes.md @@ -213,3 +213,27 @@ Driver is now compatible with **Python 3.7 or later**. WeeWX supports Python 3.7 but some type-hinting used by this driver required at least Python 3.9. This was fixed so that the driver now works with Python 3.7. +## Version 1.1.5 + +- **Fix resource leaks and cleanup issues** ([#42](https://github.com/michael-slx/weewx-weatherlink-live/issues/42)) + + WeeWX does not close and re-instantiate the driver module when an error + occurs. This previously led to issues when attempting to re-open the UDP socket. + + Additionally, there was a crash when cancelling scheduler tasks. + +- **Make retry log messages more intuitive** ([#47](https://github.com/michael-slx/weewx-weatherlink-live/issues/47)) + + Previously, retries of HTTP requests were counted starting at `0`. This + was changed to start at `1` (= first retry = second attempt). + +- **Add log messages for successful request retries** ([#46](https://github.com/michael-slx/weewx-weatherlink-live/issues/46)) + + When a HTTP request succeeds, a respective message is logged. + If it took more than one attempt, a message is logged with + the `error` level. + +- **Set `max` accumulator for `rainRate` metric** ([#44](https://github.com/michael-slx/weewx-weatherlink-live/issues/44)) + + Rain rate is accumulated by using maximum value for consistency + with WeatherLink app/dashboard. diff --git a/docs/installation.md b/docs/installation.md index 683968a..113e1ef 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -32,7 +32,7 @@ If you haven't done so already, install the following packages: 1. Install the extension by running the following command, possibly using `sudo`. ```sh -> weectl extension install https://github.com/michael-slx/weewx-weatherlink-live/releases/download/v1.1.4/weewx-weatherlink-live-v1.1.4.tar.xz +> weectl extension install https://github.com/michael-slx/weewx-weatherlink-live/releases/download/v1.1.5/weewx-weatherlink-live-v1.1.5.tar.xz ``` Answer `y` (Yes), when asked if you want to install the extension. diff --git a/install.py b/install.py index 404bb1f..ae58934 100644 --- a/install.py +++ b/install.py @@ -60,6 +60,12 @@ def loader(): # Accumulated by using last value [[rainSize]] extractor = last + + # Measurement rainRate: Precipitation rate + # Accumulated by using maximum value + # for consistency with WeatherLink app/dashboard + [[rainRate]] + extractor = max """ wll_config_dict = configobj.ConfigObj(StringIO(WLL_CONFIG)) @@ -68,7 +74,7 @@ class WeatherLinkLiveInstaller(ExtensionInstaller): def __init__(self): super(WeatherLinkLiveInstaller, self).__init__( name='weatherlink-live', - version="1.1.4", + version="1.1.5", description='WeeWX driver for Davis WeatherLink Live.', author="Michael Schantl", author_email="floss@schantl-lx.at",