catching up #52

Merged
ben merged 10 commits from hass into main 2023-04-30 22:22:24 +00:00
48 changed files with 3120 additions and 220 deletions

View File

@ -0,0 +1,18 @@
---
airconnect_dir: "/var/lib/airconnect"
airconnect_user:
name: airconnect
uid: 1337
airconnect_group:
name: airconnect
gid: 1337
airconnect_upnp: []
airconnect_containers:
# UPnP/Sonos
- prog: airupnp
state: started
# Chromecast
- prog: aircast
state: started

View File

@ -0,0 +1,11 @@
---
- name: restart airconnect containers
docker_container:
name: airconnect-{{ item }}
state: "{{ item.state }}"
restart: item.state == 'started'
with_items: "{{ airconnect_containers }}"
when:
- airconnect_containers is not defined or not airconnect_containers.changed
- item.state == 'started'

View File

@ -0,0 +1,87 @@
---
- name: create airconnect dir
file:
path: "{{ airconnect_dir }}"
state: directory
mode: "0755"
owner: hass
group: hass
tags:
- airconnect-dirs
- name: airconnect config files
template:
src: "{{ item.name }}.j2"
dest: "{{ airconnect_dir }}/{{ item.name }}"
owner: "{{ item.owner | default(systemuserlist.hass.uid) }}"
group: "{{ item.group | default(systemuserlist.hass.gid) }}"
mode: "{{ item.mode }}"
notify: restart airconnect container
with_items:
- name: airupnp.xml
mode: "0644"
- name: run
mode: "0755"
- name: supervisord.conf
mode: "0644"
owner: "root"
group: "root"
# needed to nuke the script that would otherwise
# overwrite our sane supervisord.conf file
- name: 30-install
mode: "0755"
loop_control:
label: "{{ item.name }}"
tags:
- airconnect-config
- airconnect
- name: start airconnect container
docker_container:
name: airconnect
hostname: airconnect
image: 1activegeek/airconnect
#user: "{{ systemuserlist.hass.uid }}:{{ systemuserlist.hass.gid }}"
detach: true
pull: true
auto_remove: false
restart_policy: "unless-stopped"
state: "{{ airconnect_container_state | default('started') }}"
network_mode: host
env:
# docker image uses the linuxserver base image and supervisor,
# setting 'user:' doesnt work because of all of the custom shit
# that the base image does: https://github.com/linuxserver/docker-baseimage-ubuntu/blob/bionic/root/etc/cont-init.d/10-adduser
# but this image doesnt follow that properly, and supervisor starts
# the airconnect processes as root, so we need to mount a custom
# supervisord.conf file instead
PUID: "{{ systemuserlist.hass.uid }}"
PGID: "{{ systemuserlist.hass.gid }}"
# the image runs a script
# AIRUPNP_VAR: "-x /etc/airconnect/airupnp.xml"
# will create a reference config file for chromecast when found,
# but the defaults are fine, so no need to maintain a custom file
#AIRCAST_VAR: "-i /etc/airconnect/aircast.xml"
mounts:
# generate the reference config files by setting AIRUPNP_VAR and
# AIRCAST_VAR env to '-i $PATH'
- type: bind
source: "{{ airconnect_dir }}/airupnp.xml"
target: /etc/airupnp.xml
read_only: true
# need this to set uid/gid properly
- type: bind
source: "{{ airconnect_dir }}/supervisord.conf"
target: /etc/supervisord.conf
# needed to nuke the script that would otherwise overwrite our sane
# version of the supervisord.conf file when the container starts
- type: bind
source: "{{ airconnect_dir }}/30-install"
target: /etc/cont-init.d/30-install
tags:
- airconnect
- airconnect-container
- docker-containers
register: airconnect_container

View File

@ -0,0 +1,56 @@
---
- name: create airconnect dir
file:
path: "{{ airconnect_dir }}"
state: directory
mode: "0755"
owner: "{{ owntone_user.uid }}"
group: "{{ owntone_group.gid }}"
tags:
- airconnect-dirs
- name: airconnect config files
template:
src: "{{ item.name }}.j2"
dest: "{{ airconnect_dir }}/{{ item.name }}"
owner: "{{ owntone_user.uid }}"
group: "{{ owntone_group.gid }}"
mode: "{{ item.mode | default('0644') }}"
notify: restart airconnect containers
with_items:
- name: airupnp.xml
loop_control:
label: "{{ item.name }}"
tags:
- airconnect-config
- airconnect
- name: "set up the airconnect containers"
docker_container:
name: airconnect-{{ item.prog }}
hostname: airconnect-{{ item.prog }}
image: git.sudo.is/ben/airconnect
detach: true
pull: true
auto_remove: false
restart_policy: "unless-stopped"
state: "{{ item.state | default('started') }}"
network_mode: host
user: "{{ owntone_user.uid }}:{{ owntone_group.gid }}"
env:
AIRCONNECT_PROG: "{{ item.prog }}"
AIRCONNECT_ARGS: "{{ item.args|default() }}"
mounts:
- type: bind
source: "{{ airconnect_dir }}/airupnp.xml"
target: /etc/airupnp.xml
read_only: true
tags:
- airconnect
- airconnect-container
- docker-containers
register: airconnect_containers
loop_control:
label: airconnect-{{ item.prog }}
with_items: "{{ airconnect_containers }}"

View File

@ -0,0 +1,3 @@
---
- import_tasks: airconnect.yml
tags: airconnect

View File

@ -0,0 +1,37 @@
<?xml version="1.0"?>
<airupnp>
<common>
<protocolInfo>
<pcm>http-get:*:audio/L16;rate=44100;channels=2:DLNA.ORG_PN=LPCM;DLNA.ORG_OP=00;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=0d500000000000000000000000000000</pcm>
<wav>http-get:*:audio/wav:DLNA.ORG_OP=00;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=0d500000000000000000000000000000</wav>
<flac>http-get:*:audio/flac:DLNA.ORG_OP=00;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=0d500000000000000000000000000000</flac>
<mp3>http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=00;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=0d500000000000000000000000000000</mp3>
</protocolInfo>
<enabled>1</enabled>
<max_volume>100</max_volume>
<http_length>-1</http_length>
<upnp_max>1</upnp_max>
<codec>mp3:320</codec>
<metadata>1</metadata>
<flush>1</flush>
<artwork></artwork>
<latency>0:1000</latency>
<drift>0</drift>
</common>
<main_log>info</main_log>
<upnp_log>info</upnp_log>
<util_log>warn</util_log>
<raop_log>info</raop_log>
<log_limit>-1</log_limit>
<max_players>32</max_players>
<binding>?</binding>
<ports>0:0</ports>
{% for item in airconnect_upnp -%}
<device>
<udn>uuid:{{ item.local_uid }}</udn>
<name>{{ item.name }}</name>
<mac>{{ item.mac }}</mac>
<enabled>{% if item.enabled|default(true) %}1{% else %}0{% endif %}</enabled>
</device>
{% endfor %}
</airupnp>

View File

@ -0,0 +1,5 @@
#!/usr/bin/with-contenv bash
echo "this file has been nuked, so our sane supervisord.conf file is not overwritten"
exit 0

View File

@ -0,0 +1,3 @@
#!/usr/bin/with-contenv bash
supervisord --configuration /etc/supervisord.conf

View File

@ -0,0 +1,25 @@
[supervisord]
nodaemon=true
# the base image of the airconnect image uses the env vars $PUID and $PGID
# to create a user, and those are set in the ansible role
#
# supervisord doesnt have an argument for group, uses the default
# group of the user instead.
#
# but supervisor itself needs to run as root because of
# asinine stuff that the linuxserver base image wants to do
[program:airupnp]
user={{ systemuserlist.hass.uid }}
redirect_stderr=true
# the config file maintained in this ansible role, mounted in
# the docker_container task
command=/bin/airupnp-linux-x86_64 -x /etc/airupnp.xml
process_name = airupnp-linux-x86_64
[program:aircast]
user={{ systemuserlist.hass.uid }}
redirect_stderr=true
command=/bin/aircast-linux-x86_64
process_name = aircast-linux-x86_64

View File

@ -0,0 +1,6 @@
---
- name: reload nginx
service:
name: nginx
state: reloaded

View File

@ -0,0 +1,82 @@
---
- name: create dir structure
file:
path: "{{ audiobookshelf_path }}/{{ item.name }}"
mode: "{{ item.mode | default('0750') }}"
owner: "{{ audiobookshelf_user.uid }}"
group: "{{ audiobookshelf_group.gid }}"
tags:
- audiobookshelf-dirs
loop_control:
label: "{{ item.name }}"
with_items:
- name: ''
- name: audiobooks
- name: config
mode: "0755"
- name: metadata
- name: podcasts
- name: install certs
copy:
src: "/usr/local/etc/letsencrypt/live/{{ item }}"
dest: "/usr/local/etc/certs/"
owner: root
group: root
mode: 0755
tags:
- letsencrypt-certs
notify: reload nginx
vars:
prediff_cmd: echo
with_items:
- "{{ audiobookshelf_url }}"
- name: template nginx vhost
template:
src: 02-audiobookshelf.conf.j2
dest: /etc/nginx/sites-enabled/02-audiobookshelf.conf
owner: root
group: root
mode: 0644
tags:
- nginx
- audiobookshelf-nginx
notify: reload nginx
- name: start audiobookshelf container
docker_container:
name: audiobookshelf
auto_remove: false
image: ghcr.io/advplyr/audiobookshelf:latest
detach: true
pull: true
restart_policy: "no"
state: started
container_default_behavior: compatibility
networks_cli_compatible: false
network_mode: bridgewithdns
networks:
- name: bridgewithdns
ipv4_address: "{{ bridgewithdns.audiobookshelf }}"
ben marked this conversation as resolved
Review

.

.
env:
AUDIOBOOKSHELF_UID: "{{ audiobookshelf_user.uid }}"
AUDIOBOOKSHELF_GID: "{{ audiobookshelf_group.gid }}"
user: "{{ audiobookshelf_user.uid }}:{{ audiobookshelf_group.gid }}"
mounts:
- type: bind
source: "{{ audiobookshelf_path }}/audiobooks"
target: /audiobooks
- type: bind
source: "{{ audiobookshelf_path }}/podcasts"
target: /podcasts
- type: bind
source: "{{ audiobookshelf_path }}/config"
target: /config
- type: bind
source: "{{ audiobookshelf_path }}/metadata"
target: /metadata
tags:
- audiobookshelf-container
- docker-containers

View File

@ -0,0 +1,3 @@
---
- import_tasks: audiobookshelf.yml
tags: audiobookshelf

View File

@ -0,0 +1,50 @@
server {
listen 443 ssl http2;
include listen-proxy-protocol.conf;
{% if inventory_hostname in wg_clients -%}
listen {{ wg_clients[inventory_hostname].ip }}:443 ssl http2;
{% endif -%}
server_name {{ audiobookshelf_url }};
access_log /var/log/nginx/access_{{ audiobookshelf_url }}.log main;
error_log /var/log/nginx/error_{{ audiobookshelf_url }}.log warn;
ssl_certificate /usr/local/etc/certs/{{ audiobookshelf_url }}/fullchain.pem;
ssl_certificate_key /usr/local/etc/certs/{{ audiobookshelf_url }}/privkey.pem;
include /etc/nginx/authelia_internal.conf;
location /feed/ {
include /etc/nginx/require_auth.conf;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
proxy_pass http://{{ bridgewithdns.audiobookshelf }}:80;
proxy_redirect http:// https://;
proxy_hide_header "Content-Type";
add_header "Content-Type" "application/rss+xml";
}
location / {
include /etc/nginx/require_auth.conf;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
proxy_pass http://{{ bridgewithdns.audiobookshelf }}:80;
proxy_redirect http:// https://;
}
}

View File

@ -1 +1,2 @@
---
blink1_enabled: false

View File

@ -0,0 +1,52 @@
-----BEGIN PGP ARMORED FILE-----
Comment: Use "gpg --dearmor" for unpacking
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
=P2ir
-----END PGP ARMORED FILE-----

View File

@ -0,0 +1,52 @@
-----BEGIN PGP ARMORED FILE-----
Comment: Use "gpg --dearmor" for unpacking
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
=P2ir
-----END PGP ARMORED FILE-----

View File

@ -1,6 +0,0 @@
- sensor:
- name: "chance_of_rain"
unit_of_measurement: "%"
icon: "mdi:weather-pouring"
state: "{{ state_attr('weather.hourly', 'forecast')[:2] | map(attribute='precipitation_probability') | list | max | float }}"

View File

@ -15,4 +15,18 @@
name: hass
state: started
restart: true
when: hass_container is not defined or not hass_container.changed
when:
- hass_container is not defined or not hass_container.changed
- hass_container_state|default("stopped") == "started"
- name: restart zwavejs container
docker_container:
name: zwavejs
state: started
restart: true
when:
- zwavejs_container is not defined or not zwavejs_container.changed
- hass_container_state|default("stopped") == "started"
- name: udevadm reload rules
command: udevadm control --reload-rules

View File

@ -0,0 +1,7 @@
---
- name: nmcli conn reload
command: nmcli conn reload
- name: nmcli device wifi hotspot
command: nmcli device wifi hotspot

View File

