Privacy Tools Guide

Building a smart home ecosystem that respects user privacy while remaining accessible represents a significant technical challenge. Home Assistant provides an excellent foundation for privacy-conscious home automation, but implementing it in a way that works well for users with mobility limitations requires careful planning and specific configuration choices.

This guide covers a privacy-focused Home Assistant setup designed with accessibility as a primary consideration. The recommendations target developers and power users who want full control over their data while ensuring the system remains usable for everyone in the household.

Table of Contents

Why Privacy and Accessibility Matter Together

Traditional smart home solutions often route data through cloud services, creating privacy concerns and introducing dependencies that can break accessibility features when internet connectivity fails. For users with mobility limitations, this represents a double problem: their sensitive habits get transmitted to third parties, and they lose control over their environment when services go down.

A self-hosted Home Assistant instance solves both issues. You retain ownership of your data, and the system remains functional regardless of external service availability. The key lies in configuring it correctly from the start.

Prerequisites

Before you begin, make sure you have the following ready:

Step 1: Core Installation with Privacy in Mind

Begin with a local-only installation. The Home Assistant Operating System running on dedicated hardware provides the best foundation. Avoid cloud-connected setups that default to external data processing.

# For a Raspberry Pi 4 or equivalent, download the appropriate image
# from home-assistant.io and write to SD card using balenaEtcher

# After initial setup, verify no cloud connections are active
# by checking Configuration > General > External Trading

During initial configuration, select “Local” as your preferred connection method for all integrations. Home Assistant will prompt you to choose between local and cloud options—always choose local when available.

Step 2: Essential Privacy Configuration

The configuration file serves as your privacy command center. Add these settings to your configuration.yaml to minimize data leakage:

# Disable analytics and usage data collection
analytics: false

# Prevent cloud speech processing
# Use local voice assistants instead
assist:
  pipelines:
    - name: "Local Only"
      language_model: "faster-whisper"

# Restrict network discovery visibility
network:
  enforce_srtd: true

# Disable default cloud integration
cloud:
  alexa:
    enabled: false
  google_assistant:
    enabled: false

These settings ensure your instance operates entirely within your local network. The analytics disablement stops data transmission to Home Assistant’s servers, while the cloud disabling prevents voice commands from being processed externally.

Step 3: Accessibility Layer: Making Home Assistant Usable

For users with mobility limitations, standard touchscreen interfaces often present barriers. Implementing alternative control methods transforms Home Assistant into an accessible platform.

Voice Control Without Cloud Dependencies

The Wyoming protocol enables local voice processing using tools like Whisper for speech-to-text and Piper for text-to-speech. Install these components:

# Install Wyoming protocol and voice satellites
# on your Home Assistant server
cd /opt
git clone https://github.com/rhasspy/wyoming.git
cd wyoming
./install.sh

# Start the Wyoming server
python3 -m wyoming.faster_whisper \
  --model tiny \
  --language en

Configure Home Assistant to use this local voice processing pipeline:

# In configuration.yaml
wyoming:
  - host: localhost
    port: 10300

Voice commands then process entirely on your local network, maintaining privacy while providing hands-free control essential for users with limited mobility.

Input Methods Beyond Touch

Configure multiple input pathways to accommodate various mobility needs:

# Add MQTT-based switches for external button controls
input_boolean:
  living_room_toggle:
    name: "Living Room Toggle"
    icon: mdi:lightbulb

automation:
  - alias: "Physical Button Control"
    trigger:
      - platform: mqtt
        topic: "home/button/1"
        payload: "pressed"
    action:
      - service: light.toggle
        target:
          entity_id: light.living_room

Physical buttons connected through ESPHome devices or USB input controllers provide alternative interaction methods. Users who cannot use touchscreens can press physical buttons or use adapted game controllers configured as input devices.

NFC Tag-Based Automation

NFC tags placed throughout the home enable one-tap control:

# NFC tag automation example
automation:
  - alias: "Door Tag Activation"
    trigger:
      - platform: tag
        tag_id: "your-tag-id-here"
    action:
      - service: scene.activate
        target:
          entity_id: scene.evening_mode

Users can trigger complex automations by tapping a phone or NFC card against a strategically placed tag, eliminating the need to navigate on-screen menus.

