<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Ben Basten</title><description>Full stack developer with a passion for accessibility, sustainable open source software, and collaboration.</description><link>https://www.benbasten.com/</link><language>en-us</language><item><title>Building Frontend with Right-to-Left Support</title><link>https://www.benbasten.com/posts/building-right-to-left/</link><guid isPermaLink="true">https://www.benbasten.com/posts/building-right-to-left/</guid><description>Using web standards and TailwindCSS tooling to build intuitive websites for right-to-left languages.</description><pubDate>Wed, 08 Jul 2026 00:02:13 GMT</pubDate><content:encoded>Supporting right-to-left (RTL) languages such as Arabic requires intentional development to guarantee a consistent and equitable browsing experience regardless of the language a user speaks. Web standards and Tailwind tooling are here to help!

The goal is to provide an equitable browsing experience for RTL users that is equivalent to the experience of users browsing the site in English. By mirroring important content to the right side of the page, we guide RTL users through the same key pathways and draw their attention to the same focal points that English speakers would naturally encounter.

A notable exception to this is progress bars for media like audio or video. Historically these UI elements were built to mimic cassette players, which always progress from left to right.

## Project configuration

To get started, apply `dir=&quot;rtl&quot;` to the root `&lt;html&gt;` element of the page for pages localized into a right-to-left language. Some of the layout will automatically adjust out of the box; CSS grid and flexbox get mirrored with no additional configuration.

Next, add a new &quot;custom variant&quot; in the TailwindCSS configuration to allow quick RTL styling shorthand in Tailwind classes.

```css
/* main.css */
@custom-variant rtl (&amp;:dir(rtl));
```

With the new custom variant, styling such as `translateX` transforms can be quickly mirrored for RTL languages: `translate-x-5 rtl:-translate-x-5`

Finally, consider adding utility functions for determining if the page is in RTL direction and mirroring arrow key handlers. I&apos;ve used this for handling keydown events in carousels that have left/right arrow key navigation to change slides, for example.

```ts
export const isRtl = (): boolean =&gt; {
  if (typeof document === &quot;undefined&quot;) return false;
  return document.documentElement.dir === &quot;rtl&quot;;
};

export const isForwardArrow = (key: string) =&gt; {
  const forwardKey = isRtl() ? &quot;ArrowLeft&quot; : &quot;ArrowRight&quot;;
  return key === forwardKey;
};

export const isBackwardArrow = (key: string) =&gt; {
  const backwardKey = isRtl() ? &quot;ArrowRight&quot; : &quot;ArrowLeft&quot;;
  return key === backwardKey;
};
```

## CSS logical properties

Logical properties define direction-relative layouts for elements, rather than physically specifying where an element should go. Instead of using physical properties like `left`, `right`, `margin-left`, or `margin-right`, there are relative equivalents like `inset-inline-start`, `inset-inline-end`, `margin-inline-start`, and `margin-inline-end`.

