commit eeeeca8da138ac7bf9314c6f136e384e980ec64a Author: Kyattsukuro Date: Mon Oct 12 23:44:19 2026 +0200 Init diff --git a/README.md b/README.md new file mode 100644 index 0000000..b92e34f --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# homeassistant + +Note: Homeassistant sometimes expectes .yaml NOT .yml diff --git a/defaults/main.yml b/defaults/main.yml new file mode 100644 index 0000000..818bc3e --- /dev/null +++ b/defaults/main.yml @@ -0,0 +1,22 @@ +path: /srv/{{ role_name }} + +homeassistant_override: {} +homeassistant_defaults: + url: "" + version: latest + proxy_ip: "" + mqtt: + zigbee2mqtt: + version: latest + domain: "" + auth_token: "" + zigbee_adapter_id: "" + mosquitto: + version: latest + allow_anonymous: true + oidc: + client_id: "" + client_secret: "" + configure_url: "" + mariadb: + password: "" diff --git a/handlers/main.yml b/handlers/main.yml new file mode 100644 index 0000000..e7f32dc --- /dev/null +++ b/handlers/main.yml @@ -0,0 +1,8 @@ +- name: restart container + community.docker.docker_compose_v2: + project_src: "{{ path }}" + project_name: "{{ role_name }}" + recreate: "always" + services: ["homeassistant"] + state: "restarted" + when: not _homeassistant_already_restarted diff --git a/meta/main.yml b/meta/main.yml new file mode 100644 index 0000000..8db596d --- /dev/null +++ b/meta/main.yml @@ -0,0 +1,20 @@ +--- +galaxy_info: + author: "Niklas Freese " + description: homeassistant + company: "Urmel Services" + license: AGPL-3.0-or-later + min_ansible_version: 2.1 + # If this a Container Enabled role, provide the minimum Ansible Container version. + # min_ansible_container_version: + + galaxy_tags: [] + # List tags for your role here, one per line. A tag is a keyword that describes + # and categorizes the role. Users find roles by searching for tags. Be sure to + # remove the '[]' above, if you add tags to this list. + # + # NOTE: A tag is limited to a single word comprised of alphanumeric characters. + # Maximum 20 tags per role. + +dependencies: + - role: traefik diff --git a/tasks/ensure_configuration.yml b/tasks/ensure_configuration.yml new file mode 100644 index 0000000..fb3fd7d --- /dev/null +++ b/tasks/ensure_configuration.yml @@ -0,0 +1,30 @@ +- name: Find Home Assistant configuration templates locally + ansible.builtin.set_fact: + ha_templates: "{{ query('ansible.builtin.fileglob', role_path + '/templates/homeassistant_configuration/*.yaml.j2') }}" + +- name: Template Home Assistant configuration files + ansible.builtin.template: + src: "{{ item }}" + dest: "/srv/homeassistant/config/homeassistant/{{ item | basename | regex_replace('\\.j2$', '') }}" + mode: "0644" + loop: "{{ ha_templates }}" + loop_control: + label: "{{ item | basename }}" + +- name: Ensure Home Assistant configuration.yaml exists + ansible.builtin.file: + path: "/srv/homeassistant/config/homeassistant/configuration.yaml" + state: touch + mode: "0644" + modification_time: preserve + access_time: preserve + +- name: Add Home Assistant configuration includes + ansible.builtin.blockinfile: + path: "/srv/homeassistant/config/homeassistant/configuration.yaml" + marker: "# {mark} ANSIBLE MANAGED CONFIGURATION INCLUDES" + insertafter: EOF + block: | + {% for item in ha_templates | sort %} + {{ item | basename | regex_replace('\.yaml\.j2$', '') }}: !include {{ item | basename | regex_replace('\.j2$', '') }} + {% endfor %} diff --git a/tasks/main.yml b/tasks/main.yml new file mode 100644 index 0000000..647bfa5 --- /dev/null +++ b/tasks/main.yml @@ -0,0 +1,68 @@ +--- +- name: "set local variables from overrides and defaults" + set_fact: + homeassistant: "{{ (homeassistant_defaults | combine(homeassistant_override, recursive=True)) if homeassistant_override else homeassistant_defaults }}" + +- name: ensure that path exists + file: + path: "{{ path }}/config/homeassistant" + state: directory + +- name: ensure that mosquitto config path exists + file: + path: "{{ path }}/config/mosquitto" + state: directory + +- name: ensure that mosquitto data path exists + file: + path: "{{ item }}" + state: directory + owner: "1883" + group: "1883" + loop: + - "{{ path }}/data/mosquitto" + - "{{ path }}/data/mosquitto/log" + +- name: ensure that zigbee2mqtt data path exists + file: + path: "{{ path }}/data/zigbee2mqtt" + state: directory + +- name: template docker-compose + template: + src: compose.yml.j2 + dest: "{{ path }}/compose.yml" + +- name: template .env + template: + src: .env.j2 + dest: "{{ path }}/.env" + +- name: template mosquitto config + template: + src: mosquitto.conf.j2 + dest: "{{ path }}/config/mosquitto/mosquitto.conf" + mode: "0644" + +- name: template zigbee2mqtt config + ansible.builtin.blockinfile: + path: "{{ path }}/data/zigbee2mqtt/configuration.yaml" + create: true + mode: "0644" + marker: "# Ansible {mark}" + marker_begin: start + marker_end: end + block: "{{ lookup('template', 'zigbee2mqtt/configuration.yaml.j2') }}" + +- name: Do configuration + include_tasks: ensure_configuration.yml + +- name: ensure container is running + community.docker.docker_compose_v2: + project_src: "{{ path }}" + project_name: "{{ role_name }}" + state: "present" + pull: "always" + wait: true + services: ["mariadb", "mosquitto", "homeassistant", "zigbee2mqtt"] + register: _compose_result diff --git a/templates/.env.j2 b/templates/.env.j2 new file mode 100644 index 0000000..5a175b6 --- /dev/null +++ b/templates/.env.j2 @@ -0,0 +1 @@ +SUBNET=172.31.254 diff --git a/templates/compose.yml.j2 b/templates/compose.yml.j2 new file mode 100644 index 0000000..50b5a2a --- /dev/null +++ b/templates/compose.yml.j2 @@ -0,0 +1,152 @@ +version: '3' + +services: + homeassistant: + image: homeassistant/home-assistant:{{ homeassistant.version }} + volumes: + # We do not yes manage configs with ansible + - ./config/homeassistant:/config + - /etc/localtime:/etc/localtime:ro + restart: unless-stopped + environment: + TZ: Europe/Berlin + network_mode: "host" +# networks: +# local_network: +# ipv4_address: ${SUBNET}.2 + depends_on: + - zigbee2mqtt + - mariadb + - mosquitto + extra_hosts: + - "zwave:${SUBNET}.3" + - "zigbee2mqtt:${SUBNET}.6" + - "mariadb:${SUBNET}.4" + - "mosquitto:${SUBNET}.5" +# ports: +# - 8123:8123 +# - 1400:1400 +# - 1401:1401 + +{% if homeassistant.mqtt.zigbee2mqtt.zigbee_adapter_id %} + zigbee2mqtt: + # 8080 + image: ghcr.io/koenkk/zigbee2mqtt:{{ homeassistant.mqtt.zigbee2mqtt.version }} + restart: unless-stopped + volumes: + - ./data/zigbee2mqtt:/app/data + - /run/udev:/run/udev:ro + environment: + - TZ=Europe/Berlin + networks: + local_network: + ipv4_address: ${SUBNET}.6 + exposed: + devices: + # Make sure this matched your adapter location + - /dev/serial/by-id/{{ homeassistant.mqtt.zigbee2mqtt.zigbee_adapter_id }}:/dev/ttyUSB0 + labels: + traefik.enable: true + + traefik.http.routers.homeassistant-mqtt.entrypoints: https + traefik.http.routers.homeassistant-mqtt.rule: Host(`{{ homeassistant.mqtt.zigbee2mqtt.domain }}`) + traefik.http.services.homeassistant-mqtt.loadbalancer.server.port: 8080 + traefik.http.routers.homeassistant-mqtt.tls: "true" + traefik.http.routers.homeassistant-mqtt.tls.certresolver: hetzner + traefik.http.routers.homeassistant-mqtt.middlewares: local-only@file +{% endif %} + +{% if homeassistant.matter.matter_adapter_id %} + matter: + image: ghcr.io/matter-js/matterjs-server:stable + volumes: + - ./data/matter:/data + networks: + local_network: + ipv4_address: ${SUBNET}.7 + exposed: + labels: + traefik.enable: true + + traefik.http.routers.homeassistant-matter.entrypoints: https + traefik.http.routers.homeassistant-matter.rule: Host(`{{ homeassistant.matter.domain }}`) + traefik.http.services.homeassistant-matter.loadbalancer.server.port: 5580 + traefik.http.routers.homeassistant-matter.tls: "true" + traefik.http.routers.homeassistant-matter.tls.certresolver: hetzner + traefik.http.routers.homeassistant-matter.middlewares: local-only@file + openthread: + image: openthread/border-router:latest + networks: + local_network: + ipv4_address: ${SUBNET}.8 + exposed: + environment: + - TZ=Europe/Berlin + - OT_RCP_DEVICE=/dev/ttyUSB0 + - OT_LOG_LEVEL=7 + - OT_THREAD_IF=wpan0 + - OT_INFRA_IF=br0 + - OT_REST_LISTEN_ADDR=0.0.0.0 + - OT_REST_LISTEN_PORT=9212 + volumes: + - ./data/openthread:/data + devices: + # Make sure this matched your adapter location + - /dev/serial/by-id/{{ homeassistant.matter.matter_adapter_id }}:/dev/ttyUSB0 + - /dev/net/tun:/dev/net/tun + cap_add: + - NET_ADMIN + labels: + traefik.enable: true + + traefik.http.routers.homeassistant-openthread.entrypoints: https + traefik.http.routers.homeassistant-openthread.rule: Host(`{{ homeassistant.matter.openthread_domain }}`) + traefik.http.services.homeassistant-openthread.loadbalancer.server.port: 9212 + traefik.http.routers.homeassistant-openthread.tls: "true" + traefik.http.routers.homeassistant-openthread.tls.certresolver: hetzner + traefik.http.routers.homeassistant-openthread.middlewares: local-only@file + restart: always +{% endif %} + + mosquitto: + image: eclipse-mosquitto:{{ homeassistant.mqtt.mosquitto.version }} + restart: unless-stopped + user: "1883:1883" + volumes: + - ./config/mosquitto:/mosquitto/config:ro + - ./data/mosquitto:/mosquitto/data + - ./data/mosquitto/log:/mosquitto/log + environment: + - TZ=Europe/Berlin + networks: + local_network: + ipv4_address: ${SUBNET}.5 + + mariadb: + image: mariadb:10.11.2 + volumes: + - ./data/mariadb:/var/lib/mysql + - ./config/mariadb:/etc/mysql/conf.d + - /etc/localtime:/etc/localtime:ro + + restart: unless-stopped + environment: + MARIADB_ROOT_PASSWORD: {{ homeassistant.mariadb.password }} + MARIADB_MYSQL_LOCALHOST_USER: "yes" + MARIADB_MYSQL_LOCALHOST_GRANTS: "yes" + MARIADB_AUTO_UPGRADE: "yes" + MARIADB_DISABLE_UPGRADE_BACKUP: "yes" + TZ: Europe/Berlin + networks: + local_network: + ipv4_address: ${SUBNET}.4 + +networks: + local_network: + ipam: + driver: default + config: + - subnet: ${SUBNET}.0/24 + exposed: + name: traefik_exposed + external: true diff --git a/templates/homeassistant_configuration/auth_oidc.yaml.j2 b/templates/homeassistant_configuration/auth_oidc.yaml.j2 new file mode 100644 index 0000000..96f78de --- /dev/null +++ b/templates/homeassistant_configuration/auth_oidc.yaml.j2 @@ -0,0 +1,10 @@ +client_id: "{{ homeassistant.oidc.client_id }}" +{% if homeassistant.oidc.client_secret %} +client_secret: "{{ homeassistant.oidc.client_secret }}" +{% endif %} +discovery_url: "{{ homeassistant.oidc.configure_url }}" +claims: + display_name: "preferred_username" + groups: groups +roles: + admin: urmel-admin diff --git a/templates/homeassistant_configuration/http.yaml.j2 b/templates/homeassistant_configuration/http.yaml.j2 new file mode 100644 index 0000000..9a6d1f8 --- /dev/null +++ b/templates/homeassistant_configuration/http.yaml.j2 @@ -0,0 +1,5 @@ +use_x_forwarded_for: true +trusted_proxies: +- {{ homeassistant.proxy_ip }} + +# DOSE NOT WORK, MUST BE SET MANUALY AT FIRST BOOT diff --git a/templates/mosquitto.conf.j2 b/templates/mosquitto.conf.j2 new file mode 100644 index 0000000..71ce37d --- /dev/null +++ b/templates/mosquitto.conf.j2 @@ -0,0 +1,9 @@ +# Ansible managed +persistence true +persistence_location /mosquitto/data/ +log_dest file /mosquitto/log/mosquitto.log + +listener 1883 +protocol mqtt + +allow_anonymous {{ 'true' if homeassistant.mqtt.mosquitto.allow_anonymous else 'false' }} diff --git a/templates/zigbee2mqtt/configuration.yaml.j2 b/templates/zigbee2mqtt/configuration.yaml.j2 new file mode 100644 index 0000000..8ab377a --- /dev/null +++ b/templates/zigbee2mqtt/configuration.yaml.j2 @@ -0,0 +1,13 @@ +homeassistant: + enabled: true +mqtt: + base_topic: zigbee2mqtt + server: 'mqtt://mosquitto:1883' +serial: + port: /dev/ttyUSB0 +advanced: + log_level: info +frontend: + enabled: true + auth_token: {{ homeassistant.mqtt.zigbee2mqtt.auth_token }} +version: 5