Algo Timer

Someone on reddit was looking for a way to turn off a switch (or some device) automatically after a set amount of time. They wanted the set amount of time to be the average amount of the times the switch had been on in the past. What a great use case for AppDaemon!

Algo Timer:
  module: algo_timer
  class: SmartTimer
  db_location: /opt/homeassistant/home-assistant_v2.db #your database
  entity_id: switch.bathroom_light_switch #your entity
  debug: False #additional logging

How would you make this better? What would you do differently?

i would only recalculate every night with a run_daily.
the small change wouldnt make a lot off difference but it would make quite a performance difference (for sure if the db gets big)
i would also set a preset for the average, so that when the DB is gone or damaged, the function wont stop working
i would also save the data that is collecting in another table or db.
the HA db tends to get quite big, and or people use a purge for it.

i also want to use data to predict actions in the near future. i am collecting data for it right now.

Thanks for the input!

I think the nightly calculation is a good idea, I hadnā€™t thought of that. Depending on oneā€™s use case the per-change calculation might need to stick.

For what reason would you want to save the data in another table/db?

Iā€™m looking forward to seeing what your project looks like.

with using the HA db:

  • all sensors, switches, actions, events, changes are in 1 table
  • a query on that can take quite some time
  • the db gets big, so people tend to purge them after a few days
  • more then once i have experienced that the db got damaged, so all usefull data is lost.
  • you cant easy decide how and what data you want to save and what not.

with seperate db for data collection:

  • a specific table contains only the data you want.
  • a query on that will always have maximum speed
  • no purging for data from sensors, events you dont want to purge.
  • if the data gets corrupted, just a small amount of data is lost.
  • you can decide what data you want to save and how

the first part of my project will be motion prediction based on the past.
i will calculate at night on what time (probably splitt up in minutes or a block from a few minutes) how often motion is normal
then i will compare the motions that are detected with ā€œnormalā€ motion
and i will let AD tell if there is an unusual amount of motion for that certain time.
from that i will create a db that explains what kind of motion it is and after that ill let AD tell which kind of motion it did detect.
if thats acurate enough, i will create actions based on the expected motion.

That user was me :slight_smile: I had actually already started writing something like this when I posted to reddit and followed many of these suggestions, including the separate DB and the ā€˜defaultā€™ interval. I did kinda waiver on using a separate DB though, mostly because using the HASS DB allows us to use events that occured even when the app was not in use in the algorithm calculations.

@aneisch You beat me to the punch with the meat of the code, but there were a couple of bugs i found. For instance, most SQL engines do not guarantee the order of the results unless you tell it to order them and your sql statement did not order the results. Paired with the manner that you were processing rows, this could result in two unrelated records being used as the beginning and ending of any particular period of time. Iā€™ve replied to your post on reddit as iā€™m having trouble getting appdaemon to run properly apparently. Check it out when you can plz :slight_smile:

PS When i get my version working i plan on submitting a PR to your repo

if you use appdaemn for your automations you never want that to happen.
and i must say that with normal use i find AD more reliable then HA, when it gets buggy its never AD and always HA.

the sideeffect that you get:
when the DB is big (and it will get big if you dont purge) queries are gonna hold up your automations, HA is slowing down because you query the DB (and that will happen in any case, more or less) and the more data you have collected, the more you will risk your working environment.

Oh that will eventually be a problem with any database for sure, and even more so just because weā€™re talking about SQLite. I have a sort of middle-ground solution in mind and if i can get appdaemon to cooperate iā€™ll publish it.

a DB should be created for a purpose.
the HA DB is badly created to collect data for a longer time and to make ies on that dont cause trouble.
if you create a db specific for this cause you just want small tables for each device instead of 1 big table with all devices.
the devices dont have anything in common anyway, and if you want to collect overal info on several devices you can always combine the data.

so yeah you are right that it will be a problem with any DB in the long run, but with the HA db it will be after a few days/weeks, and with a seperate table it will be after a few years.
and with the HA db you will disrupt your home automation, and with a small dedicated table you wont disrupt anything, it will only get a bit slower.

@smokes2345, replied on reddit, but letā€™s bring it here.

