Giter Site home page Giter Site logo

appdaemon / appdaemon Goto Github PK

View Code? Open in Web Editor NEW
815.0 33.0 415.0 19.8 MB

:page_facing_up: Python Apps for Home Automation

License: Other

Python 62.47% Shell 0.35% CSS 8.33% JavaScript 25.19% HTML 1.41% Dockerfile 0.28% Jinja 1.97%
python home-automation

appdaemon's Introduction

Description

AppDaemon is a loosely coupled, multi-threaded, sandboxed python execution environment for writing automation apps for various types of Home Automation Software including Home Assistant and MQTT. It has a pluggable architecture allowing it to be integrated with practically any event driven application.

It also provides a configurable dashboard (HADashboard) suitable for wall mounted tablets.

Getting started

For full instructions on installation and usage check out the AppDaemon Project Documentation.

Release Cycle Frequency

AppDaemon has reached a very stable point, works reliably and is fairly feature rich at this point in its development. For that reason, releases have been slow in recent months. This does not mean that AppDaemon has been abandoned - it is used every day by the core developers and has an active discord server here - please join us for tips and tricks, AppDaemon discussions and general home automation.

Contributing

This is an active open-source project. We are always open to people who want to use the code or contribute to it. Thank you for being involved! Have a look at the official documentation for more information.

appdaemon's People

Contributors

acockburn avatar basnijholt avatar benleb avatar clyra avatar dependabot-preview[bot] avatar dependabot[bot] avatar deviantintegral avatar dlashua avatar eboon123 avatar engrbm87 avatar jasonmhite avatar jonasped avatar jsl12 avatar kabturek avatar lexfrei avatar marconett avatar mion00 avatar mmmmmtasty avatar nigelrook avatar odianosen25 avatar renetode avatar rhumbertgz avatar rr326 avatar rschaeuble avatar smolz avatar tigger2014 avatar tschmidty69 avatar vrs01 avatar wernerhp avatar yawor avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

appdaemon's Issues

dictionary update sequence ValueError in appapi

In writing a new app, I came across this bug.

Here is my relevant code:

data = {"XX:XX:XX:XX:XX:XX": {"last_seen": "2017-02-04 01:19:19.429865", "location": "Out", "friendly_name": "SupahNoob"}}

...

        # expose this information to the front end, including the full object
        self.set_state('binary_sensor.{}_presence'.format(data['XX:XX:XX:XX:XX:XX']['friendly_name'].lower()),
                       state=data['XX:XX:XX:XX:XX:XX']['location'],
                       attributes=json.dumps(data))

raises a ValueError in appapi.py

2017-02-03 23:56:53.782014 WARNING ------------------------------------------------------------
2017-02-03 23:56:53.782606 WARNING Unexpected error in worker for App presence_listener:
2017-02-03 23:56:53.782986 WARNING Worker Ags: {'function': <bound method PresenceListener.person_is_home of <presence_listener.PresenceListener object at 0x6feb5350>>, 'data': {'mac': 'XX:XX:XX:XX:XX:XX', 'last_seen': '2017-02-03 23:56:53.758789'}, 'type': 'event', 'name': 'presence_listener', 'event': 'internal_trigger_ishome', 'id': UUID('2102ce75-bc1b-4da2-8737-052c2ababd50'), 'kwargs': {}}
2017-02-03 23:56:53.783268 WARNING ------------------------------------------------------------
2017-02-03 23:56:53.784675 WARNING Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/appdaemon/appdaemon.py", line 458, in worker
    function(args["event"], data, args["kwargs"])
  File "/home/homeassistant/.homeassistant/appdaemon/conf/apps/presence_listener.py", line 81, in person_is_home
    attributes=json.dumps({mac: self.users[mac]}))
  File "/usr/local/lib/python3.4/dist-packages/appdaemon/appapi.py", line 185, in set_state
    args["attributes"].update(kwargs["attributes"])
ValueError: dictionary update sequence element #0 has length 1; 2 is required

I'm not positive how to fix this one in appapi. I'm passing a full, serialized dictionary to the api, essentially so that the user can have all the information in the front end.

  • SN

Problems upgrading from the Initial v1 release

There were several issues with upgrading from the initial release that broke everything until I did some trial and error troubleshooting.

A big issue was that you changed from using import appapi to import appdaemon.appapi as appapi, which stopped all of my pervious apps from running. I only found out the proper import by looking at the hello.py, so I had to replace that line in all of my apps.

I was forced to run it as a systemd service because the /etc/init.d script you provided will not work as it keeps giving the error:

ImportError: No module named 'appdaemon.conf'; 'appdaemon' is not a package

So it is not finding the conf.py from the appdaemon.py

So, then, using the systemd service throws an error because it does not include the -c argument to point to the configuration file, which is at the default location along with the included appdaemon.cfg.example, but it still told me it couldn't find it, so I had to add the -c flag to the appdaemon.service file.

I really LOVE appdaemon, but enough has changed from the setup of the original version that I can guarantee that all users of the previous version will have errors and problems upgrading. Hopefully this will not be a problem for new users starting out fresh.

Thanks again for the appdaemon, don't know how I lived without it :)

feature request log file switch

When the log file switches, can you add a last line to the current file that says that the log is being switched. When I run tail on the file, it just stops and sits there and sometimes I'm not sure if nothing is happening or if there has been a log file switch. This is especially a problem with the err file.

have get trackers return state also.

Any reason why we aren't just returning a dictionary as the results for get_trackers.

def get_trackers(self):
        return (key for key, value in self.get_state("device_tracker").items())

Why not return the whole result

  def my_get_trackers(self):
    return(self.get_state("device_tracker"))

You could still iterate over it the same way

    for tracker, tstate in self.my_get_trackers().items():
      self.log("tracker_list={:<40} {:<20}".format(tracker,tstate["state"]))

It would give us the tracker list and the ability to pull the current state from one call.

2017-02-17 13:54:41.118961 INFO homeaway: checkHomeState - (32) tracker_list=device_tracker.phonecharlie              not_home            
2017-02-17 13:54:41.123799 INFO homeaway: checkHomeState - (32) tracker_list=device_tracker.phonesam                  not_home            
2017-02-17 13:54:41.128811 INFO homeaway: checkHomeState - (32) tracker_list=device_tracker.scox1209_scox1209         Quince              
2017-02-17 13:54:41.133859 INFO homeaway: checkHomeState - (32) tracker_list=device_tracker.phonesusan                not_home            
2017-02-17 13:54:41.139272 INFO homeaway: checkHomeState - (32) tracker_list=device_tracker.scox0129_sc0129           UOM                 
2017-02-17 13:54:41.144452 INFO homeaway: checkHomeState - (32) tracker_list=device_tracker.turboc1208_cc1208         house               
2017-02-17 13:54:41.149332 INFO homeaway: checkHomeState - (32) tracker_list=device_tracker.phonechip                 home                

python package for pip install

The installation instructions are pretty manual right now; it'd help if the project was set up as a normal pip-installable python package. Even just adding a setup.py should allow people to pip install it using the git url.

