Sunset trigger not working

I have the following app, that has recently just stopped working at sunset. I can not seem to figure out why. The input_boolen trigger fires the app fine and all works fine, but it will not fire at sunset. There is no entry in the log in the info or error logs

import appdaemon.plugins.hass.hassapi as hass
import datetime
import random
import globals
#
# App to turn lights on after sunset then turn off a time later
#

class AutoTurnOnOffSunset(hass.Hass):

    def initialize(self):
        self.handle = {}
        self.utility = self.get_app("utilities")

        if self.args["sunsetoffset"]:
           sunsetoffset = int(self.args["sunsetoffset"])
        self.listen_state(self.sunset_t, "input_boolean.automation_test_sensor")
        self.run_at_sunset(self.sunset_t)

    def sunset_t(self, entity, attribute, old, new, kwargs):
        self.log("function accessed")
        for light in self.args["lights"]:
            device, entity = self.split_entity(light["entity"])
            if device == "light":
                rgb = self.get_light_colour(light["rgb"])

                self.turn_on(
                    light["entity"],
                    rgb_color = rgb,
                    effect = "solid",
                    brightness=150)

                notifymessage = "{} turned on as a coloured Light at sunset with colour {}".format(light["entity"], rgb)
                self.sendNotifcation(notifymessage)

            else:
                self.turn_on(light["entity"])
                notifymessage = "{} turned on as a standard Light at sunset".format(light["entity"])
                self.sendNotifcation(notifymessage)

            offtime = self.parse_time(light["offtime"])
            self.log(offtime)
            self.handle[light["entity"]] = self.run_daily(self.light_off ,offtime ,entity_name= light["entity"],offtime = offtime)
            
    def light_off(self,kwargs):
        var = kwargs["entity_name"]
        offtime = kwargs["offtime"]
        text = "{} has just turned off after {} seconds".format(var , offtime)
        self.turn_off(var)  
        self.sendNotifcation(text)

    def get_light_colour(self,colourtype):
        if colourtype == "random":
            rgb = self.get_random_colour()
            self.log("the random color {}".format(rgb))
        else:
            rgb = colourtype
            self.log("the selected color {}".format(rgb))
        return rgb

    def get_random_colour(self):
        return self.utility.getRandomLightColour()

    def cancel(self):
        self.cancel_timer(self.handle)

    def sendNotifcation(self, notifyMessage):
        self.utility.send_notification(notifyMessage)       


##Auto Light Turn On and Off - Sunset
auto_turn_on_off_lights_sunset:
  module: auto_turn_on_off_sunset
  class: AutoTurnOnOffSunset
  dependencies: 
    - utilities
  sunsetoffset: 1800  
  lights:
    - entity: light.garage_color_light
      offtime: "22:30:00"
      rgb: "random"
    - entity:  switch.sidegarden_light
      offtime: "21:30:00"
      rgb: "random"  
    - entity: light.study_strip_light
      offtime: "22:00:00"
      rgb: "random"      
    - entity: switch.front_garden_light
      offtime: "21:45:00"
      rgb: "random"
    - entity: light.laura_bedroom_color_light
      offtime: "21:30:00"
      rgb: "random"

At least part of the problem is that listen_state() and scheduler callbacks have a different callback signature. sunset_t() has the correct signature for a listen_state() callback so is working as expected, for the sunset call, I would expect an error in your error log. You can fix it by having 2 stub functions with the right args , both of which call a common function, something like this:

def initialize(self):
        self.handle = {}
        self.utility = self.get_app("utilities")

        if self.args["sunsetoffset"]:
           sunsetoffset = int(self.args["sunsetoffset"])
        self.listen_state(self.sunset_state_t, "input_boolean.automation_test_sensor")
        self.run_at_sunset(self.sunset_schedule_t)

    def sunset_state_t(self, entity, attribute, old, new, kwargs):
      self.sunset_t()

    def sunset_schedule_t(self, kwargs):
      self.sunset_t()

    def sunset_t(self):
        self.log("function accessed")
        ....

I had the input boolean there just to test. I have removed this and set the call back correctly. As I run Hassio there is no time machine so had to wait till sunset to test. The app didn’t fire tonight either.
I have other automations that work fine so I figure AD is working OK. I do have intermittent issues with Google TTS but the sunset trigger is the most troublesome. This did work all ok prior to moving to tokens. Could there be issues in getting long/lats info from HA. I have checked the token and all good. There is nothing reported in my error.log or the info log.
I am at a loss as to why this doens’t work.
here is the app now

import appdaemon.plugins.hass.hassapi as hass
import datetime
import random
import globals
#
# App to turn lights on after sunset then turn off a time later
#
# Args:
#lights : entity to turn on
#delayoff: time after sunset to turn off


class AutoTurnOnOffSunset(hass.Hass):

    def initialize(self):
        self.handle = {}
        self.utility = self.get_app("utilities")

        if self.args["sunsetoffset"]:
           sunsetoffset = int(self.args["sunsetoffset"])
        self.run_at_sunset(self.sunset_t, offset = sunsetoffset)

    def sunset_t(self, kwargs):
        self.log("function accessed")
        for light in self.args["lights"]:
            device, entity = self.split_entity(light["entity"])
            if device == "light":
                rgb = self.get_light_colour(light["rgb"])

                self.turn_on(
                    light["entity"],
                    rgb_color = rgb,
                    effect = "solid",
                    brightness=150)

                notifymessage = "{} turned on as a coloured Light at sunset with colour {}".format(light["entity"], rgb)
                self.sendNotifcation(notifymessage)

            else:
                self.turn_on(light["entity"])
                notifymessage = "{} turned on as a standard Light at sunset".format(light["entity"])
                self.sendNotifcation(notifymessage)

            offtime = self.parse_time(light["offtime"])
            self.log(offtime)
            self.handle[light["entity"]] = self.run_daily(self.light_off ,offtime ,entity_name= light["entity"],offtime = offtime)
            
    def light_off(self,kwargs):
        var = kwargs["entity_name"]
        offtime = kwargs["offtime"]
        text = "{} has just turned off after {} seconds".format(var , offtime)
        self.turn_off(var)  
        self.sendNotifcation(text)

    def get_light_colour(self,colourtype):
        if colourtype == "random":
            rgb = self.get_random_colour()
            self.log("the random color {}".format(rgb))
        else:
            rgb = colourtype
            self.log("the selected color {}".format(rgb))
        return rgb

    def get_random_colour(self):
        return self.utility.getRandomLightColour()

    def cancel(self):
        self.cancel_timer(self.handle)

    def sendNotifcation(self, notifyMessage):
        self.utility.send_notification(notifyMessage)       

the app.yaml

#Auto Light Turn On and Off - Sunset
auto_turn_on_off_lights_sunset:
  module: auto_turn_on_off_sunset
  class: AutoTurnOnOffSunset
  dependencies: 
    - utilities
  sunsetoffset: 600  
  lights:
    - entity: light.garage_color_light
      offtime: "22:30:00"
      rgb: "random"
    - entity:  switch.sidegarden_light
      offtime: "21:30:00"
      rgb: "random"  
    - entity: light.study_strip_light
      offtime: "22:00:00"
      rgb: "random"      
    - entity: switch.front_garden_light
      offtime: "21:45:00"
      rgb: "random"
    - entity: light.laura_bedroom_color_light
      offtime: "21:30:00"
      rgb: "random"
    - entity: light.emily_strip_light
      offtime: "22:00:00"
      rgb: "random"
    - entity: light.zara_strip_light
      offtime: "21:30:00"
      rgb: "random"

and my appdaemon.yaml ( token has been changed for posting)

secrets: /config/secrets.yaml
log:
  logfile: /config/logs/info.log
  errorfile: /config/logs/err.log
  accessfile: /config/logs/access.log
  logsize: 100000
  log_generations: 4
