/aws-greengrass-labs-component-for-home-assistant

Home Assistant packaged as an AWS IoT Greengrass component

Primary LanguagePythonApache License 2.0Apache-2.0

AWS IoT Greengrass V2 Community Component - Home Assistant

Home Assistant is an open-source home automation solution.

This repository facilitates packaging Home Assistant into an AWS IoT Greengrass V2 component named aws.greengrass.labs.HomeAssistant. This enables use cases where the customer reqires Home Assistant for local control, but also requires integration with AWS services at the edge and in the cloud.

Using the Home Assistant MQTT Integration, Home Assistant can publish and subscribe to topics on either or both of AWS IoT Core and the Greengrass local Moquette MQTT broker. This allows integration with the cloud, other Greengrass components on the same device and/or with other devices on the local network. Home Assistant can therefore leverage AWS-managed Greengrass components, custom Greengrass components, community Greengrass components and AWS services to deliver powerful home automation solutions that extend Home Assistant's capabilities.

Table of Contents

Architecture

An overview of the system architecture is presented below.

ggv2-ha-architecture

The aws.greengrass.labs.HomeAssistant component is a thin wrapper around a conventional Home Assistant Container deployment.

Home Assistant Container is delivered as a Docker image on Docker Hub and on GitHub. This Greengrass component downloads the selected Docker image from Docker Hub or GitHub with the help of the Docker application manager managed component.

Home Assistant configuration files are designed to be split as the solution scales. By convention, secrets are typically separated from the rest of the configuration and stored in a file named secrets.yaml. This Greengrass component handles secrets.yaml by storing it as a secret in AWS Secrets Manager in the cloud. At the edge, this component retrieves the secrets.yaml file from Secrets Manager with the help of the Secret manager managed component. From the developer machine, the contents of the secrets directory are placed into the Secrets Manager secret by calling create_config_secret.py.

As shown in blue on the architecture diagram, Home Assistant can use its MQTT integration to connect directly to AWS IoT Core. Alternatively, and more powerfully, Home Assistant can instead connect to the local Greengrass Moquette MQTT broker. This is option is shown in red. If Home Assistant and other devices on the local network are registered as Local Client Devices with Greengrass, this architecture allows Home Assistant to communicate with those other devices via the broker and with other Greengrass components via Greengrass Interprocess Communication. Furthermore, the MQTT bridge connects AWS IoT Core as an additional publisher and subscriber, facilitating cloud integration as well.

Repository Contents

Item Description
/artifacts Greengrass V2 component artifacts that run on the Greengrass edge runtime.
/cicd CDK Typescript app for a CodePipeline CI/CD pipeline.
/images Images for README files.
/libs Python libraries shared by Python scripts.
/secrets Home Assistant secrets (secrets.yaml and optional certificates).
/tests Pytest unit tests.
create_config_secret.py Creates or updates the Home Assistant configuration secret in Secrets Manager.
deploy_component_version.py Deploys a component version to the Greengrass core device target.
gdk_build.py Custom build script for the Greengrass Development Kit (GDK) - Command Line Interface.
gdk-config.json Configuration for the Greengrass Development Kit (GDK) - Command Line Interface.
recipe.json Greengrass V2 component recipe template.
quickstart.sh Creates a secret, and creates and deploys a component version in a single operation.

Requirements and Prerequisites

Greengrass Core Device

Platform

This component requires that the Greengrass device be running a Linux operating system. It supports all architectures supported by Greengrass itself.

Edge Runtime

The Greengrass edge runtime needs to be deployed to a suitable machine, virtual machine or EC2 instance. Please see the Home Assistant installation guide for information on the resources required.

Docker Requirements

Your core device must meet the requirements to run Docker containers using Docker Compose and Docker Hub.

Python Requirements

This component requires both python3 and pip3 to be installed on the core device.

Greengrass Cloud Services

Core Device Role

Assuming the bucket name in gdk-config.json is left unchanged, this component downloads artifacts from an S3 bucket named greengrass-home-assistant-REGION-ACCOUNT. Therefore your Greengrass core device role must allow the s3:GetObject permission for this bucket. For more information: https://docs.aws.amazon.com/greengrass/v2/developerguide/device-service-role.html#device-service-role-access-s3-bucket

Additionally, this component downloads sensitive Home Assistant configuration from Secrets Manager. Therefore your Greengrass core device role must also allow the secretsmanager:GetSecretValue permission for the greengrass=home-assistant-ID secret.

Policy template to add to your device role (substituting correct values for ACCOUNT, REGION and ID):

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject"
      ],
      "Resource": "arn:aws:s3:::greengrass-home-assistant-REGION-ACCOUNT/*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetSecretValue"
      ],
      "Resource": "arn:aws:secretsmanager:REGION:ACCOUNT:secret:greengrass-home-assistant-ID"
    }
  ]
}

