--- Brian Hanifin DIY Home Automation with Home Assistant. daily 1 https://brianhanifin.com Tue, 21 Jan 2020 19:45:00 -0800 Inovelli Z-Wave Dimmer Status LED in Home Assistant Brian Hanifin <div style="float: right"><img src="//ir-na.amazon-adsystem.com/e/ir?t=brianhanifi0d-20&amp;l=am2&amp;o=1&amp;a=B07S1BMMGH" /><img src="//ws-na.amazon-adsystem.com/widgets/q?_encoding=UTF8&amp;MarketPlace=US&amp;ASIN=B07S1BMMGH&amp;ServiceVersion=20070822&amp;ID=AsinImage&amp;WS=1&amp;Format=_SL160_&amp;tag=brianhanifi0d-20" /></div> <p>Recently I ordered <a href="https://www.amazon.com/gp/product/B07S1BMMGH/ref=as_li_tl?ie=UTF8&amp;camp=1789&amp;creative=9325&amp;creativeASIN=B07S1BMMGH&amp;linkCode=as2&amp;tag=brianhanifi0d-20&amp;linkId=e9eab63e3bd22d91d96bc880228508a1">Inovelli (Red Series) Z-Wave Dimmer</a> from Amazon. I primarily got it because for the ability to take actions based on up to 5 taps up (and down). I set it up to toggle one lamp with one tap, and toggle all three lamps with a double tap.</p> <p>This dimmer has a really slick led strip embedded. As it turns they can preform animations and change colors. I am experimenting with using it as a secondary status notifier. So far I’m using Cyan to indicate an unlocked front door and Purple to indicate an open Garage Door.</p> <p>Unfortunately the LED feature requires some mathmatical gymnastics to pull off. Luckly I found <a href="https://community.inovelli.com/t/home-assistant-2nd-gen-switch-rgb-working/168/62">a discussion on the Inovell forum</a> which provided me with two amazing resources. 1.) @nathanfiscus’s amazing <a href="https://nathanfiscus.github.io/inovelli-notification-calc/">Inovelli Toolbox</a> and 2.) Inovelli’s <a href="https://docs.google.com/spreadsheets/u/1/d/1SGJrJHCUtz8AzznWL_mLCTJjjr2U0IpltcUkRr7N_6M/edit?usp=sharing">Google Spreadsheet</a>. I ended up taking the calculations from the spreadsheet and converting them into Jinja code to do the calculations.</p> <p>Anyway, here is the script I created to control the Status LED.</p> <h2 id="tip">Tip</h2> <p>If you get an error with the <code class="language-yaml highlighter-rouge"><span class="s">entity_id</span></code> @flyingsubs suggests you may need to shorten the name of your <code class="language-yaml highlighter-rouge"><span class="s">zwave.{really_long_light_switch_name_and_model_blah_blah_blah}</span></code> entity. Apparently too long of an entity_name can cause a problem.</p> <h2 id="scripts">Scripts</h2> <noscript><pre>400: Invalid request </pre></noscript> <script src="https://gist.github.com/9dcac14f7b05d7ccb62383626eac5a21.js"> </script> <h2 id="automations">Automations</h2> <noscript><pre>400: Invalid request </pre></noscript> <script src="https://gist.github.com/7464297a1e7a96839cc439695968bcca.js"> </script> Tue, 21 Jan 2020 19:45:00 -0800 https://brianhanifin.com/posts/inovelli-dimmer-status-led-home-assistant/ https://brianhanifin.com/posts/inovelli-dimmer-status-led-home-assistant/ Home Assistant Template Macros: Date and Time Brian Hanifin <p>Over time I have created a large library of date and time manipulation code which are used in my automations and scripts. I plan to update this post with the snippets as I add to my library.</p> <h2 id="date">Date</h2> <h3 id="standard-examples">Standard Examples</h3> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1 2 3 4 5 6 7 8 </pre></td><td class="rouge-code"><pre><span class="pi">{</span><span class="err">%</span> <span class="nv">set date = as_timestamp(now())|timestamp_custom("%A %B %-d</span><span class="pi">,</span> <span class="err">%</span><span class="nv">Y") %</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">set datetime = as_timestamp(now()) | timestamp_custom("%I</span><span class="pi">:</span><span class="err">%</span><span class="nv">M</span><span class="pi">:</span><span class="err">%</span><span class="nv">S %p %b/%d/%Y"</span><span class="pi">,</span> <span class="nv">true)</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">set datetime = as_timestamp(now()) | timestamp_custom("%I</span><span class="pi">:</span><span class="err">%</span><span class="nv">M</span><span class="pi">:</span><span class="err">%</span><span class="nv">S %p %b/%d/%Y"</span><span class="pi">,</span> <span class="nv">true)</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">set now_string = now().strftime("%Y-%m-%d") %</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">set month_name = now().strftime("%B") %</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">set day_name = now().strftime("%A")|lower %</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">set this_year = now().strftime("%Y")|int %</span><span class="pi">}</span> </pre></td></tr></tbody></table></code></pre></div></div> <h3 id="dayofweek_numberdayofweek">dayofweek_number(dayofweek)</h3> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 </pre></td><td class="rouge-code"><pre><span class="pi">{</span><span class="err">%</span><span class="nv">- macro dayofweek_number(dayofweek) -%</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- if dayofweek == "Sunday" or dayofweek == "Sun" -%</span><span class="pi">}</span> <span class="m">1</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- elif dayofweek == "Monday" or dayofweek == "Mon" -%</span><span class="pi">}</span> <span class="m">2</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- elif dayofweek == "Tuesday" or dayofweek == "Tue" -%</span><span class="pi">}</span> <span class="m">3</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- elif dayofweek == "Wednesday" or dayofweek == "Wed" -%</span><span class="pi">}</span> <span class="m">4</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- elif dayofweek == "Thursday" or dayofweek == "Thu" -%</span><span class="pi">}</span> <span class="m">5</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- elif dayofweek == "Friday" or dayofweek == "Fri" -%</span><span class="pi">}</span> <span class="m">6</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- elif dayofweek == "Saturday" or dayofweek == "Sat" -%</span><span class="pi">}</span> <span class="m">7</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- endif -%</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- endmacro -%</span><span class="pi">}</span> </pre></td></tr></tbody></table></code></pre></div></div> <h3 id="last_dayofmonthmonth-year">last_dayofmonth(month, year)</h3> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 </pre></td><td class="rouge-code"><pre><span class="pi">{</span><span class="err">%</span><span class="nv">- macro last_dayofmonth(month</span><span class="pi">,</span> <span class="nv">year) -%</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- set daysinmonths =</span> <span class="pi">[</span><span class="nv">31</span><span class="pi">,</span><span class="nv">28</span><span class="pi">,</span><span class="nv">31</span><span class="pi">,</span><span class="nv">30</span><span class="pi">,</span><span class="nv">31</span><span class="pi">,</span><span class="nv">30</span><span class="pi">,</span><span class="nv">31</span><span class="pi">,</span><span class="nv">31</span><span class="pi">,</span><span class="nv">30</span><span class="pi">,</span><span class="nv">31</span><span class="pi">,</span><span class="nv">30</span><span class="pi">,</span><span class="nv">31</span><span class="pi">]</span> <span class="nv">-%</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- set month = month|int -%</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- set year = year|int -%</span><span class="pi">}</span> <span class="pi">{</span><span class="c1"># Simplified leap year calculation. See https://www.mathsisfun.com/leap-years.html #}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- set isleapyear = year % 4 == 0 and (year % 100 != 0 or year % 400 == 0) -%</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- set monthindex = month-1 -%</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- if month == 2 and isleapyear -%</span><span class="pi">}</span> <span class="pi">{{</span> <span class="nv">daysinmonths</span><span class="pi">[</span><span class="nv">monthindex</span><span class="pi">]</span><span class="nv">+1</span> <span class="pi">}}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- else -%</span><span class="pi">}</span> <span class="pi">{{</span> <span class="nv">daysinmonths</span><span class="pi">[</span><span class="nv">monthindex</span><span class="pi">]</span> <span class="pi">}}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- endif -%</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- endmacro -%</span><span class="pi">}</span> </pre></td></tr></tbody></table></code></pre></div></div> <h3 id="nth_dayofmonthnth-dayofweek-month-year">nth_dayofmonth(nth, dayofweek, month, year)</h3> <p>ex. Get the nth Monday of May.<br /> 1st: <code class="language-yaml highlighter-rouge"><span class="pi">{{</span> <span class="nv">nth_dayofmonth(1</span><span class="pi">,</span> <span class="s2">"</span><span class="s">Monday"</span><span class="pi">,</span> <span class="nv">5)</span> <span class="pi">}}</span></code><br /> 2nd: <code class="language-yaml highlighter-rouge"><span class="pi">{{</span> <span class="nv">nth_dayofmonth(2</span><span class="pi">,</span> <span class="s2">"</span><span class="s">Monday"</span><span class="pi">,</span> <span class="nv">5</span><span class="pi">,</span> <span class="nv">2020)</span> <span class="pi">}}</span></code><br /> Last: <code class="language-yaml highlighter-rouge"><span class="pi">{{</span> <span class="nv">nth_dayofmonth("last"</span><span class="pi">,</span> <span class="s2">"</span><span class="s">Monday"</span><span class="pi">,</span> <span class="nv">5)</span> <span class="pi">}}</span></code></p> <p>Reference: <a href="https://www.bennadel.com/blog/1446-getting-the-nth-occurrence-of-a-day-of-the-week-for-a-given-month.htm">bennadel.com</a></p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 </pre></td><td class="rouge-code"><pre><span class="pi">{</span><span class="err">%</span><span class="nv">- macro nth_dayofmonth(nth</span><span class="pi">,</span> <span class="nv">dayofweek</span><span class="pi">,</span> <span class="nv">month</span><span class="pi">,</span> <span class="nv">year=now().strftime("%Y")) -%</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- set dayofweek = dayofweek_number(dayofweek)|int -%</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- set firstdateofmonth = strptime(year ~"-"~ month ~"-1"</span><span class="pi">,</span> <span class="s2">"</span><span class="s">%Y-%m-%d"</span><span class="nv">) -%</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- set firstdayofmonth = dayofweek_number(firstdateofmonth.strftime("%A"))|int -%</span><span class="pi">}</span> <span class="pi">{</span><span class="c1"># Determine the first occurrence of the day. #}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- if firstdayofmonth == 1 -%</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- set firstoccurrence = dayofweek -%</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- elif firstdayofmonth &lt; dayofweek -%</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- set firstoccurrence = (dayofweek - dayofweek_number(firstdayofmonth)) -%</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- else -%</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- set firstoccurrence = (7 - firstdayofmonth + dayofweek) + 1 -%</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- endif -%</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- if nth is number -%</span><span class="pi">}</span> <span class="pi">{</span><span class="c1"># Determine the nth occurrence of the dayofweek. #}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- set nthoccurrence = firstoccurrence + 7 * (nth-1) -%</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- else -%</span><span class="pi">}</span> <span class="pi">{</span><span class="c1">#</span> <span class="nv">Determine the LAST occurrence of the dayofweek.</span> <span class="nv">Reference</span><span class="pi">:</span> <span class="nv">https</span><span class="pi">:</span><span class="nv">//cflib.org/udf/GetLastOccOfDayInMonth</span> <span class="c1">#}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- set lastdayofmonth = last_dayofmonth(month</span><span class="pi">,</span> <span class="nv">year)|int -%</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- set lastdayname = strptime(year ~"-"~ month ~"-"~ lastdayofmonth</span><span class="pi">,</span> <span class="s2">"</span><span class="s">%Y-%m-%d"</span><span class="nv">).strftime("%A") -%</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- set lastdaynumber = dayofweek_number(lastdayname)|int -%</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- set daydifference = lastdaynumber - dayofweek -%</span><span class="pi">}</span> <span class="pi">{</span><span class="c1"># Add a week if the result is negative. #}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- if daydifference &lt; 0 -%</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- set daydifference = daydifference + 7 -%</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- endif -%</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- set nthoccurrence = lastdayofmonth - daydifference -%</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- endif -%</span><span class="pi">}</span> <span class="pi">{</span><span class="c1"># Return the day with the month and year so it can be useful. #}</span> <span class="pi">{{</span> <span class="nv">strptime(month ~"/"~ nthoccurrence ~"/"~ year</span><span class="pi">,</span> <span class="s2">"</span><span class="s">%m/%d/%Y"</span><span class="nv">)</span> <span class="pi">}}</span> <span class="pi">{</span><span class="err">%</span><span class="nv">- endmacro -%</span><span class="pi">}</span> </pre></td></tr></tbody></table></code></pre></div></div> <h2 id="time">Time</h2> <h3 id="standard-examples-1">Standard Examples</h3> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1 2 3 4 5 6 7 </pre></td><td class="rouge-code"><pre><span class="pi">{</span><span class="err">%</span> <span class="nv">set time = as_timestamp(now())|timestamp_custom("%h</span><span class="pi">:</span><span class="err">%</span><span class="nv">M %p") %</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">set hour = now().strftime("%I")|int %</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">set minutes = now().strftime("%M")|int %</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">set seconds = now().strftime("%S")|int %</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">set ampm = now().strftime("%p")|int %</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">set unix_timestamp = as_timestamp(now())|int %</span><span class="pi">}</span> </pre></td></tr></tbody></table></code></pre></div></div> <h3 id="time-differences">Time differences</h3> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1 2 3 </pre></td><td class="rouge-code"><pre><span class="pi">{</span><span class="err">%</span> <span class="nv">set seconds_difference = (as_timestamp(now()) - as_timestamp(last_update)) %</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">set minutes_difference = (seconds_difference) / 60 %</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">set hours_difference = (seconds_difference) / 3600 %</span><span class="pi">}</span> </pre></td></tr></tbody></table></code></pre></div></div> <h3 id="between-hours">Between hours</h3> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1 2 3 4 5 6 7 </pre></td><td class="rouge-code"><pre><span class="pi">{</span><span class="err">%</span> <span class="nv">if now().strftime("%H")|int &lt; 12 and now().strftime("%H")|int &gt; 6%</span><span class="pi">}</span> <span class="m">0.25</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">elif now().strftime("%H")|int &gt; 12 and now().strftime("%H")|int &lt; 17%</span><span class="pi">}</span> <span class="m">0.40</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">else %</span><span class="pi">}</span> <span class="m">0.20</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">endif %</span><span class="pi">}</span> </pre></td></tr></tbody></table></code></pre></div></div> <h3 id="add_time"><code class="language-yaml highlighter-rouge"><span class="s">add_time()</span></code></h3> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 </pre></td><td class="rouge-code"><pre><span class="pi">{</span><span class="err">%</span> <span class="nv">macro add_time(time</span><span class="pi">,</span> <span class="nv">add_minutes) %</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">if time|lower != "unavailable" %</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">set time = time.split("</span><span class="pi">:</span><span class="s2">"</span><span class="s">)</span><span class="nv"> </span><span class="s">%}</span> <span class="s">{%</span><span class="nv"> </span><span class="s">set</span><span class="nv"> </span><span class="s">hour</span><span class="nv"> </span><span class="s">=</span><span class="nv"> </span><span class="s">time[0]|int</span><span class="nv"> </span><span class="s">%}</span> <span class="s">{%</span><span class="nv"> </span><span class="s">set</span><span class="nv"> </span><span class="s">minutes</span><span class="nv"> </span><span class="s">=</span><span class="nv"> </span><span class="s">time[1]|int</span><span class="nv"> </span><span class="s">%}</span> <span class="s">{%</span><span class="nv"> </span><span class="s">if</span><span class="nv"> </span><span class="s">(minutes</span><span class="nv"> </span><span class="s">+</span><span class="nv"> </span><span class="s">add_minutes)</span><span class="nv"> </span><span class="s">&lt;</span><span class="nv"> </span><span class="s">60</span><span class="nv"> </span><span class="s">%}</span> <span class="s">{{</span><span class="nv"> </span><span class="s">"</span><span class="err">%</span><span class="nv">0.02d</span><span class="pi">:</span><span class="err">%</span><span class="nv">0.02d"|format(hour</span><span class="pi">,</span> <span class="nv">minutes + add_minutes)</span> <span class="pi">}</span><span class="err">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">else %</span><span class="pi">}</span> <span class="pi">{{</span> <span class="s2">"</span><span class="s">%0.02d:%0.02d"</span><span class="err">|</span><span class="nv">format(hour + 1</span><span class="pi">,</span> <span class="nv">(minutes + add_minutes) - 60)</span> <span class="pi">}}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">endif %</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">endif %</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">endmacro %</span><span class="pi">}</span> <span class="c1"># Trigger the automation 5 minutes after the wakeup time.</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">set add_minutes = 5 %</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">set current_time = states("sensor.time") %</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">set boys = add_time(states("sensor.boys_room_next_alarm")</span><span class="pi">,</span><span class="nv">add_minutes) %</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">set brian = add_time(states("sensor.wakeup_brian_time")</span><span class="pi">,</span><span class="nv">add_minutes) %</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">set nerene = add_time(states("sensor.wakeup_nerene_time")</span><span class="pi">,</span><span class="nv">add_minutes) %</span><span class="pi">}</span> <span class="pi">{{</span> <span class="nv">current_time in</span> <span class="pi">[</span><span class="nv">boys</span><span class="pi">,</span><span class="nv">brian</span><span class="pi">,</span><span class="nv">nerene</span><span class="pi">]</span> <span class="pi">}}</span> </pre></td></tr></tbody></table></code></pre></div></div> <h3 id="subtract_time"><code class="language-yaml highlighter-rouge"><span class="s">subtract_time()</span></code></h3> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 </pre></td><td class="rouge-code"><pre><span class="pi">{</span><span class="err">%</span> <span class="nv">macro subtract_time(time</span><span class="pi">,</span> <span class="nv">subtract_minutes) %</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">if time|lower != "unavailable" %</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">set time = time.split("</span><span class="pi">:</span><span class="s2">"</span><span class="s">)</span><span class="nv"> </span><span class="s">%}</span> <span class="s">{%</span><span class="nv"> </span><span class="s">set</span><span class="nv"> </span><span class="s">hour</span><span class="nv"> </span><span class="s">=</span><span class="nv"> </span><span class="s">time[0]|int</span><span class="nv"> </span><span class="s">%}</span> <span class="s">{%</span><span class="nv"> </span><span class="s">set</span><span class="nv"> </span><span class="s">minutes</span><span class="nv"> </span><span class="s">=</span><span class="nv"> </span><span class="s">time[1]|int</span><span class="nv"> </span><span class="s">%}</span> <span class="s">{%</span><span class="nv"> </span><span class="s">if</span><span class="nv"> </span><span class="s">(minutes|int</span><span class="nv"> </span><span class="s">&gt;=</span><span class="nv"> </span><span class="s">subtract_minutes)</span><span class="nv"> </span><span class="s">%}</span> <span class="s">{{</span><span class="nv"> </span><span class="s">"</span><span class="err">%</span><span class="nv">0.02d</span><span class="pi">:</span><span class="err">%</span><span class="nv">0.02d"|format(hour</span><span class="pi">,</span> <span class="nv">minutes - subtract_minutes)</span> <span class="pi">}</span><span class="err">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">else %</span><span class="pi">}</span> <span class="pi">{{</span> <span class="s2">"</span><span class="s">%0.02d:%0.02d"</span><span class="err">|</span><span class="nv">format(hour - 1</span><span class="pi">,</span> <span class="nv">minutes + (60-subtract_minutes))</span> <span class="pi">}}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">endif %</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">endif %</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">endmacro %</span><span class="pi">}</span> <span class="c1"># Trigger the automation 30 minutes before the wakeup time.</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">set subtract_minutes = 30 %</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">set current_time = states("sensor.time") %</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">set boys = subtract_time(states("sensor.boys_room_next_alarm")</span><span class="pi">,</span><span class="nv">subtract_minutes) %</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">set brian = subtract_time(states("sensor.wakeup_brian_time")</span><span class="pi">,</span><span class="nv">subtract_minutes) %</span><span class="pi">}</span> <span class="pi">{</span><span class="err">%</span> <span class="nv">set nerene = subtract_time(states("sensor.wakeup_nerene_time")</span><span class="pi">,</span><span class="nv">subtract_minutes) %</span><span class="pi">}</span> <span class="pi">{{</span> <span class="nv">current_time in</span> <span class="pi">[</span><span class="nv">boys</span><span class="pi">,</span><span class="nv">brian</span><span class="pi">,</span><span class="nv">nerene</span><span class="pi">]</span> <span class="pi">}}</span> </pre></td></tr></tbody></table></code></pre></div></div> Sat, 18 Jan 2020 21:00:00 -0800 https://brianhanifin.com/posts/home-assistant-date-time-template-macros/ https://brianhanifin.com/posts/home-assistant-date-time-template-macros/ Voice Event Reminders with a User Interface Brian Hanifin <p>Some of my favorite “quality of life” automations are: 1.) an LED strip that turns on when anyone enters the kitchen, 2.) bedside lights that help us wake up in the morning, and 3.) Alexa voice alerts that remind us when it is about time to leave for events (school, water polo, circus class, etc).</p> <p>I got caught up on the Node-Red hype train for a short while, but that ride didn’t last long. To begin the new decade I decided to retire Node-Red for good. To do so required me to move my many Event Reminders over to YAML and I wanted to really push my skills with this project.</p> <h2 id="project-requirements">Project Requirements</h2> <p><a href="/assets/img/2020-01-06/event-reminder1.png"><img src="/assets/img/2020-01-06/event-reminder1-thumbnail.png" alt="event-reminder1-thumbnail" style="float:right; margin-left: 1em;" /></a></p> <ol> <li>Schedule Alexa to alert us when an event draws near.</li> <li>Provide a User Interface (UI) with the following features for each event: <ul> <li>Enable/Disable button</li> <li>“Skip Next” button</li> <li>Days of the Week selection</li> <li>First and Second Announcement times</li> <li>First and Second Announcement text</li> <li>List of Echo devices and device groups the announcement should be heard on</li> </ul> </li> <li>The Automations must be reliable! The school principal doesn’t seem to understand that my kids are late because automated voice assistant didn’t remind me to take them to school. ;)</li> </ol> <h3 id="user-interface">User Interface</h3> <p>Before I wrote the automations, I started to lay out the UI so I knew what entities I needed to create. You can see the final results of this planning in the image above. I ended up using the following six custom Lovelace plugins, all installed via the <a href="https://github.com/hacs/integration">Home Assistant Community Store (HACS)</a>.</p> <ol> <li><a href="https://github.com/custom-cards/decluttering-card">custom:<strong>decluttering-card</strong></a></li> <li><a href="https://github.com/gadgetchnnel/lovelace-text-input-row">custom:<strong>text-input-row</strong></a></li> <li><a href="https://github.com/custom-cards/button-card">custom:<strong>button-card</strong></a></li> <li><a href="https://github.com/custom-cards/button-entity-row">custom:<strong>button-entity-row</strong></a></li> <li><a href="https://github.com/thomasloven/lovelace-fold-entity-row">custom:<strong>fold-entity-row</strong></a></li> <li><a href="https://github.com/custom-cards/text-divider-row">custom:<strong>text-divider-row</strong></a></li> </ol> <p>I consider the first two to be necessary for this project to be feasible. The last four could be omitted if you prefer. The decluttering card makes a template for each of my (currently) 10 events, while the text card allows the text field to span the entire width of the parent card.</p> <p>If you’d like to see the code behind the UI, here are the files in my repository to look at.</p> <ul> <li><a href="https://github.com/brianhanifin/Home-Assistant-Config/blob/master/lovelace/views/05_event_reminders.yaml">/lovelace/views/05_event_reminders.yaml</a></li> <li><a href="https://github.com/brianhanifin/Home-Assistant-Config/blob/master/lovelace/templates/event_reminder.yaml">/lovelace/templates/event_reminder.yaml</a></li> <li><a href="https://github.com/brianhanifin/Home-Assistant-Config/blob/master/lovelace/templates/heading.yaml">/lovelace/templates/heading.yaml</a></li> <li><a href="https://github.com/brianhanifin/Home-Assistant-Config/blob/master/lovelace/templates/button_row7.yaml">/lovelace/templates/button_row7.yaml</a></li> <li><a href="https://github.com/brianhanifin/Home-Assistant-Config/blob/master/lovelace/templates/button.yaml">/lovelace/templates/button.yaml</a></li> <li><a href="https://github.com/brianhanifin/Home-Assistant-Config/blob/master/lovelace/templates/button_pill2.yaml">/lovelace/templates/button_pill2.yaml</a></li> </ul> <p>The detail on the UI design beyond the intended scope of this article. However, I will share that the Enable button simply enables and disables the automation directly. As always feel free to ask questions in the comment section below, and who knows I may do a follow up article detailing the UI.</p> <h3 id="automation">Automation</h3> <p>Here is the base automation I wrote to trigger the Alexa voice reminders. First I trigger the automation when either the First or Second time equal the current time. This saves a lot of code duplication as you will see. Then I check if the alert is supposed to be spoken on the current day, Finally I call <code class="language-yaml highlighter-rouge"><span class="s">script.event_reminder_announce</span></code> to pass the First or Second Announcement text along to be spoken.</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 </pre></td><td class="rouge-code"><pre><span class="na">automation</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">alias</span><span class="pi">:</span> <span class="s">event_reminder_1</span> <span class="na">trigger</span><span class="pi">:</span> <span class="na">platform</span><span class="pi">:</span> <span class="s">template</span> <span class="na">value_template</span><span class="pi">:</span> <span class="pi">&gt;-</span> <span class="s">{{ is_state('sensor.event_reminder_1_1',states('sensor.time'))</span> <span class="s">or is_state('sensor.event_reminder_1_2',states('sensor.time')) }}</span> <span class="na">condition</span><span class="pi">:</span> <span class="na">condition</span><span class="pi">:</span> <span class="s">and</span> <span class="na">conditions</span><span class="pi">:</span> <span class="c1"># Is today one of the selected days?</span> <span class="pi">-</span> <span class="na">condition</span><span class="pi">:</span> <span class="s">template</span> <span class="na">value_template</span><span class="pi">:</span> <span class="pi">&gt;</span> <span class="s">{% set day_name = now().strftime("%A")|lower -%}</span> <span class="s">{%- if day_name == 'monday' and is_state('input_boolean.event_reminder_1_mon','on') -%}</span> <span class="s">{{true}}</span> <span class="s">{%- elif day_name == 'tuesday' and is_state('input_boolean.event_reminder_1_tue','on') -%}</span> <span class="s">{{true}}</span> <span class="s">{%- elif day_name == 'wednesday' and is_state('input_boolean.event_reminder_1_wed','on') -%}</span> <span class="s">{{true}}</span> <span class="s">{%- elif day_name == 'thursday' and is_state('input_boolean.event_reminder_1_thu','on') -%}</span> <span class="s">{{true}}</span> <span class="s">{%- elif day_name == 'friday' and is_state('input_boolean.event_reminder_1_fri','on') -%}</span> <span class="s">{{true}}</span> <span class="s">{%- elif day_name == 'saturday' and is_state('input_boolean.event_reminder_1_sat','on') -%}</span> <span class="s">{{true}}</span> <span class="s">{%- elif day_name == 'sunday' and is_state('input_boolean.event_reminder_1_sun','on') -%}</span> <span class="s">{{true}}</span> <span class="s">{%- else -%}</span> <span class="s">{{false}}</span> <span class="s">{%- endif %}</span> <span class="na">action</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">service</span><span class="pi">:</span> <span class="s">script.event_reminder_announce</span> <span class="na">data_template</span><span class="pi">:</span> <span class="na">media_player</span><span class="pi">:</span> <span class="s2">"</span><span class="s">{{</span><span class="nv"> </span><span class="s">states('input_select.event_reminder_1_echo')</span><span class="nv"> </span><span class="s">}}"</span> <span class="na">message</span><span class="pi">:</span> <span class="pi">&gt;-</span> <span class="s">{% if is_state('sensor.event_reminder_1_1',states('sensor.time')) %}</span> <span class="s">{{ states('input_text.event_reminder_1_1') }}</span> <span class="s">{% else %}</span> <span class="s">{{ states('input_text.event_reminder_1_2') }}</span> <span class="s">{% endif %}</span> </pre></td></tr></tbody></table></code></pre></div></div> <p>There is a little more to the final code that handles when the Skip Next button is enabled. But that just complicates things a little bit.</p> <h3 id="announcement-scripts">Announcement Scripts</h3> <h3 id="scriptevent_reminder_announce"><code class="language-yaml highlighter-rouge"><span class="s">script.event_reminder_announce</span></code></h3> <p>This script replaces the friendly media player name with the entity_id of the target Echo device, and passes the message along to <code class="language-yaml highlighter-rouge"><span class="s">script.say</span></code>.</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 </pre></td><td class="rouge-code"><pre><span class="na">script</span><span class="pi">:</span> <span class="na">event_reminder_announce</span><span class="pi">:</span> <span class="na">sequence</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">service</span><span class="pi">:</span> <span class="s">script.say</span> <span class="na">data_template</span><span class="pi">:</span> <span class="na">message</span><span class="pi">:</span> <span class="s2">"</span><span class="s">{{</span><span class="nv"> </span><span class="s">message</span><span class="nv"> </span><span class="s">}}"</span> <span class="na">media_player</span><span class="pi">:</span> <span class="pi">&gt;</span> <span class="s">{%- set room = media_player|lower|replace(' ','_')|replace('[','')|replace(']','') %}</span> <span class="s">{%-</span> <span class="s">set alexa = {</span> <span class="s">"bedroom" : "media_player.master_bedroom",</span> <span class="s">"boys_bedroom": "media_player.boys_room",</span> <span class="s">"downstairs": "media_player.downstairs",</span> <span class="s">"kitchen/garage": "group.alexa_welcome",</span> <span class="s">"garage" : "media_player.garage",</span> <span class="s">"kitchen" : "media_player.kitchen",</span> <span class="s">"family_room" : "media_player.family_room",</span> <span class="s">"play_room": "media_player.play_room",</span> <span class="s">"upstairs": "media_player.upstairs",</span> <span class="s">"upstairs_bathroom": "media_player.upstairs_bathroom"</span> <span class="s">}</span> <span class="s">-%}</span> <span class="s">{{ alexa[room] }}</span> </pre></td></tr></tbody></table></code></pre></div></div> <h3 id="scriptsay"><code class="language-yaml highlighter-rouge"><span class="s">script.say</span></code></h3> <p>The following script is an ultra simplified version of my speech script, which uses the custom <a href="https://github.com/custom-components/alexa_media_player">Alexa Media Player</a> <a href="https://github.com/custom-components/alexa_media_player/wiki/Notification-Component">voice notification feature</a>. This component is amazing and can also be installed with HACS.</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 </pre></td><td class="rouge-code"><pre> <span class="na">say</span><span class="pi">:</span> <span class="na">sequence</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">service</span><span class="pi">:</span> <span class="s">notify.alexa_media</span> <span class="na">data_template</span><span class="pi">:</span> <span class="na">data</span><span class="pi">:</span> <span class="na">type</span><span class="pi">:</span> <span class="s">announce</span> <span class="na">method</span><span class="pi">:</span> <span class="s">all</span> <span class="na">title</span><span class="pi">:</span> <span class="pi">&gt;</span> <span class="s">{%- if title is not string -%}</span> <span class="s">Home Assistant</span> <span class="s">{%- else -%}</span> <span class="s">{{ title }}</span> <span class="s">{%- endif -%}</span> <span class="na">message</span><span class="pi">:</span> <span class="s2">"</span><span class="s">{{</span><span class="nv"> </span><span class="s">message</span><span class="nv"> </span><span class="s">}}"</span> <span class="na">target</span><span class="pi">:</span> <span class="s2">"</span><span class="s">{{</span><span class="nv"> </span><span class="s">media_player</span><span class="nv"> </span><span class="s">}}"</span> </pre></td></tr></tbody></table></code></pre></div></div> <h2 id="supporting-entities">Supporting Entities</h2> <p>The tedious part was creating all 15 of the <code class="language-yaml highlighter-rouge"><span class="s">input_boolean</span></code>, <code class="language-yaml highlighter-rouge"><span class="s">input_datetime</span></code>, <code class="language-yaml highlighter-rouge"><span class="s">input_select</span></code>, <code class="language-yaml highlighter-rouge"><span class="s">input_text</span></code>, and <code class="language-yaml highlighter-rouge"><span class="s">sensor</span></code> entities. After creating my first two reminders, I realized it was going to take forever to do this 10 times! I am a big fan of the way @frenck organizes his configuration files (essentially, each entity gets a separate file). That’s when I realized I needed to package all of the automations, scripts, and entities together… well, in a <a href="https://www.home-assistant.io/docs/configuration/packages">package</a>.</p> <h3 id="packages">Packages</h3> <p>You can find all of the packages for this project in the <a href="https://github.com/brianhanifin/Home-Assistant-Config/blob/master/integrations/event_reminders/">/integrations/event_reminders</a> folder. The newest revision of the code I shared above can be found in <a href="https://github.com/brianhanifin/Home-Assistant-Config/blob/master/integrations/event_reminders/event_reminder_1_package.yaml">event_reminder_1_package.yaml</a>. The speech scripts can be found in <a href="https://github.com/brianhanifin/Home-Assistant-Config/blob/master/integrations/event_reminders/event_reminder_common_package.yaml">event_reminder_common_package.yaml</a>.</p> <h2 id="conclusion">Conclusion</h2> <p>After using this code reliably for a few days I am really proud of how it turned out. I tried to keep this article relatively brief so I didn’t bore you with every detail. If you enjoyed this overview of my most ambitious project to date, please leave a comment below. Questions are also welcomed on the <a href="https://community.home-assistant.io/u/brianhanifin">Home Assistant Community</a> forum, <a href="https://twitter.com/brianhanifin">Twitter</a>, <a href="https://github.com/brianhanifin/Home-Assistant-Config">my GitHub repo</a> or comments on this blog.</p> Mon, 06 Jan 2020 21:00:00 -0800 https://brianhanifin.com/posts/voice-event-reminders-with-user-interface/ https://brianhanifin.com/posts/voice-event-reminders-with-user-interface/ Wife Approval Factor (WAF) Crisis Brian Hanifin <h2 id="how-to-stop-accepting-flaky-components-and-start-replacing-them">How to stop accepting flaky components, and start replacing them</h2> <p>A few months ago <a href="https://community.home-assistant.io/t/waf-crisis-how-to-stop-accepting-flaky-components-and-start-replacing-them/138066">I posted a message in the Home Assistant Community</a> outlining the problems that were driving down the acceptance of my Home Automation hobby at my house.</p> <p>If 9 out of 10 devices work as they should, that 10th flaky device, which I think works most of the time but sometimes doesn’t work, is the thing my wife latches onto. She has gone from being pleasantly accepting of most things (and some automations have delighted her) to becoming more and more irritated.</p> <p>Examples of automations that delight:</p> <ul> <li>Kitchen cabinet LEDs light up when someone enters the room.</li> <li>Notifications when the garage door is closed.</li> <li>Colorful lightshow in our 9 bulb dining room chandelier.</li> </ul> <p>Examples of flakiness that irritates:</p> <ul> <li>Drip watering controller: was battery powered and her plants have died too many times from it dying without me realizing.</li> <li>Bedroom light switch: just wouldn’t turn off almost every evening for about a month!</li> </ul> <p>Anyway, the WAF was awfully low then. I couldn’t blame her as I find those things annoying as well… especially when they kill one of her outdoor plants.</p> <p>There were several things stopping me from replacing components like these.</p> <ul> <li><strong>Stubbornness.</strong> I don’t feel like I should have to replace a thing. It is supposed to work, so it should just work better!</li> <li><strong>Cost.</strong> I don’t want to replace one expensive thing, with another thing.</li> <li><strong>Uncertainty.</strong> Who knows if the thing I replace it with will work any better?</li> </ul> <p>I was finally able to convince myself the money I was saving for a CNC machine would be better spent on making our smart home less frustrating and … well, less brain dead.</p> <h3 id="making-a-list-checking-it-twice">Making a list, checking it twice</h3> <p>I made a list of things that are not working reliably so I could tackle them one at a time. Here is my list of problems and the solutions I implemented.</p> <table> <thead> <tr> <th>Problem</th> <th>Solution</th> </tr> </thead> <tbody> <tr> <td>Unreliable Wink Hub</td> <td>Replace Wink Hub with Z-Wave USB Stick and Lutron Pro Hub</td> </tr> <tr> <td>Smart Smoke Detectors, Wink only</td> <td>Replace with Z-Wave equivelent</td> </tr> <tr> <td>Unreliable Lutron switch</td> <td>Replace Wink with a Lutron Pro Hub</td> </tr> <tr> <td>Unreliable watering controller</td> <td>Install an outlet and build my own ESPHome based controller (In Progress)</td> </tr> <tr> <td>Node-Red automations</td> <td>I am currently migrating my Node-Red code to native Home Assistant code so I have one place to maintain my code.</td> </tr> </tbody> </table> <p>The advantage of the Lutron Pro hub is it allows Home Assistant to intercept the Pico Remote’s button press events. Here is how I took advantage of that feature to create Lutron Pico “Scene” remotes.</p> <ul> <li><strong>Dining Room</strong>: The primary 4 buttons control Hue bulbs. The center button toggles a secondary Family Room floor lamp which previously had no physical switch.</li> <li><strong>Play Room</strong>: I was controlling Insteon lamp modules with my wall mounted Pico Remote. I decided to simplify my system and replaced all Insteon lamp modules with refurbished white Hue bulbs. The center button controls a secondary floor lamp which previously had not physical switch.</li> </ul> <h3 id="conclusion">Conclusion</h3> <p>My family and I are much happier now that everything is working as expected much more of the time! I can spend more time create new automations, gadgets, and articles. Let me know if you have had the courage to replace unreliable modules in the comments below.</p> Sun, 29 Dec 2019 09:15:00 -0800 https://brianhanifin.com/posts/stop-accepting-flaky-components-replace-them/ https://brianhanifin.com/posts/stop-accepting-flaky-components-replace-them/ Alexa Alarm Wake Up Light Brian Hanifin <p>Thanks to the wonderful <a href="https://github.com/custom-components/alexa_media_player">Alexa Media Player</a> custom component, Home Assistant can make announcements and I can perform actions with my voice. I even have setup custom routines that are context aware. For example I can say “Alexa, turn on the lights” and depending on the room I am in, those lights will turn off! But, that’s content for another article.</p> <p>My 13 year old has been having more and more trouble waking up in the morning. I decided to help him wake up by turning a bedside lamp on at the same time as his Echo alarm. Luckily Alexa Media Player generates a <code class="language-yaml highlighter-rouge"><span class="s">next_alarm</span></code> sensor for us.</p> <h3 id="sensor">Sensor</h3> <p>While we could just have the light turn on when the alarm goes off, I have found it helpful to gradually increase the brightness starting 10 minutes before the alarm. So I created a <a href="https://www.home-assistant.io/integrations/template/">template sensor</a> to calculate a wake up light start time of 10 minutes before the next alarm.</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 </pre></td><td class="rouge-code"><pre><span class="na">platform</span><span class="pi">:</span> <span class="s">template</span> <span class="na">sensors</span><span class="pi">:</span> <span class="na">wakeup_boys_10min_early</span><span class="pi">:</span> <span class="na">friendly_name</span><span class="pi">:</span> <span class="s">Light Fade-in Start</span> <span class="na">icon_template</span><span class="pi">:</span> <span class="s">mdi:lightbulb-on-outline</span> <span class="na">entity_id</span><span class="pi">:</span> <span class="s">sensor.boys_room_next_alarm</span> <span class="na">value_template</span><span class="pi">:</span> <span class="pi">&gt;-</span> <span class="s">{%- set next_alarm = states('sensor.boys_room_next_alarm') -%}</span> <span class="s">{%- if next_alarm != "unknown" -%}</span> <span class="s">{%- set wakeup_time = next_alarm.split("T")[1].split("-")[0] -%}</span> <span class="s">{%- else -%}</span> <span class="s">{%- set wakeup_time = "06:00" -%}</span> <span class="s">{%- endif -%}</span> <span class="s">{%- set wakeup_hour = wakeup_time.split(':')[0] -%}</span> <span class="s">{%- set wakeup_minutes = wakeup_time.split(':')[1] -%}</span> <span class="s">{%- if (wakeup_minutes | int &gt;= 10) -%}</span> <span class="s">{{ "%0.02d:%0.02d"|format(wakeup_hour|int, wakeup_minutes|int -10) }}</span> <span class="s">{%- else -%}</span> <span class="s">{{ "%0.02d:%0.02d"|format(wakeup_hour|int -1, wakeup_minutes|int +50) }}</span> <span class="s">{%- endif -%}</span> </pre></td></tr></tbody></table></code></pre></div></div> <h3 id="automation">Automation</h3> <p>This automation is triggered when the current time matches <code class="language-yaml highlighter-rouge"><span class="s">sensor.wakeup_boys_10min_early</span></code>.</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 </pre></td><td class="rouge-code"><pre><span class="na">alias</span><span class="pi">:</span> <span class="s">wakeup_boys_10min_early</span> <span class="na">trigger</span><span class="pi">:</span> <span class="na">platform</span><span class="pi">:</span> <span class="s">template</span> <span class="na">value_template</span><span class="pi">:</span> <span class="pi">&gt;</span> <span class="s">{%- set next_alarm = states("sensor.boys_room_next_alarm") -%}</span> <span class="s">{%- if next_alarm != "unknown" -%}</span> <span class="s">{%- set wakeup_date = next_alarm.split("T")[0] -%}</span> <span class="s">{%- else -%}</span> <span class="s">{%- set wakeup_date = states('sensor.date') -%}</span> <span class="s">{%- endif -%}</span> <span class="s">{%- set start_time = states("sensor.wakeup_boys_10min_early") -%}</span> <span class="s">{%- if next_alarm != "unknown" -%}</span> <span class="s">{{ wakeup_date == states('sensor.date') and start_time == states('sensor.time') }}</span> <span class="s">{%- else -%}</span> <span class="s">false</span> <span class="s">{%- endif -%}</span> <span class="na">action</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">service</span><span class="pi">:</span> <span class="s">script.turn_on</span> <span class="na">data_template</span><span class="pi">:</span> <span class="na">entity_id</span><span class="pi">:</span> <span class="s">script.wakeup_boys_light_start</span> </pre></td></tr></tbody></table></code></pre></div></div> <h3 id="script">Script</h3> <p>The script is straight forward. It turns on the light and immediately dims the light to 20%. After a minute delay the light brightness is increased by 10%. The brightness is increased by 10% for 10 minutes until we are at 100% brightness! I know there are fancy python scripts to gradually increase the light. But 10% increments are good enough for me.</p> <p>(I shortened the code below for brevity. You can see the full script on my <a href="https://github.com/brianhanifin/Home-Assistant-Config/blob/master/scripts/wakeup/wakeup_boys_light_start.yaml">Github Repository</a>.)</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 </pre></td><td class="rouge-code"><pre><span class="na">wakeup_boys_light_start</span><span class="pi">:</span> <span class="na">sequence</span><span class="pi">:</span> <span class="c1"># Start lights at ~20% and increment by ~10% every minute for 9 minutes.</span> <span class="pi">-</span> <span class="na">service</span><span class="pi">:</span> <span class="s">light.turn_on</span> <span class="na">data</span><span class="pi">:</span> <span class="na">entity_id</span><span class="pi">:</span> <span class="s">light.boys_wakeup</span> <span class="pi">-</span> <span class="na">service</span><span class="pi">:</span> <span class="s">light.turn_on</span> <span class="na">data</span><span class="pi">:</span> <span class="na">entity_id</span><span class="pi">:</span> <span class="s">light.boys_wakeup</span> <span class="na">brightness</span><span class="pi">:</span> <span class="m">50</span> <span class="pi">-</span> <span class="na">delay</span><span class="pi">:</span> <span class="s">00:01:00</span> <span class="pi">-</span> <span class="na">condition</span><span class="pi">:</span> <span class="s">state</span> <span class="na">entity_id</span><span class="pi">:</span> <span class="s">light.boys_wakeup</span> <span class="na">state</span><span class="pi">:</span> <span class="s1">'</span><span class="s">on'</span> <span class="pi">-</span> <span class="na">service</span><span class="pi">:</span> <span class="s">light.turn_on</span> <span class="na">data</span><span class="pi">:</span> <span class="na">entity_id</span><span class="pi">:</span> <span class="s">light.boys_wakeup</span> <span class="na">brightness</span><span class="pi">:</span> <span class="m">75</span> <span class="s">.</span> <span class="s">.</span> <span class="s">.</span> <span class="pi">-</span> <span class="na">delay</span><span class="pi">:</span> <span class="s">00:01:00</span> <span class="pi">-</span> <span class="na">condition</span><span class="pi">:</span> <span class="s">state</span> <span class="na">entity_id</span><span class="pi">:</span> <span class="s">light.boys_wakeup</span> <span class="na">state</span><span class="pi">:</span> <span class="s1">'</span><span class="s">on'</span> <span class="pi">-</span> <span class="na">service</span><span class="pi">:</span> <span class="s">light.turn_on</span> <span class="na">data</span><span class="pi">:</span> <span class="na">entity_id</span><span class="pi">:</span> <span class="s">light.boys_wakeup</span> <span class="na">brightness</span><span class="pi">:</span> <span class="m">255</span> </pre></td></tr></tbody></table></code></pre></div></div> <h3 id="lovelace-user-interface">Lovelace User Interface</h3> <p>This represents the information I need at a glance.</p> <p><img src="/assets/img/2019-12-20-alexa-alarm.png" alt="My Alexa Alarm Lovelace UI" /></p> Sat, 21 Dec 2019 11:00:00 -0800 https://brianhanifin.com/posts/next-alexa-alarm-wakeup-light/ https://brianhanifin.com/posts/next-alexa-alarm-wakeup-light/ HOWTO Resolve Lutron Smart Bridge Pro Connection Issues Brian Hanifin <p>I have a <a href="https://www.amazon.com/gp/product/B00Z8AXQCQ/ref=as_li_qf_asin_il_tl?ie=UTF8&amp;tag=brianhanifi0d-20&amp;creative=9325&amp;linkCode=as2&amp;creativeASIN=B00Z8AXQCQ&amp;linkId=caf32d43e890dcb43592d6cb797bf1bd">Lutron Caseta Wireless Smart Bridge Pro (L-BDGPRO2-WH)</a>. I was unable to connect to it with the app on my iPhone. I would get a “Cannot connect to your Lutron system.” error every time I tried.</p> <p>After lots of troubleshooting, I was able to resolve it. If you have this problem try the following:</p> <ol> <li>Delete the Lutron app.</li> <li>Re-install the Lutron app.</li> <li>Create a new account instead of logging into your old one.</li> <li>Use a different Email address when you create this account.</li> <li>Continue following the process until the bridge is added to the app!</li> </ol> <p>I wanted to share this because I could not find anyone else suggesting this solution after searching for days on the Internet.</p> Thu, 12 Dec 2019 08:00:00 -0800 https://brianhanifin.com/posts/howto-resolve-lutron-smart-bridge-pro-connection-issues/ https://brianhanifin.com/posts/howto-resolve-lutron-smart-bridge-pro-connection-issues/ Making a dumb light switch smart with ESPHome and Home Assistant Brian Hanifin <h2 id="project-smart-light-switch-with-offline-fail-over">Project: Smart light switch with offline fail-over</h2> <h3 id="goals">Goals</h3> <ol> <li>Create a light switch that is decoupled from power delivery so the 9 Hue Bulbs in my Dining Room Chandelier can always be powered, while allowing use of the light switch on/off paddle.</li> <li>Provide a fail-over mechanism that allows the switch to operate even when Home Assistant is unavailable.</li> </ol> <h3 id="purchased-supplies">Purchased Supplies</h3> <ol> <li><a href="https://www.amazon.com/gp/product/B07G33LNDY?ie=UTF8&amp;tag=brianhanifi0d-20&amp;camp=1789&amp;linkCode=xm2&amp;creativeASIN=B07G33LNDY">Shelly1</a> (or a Sonoff Basic, or other ESPHome compatible board).</li> <li><a href="https://www.amazon.com/gp/product/B0069F4CXQ?ie=UTF8&amp;tag=brianhanifi0d-20&amp;camp=1789&amp;linkCode=xm2&amp;creativeASIN=B0069F4CXQ">Electrical wire</a> (Romex 12/2, solid wire, 2 covered conductors plus one ground conductor).</li> <li>Wire Nuts, <a href="https://www.amazon.com/gp/product/B07DW1QZF5/ref=as_li_tl?ie=UTF8&amp;camp=1789&amp;creative=9325&amp;creativeASIN=B07DW1QZF5&amp;linkCode=as2&amp;tag=brianhanifi0d-20&amp;linkId=b9b4a1708258bbb1a213949082a0eb84">Non-twist Connectors</a>, or <a href="https://www.amazon.com/gp/product/B01N5JXOVF?ie=UTF8&amp;tag=brianhanifi0d-20&amp;camp=1789&amp;linkCode=xm2&amp;creativeASIN=B01N5JXOVF">Wago Connectors</a>.</li> </ol> <p><em>The above links include my Amazon Affilite id.</em></p> <h3 id="goal-1-make-the-dumb-light-switch-talk-to-home-assistant">Goal #1: Make the dumb light switch talk to Home Assistant</h3> <p>I started with the following <a href="https://esphome.io/">ESPHome</a> code fragment which uses the Home Assistant API to toggle the smart bulbs on or off when the wall switch is flipped. This worked great and I could have stopped there. But I want to make it work if Home Assistant wasn’t available.</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 </pre></td><td class="rouge-code"><pre><span class="na">binary_sensor</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">platform</span><span class="pi">:</span> <span class="s">gpio</span> <span class="na">pin</span><span class="pi">:</span> <span class="na">number</span><span class="pi">:</span> <span class="s">GPIO5</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Wall Switch</span> <span class="na">id</span><span class="pi">:</span> <span class="s">button</span> <span class="na">filters</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">delayed_on</span><span class="pi">:</span> <span class="s">10ms</span> <span class="pi">-</span> <span class="na">delayed_off</span><span class="pi">:</span> <span class="s">10ms</span> <span class="na">on_state</span><span class="pi">:</span> <span class="pi">-</span> <span class="s">homeassistant.service</span><span class="pi">:</span> <span class="na">service</span><span class="pi">:</span> <span class="s">light.toggle</span> <span class="na">data</span><span class="pi">:</span> <span class="na">entity_id</span><span class="pi">:</span> <span class="s">light.dining_room</span> <span class="na">switch</span><span class="pi">:</span> <span class="na">platform</span><span class="pi">:</span> <span class="s">gpio</span> <span class="na">id</span><span class="pi">:</span> <span class="s">relay</span> <span class="na">pin</span><span class="pi">:</span> <span class="s">GPIO4</span> <span class="na">restore_mode</span><span class="pi">:</span> <span class="s">ALWAYS_ON</span> </pre></td></tr></tbody></table></code></pre></div></div> <h3 id="goal-2-fail-over">Goal #2: Fail-over</h3> <p>So, we need a way to check to see if Home Assistant is connected, so we can toggle the light with the relay instead. Luckily ESPHome provides a condition for checking if Home Assistant is connected: <a href="https://esphome.io/components/api.html"><em>api.connected</em></a>.</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1 2 3 4 </pre></td><td class="rouge-code"><pre><span class="na">if</span><span class="pi">:</span> <span class="na">condition</span><span class="pi">:</span> <span class="s">api.connected</span><span class="pi">:</span> <span class="na">then</span><span class="pi">:</span> </pre></td></tr></tbody></table></code></pre></div></div> <p>Next, we check to see if the relay is on, and if it is off turn it on. We need the relay to be on before Home Assistant can turn on our smart bulbs on.</p> <blockquote> <p><strong>Note</strong></p> <p>In theory the relay should always be on. However there is one scenario, which will be revealed soon, in which the relay would be off.</p> </blockquote> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1 2 3 4 5 6 7 8 9 10 </pre></td><td class="rouge-code"><pre> <span class="pi">-</span> <span class="na">if</span><span class="pi">:</span> <span class="na">condition</span><span class="pi">:</span> <span class="s">switch.is_off</span><span class="pi">:</span> <span class="s">relay</span> <span class="na">then</span><span class="pi">:</span> <span class="pi">-</span> <span class="s">switch.turn_on</span><span class="pi">:</span> <span class="s">relay</span> <span class="pi">-</span> <span class="s">homeassistant.service</span><span class="pi">:</span> <span class="na">service</span><span class="pi">:</span> <span class="s">light.turn_on</span> <span class="na">data</span><span class="pi">:</span> <span class="na">entity_id</span><span class="pi">:</span> <span class="s">light.dining_room</span> </pre></td></tr></tbody></table></code></pre></div></div> <p>If the relay is already on then ask Home Assistant to toggle the light on or off.</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1 2 3 4 5 6 </pre></td><td class="rouge-code"><pre> <span class="na">else</span><span class="pi">:</span> <span class="pi">-</span> <span class="s">homeassistant.service</span><span class="pi">:</span> <span class="na">service</span><span class="pi">:</span> <span class="s">light.toggle</span> <span class="na">data</span><span class="pi">:</span> <span class="na">entity_id</span><span class="pi">:</span> <span class="s">light.dining_room</span> </pre></td></tr></tbody></table></code></pre></div></div> <p>Now we come to the “fail-over” bit. This is the <em>else</em> condition for when <code class="language-yaml highlighter-rouge"><span class="s">api.connected</span></code> is false, meaning that ESPHome has lost connection to Home Assistant!</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1 2 </pre></td><td class="rouge-code"><pre><span class="na">else</span><span class="pi">:</span> <span class="pi">-</span> <span class="s">switch.toggle</span><span class="pi">:</span> <span class="s">relay</span> </pre></td></tr></tbody></table></code></pre></div></div> <p>This code fragment simply turns the Shelly1’s internal relay from <em>on to off</em> or <em>off to on</em> when the physical light switch is toggled.</p> <h3 id="final-code">Final Code</h3> <p>If you have ever done programming before you know may be aware a common practice is to define “constant” variables at the top of your code. Well, that is what <a href="https://esphome.io/guides/configuration-types.html?#substitutions">ESPHome’s <em>substitutions</em> feature</a> provides.</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 </pre></td><td class="rouge-code"><pre><span class="nn">---</span> <span class="c1"># Shelly 1 Power Module</span> <span class="c1"># Location: Dining Room Light Switch</span> <span class="c1">#</span> <span class="na">substitutions</span><span class="pi">:</span> <span class="na">project</span><span class="pi">:</span> <span class="s">Shelly1 </span><span class="m">01</span> <span class="na">id</span><span class="pi">:</span> <span class="s">shelly1_01</span> <span class="na">button_gpio</span><span class="pi">:</span> <span class="s">GPIO5</span> <span class="na">relay_gpio</span><span class="pi">:</span> <span class="s">GPIO4</span> <span class="na">hass_light</span><span class="pi">:</span> <span class="s">light.dining_room</span> <span class="na">esphome</span><span class="pi">:</span> <span class="na">name</span><span class="pi">:</span> <span class="s">$id</span> <span class="na">platform</span><span class="pi">:</span> <span class="s">ESP8266</span> <span class="na">board</span><span class="pi">:</span> <span class="s">esp01_1m</span> <span class="na">wifi</span><span class="pi">:</span> <span class="na">ssid</span><span class="pi">:</span> <span class="kt">!secret</span> <span class="s">wifi_ssid</span> <span class="na">password</span><span class="pi">:</span> <span class="kt">!secret</span> <span class="s">wifi_pass</span> <span class="na">ota</span><span class="pi">:</span> <span class="na">logger</span><span class="pi">:</span> <span class="c1"># Home Assistant API</span> <span class="na">api</span><span class="pi">:</span> <span class="na">script</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">id</span><span class="pi">:</span> <span class="s">hass_light_toggle</span> <span class="na">then</span><span class="pi">:</span> <span class="na">if</span><span class="pi">:</span> <span class="na">condition</span><span class="pi">:</span> <span class="s">api.connected</span><span class="pi">:</span> <span class="na">then</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">if</span><span class="pi">:</span> <span class="na">condition</span><span class="pi">:</span> <span class="s">switch.is_off</span><span class="pi">:</span> <span class="s">relay</span> <span class="na">then</span><span class="pi">:</span> <span class="c1"># Turn the relay back on and turn on the light.</span> <span class="pi">-</span> <span class="s">switch.turn_on</span><span class="pi">:</span> <span class="s">relay</span> <span class="pi">-</span> <span class="s">homeassistant.service</span><span class="pi">:</span> <span class="na">service</span><span class="pi">:</span> <span class="s">light.turn_on</span> <span class="na">data</span><span class="pi">:</span> <span class="na">entity_id</span><span class="pi">:</span> <span class="s">$hass_light</span> <span class="na">else</span><span class="pi">:</span> <span class="c1"># Have Home Assistant toggle the light.</span> <span class="pi">-</span> <span class="s">homeassistant.service</span><span class="pi">:</span> <span class="na">service</span><span class="pi">:</span> <span class="s">light.toggle</span> <span class="na">data</span><span class="pi">:</span> <span class="na">entity_id</span><span class="pi">:</span> <span class="s">$hass_light</span> <span class="na">else</span><span class="pi">:</span> <span class="c1"># When HA is unavailable, toggle the relay.</span> <span class="pi">-</span> <span class="s">switch.toggle</span><span class="pi">:</span> <span class="s">relay</span> <span class="na">binary_sensor</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">platform</span><span class="pi">:</span> <span class="s">gpio</span> <span class="na">pin</span><span class="pi">:</span> <span class="na">number</span><span class="pi">:</span> <span class="s">$button_gpio</span> <span class="na">name</span><span class="pi">:</span> <span class="s">$project Wall Switch</span> <span class="na">id</span><span class="pi">:</span> <span class="s">button</span> <span class="na">filters</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">delayed_on</span><span class="pi">:</span> <span class="s">10ms</span> <span class="pi">-</span> <span class="na">delayed_off</span><span class="pi">:</span> <span class="s">10ms</span> <span class="na">on_state</span><span class="pi">:</span> <span class="pi">-</span> <span class="s">script.execute</span><span class="pi">:</span> <span class="s">hass_light_toggle</span> <span class="na">switch</span><span class="pi">:</span> <span class="na">platform</span><span class="pi">:</span> <span class="s">gpio</span> <span class="na">id</span><span class="pi">:</span> <span class="s">relay</span> <span class="na">pin</span><span class="pi">:</span> <span class="s">$relay_gpio</span> <span class="na">restore_mode</span><span class="pi">:</span> <span class="s">ALWAYS_ON</span> </pre></td></tr></tbody></table></code></pre></div></div> <h3 id="its-not-a-bug-its-a-feature">It’s not a bug, its a feature</h3> <p>The relay can only be turned off when Home Assistant is offline when the light was turned off by the wall switch. So, when Home Assistant comes back online that smart light will be unavailable until the wall switch is flipped again.</p> <p>Let’s call this an intended side-effect. If we made the relay somehow turn back on automatically when it connects to Home Assistant again, the smart bulb would turn on! I can tell you from experience wives really don’t like your Home Automation hobby when the bedroom lights turn on in the middle of the night!</p> <h3 id="special-thanks">Special Thanks</h3> <p>Thank you to Mauricio Bonani (@mbonani) of <a href="https://bonani.tech/">bonani.tech</a> for encouraging me to create a blog as a knowledge dump that I can refer back to in the future. I hope others find some of my articles as useful and I have found Mauricio’s articles.</p> <h3 id="feedback">Feedback</h3> <p>Thank you for visiting my new blog! This is my first article, and I would really appreciate your feedback. Please stick around as I will be posting articles at least once a week for the next few months. I already have ideas set aside for 29 more articles on <a href="/tags/home-assistant/">Home Assistant</a> and <a href="/tags/esphome/">ESPHome</a>, not to mention potential tips on creating designs for laser cutters!</p> <p>To hold you until my next article please visit my <a href="https://github.com/brianhanifin/esphome-config">ESPHome Github Repository</a>.</p> Wed, 11 Dec 2019 07:00:00 -0800 https://brianhanifin.com/posts/esphome-shelly1-dumb-light-switch-smart/ https://brianhanifin.com/posts/esphome-shelly1-dumb-light-switch-smart/