appdaemon:
  threads: 10
  api_port: 5000
  api_ssl_certificate: /ssl/fullchain.pem
  api_ssl_key: /ssl/privkey.pem
  app_dir: /config/appdaemon/apps
  production_mode: true
  plugins:
    HASS:
      type: hass
      ha_url: http://hassio/homeassistant
      cert_path: /ssl/privkey.pem
      cert_verify: true
      token: 92fd735e5e4dca8290af2a11bbd8c152b4c2b6175XXXXXXXXXX
hadashboard:
  dash_url: http://127.0.0.1:5050
  dash_dir: /config/appdaemon/dashboards
  dash_ssl_certificate: /ssl/fullchain.pem
  dash_ssl_key: /ssl/privkey.pem

Just updated the token through HA. Add the following as a time based trigger and all worked.

 self.run_at_sunset(self.sunset_t, offset = sunsetoffset)
 runtime = datetime.time(20, 55, 0)
 self.run_daily(self.sunset_t, runtime)

Will need to see if the new token fixed the sunset issue tomorrow night

two days of testing ant it appears to be working again after recreating the token. Is there a reason why the token stopped working?

if you used long live token, it shouldnt stop working, unless you somehow revoke it in HASS

FYI I had the same thing happen to me last week. There were a few Ubuntu updates that needed a restart and after that all of my sunset triggers in appdaemon stopped working. Creating a new token fixed the problem. I had full logging turned on and there was nothing in the logs that would indicate any issue. All of the other triggers work fine so I the token was fine but for some reason sunset’s would never trigger.

Since last few days I am also noticing my living room light is not getting turned on based on sunset. I have logging in the code but I don’t see any log line that can prove it got called. By the way this is intermittent so someday it works someday don’t. It used to work without any issue for couple years.

class LivingroomLight(hass.Hass):

  def initialize(self):
    self.log("Hello from LivingroomLight")
    self.action_day = 0
    self.run_at_sunset(self.callback_sunset, offset = -45*60)
    
  def callback_sunset(self, kwargs):
    if self.get_state("input_boolean.automation_sunbinding") == "off":
      self.log("Sun binding is currently disabled. Skipping event for this day")
      return
    if self.action_day != datetime.datetime.now().day:
      self.action_day = datetime.datetime.now().day
      if self.get_state("light.zwave_living_room_light_level_7_0") == "off":
        self.gradually_turn_on(self)
        self.log("It's almost dark out, turning on the living room light")
      else:
        self.log("Light status is not off so ignoring it")
    else:
      self.log("Same day got called multiple times so ignoring it")

I have this same issue. I have an app, SunCover:

class SunThing(hass.Hass):

    def initialize(self):
        try:
            self.run_at_sunrise(self.sunrise_cb, offset=self.args["sunrise_offset"])
        except KeyError:
            self.log("No sunrise config defined")

        try:
            self.run_at_sunset(self.sunset_cb, offset=self.args["sunset_offset"])
        except KeyError:
            self.log("No sunset config defined")

    def sunrise_cb(self, kwargs):
        raise Exception("You must override sunrise_cb")

    def sunset_cb(self, kwargs):
        raise Exception("You must override sunset_cb")


class SunCover(SunThing):

    def set_positions(self, position):
        for entity_id in self.args["entity_ids"]:
            self.log("Setting cover {} to position {}".format(entity_id, position))
            self.call_service('cover/set_cover_position', entity_id=entity_id, position=position)

    def sunrise_cb(self, kwargs):
        self.set_positions(self.args["sunrise_position"])

    def sunset_cb(self, kwargs):
        self.set_positions(self.args["sunset_position"])

app config:

living_room_shades_sun:
  module: sun_thing
  class: SunCover
  entity_ids:
    - cover.living_room_shade_l
    - cover.living_room_shade_r
  sunrise_position: 97
  sunrise_offset: 0
  sunset_position: 9
  sunset_offset: -300