Using logical properties should be the default when building for RTL languages. This will solve the majority of RTL layout issues automatically. [Tailwind CSS v4.2 and later](https://tailwindcss.com/blog/tailwindcss-v4-3#more-logical-property-utilities) has wide support for these logical properties.

For further reading on logical properties, see the [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Logical_properties_and_values).

## Handling English text in RTL layouts

It&apos;s possible that a site may have a mix of RTL content and English content. The site may include English titles or names, or maybe the content is driven by a content management system and authors are still in the process of translating content. This creates scenarios where English text is right-justified and hard to read, or punctuation in the English text gets misplaced.

For example, for the following sample text:

&gt; Hello world!

If `dir=&quot;rtl&quot;` gets applied to a parent or ancestor of this element, it moves the punctuation:

&gt; !Hello world

This happens because the Unicode Bidirectional Algorithm that determines how text should be laid out in the browser starts by looking at the rightmost character in a block of text to determine if it should be laid out LTR or RTL. The &quot;!&quot; is a non-directional character, so it gets repositioned. The next character it looks at is &quot;o&quot;, which is a LTR character, so it stays in place.

In these situations where an element can have either LTR or RTL content, the `dir=&quot;auto&quot;` attribute can help. [According to MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/dir), this uses a basic algorithm that &quot;parses the characters inside the element until it finds a character with a strong directionality, then applies that directionality to the whole element.&quot; This resolves the punctuation issue, but it should usually be applied selectively.

With `dir` set to &quot;auto&quot;, the text goes back to looking as expected:

&gt; Hello world!

This approach is usually most effective when focusing use of the &quot;auto&quot; direction to specific pieces of text like headings. Applying this fix on larger chunks of text that include both English and RTL content could cause the opposite issue, where RTL languages get incorrectly formatted instead.

Thank you to Spotify for the [explainer about the punctuation issue](https://engineering.atspotify.com/2019/4/right-to-left-the-mirror-world).

## AI agent SKILL

I created a skill to instruct agents how to build RTL-ready frontend experiences or migrate an existing codebase. The skill includes a mapping of how to convert existing Tailwind styling to use the more responsive logical properties.

To give it a try, install the skill using the [skills.sh](https://www.skills.sh/) command line tool:

```bash
npx skills add https://github.com/ben-basten/skills --skill right-to-left
```

Or check out the source code: &lt;https://github.com/ben-basten/skills/blob/main/skills/right-to-left/SKILL.md&gt;</content:encoded></item><item><title>How to Host Home Assistant in a TrueNAS Scale VM</title><link>https://www.benbasten.com/posts/home-assistant-in-truenas-vm/</link><guid isPermaLink="true">https://www.benbasten.com/posts/home-assistant-in-truenas-vm/</guid><description>Unlocking the full capabilities of Home Assistant Operating System using a TrueNAS virtual machine.</description><pubDate>Mon, 14 Oct 2024 23:10:49 GMT</pubDate><content:encoded>**Objective:** migrate an existing Home Assistant Container installation to Home Assistant OS using a virtual machine on a TrueNAS Scale host.

Additional requirements:

- USB passthrough to the VM for a Zigbee controller
- VM is on a different VLAN than the TrueNAS host
- VM allows network requests to the TrueNAS host to allow for file share access
- Restore prior Home Assistant backup from a Home Assistant Container installation

Instructions for creating a Home Assistant VM in TrueNAS Scale were largely inspired by this forum post - kudos to all of the documentation there.

&lt;https://community.home-assistant.io/t/installing-haos-in-a-vm-on-truenas-scale/511393&gt;

## Backup the existing Home Assistant installation

For this tutorial, the existing installation is using the HA Docker container. These steps may work with other installation methods as well.

1. Sign in to the existing HA installation, and navigate to Settings &gt; System &gt; Backups
2. Click the &quot;Create Backup&quot; button, then press &quot;Create&quot; in the confirmation modal.
3. Once the backup is complete, it will appear in the list. Download a copy of the latest backup.
4. `docker compose down` - stop the running Home Assistant container.

## Create the storage location

1. In the TrueNAS admin UI, create a new Zvol under &quot;Datasets &gt; New Zvol&quot;. Make sure the Zvol is 32GiB or greater in size. Take note of the resulting Zvol path.
2. Take note of the latest `*.qcow2` installation media link from [the installation documentation](https://www.home-assistant.io/installation/alternative).
3. Start a terminal session in the TrueNAS host.
4. `wget https://github.com/home-assistant/operating-system/releases/download/13.1/haos_ova-13.1.qcow2.xz` - download the installation media, replacing the URL with the latest link found in step 2.
5. `unxz haos_ova-13.1.qcow2.xz` - decompress installation media
6. `qemu-img convert -O raw haos_ova-13.1.qcow2 /dev/zvol/[PATH/TO/ZVOL]` - write the raw image to your Zvol, using the path from step 1.

## Create the network adapter

This will create the bridged network adapter that allows the VM to access shares on its host, and puts the VM on a different VLAN.

1. Navigate to Network &gt; Interfaces &gt; Add
2. Create the interface
   - Type: VLAN
   - Name: `vlan[vlan tag]`
   - DHCP: enable (unless a static IP has already been allocated)
   - Parent interface: select your network adapter, ex. `enp7s0`
   - VLAN tag: your VLAN tag
   - Leave everything else at default
3. Save &gt; Test Changes. &quot;Save Changes&quot; if successful. Take note of the IP address.
4. Create the bridge interface: Network &gt; Interfaces &gt; Add
   - Type: Bridge
   - Name: br0
   - Bridge members: `vlan[vlan tag]` (the VLAN that was just created)
   - Aliases: add an entry for the IP address that was just assigned to the VLAN
     - ex. 192.168.2.10/24
5. Save &gt; Test Changes. &quot;Save Changes&quot; if successful.
6. Edit the VLAN interface and disable DHCP. Save the changes.

## Create the VM

1. Navigate to Virtualization &gt; Add
2. Operating System
   - Guest Operating System: Linux
   - Name: home_assistant_os
   - Boot method: UEFI
   - Password: set a password, which will be used to access the VM display
   - Leave all other settings at defaults
3. CPU and Memory
   - Choose at least 2 cores and 1 thread
   - CPU Mode: Host Passthrough
   - Memory size: at least 2GiB, more is better
4. Disks
   - Use existing disk image
   - Set the path to the path of the Zvol (from prior steps, this would be PATH/TO/ZVOL)
5. Network Interface
   - Adapter Type: VirtIO
   - Mac Address: leave as-is
   - Attach NIC: br0
6. Installation Media: skip
7. GPU: defaults are ok
8. Confirm Options &gt; Save

## Restore Home Assistant backup

Find the new Home Assistant instance, and restore the previous backup.

1. In the new VM, choose &quot;Display&quot; then enter the password you set for accessing the VM display
2. Once Home Assistant is loaded, it should show the IP address that it is running on.
3. Navigate to the instance in a web browser, ex. &lt;http://192.168.2.22:8123&gt;
4. Follow the instructions to create an account with your desired username and password.
5. After setup is completed, navigate to Settings &gt; System &gt; Backups
6. Under the ellipses menu in the top right, choose &quot;Upload backup&quot;
7. Upload the backup file that was downloaded from the previous instance. This may take a couple of minutes to restore.
8. The previous Home Assistant configurations should now be visible, with failures in Zigbee due to the missing Zigbee controller.

## Pass USB Zigbee controller into the VM

The VM needs to be given access to the Zigbee controller from the TrueNAS host. I am using the &quot;ConBee II Zigbee Controller&quot;, which has known issues with the virtual machine. Rather than using USB Passthrough, the PCI controller needs to be passed through directly instead. The forum post with the instructions for PCI passthrough can be found here:

&lt;https://community.home-assistant.io/t/installing-haos-in-a-vm-on-truenas-scale/511393/51&gt;

1. Plug the Zigbee controller into the host machine. If the USB port is using USB 3, consider using a USB 2 extension cable to prevent interference with the Zigbee signal.
2. In the TrueNAS Scale UI, navigate to Virtualization
3. For the `home_assistant_os` VM, set state to off.
4. Open a shell in the TrueNAS host.
5. `ls /dev/serial/*` - list out all the serial devices. Take note of the USB PCI path. The path will look something like `pci-0000:09:00.3 ...`
6. In the TrueNAS UI, navigate to Virtualization, expand the entry for home_assistant_os, then choose Devices. Click &quot;Add&quot;.

- Type: PCI Passthrough Device
- PCI Passthrough Device: find the entry that matches the ID from step 5. This will look something like `0000:09:00.3 &apos;USB controller&apos;: Matisse USB 3.0 Host Controller`
- Device Order: increment this to the next ID that&apos;s not already being used by a device. In my case, this was `1004`.

7. Save. Navigate back to the &quot;Virtualization&quot; page, then set the state toggle for home_assistant_os to ON.
8. Once Home Assistant boots, check that Zigbee is working. You should be all set!

## Troubleshooting issues with USB controller

It&apos;s possible that the path for the USB controller in the Docker container was mapped to a different path than it is in the new Docker VM. This path is set in the `/config/.storage/core.config_entries` file for further troubleshooting.

Consider installing the &quot;Visual Studio Code&quot; addon for easy access to a terminal and a text editor for config files or logs.

## Configuring backups to a network share

1. In Home Assistant, navigate to Settings &gt; System &gt; Storage
2. Click &quot;Add network storage&quot;
3. Fill in the details for your network share, using the IP address of the TrueNAS Scale host
4. Navigate to Settings &gt; System &gt; Backups
5. Under the ellipses menu in the top right, choose &quot;Change default backup location&quot;
6. Select the network share that was just added

## Configuring automatic nightly backups

1. Navigate to Settings &gt; Automations &amp; scenes &gt; Create automation
2. Use the following YAML:

```yml
alias: Nightly backup
description: &quot;&quot;
mode: single
triggers:
  - at: &quot;23:00:00&quot;
    trigger: time
conditions: []
actions:
  - action: hassio.backup_full
    metadata: {}
    data:
      compressed: true
      homeassistant_exclude_database: false
```

3. Save, and run the automation once to test that it worked.

## Next steps

See the [&quot;Common Tasks - Operating System&quot;](https://www.home-assistant.io/common-tasks/os/) documenation for ideas what to do next!</content:encoded></item><item><title>Wake Up to an SMS Message</title><link>https://www.benbasten.com/posts/wake-up-to-an-sms-message/</link><guid isPermaLink="true">https://www.benbasten.com/posts/wake-up-to-an-sms-message/</guid><description>Using Home Assistant automation to guarantee that I wake up when I&apos;m on call.</description><pubDate>Mon, 19 Feb 2024 01:05:35 GMT</pubDate><content:encoded>**Problem statement:**

Automate a way to guarantee waking up when an SMS message is received from specified phone numbers. My on call rotation pages me with time-sensitive text messages, so I need to guarantee that I wake up on time!

**Solution overview:**

When SMS is received, phone volume will be increased, a song will play, and lights will be turned on using the Home Assistant REST API. This solution only works with Android phones.

**How to set this up:**

1. Create a Home Assistant &quot;Group&quot; with all of the lights to turn on
   1. In the Home Assistant app, navigate to Settings &gt; Devices &amp; services &gt; Helpers &gt; Create helper
   2. Choose &quot;Group&quot; &gt; &quot;Switch group&quot;
   3. Give it a name, and input all of the light switch entities to turn on.
   4. &quot;Submit&quot; to save this new group!
2. Generate Home Assistant access token
   1. In the Home Assistant app, select your profile photo to navigate to &quot;Profile&quot; settings.
   2. Find &quot;Long-lived access tokens&quot;, then choose &quot;Create token&quot;.
   3. Copy the shown token to use later.
3. Set up lights automation
   1. Download the &quot;[Tasker](https://play.google.com/store/apps/details?id=net.dinglisch.android.taskerm)&quot; Android app. At the time of writing, it is $3.49 on the Google Play Store.
   2. In the &quot;Tasks&quot; tab, select the &quot;+&quot; floating action button. Give it a name, like &quot;Notification Task&quot;
   3. In the &quot;Task Edit&quot; screen, select the &quot;+&quot; floating action button &gt; &quot;Net&quot; &gt; &quot;HTTP Request&quot;
   4. Fill in the HTTP request details:
      - URL: `http://your_ha_ip:8123/api/services/switch/turn_on`
      - Headers
        ```
        Authorization:Bearer your_access_token
        Content-Type:application/json
        ```
      - Body
        ```json
        { &quot;entity_id&quot;: &quot;switch.your_light_group&quot; }
        ```
      - Check the box &quot;Continue Task After Error&quot;
   5. Select the back button to save changes
   6. There is a play button in the bottom left corner to test that your HTTP request actually turns on the lights :)
4. Set up sound automation
   1. Select the &quot;+&quot; floating action button to create a new Action.
   2. Choose Audio &gt; Media Volume &gt; Set &quot;Level&quot; slider to desired volume.
   3. Create another action, then choose Media &gt; Music Play
   4. In the &quot;File&quot; field, input the file path to your desired audio file to play.
   5. Press the back button 2x to save the Action and Task, which should now include turning on the lights, turning up the phone volume, and playing a song.
5. Set up SMS trigger
   1. In the &quot;Profiles&quot; tab, press the &quot;+&quot; floating action button &gt; Create &gt; Event &gt; Phone &gt; Received Text
   2. In the &quot;Sender&quot; field, select all contacts that you would like to receive notifications from in the event of a text message
   3. Press the back button to save. You will now be prompted to choose a Task that is kicked off when the trigger SMS is received.
   4. Choose the &quot;Notification Task&quot; (or whatever name was assigned in step 3.2) that was just created.
   5. Press the check mark button in the top nav to save. You&apos;re ready to go! 🎉</content:encoded></item><item><title>Debian Linux Initial Setup Guide</title><link>https://www.benbasten.com/posts/debian-linux-initial-setup-guide/</link><guid isPermaLink="true">https://www.benbasten.com/posts/debian-linux-initial-setup-guide/</guid><description>My new Linux machine configuration, as of November 2023.</description><pubDate>Sun, 12 Nov 2023 21:48:29 GMT</pubDate><content:encoded>Whenever I buy a computer or have to re-install the operating system, I find myself gravitating towards Debian-based Linux distributions for the operating system. In the recent past, this has included Ubuntu, Raspberry Pi OS, and Pop!\_OS. I have to run through very similar initial steps to get started with all of these, so it&apos;s about time to document them!

## Update the computer! ⬆

Run the command: `sudo apt-get update &amp;&amp; sudo apt-get upgrade`

This will check for updates and install them.

## Add firewall and disable unnecessary services 🛡️

Install ufw (uncomplicated firewall): `sudo apt install ufw`

For Ubuntu devices, remove the Apache web server: `sudo apt purge apache2`

## Setup remote access 🌐

I have 2 use cases for machines - headless servers, and daily drivers PCs that I need the graphical user interface for. Setup varies slightly for the different use cases.

1. Install Tailscale VPN: https://tailscale.com/download
2. Install SSH (for headless systems)

- `sudo apt install openssh-server` - installs the SSH server
- `sudo systemctl start ssh` - start the SSH server
- `sudo systemctl enable ssh` - enable SSH on computer boot

3. Install fail2ban SSH intrusion software, using default settings

- `sudo apt install fail2ban` - install the software
- `sudo systemctl enable fail2ban` - enable fail2ban on computer boot
- `sudo systemctl start fail2ban` - start the fail2ban service

4. Setup key-based SSH login

- On any client devices, generate SSH keys using `ssh-keygen` and copy the public key to the server using `ssh-copy-id`
- Disable root login and password login in the SSH configuration file `/etc/ssh/sshd_config`
  - Set: `PasswordAuthentication no`
  - Set: `PermitRootLogin no`
  - Save changes
  - `sudo systemctl restart ssh` - restart the SSH service to apply changes

## Install dev tools 🛠️

- Git: version control tool
  - `sudo apt install git`
  - If using GitHub repositories:
    - setup fine-grained Git access tokens, for scoped access to private Git information
    - setup signed commits
- net-tools: utilities for managing network, including `ifconfig` to get network adapter information
  - `sudo apt install net-tools`
- Neovim: a more feature rich version of Vim, which is a terminal text editor
  - `sudo apt-get install neovim`
- Docker: containerization tool, which I use to run many services on my network
  - Installation instructions: https://docs.docker.com/engine/install/

## Setup user session scripts 📄

Add the following to the `~/.bash_profile` file:

```bash
# Quickly navigate to Git repository directory
alias repo=&apos;cd ~/repos&apos;
# Quickly clear the screen input, using the Windows command
alias cls=&apos;clear&apos;
# Checkout the main branch and pull
alias main=&apos;git checkout main &amp;&amp; git pull&apos;
# Set my terminal prompt, so it has Git branch information and looks consistent across devices
export PS1=&apos;\n\[\e[1;37m\]\[\e[1;32m\]\u\[\e[0;39m\]@\[\e[1;36m\]\h\[\e[0;39m\]:\[\e[1;33m\]\w\[\e[0;39m\]\[\e[1;35m\]$(__git_ps1 &quot; (%s)&quot;)\[\e[0;39m\]\[\e[1;37m\]\[\e[0;39m\]\n$ &apos;
# Simplify the computer update process with an &quot;update&quot; command
alias update=&apos;sudo apt update &amp;&amp; sudo apt upgrade&apos;
```

## Disable Ubuntu crash reporting and telemetry 🕶️

Run the following commands:

```bash
sudo apt purge -y apport
sudo apt remove -y popularity-contest
sudo apt autoremove -y
```

## Setup computer backups 🔄

The methods for backing up your machine can widely vary here. My usual go-to is running [syncthing](https://github.com/syncthing/syncthing) with Docker to keep important files backed up with a storage server.

## Other 😄

For headed systems: set keyboard shortcuts! Ideas for shortcuts to add usually include:

- opening applications menu, search, workspaces
- play, pause, next song, previous song
- mute microphone</content:encoded></item><item><title>Setting Up Zigbee With Home Assistant</title><link>https://www.benbasten.com/posts/setting-up-zigbee-with-home-assistant/</link><guid isPermaLink="true">https://www.benbasten.com/posts/setting-up-zigbee-with-home-assistant/</guid><description>Expanding my home automation with a network of Zigbee devices.</description><pubDate>Wed, 23 Nov 2022 03:01:08 GMT</pubDate><content:encoded>Now that my Home Assistant server is set up, it&apos;s time to start adding device integrations! But... there&apos;s some choices to make before diving into this and buying new smart devices. Let&apos;s break those down!

There are 3 main ways to connect a device to Home Assistant: Zigbee, Z-Wave, and WiFi. Zigbee has 2 different techniques that you can use to pair devices: Zigbee Home Automation (ZHA) and Zigbee2MQTT.

For starters, there&apos;s **WiFi**. Devices connect to your local network, and since your Home Assistant server _is on the same network_ they can see each other and integrate. These devices are very common. The downside here is that there&apos;s nothing stopping your WiFi device from talking to the external web. Possible solutions for preventing this include installing custom firmware onto the device (which may require some soldering) or blocking external access to the device from your router (which may lead to loss in device functionality).

Next up, there&apos;s **Z-Wave**. Z-Wave is a mesh network for devices, where all of your smart devices can talk to each other and communicate with your server through a USB receiver.

Finally, there&apos;s **Zigbee**. Zigbee is similar to Z-Wave in that it is a mesh network of devices that communicates to your server through a USB receiver. The range may be slightly less than Z-Wave, since it uses the same 2.4Ghz frequency as your WiFi network.

I ended up choosing to get into the Zigbee ecosystem because the compatible devices that I needed were easy to find, and the ZHA pairing process looked simple.

## The hardware I&apos;m using

- **Zigbee receiver:** ConBee II Universal Zigbee USB Gateway, with USB 2.0 extension cable
- **Zigbee smart devices**
  - Sengled Smart Plugs - [Amazon link](https://www.amazon.com/Sengled-Compatible-Required-Appliances-Certified/dp/B08FJ5LHSN/ref=sr_1_5?keywords=sengled+zigbee+plug&amp;qid=1669000687&amp;sr=8-5)
    - _Note: this device can work as a Zigbee repeater. See &quot;Using Zigbee device as a repeater&quot; below._
  - THIRDREALITY Zigbee Smart Button - [Amazon link](https://www.amazon.com/THIRDREALITY-Compatible-SmartThings-Assistant-Included/dp/B09ZQGZX3G/ref=sr_1_4?crid=3V5I6WU6Q323F&amp;keywords=third+reality+light+switch&amp;qid=1669000776&amp;sprefix=thirdreality+light+switc%2Caps%2C116&amp;sr=8-4)

## Setting up the Zigbee receiver

Before getting started, it&apos;s important to note that Zigbee is very prone to interference from USB 3.0 ports. It is recommended to use a USB 2.0 extension cable to prevent connection issues and increase Zigbee reliability.

### Part 1: passing Zigbee receiver into Docker container

1. Plug your ConBee receiver USB stick into the extension cable, and plug the extension cable into an available USB port on the computer. The extension cable prevents signal interference from your computer.
2. Confirm that your ConBee receiver is talking with your Raspberry Pi.
   1. Enter the command `lsusb` (list USB devices), and you should see an entry saying something similar to &quot;Dresden Elektronik ZigBee gateway&quot;.
   2. `ls -la /dev | grep ttyACM*` - list out all the devices in your &quot;/dev&quot; folder and find any that match the pattern &quot;ttyACM\*&quot;. Your ConBee USB device will be one of these, and this is what needs to be passed to the Docker container.
3. Troubleshooting: if you&apos;re not seeing your device showing up, follow the [manufacturer&apos;s instruction](https://phoscon.de/en/conbee2/install#raspbian) to install the software for your ConBee II. Repeat step 2 to confirm that this worked.
4. Modify your `compose.yml` to pass through your USB Zigbee receiver into the Docker container. It&apos;ll look something like this:
   ```yml
   version: &quot;3&quot;
   services:
     homeassistant:
       container_name: homeassistant
       image: &quot;ghcr.io/home-assistant/home-assistant:stable&quot;
       volumes:
         - /home/joanna/dev/config:/config
         - /etc/localtime:/etc/localtime:ro
       devices: # New entry for your ConBee device
         - /dev/ttyACM0:/dev/ttyUSB0 # Taking the USB device in your file system, &quot;/dev/ttyACM0&quot;,
           # and placing it in the container file system at &quot;/dev/ttyUSB0&quot;
       restart: unless-stopped
       privileged: false
       network_mode: host
   ```
5. In the same directory where your `compose.yml` lives, restart the Docker container with the new configuration. `sudo docker compose up -d`

### Part 2: setup receiver with Home Assistant

1. Log in to the Home Assistant UI, and go to &quot;Settings &gt; Devices &amp; Services &gt; Add Integration&quot;
2. Search for &quot;zha&quot;, and choose &quot;Zigbee Home Automation&quot;.
3. You will be prompted to input the path to your USB device. Select `/dev/ttyUSB0` from the dropdown.
4. If prompted to inptu the type of radio hardware, choose &quot;deconz&quot;.
5. Choose the &quot;Area&quot; in your home for your device (in my case, I made one called &quot;Apartment&quot; since this controller will be used for devices throughout the home), and click &quot;Finish&quot;. Your receiver is ready to start pairing!

## How to connect Zigbee devices

These instructions are for pairing your Zigbee devices via &quot;Zigbee Home Assistant&quot;, also known as &quot;ZHA&quot;. I chose this technique because the integration ships with the default Home Assistant installation with no additional configuration. The easier the better!

1. Follow the instructions on your device to turn it on and start pairing mode. In the case of the Sengled smart plugs, they&apos;re in pairing mode by default when you plug them in.
2. Go into &quot;Settings &gt; Devices &amp; Services &gt; Add Integration&quot;, search for &quot;zha&quot; and select &quot;Zigbee Home Automation&quot;.
3. Choose &quot;Add Zigbee Device&quot;.
4. You&apos;ll see a message saying &quot;Searching for Zigbee devices...&quot;. Your device should show up quickly. Give it a name and select the Area in the house that it belongs to for grouping (ex. &quot;Living Room&quot;) and you&apos;re good to go! The new device will show up in your landing dashboard.

### Using Zigbee device as a repeater

Some Zigbee devices can be used as &quot;repeaters&quot;, meaning that you can connect new devices to this repeater rather than to the USB receiver directly. Since they all connect in a mesh network, this will not cause any problems with communication to your Home Assistant server.

I used this functionality for rooms deeper in my apartment, and paired new devices to the nearest Zigbee device rather than the USB receiver directly.

1. Go to &quot;Settings &gt; Devices &amp; Services&quot;.
2. Under &quot;Zigbee Home Automation&quot;, click &quot;Configure&quot;.
3. Click &quot;Devices&quot;, then choose the device that you would like to connect to as a repeater.
4. In the &quot;Device Info&quot; card, click the three ellipses &quot;...&quot;, then choose &quot;Add devices via this device&quot;.
5. The pairing process is now the same as just adding another Zigbee device. Give the device a name and area assignment, and you&apos;re off to the races!</content:encoded></item><item><title>Getting Started with Home Assistant</title><link>https://www.benbasten.com/posts/getting-started-with-home-assistant/</link><guid isPermaLink="true">https://www.benbasten.com/posts/getting-started-with-home-assistant/</guid><description>Taking control of my privacy and smart home devices by hosting container-based Home Assistant.</description><pubDate>Tue, 15 Nov 2022 23:20:36 GMT</pubDate><content:encoded>I have been spending some time learning more about cybersecurity, and the more I learn the more I become suspicious of the internet connected devices that I use on a daily basis. For example, I&apos;m a daily user of WiFi smart plugs. I love being able to remotely schedule my lights to turn on and off, or simply just turn on all of the living room lights without having to individually toggle all of the lamps. But are they secure?

How often are these plugs sending requests to the remote server? Is their network traffic encrypted with SSL? Are my daily usage patterns being tracked? Is the remote server logging my location? Who is managing this remote server?

...are a couple of questions that come to mind. After doing some reading, I found a solution for many of these problems - hosting the home automation server myself using the free and open-source &quot;Home Assistant&quot; software.

## So... what is Home Assistant?

Home Assistant puts the power of smart home automation in your hands, where the central controller is a local server. HA can integrate with a variety of different devices, including thermostats, plugs, lights, solar panels, and more.

There&apos;s alternative home automation ecosystems like Samsung SmartThings, but there were a couple of factors that led me to choose Home Assistant:

- **Active community:** I&apos;ve found all sorts of forum posts, Reddit threads, and GitHub repos with folks sharing about their experiences.
- **Open source:** the software is out in the open for anyone to see. It&apos;s also empowering - anyone can open an issue report in GitHub or propose solutions.
- **Solid device support:** from what I&apos;ve seen so far, it seems like Home Assistant supports integrations with a wide variety of devices out of the box. Some require more setup than others....

All that being said, I&apos;ve found that this experiment isn&apos;t for the faint of heart. It&apos;s still up to you to configure and maintain your personal setup.

## Installation Background

For this HA installation, I will be installing the software on a Raspberry Pi.

There are a couple of different methods for installing Home Assistant, as outlined by [the documentation](https://www.home-assistant.io/installation/raspberrypi/). Options include:

1. Installing the Home Assistant operating system
2. Running Home Assistant in a Docker container
3. Installing Home Assistant Core, which is essentially a Python package

I opted for #2, creating a docker container. One thing to note is that the Docker installation of Home Assistant _does not_ include &quot;Supervisor&quot; functionality, which gives you access to the addon store. This functionality is only available with the Home Assistant OS, read more about it [here](https://www.home-assistant.io/integrations/hassio/). I didn&apos;t know about this going into the installation, but so far it hasn&apos;t been a showstopper and I&apos;ve been able to setup everything that I need.

## Setting up Home Assistant with Docker Container

A prerequisite to this task is to make sure that the Raspbian OS is installed on your machine. See installation options [here](https://www.raspberrypi.com/documentation/computers/getting-started.html#installing-the-operating-system).

Before firing up the Docker Container, I did a couple of things to prepare the system.

**Setup SSH access**

1. `sudo apt-get install openssh-server` - installs the SSH software
2. `sudo systemctl enable ssh` - enable the service
3. `sudo systemctl start ssh` - start the SSH service
4. Edit your `/etc/ssh/sshd_config` file, and set the `PermitRootLogin` property to `no`. This will prevent remote users from trying to login as the `root` user.
5. `sudo apt install fail2ban` - install the fail2ban software that protects the computer from malicious logins by scanning log files.
6. `sudo systemctl status fail2ban` - verify that the service is active.

**Setup the firewall**

1. `sudo apt install ufw` - install ufw, AKA &quot;uncomplicated firewall&quot;
2. `sudo ufw allow 22` - allow access through the firewall on port 22. This will allow you to remotely access your computer over SSH, without requiring a monitor.
3. `sudo ufw enable` - enable the service
4. `sudo ufw status` - you should see a message indicating that the firewall is now active

**Install Docker**

Since Docker is being installed on Raspbian OS, the documentation indicates that the &quot;convenience script&quot; is required for installing Docker. [Find the instructions here](https://docs.docker.com/engine/install/debian/#install-using-the-convenience-script). Those steps will probably be more up-to-date than this documentation.

One thing to note is that this installation unfortunately requires running Docker as the `root` user. There&apos;s additional post-installation steps required to set it up more securely in root-less mode.

## Starting the Home Assistant container

We&apos;ll be using Docker Compose to start Home Assistant. This requires a `compose.yml` file with your Docker configurations.

1. `mkdir home-assistant` - create a directory for all of the Home Assistant-related installation files. Feel free to create it wherever you&apos;d like.
2. `mkdir home-assistant/config` - create the `config/` directory, which will shortly be where the Home Assistant will be storing all of its configuration files.
3. `touch home-assistant/compose.yml` - file for the Docker settings
4. Modify `home-assistant/compose.yml` with the following:
   ```yml
   version: &quot;3&quot;
   services:
     homeassistant:
       container_name: homeassistant
       image: &quot;ghcr.io/home-assistant/home-assistant:stable&quot;
       volumes:
         - YOUR_PATH_TO_CONFIG:/config
         - /etc/localtime:/etc/localtime:ro
       restart: unless-stopped
       privileged: false
       network_mode: host
   ```
   - Note: YOUR_PATH_TO_CONFIG needs to be replaced with the path to the `config/` directory that was just created. It could look something like this: `/home/yourUsername/home-assistant/config`
5. `docker pull ghcr.io/home-assistant/home-assistant:stable` - make sure the Docker image is up to date
6. `sudo docker compose up -d` - start your Docker container! Your Home Assistant server will be listening on port 8123 by default. Check it out at http://localhost:8123/!

## Onboarding

Now that Docker is up and running, you&apos;re good to get started with the Onboarding process! The web client will guide you through the process of creating a local user account and doing the initial setup. You can read more about that process [here](https://www.home-assistant.io/getting-started/onboarding/).

With these initial setup steps, your Home Assistant instance will only be accessible from your internal network.

## On my radar to try next...

- Setting up Zigbee devices with HA
- Setting up external access to the HA instance
- Connecting HA to Google Assistant, primarily to enable voice commands with a smart speaker. This requires external access to the server with https enabled.</content:encoded></item><item><title>Switching Between Java Versions</title><link>https://www.benbasten.com/posts/switching-between-java-versions/</link><guid isPermaLink="true">https://www.benbasten.com/posts/switching-between-java-versions/</guid><description>How to quickly change Java versions in a Unix terminal environment, to make working with numerous Java apps easier.</description><pubDate>Thu, 17 Feb 2022 02:47:54 GMT</pubDate><content:encoded>Problem: How do I quickly change between Java versions in the terminal?

I&apos;m currently doing development on an array of different Java apps. For the longest time, all of the apps I was working with only used Java 8. My team is now moving towards a Java 11 stack, so I can&apos;t run these apps with just the Java 8 JDK anymore.

This solution is for the zsh shell on a Mac computer.

The key lies with the `JAVA_HOME` environment variable. This dictates what version of Java to run when a command is executed. Using aliases, you will be able to quickly set this environment variable.

## List out all installed JDKs

Macs have an executable under `/usr/libexec/java_home` that can quickly list all installed JDKs, and get the Java path for any of these individual JDKs.

Enter the command `/usr/libexec/java_home -V` to get the list of installed JDKs. The output will look like this:

```
Matching Java Virtual Machines (2):
    11.0.14 (x86_64) &quot;Oracle Corporation&quot; - &quot;Java SE 11.0.14&quot; /Library/Java/JavaVirtualMachines/jdk-11.0.14.jdk/Contents/Home
    1.8.0_281 (x86_64) &quot;Oracle Corporation&quot; - &quot;Java SE 8&quot; /Library/Java/JavaVirtualMachines/jdk1.8.0_281.jdk/Contents/Home
```

There&apos;s 2 installations of Java - 11.0.14 and 1.8.0_281.

## Get the path of a specific JDK installation

`/usr/libexec/java_home -v 11` will display the path of your Java 11 installation:

```
/Library/Java/JavaVirtualMachines/jdk-11.0.14.jdk/Contents/Home
```

If you have even more than 2 installations, you can get the path of a specific Java minor version. For example, `/usr/libexec/java_home -v 1.8.0_281` will look like this:

```
/Library/Java/JavaVirtualMachines/jdk1.8.0_281.jdk/Contents/Home
```

## Changing the Java version

Using these commands to get a Java installation path, you can quickly change the `JAVA_HOME` environment variable using the `export` command.

- Set Java 8: ``export JAVA_HOME=`/usr/libexec/java_home -v 1.8.0_281` ``
- Set Java 11: ``export JAVA_HOME=`/usr/libexec/java_home -v 11` ``
- Check the current Java version: `echo $JAVA_HOME`

## Adding aliases to quickly change versions

1. `cd` - navigate to your home directory
2. With your preferred text editor (nano, vi, vim, etc.), open up the `.zshrc` file.
   - For example: `nano .zshrc`
3. Add the following lines to create new aliases:
   ```
   alias home=&apos;echo $JAVA_HOME&apos;
   alias java8=&apos;export JAVA_HOME=`/usr/libexec/java_home -v 1.8.0_281`&apos;
   alias java11=&apos;export JAVA_HOME=`/usr/libexec/java_home -v 11`&apos;
   ```
4. Save, and restart the terminal for the changes to be applied.

Now, to change the Java versions the following commands can be used:

- `java8` - set version to Java 8
- `java11` - set version to Java 11
- `home` - output the current JAVA_HOME path to quickly check which version is active

Happy coding!</content:encoded></item><item><title>Starting a blog with Hugo... lots to learn!</title><link>https://www.benbasten.com/posts/creating-hugo-blog/</link><guid isPermaLink="true">https://www.benbasten.com/posts/creating-hugo-blog/</guid><description>Diving into building a static blog site with Hugo. Time to give myself the gift of having a public place to share my writing!</description><pubDate>Mon, 17 Jan 2022 02:25:15 GMT</pubDate><content:encoded>&gt; **October 2026 update:** this blog has been rebuilt, and is no longer using the Hugo static site generator.

The other day, I watched a YouTube presentation called [&quot;Give Yourself a Blog for Christmas&quot;](https://www.youtube.com/watch?v=NKHF5VZmCig&amp;t=831s)
that one of my favorite podcasters, Jack Rhysider, shared. Jack argued that anyone can benefit from a podcast, whether
it&apos;s for posting documentation to look back on later or to share out ideas for others to benefit from on the vast internet.

This really inspired me - why not start a blog? I think it&apos;ll be a fun exercise to deliberately document my findings,
share out anything I&apos;ve learned, or just write about anything that&apos;s been on my mind.

So... what next?

## Choosing my blogging tool

Knowing that I&apos;m particular and I will want granular control over the look and feel of the blog, I knew I would have to find a some sort of site generator with an extent of customizability. Plus, this could make for a cool project to learn about a new tool.

After some searching around, some names I found coming up frequently were:

- Jekyll
- Wordpress
- Gatsby
- 11ty
- Hugo

They all had their pros and cons, but I saw a couple of intriguing examples leveraging Hugo that made me feel confident that it was flexible enough to meet my needs. Hugo it is.

## Setting up Hugo

I followed the [Binary (Cross-platform)](https://gohugo.io/getting-started/installing/#binary-cross-platform) instructions in the Hugo documentation to install it on my Windows computer. This required me to:

1. Install [Go](https://go.dev/dl/), because Hugo is powered by Go
2. Download the [Hugo binary](https://github.com/gohugoio/hugo/releases)
3. Add the `hugo.exe` file to my Windows PATH so that the command line will recognize the `hugo` command
4. To test that everything is working, run the command `hugo version` in Command Prompt to see a version number

With everything installed, creating a project was fairly easy. In your desired directory to store the project (I&apos;d recommend a Git repository for version control) run the command `hugo new site sitename`. That&apos;s it - Hugo will generate the files and directory structure that you need.

But... there&apos;s nothing to see yet. You&apos;ll need to add a theme to make it look pretty! You can check out the [themes list](https://themes.gohugo.io/) in the Hugo documentation for some potential options. I&apos;d recommend digging into the theme documentation to make sure there&apos;s clear instructions - it&apos;s no good if you don&apos;t know how to use it!

## My learnings

After generating my initial site, I quickly realized that this tool wouldn&apos;t be something that I could just look at and figure out right away. This [Hugo tutorial YouTube playlist](https://www.youtube.com/playlist?list=PLLAZ4kZ9dFpOnyRlyS-liKL5ReHDcj4G3) is what got me off the ground running. I&apos;d recommend giving them a watch!

This is by no means all-inclusive documentation, but here&apos;s a couple of helpful things that I wished I knew when I was getting started.

### There are 3 main types of pages

1. [Homepage](https://gohugo.io/templates/homepage/) - the root of your site. Since the entry to any website may have special requirements, Hugo offers an option to make this its own template.
2. [List](https://gohugo.io/templates/lists/) - display summarized contents of a directory in a list. For example, a list of blog posts.
3. [Single](https://gohugo.io/templates/single-page-templates/) - the detailed content view of a file in a directory. For example, the blog post itself.

There are more fine-grained templates than this like [taxonomy templates](https://gohugo.io/templates/taxonomy-templates/), but those big 3 are probably what you&apos;ll need the most to get started.

### Front matter is the metadata of your content

Every content file that you create can have [front matter](https://gohugo.io/content-management/front-matter/), which is essentially metadata for that content. For example, this could be the date of a blog post or its title. You can customize the default front matter when a new content file is generated by adding new custom [archetypes](https://gohugo.io/content-management/archetypes/) in the `archetypes/` folder.

### Taxonomies offer a quick and built in way to organize content

[Taxonomies](https://gohugo.io/content-management/taxonomies/) are dictated in the front matter of a content file. Hugo comes set up with 2 out of the box, &quot;tags&quot; and &quot;categories&quot;, but you can customize these as you like in the `config.toml` file. For example, you can filter a list of post content by all posts that have a shared tag of &quot;lifestyle&quot;.

### Pagination is super easy!

By default, Hugo is configured to paginate if a list is longer than 10 elements. [Check out the sample code](https://gohugo.io/templates/pagination/) in the documentation, it&apos;s really that easy. The logic for creating pages and the navigation is already done for you - enough said!

### `layouts/` is where the magic happens

This directory is where you determine what the different types of pages will look like. Hugo knows which template to render depending on the URL path, so you just need to dictate its layout and styling. Hugo offers various Site, Page, and Taxonomy variables that give you the power to dynamically generate the page. As a perk, the extended binary of Hugo supports Sass compiling without any additional configuration to make the page look the way you like! Learn more about variables [here](https://gohugo.io/variables/).

## Final thoughts

If you&apos;re looking for a static site generator that you can quickly choose a theme and get started, I probably wouldn&apos;t recommend Hugo. It offers a lot of tools to craft an elegant page, but there&apos;s definitely a learning curve. That being said, I&apos;m excited to be getting started with this blog! I&apos;m feeling encouraged now that drafting a new page is as simple as writing up a Markdown content file. Cheers to this new adventure!

_Side note: I would highly recommend checking out Jack Rhysider&apos;s podcast [&quot;Darknet Diaries&quot;](https://darknetdiaries.com/)!
He shares stories from the &quot;dark side of the internet&quot; about various hackers, exploits, social engineers, and more with
excellent music/production quality._</content:encoded></item></channel></rss>