Developer Machine

AWS CLI

It may be necessary to upgrade your AWS CLI if you wish to use any greengrassv2 commands, as these are relatively recent additions to the CLI.

Python

Most of the scripts in this repository are Python scripts. They are Python 3 scripts and hence python3 and pip3 are required.

Package dependencies can be resolved as follows:

pip3 install -r requirements.txt

Please consider to use a virtual environment.

Boto3 is included in the package dependencies and therefore your machine requires appropriate credentials.

GDK CLI

This component makes use of the Greengrass Development Kit (GDK) - Command Line Interface (CLI). This can be installed as follows:

pip3 install git+https://github.com/aws-greengrass/aws-greengrass-gdk-cli.git

Bash

The quickstart.sh script is a Bash script. If using a Windows machine, you will need a Bash environment. Alternatively you can run the Python scripts individually.

jq

The jq utility is used by quickstart.sh. Release packages for Linux, OS X and Windows are available on the jq site.

Alternatively, Ubuntu includes a jq package:

sudo apt update
sudo apt install jq

Getting Started

Here we define two ways to get started: Quickstart or Slowstart.

All scripts are compatible with Linux, Mac or Windows operating systems, provided a Bash environment is available.

Quickstart

The quickstart.sh bash script is supplied to help you get going fast. It rolls the constituent steps up into a single command.

Before running the script, users must deploy Greengrass V2 to a physical machine, virtual machine or EC2 instance, meeting all of the prerequisites including the requirements to run Docker containers using Docker Compose and Docker Hub. Addtionally, users must set the AWS region in gdk-config.json.

It is not necessary to perform any Home Assistant configuration changes. Out of the box, Home Assistant will be deployed with the latest stable version and with default configuration.

The Quickstart script will:

  1. Install required Python packages on your developer machine.
  2. Upload the default (null) secret configuration (secrets.yaml) to a secret in Secrets Manager, creating the secret.
  3. Use GDK to build the component.
  4. Use GDK to publish a new component version to Greengrass cloud services and upload artifacts to an S3 bucket.
  5. Prompt you to add permissions for the configuration secret and artifacts bucket to the Greengrass core device role.
  6. Deploy the new component version to the Greengrass core.

The script accepts 1 argument: the Greengrass Core device name.

Example execution:

bash quickstart.sh MyCoreDeviceThingName

Slowstart

For any serious use of the component, Quickstart shall not be appropriate.

Manual Deployment

If not using Quickstart, you must perform the following steps:

  1. Deploy the Greengrass runtime to your machine, virtual machine or EC2 instance, meeting all of the prerequisites.
  2. Select your desired Home Assistant Container image and tag by modifying artifacts/docker-compose.yml.
  3. Configure Home Assistant by modifying the configuration YAML files in artifacts/config and secrets as desired.
  4. Subject to your configuration, generate self-signed TLS certificates if required and add them to the secrets directory.
  5. If MQTT integration with AWS IoT Core or the Greengrass MQTT broker is configured, take the appropriate steps in the AWS cloud.
  6. Subject to your configuration, add any required MQTT-related certificates to the secrets directory.
  7. Set the AWS region in gdk-config.json.
  8. Run create_config_secret.py to create the configuration secret in Secrets Manager.
  9. Run gdk component build to build the component.
  10. Run gdk component publish to create a component version in Greengrass cloud service, and upload artifacts to S3.
  11. Add permissions for the configuration secret and artifacts bucket to the Greengrass core device role.
  12. Run deploy_component_version.py to deploy the new component version to your Greengrass device.

For iterative configuration changes, repeat steps as appropriate.

Example Execution

Example of steps 8, 9, 10 and 12:

python3 create_config_secret.py
gdk component build
gdk component publish
python3 deploy_component_version.py 1.0.0 MyCoreDeviceThingName

This example:

  1. Creates a Secrets Manager secret in your account in the region specified in gdk-config.json.
  2. Builds the component and publishes it to your account in the region specified in gdk-config.json.
  3. Deploys the new component version to Greengrass core device MyCoreDeviceThingName.

CI/CD Pipeline

This repository offers a CodePipeline CI/CD pipeline as a CDK application. This can be optionally deployed to the same account as the Greengrass core.

This CI/CD pipeline automates steps 9, 10 and 12. With the pipeline deployed, users can make iterative configuration changes, update the configuration secret using create_config_secret.py, and then trigger the CI/CD pipeline to handle the rest.

Home Assistant Configuration Tips

Configuration of Home Assistant can be done predominantly through its user interface. However, it can also be configured using the YAML files in artifacts/config and secrets. Please consult the Home Assistant configuration documentation for details.

Defaults

The configuration files in this projects are merely skeleton files. Home Assistant can be deployed with these files, yielding a greenfields installation.

Production Deployments