sunrise_cb gets executed consistently every day. sunset_cb only gets called maybe 50% of the time (based on lack of log messages). It used to work as expected. I think this started happening after I updated either homeassistant or appdaemon recently - but unfortunately I can’t offer details. It might have been when I upgraded appdaemon from 3 to 4.

I’m not quite sure how to debug this or offer more information. Here are execution logs for the last few days. It looks like sunset_cb only gets executed “every other” time that it’s supposed to execute.

$ docker logs appdaemon --since 100h | grep living_room_shades_sun
2020-06-27 19:31:05.261330 INFO AppDaemon: Terminating living_room_shades_sun
2020-06-27 19:31:05.274196 INFO AppDaemon: Initializing app living_room_shades_sun using class SunCover from module sun_thing
2020-06-27 20:34:29.009461 INFO living_room_shades_sun: Setting cover cover.living_room_shade_l to position 9
2020-06-27 20:34:29.242983 INFO living_room_shades_sun: Setting cover cover.living_room_shade_r to position 9
2020-06-28 05:44:04.007752 INFO living_room_shades_sun: Setting cover cover.living_room_shade_l to position 97
2020-06-28 05:44:04.556995 INFO living_room_shades_sun: Setting cover cover.living_room_shade_r to position 97
2020-06-29 05:44:30.010529 INFO living_room_shades_sun: Setting cover cover.living_room_shade_l to position 97
2020-06-29 05:44:31.133356 INFO living_room_shades_sun: Setting cover cover.living_room_shade_r to position 97
2020-06-29 20:34:29.006638 INFO living_room_shades_sun: Setting cover cover.living_room_shade_l to position 9
2020-06-29 20:34:29.442517 INFO living_room_shades_sun: Setting cover cover.living_room_shade_r to position 9
2020-06-30 05:44:56.014215 INFO living_room_shades_sun: Setting cover cover.living_room_shade_l to position 97
2020-06-30 05:44:56.867033 INFO living_room_shades_sun: Setting cover cover.living_room_shade_r to position 97
2020-07-01 05:45:24.010157 INFO living_room_shades_sun: Setting cover cover.living_room_shade_l to position 97
2020-07-01 05:45:24.197915 INFO living_room_shades_sun: Setting cover cover.living_room_shade_r to position 97

im not sure why you chose to create such a complicated structure with 2 classes for 1 app, but thats besides the point.

there is an open issue with sun events/times in AD 4

allthough i have no clue why it happens because i never had any issue with it.

Rene, I didn’t include a bunch of other Sun* subclasses. I have other subclasses for light entity behavior, scene behavior, etc. Hence why they’re structured in this way.

Thanks for the reference to the issue on github.

its a possibility to work that way.
not the most optimised, but its a possibility :wink:

It’s the simplest thing I could think of. The obvious choice of defining which service to call (“cover/set_cover_position”, or simply “self.turn_on()” in the case of scenes and lights) in the apps.yaml config, plus the arguments for the different method signatures, seemed more complicated to me.

What would you suggest?

create different apps for different things.
1 app 1 class.

Then I have to have the same exception handling and initialize(self) method 5 different times. This sounds less optimized to me :slight_smile:

(plus, I’d lose the possibility of adding any other helper methods to the superclass, altho I don’t anticipate adding any for this simple app).

yes you got the same initialise.
but by putting it all in 1 app it will run all in 1 thread.

if you put on a light and a cover at the same time, one will wait untill the other is finished.

helper methods can be in any class you like. as long as you define it as app.
you dont need a superclass for that at all.

pythonic way of writing is not using the possibilities from AD to the max :wink:

but like i said, its possible.

Hm. They are different apps, and different classes - they just happen to share a superclass. Looking at the brand new Appdaemon Administrative Interface UI, it looks like all my apps (which use the Sun* subclasses) are running in different threads.

Either way, thanks for the feedback and thanks again for the reference to github.

ah ok.
i got the impression from your posted code that you made 1 app from it all.