diff --git a/atom.xml b/atom.xml index 24f9bd724a..d46f67e9e8 100644 --- a/atom.xml +++ b/atom.xml @@ -4,7 +4,7 @@ <![CDATA[Home Assistant]]> - 2016-08-07T20:56:13+00:00 + 2016-08-07T21:33:33+00:00 https://home-assistant.io/ @@ -13,6 +13,159 @@ Octopress + + <![CDATA[Optimizing the Home Assistant mobile web app]]> + + 2016-08-07T19:36:00+00:00 + https://home-assistant.io/blog/2016/08/07/optimizing-the-home-assistant-mobile-web-app + This blog post will go into detail about the recent performance optimizations that went into the Home Assistant front end. For people not familiar with the app, check out the demo and the source.

+ +

TL; DR: Don’t hack the framework, separate responsibilities, ship less, use service workers, use (future) web standards.

+ +

This year at Google I/O I saw Monica from the Polymer team talk about web components and performance. In her talk she mentions a mantra that they use in the Polymer team to make things fast: Do less and be lazy.

+ +

Do less and be lazy. It sounds so obvious and it took a while before it started to dawn on me. I think most of the code I write is pretty fast, but I don’t often stop to take a harder look at how and when it runs in practice. When do we need the result, can it be postponed?

+ +

And thus started my journey to take a critical look at how the Home Assistant app was working and how to make things faster. Below is the list of the different things that I did to make it fast.

+ +

I hope this list can be useful to other people, as a guide for optimizing their own apps or for avoiding pitfalls when building a new one.

+ +

The first thing to do is to measure. The Home Assistant front end is a mobile web app, so we shouldn’t measure this on a machine with 8 cores and gigabytes of ram but instead measure on devices you expect a mobile web app to run: phones. Below are two timelines recorded with Home Assistant 0.18.2 (pre-optimizations) and Google Chrome 53. On my Mac the app starts in 1400 miliseconds and on my Nexus 5x in ~6500 miliseconds (~4.5 times slower!).

+ +

+ Timeline of loading the front end in Home Assistant 0.18.2 +

+ +

Although the app takes 6500 milliseconds to load on my phone, it would perform well afterwards. Still, that initial load is unacceptable. You expect to open an app on your phone and be able to use it, quickly. After I applied all the changes described below, I managed to reduce startup time to 900 miliseconds (-35%) on my Mac and 2400 miliseconds (-63%) on my Nexus 5x. Check out the demo here.

+ +

+ diagram showing old and new loading times next to one another + Timeline of loading the front end in Home Assistant 0.26 +

+ + + +

Technology

+ +

The Home Assistant front end consists of two parts. There is Home Assistant JS, which controls all data and interaction between JavaScript and the server. It is a Flux architecture using NuclearJS and ImmutableJS. The UI is implemented by Home Assistant Polymer using Polymer and web components.

+ +

Don’t hack the framework

+ +

I thought to be smart. I split out the JavaScript part of all web components and bundled them separately using Webpack so that I could use ES2015 via BabelJS (architecture). This is not how Polymer components are written and it meant that I was unable to use any of the tooling that is available in the community or easily split up the bundle (more on this later).

+ +

So I went ahead and backported all my web components back from shiny beautiful ES6 to ES5. And you know what? It’s not that bad. Yes, not being able to use the concise object notation and arrow functions make your code more verbose. But in the end it is the same code that is running in browsers.

+ +

Another benefit of having each web component contain their own script tag is that the browser will process them one by one, allowing the browser to render our loading spinner animation in between.

+ +

As you can see in the timelines, we were able to get rid of most of the blocking component loading.

+ +

+ Timeline of loading the front end before and after the optimization +

+ +

Separate responsibilities

+ +

Whenever you learn a new technology, you feel like you’ve learned a new superpower. Wow, I can do all this with only 2 lines?! I had the same with bundling.

+ +

I was initially very focused on shipping just a single file with everything that my app needed. The entry point would be my main component which would require all of its Flux and UI dependencies. Then, just before it all would be rendered, it would check if there is authentication and start the data fetching.

+ +

This is a very bad pattern. This means that you will not start any data fetching until your UI is ready to render. Instead, you want your data to be fetched as soon as possible, and while the request is out to the server you want the page to load all your UI components.

+ +

To accomplish this I extracted the application core out of the main bundle. In the current optimized version it’s 31.1kb gzip’d. It is loaded before any other scripts so that it can start fetching data as soon as possible.

+ +

+ Timeline of loading the front end before and after the optimization +

+ +

When the data does come back before the UI is done loading, we can process it before we start rendering the UI because of all the web components being processed individually. This means that we don’t have to show a loading screen the first time our components render – we can just render the components with the data they require.

+ +

Ship less

+ +

The theory behind this one is simple: if we manage to ship less code, the browser has to process less code and it will start faster.

+ +

Only include the components for the page that you will show

+ +

The Home Assistant mobile web application has 10 different panels (pages). Besides that, it also has a dialog for each type of device to show more info. That’s a lot of components and screens of which only a very small set is needed at the start. That means that we are shipping a lot of unnecessary data that the browser has to process before our initial render!

+ +

I broke up each panel of the app into a separate bundle that will be loaded on demand. This saved 250 kilobytes (pre-gzip) on just the embedded map alone! This change, however, required some significant changes to our build process.

+ +

Breaking up an app in JavaScript is complex because each module explicitly imports their dependencies. This has to continue to work in your browser after breaking it up in multiple files. Web components do not have this problem as it’s part of the platform and thus your browser is the registry! An unregistered web component will be rendered as an empty span element until the element gets registered. Loading order is not important.

+ +
+
// Example of the flexibility of web components.
+var spinner = document.createElement('paper-spinner');
+spinner.active = true;
+document.body.appendChild(spinner);
+
+
+
+ +

Because the browser tracks your web components, creating standalone bundles for parts of the app is easy:

+ +
    +
  • Find all dependencies included in the main bundle (using hydrolysis)
  • +
  • Create individual bundles of each panel (page) but filter out the dependencies included in main bundle.
  • +
+ +

The build script that bundles and minifies the main bundle and panel bundles is <100 lines.

+ +

Change the JavaScript bundler to Rollup

+ +

Core.js is still pure JavaScript and requires bundling. In my journey to get a smaller bundle, I went from Webpack to Webpack 2 to Rollup. At each step the bundle got smaller. Rollup is the big winner here because it doesn’t wrap all your modules in function calls but instead concatenates all files with minimal changes to make it work. This not only reduces the file size but also the loading speed. This is because the JavaScript engine will no longer have to invoke a function to resolve each import, it’s doing less work. This might not mean much for a computer but on a phone, everything counts.

+ +

Scrutinize dependencies

+ +

If the goal is to ship less, it’s time to take a good look at dependencies. It’s so often that we decide to fall back to yet another NPM package that makes our life a little easier but comes at the cost of size – size usually taken up by functionality that you might never need.

+ +

Remove Lodash

+

I realized that I only used a few methods of lodash. Lodash (and previously underscore) used to be one of the dependencies that would always be one of the first things that I would add to any project I start. But I could no longer justify it in the case of Home Assistant. Even with dead tree shaking it was not worth including it. Yes, they support a lot of edge cases but those were not relevant to my use case. And standalone lodash packages are still huge. The only thing that I couldn’t replace with a few lines of my own code was debounce. However I found a 40 line replacement.

+ +

Replace moment.js with Fecha

+ +

Moment.js is one of those power libraries. It is able to handle any date problem that you can throw at it. But this obviously comes at the cost of size. Fecha is a date formatting library at ~8% the size of moment.js (only 4.7kb pre-gzip). The only thing that it does not contain is date manipulation, which was something that was not being used.

+ +

Use Service worker to instantly load the app

+ +

Using a service worker we’re able to store all app components and core javascript in the browser. This means that after their first visit, the browser will only have to go to the network to fetch the latest data from the server.

+ +

Creating a service worker is easy using sw-precache, a service worker generation tool.

+ +

When a browser does not support service workers, Home Assistant will serve fingerprinted assets that are aggressively cached. Only when the content changes will the client redownload the asset.

+ +

Using fingerprinting with sw-precache required jumping through a few hoops. The final build script can be found here.

+ +

Make it feel fast

+ +

This one is more psychological: no one likes staring at a white screen because white screens are ambiguous: are we loading something, is there a crappy connection or maybe even a script error? That’s why it is very important to render something on the screen to show that the rest is being loaded, and as quickly as possible.

+ +

The Home Assistant landing page contains just enough CSS and HTML to render the loading screen minus the animations.

+ +

Now that the app is fast enough, I might swap out moving from a lite loading screen to drawing an empty toolbar. This makes it look like the UI is almost there.

+ +

Using a framework build on web standards

+ +

I left this to the end of the list, mainly because I had no influence on this. Polymer just happened to ship an update while I was optimizing the application which gave a big boost to the loading time.

+ +

By using Polymer we have the ability to use tomorrow’s web standards today. This is powered by polyfills. A polyfill will use JavaScript to simulate the behavior that the web standard would have taken care of. As browsers progress, more work can move from the polyfills back to the browsers. This is great because browsers will be able to optimize the work better and thus be faster.

+ +

Polymer 1.6 was introduced at the end of June and allowed the app to take advantage of native CSS variables in Chrome and Firefox. It also introduced lazy registration. Both greatly sped up our loading times.

+ +

Future optimizations

+ +

A lot of optimizations have been applied but this journey will never be over. There are still a lot of opportunities to make things even faster. Some ideas that are on my list to explore:

+ +
    +
  • Use shadow DOM instead of shady DOM polyfill.
  • +
  • Use closure compiler to optimize the JavaScript.
  • +
  • Reduce the number of icons that are loaded.
  • +
  • Embed initial API response in served page if not using a service worker.
  • +
  • Reduce size of initial bundle by moving out all things that are not visible for initial paint. For example the dialogs that show more info about entities.
  • +
  • Prefetch the other pages using <link rel="preload" …>
  • +
+ +]]>
+
+ <![CDATA[Laundry Sensors with NodeMCU and Home Assistant]]> @@ -1494,20 +1647,6 @@ target_dir /tmp -]]> - - - - <![CDATA[Talk: Automating your home with Home Assistant (OpenIoT Summit)]]> - - 2016-05-06T14:09:00+00:00 - https://home-assistant.io/blog/2016/05/06/open-iot-summit-talk - At the beginning of April I gave a talk about Home Assistant at the OpenIoT summit in San Diego. I talk about the Home Assistant architecture and explain how to get started integrating your devices. Big thanks to my employer AppFolio (we’re hiring!) for letting me attend. Slides.

