Home automation with Home Assistant on Raspberry PI – Getting Started

Hi πŸ‘‹

The purpose of this article is to get you started quickly with a Home Assistant on a Raspberry Pi. It’s a simple walkthrough on how to install Home Assistant and configure it so it will boot with your PI.

I will use my old Raspberry PI V3 board.

Flashing the Raspberry PI OS

You will need a microSD card of reasonable size, I’m using a 16GB one and a USB Adapter to connect it with my PC.

Head over to Raspberry Pi OS website and download your preferred image, for my Home Assistant I’ve chosen Raspberry Pi OS with desktop and recommended software. After the download is completed, unzip the file and prepare to flash it.

To flash the OS image on the SD card I will use a program called balenaEtcher.

Download it, select your OS image, select the SD card, and hit flash.

After SD card flashing finishes, it is time to setup the Wi-Fi connection. If you’re using an ethernet cable you can skip this step, however, remember to enable SSH.

Setting up the Wi-Fi and enabling SSH

Unplug the SD card from the computer and plug it back. You should see two new drives D: and E:

  1. Open your favorite text editor and create an empty file called ssh in drive E:. This will enable SSH access.
  2. Create a new file called wpa_supplicant.conf using your text editor and paste the following contents in it:
country=us
update_config=1
ctrl_interface=/var/run/wpa_supplicant

network={
   scan_ssid=1
   ssid="YOUR_WIFI_SSID"
   psk="YOUR_WIFI_PASSWORD"
}

Don’t forget to replace YOUR_WIFI_SSID and YOUR_WIFI_PASSWORD with the corresponding values regarding your Wi-Fi network.

Eject the SD card from your computer and plug it into the PI. At boot, the PI should automatically connect to your Wi-Fi network.

Installing Home Assistant Core

Find your Raspberry PI’s IP address and connect to it via ssh. You can run the command ssh pi@192.168.0.XXX. The password for the pi user should be raspberry.

After getting a shell, follow the instructions for installing Home Assistant from the official website.

Ensure that you run each command on its own line. Don’t directly copy the entire code block, copy each line individually.

Starting Home Assistant on boot

If you can access the Home Assistant web GUI using http://192.168.0.XXX:8123 then the next step would be to create a new systemd service so that some assistant starts at boot. Please replace XXX with your Raspberry PI’s IP address.

To create a new service:

  1. Start a new shell on the Raspberry or ensure that you’re using the pi user. We will execute commands with sudo.
  2. Use sudo nano /etc/systemd/system/hass.service to create a new file and paste the following contents into it:
[Unit]
Description=HomeAssistant Service
After=network.target

[Service]
User=homeassistant
WorkingDirectory=/home/homeassistant
Environment="PATH=$PATH:/srv/homeassistant/bin"
ExecStart=/srv/homeassistant/bin/hass

[Install]
WantedBy=multi-user.target

Stop hass command if it’s running and enables the service by executing:

sudo systemctl start hass.service
sudo systemctl enable hass.service
sudo systemctl status hass.service

If the service is running normally, everything is set up. You can safely reboot your PI and the Home Assistant service will run after boot.

Configuring Home Assistant

When visiting the Home Assistant’s web interface for the first time, you will be prompted to create a new user. You may also download the Home Assistant application for your mobile device if you wish to track things like battery, storage, steps, location and so on, in Home Assistant.

In future articles I will show you how to configure the BME680 enviromental sensor and how to activate the Apple Homekit integration. Until then, have fun exploring Home Assistant docs.

Things to do further:

Unattended Upgrades – Enable unattended upgrades for your Raspbian OS. Ensures that your OS’s is always patched and up to date.

UFW – Secure your Home Assistant server with the uncomplicated firewall.

Change default passwords or disable SSH login via password.

Thanks for reading and happy automations! πŸ“š

fzf – A command-line fuzzy finder πŸŒΈ

Hi πŸ‘‹,

fzf is a command line tool that can be used to fuzzy search files, history, and command outputs. Check out the Github repository.

This is a tool that I wish I’ve knew about earlier in my career, and for this reason I decided to blog about it.

You can also set key bindings; some popular ones are:

CTRL-T – Paste the selected files and directories onto the command-line

CTRL-R – Paste the selected command from history onto the command-line

ALT-C – cd into the selected directory

If you’re on Linux and want to try it, then installing it using Git is straight forward and it also sets up your shell and key bindings.

On Windows, to enable the key bindings you can install the PSFzf module by running Install-Module PSFzf in an admin Powershell.

Edit your $PROFILE file and add the following items:

Remove-PSReadlineKeyHandler 'Ctrl+r'
Remove-PSReadlineKeyHandler 'Ctrl+t'
Import-Module PSFzf

Thanks for reading! 🍻

FastAPI Uvicorn logging in Production

Hello πŸ™‹β€β™‚οΈ,

