AppDaemon - check component existance

Is there a function in appdaemon that I can use to determine if a component exists without throwing an error if it doesn’t? I’m working on an app and if there is a group with a specific name, then I want to do something. If the group does not exist, that’s fine, I just don’t want to throw an error.

If you call get_state() on the group, it should return None if the group doesn’t exist - does that do what you want?

That’s what I thought too. But it gives me an error.

017-01-16 11:52:24.069388 WARNING ------------------------------------------------------------
2017-01-16 11:53:20.658764 WARNING ------------------------------------------------------------
2017-01-16 11:53:20.659285 WARNING Unexpected error:
2017-01-16 11:53:20.659649 WARNING ------------------------------------------------------------
2017-01-16 11:53:20.661061 WARNING Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/appdaemon/appdaemon.py", line 415, in worker
    function()
  File "/home/hass/code/appdaemon/printermonitor.py", line 15, in initialize
    self.check_printers()
  File "/home/hass/code/appdaemon/printermonitor.py", line 85, in check_printers
    retstate = self.get_state("group."+sys,"state")
  File "/usr/local/lib/python3.4/dist-packages/appdaemon/appapi.py", line 126, in get_state
    if attribute in conf.ha_state[entity_id]:
KeyError: 'group.ofhp1'

What does the actual code look like?

sys is the name of the printer. I’m looking to see if there is a group with that name.

  self.log("checking on entity {}".format(sys))
  retstate = self.get_state("group."+sys,"state")
  self.log("state of {} = {}".format(sys,retstate))

I think the problem is that in line 126 of appapi, entity_id has not been verified against conf.ha_state.keys (I think)

You can just do it and catch if it fails

try:
  self.log("checking on entity {}".format(sys))
  retstate = self.get_state("group."+sys,"state")
  self.log("state of {} = {}".format(sys,retstate))
except KeyError:
   pass

Or I could just suggest that something like the following function be added to the next release of AppDaemon.

  def device_exists(self,entity_id):
    if entity_id in conf.ha_state:
      self.log("found {} in HA".format(entity_id))
      return(True)
    else:
      self.log("{} not found in HA".format(entity_id))
      return(False)

Or I could make it shorter still with

def device_exists(self,entity_id):
  return(True if entity_id in conf.ha_state else False)

That should work too. Right??

That should work yep - I’ll add it into the next version :slight_smile: Except I will call it entity_exists(). Thanks for the suggestion! I have also fixed get_state() to return None if the entity does not exist.

Changes are live!

Cool,
Thanks

I was just using run_minutely again in another program and captured this.

self.run_minutely("getAlerts",time=None)

Yields the following error report.

2017-01-20 14:48:14.091819 WARNING ------------------------------------------------------------
2017-01-20 14:49:04.092354 WARNING ------------------------------------------------------------
2017-01-20 14:49:04.095457 WARNING Unexpected error:
2017-01-20 14:49:04.097248 WARNING ------------------------------------------------------------
2017-01-20 14:49:04.099778 WARNING Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/appdaemon/appdaemon.py", line 422, in worker
    function()
  File "/home/hass/code/appdaemon/weatherAlert.py", line 17, in initialize
    self.run_minutely("getAlerts",time=None)
TypeError: run_minutely() missing 1 required positional argument: 'start'

2017-01-20 14:49:04.100602 WARNING ------------------------------------------------------------

if I change “time” to “start”

self.run_minutely("getAlerts",start=None)

No Error

both should give an error if i am right, because you dont have a real callback.

starttime=None
self.run_minutely(self.callbackfunction,starttime)

What Rene said - I’ll take a look.

(hass) hass@hass:~/code/appdaemon$ cat test.py
import appdaemon.appapi as appapi

class test(appapi.AppDaemon):

def initialize(self):
# self.LOGLEVEL=“DEBUG”
self.log(“Test App”)
self.run_minutely(self.testcallback,time=None)

def testcallback(self,kwargs):
self.log(“in callback”)
(hass) hass@hass:~/code/appdaemon$

2017-01-22 11:31:26.040165 INFO Reloading Module: /home/hass/code/appdaemon/test.py
2017-01-22 11:31:26.062935 INFO Loading Object test using class test from module test
2017-01-22 11:31:26.064085 INFO test: Test App
2017-01-22 11:31:26.068997 WARNING Logged an error to /home/hass/appdaemon/appdaemon.err

Gives this error

2017-01-22 11:31:26.064819 WARNING ------------------------------------------------------------
2017-01-22 11:31:26.065295 WARNING Unexpected error during loading of test:
2017-01-22 11:31:26.065793 WARNING ------------------------------------------------------------
2017-01-22 11:31:26.067608 WARNING Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/appdaemon/appdaemon.py", line 727, in readApp
    init_object(name, class_name, module_name, config[name])
  File "/usr/local/lib/python3.4/dist-packages/appdaemon/appdaemon.py", line 509, in init_object
    conf.objects[name]["object"].initialize()
  File "/home/hass/code/appdaemon/test.py", line 8, in initialize
    self.run_minutely(self.testcallback,time=None)
TypeError: run_minutely() missing 1 required positional argument: 'start'

2017-01-22 11:31:26.068356 WARNING ------------------------------------------------------------

(hass) hass@hass:~/code/appdaemon$ cat test.py
import appdaemon.appapi as appapi

class test(appapi.AppDaemon):

def initialize(self):
# self.LOGLEVEL=“DEBUG”
self.log(“Test App”)
self.run_minutely(self.testcallback,start=None)

and

  def testcallback(self,kwargs):
    self.log("in callback")
(hass) hass@hass:~/code/appdaemon$ 

Does not give an error and works.

2017-01-22 11:31:48.038225 INFO Reloading Module: /home/hass/code/appdaemon/test.py
2017-01-22 11:31:48.059775 INFO Loading Object test using class test from module test
2017-01-22 11:31:48.060777 INFO test: Test App

run_minutely() is supposed to be called with 2 positional argumentsm and optional keyword args. The second arg time defaults to None if not supplied.

So, assuming start_time is a python time object:

run_minutely(self.callback) # Run every minute at the current time
run_minutely(self.callback, start_time) # Run every minute "start_time"

Are both correct usage

start= and time= would be regarded as optional keyword parameters.

The only thing puzzling me is why the first one is throwing an error and the second is not.

Bingo ----

1 Like

Probably bacuse you have start as optional argument. If you say start=none that’s the same as providing just none.
however if you say time=none then the argument before isnt filled and that would be start.
it seems like you cant provide kwargs without filling the optional arguments.

That would make sense. But the documentation says the parameter is “time”, but it requires that I use start instead. I’m not using kwargs in this case.

The docs say time = None which is a standard way of saying that time is a positional argument with a default value of None. As with all positional arguments you don;t use keyword = value you just use a single variable or literal without the = and if it is a variable it can be named anything. If you provide nothing in that slot, the default value of None is used.