- -
- -
- ]]>
diff --git a/blog/2014/12/18/website-launched/index.html b/blog/2014/12/18/website-launched/index.html index d1bde399a7..c1f6cafc82 100644 --- a/blog/2014/12/18/website-launched/index.html +++ b/blog/2014/12/18/website-launched/index.html @@ -134,6 +134,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -179,6 +180,12 @@ diff --git a/blog/2014/12/26/home-control-home-automation-and-the-smart-home/index.html b/blog/2014/12/26/home-control-home-automation-and-the-smart-home/index.html index 849572e49b..ff6c378c76 100644 --- a/blog/2014/12/26/home-control-home-automation-and-the-smart-home/index.html +++ b/blog/2014/12/26/home-control-home-automation-and-the-smart-home/index.html @@ -189,6 +189,7 @@ This article will try to explain how they all relate.

  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -234,6 +235,12 @@ This article will try to explain how they all relate.

    diff --git a/blog/2015/01/04/hey-pushbullet-nice-talking-to-you/index.html b/blog/2015/01/04/hey-pushbullet-nice-talking-to-you/index.html index ce6cf4eafe..45cc797a7f 100644 --- a/blog/2015/01/04/hey-pushbullet-nice-talking-to-you/index.html +++ b/blog/2015/01/04/hey-pushbullet-nice-talking-to-you/index.html @@ -173,6 +173,7 @@ api_key=ABCDEFGHJKLMNOPQRSTUVXYZ
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -218,6 +219,12 @@ api_key=ABCDEFGHJKLMNOPQRSTUVXYZ diff --git a/blog/2015/01/11/bootstrapping-your-setup-with-discovery/index.html b/blog/2015/01/11/bootstrapping-your-setup-with-discovery/index.html index 21d415b96e..8695afefdf 100644 --- a/blog/2015/01/11/bootstrapping-your-setup-with-discovery/index.html +++ b/blog/2015/01/11/bootstrapping-your-setup-with-discovery/index.html @@ -148,6 +148,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -193,6 +194,12 @@ diff --git a/blog/2015/01/13/nest-in-da-house/index.html b/blog/2015/01/13/nest-in-da-house/index.html index c0dbe72747..280de57081 100644 --- a/blog/2015/01/13/nest-in-da-house/index.html +++ b/blog/2015/01/13/nest-in-da-house/index.html @@ -151,6 +151,7 @@ password=YOUR_PASSWORD
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -196,6 +197,12 @@ password=YOUR_PASSWORD diff --git a/blog/2015/01/24/release-notes/index.html b/blog/2015/01/24/release-notes/index.html index f532afa272..cffec8b8ef 100644 --- a/blog/2015/01/24/release-notes/index.html +++ b/blog/2015/01/24/release-notes/index.html @@ -157,6 +157,7 @@ Home Assistant now supports --open-ui and --demo-mode
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -202,6 +203,12 @@ Home Assistant now supports --open-ui and --demo-mode diff --git a/blog/2015/02/08/looking-at-the-past/index.html b/blog/2015/02/08/looking-at-the-past/index.html index 8b68d00f05..949a49e81d 100644 --- a/blog/2015/02/08/looking-at-the-past/index.html +++ b/blog/2015/02/08/looking-at-the-past/index.html @@ -165,6 +165,7 @@ Events are saved in a local database. Google Graphs is used to draw the graph. D
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -210,6 +211,12 @@ Events are saved in a local database. Google Graphs is used to draw the graph. D diff --git a/blog/2015/02/24/streaming-updates/index.html b/blog/2015/02/24/streaming-updates/index.html index 5ffcad5405..d73edbf03e 100644 --- a/blog/2015/02/24/streaming-updates/index.html +++ b/blog/2015/02/24/streaming-updates/index.html @@ -150,6 +150,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -195,6 +196,12 @@ diff --git a/blog/2015/03/01/home-assistant-migrating-to-yaml/index.html b/blog/2015/03/01/home-assistant-migrating-to-yaml/index.html index 863f73ee4f..ead0393b97 100644 --- a/blog/2015/03/01/home-assistant-migrating-to-yaml/index.html +++ b/blog/2015/03/01/home-assistant-migrating-to-yaml/index.html @@ -140,6 +140,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -185,6 +186,12 @@ diff --git a/blog/2015/03/08/new-logo/index.html b/blog/2015/03/08/new-logo/index.html index 86546ccc1f..7c53175158 100644 --- a/blog/2015/03/08/new-logo/index.html +++ b/blog/2015/03/08/new-logo/index.html @@ -141,6 +141,7 @@ The old logo, the new detailed logo and the new simple logo.
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -186,6 +187,12 @@ The old logo, the new detailed logo and the new simple logo. diff --git a/blog/2015/03/11/release-notes/index.html b/blog/2015/03/11/release-notes/index.html index abcf7fe612..e15243b0f5 100644 --- a/blog/2015/03/11/release-notes/index.html +++ b/blog/2015/03/11/release-notes/index.html @@ -180,6 +180,7 @@ An initial version of voice control for Home Assistant has landed. The current i
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -225,6 +226,12 @@ An initial version of voice control for Home Assistant has landed. The current i diff --git a/blog/2015/03/22/release-notes/index.html b/blog/2015/03/22/release-notes/index.html index 05a5a89dcf..07a26dd943 100644 --- a/blog/2015/03/22/release-notes/index.html +++ b/blog/2015/03/22/release-notes/index.html @@ -217,6 +217,7 @@ I (Paulus) have contributed a scene component. A user can create scenes that cap
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -262,6 +263,12 @@ I (Paulus) have contributed a scene component. A user can create scenes that cap diff --git a/blog/2015/04/25/release-notes/index.html b/blog/2015/04/25/release-notes/index.html index a4db2a6499..dd8e7a4614 100644 --- a/blog/2015/04/25/release-notes/index.html +++ b/blog/2015/04/25/release-notes/index.html @@ -228,6 +228,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -273,6 +274,12 @@ diff --git a/blog/2015/05/09/utc-time-zone-awareness/index.html b/blog/2015/05/09/utc-time-zone-awareness/index.html index 70ff919cc2..a7f073874d 100644 --- a/blog/2015/05/09/utc-time-zone-awareness/index.html +++ b/blog/2015/05/09/utc-time-zone-awareness/index.html @@ -163,6 +163,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -208,6 +209,12 @@ diff --git a/blog/2015/05/14/release-notes/index.html b/blog/2015/05/14/release-notes/index.html index 44d3ad53a1..2ddf4cdfc2 100644 --- a/blog/2015/05/14/release-notes/index.html +++ b/blog/2015/05/14/release-notes/index.html @@ -255,6 +255,7 @@ Before diving into the newly supported devices and services, I want to highlight
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -300,6 +301,12 @@ Before diving into the newly supported devices and services, I want to highlight diff --git a/blog/2015/06/10/release-notes/index.html b/blog/2015/06/10/release-notes/index.html index 4c785c18b0..a005a90992 100644 --- a/blog/2015/06/10/release-notes/index.html +++ b/blog/2015/06/10/release-notes/index.html @@ -308,6 +308,7 @@ This switch platform allows you to control your motion detection setting on your
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -353,6 +354,12 @@ This switch platform allows you to control your motion detection setting on your diff --git a/blog/2015/07/11/ip-cameras-arduino-kodi-efergy-support/index.html b/blog/2015/07/11/ip-cameras-arduino-kodi-efergy-support/index.html index c3717c3af9..ab272f6311 100644 --- a/blog/2015/07/11/ip-cameras-arduino-kodi-efergy-support/index.html +++ b/blog/2015/07/11/ip-cameras-arduino-kodi-efergy-support/index.html @@ -260,6 +260,7 @@ Fabian has added support for Forecast.io to g
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -305,6 +306,12 @@ Fabian has added support for Forecast.io to g diff --git a/blog/2015/08/09/mqtt-raspberry-pi-squeezebox-asuswrt-support/index.html b/blog/2015/08/09/mqtt-raspberry-pi-squeezebox-asuswrt-support/index.html index da856ffbaa..a28fce05af 100644 --- a/blog/2015/08/09/mqtt-raspberry-pi-squeezebox-asuswrt-support/index.html +++ b/blog/2015/08/09/mqtt-raspberry-pi-squeezebox-asuswrt-support/index.html @@ -249,6 +249,7 @@ Support for Temper temperature sensors has been contributed by Follow Home Assistant on Twitter +
  • @@ -294,6 +295,12 @@ Support for Temper temperature sensors has been contributed by +
  • + Optimizing the Home Assistant mobile web app +
  • + + +
  • Laundry Sensors with NodeMCU and Home Assistant
  • @@ -317,12 +324,6 @@ Support for Temper temperature sensors has been contributed by - Visualize your IoT data - - - diff --git a/blog/2015/08/17/verisure-and-modern-tp-link-router-support/index.html b/blog/2015/08/17/verisure-and-modern-tp-link-router-support/index.html index bc7f981421..6ef61b66c3 100644 --- a/blog/2015/08/17/verisure-and-modern-tp-link-router-support/index.html +++ b/blog/2015/08/17/verisure-and-modern-tp-link-router-support/index.html @@ -159,6 +159,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -204,6 +205,12 @@ diff --git a/blog/2015/08/26/laundry-automation-with-moteino-mqtt-and-home-assistant/index.html b/blog/2015/08/26/laundry-automation-with-moteino-mqtt-and-home-assistant/index.html index b4b7669804..684e724edd 100644 --- a/blog/2015/08/26/laundry-automation-with-moteino-mqtt-and-home-assistant/index.html +++ b/blog/2015/08/26/laundry-automation-with-moteino-mqtt-and-home-assistant/index.html @@ -272,6 +272,7 @@ The automation and script syntax here is using a deprecated and no longer suppor
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -317,6 +318,12 @@ The automation and script syntax here is using a deprecated and no longer suppor diff --git a/blog/2015/08/31/version-7-revamped-ui-and-improved-distribution/index.html b/blog/2015/08/31/version-7-revamped-ui-and-improved-distribution/index.html index 66a528671a..3e31233701 100644 --- a/blog/2015/08/31/version-7-revamped-ui-and-improved-distribution/index.html +++ b/blog/2015/08/31/version-7-revamped-ui-and-improved-distribution/index.html @@ -246,6 +246,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -291,6 +292,12 @@ diff --git a/blog/2015/09/11/different-ways-to-use-mqtt-with-home-assistant/index.html b/blog/2015/09/11/different-ways-to-use-mqtt-with-home-assistant/index.html index 9bb13b6e25..9a6604df1b 100644 --- a/blog/2015/09/11/different-ways-to-use-mqtt-with-home-assistant/index.html +++ b/blog/2015/09/11/different-ways-to-use-mqtt-with-home-assistant/index.html @@ -449,6 +449,7 @@ PubSubClient client(ethClient);
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -494,6 +495,12 @@ PubSubClient client(ethClient); diff --git a/blog/2015/09/13/home-assistant-meets-ifttt/index.html b/blog/2015/09/13/home-assistant-meets-ifttt/index.html index 1f7908caf6..38f4cd37f9 100644 --- a/blog/2015/09/13/home-assistant-meets-ifttt/index.html +++ b/blog/2015/09/13/home-assistant-meets-ifttt/index.html @@ -308,6 +308,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -353,6 +354,12 @@ diff --git a/blog/2015/09/18/monitoring-with-glances-and-home-assistant/index.html b/blog/2015/09/18/monitoring-with-glances-and-home-assistant/index.html index ce32f2a10f..8ba0ddbf8c 100644 --- a/blog/2015/09/18/monitoring-with-glances-and-home-assistant/index.html +++ b/blog/2015/09/18/monitoring-with-glances-and-home-assistant/index.html @@ -209,6 +209,7 @@ Glances web server started on http://0.0.0.0:61208/
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -254,6 +255,12 @@ Glances web server started on http://0.0.0.0:61208/ diff --git a/blog/2015/09/19/alarm-sonos-and-itunes-support/index.html b/blog/2015/09/19/alarm-sonos-and-itunes-support/index.html index dfa5a951b1..ec9a84c63c 100644 --- a/blog/2015/09/19/alarm-sonos-and-itunes-support/index.html +++ b/blog/2015/09/19/alarm-sonos-and-itunes-support/index.html @@ -188,6 +188,7 @@ Automation has gotten a lot of love. It now supports conditions, multiple trigge
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -233,6 +234,12 @@ Automation has gotten a lot of love. It now supports conditions, multiple trigge diff --git a/blog/2015/10/05/home-assistant-goes-geo-with-owntracks/index.html b/blog/2015/10/05/home-assistant-goes-geo-with-owntracks/index.html index 94d30ccac4..d6532e97ee 100644 --- a/blog/2015/10/05/home-assistant-goes-geo-with-owntracks/index.html +++ b/blog/2015/10/05/home-assistant-goes-geo-with-owntracks/index.html @@ -164,6 +164,7 @@ Map in Home Assistant showing two people and three zones (home, school, work)
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -209,6 +210,12 @@ Map in Home Assistant showing two people and three zones (home, school, work) diff --git a/blog/2015/10/11/measure-temperature-with-esp8266-and-report-to-mqtt/index.html b/blog/2015/10/11/measure-temperature-with-esp8266-and-report-to-mqtt/index.html index 83528c6084..979d2d0560 100644 --- a/blog/2015/10/11/measure-temperature-with-esp8266-and-report-to-mqtt/index.html +++ b/blog/2015/10/11/measure-temperature-with-esp8266-and-report-to-mqtt/index.html @@ -508,6 +508,7 @@ Adafruit_HDC1000 hdc = Adafruit_HDC1000();
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -553,6 +554,12 @@ Adafruit_HDC1000 hdc = Adafruit_HDC1000(); diff --git a/blog/2015/10/11/rfxtrx-blinkstick-and-snmp-support/index.html b/blog/2015/10/11/rfxtrx-blinkstick-and-snmp-support/index.html index 89f27f2922..c33f730cfd 100644 --- a/blog/2015/10/11/rfxtrx-blinkstick-and-snmp-support/index.html +++ b/blog/2015/10/11/rfxtrx-blinkstick-and-snmp-support/index.html @@ -153,6 +153,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -198,6 +199,12 @@ diff --git a/blog/2015/10/26/firetv-and-radiotherm-now-supported/index.html b/blog/2015/10/26/firetv-and-radiotherm-now-supported/index.html index c9d4aff779..23ba450e58 100644 --- a/blog/2015/10/26/firetv-and-radiotherm-now-supported/index.html +++ b/blog/2015/10/26/firetv-and-radiotherm-now-supported/index.html @@ -175,6 +175,7 @@ This makes more sense as most people run Home Assistant as a daemon

  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -220,6 +221,12 @@ This makes more sense as most people run Home Assistant as a daemon

    diff --git a/blog/2015/11/16/zwave-switches-lights-and-honeywell-thermostats-now-supported/index.html b/blog/2015/11/16/zwave-switches-lights-and-honeywell-thermostats-now-supported/index.html index 3a00ac5f9c..8418a9836a 100644 --- a/blog/2015/11/16/zwave-switches-lights-and-honeywell-thermostats-now-supported/index.html +++ b/blog/2015/11/16/zwave-switches-lights-and-honeywell-thermostats-now-supported/index.html @@ -171,6 +171,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -216,6 +217,12 @@ diff --git a/blog/2015/11/22/survey-november-2015/index.html b/blog/2015/11/22/survey-november-2015/index.html index 8f26fa3fb2..9648cf42d3 100644 --- a/blog/2015/11/22/survey-november-2015/index.html +++ b/blog/2015/11/22/survey-november-2015/index.html @@ -211,6 +211,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -256,6 +257,12 @@ diff --git a/blog/2015/12/05/community-highlights/index.html b/blog/2015/12/05/community-highlights/index.html index 7a1a3ecc4e..5dfe8bbd4a 100644 --- a/blog/2015/12/05/community-highlights/index.html +++ b/blog/2015/12/05/community-highlights/index.html @@ -146,6 +146,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -191,6 +192,12 @@ diff --git a/blog/2015/12/06/locks-rollershutters-binary-sensors-and-influxdb-support/index.html b/blog/2015/12/06/locks-rollershutters-binary-sensors-and-influxdb-support/index.html index bc3b0802d4..6aa40ce573 100644 --- a/blog/2015/12/06/locks-rollershutters-binary-sensors-and-influxdb-support/index.html +++ b/blog/2015/12/06/locks-rollershutters-binary-sensors-and-influxdb-support/index.html @@ -153,6 +153,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -198,6 +199,12 @@ diff --git a/blog/2015/12/07/influxdb-and-grafana/index.html b/blog/2015/12/07/influxdb-and-grafana/index.html index 81f284970f..75a4d8cc78 100644 --- a/blog/2015/12/07/influxdb-and-grafana/index.html +++ b/blog/2015/12/07/influxdb-and-grafana/index.html @@ -244,6 +244,7 @@ $ sudo systemctl status grafana-server
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -289,6 +290,12 @@ $ sudo systemctl status grafana-server diff --git a/blog/2015/12/10/activating-tasker-tasks-from-home-assistant-using-command-line-switches/index.html b/blog/2015/12/10/activating-tasker-tasks-from-home-assistant-using-command-line-switches/index.html index 04e10d339a..1bb0d9b809 100644 --- a/blog/2015/12/10/activating-tasker-tasks-from-home-assistant-using-command-line-switches/index.html +++ b/blog/2015/12/10/activating-tasker-tasks-from-home-assistant-using-command-line-switches/index.html @@ -194,6 +194,7 @@ requests.get('Follow Home Assistant on Twitter +
  • @@ -239,6 +240,12 @@ requests.get(' +
  • + Optimizing the Home Assistant mobile web app +
  • + + +
  • Laundry Sensors with NodeMCU and Home Assistant
  • @@ -262,12 +269,6 @@ requests.get(' - Visualize your IoT data - - - diff --git a/blog/2015/12/12/philips-hue-blocks-3rd-party-bulbs/index.html b/blog/2015/12/12/philips-hue-blocks-3rd-party-bulbs/index.html index 8a92116fad..004e48c389 100644 --- a/blog/2015/12/12/philips-hue-blocks-3rd-party-bulbs/index.html +++ b/blog/2015/12/12/philips-hue-blocks-3rd-party-bulbs/index.html @@ -166,6 +166,7 @@ Philips Hue FAQ entries regarding 3rd party light bulbs.
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -211,6 +212,12 @@ Philips Hue FAQ entries regarding 3rd party light bulbs. diff --git a/blog/2015/12/13/setup-encryption-using-lets-encrypt/index.html b/blog/2015/12/13/setup-encryption-using-lets-encrypt/index.html index f0bad954a6..d540efe446 100644 --- a/blog/2015/12/13/setup-encryption-using-lets-encrypt/index.html +++ b/blog/2015/12/13/setup-encryption-using-lets-encrypt/index.html @@ -233,6 +233,7 @@ sudo docker run -it --rm -p 80:80 --name certbot \
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -278,6 +279,12 @@ sudo docker run -it --rm -p 80:80 --name certbot \ diff --git a/blog/2015/12/22/amazon-echo-icloud-and-templates/index.html b/blog/2015/12/22/amazon-echo-icloud-and-templates/index.html index 62719a1617..01308b3cc7 100644 --- a/blog/2015/12/22/amazon-echo-icloud-and-templates/index.html +++ b/blog/2015/12/22/amazon-echo-icloud-and-templates/index.html @@ -187,6 +187,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -232,6 +233,12 @@ diff --git a/blog/2016/01/17/extended-support-for-diy-solutions/index.html b/blog/2016/01/17/extended-support-for-diy-solutions/index.html index 0fb3a49316..b6362ff165 100644 --- a/blog/2016/01/17/extended-support-for-diy-solutions/index.html +++ b/blog/2016/01/17/extended-support-for-diy-solutions/index.html @@ -167,6 +167,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -212,6 +213,12 @@ diff --git a/blog/2016/01/19/perfect-home-automation/index.html b/blog/2016/01/19/perfect-home-automation/index.html index 4bf27e6e05..a74018f6aa 100644 --- a/blog/2016/01/19/perfect-home-automation/index.html +++ b/blog/2016/01/19/perfect-home-automation/index.html @@ -171,6 +171,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -216,6 +217,12 @@ diff --git a/blog/2016/01/30/insteon-lifx-twitter-and-zigbee/index.html b/blog/2016/01/30/insteon-lifx-twitter-and-zigbee/index.html index 565680802e..0eebbea094 100644 --- a/blog/2016/01/30/insteon-lifx-twitter-and-zigbee/index.html +++ b/blog/2016/01/30/insteon-lifx-twitter-and-zigbee/index.html @@ -173,6 +173,7 @@ Example of the new views in the frontend. Learn mor
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -218,6 +219,12 @@ Example of the new views in the frontend. Learn mor diff --git a/blog/2016/02/09/smarter-smart-things-with-mqtt-and-home-assistant/index.html b/blog/2016/02/09/smarter-smart-things-with-mqtt-and-home-assistant/index.html index e9b6b92d9e..b0f49e87b8 100644 --- a/blog/2016/02/09/smarter-smart-things-with-mqtt-and-home-assistant/index.html +++ b/blog/2016/02/09/smarter-smart-things-with-mqtt-and-home-assistant/index.html @@ -360,6 +360,7 @@ Z-Wave light bulb |
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -405,6 +406,12 @@ Z-Wave light bulb | diff --git a/blog/2016/02/12/classifying-the-internet-of-things/index.html b/blog/2016/02/12/classifying-the-internet-of-things/index.html index 440aeaf36c..6776c88432 100644 --- a/blog/2016/02/12/classifying-the-internet-of-things/index.html +++ b/blog/2016/02/12/classifying-the-internet-of-things/index.html @@ -310,6 +310,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -355,6 +356,12 @@ diff --git a/blog/2016/02/13/speedtest-bloomsky-splunk-and-garage-doors/index.html b/blog/2016/02/13/speedtest-bloomsky-splunk-and-garage-doors/index.html index dab5db2f1c..f29ebb5081 100644 --- a/blog/2016/02/13/speedtest-bloomsky-splunk-and-garage-doors/index.html +++ b/blog/2016/02/13/speedtest-bloomsky-splunk-and-garage-doors/index.html @@ -176,6 +176,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -221,6 +222,12 @@ diff --git a/blog/2016/02/18/multi-room-audio-with-snapcast/index.html b/blog/2016/02/18/multi-room-audio-with-snapcast/index.html index 14e21331ab..9de311d06f 100644 --- a/blog/2016/02/18/multi-room-audio-with-snapcast/index.html +++ b/blog/2016/02/18/multi-room-audio-with-snapcast/index.html @@ -278,6 +278,7 @@ output = audioresample ! audio/x-raw,rate=48000,channels=2,format=S16LE ! audioc
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -323,6 +324,12 @@ output = audioresample ! audio/x-raw,rate=48000,channels=2,format=S16LE ! audioc diff --git a/blog/2016/02/20/community-highlights/index.html b/blog/2016/02/20/community-highlights/index.html index 64194ad8af..fabf2f0483 100644 --- a/blog/2016/02/20/community-highlights/index.html +++ b/blog/2016/02/20/community-highlights/index.html @@ -186,6 +186,7 @@ Hold your NFC tag against the belly of Garfield to unlock the alarm.
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -231,6 +232,12 @@ Hold your NFC tag against the belly of Garfield to unlock the alarm. diff --git a/blog/2016/02/27/steam-d-link-smart-plugs-and-neurio-energy-sensors/index.html b/blog/2016/02/27/steam-d-link-smart-plugs-and-neurio-energy-sensors/index.html index 663e68d3f8..bf631b6b9f 100644 --- a/blog/2016/02/27/steam-d-link-smart-plugs-and-neurio-energy-sensors/index.html +++ b/blog/2016/02/27/steam-d-link-smart-plugs-and-neurio-energy-sensors/index.html @@ -175,6 +175,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -220,6 +221,12 @@ diff --git a/blog/2016/03/12/z-wave-pep257-templated-service-calls/index.html b/blog/2016/03/12/z-wave-pep257-templated-service-calls/index.html index 51a11123c8..5c373b6772 100644 --- a/blog/2016/03/12/z-wave-pep257-templated-service-calls/index.html +++ b/blog/2016/03/12/z-wave-pep257-templated-service-calls/index.html @@ -181,6 +181,7 @@ player state attributes. This change affects automations, scripts and scenes.Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -226,6 +227,12 @@ player state attributes. This change affects automations, scripts and scenes. +
  • + Optimizing the Home Assistant mobile web app +
  • + + +
  • Laundry Sensors with NodeMCU and Home Assistant
  • @@ -249,12 +256,6 @@ player state attributes. This change affects automations, scripts and scenes. - -
  • - Visualize your IoT data -
  • - - diff --git a/blog/2016/03/26/embedded-mqtt-broker-uber-yamaha-growl/index.html b/blog/2016/03/26/embedded-mqtt-broker-uber-yamaha-growl/index.html index a04f860e2f..ae00ca5686 100644 --- a/blog/2016/03/26/embedded-mqtt-broker-uber-yamaha-growl/index.html +++ b/blog/2016/03/26/embedded-mqtt-broker-uber-yamaha-growl/index.html @@ -192,6 +192,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -237,6 +238,12 @@ diff --git a/blog/2016/04/05/your-hub-should-be-local-and-open/index.html b/blog/2016/04/05/your-hub-should-be-local-and-open/index.html index 34a5711e1f..c9ad39a47d 100644 --- a/blog/2016/04/05/your-hub-should-be-local-and-open/index.html +++ b/blog/2016/04/05/your-hub-should-be-local-and-open/index.html @@ -144,6 +144,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -189,6 +190,12 @@ diff --git a/blog/2016/04/07/static-website/index.html b/blog/2016/04/07/static-website/index.html index 5deb904f3f..74657355e8 100644 --- a/blog/2016/04/07/static-website/index.html +++ b/blog/2016/04/07/static-website/index.html @@ -150,6 +150,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -195,6 +196,12 @@ diff --git a/blog/2016/04/09/onkyo-panasonic-gtfs-and-config-validation/index.html b/blog/2016/04/09/onkyo-panasonic-gtfs-and-config-validation/index.html index cec649dce6..2f340a10c3 100644 --- a/blog/2016/04/09/onkyo-panasonic-gtfs-and-config-validation/index.html +++ b/blog/2016/04/09/onkyo-panasonic-gtfs-and-config-validation/index.html @@ -158,6 +158,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -203,6 +204,12 @@ diff --git a/blog/2016/04/17/updated-documentation/index.html b/blog/2016/04/17/updated-documentation/index.html index 118a46a8df..4ef4c046fe 100644 --- a/blog/2016/04/17/updated-documentation/index.html +++ b/blog/2016/04/17/updated-documentation/index.html @@ -142,6 +142,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -187,6 +188,12 @@ diff --git a/blog/2016/04/19/to-infinity-and-beyond/index.html b/blog/2016/04/19/to-infinity-and-beyond/index.html index 45295533a7..930d6f78dd 100644 --- a/blog/2016/04/19/to-infinity-and-beyond/index.html +++ b/blog/2016/04/19/to-infinity-and-beyond/index.html @@ -159,6 +159,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -204,6 +205,12 @@ diff --git a/blog/2016/04/20/bluetooth-lg-webos-tvs-and-roombas/index.html b/blog/2016/04/20/bluetooth-lg-webos-tvs-and-roombas/index.html index beda4cacb0..c9ba953d6e 100644 --- a/blog/2016/04/20/bluetooth-lg-webos-tvs-and-roombas/index.html +++ b/blog/2016/04/20/bluetooth-lg-webos-tvs-and-roombas/index.html @@ -177,6 +177,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -222,6 +223,12 @@ diff --git a/blog/2016/04/30/ibeacons-part-1-making-presence-detection-work-better/index.html b/blog/2016/04/30/ibeacons-part-1-making-presence-detection-work-better/index.html index 96f017d8c2..c25d3b55d0 100644 --- a/blog/2016/04/30/ibeacons-part-1-making-presence-detection-work-better/index.html +++ b/blog/2016/04/30/ibeacons-part-1-making-presence-detection-work-better/index.html @@ -268,6 +268,7 @@ For example, my wife works next door - and I couldn’t detect whether she’s a
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -313,6 +314,12 @@ For example, my wife works next door - and I couldn’t detect whether she’s a diff --git a/blog/2016/05/06/open-iot-summit-talk/index.html b/blog/2016/05/06/open-iot-summit-talk/index.html index 6b3a44db46..41420b639e 100644 --- a/blog/2016/05/06/open-iot-summit-talk/index.html +++ b/blog/2016/05/06/open-iot-summit-talk/index.html @@ -140,6 +140,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -185,6 +186,12 @@ diff --git a/blog/2016/05/07/empowering-scripts-and-alexa/index.html b/blog/2016/05/07/empowering-scripts-and-alexa/index.html index f763b371fb..a49b45d60a 100644 --- a/blog/2016/05/07/empowering-scripts-and-alexa/index.html +++ b/blog/2016/05/07/empowering-scripts-and-alexa/index.html @@ -230,6 +230,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -275,6 +276,12 @@ diff --git a/blog/2016/05/12/video-configuring-home-assistant/index.html b/blog/2016/05/12/video-configuring-home-assistant/index.html index 730275cbd4..9c3f1dfe7e 100644 --- a/blog/2016/05/12/video-configuring-home-assistant/index.html +++ b/blog/2016/05/12/video-configuring-home-assistant/index.html @@ -140,6 +140,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -185,6 +186,12 @@ diff --git a/blog/2016/05/18/why-we-use-polymer/index.html b/blog/2016/05/18/why-we-use-polymer/index.html index 7444d00a70..ba49d1ae99 100644 --- a/blog/2016/05/18/why-we-use-polymer/index.html +++ b/blog/2016/05/18/why-we-use-polymer/index.html @@ -154,6 +154,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -199,6 +200,12 @@ diff --git a/blog/2016/05/21/release-020/index.html b/blog/2016/05/21/release-020/index.html index cab6ef6e22..da67fe2cf0 100644 --- a/blog/2016/05/21/release-020/index.html +++ b/blog/2016/05/21/release-020/index.html @@ -175,6 +175,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -220,6 +221,12 @@ diff --git a/blog/2016/05/22/get-started-with-all-in-one-installer/index.html b/blog/2016/05/22/get-started-with-all-in-one-installer/index.html index 318bddb0ac..553d6e6a44 100644 --- a/blog/2016/05/22/get-started-with-all-in-one-installer/index.html +++ b/blog/2016/05/22/get-started-with-all-in-one-installer/index.html @@ -146,6 +146,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -191,6 +192,12 @@ diff --git a/blog/2016/05/26/ibeacons-how-to-track-things-that-cant-track-themselves-part-ii/index.html b/blog/2016/05/26/ibeacons-how-to-track-things-that-cant-track-themselves-part-ii/index.html index 191165b910..e946574fa7 100644 --- a/blog/2016/05/26/ibeacons-how-to-track-things-that-cant-track-themselves-part-ii/index.html +++ b/blog/2016/05/26/ibeacons-how-to-track-things-that-cant-track-themselves-part-ii/index.html @@ -284,6 +284,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -329,6 +330,12 @@ diff --git a/blog/2016/06/01/community-highlights/index.html b/blog/2016/06/01/community-highlights/index.html index ff6b7af903..c6ae9c418a 100644 --- a/blog/2016/06/01/community-highlights/index.html +++ b/blog/2016/06/01/community-highlights/index.html @@ -160,6 +160,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -205,6 +206,12 @@ diff --git a/blog/2016/06/08/super-fast-web-enocean-lirc/index.html b/blog/2016/06/08/super-fast-web-enocean-lirc/index.html index ec191cc1bd..dd85cb1516 100644 --- a/blog/2016/06/08/super-fast-web-enocean-lirc/index.html +++ b/blog/2016/06/08/super-fast-web-enocean-lirc/index.html @@ -194,6 +194,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -239,6 +240,12 @@ diff --git a/blog/2016/06/13/home-assistant-at-pycon-2016/index.html b/blog/2016/06/13/home-assistant-at-pycon-2016/index.html index f0831e9608..3228ef1aa1 100644 --- a/blog/2016/06/13/home-assistant-at-pycon-2016/index.html +++ b/blog/2016/06/13/home-assistant-at-pycon-2016/index.html @@ -165,6 +165,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -210,6 +211,12 @@ diff --git a/blog/2016/06/18/pandora-bt-home-hub-5-and-local-file-camera/index.html b/blog/2016/06/18/pandora-bt-home-hub-5-and-local-file-camera/index.html index ddbec80ca2..07dc6be33f 100644 --- a/blog/2016/06/18/pandora-bt-home-hub-5-and-local-file-camera/index.html +++ b/blog/2016/06/18/pandora-bt-home-hub-5-and-local-file-camera/index.html @@ -189,6 +189,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -234,6 +235,12 @@ diff --git a/blog/2016/06/23/usb-webcams-and-home-assistant/index.html b/blog/2016/06/23/usb-webcams-and-home-assistant/index.html index f7ea9d17e2..24104e3a81 100644 --- a/blog/2016/06/23/usb-webcams-and-home-assistant/index.html +++ b/blog/2016/06/23/usb-webcams-and-home-assistant/index.html @@ -255,6 +255,7 @@ target_dir /tmp
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -300,6 +301,12 @@ target_dir /tmp diff --git a/blog/2016/07/01/envisalink-homematic-hdmi-cec-and-sony-bravia-tv/index.html b/blog/2016/07/01/envisalink-homematic-hdmi-cec-and-sony-bravia-tv/index.html index 5c6ab07f1c..f81c32572d 100644 --- a/blog/2016/07/01/envisalink-homematic-hdmi-cec-and-sony-bravia-tv/index.html +++ b/blog/2016/07/01/envisalink-homematic-hdmi-cec-and-sony-bravia-tv/index.html @@ -188,6 +188,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -233,6 +234,12 @@ diff --git a/blog/2016/07/06/pocketchip-running-home-assistant/index.html b/blog/2016/07/06/pocketchip-running-home-assistant/index.html index 1339e57d72..2f523c3dfc 100644 --- a/blog/2016/07/06/pocketchip-running-home-assistant/index.html +++ b/blog/2016/07/06/pocketchip-running-home-assistant/index.html @@ -191,6 +191,7 @@ $ hass --open-ui
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -236,6 +237,12 @@ $ hass --open-ui diff --git a/blog/2016/07/16/sqlalchemy-knx-join-simplisafe/index.html b/blog/2016/07/16/sqlalchemy-knx-join-simplisafe/index.html index 07ea56fad0..f9f2ef0ea6 100644 --- a/blog/2016/07/16/sqlalchemy-knx-join-simplisafe/index.html +++ b/blog/2016/07/16/sqlalchemy-knx-join-simplisafe/index.html @@ -195,6 +195,7 @@ $ hass --script db_migrator --config /path/to/config
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -240,6 +241,12 @@ $ hass --script db_migrator --config /path/to/config diff --git a/blog/2016/07/19/visualizing-your-iot-data/index.html b/blog/2016/07/19/visualizing-your-iot-data/index.html index f9139d9a4d..70fa0b3b4f 100644 --- a/blog/2016/07/19/visualizing-your-iot-data/index.html +++ b/blog/2016/07/19/visualizing-your-iot-data/index.html @@ -243,6 +243,7 @@ plt.savefig('Follow Home Assistant on Twitter +
  • @@ -288,6 +289,12 @@ plt.savefig(' +
  • + Optimizing the Home Assistant mobile web app +
  • + + +
  • Laundry Sensors with NodeMCU and Home Assistant
  • @@ -311,8 +318,6 @@ plt.savefig('Follow Home Assistant on Twitter +
  • @@ -245,6 +246,12 @@ One of the graphs created with this tutorial. diff --git a/blog/2016/07/28/esp8266-and-micropython-part1/index.html b/blog/2016/07/28/esp8266-and-micropython-part1/index.html index 775e187442..46d7ee5135 100644 --- a/blog/2016/07/28/esp8266-and-micropython-part1/index.html +++ b/blog/2016/07/28/esp8266-and-micropython-part1/index.html @@ -301,6 +301,7 @@ PIN = 5
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -346,6 +347,12 @@ PIN = 5 diff --git a/blog/2016/07/30/custom-frontend-panels-jupyter-notebooks-directv/index.html b/blog/2016/07/30/custom-frontend-panels-jupyter-notebooks-directv/index.html index 523f7bb101..952c7adfa7 100644 --- a/blog/2016/07/30/custom-frontend-panels-jupyter-notebooks-directv/index.html +++ b/blog/2016/07/30/custom-frontend-panels-jupyter-notebooks-directv/index.html @@ -202,6 +202,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -247,6 +248,12 @@ diff --git a/blog/2016/08/03/laundry-automation-update/index.html b/blog/2016/08/03/laundry-automation-update/index.html index 9f0ec89a7e..39167acda3 100644 --- a/blog/2016/08/03/laundry-automation-update/index.html +++ b/blog/2016/08/03/laundry-automation-update/index.html @@ -241,6 +241,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -286,6 +287,12 @@ diff --git a/blog/2016/08/07/optimizing-the-home-assistant-mobile-web-app/index.html b/blog/2016/08/07/optimizing-the-home-assistant-mobile-web-app/index.html new file mode 100644 index 0000000000..7e739d0cb8 --- /dev/null +++ b/blog/2016/08/07/optimizing-the-home-assistant-mobile-web-app/index.html @@ -0,0 +1,404 @@ + + + + + + + + + + Optimizing the Home Assistant mobile web app - Home Assistant + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    +
    + + + +
    +
    + +
    + + +
    + +
    + +

    Optimizing the Home Assistant mobile web app

    + + + +
    + + + 11 minutes reading time + + + + + + Comments + +
    + +
    + + +

    This blog post will go into detail about the recent performance optimizations that went into the Home Assistant front end. For people not familiar with the app, check out the demo and the source.

    + +

    TL; DR: Don’t hack the framework, separate responsibilities, ship less, use service workers, use (future) web standards.

    + +

    This year at Google I/O I saw Monica from the Polymer team talk about web components and performance. In her talk she mentions a mantra that they use in the Polymer team to make things fast: Do less and be lazy.

    + +

    Do less and be lazy. It sounds so obvious and it took a while before it started to dawn on me. I think most of the code I write is pretty fast, but I don’t often stop to take a harder look at how and when it runs in practice. When do we need the result, can it be postponed?

    + +

    And thus started my journey to take a critical look at how the Home Assistant app was working and how to make things faster. Below is the list of the different things that I did to make it fast.

    + +

    I hope this list can be useful to other people, as a guide for optimizing their own apps or for avoiding pitfalls when building a new one.

    + +

    The first thing to do is to measure. The Home Assistant front end is a mobile web app, so we shouldn’t measure this on a machine with 8 cores and gigabytes of ram but instead measure on devices you expect a mobile web app to run: phones. Below are two timelines recorded with Home Assistant 0.18.2 (pre-optimizations) and Google Chrome 53. On my Mac the app starts in 1400 miliseconds and on my Nexus 5x in ~6500 miliseconds (~4.5 times slower!).

    + +

    + Timeline of loading the front end in Home Assistant 0.18.2 +

    + +

    Although the app takes 6500 milliseconds to load on my phone, it would perform well afterwards. Still, that initial load is unacceptable. You expect to open an app on your phone and be able to use it, quickly. After I applied all the changes described below, I managed to reduce startup time to 900 miliseconds (-35%) on my Mac and 2400 miliseconds (-63%) on my Nexus 5x. Check out the demo here.

    + +

    + diagram showing old and new loading times next to one another + Timeline of loading the front end in Home Assistant 0.26 +

    + + + +

    Technology

    + +

    The Home Assistant front end consists of two parts. There is Home Assistant JS, which controls all data and interaction between JavaScript and the server. It is a Flux architecture using NuclearJS and ImmutableJS. The UI is implemented by Home Assistant Polymer using Polymer and web components.

    + +

    Don’t hack the framework

    + +

    I thought to be smart. I split out the JavaScript part of all web components and bundled them separately using Webpack so that I could use ES2015 via BabelJS (architecture). This is not how Polymer components are written and it meant that I was unable to use any of the tooling that is available in the community or easily split up the bundle (more on this later).

    + +

    So I went ahead and backported all my web components back from shiny beautiful ES6 to ES5. And you know what? It’s not that bad. Yes, not being able to use the concise object notation and arrow functions make your code more verbose. But in the end it is the same code that is running in browsers.

    + +

    Another benefit of having each web component contain their own script tag is that the browser will process them one by one, allowing the browser to render our loading spinner animation in between.

    + +

    As you can see in the timelines, we were able to get rid of most of the blocking component loading.

    + +

    + Timeline of loading the front end before and after the optimization +

    + +

    Separate responsibilities

    + +

    Whenever you learn a new technology, you feel like you’ve learned a new superpower. Wow, I can do all this with only 2 lines?! I had the same with bundling.

    + +

    I was initially very focused on shipping just a single file with everything that my app needed. The entry point would be my main component which would require all of its Flux and UI dependencies. Then, just before it all would be rendered, it would check if there is authentication and start the data fetching.

    + +

    This is a very bad pattern. This means that you will not start any data fetching until your UI is ready to render. Instead, you want your data to be fetched as soon as possible, and while the request is out to the server you want the page to load all your UI components.

    + +

    To accomplish this I extracted the application core out of the main bundle. In the current optimized version it’s 31.1kb gzip’d. It is loaded before any other scripts so that it can start fetching data as soon as possible.

    + +

    + Timeline of loading the front end before and after the optimization +

    + +

    When the data does come back before the UI is done loading, we can process it before we start rendering the UI because of all the web components being processed individually. This means that we don’t have to show a loading screen the first time our components render – we can just render the components with the data they require.

    + +

    Ship less

    + +

    The theory behind this one is simple: if we manage to ship less code, the browser has to process less code and it will start faster.

    + +

    Only include the components for the page that you will show

    + +

    The Home Assistant mobile web application has 10 different panels (pages). Besides that, it also has a dialog for each type of device to show more info. That’s a lot of components and screens of which only a very small set is needed at the start. That means that we are shipping a lot of unnecessary data that the browser has to process before our initial render!

    + +

    I broke up each panel of the app into a separate bundle that will be loaded on demand. This saved 250 kilobytes (pre-gzip) on just the embedded map alone! This change, however, required some significant changes to our build process.

    + +

    Breaking up an app in JavaScript is complex because each module explicitly imports their dependencies. This has to continue to work in your browser after breaking it up in multiple files. Web components do not have this problem as it’s part of the platform and thus your browser is the registry! An unregistered web component will be rendered as an empty span element until the element gets registered. Loading order is not important.

    + +
    +
    // Example of the flexibility of web components.
    +var spinner = document.createElement('paper-spinner');
    +spinner.active = true;
    +document.body.appendChild(spinner);
    +
    +
    +
    + +

    Because the browser tracks your web components, creating standalone bundles for parts of the app is easy:

    + +
      +
    • Find all dependencies included in the main bundle (using hydrolysis)
    • +
    • Create individual bundles of each panel (page) but filter out the dependencies included in main bundle.
    • +
    + +

    The build script that bundles and minifies the main bundle and panel bundles is <100 lines.

    + +

    Change the JavaScript bundler to Rollup

    + +

    Core.js is still pure JavaScript and requires bundling. In my journey to get a smaller bundle, I went from Webpack to Webpack 2 to Rollup. At each step the bundle got smaller. Rollup is the big winner here because it doesn’t wrap all your modules in function calls but instead concatenates all files with minimal changes to make it work. This not only reduces the file size but also the loading speed. This is because the JavaScript engine will no longer have to invoke a function to resolve each import, it’s doing less work. This might not mean much for a computer but on a phone, everything counts.

    + +

    Scrutinize dependencies

    + +

    If the goal is to ship less, it’s time to take a good look at dependencies. It’s so often that we decide to fall back to yet another NPM package that makes our life a little easier but comes at the cost of size – size usually taken up by functionality that you might never need.

    + +

    Remove Lodash

    +

    I realized that I only used a few methods of lodash. Lodash (and previously underscore) used to be one of the dependencies that would always be one of the first things that I would add to any project I start. But I could no longer justify it in the case of Home Assistant. Even with dead tree shaking it was not worth including it. Yes, they support a lot of edge cases but those were not relevant to my use case. And standalone lodash packages are still huge. The only thing that I couldn’t replace with a few lines of my own code was debounce. However I found a 40 line replacement.

    + +

    Replace moment.js with Fecha

    + +

    Moment.js is one of those power libraries. It is able to handle any date problem that you can throw at it. But this obviously comes at the cost of size. Fecha is a date formatting library at ~8% the size of moment.js (only 4.7kb pre-gzip). The only thing that it does not contain is date manipulation, which was something that was not being used.

    + +

    Use Service worker to instantly load the app

    + +

    Using a service worker we’re able to store all app components and core javascript in the browser. This means that after their first visit, the browser will only have to go to the network to fetch the latest data from the server.

    + +

    Creating a service worker is easy using sw-precache, a service worker generation tool.

    + +

    When a browser does not support service workers, Home Assistant will serve fingerprinted assets that are aggressively cached. Only when the content changes will the client redownload the asset.

    + +

    Using fingerprinting with sw-precache required jumping through a few hoops. The final build script can be found here.

    + +

    Make it feel fast

    + +

    This one is more psychological: no one likes staring at a white screen because white screens are ambiguous: are we loading something, is there a crappy connection or maybe even a script error? That’s why it is very important to render something on the screen to show that the rest is being loaded, and as quickly as possible.

    + +

    The Home Assistant landing page contains just enough CSS and HTML to render the loading screen minus the animations.

    + +

    Now that the app is fast enough, I might swap out moving from a lite loading screen to drawing an empty toolbar. This makes it look like the UI is almost there.

    + +

    Using a framework build on web standards

    + +

    I left this to the end of the list, mainly because I had no influence on this. Polymer just happened to ship an update while I was optimizing the application which gave a big boost to the loading time.

    + +

    By using Polymer we have the ability to use tomorrow’s web standards today. This is powered by polyfills. A polyfill will use JavaScript to simulate the behavior that the web standard would have taken care of. As browsers progress, more work can move from the polyfills back to the browsers. This is great because browsers will be able to optimize the work better and thus be faster.

    + +

    Polymer 1.6 was introduced at the end of June and allowed the app to take advantage of native CSS variables in Chrome and Firefox. It also introduced lazy registration. Both greatly sped up our loading times.

    + +

    Future optimizations

    + +

    A lot of optimizations have been applied but this journey will never be over. There are still a lot of opportunities to make things even faster. Some ideas that are on my list to explore:

    + +
      +
    • Use shadow DOM instead of shady DOM polyfill.
    • +
    • Use closure compiler to optimize the JavaScript.
    • +
    • Reduce the number of icons that are loaded.
    • +
    • Embed initial API response in served page if not using a service worker.
    • +
    • Reduce size of initial bundle by moving out all things that are not visible for initial paint. For example the dialogs that show more info about entities.
    • +
    • Prefetch the other pages using <link rel="preload" …>
    • +
    +
    + + +
    +

    Comments

    +
    +
    + + +
    + + + + +
    +
    + + + + + + + \ No newline at end of file diff --git a/blog/archives/index.html b/blog/archives/index.html index 7acde23edf..94379b5c03 100644 --- a/blog/archives/index.html +++ b/blog/archives/index.html @@ -98,6 +98,38 @@

    2016

    + + + +
    @@ -2586,6 +2618,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -2631,6 +2664,12 @@ diff --git a/blog/categories/community/atom.xml b/blog/categories/community/atom.xml index 402aa075ab..9d973f2a4f 100644 --- a/blog/categories/community/atom.xml +++ b/blog/categories/community/atom.xml @@ -4,7 +4,7 @@ <![CDATA[Category: Community | Home Assistant]]> - 2016-08-07T20:56:13+00:00 + 2016-08-07T21:33:33+00:00 https://home-assistant.io/ diff --git a/blog/categories/community/index.html b/blog/categories/community/index.html index aab8fe4f6c..67f5fae3a8 100644 --- a/blog/categories/community/index.html +++ b/blog/categories/community/index.html @@ -223,6 +223,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -268,6 +269,12 @@ diff --git a/blog/categories/device-tracking/atom.xml b/blog/categories/device-tracking/atom.xml index 429970f22f..585e3b8311 100644 --- a/blog/categories/device-tracking/atom.xml +++ b/blog/categories/device-tracking/atom.xml @@ -4,7 +4,7 @@ <![CDATA[Category: Device-Tracking | Home Assistant]]> - 2016-08-07T20:56:13+00:00 + 2016-08-07T21:33:33+00:00 https://home-assistant.io/ diff --git a/blog/categories/device-tracking/index.html b/blog/categories/device-tracking/index.html index 046a75f727..36df0623b7 100644 --- a/blog/categories/device-tracking/index.html +++ b/blog/categories/device-tracking/index.html @@ -154,6 +154,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -199,6 +200,12 @@ diff --git a/blog/categories/esp8266/atom.xml b/blog/categories/esp8266/atom.xml index 988525dafe..6a1f45c7c4 100644 --- a/blog/categories/esp8266/atom.xml +++ b/blog/categories/esp8266/atom.xml @@ -4,7 +4,7 @@ <![CDATA[Category: ESP8266 | Home Assistant]]> - 2016-08-07T20:56:13+00:00 + 2016-08-07T21:33:33+00:00 https://home-assistant.io/ diff --git a/blog/categories/esp8266/index.html b/blog/categories/esp8266/index.html index 512aadad1f..5612594937 100644 --- a/blog/categories/esp8266/index.html +++ b/blog/categories/esp8266/index.html @@ -154,6 +154,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -199,6 +200,12 @@ diff --git a/blog/categories/how-to/atom.xml b/blog/categories/how-to/atom.xml index d90ed32b4c..04049aa266 100644 --- a/blog/categories/how-to/atom.xml +++ b/blog/categories/how-to/atom.xml @@ -4,7 +4,7 @@ <![CDATA[Category: How-To | Home Assistant]]> - 2016-08-07T20:56:13+00:00 + 2016-08-07T21:33:33+00:00 https://home-assistant.io/ diff --git a/blog/categories/how-to/index.html b/blog/categories/how-to/index.html index c046760539..16d8686e25 100644 --- a/blog/categories/how-to/index.html +++ b/blog/categories/how-to/index.html @@ -615,6 +615,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -660,6 +661,12 @@ diff --git a/blog/categories/ibeacons/atom.xml b/blog/categories/ibeacons/atom.xml index 0c1f995e3f..91ea898d2e 100644 --- a/blog/categories/ibeacons/atom.xml +++ b/blog/categories/ibeacons/atom.xml @@ -4,7 +4,7 @@ <![CDATA[Category: iBeacons | Home Assistant]]> - 2016-08-07T20:56:13+00:00 + 2016-08-07T21:33:33+00:00 https://home-assistant.io/ diff --git a/blog/categories/ibeacons/index.html b/blog/categories/ibeacons/index.html index f957ee915c..4a37037d98 100644 --- a/blog/categories/ibeacons/index.html +++ b/blog/categories/ibeacons/index.html @@ -190,6 +190,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -235,6 +236,12 @@ diff --git a/blog/categories/internet-of-things/atom.xml b/blog/categories/internet-of-things/atom.xml index ecd3fa3763..3dbe0ef6b3 100644 --- a/blog/categories/internet-of-things/atom.xml +++ b/blog/categories/internet-of-things/atom.xml @@ -4,7 +4,7 @@ <![CDATA[Category: Internet-of-Things | Home Assistant]]> - 2016-08-07T20:56:13+00:00 + 2016-08-07T21:33:33+00:00 https://home-assistant.io/ diff --git a/blog/categories/internet-of-things/index.html b/blog/categories/internet-of-things/index.html index 053176de90..33a61603db 100644 --- a/blog/categories/internet-of-things/index.html +++ b/blog/categories/internet-of-things/index.html @@ -249,6 +249,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -294,6 +295,12 @@ diff --git a/blog/categories/iot-data/atom.xml b/blog/categories/iot-data/atom.xml index 840e4d2f56..b07b2267f2 100644 --- a/blog/categories/iot-data/atom.xml +++ b/blog/categories/iot-data/atom.xml @@ -4,7 +4,7 @@ <![CDATA[Category: IoT-Data | Home Assistant]]> - 2016-08-07T20:56:13+00:00 + 2016-08-07T21:33:33+00:00 https://home-assistant.io/ diff --git a/blog/categories/iot-data/index.html b/blog/categories/iot-data/index.html index fbfd587a27..54ab9efdbf 100644 --- a/blog/categories/iot-data/index.html +++ b/blog/categories/iot-data/index.html @@ -186,6 +186,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -231,6 +232,12 @@ diff --git a/blog/categories/mqtt/atom.xml b/blog/categories/mqtt/atom.xml index 190b379db7..dd06b4f91a 100644 --- a/blog/categories/mqtt/atom.xml +++ b/blog/categories/mqtt/atom.xml @@ -4,7 +4,7 @@ <![CDATA[Category: MQTT | Home Assistant]]> - 2016-08-07T20:56:13+00:00 + 2016-08-07T21:33:33+00:00 https://home-assistant.io/ diff --git a/blog/categories/mqtt/index.html b/blog/categories/mqtt/index.html index 0373782803..50ebf19b9f 100644 --- a/blog/categories/mqtt/index.html +++ b/blog/categories/mqtt/index.html @@ -225,6 +225,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -270,6 +271,12 @@ diff --git a/blog/categories/organisation/atom.xml b/blog/categories/organisation/atom.xml index 076da5eaaf..74ce35ce26 100644 --- a/blog/categories/organisation/atom.xml +++ b/blog/categories/organisation/atom.xml @@ -4,7 +4,7 @@ <![CDATA[Category: Organisation | Home Assistant]]> - 2016-08-07T20:56:13+00:00 + 2016-08-07T21:33:33+00:00 https://home-assistant.io/ diff --git a/blog/categories/organisation/index.html b/blog/categories/organisation/index.html index fce2c599ac..0d861045db 100644 --- a/blog/categories/organisation/index.html +++ b/blog/categories/organisation/index.html @@ -185,6 +185,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -230,6 +231,12 @@ diff --git a/blog/categories/owntracks/atom.xml b/blog/categories/owntracks/atom.xml index 6abd28a075..5c97c3f34a 100644 --- a/blog/categories/owntracks/atom.xml +++ b/blog/categories/owntracks/atom.xml @@ -4,7 +4,7 @@ <![CDATA[Category: OwnTracks | Home Assistant]]> - 2016-08-07T20:56:13+00:00 + 2016-08-07T21:33:33+00:00 https://home-assistant.io/ diff --git a/blog/categories/owntracks/index.html b/blog/categories/owntracks/index.html index e37294038f..e8c61796af 100644 --- a/blog/categories/owntracks/index.html +++ b/blog/categories/owntracks/index.html @@ -190,6 +190,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -235,6 +236,12 @@ diff --git a/blog/categories/presence-detection/atom.xml b/blog/categories/presence-detection/atom.xml index f831975dbc..880afe527e 100644 --- a/blog/categories/presence-detection/atom.xml +++ b/blog/categories/presence-detection/atom.xml @@ -4,7 +4,7 @@ <![CDATA[Category: Presence-Detection | Home Assistant]]> - 2016-08-07T20:56:13+00:00 + 2016-08-07T21:33:33+00:00 https://home-assistant.io/ diff --git a/blog/categories/presence-detection/index.html b/blog/categories/presence-detection/index.html index d9221c25bb..299e7308df 100644 --- a/blog/categories/presence-detection/index.html +++ b/blog/categories/presence-detection/index.html @@ -154,6 +154,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -199,6 +200,12 @@ diff --git a/blog/categories/public-service-announcement/atom.xml b/blog/categories/public-service-announcement/atom.xml index 2e22f49066..5de5ed2707 100644 --- a/blog/categories/public-service-announcement/atom.xml +++ b/blog/categories/public-service-announcement/atom.xml @@ -4,7 +4,7 @@ <![CDATA[Category: Public-Service-Announcement | Home Assistant]]> - 2016-08-07T20:56:13+00:00 + 2016-08-07T21:33:33+00:00 https://home-assistant.io/ diff --git a/blog/categories/public-service-announcement/index.html b/blog/categories/public-service-announcement/index.html index 938f24a6ab..71de879540 100644 --- a/blog/categories/public-service-announcement/index.html +++ b/blog/categories/public-service-announcement/index.html @@ -150,6 +150,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -195,6 +196,12 @@ diff --git a/blog/categories/release-notes/atom.xml b/blog/categories/release-notes/atom.xml index 11ca6b45a8..4b78bbe7b4 100644 --- a/blog/categories/release-notes/atom.xml +++ b/blog/categories/release-notes/atom.xml @@ -4,7 +4,7 @@ <![CDATA[Category: Release-Notes | Home Assistant]]> - 2016-08-07T20:56:13+00:00 + 2016-08-07T21:33:33+00:00 https://home-assistant.io/ diff --git a/blog/categories/release-notes/index.html b/blog/categories/release-notes/index.html index 2441de114b..32eded7090 100644 --- a/blog/categories/release-notes/index.html +++ b/blog/categories/release-notes/index.html @@ -1403,6 +1403,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -1448,6 +1449,12 @@ diff --git a/blog/categories/survey/atom.xml b/blog/categories/survey/atom.xml index 3573d96de1..5dcdf49cb1 100644 --- a/blog/categories/survey/atom.xml +++ b/blog/categories/survey/atom.xml @@ -4,7 +4,7 @@ <![CDATA[Category: Survey | Home Assistant]]> - 2016-08-07T20:56:13+00:00 + 2016-08-07T21:33:33+00:00 https://home-assistant.io/ diff --git a/blog/categories/survey/index.html b/blog/categories/survey/index.html index 830c3affca..78095795b8 100644 --- a/blog/categories/survey/index.html +++ b/blog/categories/survey/index.html @@ -150,6 +150,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -195,6 +196,12 @@ diff --git a/blog/categories/talks/atom.xml b/blog/categories/talks/atom.xml index 9b062d2069..7e5f844fbb 100644 --- a/blog/categories/talks/atom.xml +++ b/blog/categories/talks/atom.xml @@ -4,7 +4,7 @@ <![CDATA[Category: Talks | Home Assistant]]> - 2016-08-07T20:56:13+00:00 + 2016-08-07T21:33:33+00:00 https://home-assistant.io/ diff --git a/blog/categories/talks/index.html b/blog/categories/talks/index.html index acd75a5d17..bdf3c8b978 100644 --- a/blog/categories/talks/index.html +++ b/blog/categories/talks/index.html @@ -152,6 +152,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -197,6 +198,12 @@ diff --git a/blog/categories/technology/atom.xml b/blog/categories/technology/atom.xml index b4e59e3688..8fa665c35e 100644 --- a/blog/categories/technology/atom.xml +++ b/blog/categories/technology/atom.xml @@ -4,7 +4,7 @@ <![CDATA[Category: Technology | Home Assistant]]> - 2016-08-07T20:56:13+00:00 + 2016-08-07T21:33:33+00:00 https://home-assistant.io/ @@ -13,6 +13,159 @@ Octopress + + <![CDATA[Optimizing the Home Assistant mobile web app]]> + + 2016-08-07T19:36:00+00:00 + https://home-assistant.io/blog/2016/08/07/optimizing-the-home-assistant-mobile-web-app + This blog post will go into detail about the recent performance optimizations that went into the Home Assistant front end. For people not familiar with the app, check out the demo and the source.

    + +

    TL; DR: Don’t hack the framework, separate responsibilities, ship less, use service workers, use (future) web standards.

    + +

    This year at Google I/O I saw Monica from the Polymer team talk about web components and performance. In her talk she mentions a mantra that they use in the Polymer team to make things fast: Do less and be lazy.

    + +

    Do less and be lazy. It sounds so obvious and it took a while before it started to dawn on me. I think most of the code I write is pretty fast, but I don’t often stop to take a harder look at how and when it runs in practice. When do we need the result, can it be postponed?

    + +

    And thus started my journey to take a critical look at how the Home Assistant app was working and how to make things faster. Below is the list of the different things that I did to make it fast.

    + +

    I hope this list can be useful to other people, as a guide for optimizing their own apps or for avoiding pitfalls when building a new one.

    + +

    The first thing to do is to measure. The Home Assistant front end is a mobile web app, so we shouldn’t measure this on a machine with 8 cores and gigabytes of ram but instead measure on devices you expect a mobile web app to run: phones. Below are two timelines recorded with Home Assistant 0.18.2 (pre-optimizations) and Google Chrome 53. On my Mac the app starts in 1400 miliseconds and on my Nexus 5x in ~6500 miliseconds (~4.5 times slower!).

    + +

    + Timeline of loading the front end in Home Assistant 0.18.2 +

    + +

    Although the app takes 6500 milliseconds to load on my phone, it would perform well afterwards. Still, that initial load is unacceptable. You expect to open an app on your phone and be able to use it, quickly. After I applied all the changes described below, I managed to reduce startup time to 900 miliseconds (-35%) on my Mac and 2400 miliseconds (-63%) on my Nexus 5x. Check out the demo here.

    + +

    + diagram showing old and new loading times next to one another + Timeline of loading the front end in Home Assistant 0.26 +

    + + + +

    Technology

    + +

    The Home Assistant front end consists of two parts. There is Home Assistant JS, which controls all data and interaction between JavaScript and the server. It is a Flux architecture using NuclearJS and ImmutableJS. The UI is implemented by Home Assistant Polymer using Polymer and web components.

    + +

    Don’t hack the framework

    + +

    I thought to be smart. I split out the JavaScript part of all web components and bundled them separately using Webpack so that I could use ES2015 via BabelJS (architecture). This is not how Polymer components are written and it meant that I was unable to use any of the tooling that is available in the community or easily split up the bundle (more on this later).

    + +

    So I went ahead and backported all my web components back from shiny beautiful ES6 to ES5. And you know what? It’s not that bad. Yes, not being able to use the concise object notation and arrow functions make your code more verbose. But in the end it is the same code that is running in browsers.

    + +

    Another benefit of having each web component contain their own script tag is that the browser will process them one by one, allowing the browser to render our loading spinner animation in between.

    + +

    As you can see in the timelines, we were able to get rid of most of the blocking component loading.

    + +

    + Timeline of loading the front end before and after the optimization +

    + +

    Separate responsibilities

    + +

    Whenever you learn a new technology, you feel like you’ve learned a new superpower. Wow, I can do all this with only 2 lines?! I had the same with bundling.

    + +

    I was initially very focused on shipping just a single file with everything that my app needed. The entry point would be my main component which would require all of its Flux and UI dependencies. Then, just before it all would be rendered, it would check if there is authentication and start the data fetching.

    + +

    This is a very bad pattern. This means that you will not start any data fetching until your UI is ready to render. Instead, you want your data to be fetched as soon as possible, and while the request is out to the server you want the page to load all your UI components.

    + +

    To accomplish this I extracted the application core out of the main bundle. In the current optimized version it’s 31.1kb gzip’d. It is loaded before any other scripts so that it can start fetching data as soon as possible.

    + +

    + Timeline of loading the front end before and after the optimization +

    + +

    When the data does come back before the UI is done loading, we can process it before we start rendering the UI because of all the web components being processed individually. This means that we don’t have to show a loading screen the first time our components render – we can just render the components with the data they require.

    + +

    Ship less

    + +

    The theory behind this one is simple: if we manage to ship less code, the browser has to process less code and it will start faster.

    + +

    Only include the components for the page that you will show

    + +

    The Home Assistant mobile web application has 10 different panels (pages). Besides that, it also has a dialog for each type of device to show more info. That’s a lot of components and screens of which only a very small set is needed at the start. That means that we are shipping a lot of unnecessary data that the browser has to process before our initial render!

    + +

    I broke up each panel of the app into a separate bundle that will be loaded on demand. This saved 250 kilobytes (pre-gzip) on just the embedded map alone! This change, however, required some significant changes to our build process.

    + +

    Breaking up an app in JavaScript is complex because each module explicitly imports their dependencies. This has to continue to work in your browser after breaking it up in multiple files. Web components do not have this problem as it’s part of the platform and thus your browser is the registry! An unregistered web component will be rendered as an empty span element until the element gets registered. Loading order is not important.

    + +
    +
    // Example of the flexibility of web components.
    +var spinner = document.createElement('paper-spinner');
    +spinner.active = true;
    +document.body.appendChild(spinner);
    +
    +
    +
    + +

    Because the browser tracks your web components, creating standalone bundles for parts of the app is easy:

    + +
      +
    • Find all dependencies included in the main bundle (using hydrolysis)
    • +
    • Create individual bundles of each panel (page) but filter out the dependencies included in main bundle.
    • +
    + +

    The build script that bundles and minifies the main bundle and panel bundles is <100 lines.

    + +

    Change the JavaScript bundler to Rollup

    + +

    Core.js is still pure JavaScript and requires bundling. In my journey to get a smaller bundle, I went from Webpack to Webpack 2 to Rollup. At each step the bundle got smaller. Rollup is the big winner here because it doesn’t wrap all your modules in function calls but instead concatenates all files with minimal changes to make it work. This not only reduces the file size but also the loading speed. This is because the JavaScript engine will no longer have to invoke a function to resolve each import, it’s doing less work. This might not mean much for a computer but on a phone, everything counts.

    + +

    Scrutinize dependencies

    + +

    If the goal is to ship less, it’s time to take a good look at dependencies. It’s so often that we decide to fall back to yet another NPM package that makes our life a little easier but comes at the cost of size – size usually taken up by functionality that you might never need.

    + +

    Remove Lodash

    +

    I realized that I only used a few methods of lodash. Lodash (and previously underscore) used to be one of the dependencies that would always be one of the first things that I would add to any project I start. But I could no longer justify it in the case of Home Assistant. Even with dead tree shaking it was not worth including it. Yes, they support a lot of edge cases but those were not relevant to my use case. And standalone lodash packages are still huge. The only thing that I couldn’t replace with a few lines of my own code was debounce. However I found a 40 line replacement.

    + +

    Replace moment.js with Fecha

    + +

    Moment.js is one of those power libraries. It is able to handle any date problem that you can throw at it. But this obviously comes at the cost of size. Fecha is a date formatting library at ~8% the size of moment.js (only 4.7kb pre-gzip). The only thing that it does not contain is date manipulation, which was something that was not being used.

    + +

    Use Service worker to instantly load the app

    + +

    Using a service worker we’re able to store all app components and core javascript in the browser. This means that after their first visit, the browser will only have to go to the network to fetch the latest data from the server.

    + +

    Creating a service worker is easy using sw-precache, a service worker generation tool.

    + +

    When a browser does not support service workers, Home Assistant will serve fingerprinted assets that are aggressively cached. Only when the content changes will the client redownload the asset.

    + +

    Using fingerprinting with sw-precache required jumping through a few hoops. The final build script can be found here.

    + +

    Make it feel fast

    + +

    This one is more psychological: no one likes staring at a white screen because white screens are ambiguous: are we loading something, is there a crappy connection or maybe even a script error? That’s why it is very important to render something on the screen to show that the rest is being loaded, and as quickly as possible.

    + +

    The Home Assistant landing page contains just enough CSS and HTML to render the loading screen minus the animations.

    + +

    Now that the app is fast enough, I might swap out moving from a lite loading screen to drawing an empty toolbar. This makes it look like the UI is almost there.

    + +

    Using a framework build on web standards

    + +

    I left this to the end of the list, mainly because I had no influence on this. Polymer just happened to ship an update while I was optimizing the application which gave a big boost to the loading time.

    + +

    By using Polymer we have the ability to use tomorrow’s web standards today. This is powered by polyfills. A polyfill will use JavaScript to simulate the behavior that the web standard would have taken care of. As browsers progress, more work can move from the polyfills back to the browsers. This is great because browsers will be able to optimize the work better and thus be faster.

    + +

    Polymer 1.6 was introduced at the end of June and allowed the app to take advantage of native CSS variables in Chrome and Firefox. It also introduced lazy registration. Both greatly sped up our loading times.

    + +

    Future optimizations

    + +

    A lot of optimizations have been applied but this journey will never be over. There are still a lot of opportunities to make things even faster. Some ideas that are on my list to explore:

    + +
      +
    • Use shadow DOM instead of shady DOM polyfill.
    • +
    • Use closure compiler to optimize the JavaScript.
    • +
    • Reduce the number of icons that are loaded.
    • +
    • Embed initial API response in served page if not using a service worker.
    • +
    • Reduce size of initial bundle by moving out all things that are not visible for initial paint. For example the dialogs that show more info about entities.
    • +
    • Prefetch the other pages using <link rel="preload" …>
    • +
    + +]]>
    +
    + <![CDATA[Why we use web components and Polymer]]> diff --git a/blog/categories/technology/index.html b/blog/categories/technology/index.html index 3c95481809..617efcab81 100644 --- a/blog/categories/technology/index.html +++ b/blog/categories/technology/index.html @@ -98,6 +98,38 @@

    2016

    + + + +
    @@ -150,6 +182,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -195,6 +228,12 @@ diff --git a/blog/categories/user-stories/atom.xml b/blog/categories/user-stories/atom.xml index ec6308e01a..d002bcbd72 100644 --- a/blog/categories/user-stories/atom.xml +++ b/blog/categories/user-stories/atom.xml @@ -4,7 +4,7 @@ <![CDATA[Category: User-Stories | Home Assistant]]> - 2016-08-07T20:56:13+00:00 + 2016-08-07T21:33:33+00:00 https://home-assistant.io/ diff --git a/blog/categories/user-stories/index.html b/blog/categories/user-stories/index.html index 9c563e1982..846414269e 100644 --- a/blog/categories/user-stories/index.html +++ b/blog/categories/user-stories/index.html @@ -185,6 +185,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -230,6 +231,12 @@ diff --git a/blog/categories/video/atom.xml b/blog/categories/video/atom.xml index 1cf218d716..38fe49ffbe 100644 --- a/blog/categories/video/atom.xml +++ b/blog/categories/video/atom.xml @@ -4,7 +4,7 @@ <![CDATA[Category: Video | Home Assistant]]> - 2016-08-07T20:56:13+00:00 + 2016-08-07T21:33:33+00:00 https://home-assistant.io/ diff --git a/blog/categories/video/index.html b/blog/categories/video/index.html index f343f81617..ae546646dc 100644 --- a/blog/categories/video/index.html +++ b/blog/categories/video/index.html @@ -353,6 +353,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -398,6 +399,12 @@ diff --git a/blog/categories/website/atom.xml b/blog/categories/website/atom.xml index 8a142cc996..bb609d731b 100644 --- a/blog/categories/website/atom.xml +++ b/blog/categories/website/atom.xml @@ -4,7 +4,7 @@ <![CDATA[Category: Website | Home Assistant]]> - 2016-08-07T20:56:13+00:00 + 2016-08-07T21:33:33+00:00 https://home-assistant.io/ diff --git a/blog/categories/website/index.html b/blog/categories/website/index.html index 610e73c7aa..896c34a558 100644 --- a/blog/categories/website/index.html +++ b/blog/categories/website/index.html @@ -185,6 +185,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • @@ -230,6 +231,12 @@ diff --git a/blog/index.html b/blog/index.html index a358618cdc..cd61f697ed 100644 --- a/blog/index.html +++ b/blog/index.html @@ -78,6 +78,73 @@ +
    +
    + +

    + Optimizing the Home Assistant mobile web app +

    + + + +
    + + + 11 minutes reading time + + + + + + Comments + +
    + +
    + + +
    +

    This blog post will go into detail about the recent performance optimizations that went into the Home Assistant front end. For people not familiar with the app, check out the demo and the source.

    + +

    TL; DR: Don’t hack the framework, separate responsibilities, ship less, use service workers, use (future) web standards.

    + +

    This year at Google I/O I saw Monica from the Polymer team talk about web components and performance. In her talk she mentions a mantra that they use in the Polymer team to make things fast: Do less and be lazy.

    + +

    Do less and be lazy. It sounds so obvious and it took a while before it started to dawn on me. I think most of the code I write is pretty fast, but I don’t often stop to take a harder look at how and when it runs in practice. When do we need the result, can it be postponed?

    + +

    And thus started my journey to take a critical look at how the Home Assistant app was working and how to make things faster. Below is the list of the different things that I did to make it fast.

    + +

    I hope this list can be useful to other people, as a guide for optimizing their own apps or for avoiding pitfalls when building a new one.

    + +

    The first thing to do is to measure. The Home Assistant front end is a mobile web app, so we shouldn’t measure this on a machine with 8 cores and gigabytes of ram but instead measure on devices you expect a mobile web app to run: phones. Below are two timelines recorded with Home Assistant 0.18.2 (pre-optimizations) and Google Chrome 53. On my Mac the app starts in 1400 miliseconds and on my Nexus 5x in ~6500 miliseconds (~4.5 times slower!).

    + +

    + Timeline of loading the front end in Home Assistant 0.18.2 +

    + +

    Although the app takes 6500 milliseconds to load on my phone, it would perform well afterwards. Still, that initial load is unacceptable. You expect to open an app on your phone and be able to use it, quickly. After I applied all the changes described below, I managed to reduce startup time to 900 miliseconds (-35%) on my Mac and 2400 miliseconds (-63%) on my Nexus 5x. Check out the demo here.

    + +

    + diagram showing old and new loading times next to one another + Timeline of loading the front end in Home Assistant 0.26 +

    + + + + Read on → + +
    +
    +
    +
    @@ -688,103 +755,6 @@ In the past month I was thinking about ways to integrate USB webcams into Home A Read on → -
    -
    -
    - -
    -
    - -

    - 0.22: Pandora, BT Home Hub 5 and local file camera. -

    - - - -
    - - - two minutes reading time - - - - - - Comments - -
    - -
    - - -
    -

    It’s time for the 0.22 release. This was a pretty rough release cycle and we had to issue two hot fixes for our core improvements. But it seems now that all is good and a lot of people have reported that their installs are faster than ever and the occasional quirks no longer occur.

    - -

    We are aware that our new web stack has caused issues installing Home Assistant on ARM-based platforms. This sadly includes the Raspberry Pi and Synology NAS systems. We’re working on getting to a better solution. For Raspberry Pi, the All-in-One installer will take care of everything for you. We’re working on updating our standalone Raspberry Pi installation guide.

    - -

    There are two cool things that I want to highlight in this release. The first is Pandora support. This is based on the CLI player called pianobar. This means that your machine running Home Assistant can be connected to the speakers and provide your house with tunes.

    - -

    - -

    - -

    Another cool addition is the local file camera. This seems very basic at first but will allow you to generate a graph with your favorite 3rd party graphing tool and display it on your Home Assistant dashboard. We’re looking forward to see what you can do with this!

    - -

    - - - -

    Breaking change

    - -
      -
    • The new Netatmo support caused us to change how Netatmo are configured. It’s now done via it’s own component.
    • -
    - -
    -
    netatmo:
    -    api_key: API_KEY
    -    secret_key: SECRET_KEY
    -    username: username
    -    password: password
    -
    -
    -
    - -

    Hotfix 0.22.1 - June 20

    - -
      -
    • Insteon Hub lights will load again
    • -
    - - -

    @@ -815,6 +785,7 @@ In the past month I was thinking about ways to integrate USB webcams into Home A
  • Get started with Home Assistant
  • Try the online demo
  • +
  • diff --git a/blog/posts/2/index.html b/blog/posts/2/index.html index e044d59466..a6613c9237 100644 --- a/blog/posts/2/index.html +++ b/blog/posts/2/index.html @@ -78,6 +78,103 @@ +
    +
    + +

    + 0.22: Pandora, BT Home Hub 5 and local file camera. +

    + + + +
    + + + two minutes reading time + + + + + + Comments + +
    + +
    + + +
    +

    It’s time for the 0.22 release. This was a pretty rough release cycle and we had to issue two hot fixes for our core improvements. But it seems now that all is good and a lot of people have reported that their installs are faster than ever and the occasional quirks no longer occur.

    + +

    We are aware that our new web stack has caused issues installing Home Assistant on ARM-based platforms. This sadly includes the Raspberry Pi and Synology NAS systems. We’re working on getting to a better solution. For Raspberry Pi, the All-in-One installer will take care of everything for you. We’re working on updating our standalone Raspberry Pi installation guide.

    + +

    There are two cool things that I want to highlight in this release. The first is Pandora support. This is based on the CLI player called pianobar. This means that your machine running Home Assistant can be connected to the speakers and provide your house with tunes.

    + +

    + +

    + +

    Another cool addition is the local file camera. This seems very basic at first but will allow you to generate a graph with your favorite 3rd party graphing tool and display it on your Home Assistant dashboard. We’re looking forward to see what you can do with this!

    + +

    + + + +

    Breaking change

    + +
      +
    • The new Netatmo support caused us to change how Netatmo are configured. It’s now done via it’s own component.
    • +
    + +
    +
    netatmo:
    +    api_key: API_KEY
    +    secret_key: SECRET_KEY
    +    username: username
    +    password: password
    +
    +
    +
    + +

    Hotfix 0.22.1 - June 20

    + +
      +
    • Insteon Hub lights will load again
    • +
    + + + +
    +
    +
    +
    @@ -738,54 +835,6 @@
    - -
    -
    - -
    -
    - -

    - Talk: Automating your home with Home Assistant (OpenIoT Summit) -

    - - - -
    - - - less than one minute reading time - - - - - - Comments - -
    - -
    - - -
    -

    At the beginning of April I gave a talk about Home Assistant at the OpenIoT summit in San Diego. I talk about the Home Assistant architecture and explain how to get started integrating your devices. Big thanks to my employer AppFolio (we’re hiring!) for letting me attend. Slides.

    - -
    - -
    - - -

    @@ -818,6 +867,7 @@
  • Get started with Home Assistant
  • Try the online demo
  • +
  • diff --git a/blog/posts/3/index.html b/blog/posts/3/index.html index 7fb8e174d5..0c49fbc49e 100644 --- a/blog/posts/3/index.html +++ b/blog/posts/3/index.html @@ -78,6 +78,54 @@ +
    +
    + +

    + Talk: Automating your home with Home Assistant (OpenIoT Summit) +

    + + + +
    + + + less than one minute reading time + + + + + + Comments + +
    + +
    + + +
    +

    At the beginning of April I gave a talk about Home Assistant at the OpenIoT summit in San Diego. I talk about the Home Assistant architecture and explain how to get started integrating your devices. Big thanks to my employer AppFolio (we’re hiring!) for letting me attend. Slides.

    + +
    + +
    + + + +
    +
    +
    +
    @@ -687,89 +735,6 @@ player state attributes. This change affects automations, scripts and scenes. -
    -
    - -
    -
    - -

    - 0.14: Steam, D-Link smart plugs and Neurio Energy Sensors -

    - - - -
    - - - two minutes reading time - - - - - - Comments - -
    - -
    - - -
    -

    It’s been another two weeks which means it’s time for release: 0.14!

    - -

    - - - -

    - - Camera feeds are now directly embedded in the frontend. -

    - -

    Backwards incompatible changes

    -
      -
    • Component: Simple Alarm has been removed. Still available in the cookbook.
    • -
    • Script: Turning on a script that is already on is now a no-op instead of skipping current delay.
    • -
    • Wemo switches now have to be set up via the main Wemo component
    • -
    • Command line platforms for switch, sensor and binary_sensor have been renamed to command_line.
    • -
    • The rfxtrx sensors entity ids will incur a one time change to move to a stable format. See the docs for more details.
    • -
    - - -

    @@ -802,6 +767,7 @@ player state attributes. This change affects automations, scripts and scenes.Get started with Home Assistant
  • Try the online demo
  • +
  • diff --git a/blog/posts/4/index.html b/blog/posts/4/index.html index 89ca89dfaf..2844635f94 100644 --- a/blog/posts/4/index.html +++ b/blog/posts/4/index.html @@ -78,6 +78,89 @@ +
    +
    + +

    + 0.14: Steam, D-Link smart plugs and Neurio Energy Sensors +

    + + + +
    + + + two minutes reading time + + + + + + Comments + +
    + +
    + + +
    +

    It’s been another two weeks which means it’s time for release: 0.14!

    + +

    + + + +

    + + Camera feeds are now directly embedded in the frontend. +

    + +

    Backwards incompatible changes

    +
      +
    • Component: Simple Alarm has been removed. Still available in the cookbook.
    • +
    • Script: Turning on a script that is already on is now a no-op instead of skipping current delay.
    • +
    • Wemo switches now have to be set up via the main Wemo component
    • +
    • Command line platforms for switch, sensor and binary_sensor have been renamed to command_line.
    • +
    • The rfxtrx sensors entity ids will incur a one time change to move to a stable format. See the docs for more details.
    • +
    + + + +
    +
    +
    +
    @@ -742,56 +825,6 @@ Example of the new views in the frontend. Learn mor

    -
    -
    - -

    - Set up encryption using Let's Encrypt -

    - - - -
    - - - four minutes reading time - - - - - - Comments - -
    - -
    - - -
    -

    Exposing your Home Assistant instance outside of your network always has been tricky. You have to set up port forwarding on your router and most likely add a dynamic DNS service to work around your ISP changing your IP. After this you would be able to use Home Assistant from anywhere but there is one big red flag: no encryption.

    - -

    This tutorial will take you through the steps to setup a dynamic DNS for your IP and allow trusted encrypted connection to it - for free using DuckDNS and Let’s Encrypt.

    - -

    - -

    - - - - Read on → - -
    -
    -
    -