@ -1,53 +1,5 @@
---
- name: allow ssh
ufw:
rule: allow
to_port: "22"
direction: in
state: enabled
tags:
- ufw
- name: allow loopback
ufw:
rule: allow
interface: lo
direction: in
state: enabled
tags:
- ufw
- name: default policy
ufw:
policy: allow
state: enabled
tags:
- ufw
- name: deny hass cloud port stuff
ufw:
# drops packets
rule: deny
to_port: '42161'
direction: in
state: enabled
tags:
- ufw
- name: reject zwavejs ws and hass ports (loopback only)
ufw:
# connection refused
rule: reject
to_port: "{{ item }}"
direction: in
state: enabled
with_items:
- "8091"
- "8123"
tags:
- ufw
- name: copy ssh keys for {{ hass_config_repo_name }}
template:
src: "private/sshkeys/{{ item }}"
@ -66,22 +18,30 @@
- name: create dir structure
file:
path: "{{ systemuserlist.hass.home }}/{{ item }}"
path: "{{ systemuserlist.hass.home }}/{{ item.name }}"
state: directory
mode: 0755
mode: "{{ item.mode | default('0755') }}"
owner: hass
group: hass
tags:
- hass-dirs
loop_control:
label: "{{ item.name }}"
with_items:
- home-assistant
- home-assistant/config
- home-assistant/.config
- home-assistant/media
- zwavejs
- zwavejs/app
- zwavejs/app/store
- git
- name: .local
mode: "0775"
- name: home-assistant
- name: home-assistant/config
- name: home-assistant/config/python_scripts
- name: home-assistant/config/bvg
- name: home-assistant/.config # might not be needed, misread 'cache' as 'config'
- name: home-assistant/.cache
- name: home-assistant/media
mode: "0775"
- name: zwavejs
- name: zwavejs/app
- name: zwavejs/app/store
- name: git
- name: template gitconfig
template:
@ -108,36 +68,38 @@
- hass-git
- hass-git-clone
- name: home assistant main configuration.yaml
- name: home assistant config files
template:
src: configuration.yaml.j2
dest: "{{ systemuserlist.hass.home }}/home-assistant/config/configuration.yaml"
src: "{{ item }}.j2"
dest: "{{ systemuserlist.hass.home }}/home-assistant/config/{{ item }}"
owner: "{{ systemuserlist.hass.uid }}"
group: "{{ systemuserlist.hass.gid }}"
mode: 0644
notify: restart hass container
with_items:
- secrets.yaml
- configuration.yaml
- templates.yaml
- climate.yaml
- automations-ansible-managed.yaml
- scripts-ansible-managed.yaml
- blink1.yaml
tags:
- hass-config
- name: home assistant secrets file
template:
src: secrets.yaml.j2
dest: "{{ systemuserlist.hass.home }}/home-assistant/config/secrets.yaml"
owner: "{{ systemuserlist.hass.uid }}"
group: "{{ systemuserlist.hass.gid }}"
mode: 0644
notify: restart hass container
tags:
- hass-config
- name: copy home assistant templates file
- name: copy dashboards
copy:
src: templates.yaml
dest: "{{ systemuserlist.hass.home }}/home-assistant/config/templates.yaml"
owner: "{{ systemuserlist.hass.uid }}"
group: "{{ systemuserlist.hass.gid }}"
mode: 0644
src: "private/hass/{{ item }}"
dest: "{{ systemuserlist.hass.home }}/home-assistant/config/{{ item }}"
mode: 0755
owner: hass
group: hass
notify: restart hass container
with_items:
- mini.yaml
- ui-test.yaml
- card_room.yaml
tags:
- hass-config
@ -163,15 +125,106 @@
- hass-cron
- hass-git
- name: udev rules
template:
src: "{{ item }}.j2"
dest: /etc/udev/rules.d/{{ item }}
owner: root
group: root
mode: 0644
notify: udevadm reload rules
with_items:
- 20-sdr.rules
tags:
- hass-udev
# key source:
# - http://download.ag-projects.com/agp-debian-gpg.key
# - http://download.ag-projects.com/agp-debian-key.key
# gpg --enarmor roles/hass/files/agp-debian-gpg.key
# binary keys: .gpg
# ascii armor: .asc (or .key?)
- name: add apt key for sip tools
copy:
src: "{{ item }}"
dest: /etc/apt/trusted.gpg.d/{{ item }}
owner: root
group: root
mode: "0644"
with_items:
- agp-debian-gpg.asc
- agp-debian-key.asc
tags:
- packages
- hass-sip
- sip
# - debug:
# msg: "deb [signed-by=/usr/share/keyrings/agp-debian-gpg.key] http://ag-projects.com/{{ ansible_lsb.id | lower }} {{ ansible_lsb.codename }} main"
# tags: hass-sip
# [signed-by=/usr/share/keyrings/agp-debian-gpg.gpg]
# [signed-by=/etc/apt/trusted.gpg.d/agp-debian-gpg.asc]
- name: add repo for sip tools
apt_repository:
#repo: "{{ item }} [signed-by=/etc/apt/trusted.gpg.d/agp-debian-key.asc] http://ag-projects.com/{{ ansible_lsb.id | lower }} {{ ansible_lsb.codename }} main"
repo: "{{ item }} [signed-by=/etc/apt/trusted.gpg.d/agp-debian-key.asc] http://ag-projects.com/{{ ansible_lsb.id | lower }} sid main"
state: present
update_cache: false
with_items:
- "deb"
- "deb-src"
register: sip_repo
tags:
- packages
- hass-sip
- sip
when: false
- name: update apt if new repo was added
apt:
update_cache: true
tags:
- packages
- hass-sip
- sip
when:
- sip_repo.changed
- false
# the host needs to have bluez installed for the container to use bluetooth
- name: install bluetooth packages
- name: install packages
apt:
name:
- vlc
- mplayer
- bluez
- bluetooth
- fapg
- podget
- sqlite3
- rtl-433
- mosquitto
- python3-paho-mqtt
- blink1 # git.sudo.is/ben/build-blink1
# # sip tools
# - python3-sipsimple
# - sipclients3
state: latest
tags:
- packages
- hass-bluetooth
- hass-packages
- hass-sip
- sip
- name: ensure bluetooth service is started and enabled
service:
name: bluetooth
state: started
enabled: true
tags:
- hass-bluetooth
# docker run --run -it -p 8091:8091 -p 3000:3000 --network
#bridgewithdns --device /dev/ttyACM0:/dev/zwave -v
@ -186,7 +239,7 @@
detach: true
pull: true
restart_policy: "unless-stopped"
state: "{{ container_state | default('started') }}"
state: "{{ hass_container_state | default('stopped') }}"
container_default_behavior: compatibility
user: "{{ systemuserlist.hass.uid }}:dialout"
networks_cli_compatible: false
@ -200,18 +253,21 @@
# ws for hass<->zwavejs
# hass is configured to use localhost:3000 to talk to zwavejs, but can
# also use {{ bridgewithdns.zwavejs }}, but hass is very fragile and
# you have to manually work around it if it cant access zwaevjs because the
# ip/dns changed or the container moved networks. it is not configured in a
# config file either. so using localhost is the least fragile strategy.
# you have to manually work around it if it cant access zwaevjs because
# the ip/dns changed or the container moved networks. it is not
# configured in a config file either. so using localhost is the least
# fragile strategy.
- "127.0.0.1:3000:3000"
env:
#BASE_URL: "/zwavejs/"
SESSION_SECRET: "{{ zwavejs_session_secret }}"
ZWAVEJS_EXTERNAL_CONFIG: /usr/src/app/store/.config-db
SERVER_SSL: "true"
mounts:
- type: bind
source: "{{ systemuserlist.hass.home }}/zwavejs/app/store"
target: /usr/src/app/store
register: zwavejs_container
tags:
- zwavejs
- zwavejs-container
@ -219,20 +275,25 @@
- docker-containers
# docker run --rm it --name hass -p 8123:8123 -e TZ=Etc/UTC -v
# /home/ben/hass:/config --network-bridgewithdns
# /home/ben/hass:/config --network=bridgewithdns
# ghcr.io/home-assistant/home-assistant:stable
- name: start home-assistant container
docker_container:
name: hass
image: ghcr.io/home-assistant/home-assistant:stable
#image: git.sudo.is/ben/hass:latest
detach: true
pull: true
restart_policy: "unless-stopped"
state: "{{ container_state | default('started') }}"
state: "{{ hass_container_state | default('stopped') }}"
container_default_behavior: compatibility
user: "{{ systemuserlist.hass.uid }}:{{ systemuserlist.hass.gid }}"
network_mode: host
privileged: true
capabilities:
- SYS_ADMIN
- NET_ADMIN
env:
TZ: "Etc/UTC"
mounts:
@ -242,19 +303,27 @@
- type: bind
source: "{{ systemuserlist.hass.home }}/home-assistant/.config"
target: /.config
- type: bind
source: "{{ systemuserlist.hass.home }}/home-assistant/.cache"
target: /.cache
- type: bind
source: "{{ systemuserlist.hass.home }}/.local"
target: /.local
- type: bind
source: "{{ systemuserlist.hass.home }}/home-assistant/media"
target: /usr/var/media
# for bluetooth, container needs access to the dbus socket
# https://www.home-assistant.io/integrations/bluetooth/
- type: bind
source: /run/dbus/
target: /run/dbus/
read_only: true
source: "{{ systemuserlist.archives.home }}/podgrab/data"
target: /usr/var/media/podcasts
- type: bind
source: /etc/bluetooth/main.conf
target: /etc/bluetooth/main.conf
read_only: true
read_only: false
source: /run/dbus
target: /run/dbus
# - type: bind
# source: /etc/bluetooth/main.conf
# target: /etc/bluetooth/main.conf
# read_only: true
# scripts from role: common
# only depends on requests, which hass image has
- type: bind
@ -283,20 +352,23 @@
vars:
prediff_cmd: echo
with_items:
- "{{ hass_url }}"
- "{{ domain }}"
- name: template nginx vhost for hass
- name: template nginx vhosts for hass and friends
template:
src: 01-hass.j2
dest: /etc/nginx/sites-enabled/01-hass
src: "01-{{ item }}.conf.j2"
dest: /etc/nginx/sites-enabled/{{ item }}.conf
owner: root
group: root
mode: 0644
with_items:
- hass
- zwavejs
tags:
- nginx
- hass-nginx
- zwave-nginx
notify: restart nginx
notify: reload nginx
# different task because its better for the hass config to restart nginx
- name: template nginx vhost for grafana-proxy

View File

@ -0,0 +1,100 @@
- name: allow ssh
ufw:
rule: allow
to_port: "22"
direction: in
state: enabled
tags:
- ufw
- name: allow loopback
ufw:
rule: allow
interface: lo
direction: in
state: enabled
tags:
- ufw
- name: default policy
ufw:
policy: allow
state: enabled
tags:
- ufw
- name: deny hass cloud port stuff
ufw:
# drops packets
rule: deny
to_port: '42161'
direction: in
state: enabled
tags:
- ufw
- name: reject zwavejs ws and hass ports (loopback only)
ufw:
# connection refused
rule: reject
to_port: "{{ item }}"
direction: in
state: enabled
with_items:
- "8091"
- "8123"
tags:
- ufw
- name: get current timestamp line
command: grep "timestamp=" /etc/NetworkManager/system-connections/blackbox.connection
check_mode: false
ignore_errors: true
changed_when: false
register: timestamp
tags:
- hass-wifi
- hass-blackbox
# nmcli device wifi blackbox ifname wlo1 ssid {{ hass_wifi_blackbox.ssid }} password {{ hass_wifi_blackbox.pass }}
- name: config for blackbox wifi ap with NetworkManager
template:
src: blackbox.connection.j2
dest: /etc/NetworkManager/system-connections/blackbox.connection
owner: root
group: root
mode: 0600
tags:
- hass-wifi
- hass-blackbox
notify:
- nmcli conn reload
- nmcli device wifi hotspot
# routing/forwarding should not be enabled, but block it to be sure
- name: allow local traffic on blackbox wifi
ufw:
rule: allow
interface: "{{ hass_wifi_blackbox.iface }}"
direction: out
dest: "{{ hass_wifi_blackbox.ip }}/{{ hass_wifi_blackbox.cidr_prefix }}"
state: enabled
tags:
- hass-wifi
- hass-blackbox
- ufw
- name: reject everything else on the blackbox wifi
ufw:
# connection refused
rule: reject
interface: "{{ hass_wifi_blackbox.iface }}"
direction: out
dest: any
state: enabled
tags:
- hass-wifi
- hass-blackbox
- ufw

View File