Adding a requirements.txt and changing the instructions to pip3 install -r requirements.txt would also be a good improvement over manually installing multiple dependencies.

AppDaemon won't start after upgrade

I upgraded appdaemon to 1.5 and got the following error when trying to start it

โ— appdaemon.service - LSB: Start daemon at boot time
   Loaded: loaded (/etc/init.d/appdaemon)
   Active: failed (Result: exit-code) since Sun 2017-01-29 10:47:19 CST; 1min 45s ago
  Process: 24611 ExecStop=/etc/init.d/appdaemon stop (code=exited, status=0/SUCCESS)
  Process: 24696 ExecStart=/etc/init.d/appdaemon start (code=exited, status=1/FAILURE)

Jan 29 10:47:19 hass appdaemon[24696]: File "/usr/local/lib/python3.4/dist-packages/pkg_resources/__init__.py", line 2631, in load_entry_point
Jan 29 10:47:19 hass appdaemon[24696]: return ep.load()
Jan 29 10:47:19 hass appdaemon[24696]: File "/usr/local/lib/python3.4/dist-packages/pkg_resources/__init__.py", line 2291, in load
Jan 29 10:47:19 hass appdaemon[24696]: return self.resolve()
Jan 29 10:47:19 hass appdaemon[24696]: File "/usr/local/lib/python3.4/dist-packages/pkg_resources/__init__.py", line 2297, in resolve
Jan 29 10:47:19 hass appdaemon[24696]: module = __import__(self.module_name, fromlist=['__name__'], level=0)
Jan 29 10:47:19 hass appdaemon[24696]: ImportError: No module named 'appdaemon.appdaemon'
Jan 29 10:47:19 hass systemd[1]: appdaemon.service: control process exited, code=exited status=1
Jan 29 10:47:19 hass systemd[1]: Failed to start LSB: Start daemon at boot time.
Jan 29 10:47:19 hass systemd[1]: Unit appdaemon.service entered failed state.

I have not upgraded to the latest HA, still on 0.36.1

Allow configuration of logger via config file

As far as I can see the only way to set the log level to debug is to do this via the -D LOG_LEVEL option at application startup. The log level will then be set application wide. Also the message format is fixed. Libraries used in application won't adhere to this format though since they do not use the ha.log function.

I would prefer to have my logging configuration in a file read from a configuration directory, then use the python logging logger directly rather than the ha.log function as libraries do.

I therefore suggest reading the configuration of the logger from a logging.cfg file that is placed in a standard location (i.e /home/userdir/.appdaemon followed by /etc/appdaemon on a Linux box). If there is no such file a basic configuration can be set up programmatically. A new command line argument can be put into place to change the configuration directory to an arbitrary location and a sample logging.cfg can be shared or written on startup to the user's home directory if there is no other such file in the system so far.

Do you think this way of configuring the logger fits into the project? If so, I can of course help you with the necessary changes.

Feature request: Allow a dashboard to import an arbitrary js file

There are some dashboard use cases which may be difficult to implement without some user code running in the browser after the dashboard has been loaded. Some examples are:

  • changing style-sheets for DOM elements where no change is allowed via the configuration
  • implementing custom code that, for examples triggers loading a different dashboard after a period of time (cycling through dashboards)
  • further custom development

In order to implement those I suggest adding a dashboard global parameter that points to a js file (either local or a URL) that is included in the generated HTML file after the required javascript code is loaded. The user's javascript code could then use something like $( document ).ready() to add their custom code to be executed according to their needs.

If I manage to find where to add such functionality, I'll submit a PR.

Appdaemon Pre-processor

The way you did the log files got me thinking. It's almost a macro the way you did it. How about a pre-processor that does simple string replacements into our code as it's loaded into appdaemon? Here is why I am thinking this. Continually typing

self.log("__function__ (__line__) here is my log entry")
repeat 20 or 30 times while debugging which arguably is when you need the function and line numbers the most. It's a pain.

even using a variable isn't much better.

self.log(self.func + "("+self.line+") " + "here is my log entry")
doesn't make it any better

but
typing Dlog("here is my log entry")
and having it replaced at run time with
self.log("__function__ (__line__) here is my log entry")
would be really cool.

The problem with making Dlog a local function is that they any function and line references it puts in the log would reference Dlog as the function so it has to be some type of code substitution.

Make sense??

Feature Request - Recursively monitor apps folder

Thought about posting this in the HA community thread, but I thought it might get lost. In HA, I have each of my automations in separate files, organized in subfolders. I am on a roll making lots of apps, so it would be great if we could organize them in subfolders under the apps direction and have it monitor recursively to pickup all new apps instead of having them all out in the root of the apps directory.

Callback keyword arguments inconsistent with API documentation

Hi,

I've found that the documentation for callback functions says that the callback should get extra args as a standard python keyword args (**kwargs). Unfortunately this seems to not be true and instead whole kwargs dict is passed as a last positional argument.

For example here's a code that calls callback for event:

function(args["event"], data, args["kwargs"])

but, to be consistent with documentation, it should be:

function(args["event"], data, **args["kwargs"])

The same for other calls.

Connecting with SSL enabled: Option to specify root CA certificate

Thanks for this immensely helpful extension to HASS.
I am connecting with SSL enabled with a self-signed certificate.
To do this, I made changes in the source files so that all references to requests.get includes a verify option.

For instance:
r = requests.get(apiurl, headers=headers, verify="/path/to/root/CA/cert")

Would it be possible to add an option for a root CA certificate file in the config file?

Option to not set the TZ environment variable

The following line in appdaemon.py causes all of the callbacks in my setup to run one hour late during daylight saving time:
os.environ['TZ'] = conf.time_zone
Which was introduced in version 1.3.2

Both datetime.datetime.now() and the unix date command report the correct date when run independently of appdaemon, as does the initial log entry:
2017-06-11 17:09:42.740172 INFO AppDaemon Version 1.5.2 starting <-- this is the correct time
2017-06-11 16:09:53.338815 INFO Got initial state <-- Now we have an incorrect time

The system TZ environment variable is set correctly at system startup, however my system requires the extended format to correctly adjust for DST rather than the simpler Region/City format used in the HA config.

Is it possible to adjust this to one of the following options:

  • Only set TZ if it is currently blank
  • Provide an option (defaulting to False) to use the system supplied timezone
  • Get the current time using the same method as home assistant (which reports the correct time on my system).

FileNotFoundError: [Errno 2] No such file or directory: 'conf/appdaemon.cfg'

i just installed it according to https://github.com/home-assistant/appdaemon/blob/master/README.md and https://github.com/home-assistant/appdaemon/blob/master/DASHBOARD.md

cant run appdaemon -c conf because it throws back: FileNotFoundError: [Errno 2] No such file or directory: 'conf/appdaemon.cfg' - when i rename the appdaemon.yaml into appdaemon.cfg it still fails with following error:

root@raspberrypi:/opt/appdaemon_dashboard/appdaemon# appdaemon -c conf
Traceback (most recent call last):
File "/usr/local/bin/appdaemon", line 9, in
load_entry_point('appdaemon==2.0.0beta3.5', 'console_scripts', 'appdaemon')()
File "/usr/local/lib/python3.4/dist-packages/appdaemon/appdaemon.py", line 1436, in main
config.read_file(open(config_file))
File "/usr/lib/python3.4/configparser.py", line 691, in read_file
self._read(f, source)
File "/usr/lib/python3.4/configparser.py", line 1058, in _read
raise MissingSectionHeaderError(fpname, lineno, line)
configparser.MissingSectionHeaderError: File contains no section headers.
file: 'conf/appdaemon.cfg', line: 1
'AppDaemon:\n'

documentation is still very unclear.
what am i missing?

compatibility for requests-2.16.0

After updating to requests-2.16.0 (automatically updated when updating home assistant to 0.45.1) appdaemon won't start anymore:

May 27 13:45:56 appdaemon[1407]: Traceback (most recent call last): May 27 13:45:56 appdaemon[1407]: File "/usr/local/bin/appdaemon", line 11, in <module> May 27 13:45:56 appdaemon[1407]: load_entry_point('appdaemon==1.5.2', 'console_scripts', 'appdaemon')() May 27 13:45:56 appdaemon[1407]: File "/usr/local/lib/python3.4/dist-packages/pkg_resources/__init__.py", line 560, in load_entry_point May 27 13:45:56 appdaemon[1407]: return get_distribution(dist).load_entry_point(group, name) May 27 13:45:56 appdaemon[1407]: File "/usr/local/lib/python3.4/dist-packages/pkg_resources/__init__.py", line 2648, in load_entry_point May 27 13:45:56 appdaemon[1407]: return ep.load() May 27 13:45:56 appdaemon[1407]: File "/usr/local/lib/python3.4/dist-packages/pkg_resources/__init__.py", line 2302, in load May 27 13:45:56 appdaemon[1407]: return self.resolve() May 27 13:45:56 appdaemon[1407]: File "/usr/local/lib/python3.4/dist-packages/pkg_resources/__init__.py", line 2308, in resolve May 27 13:45:56 appdaemon[1407]: module = __import__(self.module_name, fromlist=['__name__'], level=0) May 27 13:45:56 appdaemon[1407]: File "/usr/local/lib/python3.4/dist-packages/appdaemon/appdaemon.py", line 30, in <module> May 27 13:45:56 appdaemon[1407]: import appdaemon.homeassistant as ha May 27 13:45:56 appdaemon[1407]: File "/usr/local/lib/python3.4/dist-packages/appdaemon/homeassistant.py", line 8, in <module> May 27 13:45:56 appdaemon[1407]: from requests.packages.urllib3.exceptions import InsecureRequestWarning May 27 13:45:56 appdaemon[1407]: ImportError: No module named 'requests.packages'

I had to manually downgrade requests to the previous version: sudo pip install --upgrade requests==2.14.2

Listening for an event with specific data

Hi,

I am loving this functionality! Thank you very much for making it so easy to have very complex automations :D!

I was trying out a custom automation using my zwave minimote. The tl;dr about it is that it is a multi-button remote. When a button is pressed, it emits an event, zwave.scene_activated, and it also associates some data about which button was pressed in the form of scene_id in an object:

2016-09-07 22:19:11.654286 DEBUG Event type:zwave.scene_activated:
2016-09-07 22:19:11.654432 DEBUG {'object_id': 'aeotec_dsa03202_minimote_4', 'entity_id': 'aeotec_dsa03202_minimote_4', 'scene_id': 7}

I am currently listening for events like this:

self.listen_event(self.cycle_scene, 'zwave.scene_activated', entity_id='aeotec_dsa03202_minimote_4')

I had originally thought that by passing another named parameter, scene_id, I'd be able to automatically filter on that.

self.listen_event(self.cycle_scene, 'zwave.scene_activated', entity_id='aeotec_dsa03202_minimote_4', scene_id=self.scene_id)

However, that did not work and cycle_scene was called for each different button press.

I'm currently getting around this by persisting a configured scene_id in initialize, and in the callback method, checking the incoming data and aborting the action if the numbers do not match:

  def cycle_scene(self, event_name, data, kwargs):
      if 'scene_id' in data and int(data['scene_id']) != int(self.scene_id):
          self.log('done')
          return

      # other code removed

Not bad, but I'm wondering if I've just missed something in the docs about how better to deal with this?

Thanks

1.5.1 Doesn't like Dev

Looks like the new version pull/check doesn't account for someone running a dev build of HASS. Not sure the best way to handle the fix since you want to check against the version to determine whether or not to use websockets.

2017-01-30 08:51:47.626748 INFO AppDaemon Version 1.5.1 starting

Traceback (most recent call last):
File "/usr/local/bin/appdaemon", line 11, in <module>
load_entry_point('appdaemon==1.5.1', 'console_scripts', 'appdaemon')()
File "/usr/local/lib/python3.5/site-packages/appdaemon/appdaemon.py", line 1250, in main
conf.version = int(ha_config["version"].replace(".", ""))

ValueError: invalid literal for int() with base 10: '0380dev0

Storing basic options separately from app config

What I want to do is to push the app configuration to Github along with the apps themselves, but keep the other configuration (host, password etc.) locally. Is there any way to achieve this? There should be something similar to Home Assistant's secret handling, or at least a way to store configuration in multiple files.

Appdaemon 2.0.0beta4 - YAML without HADashboard does not work

I just tried to convert one of my Appdaemon instances to the new version of appdaemon 2.0.0beta4. Therefore I converted my config to YAML. I tried starting it without the dashboard part.

This results in the following error, which prevents Appdaemon from startup:

Jun 18 22:36:42 watchpi systemd[1]: Started HA AppDaemon.
Jun 18 22:36:48 watchpi appdaemon[11319]: Traceback (most recent call last):
Jun 18 22:36:48 watchpi appdaemon[11319]: File "/usr/local/bin/appdaemon", line 9, in <module>
Jun 18 22:36:48 watchpi appdaemon[11319]: load_entry_point('appdaemon==2.0.0beta4', 'console_scripts', 'appdaemon')()
Jun 18 22:36:48 watchpi appdaemon[11319]: File "/usr/local/lib/python3.4/dist-packages/appdaemon/appdaemon.py", line 1570, in main
Jun 18 22:36:48 watchpi appdaemon[11319]: conf.dash_url = config['HADashboard'].get("dash_url")
Jun 18 22:36:48 watchpi appdaemon[11319]: KeyError: 'HADashboard'
Jun 18 22:36:48 watchpi systemd[1]: hass-appdaemon.service: main process exited, code=exited, status=1/FAILURE
Jun 18 22:36:48 watchpi systemd[1]: Unit hass-appdaemon.service entered failed state.

Adding a valid dashboard configuration to the YAML file solves the issue:

HADashboard:
  dash_url: 'http://127.0.0.1:5050'

Deprecated vars

Elevation, latitude, longitude and time_zone are deprecated, but are still in the docs:

2017-02-03 18:42:05.759027 WARNING 'elevation' directive is deprecated, please remove

Systemd unit and standardizing the configuration location

Per discussion from #3...

The unitfiles for systemd are pretty simple, assuming appdaemon is executable and in $PATH then it's just something like

