Announcement - AppDaemon 3.0 beta 5

A minor release today to address a couple of bugs.:

3.0.0b5

Features

  • Added additional error checking for badly formed RSS feeds

Fixes

  • Fixed a bug that broke binary_sensor widget.
  • Fixed a bug that broke retries when connecting to Home Assistant
  • Fixed a bug that could cause lockups during app initialization
  • Fixed a bug for Docker that prevented the initial config from working correctly - contributed by mradziwo <https://github.com/mradziwo>__

Breaking Changes

None

1 Like

I’m sure no surprise considering you were able to reproduce the issue, but I can confirm that this problem has been fixed with this new release.

Two hours from report to new code release - what took you so long? (hahahaha!) :grin:

Thanks again for all you do - don’t know what I would do without AppDaemon (oh yeah, I’d be stuck trying to code using YAML :face_with_raised_eyebrow:)

Tom

3 Likes

Thanks Tom, and that was a pretty quick test turnaround on your part too :slight_smile:

2 Likes

in the good old days he created his record from 5 (dev)releases in 2 days :wink:
please dont let him break that :wink:

3 Likes

Just released the Hass.io add-on for AppDaemon3, version v0.3.0, which contains AppDaemon v3.0.0b5.

4 Likes

hold on, andrew is working on b8 now :stuck_out_tongue:

1 Like

Hehe - not just yet!

I’m getting some odd errors with this one. For example, this error occurs:

2018-03-05 17:07:34.292575 WARNING AppDaemon: ------------------------------------------------------------
2018-03-05 17:07:34.293070 WARNING AppDaemon: Unexpected error during API call
2018-03-05 17:07:34.293496 WARNING AppDaemon: ------------------------------------------------------------
2018-03-05 17:07:34.295235 WARNING AppDaemon: Traceback (most recent call last):
  File "/usr/lib/python3.5/site-packages/appdaemon/adapi.py", line 91, in call_api
    ret, code = await self.AD.dispatch_app_by_name(app, args)
TypeError: 'NoneType' object is not iterable

…when I try to hit any API endpoint registered with register_endpoint. Sometimes, the stack trace is longer, but each one includes the same TypeError exception ('NoneType' object is not iterable). For what it’s worth, I’ve not changed that code since 3.0.0b4 (where it worked perfectly).

Thanks!

Can you post your code? This is workng ok for me on b5

You bet – it’s long, but it relates to the self.register_endpoint(self._eta_endpoint, 'eta') call. The App superclass correctly inherits from hass.Hass:

"""Define an app for working with TTS (over Sonos)."""

# pylint: disable=attribute-defined-outside-init,too-few-public-methods
# pylint: disable=unused-argument,too-many-arguments

from typing import Tuple, Union

from app import App

OPENER_FILE_URL = '/local/tts_opener.mp3'

TTS_HEADING_HOME = ('{0} is headed home and should arrive in '
                    'approximately {1} minutes.')