Production deployments should reference a specific Docker image tag (not just latest) in artifacts/docker-compose.yml.

Machine Specific Images

Docker images from Home Assistant's GitHub releases can be used directly as the image in artifacts/docker-compose.yml.

MQTT

Here we present Home Assistant configuration options to integrate with AWS IoT Core and AWS IoT Greengrass.

AWS IoT Core

We can use the MQTT Integration to connect Home Assistant directly to AWS IoT Core. Firstly create a Thing representing Home Assistant, and obtain the device certificate, private key and CA certificate. These certificates and keys should NOT be committed to your source repository and thus we instead disseminate them to Greengrass using Secrets Manager. The certificates and key should be added to the secrets directory. An example structure:

secrets/secrets.yaml
secrets/mqtt/AmazonRootCA1.pem
secrets/mqtt/dc536a53c3fcbce54833f9d90ab3ef1bd54523b4f371f60a811c0970dc8d4d82-certificate.pem.crt
secrets/mqtt/dc536a53c3fcbce54833f9d90ab3ef1bd54523b4f371f60a811c0970dc8d4d82-private.pem.key

Obtain the AWS IoT Core endpoint:

aws iot describe-endpoint --endpoint-type iot:Data-ATS
{
    "endpointAddress": "ENDPOINTID-ats.iot.REGION.amazonaws.com"
}

And add that to a secret in secrets/secrets.yaml:

aws_iot_core_endpoint: ENDPOINTID-ats.iot.REGION.amazonaws.com

Update the secret in Secrets Manager:

python3 create_config_secret.py
Files to add to secret: ['secrets/secrets.yaml', 'secrets/mqtt/dc536a53c3fcbce54833f9d90ab3ef1bd54523b4f371f60a811c0970dc8d4d82-certificate.pem.crt', 'secrets/mqtt/dc536a53c3fcbce54833f9d90ab3ef1bd54523b4f371f60a811c0970dc8d4d82-private.pem.key', 'secrets/mqtt/AmazonRootCA1.pem']
Updating the Home Assistant secret greengrass-home-assistant
Successfully updated the Home Assistant secret

Update the artifacts/config/configuration.yaml to add the AWS IoT Core connection information for the MQTT integration within Home Assistant (where the Thing name is "home-assistant"):

# Example configuration.yaml entry for connecting to IoT Core
mqtt:
  broker: !secret aws_iot_core_endpoint
  port: 8883
  certificate: /config/mqtt/AmazonRootCA1.pem
  client_key: /config/mqtt/dc536a53c3fcbce54833f9d90ab3ef1bd54523b4f371f60a811c0970dc8d4d82-private.pem.key
  client_cert: /config/mqtt/dc536a53c3fcbce54833f9d90ab3ef1bd54523b4f371f60a811c0970dc8d4d82-certificate.pem.crt
  client_id: home-assistant
  tls_insecure: false
  tls_version: '1.2'
  protocol: '3.1.1'

And then create and deploy a new component version.

Greengrass Moquette MQTT Broker

Greengrass V2 includes an AWS-managed Moquette MQTT broker component. This can be deployed to Greengrass to allow Greengrass components and devices on your local network to communicate with each other, without relying on an internet connection to AWS IoT Core.

Using the MQTT Integration, Home Assistant can be a "local IoT device" that connects to the Moquette broker. Additionally, Greengrass V2 includes an AWS-managed MQTT Bridge component. When this is also deployed, Home Assistant can use its MQTT Integration to communicate with local devices, Greengrass components and AWS IoT Core; the best of all worlds.

To begin, update the Greengrass deployment to add the necessary components to your Greengrass core device:

As with connecting to AWS IoT Core, the device certificate and key should be added to your secrets. However, instead of the Amazon Root CA certificate being added for authenticating AWS IoT Core, you instead need the CA generated by the component installations; this can be found at /greengrass/v2/work/aws.greengrass.clientdevices.Auth/ca.pem on your Greengrass device and copied to your secrets directory on your developer machine. These certificates and keys should NOT be committed to your source repository and thus we instead disseminate them to Greengrass using Secrets Manager.

secrets/secrets.yaml
secrets/mqtt/ca.pem
secrets/mqtt/dc536a53c3fcbce54833f9d90ab3ef1bd54523b4f371f60a811c0970dc8d4d82-certificate.pem.crt
secrets/mqtt/dc536a53c3fcbce54833f9d90ab3ef1bd54523b4f371f60a811c0970dc8d4d82-private.pem.key

Update the secrets in Secrets Manager:

python3 create_config_secret.py
Files to add to secret: ['secrets/secrets.yaml', 'secrets/mqtt/dc536a53c3fcbce54833f9d90ab3ef1bd54523b4f371f60a811c0970dc8d4d82-certificate.pem.crt', 'secrets/mqtt/dc536a53c3fcbce54833f9d90ab3ef1bd54523b4f371f60a811c0970dc8d4d82-private.pem.key', 'secrets/mqtt/ca.pem']
Updating the Home Assistant secret greengrass-home-assistant
Successfully updated the Home Assistant secret