[Unit]
Description=AppDaemon service for Home Assistant

[Service]
ExecStart=/usr/bin/appdaemon /path/to/config

[Install]
WantedBy=multi-user.target

This would be appdaemon.service and gets dropped in /etc/systemd/system.

As a side note, you might want to set a default location for the configuration file like /etc/appdaemon/appdaemon.cfg or something. That way you don't need to pass the name of the config file in the service call (same applies to sysv init scripts). The end goal in my mind being that AppDaemon can behave like most daemons and use standard paths so the user doesn't have to edit the service files to set paths.

Once you merge your changes to repackage AppDaemon I can test and add the unit file. Lemme know your opinions on standardizing the config file location, I can do the work there too but it's your call on if/how to do it.

Allow API Calls to dump schedule etc.

I know we talked about this a few months ago, but can you move the dump_schedule, dump_callbacks, etc functions into the api and have them return a list or dictionary or something? It would be useful from a debugging perspective to be able to monitor the schedule and callbacks as well as others and have the choice of outputting the results to the log or to the command line. Outputting the results of the killall 10 command just push everything I am looking for up in the log so that it's hard to compare the output I put in the log against the output of the debug statement, or alternatively, make the dups accessible from the appdaemon command line so that we could just type in appdaemon --dump=schedule or --dump=callbacks, etc

change run_in to ms

Hi

Im running a looping script to change the brightness of a light depending on the last brightness reported.

I've gotten the script to run fine but because of the restriction of a minimum 1sec on self.run_in i cannot get it to work "kinda smooth". The lamp im atm using is on a wifi and the latency is well obiously not gonna get me down to a really smooth dim but running each step under 1sec would be awesome.

Ill post my code so you can see what i mean:

import appdaemon.appapi as appapi
import appdaemon.homeassistant as ha
#Args:
#
# switch-trigger: switch to use as trigger
# entity : entity to turn on when detecting switch-trigger, can only be light (brightness is only in light)
#


class DimmerSwitch(appapi.AppDaemon):

  def initialize(self):
    self.dimming = 0
    self.old_brightness = 0
    if "switch-trigger" in self.args:
      self.listen_state(self.switchchange, self.args["switch-trigger"])
    else:
      self.log("No trigger switch specified, doing nothing")

  def switchchange(self, entity, attribute, old, new, kwargs):
    if new == "on" and old == "off" :
      if "entity" in self.args:
        self.log("Switch turn on: turning {} on".format(self.args["entity"]))
        self.turn_on(self.args["entity"])
    elif new == "off" and old == "on" :
      if "entity" in self.args:
        self.log("Switch turn off: turning {} off".format(self.args["entity"]))
        self.turn_off(self.args["entity"])
    elif new == "off" and old == "off" :
      if "entity" in self.args:
        self.log("Switch turn off: turning {} off".format(self.args["entity"]))
        self.turn_off(self.args["entity"])
    elif new == "on" and old == "on" :
      if self.dimming == 1:
        self.noloop(0)
      else:
        self.stoploop = 0
        self.dimmerloop(0)
      self.dimming = 1

  def noloop(self, kwargs):
    self.dimming = 0
    self.stoploop = 1
    self.log("Stopping Dimmer loop")

  def dimmerloop(self, kwargs):
    print(ha.get_now_ts())
    self.new_brightness = self.get_state(self.args["entity"], "brightness")
    if self.old_brightness == 0:
      self.old_brightness = self.new_brightness
    if self.new_brightness <= 6 :
      self.log("Brightness at 1: waiting 2 sec and then increasing by 25")
      self.run_in(self.minbrightness, 2)
    elif 7 <= self.new_brightness <= 250 and self.new_brightness >= self.old_brightness :
      self.increasebrightness(0)
    elif 7 <= self.new_brightness <= 250 and self.new_brightness < self.old_brightness :
      self.decreasebrightness(0)
    elif self.new_brightness >= 251 :
      self.log("Brightness at 255: waiting 2 sec and then decreasing by 25")
      self.run_in(self.maxbrightness, 2)

  def minbrightness(self, kwargs):
    self.old_brightness = self.new_brightness
    self.new_brightness = self.new_brightness + 25
    self.turn_on(self.args["entity"], brightness = self.new_brightness)
    if self.stoploop == 1 :
      self.noloop(0)
    else:
      self.dimmerloop(0)

  def decreasebrightness(self, kwargs):
    self.log("Brightness at {}: decreasing by 25".format(self.new_brightness))
    self.old_brightness = self.new_brightness
    self.new_brightness = self.new_brightness - 25
    self.turn_on(self.args["entity"], brightness = self.new_brightness)
    if self.stoploop == 1 :
      self.noloop(0)
    else:
      self.run_in(self.dimmerloop, .2)

  def increasebrightness(self, kwargs):
    self.log("Brightness at {}: increasing by 25".format(self.new_brightness))
    self.old_brightness = self.new_brightness
    self.new_brightness = self.new_brightness + 25
    self.turn_on(self.args["entity"], brightness = self.new_brightness)
    if self.stoploop == 1 :
      self.noloop(0)
    else:
      self.run_in(self.dimmerloop, .2)

  def maxbrightness(self, kwargs):
    self.old_brightness = self.new_brightness
    self.new_brightness = self.new_brightness - 25
    self.turn_on(self.args["entity"], brightness = self.new_brightness)
    if self.stoploop == 1 :
      self.noloop(0)
    else:
      self.dimmerloop(0)

Allow logging to stdout and stderr

I'm managing AppDaemon via a systemd unit on Debian 8. The easiest way to do this is to actually not use the daemonize option and instead to run in the foreground. Systemd then handles managing the process and its children and also automatically captures stderr and stdout to the system log.

Currently when running in the foreground, log messages go stderr and errors get put into a RotatingFileHandler controlled by the errorfile config setting. It would be very convenient if I could set it to dump regular messages to stdout and errors to stderr, so that I can just let systemd handle organizing the logs; I'm on a RasPi and want to avoid writing to the filesystem (and have systemd configured to save logs in memory), plus it's handy to be able to view the logs with messages and errors colorized properly with systemctl status.

