Announcement: AppDaemon 4.0.0 beta 2

Good morning all,

Here is the latest beta for AppDaemon 4.0.0

As promised, thanks to hard work from the team we now have among other things Async Apps and 3 new and one reworked dashboard widget.

In addition, we have a new feature called sequences - these allow predefined sequences of service calls to be triggered by apps. Initially they are useful for self contained scenes within AppDaemon but also have many other uses as they include the ability to delay execution for periods of time, something that is not recommended in threaded apps (although perfectly fine in the new Async apps!). Sequences are a key building block of the upcoming automation rules engine we are working on for a future version of AppDaemon.

Updated docs for AD 4.0 can be found here .

Installation instructions can be found here - PyPi has a development build available, use appdaemon==4.0.0b2, there is also a Docker image available on Docker Hub.

Some hints and tips on upgrading can be found here .

Take a look and let us know if you find any issues. The next release will be the official 4.0.0 version!

4.0.0 Beta 2 (2019-10-19)

Features

  • Added a timeout parameter to listen_state() and listen_event() to delete the callback after a pre-determined interval.
  • Added render_template() handling
  • global_modules can now be declared in multiple yaml files
  • It is now possible to inject arbitrary headers in served http content
  • Updated camera widget now supports streams and token refreshing
  • Added input_text and input_datetime widgets
  • Added the ability to control the number of threadpool workers
  • Each time a new service is registered, a service_registered event is fired, which can be picked up by apps
  • Added support for async apps
  • Added authorization to stream as well as command semantics for various functions
  • Added sequences
  • Added sequence widget
  • Added app access to dashboard directory using self.dashboard_dir
  • List of available dashes is now alphabetically sorted
  • Changed namespaces implementation to use shelve instead of JSON enabling non JSON-serializable objects to be stored and also potential performance increases - contributed by Robert Schindler <https://github.com/efficiosoft>__
  • MDI updated to version 4.4.95 - contributed by Roeland Van Lembergen <https://github.com/clayhill>__

Fixes

  • Fixed a bug in global_modules that caused a exception
  • Fixed icon bug in weather widget - contributed by Roeland Van Lembergen <https://github.com/clayhill>__

Breaking Changes

  • timeout is now an official parameter to listen_state() and listen_event(). If you were using timeout in your kwargs section for either you should rename that parameter.
  • The camera widget has changed parameters - check the docs for details
  • Moved the log events from global to admin namespace. if listen_log is just used for listening to logs, it shouldn’t matter
  • If you have used persistent namespaces in the previous beta it is necessary to delete all saved namespaces by removing all files in the namespaces subdirectory under your appdaemon config directory
10 Likes

Hmmm… upgraded from b1 to b2. Doesn’t start.

2019-10-19 10:57:26.307022 WARNING AppDaemon: ------------------------------------------------------------
2019-10-19 10:57:26.307604 WARNING AppDaemon: Unexpected error during run()
2019-10-19 10:57:26.310298 WARNING AppDaemon: ------------------------------------------------------------
Traceback (most recent call last):
  File "/opt/python-venvs/appdaemon/lib/python3.7/site-packages/appdaemon/__main__.py", line 135, in run
    loop.run_until_complete(asyncio.gather(*pending))
  File "/usr/lib/python3.7/asyncio/base_events.py", line 584, in run_until_complete
    return future.result()
  File "/opt/python-venvs/appdaemon/lib/python3.7/site-packages/appdaemon/utility_loop.py", line 58, in loop
    await self.AD.http.start_server()
AttributeError: 'NoneType' object has no attribute 'start_server'
2019-10-19 10:57:26.310852 INFO AppDaemon: Previous message repeated 1 times
2019-10-19 10:57:26.311152 INFO AppDaemon: AppDaemon Exited

Okay, so there is an additional breaking change. This is no longer optional.

http:
  url: http://0.0.0.0:5050

for now it seems not to be, but thats going to change.

Running 4.0.0b2 and trying to use @ad.app_lock as described in section 6.14:

import hassapi as hass
import datetime

class Locking(hass.Hass):
   def initialize(self):
     self.important_var = 0
     now = datetime.datetime.now()
     target = now + datetime.timedelta(seconds=2)
     for i in range (1000):
       self.run_at(self.hass_cb, target)

   @ad.app_lock
   def hass_cb(self, kwargs):
     self.important_var += 1
     self.log(self.important_var)

Getting this error (NameError: name ‘ad’ is not defined):

==> /config/appdaemon/Logs/appdaemonerr.log <==
2019-12-02 23:03:02.195877 WARNING Error: ------------------------------------------------------------
2019-12-02 23:03:02.196936 WARNING Error: Unexpected error loading module: /config/appdaemon/apps/ttt.py:
2019-12-02 23:03:02.198732 WARNING Error: ------------------------------------------------------------
2019-12-02 23:03:02.201931 WARNING Error: Traceback (most recent call last):
  File "/usr/lib/python3.7/site-packages/appdaemon/app_management.py", line 551, in read_app
    importlib.reload(self.modules[module_name])
