Site updated at 2018-01-28 22:02:31 UTC
This commit is contained in:
parent
57a21e9eb0
commit
01b474f87c
268 changed files with 412 additions and 412 deletions
|
@ -83,11 +83,11 @@
|
|||
<span class="k">class</span> <span class="nc">MotionLights</span><span class="p">(</span><span class="n">appapi</span><span class="o">.</span><span class="n">AppDaemon</span><span class="p">):</span>
|
||||
</code></pre>
|
||||
</div>
|
||||
<p>When configured as an app in the config file (more on that later) the lifecycle of the App begins. It will be instantiated as an object by AppDaemon, and immediately, it will have a call made to it’s <code class="highlighter-rouge">initialize()</code> function - this function must appear as part of every app:</p>
|
||||
<p>When configured as an app in the config file (more on that later) the lifecycle of the App begins. It will be instantiated as an object by AppDaemon, and immediately, it will have a call made to its <code class="highlighter-rouge">initialize()</code> function - this function must appear as part of every app:</p>
|
||||
<div class="language-python highlighter-rouge"><pre class="highlight"><code> <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
</code></pre>
|
||||
</div>
|
||||
<p>The initialize function allows the app to register any callbacks it might need for responding to state changes, and also any setup activities. When the <code class="highlighter-rouge">initialize()</code> function returns, the App will be dormant until any of it’s callbacks are activated.</p>
|
||||
<p>The initialize function allows the app to register any callbacks it might need for responding to state changes, and also any setup activities. When the <code class="highlighter-rouge">initialize()</code> function returns, the App will be dormant until any of its callbacks are activated.</p>
|
||||
<p>There are several circumstances under which <code class="highlighter-rouge">initialize()</code> might be called:</p>
|
||||
<ul>
|
||||
<li>Initial start of AppDaemon</li>
|
||||
|
@ -140,7 +140,7 @@
|
|||
</code></pre>
|
||||
</div>
|
||||
<p>When AppDaemon sees the following configuration it will expect to find a class called <code class="highlighter-rouge">NewApp</code> defined in a module called <code class="highlighter-rouge">new.py</code> in the apps subdirectory. Apps can be placed at the root of the Apps directory or within a subdirectory, an arbitrary depth down - wherever the App is, as long as it is in some subdirectory of the Apps dir, or in the Apps dir itself, AppDaemon will find it. There is no need to include information about the path, just the name of the file itself (without the <code class="highlighter-rouge">.py</code>) is sufficient. If names in the subdirectories overlap, AppDir will pick one of them but the exact choice it will make is undefined.</p>
|
||||
<p>When starting the system for the first time or when reloading an App or Module, the system will log the fact in it’s main log. It is often the case that there is a problem with the class, maybe a syntax error or some other problem. If that is the case, details will be output to the error log allowing the user to remedy the problem and reload.</p>
|
||||
<p>When starting the system for the first time or when reloading an App or Module, the system will log the fact in its main log. It is often the case that there is a problem with the class, maybe a syntax error or some other problem. If that is the case, details will be output to the error log allowing the user to remedy the problem and reload.</p>
|
||||
<h2><a class="title-link" name="steps-to-writing-an-app" href="#steps-to-writing-an-app"></a> Steps to writing an App</h2>
|
||||
<ol>
|
||||
<li>Create the code in a new or shared module by deriving a class from AppDaemon, add required callbacks and code</li>
|
||||
|
@ -186,7 +186,7 @@
|
|||
<h2><a class="title-link" name="callback-constraints" href="#callback-constraints"></a> Callback Constraints</h2>
|
||||
<p>Callback constraints are a feature of AppDaemon that removes the need for repetition of some common coding checks. Many Apps will wish to process their callbacks only when certain conditions are met, e.g. someone is home, and it’s after sunset. These kinds of conditions crop up a lot, and use of callback constraints can significantly simplify the logic required within callbacks.</p>
|
||||
<p>Put simply, callback constraints are one or more conditions on callback execution that can be applied to an individual App. An App’s callbacks will only be executed if all of the constraints are met. If a constraint is absent it will not be checked for.</p>
|
||||
<p>For example, the presence callback constraint can be added to an App by adding a parameter to it’s configuration like this:</p>
|
||||
<p>For example, the presence callback constraint can be added to an App by adding a parameter to its configuration like this:</p>
|
||||
<div class="language-ini highlighter-rouge"><pre class="highlight"><code><span class="nn">[some_app]</span>
|
||||
<span class="py">module</span> <span class="p">=</span> <span class="s">some_module</span>
|
||||
<span class="py">class</span> <span class="p">=</span> <span class="s">SomeClass</span>
|
||||
|
@ -476,7 +476,7 @@
|
|||
</code></pre>
|
||||
</div>
|
||||
<h3><a class="title-link" name="info_listen_state" href="#info_listen_state"></a> info_listen_state()</h3>
|
||||
<p>Get information on state a callback from it’s handle.</p>
|
||||
<p>Get information on state a callback from its handle.</p>
|
||||
<h4><a class="title-link" name="synopsis" href="#synopsis"></a> Synopsis</h4>
|
||||
<div class="language-python highlighter-rouge"><pre class="highlight"><code><span class="n">entity</span><span class="p">,</span> <span class="n">attribute</span><span class="p">,</span> <span class="n">kwargs</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">info_listen_state</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">handle</span><span class="p">)</span>
|
||||
</code></pre>
|
||||
|
@ -683,7 +683,7 @@
|
|||
</code></pre>
|
||||
</div>
|
||||
<h3><a class="title-link" name="info_timer" href="#info_timer"></a> info_timer()</h3>
|
||||
<p>Get information on a scheduler event from it’s handle.</p>
|
||||
<p>Get information on a scheduler event from its handle.</p>
|
||||
<h4><a class="title-link" name="synopsis" href="#synopsis"></a> Synopsis</h4>
|
||||
<div class="language-python highlighter-rouge"><pre class="highlight"><code><span class="n">time</span><span class="p">,</span> <span class="n">interval</span><span class="p">,</span> <span class="n">kwargs</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">info_timer</span><span class="p">(</span><span class="n">handle</span><span class="p">)</span>
|
||||
</code></pre>
|
||||
|
@ -705,7 +705,7 @@
|
|||
<li><code class="highlighter-rouge">random_start</code> - start of range of the random time</li>
|
||||
<li><code class="highlighter-rouge">random_end</code> - end of range of the random time</li>
|
||||
</ul>
|
||||
<p><code class="highlighter-rouge">random_start</code> must always be numerically lower than <code class="highlighter-rouge">random_end</code>, they can be negative to denote a random offset before and event, or positive to denote a random offset after an event. The event would be a an absolute or relative time or sunrise/sunset depending on which scheduler call you use and these values affect the base time by the spcified amount. If not specified, they will default to <code class="highlighter-rouge">0</code>.</p>
|
||||
<p><code class="highlighter-rouge">random_start</code> must always be numerically lower than <code class="highlighter-rouge">random_end</code>, they can be negative to denote a random offset before and event, or positive to denote a random offset after an event. The event would be an absolute or relative time or sunrise/sunset depending on which scheduler call you use and these values affect the base time by the spcified amount. If not specified, they will default to <code class="highlighter-rouge">0</code>.</p>
|
||||
<p>For example:</p>
|
||||
<div class="language-python highlighter-rouge"><pre class="highlight"><code><span class="c"># Run a callback in 2 minutes minus a random number of seconds between 0 and 60, e.g. run between 60 and 120 seconds from now</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">handle</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">run_in</span><span class="p">(</span><span class="n">callback</span><span class="p">,</span> <span class="mi">120</span><span class="p">,</span> <span class="n">random_start</span> <span class="o">=</span> <span class="o">-</span><span class="mi">60</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
|
||||
|
@ -1029,7 +1029,7 @@
|
|||
</code></pre>
|
||||
</div>
|
||||
<h3><a class="title-link" name="info_listen_event" href="#info_listen_event"></a> info_listen_event()</h3>
|
||||
<p>Get information on an event callback from it’s handle.</p>
|
||||
<p>Get information on an event callback from its handle.</p>
|
||||
<h4><a class="title-link" name="synopsis" href="#synopsis"></a> Synopsis</h4>
|
||||
<div class="language-python highlighter-rouge"><pre class="highlight"><code><span class="n">service</span><span class="p">,</span> <span class="n">kwargs</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">info_listen_event</span><span class="p">(</span><span class="n">handle</span><span class="p">)</span>
|
||||
</code></pre>
|
||||
|
@ -1082,7 +1082,7 @@
|
|||
<div class="language-python highlighter-rouge"><pre class="highlight"><code><span class="bp">self</span><span class="o">.</span><span class="n">listen_event</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">mode_event</span><span class="p">,</span> <span class="s">"MODE_CHANGE"</span><span class="p">)</span>
|
||||
</code></pre>
|
||||
</div>
|
||||
<p>Home Assistant can send these events in a variety of other places - within automations, and also directly from Alexa intents. Home Assistant can also listen for custom events with it’s automation component. This can be used to signal from AppDaemon code back to Home Assistant. Here is a sample automation:</p>
|
||||
<p>Home Assistant can send these events in a variety of other places - within automations, and also directly from Alexa intents. Home Assistant can also listen for custom events with its automation component. This can be used to signal from AppDaemon code back to Home Assistant. Here is a sample automation:</p>
|
||||
<div class="language-yaml highlighter-rouge"><pre class="highlight"><code><span class="s">automation</span><span class="pi">:</span>
|
||||
<span class="s">trigger</span><span class="pi">:</span>
|
||||
<span class="s">platform</span><span class="pi">:</span> <span class="s">event</span>
|
||||
|
@ -1401,7 +1401,7 @@
|
|||
<h2><a class="title-link" name="time-travel" href="#time-travel"></a> Time Travel</h2>
|
||||
<p>OK, time travel sadly isn’t really possible but it can be very useful when testing Apps. For instance, imagine you have an App that turns a light on every day at sunset. It might be nice to test it without waiting for Sunset - and with AppDaemon’s “Time Travel” features you can.</p>
|
||||
<h3><a class="title-link" name="choosing-a-start-time" href="#choosing-a-start-time"></a> Choosing a Start Time</h3>
|
||||
<p>Internally, AppDaemon keeps track of it’s own time relative to when it was started. This make is possible to start AppDaemon with a different start time and date to the current time. For instance to test that sunset App, start AppDaemon at a time just before sunset and see if it works as expected. To do this, simply use the “-s” argument on AppDaemon’s command line. e,g,:</p>
|
||||
<p>Internally, AppDaemon keeps track of its own time relative to when it was started. This make is possible to start AppDaemon with a different start time and date to the current time. For instance to test that sunset App, start AppDaemon at a time just before sunset and see if it works as expected. To do this, simply use the “-s” argument on AppDaemon’s command line. e,g,:</p>
|
||||
<div class="language-bash highlighter-rouge"><pre class="highlight"><code><span class="gp">$ </span>appdaemon -s <span class="s2">"2016-06-06 19:16:00"</span>
|
||||
2016-09-06 17:16:00 INFO AppDaemon Version 1.3.2 starting
|
||||
2016-09-06 17:16:00 INFO Got initial state
|
||||
|
|
|
@ -75,7 +75,7 @@
|
|||
</h1>
|
||||
</header>
|
||||
<hr class="divider">
|
||||
<p>To run <code class="highlighter-rouge">AppDaemon</code> at reboot, I have provided a sample init script in the <code class="highlighter-rouge">./scripts</code> directory. These have been tested on a Raspberry PI - your mileage may vary on other systems. There is also a sample Systemd script.</p>
|
||||
<p>To run <code class="highlighter-rouge">AppDaemon</code> at reboot, I have provided a sample init script in the <code class="highlighter-rouge">./scripts</code> directory. These have been tested on a Raspberry Pi - your mileage may vary on other systems. There is also a sample Systemd script.</p>
|
||||
</article>
|
||||
</div>
|
||||
<aside id="sidebar" class="grid__item one-third lap-one-whole palm-one-whole">
|
||||
|
|
|
@ -86,13 +86,13 @@
|
|||
<li>Is it open and expandable?</li>
|
||||
<li>Does it run locally without any reliance on the cloud?</li>
|
||||
</ul>
|
||||
<p>In my opinion, Home Assistant accomplishes the majority of these very well with a combination of Automations, Scripts and Templates, and it’s Restful API.</p>
|
||||
<p>In my opinion, Home Assistant accomplishes the majority of these very well with a combination of Automations, Scripts and Templates, and its Restful API.</p>
|
||||
<p>So why <code class="highlighter-rouge">AppDaemon</code>? AppDaemon is not meant to replace Home Assistant Automations and Scripts, rather complement them. For a lot of things, automations work well and can be very succinct. However, there is a class of more complex automations for which they become harder to use, and appdeamon then comes into its own. It brings quite a few things to the table:</p>
|
||||
<ul>
|
||||
<li>New paradigm - some problems require a procedural and/or iterative approach, and <code class="highlighter-rouge">AppDaemon</code> Apps are a much more natural fit for this. Recent enhancements to Home Assistant scripts and templates have made huge strides, but for the most complex scenarios, Apps can do things that Automations can’t</li>
|
||||
<li>Ease of use - AppDaemon’s API is full of helper functions that make programming as easy and natural as possible. The functions and their operation are as “Pythonic” as possible, experienced Python programmers should feel right at home.</li>
|
||||
<li>Reuse - write a piece of code once and instantiate it as an app as many times as you need with different parameters e.g. a motion light program that you can use in 5 different places around your home. The code stays the same, you just dynamically add new instances of it in the config file</li>
|
||||
<li>Dynamic - AppDaemon has been designed from the start to enable the user to make changes without requiring a restart of Home Assistant, thanks to it’s loose coupling. However, it is better than that - the user can make changes to code and AppDaemon will automatically reload the code, figure out which Apps were using it and restart them to use the new code with out the need to restart <code class="highlighter-rouge">AppDaemon</code> itself. It is also possible to change parameters for an individual or multiple apps and have them picked up dynamically, and for a final trick, removing or adding apps is also picked up dynamically. Testing cycles become a lot more efficient as a result.</li>
|
||||
<li>Dynamic - AppDaemon has been designed from the start to enable the user to make changes without requiring a restart of Home Assistant, thanks to its loose coupling. However, it is better than that - the user can make changes to code and AppDaemon will automatically reload the code, figure out which Apps were using it and restart them to use the new code with out the need to restart <code class="highlighter-rouge">AppDaemon</code> itself. It is also possible to change parameters for an individual or multiple apps and have them picked up dynamically, and for a final trick, removing or adding apps is also picked up dynamically. Testing cycles become a lot more efficient as a result.</li>
|
||||
<li>Complex logic - Python’s If/Else constructs are clearer and easier to code for arbitrarily complex nested logic</li>
|
||||
<li>Durable variables and state - variables can be kept between events to keep track of things like the number of times a motion sensor has been activated, or how long it has been since a door opened</li>
|
||||
<li>All the power of Python - use any of Python’s libraries, create your own modules, share variables, refactor and re-use code, create a single app to do everything, or multiple apps for individual tasks - nothing is off limits!</li>
|
||||
|
|
|
@ -147,7 +147,7 @@ Change below path to where you placed the <code class="highlighter-rouge">usb_ba
|
|||
</div>
|
||||
<h3><a class="title-link" name="auto-mount" href="#auto-mount"></a> Auto mount</h3>
|
||||
<p>This does not automatically mount your USB drive at boot. You need to do that manually or add a line to your <code class="highlighter-rouge">/etc/fstab</code> file.</p>
|
||||
<p>If your drive is on <code class="highlighter-rouge">/dev/sda1</code>, you could add a entry to your <code class="highlighter-rouge">/etc/fstab</code> like so:</p>
|
||||
<p>If your drive is on <code class="highlighter-rouge">/dev/sda1</code>, you could add an entry to your <code class="highlighter-rouge">/etc/fstab</code> like so:</p>
|
||||
<div class="language-text highlighter-rouge"><pre class="highlight"><code>/dev/sda1 /media ext4 defaults,noatime 0 1
|
||||
</code></pre>
|
||||
</div>
|
||||
|
|
|
@ -237,7 +237,7 @@ In cases where your ISP blocks port 80 you will need to change the port forward
|
|||
</p>
|
||||
<p>Now SSH in to the device your Home Assistant is running on.</p>
|
||||
<p class="note">
|
||||
If you’re running the ‘standard’ setup on a Raspberry Pi the chances are you just logged in as the ‘pi’ user. If not, you may have logged in as the Home Assistant user. There are commands below that require the Home Assistant user to be on the <code class="highlighter-rouge">sudoers</code> list. If you are not using the ‘standard’ pi setup it is presumed you will know how to get your Home Assistant user on the <code class="highlighter-rouge">sudoers</code> list before continuing. If you are running the ‘standard’ pi setup, from your ‘pi’ user issue the following command (where <code class="highlighter-rouge">hass</code> is the Home Assistant user):
|
||||
If you’re running the ‘standard’ setup on a Raspberry Pi the chances are you just logged in as the ‘pi’ user. If not, you may have logged in as the Home Assistant user. There are commands below that require the Home Assistant user to be on the <code class="highlighter-rouge">sudoers</code> list. If you are not using the ‘standard’ Pi setup it is presumed you will know how to get your Home Assistant user on the <code class="highlighter-rouge">sudoers</code> list before continuing. If you are running the ‘standard’ Pi setup, from your ‘pi’ user issue the following command (where <code class="highlighter-rouge">hass</code> is the Home Assistant user):
|
||||
<code class="highlighter-rouge">
|
||||
$ sudo adduser hass sudo
|
||||
</code>
|
||||
|
|
|
@ -176,7 +176,7 @@ Be careful when setting up port forwarding to the configurator while embedding i
|
|||
<ol>
|
||||
<li>Fork the process into the background with the command:<br />
|
||||
<code class="highlighter-rouge">nohup sudo ./configurator.py &</code></li>
|
||||
<li>If your system is using systemd (that’s usually what you’ll find on a Raspberry PI), there’s a <a href="https://github.com/danielperna84/hass-configurator/blob/master/hass-poc-configurator.systemd">template file</a> you can use and then apply the same process to integrate it as mentioned in the <a href="https://home-assistant.io/docs/autostart/systemd/">Home Assistant documentation</a>. If you use this method you have to set the <code class="highlighter-rouge">BASEPATH</code> variable according to your environment.</li>
|
||||
<li>If your system is using systemd (that’s usually what you’ll find on a Raspberry Pi), there’s a <a href="https://github.com/danielperna84/hass-configurator/blob/master/hass-poc-configurator.systemd">template file</a> you can use and then apply the same process to integrate it as mentioned in the <a href="https://home-assistant.io/docs/autostart/systemd/">Home Assistant documentation</a>. If you use this method you have to set the <code class="highlighter-rouge">BASEPATH</code> variable according to your environment.</li>
|
||||
<li>If you have <a href="http://supervisord.org/">supervisor</a> running on your system, <a href="https://github.com/danielperna84/hass-configurator/blob/master/hass-poc-configurator.supervisor">hass-poc-configurator.supervisor</a> would be an example configuration you could use to control the configurator.</li>
|
||||
<li>A tool called <a href="https://tmux.github.io/">tmux</a>, which should be pre-installed with <a href="https://home-assistant.io/docs/hassbian/">HASSbian</a>.</li>
|
||||
<li>A tool called <a href="http://ss64.com/bash/screen.html">screen</a> (alternative to tmux). If it’s not already installed on your system, you can do <code class="highlighter-rouge">sudo apt-get install screen</code> or <code class="highlighter-rouge">sudo yum install screen</code> to get it. When it’s installed, start a screen session by executing <code class="highlighter-rouge">screen</code>. Then navigate to your Home Assistant directory and start the configurator like described above. Put the screen session into the background by pressing <code class="highlighter-rouge">CTRL+A</code> and then <code class="highlighter-rouge">CTRL+D</code>. It is now safe to disconnect from your SSH session.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue