AppDaemon Q&A

Got it working. I had to convert the UUID to hex to get it to work otherwise it was an invalid type. But it seems to be working. Or at least no errors.
Thanks

  1. Yes!

I have thought about this a lot - it would make perfect sense to make hapush an app, but then everyone using the dashboard would need to install appdaemon and I wouldn’t want to force them to do that. It would take some work on my part but eventually I decided not to do it.

  1. 10 threads is not a lot. Reducing it would not save a significant amount of resources but the way AppDaemon is written is pretty resilient. If an App can;t get a thread, it will queue and wait for a thread. As a result, even with one thread you would be fine, just any things that happened together would be queued and executed in sequence.

At the end of the day - I think it has very little bearing on any performance and if you want just one thread I have you covered :slight_smile:

  1. do you think it would take a lot of efford?
    i am thinking about doing such a thing then, because it makes sence to have less programms running (at least i will have less logs and a terminal less to observe)

  2. i was thinking in the other direction. it is already on 20 (because i had the idea that it did give trouble some time ago that it was to low) but why not make it 40 or 100 or 1000?

  1. Yes would be a several hours of work to get it going properly. It looks like HASS is moving away from event stream towards WebSockets - at that time I’ll need to make changes to boith AppDaemon and HAPush - maybe I’ll look at it then!

  2. You can have as many as you want - but bear in mind it is only concurrent tyasks you are thinking about. Actually, if you have an issue and run out of threads, AppDaemon will queue the task and execute it whern a thread becomes available. If you back up too much (> 10 tasks) it will put a warning in the log, and then another for each 10 of backed up tasks. Unless you are doing work with threads that lasts more than a second or two you shouldn’t need more than 20, but if you are seeing a problem by all means bump it up. The downside I guess is that additional threads will use some more memory and maybe additional CPU to manage but I have no idea how to quantify that.

1 Like

I’m using the following format for calling run_minutely and it’s complaining about a missing positional parameter (Start)

self.handle = self.run_minutely(callback, time = None, **kwargs)

I have SSEClient version 0.0.12, looks like vey old as there is 1.4 out. Not sure how 0.0.12 came may be long back in time. I think I can upgrade it to latest, do you see/think any issue with appdaemon or hapush? I noticed HA is not using it that should be OK.
Few more observations: I mentioned in past that looks like few/some appdaemon app works but those apps are time based triggers and does not depend on any HA status changes, rest which depends on HA updates fails as not getting updates.
Thanks

how does the def line from the callback look?

I got it. No problem. The way they show time=None confused me. I took “time=” out and it compiled fine. I think it was seeing it as part of the kwargs variable.

1 Like

hi Andrew,

this error doesnt give much info to go on:

2016-12-19 21:29:50.022886 WARNING ------------------------------------------------------------
2016-12-19 21:29:51.013637 WARNING ------------------------------------------------------------
2016-12-19 21:29:51.015133 WARNING Unexpected error during do_every_second()
2016-12-19 21:29:51.016479 WARNING ------------------------------------------------------------
2016-12-19 21:29:51.018335 WARNING Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/appdaemon/appdaemon.py", line 374, in do_every_second
    exec_schedule(name, entry, conf.schedule[name][entry])
  File "/usr/local/lib/python3.4/dist-packages/appdaemon/appdaemon.py", line 293, in exec_schedule
    args["basetime"] += args["interval"]
TypeError: unsupported operand type(s) for +=: 'int' and 'datetime.timedelta'

2016-12-19 21:29:51.019480 WARNING ------------------------------------------------------------

i made a new app with run_every. it must from there but the error doesnt give me much to work with :wink:

Can you post the code? If you are using run_every() instead of one of the sunrise or sunset calls, something is strange.

No forget that - looks like you are on a different version to me - give me a sec

Looks like you are passing a timedelta object instead of an integer to the repeat argument in run_every()

yeah, you are right (i followed the API and forgot that i already had seen that that was wrong :P)

but something else was strange too.

i ran the code and it gave me 22 callbacks.
and after that the callbacks started falling back quickly.

  def initialize(self):
    time = datetime.datetime.now() + datetime.timedelta(minutes=1)
    repeat  = datetime.timedelta(minutes=11)
    self.run_every(self.say_something, time, repeat)

  def say_something(self, kwargs):

changed it now to repeat = 60*11
and now i get nothing anymore.

i will restart my pi, because it seems like something is wrong. tried restarting appdaemon twice, but all i get is the moduleloading part

edit: oke, after restarting all problems are gone.

1 Like

i havent said it enough lately how appdaemon rocks!!

i have homeassistant version 0.28 running.
that doesnt have tts. and in my homeassistant i havent used a mediaplayer.

but with appdaemon my rpi tells me everything loudly.
all i had to do was install gtts and with 11 lines of code hass speaks to me in every language i like.

thx andrew!