Step 4: Network Isolation for Enhanced Privacy

Create a dedicated network segment for your smart home devices. VLAN separation ensures that even if a device gets compromised, it cannot access your personal computers or data:

# Router-level configuration (example for pfSense)
# Create VLAN 20 for IoT devices
# Assign static routes to keep IoT traffic separate
# Block IoT-to-LAN traffic by default

This isolation approach protects privacy by containing potential data leaks while also preventing compromised devices from accessing sensitive information on your main network.

Step 5: Automations That Respect Privacy While Enabling Independence

Design automations that provide independence without sacrificing privacy. The following example creates a morning routine that operates entirely locally:

automation:
  - alias: "Morning Routine - Privacy Focused"
    trigger:
      - platform: time
        at: "07:00:00"
    condition:
      - condition: state
        entity_id: input_boolean.morning_mode
        state: "on"
    action:
      - service: light.turn_on
        target:
          entity_id:
            - light.bedroom
            - light.kitchen
        data:
          brightness_pct: 70
          kelvin: 4000
      - service: climate.set_temperature
        target:
          entity_id: climate.thermostat
        data:
          temperature: 21
      - service: cover.open_cover
        target:
          entity_id: cover.bedroom_blinds
    mode: single

This automation activates at a scheduled time without requiring voice commands or physical interaction, providing automatic environmental control that preserves user autonomy.

Step 6: Monitor and Maintaining Privacy

Regularly audit your system to ensure privacy settings remain intact:

# Check for cloud connections
grep -r "cloud" /homeassistant/.storage/ || echo "No cloud configs found"

# Review active integrations
curl -H "Authorization: Bearer YOUR_TOKEN" \
  http://localhost:8123/api/integrations | jq '.'

Create a simple script that runs weekly to confirm no unexpected cloud connections have been enabled through updates or new integrations.

Advanced: Custom Integration Development

Building custom integrations keeps all data internal while enabling specific accessibility features. A simple example creates an adaptive interface for users with limited dexterity:

# custom_accessibility_integration.py
import asyncio
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import Entity

class AccessibilityAdapter:
    """Adapt Home Assistant for accessibility needs"""

    def __init__(self, hass: HomeAssistant):
        self.hass = hass
        self.long_hold_time = 2.0  # seconds
        self.enable_voice = True
        self.button_size = 'large'

    async def handle_long_press(self, device_id: str, action: str):
        """Support long-press activation for users with tremors"""
        start_time = None

        async def on_button_press():
            nonlocal start_time
            start_time = time.time()

        async def on_button_release():
            if start_time:
                hold_duration = time.time() - start_time
                if hold_duration >= self.long_hold_time:
                    await self.execute_action(device_id, action)

        return {'press': on_button_press, 'release': on_button_release}

    async def execute_action(self, device_id: str, action: str):
        """Execute accessibility action"""
        if action == 'light_toggle':
            await self.hass.services.async_call(
                'light', 'toggle',
                {'entity_id': f'light.{device_id}'}
            )

async def async_setup(hass: HomeAssistant, config):
    """Setup accessibility integration"""
    adapter = AccessibilityAdapter(hass)

    # Register services for custom actions
    async def handle_accessibility_service(service):
        await adapter.execute_action(
            service.data['device'],
            service.data['action']
        )

    hass.services.async_register(
        'accessibility',
        'perform_action',
        handle_accessibility_service
    )

    return True

Hardware Requirements for Privacy

Choose hardware that prioritizes local processing:

Hardware Privacy Score Accessibility Notes
Raspberry Pi 4 10/10 Good ARM processor, limited cloud integration
Orange Pi 5 10/10 Good Faster ARM, community-driven
Intel NUC 9/10 Excellent Full x86, but more power consumption
Used laptop 8/10 Excellent Reliable hardware, good performance
Cloud-based HA 0/10 Poor All data exposed

For users with accessibility needs, the Intel NUC or used laptop offers the best balance of processing power and local control.

Step 7: Data Isolation: Network Segregation Details

Implement strict network isolation to prevent smart devices from accessing sensitive data:

#!/bin/bash
# setup-vlan-isolation.sh