It looks like you have the algo_switch.py in the apps directory, and you have:

  module: algo_timer
  class: SmartTimer
  db_location: /opt/homeassistant/home-assistant_v2.db #your database location here
  entity_id: switch.bathroom_light_switch #your entity here
  debug: False

in an apps.yaml? It looks to me like appdaemon isnā€™t seeing that you have the app configured in apps.yaml. I have the same behavior when I comment out the above lines.

I have the same behavior when I comment out the above lines.

Thatā€™s the expected behavior though. Forgive me if i missed something, but i donā€™t see how thatā€™s helpful. Otherwise, yes that is exactly the problem.

As in, when I comment the lines defining apps instance I have the same behavior you describe. Which makes me believe appdaemon isnā€™t seeing that youā€™ve defined an instance of this app. Do you have any other app instances configured in your apps.yaml?

No, at this time this is the only object in apps.yaml

whats the exact problem, maybe i could help.

I have apps in apps.yaml, exactly one. The module/class (the topic of this thread, SmartTimer) is supposed to log when itā€™s initialize function is called, but I never see those log entries. Appdaemon does recognize my apps folder as it calls out the modules i have in there (more than one), but it does not log the item from the initialize function of the ā€˜SmartTimerā€™ class thus i suspect the initialize method is not being invoked which means the automation never actually happens.

please post the complete log from the moment you startup appdaemon (incl. version)
how do you start AD?
in which dir is your apps.yaml?
and in which dir are your apps?
and for completeness, what is in your appdaemon.yaml and in your apps.yaml?

if you provide this, i m sure we can figure the problem out fast.

how do you start AD?

[Unit]
Description=AppDaemon
[email protected]
[Service]
Type=simple
User=hass
ExecStart=/bin/sh -c "/srv/hass/bin/appdaemon -c /home/hass/.homeassistant/ --debug DEBUG | /usr/bin/tee /var/log/appdaemon/appdaemon.log"
[Install]
WantedBy=multi-user.target

in which dir is your apps.yaml?

/home/hass/.homeassistant/

and in which dir are your apps?

/home/hass/.homeassistant/apps/

and for completeness, what is in your appdaemon.yaml

AppDaemon:
  #logfile: /var/log/appdaemon/appdaemon.log
  #errorfile: /var/log/appdaemon/appdaemon.err
  logfile: STDOUT
  errorfile: STDERR
  logsize: 100000
  log_generations: 3
  threads: 10
  disable_apps: 0
  app_dir: /home/hass/.homeassistant/apps
  #cert_path: <path/to/root/CA/cert>
  #cert_verify: True
  #time_zone: <time zone>
  api_port: 5000
  api_key: !secret api_key
  #api_ssl_certificate: <path/to/root/CA/cert>
  #api_ssl_key: <path/to/root/CA/key>
HASS:
  ha_url: http://localhost:8123
  #  ha_key: <some key>

and in your apps.yaml?

adaptive_timer:
  module: algo_timer
  class: SmartTimer
  db_location: /home/hass/.home-assistant/home-assistant_v2.db #your database location here
  entity_id: switch.closet_light_switch #your entity here
  debug: True

please set the logs to files instead off STDOUT and STDERR
and then restart appdaemon and show what is in the logs.

If you look at my serviced service unit, both stdout and stderr are being sent to a file. I restarted appdaemon to capture the startup messages fresh. Hereā€™s the result:

2018-01-29 02:34:51.339020 INFO AppDaemon Version 2.1.12 starting
2018-01-29 02:34:51.339590 INFO Configuration read from: /home/hass/.homeassistant/appdaemon.yaml
2018-01-29 02:34:51.340022 DEBUG AppDaemon Section: {'api_key': 'xxxxxxxx', 'api_port': 5000, 'disable_apps': 0, 'threads': 10, 'logfile': 'STDOUT', 'logsize': 100000, 'errorfile': 'STDERR', 'app_dir': '/home/hass/.homeassistant/apps', 'log_generations': 3}
2018-01-29 02:34:51.340403 DEBUG Hass Section: {'ha_url': 'http://localhost:8123'}
2018-01-29 02:34:51.340710 DEBUG HADashboard Section: None
2018-01-29 02:34:51.341000 DEBUG Calling HA for config with key:  and url: http://localhost:8123
2018-01-29 02:34:51.341339 DEBUG get_ha_config()
2018-01-29 02:34:51.341719 DEBUG get_ha_config: url is http://localhost:8123/api/config
2018-01-29 02:34:51.371565 DEBUG Success
2018-01-29 02:34:51.372099 DEBUG {'latitude': 32.551841, 'whitelist_external_dirs': ['/home/hass/.homeassistant/www'], 'elevation': 243, 'longitude': -84.817888, 'components': ['group', 'config.script', 'sensor', 'zwave', 'media_player', 'media_player.pandora', 'zone', 'config.group', 'config.core', 'media_player.vlc', 'sensor.yr', 'alarm_control_panel.alarmdotcom', 'sensor.speedtest', 'lock.zwave', 'switch', 'media_player.cast', 'sensor.dnsip', 'device_tracker', 'conversation', 'alarm_control_panel', 'http', 'vacuum.roomba', 'logbook', 'person', 'config', 'updater', 'websocket_api', 'sensor.zwave', 'config.customize', 'sensor.template', 'automation', 'ffmpeg', 'map', 'tts', 'mqtt', 'config.automation', 'frontend', 'media_player.plex', 'sensor.plex', 'switch.zwave', 'config.zwave', 'api', 'notify', 'vacuum', 'history', 'recorder', 'logger', 'discovery', 'lock', 'sun', 'system_log', 'media_player.roku'], 'config_dir': '/home/hass/.homeassistant', 'version': '0.62.0', 'unit_system': {'volume': 'gal', 'temperature': 'Ā°F', 'mass': 'lb', 'length': 'mi'}, 'time_zone': 'America/New_York', 'location_name': 'Home'}
2018-01-28 21:34:51.480042 INFO Starting Apps
2018-01-28 21:34:51.480698 DEBUG Entering run()
2018-01-28 21:34:51.552072 DEBUG Creating worker threads ...
2018-01-28 21:34:51.556254 DEBUG Done
2018-01-28 21:34:51.556733 DEBUG Calling HA for initial state with key:  and url: http://localhost:8123
2018-01-28 21:34:51.557108 DEBUG Refreshing HA state
2018-01-28 21:34:51.557472 DEBUG get_ha_state: url is http://localhost:8123/api/states
2018-01-28 21:34:51.589327 INFO Got initial state
2018-01-28 21:34:51.590108 DEBUG Reading Apps
2018-01-28 21:34:51.591241 INFO Loading Module: /home/hass/.homeassistant/apps/adaptive_switches.py
2018-01-28 21:34:51.601588 INFO Loading Module: /home/hass/.homeassistant/apps/algo_switch.py
2018-01-28 21:34:51.603476 INFO App initialization complete
2018-01-28 21:34:51.603942 DEBUG Starting timer loop
2018-01-28 21:34:51.604668 INFO Dashboards are disabled
2018-01-28 21:34:51.605118 INFO Starting API
2018-01-28 21:34:51.608062 DEBUG Start Loop
2018-01-28 21:34:51.620910 INFO Connected to Home Assistant 0.62.0
2018-01-28 21:34:52.013409 DEBUG Main loop compute time: 11.0ms
2018-01-28 21:34:53.013378 DEBUG Main loop compute time: 10.0ms
2018-01-28 21:34:54.010364 DEBUG Main loop compute time: 8.0ms
2018-01-28 21:34:55.013580 DEBUG Main loop compute time: 10.0ms

As you can see, it recognizes the modules in the apps folder, but nowhere in there do you see the output from the ā€˜initializeā€™ method.

nope and i cant.

in your apps.yaml there is only 1 app instance and it calls the module algo_timer
in your app_dir there are 2 files > algo_switch.py and and adaptive_switches.py

the module algo_timer is not there so it cant be loaded.

you need to change the module name in the apps.yaml or the name of the py file.

well i feel like an idiot. So now I see

2018-01-29 09:15:39.282581 INFO Loading Object adaptive_timer using class SmartTimer from module algo_switch

After this change it still wasnā€™t working, so I checked the apps.yaml. Turns out the database location was wrong. So basically this was all just typos on my part, SORRY! And thanks a bunch for the assist. Now that I know i have a working base I have some changes planned and will likely be submitting a PR soon.

1 Like