Running a ⏩FastAPI ⏩ application in production is very easy and fast, but along the way some Uvicorn logs are lost.

In this article I will discuss how to write a custom UvicornWorker and to centralize your logging configuration into a single file.

To keep things as simple as possible I’ve put all my code in a single Python file.

main.py

import uvicorn as uvicorn
from fastapi import FastAPI, APIRouter

router = APIRouter(prefix="")


def create_app():
    fast_app = FastAPI()
    fast_app.include_router(router)
    return fast_app


@router.get("/")
def read_root():
    return {"Hello": "World"}


if __name__ == '__main__':
    app = create_app()
    uvicorn.run(app=app)

Running the code will return a {"Hello": "World"} json when you visit the root endpoint / at http://127.0.0.1:8000. 😁

When you check the console window, the following log lines are printed:

INFO:     Started server process [10276]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     127.0.0.1:53491 - "GET / HTTP/1.1" 200 OK

Notice the Uvicorn log GET / HTTP/1.1″ 200 OK.

According to Uvicorn’s deployment docs we should run Uvicorn in a production settings with the following command: gunicorn -k uvicorn.workers.UvicornWorker main:create_app.

(venv2) ➜  FastAPILogging gunicorn -k uvicorn.workers.UvicornWorker main:create_app
[2021-05-17 22:10:44 +0300] [6250] [INFO] Starting gunicorn 20.1.0
[2021-05-17 22:10:44 +0300] [6250] [INFO] Listening at: http://127.0.0.1:8000 (6250)
[2021-05-17 22:10:44 +0300] [6250] [INFO] Using worker: uvicorn.workers.UvicornWorker
[2021-05-17 22:10:44 +0300] [6252] [INFO] Booting worker with pid: 6252
[2021-05-17 22:10:45 +0300] [6252] [WARNING] ASGI app factory detected. Using it, but please consider setting the --factory flag explicitly.
[2021-05-17 22:10:45 +0300] [6252] [INFO] Started server process [6252]
[2021-05-17 22:10:45 +0300] [6252] [INFO] Waiting for application startup.
[2021-05-17 22:10:45 +0300] [6252] [INFO] Application startup complete.

Now, if we visit the root endpoint, the console won’t print “GET / HTTP/1.1” 200 OK anymore/ πŸ€¦β€β™‚οΈ.

To fix it we need a custom UvicornWorker βš™ and a logging configuration file πŸ—ƒ.

Create a new file and name it logging.yaml, then paste the following contents in it:

version: 1
disable_existing_loggers: false

formatters:
standard:
format: "%(asctime)s - %(levelname)s - %(message)s"

handlers:
console:
class: logging.StreamHandler
formatter: standard
stream: ext://sys.stdout

loggers:
uvicorn:
error:
propagate: true

root:
level: INFO
handlers: [console]
propagate: no

This file will configure our root logger and our Uvicorn logger. To read more on the topic please see Python logging configuration.

Next, we will create a custom UvicornWorker class that will set log_config to the path of our logging.yaml file, to pass the logging configuration that we’ve just made to Uvicorn. πŸ¦„

I added the following code in main.py:

class MyUvicornWorker(UvicornWorker):
    CONFIG_KWARGS = {
        "log_config": "/mnt/c/Users/denis/PycharmProjects/FastAPILogging/logging.yaml",
    }

β–Ά If we run the application with:

gunicorn -k main.MyUvicornWorker main:create_app

We should see the Uvicorn access logs printed in the console πŸ¦„

(venv2) ➜  FastAPILogging gunicorn -k main.MyUvicornWorker main:create_app
[2021-05-17 22:31:28 +0300] [6278] [INFO] Starting gunicorn 20.1.0
[2021-05-17 22:31:28 +0300] [6278] [INFO] Listening at: http://127.0.0.1:8000 (6278)
[2021-05-17 22:31:28 +0300] [6278] [INFO] Using worker: main.MyUvicornWorker
[2021-05-17 22:31:28 +0300] [6280] [INFO] Booting worker with pid: 6280
2021-05-17 22:31:28,185 - WARNING - ASGI app factory detected. Using it, but please consider setting the --factory flag explicitly.
2021-05-17 22:31:28,185 - INFO - Started server process [6280]
2021-05-17 22:31:28,185 - INFO - Waiting for application startup.
2021-05-17 22:31:28,185 - INFO - Application startup complete.
2021-05-17 22:31:30,129 - INFO - 127.0.0.1:54004 - "GET / HTTP/1.1" 200

Thanks for reading! πŸ“š

requirements.txt

click==7.1.2
fastapi==0.65.1
gunicorn==20.1.0
h11==0.12.0
httptools==0.2.0
pydantic==1.8.2
PyYAML==5.4.1
starlette==0.14.2
typing-extensions==3.10.0.0
uvicorn==0.13.4
uvloop==0.15.2