class TTS(App):
    """Define a class to represent the app."""

    @property
    def briefings(self) -> list:
        """Define a property to get saved briefings."""
        return self._briefings

    # --- INITIALIZERS --------------------------------------------------------
    def initialize(self) -> None:
        """Initialize."""
        self._briefings = []
        self._last_spoken_text = None
        self._last_spoken_volume = None
        self.living_room_tv = self.get_app('living_room_tv')
        self.presence_manager = self.get_app('presence_manager')
        self.sonos_manager = self.get_app('sonos_manager')
        self.utilities = self.get_app('utilities')

        self.register_endpoint(self._emergency_endpoint, 'emergency')
        self.register_endpoint(self._eta_endpoint, 'eta')
        self.register_endpoint(self._tts_endpoint, 'tts')

    # --- ENDPOINTS -----------------------------------------------------------
    def _emergency_endpoint(self, data: dict) -> Tuple[str, int]:
        """Define an endpoint to alert us of an emergency."""
        if self.presence_manager.anyone(
                self.presence_manager.HOME_STATES.Home):
            try:
                name = data['name'].title()

                self.log('Emergency Notification from {0}'.format(name))

                statement = 'Please call {0} as soon as possible.'.format(name)
                self.speak(statement)
                return {"status": "ok", "message": statement}, 200
            except KeyError:
                self.error("Unknown person: {0}".format(name))
                return '', 502

    def _eta_endpoint(self, data: dict) -> Tuple[str, int]:
        """Define an endpoint to send Aaron's ETA."""
        if self.presence_manager.anyone(
                self.presence_manager.HOME_STATES.Home):
            try:
                key = data['person']
                name = key.title()

                eta = self.get_state('sensor.{0}_travel_time'.format(key))
                statement = TTS_HEADING_HOME.format(name, eta)

                self.log("Announcing {0}'s ETA: {1} minutes".format(name, eta))
                self.speak(statement)
                return {"status": "ok", "message": statement}, 200
            except KeyError:
                self.error("Can't announce unknown person: {0}".format(name))
                return '', 502

    def _tts_endpoint(self, data: dict) -> Tuple[str, int]:
        """Define an API endpoint to handle incoming TTS requests."""
        self.log('Received TTS data: {}'.format(data), level='DEBUG')
        if 'text' not in data:
            self.error('No TTS data provided')
            return '', 502

        self.speak(data['text'])
        return {"status": "ok", "message": data['text']}, 200

    # --- CALLBACKS -----------------------------------------------------------
    def _calculate_ending_duration_cb(self, kwargs: dict) -> None:
        """Calculate how long the TTS should play."""
        master_sonos_player = kwargs['master_sonos_player']

        self.run_in(
            self._end_cb,
            self.get_state(
                str(master_sonos_player), attribute='media_duration'),
            master_sonos_player=master_sonos_player)

    def _end_cb(self, kwargs: dict) -> None:
        """Restore the Sonos to its previous state after speech is done."""
        master_sonos_player = kwargs['master_sonos_player']

        master_sonos_player.play_file(OPENER_FILE_URL)
        self.run_in(self._restore_cb, 3.25)

    def _restore_cb(self, kwargs: dict) -> None:
        """Restore the Sonos to its previous state after speech is done."""
        if self.living_room_tv.current_activity_id:
            self.living_room_tv.play()
        self.sonos_manager.ungroup_all()
        self.sonos_manager.restore_all()

    def _speak_cb(self, kwargs: dict) -> None:
        """Restore the Sonos to its previous state after speech is done."""
        master_sonos_player = kwargs['master_sonos_player']
        text = kwargs['text']

        self.call_service(
            'tts/amazon_polly_say',
            entity_id=str(master_sonos_player),
            message=text)

        self.run_in(
            self._calculate_ending_duration_cb,
            1,
            master_sonos_player=master_sonos_player)

    # --- APP API -------------------------------------------------------------
    def repeat(self) -> None:
        """Repeat the last thing that was spoken."""
        if self._last_spoken_text:
            self.log('Repeating over TTS: {0}'.format(self._last_spoken_text))
            self.speak(self._last_spoken_text, self._last_spoken_volume)

    def speak(self, text: str, volume: float = 0.5) -> None:
        """Speak the provided text through the Sonos (pausing as needed)."""
        self.log('Speaking over TTS: {0}'.format(text))

        self.sonos_manager.snapshot_all()
        master_sonos_player = self.sonos_manager.group()
        master_sonos_player.volume = volume
        master_sonos_player.play_file(OPENER_FILE_URL)

        if self.living_room_tv.current_activity_id:
            self.living_room_tv.pause()

        self.run_in(
            self._speak_cb,
            3.25,
            master_sonos_player=master_sonos_player,
            text='Good {0}. {1}'.format(self.utilities.relative_time_of_day(),
                                        text),
            volume=volume)

        self._last_spoken_text = text
        self._last_spoken_volume = volume

thats some complicated coding :wink:
is the eta endpoint the only one that generates errors?

Found the issue buried further in. All’s well here. Thank you both! :laughing:

2 Likes

Is there still an issue with binary sensors? I have several door sensors connected via wink hub as binary senors, but they do not show any status change on HADashboard?

Should be fixed in beta 5

Beta 5 is 0.3 correct? If so, then it is not working for me. Is there some change in the dashboard widget? I assume I just use the standard binary sensor widget from previous releases? The status does show up correctly in HA frontend, but none are updating on HADashboard. Let me know if I can help troubleshoot.

find out if it is a cash problem somewhere by doing the following:
 close all dashboards
 clear the cash from the browsers that you use the dashboards in
 close appdaemon
 clear your logfiles
 clear the subdirectories that are in conf/compiled but leave the structure
 close the device that is running appdaemon
 restart the device that is running appdaemon
 restart appdaemon
 open 1 dashboard in google chrome
 if you still have problems then look at the java console (CTRL Shift I) in chrome for errors and look in your logfiles for errors.

to debug we need:
|o|which appdaemon version you are running
|o|which python version you are running
|o|which system you are running it on (hassbian, hassio, ubuntu, etc.)
|o|the logfiles from the start
|o|the java console error(s)

Thanks for the detail, I don’t see a directory called conf/compiled, where would that be? I did do the rest of the steps and still have the issue, it also seems to be my motion sensors which are also binary sensors. I did not see any obvious errors in the java console (granted not quite sure what I would be looking for)