To this end, I have a pull request where I have made a couple small changes. Basically, if you are running in the foreground and you have logfile = STDOUT in the configuration, then standard log messages will go to stdout. Similarly, if you have errorfile = STDERR then errors go to stderr. Finally, if you have both set, then it also suppresses the log messages that mention when an error has been logged (since you're going to see it in the output).

I did this in a way that I think won't break anything. For one, if called with --daemonize these checks are bypassed. Also, the previous behavior is preserved and this only kicks in when passing STDOUT or STDERR.

Let me know if you would prefer that it is implemented differently and I can change it.

Issue with the run_every scheduler

Hello

I was getting an error with the run_every() scheduler, complaining of "TypeError: unsupported operand type(s) for +=: 'int' and 'datetime.timedelta'".

In appdaemon.py, I added .total_seconds() to the following line:

args["basetime"] += args["interval"].total_seconds()

This seemed to have fixed the issue. Just wanted to let you know for the next release. I'm surprised nobody else was getting this error.

HA restart error message

Prior to the latest release, when HA restarted, there was just a little message saying that HA was unreachable. Now it's a full trace.


raceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/appdaemon/appdaemon.py", line 993, in run
    get_ha_state()
  File "/usr/local/lib/python3.4/dist-packages/appdaemon/appdaemon.py", line 905, in get_ha_state
    states = ha.get_ha_state()
  File "/usr/local/lib/python3.4/dist-packages/appdaemon/homeassistant.py", line 164, in get_ha_state
    r = requests.get(apiurl, headers=headers, verify = conf.certpath)
  File "/usr/local/lib/python3.4/dist-packages/requests/api.py", line 70, in get
    return request('get', url, params=params, **kwargs)
  File "/usr/local/lib/python3.4/dist-packages/requests/api.py", line 56, in request
    return session.request(method=method, url=url, **kwargs)
  File "/usr/local/lib/python3.4/dist-packages/requests/sessions.py", line 488, in request
    resp = self.send(prep, **send_kwargs)
  File "/usr/local/lib/python3.4/dist-packages/requests/sessions.py", line 609, in send
    r = adapter.send(request, **kwargs)
  File "/usr/local/lib/python3.4/dist-packages/requests/adapters.py", line 487, in send
    raise ConnectionError(e, request=request)
requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=8123): Max retries exceeded with url: /api/states (Caused by NewConnectionError('<requests.packages.urllib3.connection.HTTPConnection object at 0x70470cd0>: Failed to establish a new connection: [Errno 111] Connection refused',))

2017-01-24 17:26:43.881362 WARNING ------------------------------------------------------------
2017-01-24 17:26:48.896779 WARNING Not connected to Home Assistant, retrying in 5 seconds
2017-01-24 17:26:48.897406 WARNING ------------------------------------------------------------
2017-01-24 17:26:48.905124 WARNING Unexpected error:
2017-01-24 17:26:48.906047 WARNING ------------------------------------------------------------
2017-01-24 17:26:48.908834 WARNING Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/requests/packages/urllib3/connection.py", line 138, in _new_conn
    (self.host, self.port), self.timeout, **extra_kw)
  File "/usr/local/lib/python3.4/dist-packages/requests/packages/urllib3/util/connection.py", line 98, in create_connection
    raise err
  File "/usr/local/lib/python3.4/dist-packages/requests/packages/urllib3/util/connection.py", line 88, in create_connection
    sock.connect(sa)
ConnectionRefusedError: [Errno 111] Connection refused

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/requests/packages/urllib3/connectionpool.py", line 594, in urlopen
    chunked=chunked)
  File "/usr/local/lib/python3.4/dist-packages/requests/packages/urllib3/connectionpool.py", line 361, in _make_request
    conn.request(method, url, **httplib_request_kw)
  File "/usr/lib/python3.4/http/client.py", line 1090, in request
    self._send_request(method, url, body, headers)
  File "/usr/lib/python3.4/http/client.py", line 1128, in _send_request
    self.endheaders(body)
  File "/usr/lib/python3.4/http/client.py", line 1086, in endheaders
    self._send_output(message_body)
  File "/usr/lib/python3.4/http/client.py", line 924, in _send_output
    self.send(msg)
  File "/usr/lib/python3.4/http/client.py", line 859, in send
    self.connect()
  File "/usr/local/lib/python3.4/dist-packages/requests/packages/urllib3/connection.py", line 163, in connect
    conn = self._new_conn()
  File "/usr/local/lib/python3.4/dist-packages/requests/packages/urllib3/connection.py", line 147, in _new_conn
    self, "Failed to establish a new connection: %s" % e)
requests.packages.urllib3.exceptions.NewConnectionError: <requests.packages.urllib3.connection.HTTPConnection object at 0x6f5bbb10>: Failed to establish a new connection: [Errno 111] Connection refused

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/requests/adapters.py", line 423, in send
    timeout=timeout
  File "/usr/local/lib/python3.4/dist-packages/requests/packages/urllib3/connectionpool.py", line 643, in urlopen
    _stacktrace=sys.exc_info()[2])
  File "/usr/local/lib/python3.4/dist-packages/requests/packages/urllib3/util/retry.py", line 363, in increment
    raise MaxRetryError(_pool, url, error or ResponseError(cause))
requests.packages.urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host='localhost', port=8123): Max retries exceeded with url: /api/states (Caused by NewConnectionError('<requests.packages.urllib3.connection.HTTPConnection object at 0x6f5bbb10>: Failed to establish a new connection: [Errno 111] Connection refused',))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/appdaemon/appdaemon.py", line 993, in run
    get_ha_state()
  File "/usr/local/lib/python3.4/dist-packages/appdaemon/appdaemon.py", line 905, in get_ha_state
    states = ha.get_ha_state()
  File "/usr/local/lib/python3.4/dist-packages/appdaemon/homeassistant.py", line 164, in get_ha_state
    r = requests.get(apiurl, headers=headers, verify = conf.certpath)
  File "/usr/local/lib/python3.4/dist-packages/requests/api.py", line 70, in get
    return request('get', url, params=params, **kwargs)
  File "/usr/local/lib/python3.4/dist-packages/requests/api.py", line 56, in request
    return session.request(method=method, url=url, **kwargs)
  File "/usr/local/lib/python3.4/dist-packages/requests/sessions.py", line 488, in request
    resp = self.send(prep, **send_kwargs)
  File "/usr/local/lib/python3.4/dist-packages/requests/sessions.py", line 609, in send
    r = adapter.send(request, **kwargs)
  File "/usr/local/lib/python3.4/dist-packages/requests/adapters.py", line 487, in send
    raise ConnectionError(e, request=request)
requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=8123): Max retries exceeded with url: /api/states (Caused by NewConnectionError('<requests.packages.urllib3.connection.HTTPConnection object at 0x6f5bbb10>: Failed to establish a new connection: [Errno 111] Connection refused',))

2017-01-24 17:26:48.909529 WARNING ------------------------------------------------------------
2

It's just kind of ugly.

run hourly documentation

The run hour documentation says the format is
run_hourly(,time=None,kwargs)

Using that, I got the following error:

TypeError: run_hourly() missing 1 required positional argument: 'start'

Also the example for run_hourly is the example from above for run_daily.

If you will tell me how to edit the document to submit changes, I'll be happy to work on it.

Unable to listen to state of `input_slider`

I have an app that's listening to changes on a config defined input_slider sensor. It initially takes the state, and then listens for changes, but the state changes don't propagate. Other listeners, such as a temp sensor listener, work fine. Is this perhaps an event that is missing or might I have missed something?

Here's a simplified version of the code

class FermentationController(appapi.AppDaemon):
    def initialize(self):
        self.log("Initializing fermenter")
        self.log("Temp Sensor: {}".format(self.args["temp_sensor"]))
        self.log("Target Temp Sensor: {}".format(self.args["target_temp_sensor"]))
        self.log("Cool Switch: {}".format(self.args["cool_switch"]))
        self.target_temp = float(self.get_state(self.args["target_temp_sensor"]))
        self.log("Target temperature is {}".format(self.target_temp))
        self.listen_state(self.target_temp_did_change, self.args["target_temp_sensor"])
        self.log("Initialized fermenter")

    def target_temp_did_change(self, entity, attribute, old, new, kwargs):
        self.log("Received new target temp {}".format(new))
        self.target_temp = float(new)

