Installation #
This will install Home Assistant on a docker container on a Linux machine. The steps below are based on my specific use case. This method of installation will not allow you to install Add-Ons to Home Assistant.
- Install your preferred Linux distro:
- The steps below will include some comments targeting the typical arch Linux minimal installation, you'll have to adapt them to your own chosen distro.
- Power loss recovery:
- Make sure your machine automatically powers on once power is available again;
- In my specific machine, there was an option to automatically power it on once AC power is detected;
- Make sure your machine connects to the internet on boot.
- I had to configure
systemd-networkd
andsystemd-resolved
by enabling both services and copying the contents of arch Linux live boot system's/etc/systemd/network
to my installation's/etc/systemd/network
;
- I had to configure
- Make sure your machine automatically powers on once power is available again;
- Install your preferred
ssh
server and make sure it is enabled on boot and accessible in the same network:pacman -Syu openssh systemctl enable --now sshd.service
- Install docker and docker-compose and make sure they are enabled on boot:
pacman -Syu docker docker-compose systemctl enable --now docker.service
- Follow the official guide on how to install Home Assistant on a container. These were the steps I followed, but they might be outdated:
mkdir -p $HOME/homeassistant/config && cd $HOME/homeassistant
- Run the Home Assistant container (replace
MY_TIME_ZONE
with your time zone from this list)):1docker run -d \ 2 --name homeassistant \ 3 --privileged \ 4 --restart=unless-stopped \ 5 -e TZ=MY_TIME_ZONE \ 6 -v $HOME/homeassistant/config:/config \ 7 --network=host \ 8 ghcr.io/home-assistant/home-assistant:stable
- Once Home Assistant is up and running, you can access it at
http://localhost:8123/
from within the machine where the container is running or from any other machine in the same network by replacinglocalhost
with the machine's IP address;- If the links above don't work, try
http://<machine's IP address or localhost>:8123/onboarding.html
instead;
- If the links above don't work, try
- Finish the onboarding process;
- Run the Home Assistant container (replace
- ...
- Profit!
Configuration Management #
If you followed the installation section, Home Assistant configuration files should be located at $HOME/homeassistant/config
with the following structure:
1$HOME/homeassistant/config
2├── configuration.yaml
3├── automations.yaml
4├── scripts.yaml
5├── secrets.yaml
6├── scenes.yaml
Where configuration.yaml
is the main configuration file and the others get imported. I did not find a recommended way to organize the configuration files, so for my specific use case I decided to organize them by type, but you can organize them however you want:
1$HOME/homeassistant/config
2├── configuration.yaml
3├── automations
4│ ├── your_automation_1.yaml
5│ ├── your_automation_2.yaml
6│ └── ...
7├── scripts
8│ ├── your_script_1.yaml
9│ ├── your_script_2.yaml
10│ └── ...
11├── secrets.yaml
12├── scenes
13│ ├── your_scene_1.yaml
14│ ├── your_scene_2.yaml
15│ └── ...
16└── ...
With the configuration files organized as above, the contents of configuration.yaml
will look like this:
1automation: !include_dir_merge_list automations
2script: !include_dir_list scripts
3scene: !include_dir_list scenes
The above configuration change can be validated in Home Assistant's Developer Tools page, in the YAML
tab, by clicking on Check configuration
. You should be greeted with a message saying Configuration will not prevent Home Assistant from starting!
, or something along those lines.
Virtual Device Example #
In my house I have a pallet stove that I control with a IR remote control. This stove takes 7W of power on idle, it takes a few seconds to turn on with the IR controller and takes a some minutes to shutdown completely. Since this stove is not a "smart device", I have two options to control it:
- Modify its internals , soI can merge it into my zigbee network and control it from there;
- Get an external IR controller to turn it on and off and a smart plug to shut it down when on idle.
Since I'm not the best with electronics and I didn't want to damage the stove's internals, I decided to go with option #2.
I got a Broadlink RM Mini 4 IR controller and a NOUS A1Z smart plug. Both of these devices are compatible with Home Assistant. To cater to the above flow of control, this is a possible configuration:
stateDiagram-v2
[*] --> Off
Off --> Idle : Stove consuming around 7W
Idle --> TurningOn : IR controller turned on
TurningOn --> On : IR controller turned on
On --> TurningOff: IR controller turned off
TurningOff --> Idle: Stove consuming around 7W
Idle --> Off: Wall plug turned off
There are a few options to implement this flow of control, one of which is to create a virtual device comprised of both the IR controller and the smart plug. To achieve this, I put together the following yaml configuration:
Show YAML
- Located in
automations/stove.yaml
:
1- id: 'turn_on_stove_power'
2 alias: Turn On stove Power
3 description: ''
4 trigger:
5 - platform: state
6 entity_id: [input_boolean.stove_desired_state]
7 from: 'off'
8 to: 'on'
9 condition:
10 - condition: device
11 domain: switch
12 device_id: 105196245911f2b1fb03248d11fdff38
13 entity_id: switch.wall_plug_2_switch
14 type: is_off
15 - condition: state
16 entity_id: input_select.stove_state
17 state: Turned Off
18 action:
19 - type: turn_on
20 domain: switch
21 device_id: 105196245911f2b1fb03248d11fdff38
22 entity_id: switch.wall_plug_2_switch
23 mode: single
24- id: 'set_stove_state_idle'
25 alias: 'Set stove State Idle'
26 description: ''
27 mode: single
28 trigger:
29 - type: power
30 platform: device
31 device_id: 105196245911f2b1fb03248d11fdff38
32 entity_id: sensor.wall_plug_2_active_power
33 domain: sensor
34 below: 10
35 above: 5
36 for:
37 hours: 0
38 minutes: 0
39 seconds: 10
40 condition:
41 - condition: not
42 conditions:
43 - condition: state
44 entity_id: input_select.stove_state
45 state: Idle
46 action:
47 - service: input_select.select_option
48 data:
49 option: Idle
50 target:
51 entity_id: input_select.stove_state
52- id: 'turn_on_stove'
53 alias: Turn On stove
54 description: ''
55 trigger:
56 - platform: state
57 entity_id: [input_select.stove_state]
58 from: 'Turned Off'
59 to: Idle
60 for:
61 hours: 0
62 minutes: 0
63 seconds: 40
64 condition:
65 - condition: state
66 entity_id: input_boolean.stove_desired_state
67 state: "on"
68 - condition: device
69 type: is_on
70 device_id: 0fc2386a6d618e8aaf8eeb7ed55dd955
71 entity_id: remote.stove_controller
72 domain: remote
73 action:
74 - service: remote.send_command
75 target:
76 entity_id: remote.stove_controller
77 data:
78 device: stove_remote
79 command: power_on
80 num_repeats: 3
81 delay_secs: 3
82 hold_secs: 2
83 mode: single
84- id: 'set_stove_state_turning_on'
85 alias: 'Set stove State Turning On'
86 description: ''
87 mode: single
88 trigger:
89 - type: power
90 platform: device
91 device_id: 105196245911f2b1fb03248d11fdff38
92 entity_id: sensor.wall_plug_2_active_power
93 domain: sensor
94 below: 270
95 above: 190
96 for:
97 hours: 0
98 minutes: 0
99 seconds: 5
100 condition:
101 - condition: state
102 entity_id: input_select.stove_state
103 state: Idle
104 action:
105 - service: input_select.select_option
106 target:
107 entity_id: input_select.stove_state
108 data:
109 option: 'Turning On'
110- id: 'set_stove_state_turned_on'
111 alias: 'Set stove State Turned On'
112 description: ''
113 mode: single
114 trigger:
115 - type: power
116 platform: device
117 device_id: 105196245911f2b1fb03248d11fdff38
118 entity_id: sensor.wall_plug_2_active_power
119 domain: sensor
120 below: 70
121 above: 20
122 for:
123 hours: 0
124 minutes: 0
125 seconds: 15
126 condition:
127 - condition: state
128 entity_id: input_select.stove_state
129 state: 'Turning On'
130 action:
131 - service: input_select.select_option
132 target:
133 entity_id: input_select.stove_state
134 data:
135 option: 'Turned On'
136- id: 'turn_off_stove'
137 alias: Turn Off stove
138 description: ''
139 trigger:
140 - platform: state
141 entity_id: [input_boolean.stove_desired_state]
142 from: 'on'
143 to: 'off'
144 condition:
145 - condition: state
146 entity_id: input_select.stove_state
147 state: Turned On
148 - condition: device
149 type: is_on
150 device_id: 0fc2386a6d618e8aaf8eeb7ed55dd955
151 entity_id: remote.stove_controller
152 domain: remote
153 action:
154 - service: remote.send_command
155 data:
156 device: stove_remote
157 command: power_off
158 num_repeats: 3
159 delay_secs: 3
160 hold_secs: 2
161 target:
162 entity_id: remote.stove_controller
163 mode: single
164- id: 'set_stove_state_turning_off'
165 alias: 'Set stove State Turning Off'
166 description: ''
167 mode: single
168 trigger:
169 - type: power
170 platform: device
171 device_id: 105196245911f2b1fb03248d11fdff38
172 entity_id: sensor.wall_plug_2_active_power
173 domain: sensor
174 above: 48
175 below: 54
176 for:
177 hours: 0
178 minutes: 0
179 seconds: 20
180 - type: power
181 platform: device
182 device_id: 105196245911f2b1fb03248d11fdff38
183 entity_id: sensor.wall_plug_2_active_power
184 domain: sensor
185 above: 54
186 below: 58
187 for:
188 hours: 0
189 minutes: 0
190 seconds: 20
191 - type: power
192 platform: device
193 device_id: 105196245911f2b1fb03248d11fdff38
194 entity_id: sensor.wall_plug_2_active_power
195 domain: sensor
196 above: 58
197 below: 64
198 for:
199 hours: 0
200 minutes: 0
201 seconds: 20
202 condition:
203 - condition: state
204 entity_id: input_select.stove_state
205 state: 'Turned On'
206 action:
207 - service: input_select.select_option
208 target:
209 entity_id: input_select.stove_state
210 data:
211 option: 'Turning Off'
212- id: 'turn_off_stove_power'
213 alias: Turn Off stove Power
214 description: ''
215 trigger:
216 - platform: state
217 entity_id: [input_select.stove_state]
218 from: 'Turning Off'
219 to: Idle
220 condition:
221 - condition: device
222 device_id: 105196245911f2b1fb03248d11fdff38
223 entity_id: switch.wall_plug_2_switch
224 type: is_on
225 domain: switch
226 action:
227 - type: turn_off
228 domain: switch
229 device_id: 105196245911f2b1fb03248d11fdff38
230 entity_id: switch.wall_plug_2_switch
231 mode: single
232- id: 'set_stove_state_turned_off'
233 alias: 'Set stove State Turned Off'
234 description: ''
235 mode: single
236 trigger:
237 - type: power
238 platform: device
239 device_id: 105196245911f2b1fb03248d11fdff38
240 entity_id: sensor.wall_plug_2_active_power
241 domain: sensor
242 below: 1
243 above: -1
244 for:
245 hours: 0
246 minutes: 0
247 seconds: 10
248 condition:
249 - condition: not
250 conditions:
251 - condition: state
252 entity_id: input_select.stove_state
253 state: Turned Off
254 action:
255 - service: input_select.select_option
256 target:
257 entity_id: input_select.stove_state
258 data:
259 option: 'Turned Off'
260- description: 'set_stove_desired_state_on_on_external_operation'
261 alias: 'Set stove desired state on on external operation'
262 mode: single
263 trigger:
264 - platform: state
265 entity_id: [input_select.stove_state]
266 to: Turned On
267 - platform: state
268 entity_id: [input_select.stove_state]
269 to: Turning On
270 condition:
271 - condition: state
272 entity_id: input_boolean.stove_desired_state
273 state: "off"
274 action:
275 - service: input_boolean.turn_on
276 data: {}
277 target:
278 entity_id: input_boolean.stove_desired_state
279- description: 'set_stove_desired_state_off_on_external_operation'
280 alias: 'Set stove desired state off on external operation'
281 mode: single
282 trigger:
283 - platform: state
284 entity_id: [input_select.stove_state]
285 to: Turned Off
286 - platform: state
287 entity_id: [input_select.stove_state]
288 to: Turning Off
289 condition:
290 - condition: state
291 entity_id: input_boolean.stove_desired_state
292 state: "on"
293 action:
294 - service: input_boolean.turn_off
295 data: {}
296 target:
297 entity_id: input_boolean.stove_desired_state
298- description: 'notification_reminder_turn_on_stove'
299 alias: 'Reminder to turn on stove'
300 mode: single
301 trigger:
302 - platform: time
303 at: "17:00:00"
304 condition:
305 - condition: state
306 entity_id: input_select.stove_state
307 state: Turned Off
308 - type: is_temperature
309 condition: device
310 device_id: 0fc2386a6d618e8aaf8eeb7ed55dd955
311 entity_id: sensor.stove_controller_temperature
312 domain: sensor
313 below: 17
314 action:
315 - service: notify.mobile_app_YOU_MOBILE_NAME
316 data:
317 title: It's cold ❄️
318 message: Turn on stove ?
- In
configuration.yaml
:
1# your imports and other configurations above
2
3input_select:
4stove_state:
5 name: READ ONLY Current State of the stove
6 options:
7 - Idle
8 - Turned Off
9 - Turned On
10 - Turning Off
11 - Turning On
12 initial: Turned Off
13
14input_boolean:
15 stove_desired_state:
16 name: stove desired state
17 initial: off
18
19switch:
20 - platform: template
21 switches:
22 stove_switch:
23 unique_id: stove_switch
24 friendly_name: stove Switch
25 value_template: "{{ is_state('input_boolean.stove_desired_state', 'on') }}"
26 turn_on:
27 service: input_boolean.turn_on
28 data_template:
29 entity_id: >
30 {% if is_state('input_select.stove_state', 'Turned Off') %}
31 input_boolean.stove_desired_state
32 {% else %}
33 switch.null
34 {% endif %}
35 turn_off:
36 service: input_boolean.turn_off
37 data_template:
38 entity_id: >
39 {% if is_state('input_select.stove_state', 'Turned On') or is_state('input_select. stove_state', 'Turned Off') %}
40 input_boolean.stove_desired_state
41 {% else %}
42 switch.null
43 {% endif %}
44
45# your other configuration below
This also includes a notification to your phone when the temperature is low.
Accessing HA outside your local network #
Using cloudflared #
- Setup a cloudflare account with a custom domain.
- Install cloudflared:
pacman -Syu cloudflared
- Login to cloudflare:
cloudflared login
- Setup a tunnel pointing to your home assistant instance with your custom domain:
cloudflared tunnel --hostname <your sub domain>.<your domain> --url localhost:8123 --name <your tunnel preferred name>
- Allowlist your local ip to connect to homeassistant by adding the following to the root of your
$HOME/homeassistant/config/configuration.yaml
file:1http: 2 use_x_forwarded_for: true 3 trusted_proxies: 4 - ::1
- Access
<your sub domain>.<your domain>
; - ...
- Profit!
Create a systemd service to run cloudflared on boot:
- If you have a cloudflared process running, kill it:
killall cloudflared
- Create a unit file at
/etc/systemd/system/cloudflared.service
with the following content:[Unit] Description=cloudflared-homeassistant After=network-online.target Wants=network-online.target [Service] Type=simple User=<your user> Group=<your group, usually the same name as your user> ExecStart=cloudflared tunnel --hostname <your sub domain>.<your domain> --url localhost:8123 --name <your tunnel preferred name> Restart=on-failure RestartSec=10 [Install] WantedBy=multi-user.target
- Enable and start the service:
systemctl enable --now cloudflared.service
Setting up cloudflare VPN-like access:
Keep in mind that you will not be able to login with the home assistant app if you enabled this.
- Go to your cloudflare dashboard;
- Go to
Access
; - Launch Zero Trust;
- Go to
Access
>Applications
>Add an Application
>Self-Host
; - Fill out the form as you prefer, but make sure to set the
Application domain
to<your sub domain>.<your domain>
; - Carry on with remaining steps, leave everything as default if you don't know what the configuration options mean;
- Access
<your sub domain>.<your domain>
; - ...
- Profit! Keep in mind that enabling the above will make you unable to use home assistant app, you'll have to use the web interface instead.
Using the app:
- Disable cloudflare VPN-like access if you have it enabled;
- Edit your
$HOME/homeassistant/config/configuration.yaml
file and add the following:1homeassistant: 2 external_url: https://<your sub domain>.<your domain>/
- Restart home assistant;
- Install the Home Assistant app on your phone;
- Add your home assistant instance with
https://<your sub domain>.<your domain>/
as the URL;- If it fails, try clearing the app's cache and data, uninstalling the app, reboot your phone and try again from the step 1;
- ...
- Profit!