AppDaemon: Thread will be restarted

Good morning,

i have an app that monitors my network status and sends a notification when the network was offline for a longer period. The app worked fine in v3 of appdaemon, but since upgrading to v4 I get endless messages of Thread restart message after a trigger event.

2020-08-17 08:00:41.617856 CRITICAL AppDaemon: Thread thread-7 has died
2020-08-17 08:00:41.618027 CRITICAL AppDaemon: Pinned apps were: ['network_status']
2020-08-17 08:00:41.618125 CRITICAL AppDaemon: Thread will be restarted

Any ideas what I am doing wrong in my code ?

import appdaemon.plugins.hass.hassapi as hass
import appdaemon
import time
import globals


class NetworkStatus(hass.Hass):
    """Notify when WAN is out.

    Checks the WAN sensor to see if the network is out. Rechecking every few sec
    and send alert when downtime is too long.

    Parameters
    ----------
    wan_sensor : str
      Sensor monitoring the wan status
    """

    def initialize(self):
        self.handle = None
        self.refresh = 30       # Refresh time to check if the network is back
        self.threshold = 300    # Sec downtime to trigger an alert
        self.downtime = 0       # Downtime counter
        # Old light values
        self.old_status = ""
        # Subscribe to state
        self.listen_state(self.network_went_down,
                          self.args["wan_sensor"], new="off")

    def network_went_down(self, entity, attribute, old, new, kwargs):
        """Network went down, start monitoring it."""
        self.log("Network went down ..")
        # The status will be indicated with the alert light
        # Save the old state, turn it on and store the current colour/brighness
        self.old_status = self.get_state(globals.alert_light)
        self.turn_on(globals.alert_light)
        # Change the colour to blue alert
        self.turn_on(globals.alert_light, brightness=globals.alert_blue_brightness,
                     rgb_color=globals.alert_blue_color)
        # Network is done and keep checking
        self.handle = self.run_in(self.monitor_network, self.refresh)

    def monitor_network(self, kwargs):
        """Monitor the network status."""
        self.cancel_timer(self.handle)
        self.downtime += self.refresh
        status = self.get_state(self.args["wan_sensor"])
        if(status == "on"):   # The network is back, check if alert needs to be sent
            self.log("  network is back (" + str(self.downtime/60) + "min)")
            # Restore the old light settings
            self.turn_on(
                globals.alert_light, brightness=globals.default_brightness, rgb_color=globals.default_color)
            if(self.old_status == "off"):
                self.turn_off(globals.alert_light)
            # Check if the downtime was longer than the threshold
            if self.downtime >= self.threshold:
                # Let the network settle down and then send the alert.
                self.run_in(globals.log_notify(
                    self, "Network Issue", "Network back: " + str(self.downtime/60) + "min", "WARNING"), 30)
            self.downtime = 0
        else:                 # Network is still down, check again later
            self.log("  network still down: " + str(self.downtime/60) + "min")
            self.handle = self.run_in(self.monitor_network, self.refresh)

Thanks, David

This looks suspect. It should only be passing the function, not a called function, and you should be passing the values for that function through kwargs. You could simply wrap that into a method then call that.

So to clarify:

It want’s func. so that run_in can call func(kwargs).

But you’re giving it func(). So run_in calls func()(kwargs).

                ...... code ........
                self.run_in(self.logmystuff, 30, downtime=self.downtime)
                ......  more code ........

    def logmystuff(self, kwargs):
        downtime = kwargs.get('downtime', 0)
        globals.log_notify(
            self, "Network Issue", "Network back: " + str(downtime/60) + "min", "WARNING")

or, if you don’t want to pass downtime since it’s on the class…

                ...... code ........
                self.run_in(self.logmystuff, 30)
                ......  more code ........

    def logmystuff(self, kwargs):
        globals.log_notify(
            self, "Network Issue", "Network back: " + str(self.downtime/60) + "min", "WARNING")

Thanks @petro ! Will give it a try and report if it solves the issue.