@ -0,0 +1,144 @@
map $http_upgrade $connection_upgrade {
default upgrade;
#default $http_connection;
'' close;
}
server {
listen 443 ssl http2;
{% if inventory_hostname in wg_clients -%}
listen {{ wg_clients[inventory_hostname].ip }}:443 ssl http2;
{% endif -%}
include /etc/nginx/authelia_internal.conf;
include listen-proxy-protocol.conf;
include /etc/nginx/sudo-known.conf;
server_name {{ hass_url }};
location / {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:8123;
}
# location /media {
# root {{ systemuserlist.hass.home }}/home-assistant/media;
# autoindex on;
# autoindex_exact_size off;
# }
{% if blink1_enabled -%}
location /blink1/ {
{% for cidr in my_local_cidrs -%}
allow {{ cidr }};
{% endfor -%}
allow {{ my_public_ips[ansible_control_host] }}/32;
allow 127.0.0.1;
deny all;
{% if blink1_tiny_html|default(false) -%}
rewrite '^/blink1(/.*)$' $1 break;
sub_filter_once off;
sub_filter '"/' '"./';
{% else -%}
add_header Content-Type 'application/json' always;
{% endif -%}
proxy_http_version 1.1;
proxy_pass http://localhost:{{ blink1_server_port }};
}
{% endif %}
location = {{ nginx_zwavejs_path }} {
# zwavejs needs to be accessed with a trailing / to respond.
#
# temporary redirects dont get remembered by the browser
# and redirect issues are no fun
return 302 https://{{ hass_url }}{{ nginx_zwavejs_path }}/;
}
location {{ nginx_zwavejs_path }} {
#add_header Access-Control-Allow-Origin "*" always;
# kill cache
add_header Last-Modified $date_gmt always;
add_header Cache-Control 'no-store' always;
if_modified_since off;
expires off;
etag off;
# nuke the service worker cache
# sub_filter '.js' '.js?id=$request_id';
include /etc/nginx/require_auth.conf;
rewrite ^ $request_uri;
rewrite '^{{ nginx_zwavejs_path }}(/.*)$' $1 break;
proxy_set_header X-External-Path {{ nginx_zwavejs_path }};
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
#proxy_socket_keepalive on;
## for the special dashboard
## https://zwave-js.github.io/zwave-js-ui/#/usage/reverse-proxy?id=using-an-http-header
## proxy_set_header X-External-Path $http_x_ingress_path;
proxy_pass http://{{ bridgewithdns.zwavejs }}:8091$uri;
#proxy_pass http://{{ bridgewithdns.zwavejs }}:8091/;
}
ben marked this conversation as resolved
Review

remove

remove
Review

more or less fixed, not in this pr.

more or less fixed, not in this pr.
location = {{ nginx_podgrab_path }} {
return 302 https://{{ hass_url }}{{ nginx_podgrab_path }};
}
location {{ nginx_podgrab_path }} {
#include /etc/nginx/require_auth.conf;
# json for a tag:
# https://hass.sudo.is/podcasts/tags/${tag}
# add rss type or let podgrab handle it?
# slice out the url prefix
rewrite '^{{ nginx_podgrab_path }}(/.*)$' $1 break;
# rewrite html responses to add the url prefix
sub_filter_once off;
sub_filter 'href="/' 'href="{{ nginx_podgrab_path }}/';
sub_filter 'src="/' 'src="{{ nginx_podgrab_path }}/';
sub_filter '= "/' '= "{{ nginx_podgrab_path }}/';
sub_filter ':"/' ':"{{ nginx_podgrab_path }}/';
sub_filter ':href="\'/' ':href="\'{{ nginx_podgrab_path }}/';
sub_filter 'return "/' 'return "{{ nginx_podgrab_path }}/';
sub_filter '("/' '("{{ nginx_podgrab_path }}/';
sub_filter '`/' '`{{ nginx_podgrab_path }}/';
sub_filter '/ws' '{{ nginx_podgrab_path }}/ws';
# nuke the service worker cache
sub_filter '.js' '.js?id=$request_id';
sub_filter '.css' '.css?id=$request_id';
# headers for websockets
#proxy_set_header Upgrade $http_upgrade;
#proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Real-IP $remote_addr;
#proxy_set_header X-Forwarded-Proto $scheme;
#proxy_set_header X-Forwarded-Host $http_host;
#proxy_set_header Host $http_host;
proxy_pass http://localhost:{{ podgrab_port }}{{ nginx_podgrab_path }}/;
}
Review

vhost

vhost
access_log /var/log/nginx/access_{{ hass_url }}.log main;
error_log /var/log/nginx/error_{{ hass_url }}.log warn;
ssl_session_timeout 5m;
ssl_certificate /usr/local/etc/certs/{{ domain }}/fullchain.pem;
ssl_certificate_key /usr/local/etc/certs/{{ domain }}/privkey.pem;
fastcgi_hide_header X-Powered-By;
}

View File

@ -1,74 +0,0 @@
map $http_upgrade $connection_upgrade {
default upgrade;
#default $http_connection;
'' close;
}
server {
listen 443 ssl http2;
{% if inventory_hostname in wg_clients -%}
listen {{ wg_clients[inventory_hostname].ip }}:443 ssl http2;
{% endif -%}
include /etc/nginx/authelia_internal.conf;
include listen-proxy-protocol.conf;
include /etc/nginx/sudo-known.conf;
server_name {{ hass_url }};
location / {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:8123;
}
location = {{ nginx_zwavejs_path }} {
# zwavejs needs to be accessed with a trailing / to respond.
#
# temporary redirects dont get remembered by the browser
# and redirect issues are no fun
return 302 https://{{ hass_url }}{{ nginx_zwavejs_path }}/;
}
location {{ nginx_zwavejs_path }} {
#add_header Access-Control-Allow-Origin "*" always;
# kill cache
add_header Last-Modified $date_gmt always;
add_header Cache-Control 'no-store' always;
if_modified_since off;
expires off;
etag off;
include /etc/nginx/require_auth.conf;
rewrite ^ $request_uri;
rewrite '^{{ nginx_zwavejs_path }}(/.*)$' $1 break;
proxy_set_header X-External-Path {{ nginx_zwavejs_path }};
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
#proxy_socket_keepalive on;
proxy_pass http://{{ bridgewithdns.zwavejs }}:8091$uri;
#proxy_pass http://{{ bridgewithdns.zwavejs }}:8091;
# for the special dashboard
# https://zwave-js.github.io/zwave-js-ui/#/usage/reverse-proxy?id=using-an-http-header
# proxy_set_header X-External-Path $http_x_ingress_path;
}
access_log /var/log/nginx/access_{{ hass_url }}.log main;
error_log /var/log/nginx/error_{{ hass_url }}.log warn;
ssl_session_timeout 5m;
ssl_certificate /usr/local/etc/certs/{{ hass_url }}/fullchain.pem;
ssl_certificate_key /usr/local/etc/certs/{{ hass_url }}/privkey.pem;
fastcgi_hide_header X-Powered-By;
}

View File

@ -0,0 +1,47 @@
server {
listen 443 ssl http2;
{% if inventory_hostname in wg_clients -%}
listen {{ wg_clients[inventory_hostname].ip }}:443 ssl http2;
{% endif -%}
include /etc/nginx/authelia_internal.conf;
include listen-proxy-protocol.conf;
include /etc/nginx/sudo-known.conf;
server_name {{ zwavejs_url }};
location / {
include /etc/nginx/require_auth.conf;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# nuke cache
add_header Last-Modified $date_gmt always;
add_header Cache-Control 'no-store' always;
if_modified_since off;
expires off;
etag off;
# nuke the service worker cache
sub_filter '.js' '.js?id=$request_id';
## for the special dashboard
## https://zwave-js.github.io/zwave-js-ui/#/usage/reverse-proxy?id=using-an-http-header
#proxy_set_header X-External-Path "/";
proxy_set_header X-External-Path $http_x_ingress_path;
proxy_pass http://{{ bridgewithdns.zwavejs }}:8091;
}
access_log /var/log/nginx/access_{{ zwavejs_url }}.log main;
error_log /var/log/nginx/error_{{ zwavejs_url }}.log warn;
ssl_session_timeout 5m;
ssl_certificate /usr/local/etc/certs/{{ domain }}/fullchain.pem;
ssl_certificate_key /usr/local/etc/certs/{{ domain }}/privkey.pem;
fastcgi_hide_header X-Powered-By;
}

View File

@ -0,0 +1 @@
SUBSYSTEM=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="2838", GROUP="adm", MODE="0666", SYMLINK+="rtl_sdr"

View File

@ -0,0 +1,174 @@
- alias: monitor_radiators_reporting
description: monitor that the battery-powered radiator knobs are working
trigger:
{% for radiator in hass_radiators -%}
{% if 'status' in radiator -%}
- platform: state
id: "radiator {{ radiator.name }}"
entity_id:
- binary_sensor.radiator_{{ radiator.name }}_reporting
to: 'off'
{% endif -%}
{% endfor %}
condition: []
mode: single
action:
- service: notify.persistent_notification
data:
title: 'device not reporting'
message: 'stopped reporting: {%raw%}{{ trigger.id }}{%endraw%}'
- service: notify.notify
data:
title: 'device not reporting'
message: 'stopped reporting: {%raw%}{{ trigger.id }}{%endraw%}'
- alias: refresh_light_switches_state
description: the tkbhome switches dont automatically report their state
trigger:
- platform: time_pattern
minutes: "/1"
condition: []
mode: single
action:
- service: zwave_js.refresh_value
data:
entity_id:
{% for item in hass_light_switches -%}
{% if item.automation_refresh|default(false) -%}
- {{ item.entity_id }}
{% endif -%}
{% endfor %}
{% for item in hass_light_switches -%}
{% set domain = item.entity_id.split('.')[0] %}
{% set name = item.entity_id.split('.')[1] %}
{% if 'auto_off' in item %}
- alias: {{ name }}_turn_off
description: automatically turn off {{ name }} {{ domain}}
trigger:
- platform: state
entity_id:
- {{ item.entity_id }}
to: "on"
for:
minutes: {{ item.auto_off }}
condition:
- condition: state
entity_id: {{ item.entity_id }}
state: "on"
action:
- service: {{ domain }}.turn_off
data: {}
target:
entity_id: {{ item.entity_id }}
mode: single
{% endif -%}
{% endfor %}
{% for linux_tracker in hass_linux_presence_trackers -%}
- alias: "webhook_presence_trackers_{{ linux_tracker.name }}"
description: ""
trigger:
- platform: webhook
webhook_id: {{ linux_tracker.name }}-{{ linux_tracker.webhook_key }}
id: webhook
mode: single
action:
- if:
- condition: template
value_template: >-
{%raw -%} {% {%endraw%} set current_value = states('input_text.webhook_{{ linux_tracker.name }}') {%raw%} %} {%endraw%}
{% raw %}
{{ current_value != trigger.json['state'] }}
{% endraw %}
then:
- service: input_text.set_value
target:
entity_id: input_text.webhook_{{ linux_tracker.name }}
data:
value: "{% raw %}{{ trigger.json.state }}{% endraw %}"
- alias: "inactive_webhook_presence_trackers_{{ linux_tracker.name }}"
description: ""
trigger:
- platform: state
entity_id: binary_sensor.{{ linux_tracker.name }}_webhook_triggering
to: "off"
action:
- service: input_text.set_value
target:
entity_id: input_text.webhook_{{ linux_tracker.name }}
data:
value: "inactive"
{% endfor %}
- alias: flood_sensor_washing_machine
description: ""
trigger:
- platform: state
entity_id:
- binary_sensor.flood_sensor_water_leak_detected
to: "on"
condition: []
mode: single
action:
- service: switch.turn_off
data: {}
target:
entity_id: switch.washing_machine
- service: notify.notify
data:
title: "FLOOD SENSOR BATHROOM"
message: "WATER DETECTED! power to washing machine was cut"
- if:
- condition: zone
entity_id: person.ben
zone: zone.home
then:
- service: switch.turn_on
data: {}
target:
entity_id: switch.nad_c370
- service: media_player.play_media
data:
media_content_type: video/webm
media_content_id: media-source://media_source/media/flood_alert.mp3
target:
entity_id: media_player.den_tv
Review

improve

improve
- alias: buzzer_normally_closed
description: "keep the buzzer switch closed"
mode: single
trigger:
- platform: state
entity_id:
- switch.doorbell_buzzer
to: "on"
for:
hours: 0
minutes: 0
seconds: 1
condition: []
action:
- service: switch.turn_off
data: {}
target:
entity_id: switch.doorbell_buzzer
{% for item in hass_feedreader -%}
- alias: "podcast_parse_feed_{{ item.short_name }}"
trigger:
platform: event
event_type: feedreader
event_data:
feed_url: "{{ item.url }}"
action:
service: persistent_notification.create
data:
title: "Podcast parsed"
message: {% raw %}"{{ trigger.event.data }}"{% endraw %}
{% endfor %}

View File