1 Like

@aimc in the api you state that you would consider to develope a locking possibility.
i think that would be highly apreciated (by me)

i let appdaemon speak out loud when a thermostat is set to a different temperature.
and at random time tell me temperature from different rooms and the time.
a few thermostats are set at the same time.

and then starts the problem. all the different threads start talking so fast after another that it seems like a bunch of people are talking. but i cant understand anything anymore.

off course i can workaround that by setting the different thermostats a minute from another.
but the event triggered spoken text and the random spoken text i cant set apart.

so i need a way to hold up entire appdaemon untill the spoken text is ready.
i just remembered i can set appdaemon to 1 thread. (for now)

@ReneTode - As a work-around, you could set up a “currently_talking” input boolean, and have your say_something app toggle it true while talking and false when done. Then just have it check for that switch before running. If the switch is true, set a one minute timer (or whatever length make sense), and call the function when it expires. That way you don’t miss any speech, but the voices aren’t talking over one another.

1 Like

probably that is better then my workaround.
because appdaemon starts struggling now as soon as something is spoken.

Are the thermostats in different apps or the same one?

I really don’t think restricting appdaemon to one thread or holding up execution is a good answer - maybe you could implement some python queuing in your app? If you tell me more about the setup we might be able to figure something out.

i am using speach from different apps.

the code is now like this:

  def say(self,text,lang):
    with tempfile.NamedTemporaryFile(suffix='.mp3', delete=False) as f:
        fname = f.name
    tts = gTTS(text=text, lang=lang)
    tts.save(fname)
    self.play(fname)
    os.remove(fname)
    
  def play(self,filename):
    cmd = ['omxplayer','-o','local',filename]
    with tempfile.TemporaryFile() as f:
        subprocess.call(cmd, stdout=f, stderr=f)
        f.seek(0)
        output = f.read()

in different apps i use:

      speak = self.get_app("speak")
      speak.say(speaktext,"nl")

or like now in the Christmas time every hour:

    speaktext = "het is nu " + str(runhour) + " uur."
    speak = self.get_app("speak")
    speak.say(speaktext,"nl")
    musiclist = ["/mnt/music/Groepen/Kerst mp3's/Gene Autry - Frosty the Snowman.mp3",
                 "/mnt/music/Groepen/Kerst mp3's/Kenny G - White Christmas.mp3",
                 "/mnt/music/Groepen/Kerst mp3's/Pat Benatar - Please Come Home For Chistmas.mp3",
                 "/mnt/music/Groepen/Kerst mp3's/Paul McCartney - Pipes Of Peace.mp3",
                 "/mnt/music/Groepen/Kerst mp3's/Moonglows - Hey Santa Claus.mp3",
                 "/mnt/music/Groepen/Kerst mp3's/Techno Christmas - Jingle Bells.mp3",
                 "/mnt/music/Groepen/Kerst mp3's/The Platters - Blue Christmas.mp3",
                 "/mnt/music/Groepen/Kerst mp3's/Mariah Carey - All I Want For Christmas Is You.mp3",
                 "/mnt/music/Groepen/Kerst mp3's/Bobby Sherman - I Saw Mommy Kissing Santa Claus.mp3",
                 "/mnt/music/Groepen/Kerst mp3's/Enya - Silent Night.mp3",
                 "/mnt/music/Groepen/Kerst mp3's/Louis Armstrong - Christmas in New Orleans.mp3",
                 "/mnt/music/Groepen/Kerst mp3's/Bill Pinky and the Original Drifters - We Wish You a Merry Christmas.mp3"]
    myrandomnumber = random.randrange(0,11,1)
    speak.play(musiclist[myrandomnumber])

and as long as i use 1 thread it works like a charm.
as soon as i use more threads i get things spoken/played at the same time.

right now i am trying to get vlc mediaplayer working with hass or in appdaemon.
then i could create a playlist and my problem would also be gone.

but i struggle with vlc. :wink:

OK, so you are running into a classic problem with multi-threaded event driven concurrent programming :slight_smile: The problem is that the real world isn’t our friend and things happen randomly and all together

I think that the way to solve this is to have a common piece of code that controls access to all the spheech. When a program wants to say something, it tells the common code, and the common code maintains a queue and makes sure that only one thing is being said at once, It sounds complicated but Python has good tools to help with this and I can try and help you figure it out if you like. This is probably the only sensible way to solve the problem without crippling AppDaemon.

If we manage to figure it out it would make a great additional example App!

EDIT: It looks like you are part way there, you seem to have the speak and play all in a single App already?

With a little restructuring this could work fine:

  1. Modify speak and say to put the parameter info on a queue rather than do it directly
  2. Create a worker thread to read from the queue, do the speak or say, then maybe wait a second or two before grabbing the next one.

This is pretty easy as it is how AppDaemon works internally.

What do you think?

1 Like