Now when I change the input slider via the frontend, I see the event pushed in the hass logs

homeassistant_1              | 17-03-10 12:35:38 INFO (MainThread) [homeassistant.core] Bus:Handling <Event call_service[L]: service_call_id=139703905603712-45, service_data=value=24, entity_id=input_slider.brew_1_target_temp, service=select_value, domain=input_slider>
homeassistant_1              | 17-03-10 12:35:38 INFO (MainThread) [homeassistant.core] Bus:Handling <Event state_changed[L]: old_state=<state input_slider.brew_1_target_temp=23.0; min=4.0, friendly_name=Target Temp, max=28.0, step=1.0 @ 2017-03-10T12:35:09.214463+13:00>, entity_id=input_slider.brew_1_target_temp, new_state=<state input_slider.brew_1_target_temp=24.0; min=4.0, friendly_name=Target Temp, max=28.0, step=1.0 @ 2017-03-10T12:35:38.247162+13:00>>

But nothing happens in the appdaemon logs, here's the log from the start of initialization

hass-apps_1                  | 2017-03-10 12:34:47.005736 INFO Loading Object ferment using class FermentationController from module ferment
hass-apps_1                  | 2017-03-10 12:34:47.008847 INFO ferment: Initializing fermenter
hass-apps_1                  | 2017-03-10 12:34:47.011593 INFO ferment: Temp Sensor: sensor.temperature_sensor_2
hass-apps_1                  | 2017-03-10 12:34:47.014214 INFO ferment: Target Temp Sensor: input_slider.brew_1_target_temp
hass-apps_1                  | 2017-03-10 12:34:47.015647 INFO ferment: Cool Switch: switch.orvibo_s20_1
hass-apps_1                  | 2017-03-10 12:34:48.146091 INFO ferment: Target temperature is 23.0
hass-apps_1                  | 2017-03-10 12:34:48.148166 INFO ferment: Initialized fermenter
hass-apps_1                  | 2017-03-10 12:40:37.001935 INFO /conf/appdaemon.cfg modified

Note the timing of the logs, that last 'modified' line there occurred when I arbitrarily saved the appdaemon config just to get it to log to show it never called the self.target_temp_did_change method.

HADashboard V2 Request: input_select

I want to make a dashboard for my kid's room, and part of that is picking from a specific list of playlists from an input_select and running a script that starts the playlist playing on a music player in the room. I've got all that working right now in HA, but there's no input_select widget for HA Dashboard V2.

Is the input_select widget on the roadmap?

Redundant configuration entries

Maybe I am missing something obvious but what is the reason of creating these redundant entries in the configuration file:

latitude = <latitude>
longitude = <longitude>
elevation = <elevation
timezone = <timezone>

Shouldn't the appdeamon know them from HA?

P.S. Not sure if raising an issue is the right way to address such question...

timezone vs time_zone

Home assistant uses "time_zone" in it's configuration file. Current AppDaemon uses "timezone". It would probably be nice for AppDaemon to be consistent with Home Assistant's syntax.

Optional arguments for weather widget

I wonder if you could add the function to define entities for the weather widget.

Like optional arguments for all the entities. and if nothing is defined it will got to default aka. Dark sky.

Im asking because i have my own weather station that i collect data from :) (and also dark sky sucks anywhere else but US and UK)

extend set_state to allow icons

As I was coding for my new app, I found it useful to place a customized icon. "mdi:home" is recognized as a material design icon and should be sourced correctly. I am assuming it is not passing correctly into arg for the POST request in appapi.py.

        # expose this information to the front end, including the full object
        self.set_state('binary_sensor.{}_presence'.format(self.users[mac]['friendly_name'].lower()),
                       state=self.users[mac]['location'],
                       icon="mdi:home",)
                       #attributes=json.dumps({mac: self.users[mac]}))

I currently do something similar with Tasker on my phone. HTTP POST to http://%EXTERNAL_IP:8123/api/states/sensor.supahnoob_phone_battery?%API_PASSWORD with data below. %Battery_Icon is always a material design icon.

{"state":"%BATT", "attributes": {"friendly_name": "Phone Battery", "icon":"%Battery_Icon","unit_of_measurement":"%"}}
  • NC

ed//
I'm dumb, this is essentially a duplicate of issue #37 where attributes don't get passed correctly.

Enhance reload mechanism to support dependencies between files

The automatic reload mechanism in appdaemon in cool, but doesn't support one of the most compelling use cases for appdaemon vs HAs built in automations: code reuse.

For example: I have a utils.py file that contains some utility functions that are used across several of my apps, like so:

-- utils.py --

class BaseApp(appapi.AppDaemon):
    def do_a_thing(self):
        self.foo()

-- lights.py --

from utils import BaseApp

class FunLights(BaseApp):

    def on_lights_on(self, kwargs):
        self.do_a_thing()

At the moment, if I change lights.py, everything is reloaded as expected (good) but if I change utils.py appdaemon doesn't recognize that it needs to reload lights.py as well (bad)

It would be really awesome if appdaemon would recognize (automatically? specially formed docstring?) that if utils.py changes, it also needs to reload lights.py

Thanks

please change get_app as follows

def get_app(self, name):
return conf.objects[name]["object"] if name in conf.objects else None

This way it won't blow if it's called and the app doesn't exist.

Coding standards and PEP8

Hi,

I've been reading through the source code of AppDaemon. To be honest it's really hard to read. I don't know if there are any plans to make the code PEP8 compliant in the future but I've been thinking about formatting the code myself and submitting a PR. So if the author has nothing against it I can do it. So please let me know in the comment.

logger throwing AttributeErrors

A simple call to the logger seems to be throwing errors.

self.log('Killing tshark...')

2017-01-29 23:36:41.116127 WARNING Unexpected error during loading of find_lf.py:
2017-01-29 23:36:41.116698 WARNING ------------------------------------------------------------
2017-01-29 23:36:41.117736 WARNING Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/appdaemon/appdaemon.py", line 704, in readApp
    term_file(file)
  File "/usr/local/lib/python3.4/dist-packages/appdaemon/appdaemon.py", line 481, in term_file
    term_object(key)
  File "/usr/local/lib/python3.4/dist-packages/appdaemon/appdaemon.py", line 506, in term_object
    conf.objects[name]["object"].terminate()
  File "/home/homeassistant/.homeassistant/appdaemon/conf/apps/find_lf.py", line 44, in terminate
    self.stop(event_name=None, data=None, kwargs=None)
  File "/home/homeassistant/.homeassistant/appdaemon/conf/apps/find_lf.py", line 161, in stop
    self.log('Killing tshark...')
  File "/usr/local/lib/python3.4/dist-packages/appdaemon/appapi.py", line 57, in log
    msg = self._sub_stack(msg)
  File "/usr/local/lib/python3.4/dist-packages/appdaemon/appapi.py", line 40, in _sub_stack
    msg = msg.replace("__module__", stack[2].filename)