@ -0,0 +1,38 @@
{#
# nmcli device wifi blackbox ifname wlo1 ssid {{ hass_wifi_blackbox.ssid }} password {{ hass_wifi_blackbox.pass }}
#}
[connection]
id=blackbox
uuid={{ hass_wifi_blackbox.uuid }}
type=wifi
autoconnect=false
interface-name={{ hass_wifi_blackbox.iface }}
{% if timestamp.stdout %}
{{ timestamp.stdout }}
{% else %}
timestamp={{ ansible_date_time.epoch }}
{% endif %}
[wifi]
mode=ap
ssid={{ hass_wifi_blackbox.ssid }}
{% if hass_wifi_blackbox.hidden|default(false) -%}
hidden=true
{% endif %}
[wifi-security]
group=ccmp;
key-mgmt=wpa-psk
pairwise=ccmp;
proto=rsn;
psk={{ hass_wifi_blackbox.pass }}
[ipv4]
address1={{ hass_wifi_blackbox.ip }}/{{ hass_wifi_blackbox.cidr_prefix }}
method=manual
[ipv6]
addr-gen-mode=stable-privacy
method=ignore
[proxy]

View File

@ -0,0 +1,71 @@
{% if blink1_enabled -%}
friendly_name: blink1
value_template: >-
{% raw -%}
{{ state_attr('sensor.blink1', 'rgb') != "#000000" }}
{% endraw %}
# color_template: >-
# {% raw -%}
# {{ state_attr('sensor.blink1', 'rgb') }}
# {% endraw %}
turn_on:
- service: rest_command.blink1_turn_on
- delay:
milliseconds: 500
- service: homeassistant.update_entity
target:
entity_id: sensor.blink1
turn_off:
- service: rest_command.blink1_turn_off
- delay:
milliseconds: 500
- service: homeassistant.update_entity
target:
entity_id: sensor.blink1
set_color:
- service: rest_command.blink1_turn_off
- service: rest_command.blink1_set_color
data:
# https://github.com/velijv/home-assistant-color-helpers#rgb-to-hex
# https://community.home-assistant.io/t/advanced-light-template-help/175654
# https://community.home-assistant.io/t/using-hsv-hsb-to-set-colored-lights/15472
rgb: >-
{%raw%}
{%- set h2 = h / 360 -%}
{%- set s2 = s / 100 -%}
{%- set v = 100 -%}
{%- set i = (h2 * 6 ) | round(2,'floor') | int-%}
{%- set f = h2 * 6 - i -%}
{%- set p = v * (1 - s2) -%}
{%- set q = v * (1 - f * s2) -%}
{%- set t = v * (1 - (1 - f) * s2) -%}
{%- if i % 6 == 0 -%}
{%- set r = v | int -%}
{%- set g = t | int -%}
{%- set b = p | int -%}
{%- elif i % 6 == 1 -%}
{%- set r = q | int -%}
{%- set g = v | int -%}
{%- set b = p | int -%}
{%- elif i % 6 == 2 -%}
{%- set r = p | int -%}
{%- set g = v | int -%}
{%- set b = t | int -%}
{%- elif i % 6 == 3 -%}
{%- set r = p | int -%}
{%- set g = q | int -%}
{%- set b = v | int -%}
{%- elif i % 6 == 4 -%}
{%- set r = t | int -%}
{%- set g = p | int -%}
{%- set b = v | int -%}
{%- elif i % 6 == 5 -%}
{%- set r = v | int -%}
{%- set g = p | int -%}
{%- set b = q | int -%}
{%- endif -%}
{{ '%02x%02x%02x' | format(r, g, b) }}
{%endraw%}
{% endif %}

View File

@ -0,0 +1,52 @@
{% raw -%}
- platform: climate_template
name: Radiators
modes:
- "auto"
- "heat"
- "cool"
- "off"
min_temp: 0
max_temp: 30
current_temperature_template: "{{ states('input_number.heating_setpoint_test') }}"
hvac_mode_template: "{{ states('input_select.heating_mode_test') }}"
current_humidity_template: 0.0
swing_mode_template: false
availability_template: true
set_temperature:
- service: input_number.set_value
data:
value: >-
{% set set_point = float(state_attr('climate.radiators', 'temperature'), 14.0) %}
{{ set_point }}
target:
entity_id: input_number.heating_setpoint_test
set_hvac_mode:
- service: input_select.select_option
data:
option: >-
{% set hvac_mode = state_attr('climate.radiators', 'hvac_mode') | default('off') %}
{{ hvac_mode }}
target:
entity_id: input_select.heating_mode_test
{% endraw %}
{# use this in script?
{{ state_attr('climate.radiators', 'temperature') }}
this should work, but doesnt
docs: https://www.home-assistant.io/integrations/template/
{{ this.attributes.temperature }}
https://github.com/jcwillox/hass-template-climate/issues/29
this syntax works:
{% set set_point = float(state_attr('climate.radiators', 'temperature'), 14.0) %}
{{ set_point }}
target_temperature_template: "{{ states('input_number.heating_setpoint_test') }}"
#}

View File

@ -57,48 +57,84 @@ default_config:
# zeroconf:
# zone:
automation ui: !include automations.yaml
automation ansible: !include automations-ansible-managed.yaml
script: !include scripts.yaml
scene: !include scenes.yaml
template: !include templates.yaml
climate: !include climate.yaml
# Text to speech
tts:
- platform: voicerss
api_key: !secret voicerss_api_key
- platform: google_translate
automation: !include automations.yaml
script: !include scripts.yaml
scene: !include scenes.yaml
template: !include templates.yaml
{# calendar:
# {% for item in hass_caldav.urls %}
#
# - platform: caldav
# days: 30
# username: !secret caldav_user
# password: !secret caldav_passwd
# # {{ item.name }}
# url: {{ item.url }}
#
# {% endfor %}
#}
- platform: picotts
language: "en-GB"
calendar:
{% for item in hass_caldav.calendars -%}
- platform: caldav
days: 30
username: !secret caldav_user
password: !secret caldav_passwd
# {{ hass_caldav.urls[0].name }}
url: {{ hass_caldav.urls[0].url }}
# {{ item.name | trim }}
url: {{ item.url | trim }}
{% endfor %}
http:
# container runs with network_mode=host, so no network isolation. the docs say to not
# do this, and it doesnt work as expected either.
# using ufw/iptables for now....
#
#server_host: 127.0.0.1
server_host: 127.0.0.1
server_port: 8123
trusted_proxies:
- 127.0.0.1
use_x_forwarded_for: true
frontend:
themes: !include_dir_merge_named themes
panel_custom:
- name: zwave
sidebar_title: Z-Wave
sidebar_icon: mdi:z-wave
js_url: /api/hassio/app/entrypoint.js
url_path: 'config/devices/dashboard?historyBack=1&config_entry=d6e38621854098348266029e18f93048'
embed_iframe: true
require_admin: true
config:
ingress: core_configurator
- name: automations
sidebar_title: Automations
sidebar_icon: mdi:robot
js_url: /api/hassio/app/entrypoint.js
url_path: 'config/automation/dashboard'
embed_iframe: true
require_admin: true
config:
ingress: core_configurator
- name: scripts
sidebar_title: Scripts
sidebar_icon: mdi:script
js_url: /api/hassio/app/entrypoint.js
url_path: 'config/script/dashboard'
embed_iframe: true
require_admin: true
config:
ingress: core_configurator
- name: integrations
sidebar_title: Integrations
sidebar_icon: mdi:integrated-circuit-chip
js_url: /api/hassio/app/entrypoint.js
url_path: 'config/integrations'
embed_iframe: true
require_admin: true
config:
ingress: core_configurator
{% set zone = {'zone': hass_zones} %}
{{ zone | to_nice_yaml }}
homeassistant:
auth_providers:
- type: command_line
@ -109,6 +145,7 @@ homeassistant:
currency: EUR
unit_system: metric
time_zone: "Europe/Berlin"
country: DE
external_url: https://{{ hass_url }}
internal_url: https://{{ hass_url }}
allowlist_external_dirs:
@ -118,6 +155,42 @@ homeassistant:
- "https://{{ hass_notflix_url }}"
media_dirs:
media: "/usr/var/media"
customize:
zone.home:
friendly_name: S21
lovelace:
mode: storage
dashboards:
lovelace-yaml:
mode: yaml
title: Mini
icon: mdi:view-dashboard
show_in_sidebar: true
require_admin: false
filename: mini.yaml
lovelace-yaml2:
mode: yaml
title: Test
icon: mdi:view-dashboard
show_in_sidebar: true
require_admin: false
filename: ui-test.yaml
{# resources:
# - url: /config/custom_components/ui_lovelace_minimalist/cards/button-card/button-card.js
# type: module
# - url: /config/custom_components/ui_lovelace_minimalist/cards/button-card/button-card.js
# type: module #}
recorder:
purge_keep_days: 3
exclude:
entity_globs:
- binary_sensor.1066d799*
- sensor.1066d799*
- light.1066d799*
sensor:
# https://www.home-assistant.io/integrations/dwd_weather_warnings/
@ -144,28 +217,116 @@ sensor:
# Stadt Berlin
region_name: 811000000
{% for item in hass_bvg -%}
- platform: bvg_berlin_public_transport
name: {{ item.name }}
stop_id: "{{ item.stop_id }}"
direction: {{ item.direction | trim }}
{% if item.walking_distance is defined -%}
walking_distance: {{ item.walking_distance | trim }}
{% endif -%}
file_path: "/config/bvg/"
{% endfor %}
- platform: waqi
token: !secret waqi_token
locations:
{% for item in hass_waqi.locations -%}
- "{{ item | trim }}"
{%- endfor +%}
{#stations:
#{% for item in hass_waqi.stations -%}
#- "{{ item | trim }}"
#{% endfor %}
#}
{% if blink1_enabled -%}
- platform: rest
resource: http://localhost:{{ blink1_server_port }}/blink1
name: blink1
json_attributes:
- rgb
- bright
value_template: "{%raw%}{{ value_json.rgb }}{%endraw%}"
{% endif %}
binary_sensor:
- platform: workday
country: DE
workdays: [mon, tue, wed, thu, fri]
excludes: [sat, sun, holiday]
{% for radiator in hass_radiators -%}
{% if 'status' in radiator -%}
- platform: threshold
entity_id: sensor.radiator_{{ radiator.name }}_last_updated
# defined in templates.yaml
name: radiator_{{ radiator.name }}_reporting
# minutes
lower: 10
{% endif -%}
{% endfor -%}
{% for target in hass_ping -%}
- platform: ping
name: ping_{{ target.name }}
host: {{ target.host }}
count: 1
scan_interval: {{ target.interval_secs }}
count: {{ target.count | default('1') }}
scan_interval: {{ target.interval_secs | default('30') }}
{% endfor %}
input_select:
heating_mode_test:
name: Heating Mode Test
options:
- "auto"
- "heat"
- "cool"
- "off"
initial: "off"
icon: mdi:thermometer-lines
input_number:
heating_setpoint_test:
name: Heating Setpoint Test
icon: mdi:home-thermometer
initial: 0
min: 0
max: 35
step: 0.5
input_text:
{% for linux_tracker in hass_linux_presence_trackers -%}
webhook_{{ linux_tracker.name }}:
name: webhook_{{ linux_tracker.name }}
icon: "mdi:laptop"
initial: "inactive"
pattern: "^active|inactive$"
{% endfor %}
device_tracker:
- platform: bluetooth_le_tracker
interval_seconds: 12
track_new_devices: false
track_battery: false
consider_home: 150
new_device_defaults:
track_new_devices: false
- platform: bluetooth_tracker
request_rssi: false
interval_seconds: 12
track_new_devices: false
consider_home: 150
new_device_defaults:
track_new_devices: false
- platform: ping
hosts:
{% for target in hass_ping -%}
{% if target.device_tracker|default(true) -%}
{{ target.name }}: {{ target.host }}
{% endif -%}
{% endfor %}
# enabling bluetooth
bluetooth:
influxdb:
host: "{{ influxdb_url }}"
@ -186,5 +347,79 @@ influxdb:
source: hass
home: S21
matrix:
homeserver: https://{{ matrix_url }}
username: !secret matrix_username
password: !secret matrix_password
rooms: !secret matrix_rooms
commands:
- word: hass
name: hass
notify:
- name: matrix
platform: matrix
default_room: !secret matrix_default_room
- name: pagerduty
platform: smtp
sender: hass@{{ domain }}
recipient:
- !secret smtp_recipient_email
server: !secret smtp_server
port: {{ smtp_port_starttls }}
username: !secret smtp_username
password: !secret smtp_passwd
encryption: starttls
sender_name: "{{ hass_url }}"
shell_command:
matrixmsg: /usr/local/bin/matrixmsg.py
rest_command:
{% if blink1_enabled -%}
blink1_turn_on:
url: {{ hass_blink1_url }}/blink1/on?bright=250
#url: http://localhost:{{ blink1_server_port }}/blink1/fadeToRGB?rgb=ff0ff
method: GET
content_type: "application/json"
blink1_turn_off:
url: {{ hass_blink1_url }}/blink1/off
method: GET
content_type: "application/json"
blink1_turn_magenta:
url: {{ hass_blink1_url }}/blink1/fadeToRGB?rgb=ff00ff
method: GET
content_type: "application/json"
blink1_set_color:
url: "{{ hass_blink1_url }}/blink1/fadeToRGB?rgb={%raw%}{{ rgb }}{%endraw%}"
method: GET
{% endif %}
light:
{% if blink1_enabled -%}
- platform: template
lights:
blink1: !include blink1.yaml
{% endif %}
# enable 'wake_on_lan' for 'samsungtv'
wake_on_lan:
samsungtv:
- host: {{ hass_wifi_blackbox.tv_ip }}
name: The TV
turn_on_action:
- service: wake_on_lan.send_magic_packet
data:
mac: "{{ hass_wifi_blackbox.tv_mac }}"
feedreader:
urls:
{% for item in hass_feedreader -%}
- "{{ item.url | trim }}"
{% endfor %}
{# logger:
# logs:
# pyatv: debug
# homeassistant.components.apple_tv: debug #}

View File

@ -3,6 +3,9 @@
# we can "safely" template in the actual secrets here and keep them out of
# configuration.yaml, which does get synced to the repo.
openwrt_user: "{{ hass_openwrt_user }}"
openwrt_pass: "{{ hass_openwrt_pass }}"
caldav_user: "{{ hass_caldav.user }}"
caldav_passwd: "{{ hass_caldav.passwd }}"
@ -10,3 +13,17 @@ voicerss_api_key: {{ voicerss_api_key }}
# see group_vars/monitoring.yml
influxdb_pass: {{ hass_influxdb_pass }}
matrix_username: "{{ hass_matrix.username }}"
matrix_password: "{{ hass_matrix.password }}"
{% set rooms = {'matrix_rooms': hass_matrix.rooms} -%}
{{ rooms | to_nice_yaml }}
matrix_default_room: "{{ hass_matrix.rooms[0] }}"
smtp_recipient_email: "{{ pagerduty_email }}"
smtp_server: "{{ smtp_server }}"
smtp_username: "{{ smtp_username }}"
smtp_passwd: "{{ smtp_passwd }}"
waqi_token: {{ hass_waqi.token }}

View File

@ -0,0 +1,126 @@
- sensor:
ben marked this conversation as resolved
Review

this file needs serious work but thats not for this pr

this file needs serious work but thats not for this pr
- name: "chance_of_rain"
unit_of_measurement: "%"
icon: "mdi:weather-pouring"
state: >-
{% raw -%}
{% set ipma_2h = state_attr('weather.ipma_hourly_home', 'forecast')[:2] | map(attribute='precipitation_probability') %}
{% set ipma = state_attr('weather.ipma_hourly_home', 'forecast')[0]['precipitation_probability'] | int %}
{% set owm = states('sensor.owm_home_forecast_precipitation_probability') | int %}
{{ [owm, ipma, 0] | max | int }}
{% endraw %}
{% for radiator in hass_radiators %}
{% if 'status' in radiator %}
- name: "radiator_{{ radiator.name }}_last_updated"
unit_of_measurement: "minutes"
icon: "mdi:update"
device_class: duration
state: >-
{% raw %} {% {% endraw -%}
set since_last_update = now() - states.{{ radiator.status }}.last_updated
{%- raw %} %} {% endraw %}
{% raw %} {{ {% endraw -%}
since_last_update.seconds|int // 60
{%- raw %} }} {% endraw -%}
{% endif %}
{% endfor %}
{% for linux_tracker in hass_linux_presence_trackers -%}
{% endfor %}
- binary_sensor:
{% if blink1_enabled -%}
- name: "blink1_on"
device_class: light
state: >-
{% raw -%}
{{ state_attr('sensor.blink1', 'rgb') != "#000000" }}
{% endraw %}
{% endif %}
- name: "heating_on"
icon: "mdi:home-thermometer"
device_class: heat
state: >-
{% raw -%}
{% set all_radiators = states.climate | selectattr("attributes", "defined") | map(attribute="attributes") | selectattr("temperature", "defined") | map(attribute="temperature") | default([]) | list %}
{% set max_radiator_temp = all_radiators | max | default(0.0) | float %}
{% set target_temp = states('input_number.target_temp_heat') | default(0.0) | float %}
{{ max_radiator_temp >= target_temp }}
{% endraw %}
- name: s21_anyone_home
ben marked this conversation as resolved
Review

remove

remove
Review

fixed, not in this pr.

fixed, not in this pr.
icon: "mdi:home-account"
attributes:
friendly_name: "Anyone home"
state: >-
{% raw -%}
{{ state_attr("zone.home", "persons") | default([]) | length > 0 }}
{% endraw %}
- name: doorbell_buzzer
state: >-
{% raw %} {{ is_state("switch.doorbell_buzzer", "on") }} {% endraw +%}
icon: >-
{% raw -%}
{% if is_state("switch.doorbell_buzzer", "on") %}
mdi:electric-switch-closed
{% else %}
mdi:electric-switch
{% endif %}
{% endraw %}
- name: washing_machine_on
icon: "mdi:washing-machine"
device_class: running
delay_on: "00:00:05"
delay_off: "00:00:05"
state: >-
{% raw -%}
{% set current = states('sensor.washing_machine_electric_a') %}
{% set power = states('sensor.washing_machine_electric_w') %}
{% if current == "unavailable" or power == "unavailable" %}
{{ false }}
{% else %}
{{ current|default(0.0)|float > 0.14 or power|default(0.0)|float > 2.8 }}
{% endif %}
{% endraw %}
{% for linux_tracker in hass_linux_presence_trackers -%}
- name: {{ linux_tracker.name }}_active
icon: "mdi:laptop"
state: >-
{% raw -%} {% {% endraw %} set state_text = states('input_text.webhook_{{ linux_tracker.name }}') {%raw%} %} {%endraw%}
{% raw %}
{{ state_text == "active" }}
{% endraw %}
- name: "{{ linux_tracker.name }}_webhook_triggering"
state: >-
{% raw %} {% {% endraw -%}
set since_last_triggered = now() - state_attr('automation.webhook_presence_trackers_{{ linux_tracker.name }}', 'last_triggered')
{%- raw %} %} {% endraw %}
{% raw %} {{ {% endraw -%}
since_last_triggered.seconds|int < 666
{%- raw %} }} {% endraw -%}
{% endfor %}
- button:
name: doorbell_buzzer
icon: >-
{% raw -%}
{% if is_state("switch.doorbell_buzzer", "on") %}
mdi:electric-switch-closed
{% else %}
mdi:electric-switch
{% endif %}
{% endraw +%}
press:
- service: script.toggle_switch_like_button
data:
target_switch: switch.doorbell_buzzer
press_for_ms: 200
ben marked this conversation as resolved
Review

duplicate file?

duplicate file?

7
roles/home/meta/main.yml Normal file
View File

@ -0,0 +1,7 @@
---
dependencies:
- unifi
- sudoisbot
- hass
- homeaudio

View File

@ -0,0 +1,7 @@
---
dependencies:
- podgrab
- airconnect
- shairplay
- owntone

View File

@ -0,0 +1,452 @@
# A quick guide to configuring OwnTone:
#
# For regular use, the most important setting to configure is "directories",
# which should be the location of your media. Whatever user you have set as
# "uid" must have read access to this location. If the location is a network
# mount, please see the README.
#
# In all likelihood, that's all you need to do!
general {
# Username
# Make sure the user has read access to the library directories you set
# below, and full access to the databases, log and local audio
uid = "abc"
# Database location
db_path = "/config/dbase_and_logs/songs3.db"
# Database backup location
# Uncomment and specify a full path to enable abilty to use REST endpoint
# to initiate backup of songs3.db
#db_backup_path = "/var/cache/owntone/songs3.bak"
# Log file and level
# Available levels: fatal, log, warning, info, debug, spam
logfile = "/config/dbase_and_logs/owntone.log"
loglevel = log
# Admin password for the web interface
# Note that access to the web interface from computers in
# "trusted_network" (see below) does not require password
#admin_password = ""
# Websocket port for the web interface.
websocket_port = 3688
# Websocket interface to bind listener to (e.g. "eth0"). Default is
# disabled, which means listen on all interfaces.
#websocket_interface = ""
# Sets who is allowed to connect without authorisation. This applies to
# client types like Remotes, DAAP clients (iTunes) and to the web
# interface. Options are "any", "localhost" or the prefix to one or
# more ipv4/6 networks. The default is { "localhost", "192.168", "fd" }
trusted_networks = { "localhost", "192.168.21", "10.102.47", "fd" }
# Enable/disable IPv6
ipv6 = no
# Set this if you want the server to bind to a specific IP address. Can
# be ipv6 or ipv4. Default (commented out or "::") is to listen on all
# IP addresses.
#bind_address = "::"
# Location of cache database
cache_path = "/config/dbase_and_logs/cache.db"
# DAAP requests that take longer than this threshold (in msec) get their
# replies cached for next time. Set to 0 to disable caching.
#cache_daap_threshold = 1000
# When starting playback, autoselect speaker (if none of the previously
# selected speakers/outputs are available)
#speaker_autoselect = no
# Most modern systems have a high-resolution clock, but if you are on an
# unusual platform and experience audio drop-outs, you can try changing
# this option
#high_resolution_clock = yes
}
# Library configuration
library {
# Name of the library as displayed by the clients (%h: hostname). If you
# change the name after pairing with Remote you may have to re-pair.
name = "audio.sudo.is"
# TCP port to listen on. Default port is 3689 (daap)
port = 3689
# Password for the library. Optional.
#password = ""
# Directories to index
directories = { "/music" }
# Follow symlinks. Default: true.
#follow_symlinks = true
# Directories containing podcasts
# For each directory that is indexed the path is matched against these
# names. If there is a match all items in the directory are marked as
# podcasts. Eg. if you index /music, and your podcasts are in
# /music/Podcasts, you can set this to "/Podcasts".
# (changing this setting only takes effect after rescan, see the README)
podcasts = { "/podcasts" }
# Directories containing audiobooks
# For each directory that is indexed the path is matched against these
# names. If there is a match all items in the directory are marked as
# audiobooks.
# (changing this setting only takes effect after rescan, see the README)
audiobooks = { "/audiobooks" }
# Directories containing compilations (eg soundtracks)
# For each directory that is indexed the path is matched against these
# names. If there is a match all items in the directory are marked as
# compilations.
# (changing this setting only takes effect after rescan, see the README)
compilations = { "/compilations" }
# Compilations usually have many artists, and sometimes no album artist.
# If you dont want every artist to be listed in artist views, you can
# set a single name which will be used for all compilation tracks
# without an album artist, and for all tracks in the compilation
# directories.
# (changing this setting only takes effect after rescan, see the README)
compilation_artist = "Various Artists"
# If your album and artist lists are cluttered, you can choose to hide
# albums and artists with only one track. The tracks will still be
# visible in other lists, e.g. songs and playlists. This setting
# currently only works in some remotes.
#hide_singles = false
# Internet streams in your playlists will by default be shown in the
# "Radio" library, like iTunes does. However, some clients (like
# TunesRemote+) wont show the "Radio" library. If you would also like
# to have them shown like normal playlists, you can enable this option.
radio_playlists = true
# These are the default playlists. If you want them to have other names,
# you can set it here.
#name_library = "Library"
#name_music = "Music"
#name_movies = "Movies"
#name_tvshows = "TV Shows"
#name_podcasts = "Podcasts"
#name_audiobooks = "Audiobooks"
#name_radio = "Radio"
# Artwork file names (without file type extension)
# OwnTone will look for jpg and png files with these base names
artwork_basenames = { "artwork", "cover", "Folder" }
# Enable searching for artwork corresponding to each individual media
# file instead of only looking for album artwork. This is disabled by
# default to reduce cache size.
#artwork_individual = false
# File types the scanner should ignore
# Non-audio files will never be added to the database, but here you
# can prevent the scanner from even probing them. This might improve
# scan time. By default .db, .ini, .db-journal, .pdf and .metadata are
# ignored.
#filetypes_ignore = { ".db", ".ini", ".db-journal", ".pdf", ".metadata" }
# File paths the scanner should ignore
# If you want to exclude files on a more advanced basis you can enter
# one or more POSIX regular expressions, and any file with a matching
# path will be ignored.
#filepath_ignore = { "myregex" }
# Disable startup file scanning
# When OwnTone starts it will do an initial file scan of your
# library (and then watch it for changes). If you are sure your library
# never changes while OwnTone is not running, you can disable the
# initial file scan and save some system ressources. Disabling this scan
# may lead to OwnTones database coming out of sync with the
# library. If that happens read the instructions in the README on how
# to trigger a rescan.
#filescan_disable = false
# Should metadata from m3u playlists, e.g. artist and title in EXTINF,
# override the metadata we get from radio streams?
#m3u_overrides = false
# Should iTunes metadata override ours?
itunes_overrides = true
# Should we import the content of iTunes smart playlists?
#itunes_smartpl = false
# Decoding options for DAAP clients
# Since iTunes has native support for mpeg, mp4a, mp4v, alac and wav,
# such files will be sent as they are. Any other formats will be decoded
# to raw wav. If OwnTone detects a non-iTunes DAAP client, it is
# assumed to only support mpeg and wav, other formats will be decoded.
# Here you can change when to decode. Note that these settings have no
# effect on AirPlay.
# Formats: mp4a, mp4v, mpeg, alac, flac, mpc, ogg, wma, wmal, wmav, aif, wav
# Formats that should never be decoded
#no_decode = { "format", "format" }
# Formats that should always be decoded
#force_decode = { "format", "format" }
# Watch named pipes in the library for data and autostart playback when
# there is data to be read. To exclude specific pipes from watching,
# consider using the above _ignore options.
#pipe_autostart = true
# Enable automatic rating updates
# If enabled, rating is automatically updated after a song has either been
# played or skipped (only skipping to the next song is taken into account).
# The calculation is taken from the beets plugin "mpdstats" (see
# https://beets.readthedocs.io/en/latest/plugins/mpdstats.html).
# It consist of calculating a stable rating based only on the play- and
# skipcount and a rolling rating based on the current rating and the action
# (played or skipped). Both results are combined with a mix-factor of 0.75:
# new rating = 0.75 * stable rating + 0.25 * rolling rating)
#rating_updates = false
# Allows creating, deleting and modifying m3u playlists in the library directories.
# Only supported by the player web interface and some mpd clients
# Defaults to being disabled.
allow_modifying_stored_playlists = true
# A directory in one of the library directories that will be used as the default
# playlist directory. OwnTone creates new playlists in this directory if only
# a playlist name is provided (requires "allow_modify_stored_playlists" set to true).
default_playlist_directory = "/music/playlists"
# By default OwnTone will - like iTunes - clear the playqueue if
# playback stops. Setting clear_queue_on_stop_disable to true will keep
# the playlist like MPD does. Note that some dacp clients do not show
# the playqueue if playback is stopped.
#clear_queue_on_stop_disable = false
}
# Local audio output
audio {
# Name - used in the speaker list in Remote
nickname = "Computer"
# Type of the output (alsa, pulseaudio, dummy or disabled)
#type = "alsa"
# For pulseaudio output, an optional server hostname or IP can be
# specified (e.g. "localhost"). If not set, connection is made via local
# socket.
#server = ""
# Audio PCM device name for local audio output - ALSA only
#card = "default"
# Mixer channel to use for volume control - ALSA only
# If not set, PCM will be used if available, otherwise Master.
#mixer = ""
# Mixer device to use for volume control - ALSA only
# If not set, the value for "card" will be used.
#mixer_device = ""
# Enable or disable audio resampling to keep local audio in sync with
# e.g. Airplay. This feature relies on accurate ALSA measurements of
# delay, and some devices dont provide that. If that is the case you
# are better off disabling the feature.
#sync_disable = false
# Here you can adjust when local audio is started relative to other
# speakers, e.g. Airplay. Negative values correspond to moving local
# audio ahead, positive correspond to delaying it. The unit is
# milliseconds. The offset must be between -1000 and 1000 (+/- 1 sec).
#offset_ms = 0
# To calculate what and if resampling is required, local audio delay is
# measured each second. After a period the collected measurements are
# used to estimate drift and latency, which determines if corrections
# are required. This setting sets the length of that period in seconds.
#adjust_period_seconds = 100
}
# ALSA device settings
# If you have multiple ALSA devices you can configure them individually via
# sections like the below. Make sure to set the "card name" correctly. See the
# README about ALSA for details. Note that these settings will override the ALSA
# settings in the "audio" section above.
#alsa "card name" {
# Name used in the speaker list. If not set, the card name will be used.
#nickname = "Computer"
# Mixer channel to use for volume control
# If not set, PCM will be used if available, otherwise Master
#mixer = ""
# Mixer device to use for volume control
# If not set, the card name will be used
#mixer_device = ""
# }
# Pipe output
# Allows OwnTone to output audio data to a named pipe
#fifo {
#nickname = "fifo"
#path = "/path/to/fifo"
# }
# AirPlay settings common to all devices
#airplay_shared {
# UDP ports used when airplay devices make connections back to
# OwnTone (choosing specific ports may be helpful when running
# OwnTone behind a firewall)
# control_port = 0
# timing_port = 0
# }
# AirPlay per device settings
# (make sure you get the capitalization of the device name right)
#airplay "My AirPlay device" {
# OwnTone's volume goes to 11! If that's more than you can handle
# you can set a lower value here
#max_volume = 11
# Enable this option to exclude a particular AirPlay device from the
# speaker list
#exclude = false
# Enable this option to keep a particular AirPlay device in the speaker
# list and thus ignore mdns notifications about it no longer being
# present. The speaker will remain until restart of OwnTone.
#permanent = false
# Some devices spuriously disconnect during playback, and based on the
# device type OwnTone may attempt to reconnect. Setting this option
# overrides this so reconnecting is either always enabled or disabled.
#reconnect = false
# AirPlay password
#password = "s1kr3t"
# Disable AirPlay 1 (RAOP)
#raop_disable = false
# Name used in the speaker list, overrides name from the device
#nickname = "My speaker name"
# }
# Chromecast settings
# (make sure you get the capitalization of the device name right)
#chromecast "My Chromecast device" {
# OwnTone's volume goes to 11! If that's more than you can handle
# you can set a lower value here
#max_volume = 11
# Enable this option to exclude a particular device from the speaker
# list
#exclude = false
# Name used in the speaker list, overrides name from the device
#nickname = "My speaker name"
# }
# Spotify settings (only have effect if Spotify enabled - see README/INSTALL)
spotify {
# Set preferred bitrate for music streaming
# 0: No preference (default), 1: 96kbps, 2: 160kbps, 3: 320kbps
#bitrate = 0
# Your Spotify playlists will by default be put in a "Spotify" playlist
# folder. If you would rather have them together with your other
# playlists you can set this option to true.
#base_playlist_disable = false
# Spotify playlists usually have many artist, and if you dont want
# every artist to be listed when artist browsing in Remote, you can set
# the artist_override flag to true. This will use the compilation_artist
# as album artist for Spotify items.
#artist_override = false
# Similar to the different artists in Spotify playlists, the playlist
# items belong to different albums, and if you do not want every album
# to be listed when browsing in Remote, you can set the album_override
# flag to true. This will use the playlist name as album name for
# Spotify items. Notice that if an item is in more than one playlist,
# it will only appear in one album when browsing (in which album is
# random).
#album_override = false
}
# RCP/Roku Soundbridge output settings
# (make sure you get the capitalization of the device name right)
#rcp "My SoundBridge device" {
# Enable this option to exclude a particular device from the speaker
# list
#exclude = false
# A Roku/SoundBridge can power up in 2 modes: (default) reconnect to the
# previously used library (ie OwnTone) or in a 'cleared library' mode.
# The Roku power up behaviour is affected by how OwnTone disconnects
# from the Roku device.
#
# Set to false to maintain default Roku power on behaviour
#clear_on_close = false
# }
# MPD configuration (only have effect if MPD enabled - see README/INSTALL)
mpd {
# TCP port to listen on for MPD client requests.
# Default port is 6600, set to 0 to disable MPD support.
#port = 6600
# HTTP port to listen for artwork requests (only supported by some MPD
# clients and will need additional configuration in the MPD client to
# work). Set to 0 to disable serving artwork over http.
#http_port = 0
}
# SQLite configuration (allows to modify the operation of the SQLite databases)
# Make sure to read the SQLite documentation for the corresponding PRAGMA
# statements as changing them from the defaults may increase the possibility of
# database corruptions! By default the SQLite default values are used.
sqlite {
# Cache size in number of db pages for the library database
# (SQLite default page size is 1024 bytes and cache size is 2000 pages)
#pragma_cache_size_library = 2000
# Cache size in number of db pages for the daap cache database
# (SQLite default page size is 1024 bytes and cache size is 2000 pages)
#pragma_cache_size_cache = 2000
# Sets the journal mode for the database
# DELETE (default), TRUNCATE, PERSIST, MEMORY, WAL, OFF
#pragma_journal_mode = DELETE
# Change the setting of the "synchronous" flag
# 0: OFF, 1: NORMAL, 2: FULL (default)
#pragma_synchronous = 2
# Number of bytes set aside for memory-mapped I/O for the library database
# (requires sqlite 3.7.17 or later)
# 0: disables mmap (default), any other value > 0: number of bytes for mmap
#pragma_mmap_size_library = 0
# Number of bytes set aside for memory-mapped I/O for the cache database
# (requires sqlite 3.7.17 or later)
# 0: disables mmap (default), any other value > 0: number of bytes for mmap
#pragma_mmap_size_cache = 0
# Should the database be vacuumed on startup? (increases startup time,
# but may reduce database size). Default is yes.
#vacuum = yes
}
# Streaming audio settings for remote connections (ie stream.mp3)
streaming {
# Sample rate, typically 44100 or 48000
#sample_rate = 44100
# Set the MP3 streaming bit rate (in kbps), valid options: 64 / 96 / 128 / 192 / 320
bit_rate = 320
}

View File

@ -0,0 +1,12 @@
---
- name: reload nginx
service:
name: nginx
state: reloaded
- name: restart owntone container
docker_container:
name: hass
state: started
restart: true

View File

@ -0,0 +1,4 @@
---
- import_tasks: owntone.yml
tags: owntone

View File

@ -0,0 +1,145 @@
---
ben marked this conversation as resolved
Review

currently here

currently here
Review

owntone works reasonably well (and is building out of ben/builds/owntone), but its not done. not in this pr though.

owntone works reasonably well (and is building out of ben/builds/owntone), but its not done. not in this pr though.
- name: create dir structure
file:
state: directory
path: "{{ owntone_path }}/{{ item.name }}"
mode: "{{ item.mode | default('0770') }}"
owner: "{{ owntone_user.uid }}"
group: "{{ owntone_group.gid }}"
tags:
- owntone-dirs
loop_control:
label: "{{ item.name }}"
with_items:
- name: ''
- name: config
- name: log
- name: audio
- name: audio/local_music
- name: audio/playlists
- name: audio/compilations
- name: audio/pipes
#- name: audio/lidarr
#- name: audio/audiobooks
#- name: audio/podcasts
- name: create input pipe
command:
cmd: mkfifo "{{ owntone_path }}/audio/pipes/{{ item }}"
creates: "{{ owntone_path }}/audio/pipes/{{ item }}"
become_user: "{{ owntone_user.username }}"
loop_control:
label: "{{ item }}"
with_items:
- shairport-output.fifo
- shairport-metadata.fifo
tags:
- input.fifo
- name: install certs
copy:
src: "/usr/local/etc/letsencrypt/live/{{ item }}"
dest: "/usr/local/etc/certs/"
owner: root
group: root
mode: 0755
tags:
- letsencrypt-certs
notify: reload nginx
vars:
prediff_cmd: echo
with_items:
- "{{ domain }}"
- name: template nginx vhost
template:
src: 01-owntone.conf.j2
dest: /etc/nginx/sites-enabled/01-owntone.conf
owner: root
group: root
mode: 0644
tags:
- nginx
- owntone-nginx
notify: reload nginx
- name: template config file
template:
src: owntone.conf.j2
dest: "{{ owntone_path }}/config/owntone.conf"
owner: "{{ owntone_user.uid }}"
group: "{{ owntone_group.gid }}"
mode: 0644
notify:
- restart owntone container
tags:
- owntone.conf
- name: cron file
template:
src: owntone-cron.j2
dest: /etc/cron.d/owntone
owner: root
group: root
mode: 0600
tags:
- cron
- owntone-cron
- name: install utils for tagging
apt:
name:
- id3v2
- ffmpeg
state: present
tags:
- packages
- name: install yt-dlp
pip:
name: yt-dlp
state: latest
tags:
- packages
- pip-packages
- yt-dlp
- name: fuse allow other
lineinfile:
path: /etc/fuse.conf
line: user_allow_other
state: present
- name: start owntone container
docker_container:
name: owntone
#image: lscr.io/linuxserver/daapd:latest
image: git.sudo.is/ben/owntone:latest
detach: true
pull: true
restart_policy: "unless-stopped"
state: started
container_default_behavior: compatibility
networks_cli_compatible: false
# user:
network_mode: host
env:
VITE_OWNTONE_URL: "https://{{ owntone_url }}"
mounts:
- type: bind
source: "{{ owntone_path }}/config/owntone.conf"
target: "/etc/owntone.conf"
- type: bind
source: "{{ owntone_path }}/config"
target: "/config"
- type: bind
source: "{{ owntone_path }}/log"
target: "/log"
- type: bind
source: "{{ owntone_path }}/audio"
target: "/audio"
tags:
- owntone-container
- docker-containers

View File

@ -0,0 +1,70 @@
server {
listen 443 ssl http2;
# listen {{ owntone_port_tcp }};
{% if inventory_hostname in wg_clients -%}
listen {{ wg_clients[inventory_hostname].ip }}:443 ssl http2;
{% endif -%}
include /etc/nginx/authelia_internal.conf;
include listen-proxy-protocol.conf;
include /etc/nginx/sudo-known.conf;
server_name {{ owntone_url }};
access_log /var/log/nginx/access_{{ owntone_url }}.log main;
error_log /var/log/nginx/error_{{ owntone_url }}.log warn;
ssl_certificate /usr/local/etc/certs/{{ domain }}/fullchain.pem;
ssl_certificate_key /usr/local/etc/certs/{{ domain }}/privkey.pem;
# !
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
location / {
sub_filter 'owntone.local:3689' '{{ owntone_url }}';
sub_filter 'http%3A%2F%2Fowntone.local%3A3689' 'https%3A%2F%2F{{ owntone_url }}';
sub_filter 'http://owntone.local:3689' 'https://{{ owntone_url }}';
sub_filter_types '*';
sub_filter_once off;
proxy_pass http://127.0.0.1:{{ owntone_port_tcp }}/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
server {
# only needs to be accessed by players that are being streamed to
# maybe need to remove 'http2'
listen {{ ansible_default_ipv4.address }}:{{ owntone_port_ws }} ssl http2;
server_name {{ owntone_url }};
access_log /var/log/nginx/access_{{ owntone_url }}_{{ owntone_port_ws }}.log main;
error_log /var/log/nginx/error_{{ owntone_url }}_{{ owntone_port_ws }}.log warn;
ssl_certificate /usr/local/etc/certs/{{ domain }}/fullchain.pem;
ssl_certificate_key /usr/local/etc/certs/{{ domain }}/privkey.pem;
# !
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
location / {
proxy_pass http://127.0.0.1:{{ owntone_port_ws }}/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}

View File

@ -0,0 +1,7 @@
# {{ ansible_managed }}
# m h dom mon dow
*/60 * * * * {{ owntone_user.username }} touch {{ owntone_path }}/audio/local_music/trigger.init-rescan
#

View File

@ -0,0 +1,472 @@
# A quick guide to configuring OwnTone:
#
# For regular use, the most important setting to configure is "directories",
# which should be the location of your media. Whatever user you have set as
# "uid" must have read access to this location. If the location is a network
# mount, please see the README.
#
# In all likelihood, that's all you need to do!
general {
# Username
# Make sure the user has read access to the library directories you set
# below, and full access to the databases, log and local audio
uid = "owntone"
db_path = "/config/dbase_and_logs/songs3.db"
# Database backup location
# Uncomment and specify a full path to enable abilty to use REST endpoint
# to initiate backup of songs3.db
#db_backup_path = "/var/cache/owntone/songs3.bak"
# Log file and level
# Available levels: fatal, log, warning, info, debug, spam
logfile = "/log/owntone.log"
loglevel = log
# Admin password for the web interface
# Note that access to the web interface from computers in
# "trusted_network" (see below) does not require password
admin_password = "{{ owntone_admin_pass }}"
# Websocket port for the web interface.
websocket_port = {{ owntone_port_ws }}
# Websocket interface to bind listener to (e.g. "eth0"). Default is
# disabled, which means listen on all interfaces.
websocket_interface = "{{ owntone_interface }}"
# Sets who is allowed to connect without authorisation. This applies to
# client types like Remotes, DAAP clients (iTunes) and to the web
# interface. Options are "any", "localhost" or the prefix to one or
# more ipv4/6 networks. The default is { "localhost", "192.168", "fd" }
{% set s21 = s21_cidr.split(".")[:3] | join(".") -%}
trusted_networks = { "localhost", "{{ s21 }}", "fd" }
# Enable/disable IPv6
ipv6 = no
# Set this if you want the server to bind to a specific IP address. Can
# be ipv6 or ipv4. Default (commented out or "::") is to listen on all
# IP addresses.
#bind_address = "{{ owntone_interface }}"
# Location of cache database
cache_path = "/config/dbase_and_logs/cache.db"
# DAAP requests that take longer than this threshold (in msec) get their
# replies cached for next time. Set to 0 to disable caching.
#cache_daap_threshold = 1000
# When starting playback, autoselect speaker (if none of the previously
# selected speakers/outputs are available)
#speaker_autoselect = no
# Most modern systems have a high-resolution clock, but if you are on an
# unusual platform and experience audio drop-outs, you can try changing
# this option
#high_resolution_clock = yes
}
# Library configuration
library {
# Name of the library as displayed by the clients (%h: hostname). If you
# change the name after pairing with Remote you may have to re-pair.
name = "{{ owntone_url }}"
# TCP port to listen on. Default port is 3689 (daap)
port = {{ owntone_port_tcp }}
# Password for the library. Optional.
#password = "{{ owntone_library_pass }}"
# Directories to index
directories = { "/audio" }
# Follow symlinks. Default: true.
#follow_symlinks = true
# Directories containing podcasts
# For each directory that is indexed the path is matched against these
# names. If there is a match all items in the directory are marked as
# podcasts. Eg. if you index /music, and your podcasts are in
# /music/Podcasts, you can set this to "/Podcasts".
# (changing this setting only takes effect after rescan, see the README)
podcasts = { "/podcasts" }
# Directories containing audiobooks
# For each directory that is indexed the path is matched against these
# names. If there is a match all items in the directory are marked as
# audiobooks.
# (changing this setting only takes effect after rescan, see the README)
audiobooks = { "/audiobooks" }
# Directories containing compilations (eg soundtracks)
# For each directory that is indexed the path is matched against these
# names. If there is a match all items in the directory are marked as
# compilations.
# (changing this setting only takes effect after rescan, see the README)
compilations = { "/compilations" }
# Compilations usually have many artists, and sometimes no album artist.
# If you dont want every artist to be listed in artist views, you can
# set a single name which will be used for all compilation tracks
# without an album artist, and for all tracks in the compilation
# directories.
# (changing this setting only takes effect after rescan, see the README)
compilation_artist = "Various Artists"
# If your album and artist lists are cluttered, you can choose to hide
# albums and artists with only one track. The tracks will still be
# visible in other lists, e.g. songs and playlists. This setting
# currently only works in some remotes.
#hide_singles = false
# Internet streams in your playlists will by default be shown in the
# "Radio" library, like iTunes does. However, some clients (like
# TunesRemote+) wont show the "Radio" library. If you would also like
# to have them shown like normal playlists, you can enable this option.
radio_playlists = false
# These are the default playlists. If you want them to have other names,
# you can set it here.
#name_library = "Library"
#name_music = "Music"
#name_movies = "Movies"
#name_tvshows = "TV Shows"
#name_podcasts = "Podcasts"
#name_audiobooks = "Audiobooks"
#name_radio = "Radio"
# Artwork file names (without file type extension)
# OwnTone will look for jpg and png files with these base names
artwork_basenames = { "artwork", "cover", "Folder" }
# Enable searching for artwork corresponding to each individual media
# file instead of only looking for album artwork. This is disabled by
# default to reduce cache size.
artwork_individual = true
# File types the scanner should ignore
# Non-audio files will never be added to the database, but here you
# can prevent the scanner from even probing them. This might improve
# scan time. By default .db, .ini, .db-journal, .pdf and .metadata are
# ignored.
#filetypes_ignore = { ".db", ".ini", ".db-journal", ".pdf", ".metadata" }
# File paths the scanner should ignore
# If you want to exclude files on a more advanced basis you can enter
# one or more POSIX regular expressions, and any file with a matching
# path will be ignored.
#filepath_ignore = { "myregex" }
# Disable startup file scanning
# When OwnTone starts it will do an initial file scan of your
# library (and then watch it for changes). If you are sure your library
# never changes while OwnTone is not running, you can disable the
# initial file scan and save some system ressources. Disabling this scan
# may lead to OwnTones database coming out of sync with the
# library. If that happens read the instructions in the README on how
# to trigger a rescan.
#filescan_disable = false
# Should metadata from m3u playlists, e.g. artist and title in EXTINF,
# override the metadata we get from radio streams?
#m3u_overrides = false
# Should iTunes metadata override ours?
itunes_overrides = {{ owntone_itunes_metadata_override | default(false) }}
# Should we import the content of iTunes smart playlists?
#itunes_smartpl = false
# Decoding options for DAAP clients
# Since iTunes has native support for mpeg, mp4a, mp4v, alac and wav,
# such files will be sent as they are. Any other formats will be decoded
# to raw wav. If OwnTone detects a non-iTunes DAAP client, it is
# assumed to only support mpeg and wav, other formats will be decoded.
# Here you can change when to decode. Note that these settings have no
# effect on AirPlay.
# Formats: mp4a, mp4v, mpeg, alac, flac, mpc, ogg, wma, wmal, wmav, aif, wav
# Formats that should never be decoded
#no_decode = { "format", "format" }
# Formats that should always be decoded
#force_decode = { "format", "format" }
# Watch named pipes in the library for data and autostart playback when
# there is data to be read. To exclude specific pipes from watching,
# consider using the above _ignore options.
pipe_autostart = true
# Enable automatic rating updates
# If enabled, rating is automatically updated after a song has either been
# played or skipped (only skipping to the next song is taken into account).
# The calculation is taken from the beets plugin "mpdstats" (see
# https://beets.readthedocs.io/en/latest/plugins/mpdstats.html).
# It consist of calculating a stable rating based only on the play- and
# skipcount and a rolling rating based on the current rating and the action
# (played or skipped). Both results are combined with a mix-factor of 0.75:
# new rating = 0.75 * stable rating + 0.25 * rolling rating)
#rating_updates = false
# Allows creating, deleting and modifying m3u playlists in the library directories.
# Only supported by the player web interface and some mpd clients
# Defaults to being disabled.
allow_modifying_stored_playlists = true
# A directory in one of the library directories that will be used as the default
# playlist directory. OwnTone creates new playlists in this directory if only
# a playlist name is provided (requires "allow_modify_stored_playlists" set to true).
default_playlist_directory = "/audio/playlists"
# By default OwnTone will - like iTunes - clear the playqueue if
# playback stops. Setting clear_queue_on_stop_disable to true will keep
# the playlist like MPD does. Note that some dacp clients do not show
# the playqueue if playback is stopped.
clear_queue_on_stop_disable = true
}
# Local audio output
audio {
# Name - used in the speaker list in Remote
nickname = "Computer"
# Type of the output (alsa, pulseaudio, dummy or disabled)
type = "disabled"
# For pulseaudio output, an optional server hostname or IP can be
# specified (e.g. "localhost"). If not set, connection is made via local
# socket.
#server = ""
# Audio PCM device name for local audio output - ALSA only
#card = "default"
# Mixer channel to use for volume control - ALSA only
# If not set, PCM will be used if available, otherwise Master.
#mixer = ""
# Mixer device to use for volume control - ALSA only
# If not set, the value for "card" will be used.
#mixer_device = ""
# Enable or disable audio resampling to keep local audio in sync with
# e.g. Airplay. This feature relies on accurate ALSA measurements of
# delay, and some devices dont provide that. If that is the case you
# are better off disabling the feature.
#sync_disable = false
# Here you can adjust when local audio is started relative to other
# speakers, e.g. Airplay. Negative values correspond to moving local
# audio ahead, positive correspond to delaying it. The unit is
# milliseconds. The offset must be between -1000 and 1000 (+/- 1 sec).
#offset_ms = 0
# To calculate what and if resampling is required, local audio delay is
# measured each second. After a period the collected measurements are
# used to estimate drift and latency, which determines if corrections
# are required. This setting sets the length of that period in seconds.
#adjust_period_seconds = 100
}
# ALSA device settings
# If you have multiple ALSA devices you can configure them individually via
# sections like the below. Make sure to set the "card name" correctly. See the
# README about ALSA for details. Note that these settings will override the ALSA
# settings in the "audio" section above.
#alsa "card name" {
# Name used in the speaker list. If not set, the card name will be used.
#nickname = "Computer"
# Mixer channel to use for volume control
# If not set, PCM will be used if available, otherwise Master
#mixer = ""
# Mixer device to use for volume control
# If not set, the card name will be used
#mixer_device = ""
# }
# Pipe output
# Allows OwnTone to output audio data to a named pipe
fifo {
nickname = "fifo"
path = "/audio/output.fifo"
}
# AirPlay settings common to all devices
#airplay_shared {
# UDP ports used when airplay devices make connections back to
# OwnTone (choosing specific ports may be helpful when running
# OwnTone behind a firewall)
# control_port = 0
# timing_port = 0
# }
# AirPlay per device settings
# (make sure you get the capitalization of the device name right)
#airplay "My AirPlay device" {
# OwnTone's volume goes to 11! If that's more than you can handle
# you can set a lower value here
#max_volume = 11
# Enable this option to exclude a particular AirPlay device from the
# speaker list
#exclude = false
# Enable this option to keep a particular AirPlay device in the speaker
# list and thus ignore mdns notifications about it no longer being
# present. The speaker will remain until restart of OwnTone.
#permanent = false
# Some devices spuriously disconnect during playback, and based on the
# device type OwnTone may attempt to reconnect. Setting this option
# overrides this so reconnecting is either always enabled or disabled.
#reconnect = false
# AirPlay password
#password = "s1kr3t"
# Disable AirPlay 1 (RAOP)
#raop_disable = false
# Name used in the speaker list, overrides name from the device
#nickname = "My speaker name"
# }
{% for item in owntone_airplay -%}
{% if item.exclude|default(false) -%}
# Excluded AirPlay device: {{ item.name }}
{% endif %}
airplay "{{ item.name }}" {
{% if 'nickname' in item -%}
nickname = "{{ item.nickname }}"
{% endif -%}
{% if 'password' in item -%}
password = "{{ item.password }}"
{% endif -%}
{% if 'max_volume' in item -%}
max_volume = {{ item.max_volume }}
{% endif -%}
exclude = {{ item.exclude|default(false) | lower }}
permanent = {{ item.permanent|default(false) | lower }}
reconnect = {{ item.reconnect|default(false) | lower }}
}
{% endfor %}
# Chromecast settings
# (make sure you get the capitalization of the device name right)
#chromecast "My Chromecast device" {
# OwnTone's volume goes to 11! If that's more than you can handle
# you can set a lower value here
#max_volume = 11
# Enable this option to exclude a particular device from the speaker
# list
#exclude = false
# Name used in the speaker list, overrides name from the device
#nickname = "My speaker name"
# }
# Spotify settings (only have effect if Spotify enabled - see README/INSTALL)
spotify {
# Set preferred bitrate for music streaming
# 0: No preference (default), 1: 96kbps, 2: 160kbps, 3: 320kbps
bitrate = 3
# Your Spotify playlists will by default be put in a "Spotify" playlist
# folder. If you would rather have them together with your other
# playlists you can set this option to true.
base_playlist_disable = true
# Spotify playlists usually have many artist, and if you dont want
# every artist to be listed when artist browsing in Remote, you can set
# the artist_override flag to true. This will use the compilation_artist
# as album artist for Spotify items.
artist_override = true
# Similar to the different artists in Spotify playlists, the playlist
# items belong to different albums, and if you do not want every album
# to be listed when browsing in Remote, you can set the album_override
# flag to true. This will use the playlist name as album name for
# Spotify items. Notice that if an item is in more than one playlist,
# it will only appear in one album when browsing (in which album is
# random).
album_override = true
}
# RCP/Roku Soundbridge output settings
# (make sure you get the capitalization of the device name right)
#rcp "My SoundBridge device" {
# Enable this option to exclude a particular device from the speaker
# list
#exclude = false
# A Roku/SoundBridge can power up in 2 modes: (default) reconnect to the
# previously used library (ie OwnTone) or in a 'cleared library' mode.
# The Roku power up behaviour is affected by how OwnTone disconnects
# from the Roku device.
#
# Set to false to maintain default Roku power on behaviour
#clear_on_close = false
# }
# MPD configuration (only have effect if MPD enabled - see README/INSTALL)
mpd {
# TCP port to listen on for MPD client requests.
# Default port is 6600, set to 0 to disable MPD support.
port = {{ owntone_port_mpd|default('6600') }}
# HTTP port to listen for artwork requests (only supported by some MPD
# clients and will need additional configuration in the MPD client to
# work). Set to 0 to disable serving artwork over http.
#http_port = 0
}
# SQLite configuration (allows to modify the operation of the SQLite databases)
# Make sure to read the SQLite documentation for the corresponding PRAGMA
# statements as changing them from the defaults may increase the possibility of
# database corruptions! By default the SQLite default values are used.
sqlite {
# Cache size in number of db pages for the library database
# (SQLite default page size is 1024 bytes and cache size is 2000 pages)
#pragma_cache_size_library = 2000
# Cache size in number of db pages for the daap cache database
# (SQLite default page size is 1024 bytes and cache size is 2000 pages)
#pragma_cache_size_cache = 2000
# Sets the journal mode for the database
# DELETE (default), TRUNCATE, PERSIST, MEMORY, WAL, OFF
#pragma_journal_mode = DELETE
# Change the setting of the "synchronous" flag
# 0: OFF, 1: NORMAL, 2: FULL (default)
#pragma_synchronous = 2
# Number of bytes set aside for memory-mapped I/O for the library database
# (requires sqlite 3.7.17 or later)
# 0: disables mmap (default), any other value > 0: number of bytes for mmap
#pragma_mmap_size_library = 0
# Number of bytes set aside for memory-mapped I/O for the cache database
# (requires sqlite 3.7.17 or later)
# 0: disables mmap (default), any other value > 0: number of bytes for mmap
#pragma_mmap_size_cache = 0
# Should the database be vacuumed on startup? (increases startup time,
# but may reduce database size). Default is yes.
#vacuum = yes
}
# Streaming audio settings for remote connections (ie stream.mp3)
streaming {
# Sample rate, typically 44100 or 48000
#sample_rate = 44100
# Set the MP3 streaming bit rate (in kbps), valid options: 64 / 96 / 128 / 192 / 320
bit_rate = 320
}

View File

@ -1,7 +1 @@
---
dependencies:
- mariadb
- zflux
- sudoisbot
- hass

View File

@ -56,6 +56,191 @@
when: dht_builder|default(False)
tags: dht
# https://bluedot.readthedocs.io/en/latest/pairpipi.html#using-the-command-line
#
# $ sudo bluetoothctl
# [bluetooth]# discoverable on
# Changing discoverable on succeeded
# [bluetooth]# pairable on
# Changing pairable on succeeded
# [bluetooth]# agent on
# Agent is already registered
# [bluetooth]# default-agent
# Default agent request successful
# [bluetooth]# scan on
# [bluetooth]# pair EA:26:7D:4A:ED:E4
# 0a-11e5-a837-0800200c9a66
# Vendor specific
# [NEW] Descriptor
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0009/char000d/desc000f
# 00002901-0000-1000-8000-00805f9b34fb
# Characteristic User Description
# [NEW] Descriptor
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0009/char000d/desc0010
# 00002902-0000-1000-8000-00805f9b34fb
# Client Characteristic Configuration
# [NEW] Characteristic
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0009/char0011
# e6807d23-b90a-11e5-a837-0800200c9a66
# Vendor specific
# [NEW] Descriptor
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0009/char0011/desc0013
# 00002901-0000-1000-8000-00805f9b34fb
# Characteristic User Description
# [NEW] Characteristic
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0009/char0014
# e6807d24-b90a-11e5-a837-0800200c9a66
# Vendor specific
# [NEW] Descriptor
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0009/char0014/desc0016
# 00002901-0000-1000-8000-00805f9b34fb
# Characteristic User Description
# [NEW] Descriptor
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0009/char0014/desc0017
# 00002902-0000-1000-8000-00805f9b34fb
# Client Characteristic Configuration
# [NEW] Characteristic
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0009/char0018
# e6807d25-b90a-11e5-a837-0800200c9a66
# Vendor specific
# [NEW] Descriptor
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0009/char0018/desc001a
# 00002901-0000-1000-8000-00805f9b34fb
# Characteristic User Description
# [NEW] Characteristic
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0009/char001b
# e6807d26-b90a-11e5-a837-0800200c9a66
# Vendor specific
# [NEW] Descriptor
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0009/char001b/desc001d
# 00002901-0000-1000-8000-00805f9b34fb
# Characteristic User Description
# [NEW] Characteristic
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0009/char001e
# e6807d27-b90a-11e5-a837-0800200c9a66
# Vendor specific
# [NEW] Descriptor
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0009/char001e/desc0020
# 00002901-0000-1000-8000-00805f9b34fb
# Characteristic User Description
# [NEW] Characteristic
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0009/char0021
# e6807e20-b90a-11e5-a837-0800200c9a66
# Vendor specific
# [NEW] Descriptor
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0009/char0021/desc0023
# 00002901-0000-1000-8000-00805f9b34fb
# Characteristic User Description
# [NEW] Descriptor
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0009/char0021/desc0024
# 00002902-0000-1000-8000-00805f9b34fb
# Client Characteristic Configuration
# [NEW] Characteristic
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0009/char0025
# e6807e21-b90a-11e5-a837-0800200c9a66
# Vendor specific
# [NEW] Descriptor
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0009/char0025/desc0027
# 00002901-0000-1000-8000-00805f9b34fb
# Characteristic User Description
# [NEW] Characteristic
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0009/char0028
# e6807e24-b90a-11e5-a837-0800200c9a66
# Vendor specific
# [NEW] Descriptor
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0009/char0028/desc002a
# 00002901-0000-1000-8000-00805f9b34fb
# Characteristic User Description
# [NEW] Descriptor
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0009/char0028/desc002b
# 00002902-0000-1000-8000-00805f9b34fb
# Client Characteristic Configuration
# [NEW] Characteristic
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0009/char002c
# e6807e25-b90a-11e5-a837-0800200c9a66
# Vendor specific
# [NEW] Descriptor
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0009/char002c/desc002e
# 00002901-0000-1000-8000-00805f9b34fb
# Characteristic User Description
# [NEW] Primary Service
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service002f
# 0000181a-0000-1000-8000-00805f9b34fb
# Environmental Sensing
# [NEW] Characteristic
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service002f/char0030
# 00002a6e-0000-1000-8000-00805f9b34fb
# Temperature
# [NEW] Descriptor
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service002f/char0030/desc0032
# 00002901-0000-1000-8000-00805f9b34fb
# Characteristic User Description
# [NEW] Descriptor
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service002f/char0030/desc0033
# 00002902-0000-1000-8000-00805f9b34fb
# Client Characteristic Configuration
# [NEW] Characteristic
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service002f/char0034
# 00002a6f-0000-1000-8000-00805f9b34fb
# Humidity
# [NEW] Descriptor
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service002f/char0034/desc0036
# 00002901-0000-1000-8000-00805f9b34fb
# Characteristic User Description
# [NEW] Descriptor
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service002f/char0034/desc0037
# 00002902-0000-1000-8000-00805f9b34fb
# Client Characteristic Configuration
# [NEW] Primary Service
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0038
# 0000180a-0000-1000-8000-00805f9b34fb
# Device Information
# [NEW] Characteristic
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0038/char0039
# 00002a29-0000-1000-8000-00805f9b34fb
# Manufacturer Name String
# [NEW] Characteristic
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0038/char003b
# 00002a24-0000-1000-8000-00805f9b34fb
# Model Number String
# [NEW] Characteristic
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0038/char003d
# 00002a25-0000-1000-8000-00805f9b34fb
# Serial Number String
# [NEW] Characteristic
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0038/char003f
# 00002a27-0000-1000-8000-00805f9b34fb
# Hardware Revision String
# [NEW] Characteristic
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0038/char0041
# 00002a26-0000-1000-8000-00805f9b34fb
# Firmware Revision String
# [NEW] Characteristic
# /org/bluez/hci0/dev_EA_26_7D_4A_ED_E4/service0038/char0043
# 00002a28-0000-1000-8000-00805f9b34fb
# Software Revision String
# [CHG] Device EA:26:7D:4A:ED:E4 UUIDs: 00001800-0000-1000-8000-00805f9b34fb
# [CHG] Device EA:26:7D:4A:ED:E4 UUIDs: 00001801-0000-1000-8000-00805f9b34fb
# [CHG] Device EA:26:7D:4A:ED:E4 UUIDs: 0000180a-0000-1000-8000-00805f9b34fb
# [CHG] Device EA:26:7D:4A:ED:E4 UUIDs: 0000181a-0000-1000-8000-00805f9b34fb
# [CHG] Device EA:26:7D:4A:ED:E4 UUIDs: e6807d20-b90a-11e5-a837-0800200c9a66
# [CHG] Device EA:26:7D:4A:ED:E4 ServicesResolved: yes
# [CHG] Device EA:26:7D:4A:ED:E4 Appearance: 0x03c0
# [CHG] Device EA:26:7D:4A:ED:E4 Paired: yes
# Pairing successful
# [Beddit 2564]# quit
- name: set up bluetooth
apt:
name:
- pi-bluetooth
- bluez
- libgirepository1.0-dev
# - bluez-utils
# - bluetooth
# - blueman
when: bluetooth_enabled | default(false)
tags: bluetooth
- name: install fpm with gem
gem:
name: fpm

View File

@ -0,0 +1,5 @@
---
dependencies:
- mariadb
- zflux

View File

@ -14,7 +14,7 @@
vars:
prediff_cmd: echo
with_items:
- "{{ unifi_url }}"
- "{{ domain }}"
- name: template nginx vhost
template:
@ -61,10 +61,13 @@
# v6.5.55
# v6.0.45
# v5.14.23
#
# updated: v5.14.23 -> stable-5 -> stable-6 -> latest (v7)
- name: start docker container
docker_container:
name: "unifi"
image: "jacobalberty/unifi:v5.14.23"
#image: "jacobalberty/unifi:v5.14.23"
image: jacobalberty/unifi:latest
Review

v5 was better

v5 was better
auto_remove: false
detach: true
restart_policy: "unless-stopped"
@ -86,8 +89,9 @@
- "8080:8080/tcp" # Device/ controller comm.
- "127.0.0.1:8443:8443/tcp" # Controller GUI/API as seen in a web browser
- "10001:10001/udp" # AP discovery
dns_servers:
- "{{ ansible_docker0.ipv4.address }}"
tags:
- unifi-container
- docker-containers
- name: wait for controller to be responsive

View File

@ -15,6 +15,15 @@ server {
proxy_set_header Host $host;
}
location /inform {
proxy_pass http://localhost:8080;
proxy_redirect off;
proxy_set_header Host $host;
}
location / {
proxy_pass https://localhost:8443/;
@ -32,8 +41,8 @@ server {
ssl_session_timeout 5m;
ssl_certificate /usr/local/etc/certs/{{ unifi_url }}/fullchain.pem;
ssl_certificate_key /usr/local/etc/certs/{{ unifi_url }}/privkey.pem;
ssl_certificate /usr/local/etc/certs/{{ domain }}/fullchain.pem;
ssl_certificate_key /usr/local/etc/certs/{{ domain }}/privkey.pem;
add_header Referrer-Policy "no-referrer" always;
add_header X-Content-Type-Options "nosniff" always;

View File

@ -1,8 +1,26 @@
server {
server_name {%- for d in server_names %} {{ d }}{% endfor %};
{% if inventory_hostname in wg_clients -%}
listen {{ wg_clients[inventory_hostname].ip }}:443 ssl http2;
{% endif -%}
listen 443 ssl http2;
include listen-proxy-protocol.conf;
ssl_certificate /usr/local/etc/certs/www.{{ domain }}/fullchain.pem;
ssl_certificate_key /usr/local/etc/certs/www.{{ domain }}/privkey.pem;
location / {
return 301 https://www.$http_host$request_uri;
}
access_log /var/log/nginx/access_{{ domain }}.log main;
error_log /var/log/nginx/error_{{ domain }}.log warn;
}
server {
server_name {%- for d in server_names %} www.{{ d }} {{ d }}{% endfor %};
server_name {%- for d in server_names %} www.{{ d }}{% endfor %};
{% if inventory_hostname in wg_clients -%}
listen {{ wg_clients[inventory_hostname].ip }}:443 ssl http2;