Parameters not updating with listen_state

I have an app where I am trying to schedule the starting of a pump. The automation seems to work with the initial time parameter; however when the input_datetime is changed in HA, the variable is not updated in appdaemon. Any ideas?

import appdaemon.plugins.hass.hassapi as hass
import datetime



class poolPumpMain(hass.Hass):

  def initialize(self):

    startTime = self.get_state(self.args["startTime"])
    startTimeHour = int(startTime[0:2])
    startTimeMinute = int(startTime[3:5])

    stopTime = self.get_state(self.args["stopTime"])
    stopTimeHour = int(stopTime[0:2])
    stopTimeMinute = int(stopTime[3:5])

    on_time = datetime.time(startTimeHour, startTimeMinute, 0)
    off_time = datetime.time(stopTimeHour, stopTimeMinute, 0)

    self.handle = self.listen_state(self.startTimeChangedCallBack, "input_datetime.pool_pump_start_time")


    self.log("***********************")
    self.log("hass start hour=")
    self.log(startTimeHour)
    self.log("hass start minute=")
    self.log(startTimeMinute)
    self.log("hass stop hour=")
    self.log(stopTimeHour)
    self.log("hass stop minute=")
    self.log(stopTimeMinute)
    
    self.run_daily(self.off_time_callback, off_time)
    self.run_daily(self.on_time_callback, on_time)
    
  def on_time_callback(self, kwargs):
    # Call to Home Assistant to turn the porch light on
    self.turn_on("switch.pool_main_pump")
    self.log("on_time_callback called")
    
  def off_time_callback(self, kwargs):
    # Call to Home Assistant to turn the porch light on
    self.turn_off("switch.pool_main_pump")

  def startTimeChangedCallBack(self, kwargs):
    self.log("start time changed")

I discovered my problem with “startTimeChangedCallBack”. However, I still have not been able to update the “startTime” variable. Any ideas?

get_state only calls the state at the time the code is running.
and you got it in your initialise so it will only be called when the app starts.

get_state only is used with HA entities, so self.args[“startTime”] must contain a HA entity.
if you want to do something based on a time in an HA entity you need to use something like:

    self.my_timer_name = None
    self.handle = self.listen_state(self.startTimeChangedCallBack, "input_datetime.pool_pump_start_time")
  def startTimeChangedCallBack(self, entity, attribute, old, new, kwargs): #please read docs how to use callbacks
    self.log("start time changed")
    self.log("starttime has changed to {}".format(new))
    startTimeHour = int(new[0:2])
    startTimeMinute = int(new[3:5])
    on_time = datetime.time(startTimeHour, startTimeMinute, 0)
    if self.my_timer_name != None:
      self.cancel_timer(self.my_timer_name)
    self.my_timer_name = self.run_daily(self.on_time_callback, on_time)

Thank you for the code. Would the first two lines be in the initialize function?

yes indeed, and off course you need to have the callback and create the other parts.

The code works great for a single run_daily but when there is two calls one for start time and another for stop time the self.cancel_timer seems to be in conflict with one another and if I try to give the cancel_timer a slightly different name it causes an error. I have looked at the docs. It states “A handle that can be used to cancel the timer.” https://www.home-assistant.io/docs/ecosystem/appdaemon/api/
however this is not very clear to me. Where can I get more detailed information? Do I have to put the cancel_timer in completely separate apps? I already have them in separate callbacks, but they seem to reference each other. Any thoughts?

with self.my_timer_name = self.run_daily
you store the name from the timer in the var called my_timer_name
so you can change that name

with self.cancel_timer(self.my_timer_name) you cancel the timer with the name my_timer_name

if you chose 2 different names they cant interfere.

you can use more timers in 1 app, even in the same callback

here are the docs
https://appdaemon.readthedocs.io/en/latest/index.html

I had a problem with a self.log command. I failed to look at the error file. thanks for all your help

1 Like

there are a lot of people forgetting that.

Hello @ReneTode, @aimc et al,

What’s the best way to iterate this code with timers for multiple input_datetime instances please? I have quite a few input_datetime and I’d like to call different functions for each of them. I tried this but got tangled up in a big mess:

apps.yaml

morning_input:
  module: sandbox
  class: sandbox
  input_name: input_datetime.morning
  callback_timer: self.morning_callback_timer
  callback_func: self.morning_on
  time_name: self.morning_lights_on
evening_input:
  module: sandbox
  class: sandbox
  input_name: input_datetime.evening
  callback_timer: self.evening_callback_timer
  callback_func: self.evening_on
  time_name: self.evening_lights_on

sandbox.py

import hassapi as hass
import datetime

class sandbox(hass.Hass):
    def initialize(self):
        self.args["callback_timer"] = None
        self.args["time_name"] = self.str_to_datetime(self.args["input_name"])
        self.args["callback_timer"] = self.run_daily(self.args["callback_func"], self.args["time_name"])
        self.handle = self.listen_state(self.input_datetime_changed, self.args["input_name"])

    def input_datetime_changed(self, entity, attribute, old, new, kwargs):
        on_time = self.str_to_datetime(entity)
        if self.args["callback_timer"] != None:
            self.log("cancelling callback timer %s", self.args["callback_timer"])
            self.cancel_timer(self.args["callback_timer"])
        self.args["callback_timer"] = self.run_daily(self.args["callback_func"], on_time)

    def str_to_datetime(self, entity):
        state = self.get_state(entity)
        if state is datetime.time:
            self.log("state %s is datetime" + state)
            return state
        elif str(isinstance(entity, str)):
            self.log("Converting string %s %s", entity, state)
            startTimeHour = int(state[0:2])
            startTimeMinute = int(state[3:5])
            new_time = datetime.time(startTimeHour, startTimeMinute, 0)
            return new_time
        else:
            self.error("Not datetime or str %s %s", entity, state, level = "ERROR")

    def morning_on(self, entity, attribute, old, new, kwargs):
        self.log("morning_on called")
    def evening_on(self, entity, attribute, old, new, kwargs):
        self.log("evening_on called")

I have a problem with the setting the timer on lines 8 and 16. I tried eval(self.args[“callback_timer”]) to no avail

Many thanks for your awesome help with this and various other threads.

first of all this is a bad idea:

        self.args["callback_timer"] = None

self.args is the dict containing the yaml from the app.
you dont want to change that, or you are messing with the working from AD

secondly you dont need to use a get_state for the entity, because “new” will contain the actual state.

third:

self.args["callback_timer"] = self.run_daily(self.args["callback_func"], self.args["time_name"])

cant work because self.args[“callback_func”] is a string and not a callback function