# Configure UFW firewall to isolate IoT traffic
sudo ufw default deny incoming
sudo ufw default deny outgoing
sudo ufw allow out 53  # DNS only to trusted server
sudo ufw allow out 123 # NTP for time sync
sudo ufw allow in from 10.0.0.0/8  # Home Assistant network

# On OpenWrt router: Create VLAN 20 for IoT devices
# and block all VLAN 20 → VLAN 1 (main network) traffic

# Test isolation with a device on VLAN 20
nmap -sU -p 22 10.0.1.1  # Should be blocked

This ensures compromised smart home devices cannot reach your Home Assistant server or personal computers.

Step 8: Backup and Disaster Recovery

Maintain local backups of all Home Assistant configuration:

#!/bin/bash
# home-assistant-backup.sh

BACKUP_DIR="$HOME/.local/share/ha-backups"
HA_CONFIG="/home/homeassistant/.homeassistant"

mkdir -p "$BACKUP_DIR"

# Create tarball backup
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/ha_config_$TIMESTAMP.tar.gz"

sudo tar --exclude='.*' --exclude='*.db' \
  -czf "$BACKUP_FILE" "$HA_CONFIG"

# Verify backup integrity
tar -tzf "$BACKUP_FILE" > /dev/null && \
  echo "Backup verified: $BACKUP_FILE" || \
  echo "Backup FAILED"

# Encrypt backup for cloud storage (optional)
gpg --cipher-algo AES256 --symmetric "$BACKUP_FILE"

# Keep only last 30 days of backups
find "$BACKUP_DIR" -name "ha_config_*.tar.gz" -mtime +30 -delete

Schedule daily via cron to maintain consistent recovery capability.

Step 9: Test Accessibility Features

Verify accessibility features work independently of internet:

automation:
  - alias: "Test Accessibility - Voice Only"
    trigger:
      - platform: tag
        tag_id: "test-voice-trigger"
    action:
      - service: tts.google_say
        target:
          entity_id: media_player.bedroom_speaker
        data:
          message: "Accessibility test complete"

  - alias: "Test Accessibility - Large Buttons"
    trigger:
      - platform: mqtt
        topic: "home/test/large_button"
    action:
      - service: light.turn_on
        target:
          entity_id: light.living_room
        data:
          brightness_pct: 100

  - alias: "Accessibility - Auto-Verify No Network"
    trigger:
      - platform: time
        at: "02:00:00"
    action:
      - service: shell_command.verify_isolation

Add shell commands to verify:

shell_command:
  verify_isolation: 'ping -c 1 8.8.8.8 && echo "ERROR: Internet accessible" || echo "OK: Isolated"'

Step 10: User Scenarios: Real-World Configuration

Example setup for a user with limited upper body mobility:

input_boolean:
  mobility_assist_enabled:
    name: "Mobility Assistance Enabled"
    icon: mdi:wheelchair-accessibility

automation:
  # Large, highly accessible control panel
  - alias: "Mobility Assist - Master Control"
    trigger:
      - platform: state
        entity_id: input_boolean.mobility_assist_enabled
        to: "on"
    action:
      - service: lovelace.dashboard_update
        data:
          mode: "yaml"
          strategy:
            type: "custom:button-card"
            config:
              size: 200px  # Extra large buttons
              text_transform: "uppercase"
              font_size: 80px

  # Voice-activated emergency shutdown
  - alias: "Emergency Stop via Voice"
    trigger:
      - platform: state
        entity_id: input_select.voice_command
        to: "emergency_stop"
    action:
      - service: scene.turn_on
        target:
          entity_id: scene.all_lights_off
      - service: climate.turn_off
        target:
          entity_id: climate.thermostat
      - service: tts.google_say
        data:
          message: "Emergency shutdown activated"

  # Adaptive timeout for accessibility
  - alias: "Extend Timeout for Users"
    trigger:
      - platform: homeassistant
        event: start
    action:
      - service: input_number.set_value
        target:
          entity_id: input_number.voice_recognition_timeout
        data:
          value: 10  # 10 seconds to respond

This configuration provides rapid emergency response alongside accessible normal operation.

Built by theluckystrike — More at zovo.one