KeyError: 'ttt'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3.7/site-packages/appdaemon/app_management.py", line 773, in check_app_updates
    await utils.run_in_executor(self, self.read_app, mod["name"], mod["reload"])
  File "/usr/lib/python3.7/site-packages/appdaemon/utils.py", line 277, in run_in_executor
    response = future.result()
  File "/usr/lib/python3.7/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/usr/lib/python3.7/site-packages/appdaemon/app_management.py", line 556, in read_app
    self.read_app(file)
  File "/usr/lib/python3.7/site-packages/appdaemon/app_management.py", line 565, in read_app
    self.modules[module_name] = importlib.import_module(module_name)
  File "/usr/lib/python3.7/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 728, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/config/appdaemon/apps/ttt.py", line 4, in <module>
    class Locking(hass.Hass):
  File "/config/appdaemon/apps/ttt.py", line 12, in Locking
    @ad.app_lock
NameError: name 'ad' is not defined

2019-12-02 23:03:02.203259 WARNING Error: ------------------------------------------------------------

What am I missing?

Thanks!

I assume it’s the import of the appdaemon library that you are missing.

import adbase as ad

1 Like

where do i find section 6.14?

I think he’s referring to this document https://buildmedia.readthedocs.org/media/pdf/appdaemon/dev/appdaemon.pdf

1 Like

thx. i didnt even know that existed :wink:

Me neither until I did a google search for ad.app_lock appdaemon, it seems the document is from 2 days ago :slight_smile:

i guess its an option from readthedocs.
andrew updated dev 2 days ago, so there is new stuff in the docs.

Thank you - that was it!

One more question … I am trying to set production mode on/off using the service call:

self.call_service("production_mode/set", mode=False, namespace="appdaemon")

and I get the following WARNING:

WARNING AppDaemon: Unknown domain (appdaemon/production_mode) in call_service from ADProdMode

Here’s the code:

import hassapi as hass
import datetime
import adbase as ad

class ADProdMode(hass.Hass):
   def initialize(self):
     self.listen_state(self.chk_prod_mode,"input_boolean.turn_on_ad_production_mode")
     #self.call_service("app/restart", app="BedHeat", namespace="appdaemon")

   def chk_prod_mode(self, entity, attribute, old, new, kwargs):
     if new=="off" and old=="on":
       self.log("Turning Appdaemon Production Mode OFF")
       self.call_service("production_mode/set", mode=False, namespace="appdaemon")
     if new=="on" and old=="off":
       self.log("Turning Appdaemon Production Mode ON")
       self.call_service("production_mode/set", mode=True, namespace="appdaemon")

Here’s my appdaemon.yaml file:

secrets: /config/secrets.yaml
logs:
  main_log:
    filename: /config/appdaemon/Logs/appdaemon.log
  access_log:
    filename: /config/appdaemon/Logs/appdaemonaccess.log
  error_log:
    filename: /config/appdaemon/Logs/appdaemonerr.log
appdaemon:
  latitude: redaction
  longitude: redaction
  elevation: 9
  time_zone: America/New_York
  app_dir: /config/appdaemon/apps
  plugins:
    HASS:
      type: hass
      ha_url: http://192.168.1.215:8123
      token: eyJ0eXAiOiJ......redacted
http:
  url: http://192.168.1.215:5050
api:
admin:
  title: AppDaemon
  stats_update: realtime

Note that the restart service call works without any issues.

Thanks for any insight you can provide!

Tom

I suggest opening a new topic for your question instead of posting it in this topic.

I can only guess, buy maybe you need to add production_mode: true to your appdaemon.yaml file for the service calls to work.

tom, if its possible to ask your questions on our discord server then i would highly appreciate that.

i just tested but i got the same problem. so lets ask @Odianosen25 how he uses it.
@Burningstone if that would work it would be a bug anyway. the service call should just work.

but another remark @eBoon
please try to avoid using old style app writing combined with new style appwriting.

old style is inherit from 1 plugin by using:

import appdaemon.plugins.hass.hassapi as hass
class Alexa_AD(hass.Hass):

    def initialize(self): 
        self.log("a")
        self.turn_on(entity)

in that case dont import adbase

new style:

import adbase as ad

class Broadlink_App(ad.ADBase):
  
    def initialize(self): 
        self.adbase = self.get_ad_api()
        self.hass = self.get_plugin_api("hass")
        self.adbase.log("a")
        self.hass.turn_on(entity)

there are a lot of new functions/options in AD 4, but they are mostly developed and tested for the new style apps. combining styles (inherit from plugin, and still import adbase and use it) is asking for trouble.

2 Likes

Yeah, you’re right (as always :stuck_out_tongue:). I was just making an uneducated guess.

hmm, i like to be always right, but i am still human :wink:
but it wouldnt be a bad try, and it would be possible that thats the reason the bug got unnoticed.
my other guess was that new style app was needed, but that gave the same error.

and the code has become to complicated so that i can do a quick lookup, to see if another namespace is needed

and then i saw why the error probably isnt noticed before:

dont use call_service.

but in stead just use the function that is created for it:

self.set_production_mode(True/False)

1 Like

@eBoon,

Strange this issue is happening. This works for me

def initialize(self): 
        self.adbase = self.get_ad_api()
        self.adbase.call_service("production_mode/set", mode=True, namespace="appdaemon")

Not sure why this is happening for you really

Yes that actually was imputed before the service call, so might just be the call_service side of things is quite new. Actually it is, one of the things that was added newly