I am running AppDaemon3 0.3.0
Running hass.io V0.64.3 not sure exactly python level as it comes with hass.io install and installed on a raspberry Pi 3

Which logs would help? The only log file I see is the home-assistant.log

0.3.0 of not the AppDaemon version, the version we need is output in the log when you start it

Here is the start of the AppD log, looks like 3.0.0b5

Hass.io Add-on: AppDaemon3 v0.3.0
Python Apps and HADashboard using AppDaemon 3.x for Home Assistant
From: Community Hass.io Add-ons
By: Franck Nijhof [email protected]

[cont-init.d] 00-banner.sh: exited 0.
[cont-init.d] 01-log-level.sh: executing…
Log level is set to INFO
[cont-init.d] 01-log-level.sh: exited 0.
[cont-init.d] 02-updates.sh: executing…
INFO: You are running the latest version of this add-on
[cont-init.d] 02-updates.sh: exited 0.
[cont-init.d] 03-version-requirements.sh: executing…
INFO: Supervisor version requirements checks passed.
[cont-init.d] 03-version-requirements.sh: exited 0.
[cont-init.d] 20-init-configuration.sh: executing…
[cont-init.d] 20-init-configuration.sh: exited 0.
[cont-init.d] 21-compiled-dir.sh: executing…
[cont-init.d] 21-compiled-dir.sh: exited 0.
[cont-init.d] 30-auto-password.sh: executing…
[cont-init.d] 30-auto-password.sh: exited 0.
[cont-init.d] 31-ha-url.sh: executing…
[cont-init.d] 31-ha-url.sh: exited 0.
[cont-init.d] 50-compiled-symlink.sh: executing…
[cont-init.d] 50-compiled-symlink.sh: exited 0.
[cont-init.d] 80-system-packages.sh: executing…
[cont-init.d] 80-system-packages.sh: exited 0.
[cont-init.d] 81-python-packages.sh: executing…
[cont-init.d] 81-python-packages.sh: exited 0.
[cont-init.d] done.
[services.d] starting services
starting version 3.2.4
[services.d] done.
2018-03-06 13:47:30.993196 INFO AppDaemon Version 3.0.0b5 starting
2018-03-06 13:47:30.993805 INFO Configuration read from: /config/appdaemon/appdaemon.yaml
2018-03-06 13:47:30.997407 INFO AppDaemon: Starting Apps
2018-03-06 13:47:31.003627 INFO AppDaemon: Loading Plugin HASS using class HassPlugin from module hassplugin
2018-03-06 13:47:31.045941 INFO AppDaemon: HASS: HASS Plugin Initializing
2018-03-06 13:47:31.047598 INFO AppDaemon: HASS: HASS Plugin initialization complete
2018-03-06 13:47:31.049176 INFO Starting Dashboards
2018-03-06 13:47:31.067140 INFO API is disabled
2018-03-06 13:47:31.088220 INFO AppDaemon: HASS: Connected to Home Assistant 0.64.3
2018-03-06 13:47:31.319756 INFO AppDaemon: Got initial state from namespace default
2018-03-06 13:47:33.570001 INFO AppDaemon: Reading config
2018-03-06 13:47:33.578197 INFO AppDaemon: /config/appdaemon/apps/apps.yaml added or modified
2018-03-06 13:47:33.578740 INFO AppDaemon: /config/appdaemon/apps/apps.yaml added or modified
2018-03-06 13:47:33.579221 INFO AppDaemon: App ‘hello_world’ added
2018-03-06 13:47:33.580039 INFO AppDaemon: Adding /config/appdaemon/apps to module import path
2018-03-06 13:47:33.581470 INFO AppDaemon: Loading App Module: /config/appdaemon/apps/hello.py
2018-03-06 13:47:33.619222 INFO AppDaemon: Initializing app hello_world using class HelloWorld from module hello
2018-03-06 13:47:33.953416 INFO hello_world: Hello from AppDaemon
2018-03-06 13:47:33.958215 INFO hello_world: You are now ready to run Apps!
2018-03-06 13:47:33.959786 INFO AppDaemon: App initialization complete
2018-03-06 13:47:34.262722 INFO HADashboard: New dashboard connected: Hello Panel
2018-03-06 13:47:38.486345 INFO HADashboard: New dashboard connected: Hello Panel

Suggestion for @frenck: maybe it would help to have the versioning of the plugin related to the AD version.

Are there specific requirements for the version numbering? I have seen software (linux packages if I remember well) following a double scheme like v0.3.0-AD3.0b5 .