Update the artifacts/config/configuration.yaml to add the Moquette broker connection information for the MQTT integration within Home Assistant (where the Thing name is "home-assistant"):

# Example configuration.yaml entry for connecting to the Greengrass MQTT broker (Moquette)
mqtt:
  # Moquette is on the same machine as Home Assistant
  broker: localhost
  port: 8883
  # CA certificate copied from /greengrass/v2/work/aws.greengrass.clientdevices.Auth/ca.pem
  certificate: /config/mqtt/ca.pem
  client_key: /config/mqtt/dc536a53c3fcbce54833f9d90ab3ef1bd54523b4f371f60a811c0970dc8d4d82-private.pem.key
  client_cert: /config/mqtt/dc536a53c3fcbce54833f9d90ab3ef1bd54523b4f371f60a811c0970dc8d4d82-certificate.pem.crt
  client_id: home-assistant
  tls_insecure: false
  tls_version: '1.2'
  protocol: '3.1.1'

And then create and deploy a new component version.

HTTPS

Home Assistant supports secure remote access if you have a domain name and/or a static IP address.

Alternatively, you can enable HTTPS on your local network using self-signed certificates. These can be generated using openssl as follows:

openssl req -sha256 -addext "subjectAltName = IP:xxx.xxx.xxx.xxx" -newkey rsa:4096 -nodes -keyout privkey.pem -x509 -days 730 -out fullchain.pem

These certificates should NOT be committed to your source repository and thus we instead disseminate them to Greengrass using Secrets Manager. The certificates should be added to the secrets directory. An example structure:

secrets/secrets.yaml
secrets/https/fullchain.pem
secrets/https/privkey.pem

Update the secrets in Secrets Manager:

python3 create_config_secret.py
Files to add to secret: ['secrets/secrets.yaml', 'secrets/https/fullchain.pem', 'secrets/https/privkey.pem']
Updating the Home Assistant secret greengrass-home-assistant
Successfully updated the Home Assistant secret

And then create and deploy a new component version.

Operations

Clean Uninstall

Removing this component from your deployment will not remove all vestiges from your Greengrass core device. Additional steps:

  • Remove any Home Assistant Docker images that have persisted.
  • Remove the working directory: /greengrass/v2/work/aws.greengrass.labs.HomeAssistant. This also deletes persistent data and settings.

Data Backup

If this component is deployed with default settings, persistent data and settings are located in /greengrass/v2/work/aws.greengrass.labs.HomeAssistant/config.

Troubleshooting

Tips for investigating failed deployments, or deployments that succeed but Home Assistant is still not working as expected.

Troubleshooting Tools

Core Device Log Files

Detailed component logs can be found on the Core Device in /greengrass/v2/logs/aws.greengrass.labs.HomeAssistant.log.

The Greengrass Core log file can be found at /greengrass/v2/logs/greengrass.log.

For more information please refer to the Greengrass V2 documentation: https://docs.aws.amazon.com/greengrass/v2/developerguide/monitor-logs.html

Greengrass CLI

Consider to install the Greengrass Command Line Interface component to obtain greater visibility into the state of your core device.

Docker Container Logs

The logs within the Docker container can be inspected as follows:

docker logs homeassistant

Common Failures

Wrong Docker Image Architecture

If a Docker image of the wrong architecture is deployed, it will fail to start. A message similar to the following indicates that the wrong architecture is being used:

standard_init_linux.go:228: exec user process caused: exec format error

This message will appear in /greengrass/v2/logs/aws.greengrass.labs.HomeAssistant.log.

To resolve incorrect architecture, please check the available architectures for the image tag. Image tags on DockerHub do not always support all architectures. Update docker-compose.yml and deploy a new version of the component.

Secret Configuration Changes Not Deployed

The Greengrass Secret Manager component needs to fetch the configuration secret from the cloud, for any changes to secrets.yaml or the certificates to be seen by the Home Assistant component. The Secret Manager will not necessarily fetch the secret even when a new version of the component is deployed. Restart or reboot the core device to force a fetch.

The deployed secrets.yaml can be found at /greengrass/v2/work/aws.greengrass.labs.HomeAssistant/secrets.yaml.

Development

Static Analysis

Static analysis is performed using Pylint. Example execution:

pylint artifacts libs tests *.py

Unit Tests

Unit tests are performed using pytest and moto.

Example execution:

pytest --cov=artifacts --cov=.

Producing an HTML coverage report into the htmlcov directory:

pytest --cov=artifacts --cov=. --cov-report=html

Producing a coverage report for just the on-device artifacts (100% coverage):

pytest --cov=artifacts