AttributeError: 'tuple' object has no attribute 'filename'

2017-01-29 23:36:41.118262 WARNING ------------------------------------------------------------

It looks like something is wrong with _sub_stack in appapi.

Error generated when multiple state changes after listen_event trigger

self.listen_state(self.everyone_left, "group.all_devices", constrain_start_time = "sunset - 00:05:00", constrain_end_time = "23:30:00", new = "not_home", duration = 600)
With the above event triggered, if the state changes from not_home to home within the duration, I get the following error in the error log and the expiry of the duration. Nothing bad happens, just a log message at seeming random time.

Edit:
I ought to point out that the time was outside the contraint times.

`
2017-02-16 12:04:40.007071 WARNING ------------------------------------------------------------
2017-02-16 12:04:40.016404 WARNING Unexpected error during exec_schedule() for App: security_lights
2017-02-16 12:04:40.017650 WARNING Args: {'repeat': False, 'kwargs': {'old_state': 'not_home', 'handle': UUID('9fcb6a6f-966c-4ea7-b3a1-cd41c22b115a'), 'duration': 600, 'new_state': 'home', 'attribute': 'state', 'constrain_end_time': '23:30:00', 'constrain_start_time': 'sunset - 00:05:00', 'new': 'home', 'entity': 'group.all_devices'}, 'name': 'security_lights', 'id': UUID('6cbb2e68-7ec8-4914-a712-684ae4d5e8e9'), 'basetime': 1487246680, 'offset': 0, 'interval': 0, 'callback': <bound method SecurityLights.someone_home of <security_lights.SecurityLights object at 0x7f3cd0390240>>, 'type': None, 'timestamp': 1487246680}
2017-02-16 12:04:40.018044 WARNING ------------------------------------------------------------
2017-02-16 12:04:40.020499 WARNING Traceback (most recent call last):
File "/home/graham/lib/python3.5/site-packages/appdaemon/appdaemon.py", line 395, in exec_schedule
"kwargs": args["kwargs"],
File "/home/graham/lib/python3.5/site-packages/appdaemon/appdaemon.py", line 331, in dispatch_worker
for arg in config[name].keys():
File "/usr/lib/python3.5/configparser.py", line 956, in getitem
raise KeyError(key)
KeyError: 'security_lights'

2017-02-16 12:04:40.020948 WARNING ------------------------------------------------------------
2017-02-16 12:04:40.021720 WARNING Scheduler entry has been deleted
2017-02-16 12:04:40.022591 WARNING ------------------------------------------------------------

`

terminate() is not running

I'm on AppDaemon 1.5.2 ... I'm unsure of how to help debugging this one.

class Camera(appapi.AppDaemon):

    def initialize(self):
        #self.utils = self.get_app('utils')

        if self.args['node'] == 'server':
            self.log('Starting server...')
            self.start_server()

        self.log('Initializing app...')

    def terminate(self):
        self.log('Terminating..')
        self.stop_server()

    def start_server(self):
        """
        For the life of this app turn our cfg content above into a file, for 
        purposes of standing up `ffserver` 

        Less scattered files == More user-control
        """
        self.config = NamedTemporaryFile()
        #_config_path = config.name
        self.config.write(SERVER_CONFIG.encode())
        self.config.flush()

        self.server = subprocess.Popen(
                [ # popen args!
                    'ffserver',
                    '-hide_banner',
                    '-f', self.config.name
                ], stderr=subprocess.PIPE
            )

    def stop_server(self):
        self.log('Error: {}'.format(self.server.stderr.read()))
        self.server.kill()
        self.config.close()
        self.log('Killed..')

Nothing serious going on in the app thus far ... terminate() just never gets called. My log files don't show teardown of any app, now that I'm looking through it.

I uninstalled/installed the AppDaemon package and it didn't change a thing -- not that it should have, but I thought I might had changed the program a bit~

  • SN

RSS widget is not working

Greetings,

I'm using v2 and trying to add RSS widget to my dashboard.
Even if everything is configured using examples, RSS is not displaying.
AppDaemon config

AppDaemon:
  cert_verify: False
  logfile: STDOUT
  errorfile: STDERR
  threads: 10
  app_dir: /config/hadaemon/apps
  rss_feeds: 
    - feed: http://rss.cnn.com/rss/cnn_topstories.rss
      target: cnn
  rss_update: 600

And in dashboard I have

rss_cnn: 
  widget_type: rss
  title: CNN
  entity: cnn
  interval: 5

I couldn't find anything related to RSS in logs.

'str' object has no attribute 'get' while parsing config

pi@raspberrypi_wozi:~/appdaemon $ appdaemon -D DEBUG -c conf
Traceback (most recent call last):
  File "/usr/local/bin/appdaemon", line 11, in <module>
    load_entry_point('appdaemon==2.0.0b4', 'console_scripts', 'appdaemon')()
  File "/usr/local/lib/python3.4/dist-packages/appdaemon/appdaemon.py", line 1553, in main
    conf.logfile = config['AppDaemon'].get("logfile")
AttributeError: 'str' object has no attribute 'get'

What can I do about this? Is this an issue with python versions?

Disconnections with SSL and a self-signed certificate

I'm using a self-signed certificate for HASS. After upgrading appdaemon to the newest version, I am able to connect, but being disconnected every 10 seconds. I am running AppDaemon in its own virtualenv. I do see state updates come through, but am questioning if I should be getting disconnected.

(appdaemon) homeassistant@RPi3-HA:/home/pi $ appdaemon -D DEBUG --commtype "SSE" --config /home/homeassistant/.homeassistant/appdaemon.cfg
2017-02-08 12:02:08.709546 INFO AppDaemon Version 1.5.2 starting
2017-02-08 12:02:08.710027 DEBUG get_ha_config()
2017-02-08 12:02:13.877247 DEBUG Entering run()
2017-02-08 12:02:13.925405 DEBUG Creating worker threads ...
2017-02-08 12:02:13.928810 DEBUG Done
2017-02-08 12:02:13.929257 DEBUG Calling HA for initial state
2017-02-08 12:02:13.929567 DEBUG Refreshing HA state
2017-02-08 12:02:13.929833 DEBUG get_ha_state: entity is None
2017-02-08 12:02:19.029655 INFO Got initial state
2017-02-08 12:02:19.030529 DEBUG Reading Apps
2017-02-08 12:02:19.034507 INFO Loading Module: /home/homeassistant/.homeassistant/apps/input_selector.py
2017-02-08 12:02:19.037770 INFO Loading Module: /home/homeassistant/.homeassistant/apps/channel_changer.py
2017-02-08 12:02:19.040684 INFO Loading Module: /home/homeassistant/.homeassistant/apps/hyperion_effect_selector.py
2017-02-08 12:02:19.159517 INFO Loading Module: /home/homeassistant/.homeassistant/apps/hello.py
2017-02-08 12:02:19.161068 INFO Loading Module: /home/homeassistant/.homeassistant/apps/scene_selector.py
2017-02-08 12:02:19.162586 INFO App initialization complete
2017-02-08 12:02:19.163008 DEBUG Starting timer thread
2017-02-08 12:02:19.164062 INFO Using SSE
2017-02-08 12:02:19.224524 INFO Connected to Home Assistant with timeout = 10
2017-02-08 12:02:29.238052 WARNING Disconnected from Home Assistant, retrying in 5 seconds
2017-02-08 12:02:29.238887 WARNING ------------------------------------------------------------
2017-02-08 12:02:29.239583 WARNING Unexpected error:
2017-02-08 12:02:29.240272 WARNING ------------------------------------------------------------
2017-02-08 12:02:29.259646 WARNING Traceback (most recent call last):
  File "/srv/appdaemon/lib/python3.4/site-packages/requests/packages/urllib3/contrib/pyopenssl.py", line 277, in recv_into
    return self.connection.recv_into(*args, **kwargs)
  File "/srv/appdaemon/lib/python3.4/site-packages/OpenSSL/SSL.py", line 1335, in recv_into
    self._raise_ssl_error(self._ssl, result)
  File "/srv/appdaemon/lib/python3.4/site-packages/OpenSSL/SSL.py", line 1149, in _raise_ssl_error
    raise WantReadError()
OpenSSL.SSL.WantReadError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/srv/appdaemon/lib/python3.4/site-packages/requests/packages/urllib3/response.py", line 298, in _error_catcher
    yield
  File "/srv/appdaemon/lib/python3.4/site-packages/requests/packages/urllib3/response.py", line 380, in read
    data = self._fp.read(amt)
  File "/usr/lib/python3.4/http/client.py", line 500, in read
    return super(HTTPResponse, self).read(amt)
  File "/usr/lib/python3.4/http/client.py", line 529, in readinto
    return self._readinto_chunked(b)
  File "/usr/lib/python3.4/http/client.py", line 614, in _readinto_chunked
    chunk_left = self._read_next_chunk_size()
  File "/usr/lib/python3.4/http/client.py", line 552, in _read_next_chunk_size
    line = self.fp.readline(_MAXLINE + 1)
  File "/usr/lib/python3.4/socket.py", line 371, in readinto
    return self._sock.recv_into(b)
  File "/srv/appdaemon/lib/python3.4/site-packages/requests/packages/urllib3/contrib/pyopenssl.py", line 291, in recv_into
    raise timeout('The read operation timed out')
socket.timeout: The read operation timed out

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/srv/appdaemon/lib/python3.4/site-packages/appdaemon/appdaemon.py", line 1348, in run
    for msg in messages:
  File "/srv/appdaemon/lib/python3.4/site-packages/sseclient.py", line 64, in __next__
    nextline = self.resp_file.readline()
  File "/srv/appdaemon/lib/python3.4/site-packages/requests/packages/urllib3/response.py", line 397, in read
    raise IncompleteRead(self._fp_bytes_read, self.length_remaining)
  File "/usr/lib/python3.4/contextlib.py", line 77, in __exit__
    self.gen.throw(type, value, traceback)
  File "/srv/appdaemon/lib/python3.4/site-packages/requests/packages/urllib3/response.py", line 303, in _error_catcher
    raise ReadTimeoutError(self._pool, None, 'Read timed out.')
requests.packages.urllib3.exceptions.ReadTimeoutError: HTTPSConnectionPool(host='192.168.1.100', port=8123): Read timed out.

2017-02-08 12:02:29.260608 WARNING ------------------------------------------------------------

Suggestion: more pythonic/object-oriented high-level API

Hi, I have been doing some preliminary testing to get a feel how to work with appdaemon, and got curious whether it would be ok to provide a nicer API for common component types?

So instead of having this:

for light in self.get_entity("group.ceiling_lights")["attributes"]["entity_id"]:
    self.toggle(light)

one could write:

for light in self.get_group("ceiling_lights"):
    light.toggle()

It'd also be nice to access the common properties directly, for example in case of lights of all what Light class of homeassistant provides. I haven't yet dug into what kind of data homeassistant gives out through the API, e.g. do we get enumeration of supported operations & properties, which would make pulling this off even simpler, but assuming this sort of development would be accepted I might spend some time on it to make it happen. Any thoughts?

Add module and line number to log messages

This would be helpful in tracking down issues. (at least for me)

In appapi

At the top
import inspect
change log as follows


  def log(self, msg, level = "INFO"):
   msg=str(inspect.stack()[1][3]) + " (" + str(inspect.stack()[1][2])+") - " + msg
   ha.log(self._logger, level,msg, self.name)

output looks like this now

2017-01-23 14:56:00.921066 INFO bigdata: restart_Big_Data (44) - In restart_Big_Data
2017-01-23 14:56:00.941680 INFO bigdata: start_Big_Data (34) - called listen_state
2017-01-23 14:56:00.951857 INFO bigdata: start_Big_Data (36) - called listen_event
2017-01-23 14:56:01.066585 INFO calalarm: schedulealarm (111) - In schedulealarm - master
2017-01-23 14:56:01.077012 INFO calalarm: schedulealarm (113) - room=master, owner=['chip', 'susan']
2017-01-23 14:56:01.097669 INFO calalarm: schedulealarm (116) - owner=chip, room=master, meeting=wakeup
2017-01-23 14:56:01.128598 INFO bigdata: event_happened (39) - event=SPEAK_EVENT
2017-01-23 14:56:01.132161 INFO speak: handle_speak_event (45) - handling speak event SPEAK_EVENT text=ahlexa, Turn off stairway light switch language=en  priority=1
2017-01-23 14:56:01.139090 INFO calalarm: addalarm (68) - adding alarm
2017-01-23 14:56:01.149303 INFO calalarm: addalarm (71) - existing timer 2017-01-24 05:30:00, interval 0, kwargs={}
2017-01-23 14:56:01.158923 INFO calalarm: addalarm (76) - Duplicate alarm
2017-01-23 14:56:01.167875 INFO calalarm: schedulealarm (119) - alarm scheduled for 2017-01-24 05:30:00
2017-01-23 14:56:01.180028 INFO calalarm: schedulealarm (116) - owner=susan, room=master, meeting=

call_service example in API.md has an error

The example

self.call_service("light.turn_on", entity_id = "light/office_lamp", color_name = "red")

should be

self.call_service("light/turn_on", entity_id = "light.office_lamp", color_name = "red")

Connecting with SSL enabled

When I set HA and AppDaemon to use http everything works just fine. When I change over to using SSL AppDaemon is unable to connect to HA. I am using a self signed certificate with HA, is this a problem?

Moving docs to home-assistant.io

Hi @acockburn,

We are about to add a new section to home-assistant.io titled "Ecosystem". It's a place where any external tools can share their documentation in an official and easy to reference capacity. I think that appdaemon would be a great fit. The PR to add this section should be merged tonight or tomorrow and docs can start being written shortly thereafter. I don't think you would need to do anything more than taking the existing README.md and splitting it up into pages for easy linking.

Obviously you don't have to do this but we thought we'd let you know.

We could also potentially take this opportunity to move appdaemon into the home-assistant organization if you wanted.

The PR that needs to be merged is here.

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.