From f70e9e83f8c13ec60641491cc3d5e50f3116ff18 Mon Sep 17 00:00:00 2001 From: oddlama Date: Wed, 29 Jan 2025 00:55:42 +0100 Subject: [PATCH] feat: add mennekes modbus, add influxdb for hass --- hosts/sausebiene/default.nix | 1 + .../hass-modbus/mennekes-amtron-xtra.nix | 268 ++++++++++++++++++ hosts/sausebiene/home-assistant.nix | 45 +-- hosts/sausebiene/influxdb.nix | 62 ++++ hosts/sausebiene/net.nix | 5 +- hosts/sausebiene/wyoming.nix | 3 - hosts/sire/guests/influxdb.nix | 13 +- .../sausebiene/influxdb-admin-password.age | 10 + .../sausebiene/influxdb-admin-token.age | 9 + .../generated/sentinel/plausible-admin-pw.age | 9 - .../influxdb-user-telegraf-token.age | 11 - ...fc8b8bdbaa0907-influxdb-admin-password.age | Bin 0 -> 346 bytes ...2cc652fd78483beb0-influxdb-admin-token.age | Bin 0 -> 409 bytes ...b67e345542aee86292f-plausible-admin-pw.age | 8 - ...57fccb699-influxdb-user-telegraf-token.age | 8 - 15 files changed, 367 insertions(+), 85 deletions(-) create mode 100644 hosts/sausebiene/hass-modbus/mennekes-amtron-xtra.nix create mode 100644 hosts/sausebiene/influxdb.nix create mode 100644 secrets/generated/sausebiene/influxdb-admin-password.age create mode 100644 secrets/generated/sausebiene/influxdb-admin-token.age delete mode 100644 secrets/generated/sentinel/plausible-admin-pw.age delete mode 100644 secrets/generated/sire-influxdb/influxdb-user-telegraf-token.age create mode 100644 secrets/rekeyed/sausebiene/4c71b3633219d83e3dfc8b8bdbaa0907-influxdb-admin-password.age create mode 100644 secrets/rekeyed/sausebiene/e2faf6f3896127b2cc652fd78483beb0-influxdb-admin-token.age delete mode 100644 secrets/rekeyed/sentinel/717d95da48eecb67e345542aee86292f-plausible-admin-pw.age delete mode 100644 secrets/rekeyed/sire-influxdb/c55bd55405c20bf836ad79657fccb699-influxdb-user-telegraf-token.age diff --git a/hosts/sausebiene/default.nix b/hosts/sausebiene/default.nix index 6087f10..706cea6 100644 --- a/hosts/sausebiene/default.nix +++ b/hosts/sausebiene/default.nix @@ -22,6 +22,7 @@ ./esphome.nix ./home-assistant.nix + ./influxdb.nix ./mosquitto.nix ./wyoming.nix ]; diff --git a/hosts/sausebiene/hass-modbus/mennekes-amtron-xtra.nix b/hosts/sausebiene/hass-modbus/mennekes-amtron-xtra.nix new file mode 100644 index 0000000..8e29b9e --- /dev/null +++ b/hosts/sausebiene/hass-modbus/mennekes-amtron-xtra.nix @@ -0,0 +1,268 @@ +{ globals, ... }: +{ + services.home-assistant.config = { + recorder.exclude.entities = [ "sensor.amtron_registers" ]; + logbook.exclude.entities = [ "sensor.amtron_registers" ]; + influxdb.exclude.entities = [ "sensor.amtron_registers" ]; + + modbus = [ + { + delay = 1; + host = globals.net.home-lan.vlans.devices.hosts.wallbox.ipv4; + name = "Amtron Xtra 22 C2"; + port = 502; + retries = 1; + retry_on_empty = true; + sensors = [ + { + address = 768; + count = 38; + data_type = "custom"; + input_type = "input"; + lazy_error_count = 1; + name = "Amtron Registers"; + precision = 0; + scan_interval = 120; + slave = 255; + structure = ">2h15H22B10H"; + } + { + address = 1024; + count = 1; + data_type = "uint16"; + device_class = "current"; + input_type = "holding"; + name = "Amtron Current Limitation"; + slave = 255; + unique_id = "amtron_current_limitation"; + unit_of_measurement = "A"; + } + { + address = 1025; + count = 1; + data_type = "uint16"; + input_type = "holding"; + name = "Amtron Change Charge State"; + slave = 255; + unique_id = "amtron_change_charge_state"; + } + ]; + timeout = 10; + type = "tcp"; + } + ]; + template = [ + { + sensor = [ + { + availability = "{{ has_value('sensor.amtron_registers') }}"; + device_class = "temperature"; + name = "Amtron HMI Temp Internal"; + state = "{{ states('sensor.amtron_registers').split(',')[0] }}"; + state_class = "measurement"; + unique_id = "amtron_hmi_temp_int"; + unit_of_measurement = "°C"; + } + ]; + } + { + sensor = [ + { + availability = "{{ has_value('sensor.amtron_registers') }}"; + device_class = "temperature"; + name = "Amtron HMI Temp External"; + state = "{{ states('sensor.amtron_registers').split(',')[1] }}"; + state_class = "measurement"; + unique_id = "amtron_hmi_temp_ext"; + unit_of_measurement = "°C"; + } + ]; + } + { + sensor = [ + { + availability = "{{ has_value('sensor.amtron_registers') }}"; + name = "Amtron CP State"; + state = '' + {% set mapper = { + '0' : 'illegal/bad', + '1' : 'A1 - Not connected', + '2' : 'A2 - Not connected', + '3' : 'B1 - Connected', + '4' : 'B2 - Connected', + '5' : 'C1 - Charging', + '6' : 'C2 - Charging', + '7' : 'D1 - Charging with Ventilation', + '8' : 'D2 - Charging with Ventilation' } %} + {% set state = states('sensor.amtron_registers').split(',')[2] %} + {{ mapper[state] if state in mapper else 'Unknown' }} + ''; + unique_id = "amtron_cp_state"; + } + ]; + } + { + sensor = [ + { + availability = "{{ has_value('sensor.amtron_registers') }}"; + name = "Amtron PP State"; + state = '' + {% set mapper = { + '0' : 'illegal/bad', + '1' : 'Open', + '2' : '13A', + '3' : '20A', + '4' : '32A' } %} + {% set state = states('sensor.amtron_registers').split(',')[3] %} + {{ mapper[state] if state in mapper else 'Unknown' }} + ''; + unique_id = "amtron_pp_state"; + } + ]; + } + { + sensor = [ + { + availability = "{{ has_value('sensor.amtron_registers') }}"; + name = "Amtron State"; + state = '' + {% set mapper = { + '0' : 'Idle', + '1' : 'Standby Authorize', + '2' : 'Standby Connect', + '3' : 'Charging', + '4' : 'Paused', + '5' : 'Terminated', + '6' : 'Error' } %} + {% set state = states('sensor.amtron_registers').split(',')[5] %} + {{ mapper[state] if state in mapper else 'Unknown' }} + ''; + unique_id = "amtron_state"; + } + ]; + } + { + sensor = [ + { + availability = "{{ has_value('sensor.amtron_registers') }}"; + name = "Amtron Phases"; + state = '' + {% set mapper = { + '0' : 'Unknown', + '1' : '1 Phase', + '3' : '3 Phases' } %} + {% set state = states('sensor.amtron_registers').split(',')[8] %} + {{ mapper[state] if state in mapper else 'Unknown' }} + ''; + unique_id = "amtron_phases"; + } + ]; + } + { + sensor = [ + { + availability = "{{ has_value('sensor.amtron_registers') }}"; + device_class = "current"; + name = "Amtron Rated Current"; + state = "{{ states('sensor.amtron_registers').split(',')[9] }}"; + state_class = "measurement"; + unique_id = "amtron_rated_current"; + unit_of_measurement = "A"; + } + ]; + } + { + sensor = [ + { + availability = "{{ has_value('sensor.amtron_registers') }}"; + device_class = "current"; + name = "Amtron Installation Current"; + state = "{{ states('sensor.amtron_registers').split(',')[10] }}"; + state_class = "measurement"; + unique_id = "amtron_installation_current"; + unit_of_measurement = "A"; + } + ]; + } + { + sensor = [ + { + availability = "{{ has_value('sensor.amtron_registers') }}"; + name = "Amtron Serial Number"; + state = "{% set sn = (states('sensor.amtron_registers').split(',')[11]|int + states('sensor.amtron_registers').split(',')[12]|int * 65536) | string %} 135{{ sn[:4] }}.{{ sn[4:] }}"; + unique_id = "amtron_serial_number"; + } + ]; + } + { + sensor = [ + { + availability = "{{ has_value('sensor.amtron_registers') }}"; + device_class = "energy"; + name = "Amtron Energy"; + state = "{{ states('sensor.amtron_registers').split(',')[13]|int + states('sensor.amtron_registers').split(',')[14]|int * 65536 }}"; + state_class = "total_increasing"; + unique_id = "amtron_energy"; + unit_of_measurement = "Wh"; + } + ]; + } + { + sensor = [ + { + availability = "{{ has_value('sensor.amtron_registers') }}"; + device_class = "power"; + name = "Amtron Power"; + state = "{{ states('sensor.amtron_registers').split(',')[15]|int + states('sensor.amtron_registers').split(',')[16]|int * 65536 }}"; + state_class = "measurement"; + unique_id = "amtron_power"; + unit_of_measurement = "W"; + } + ]; + } + { + sensor = [ + { + availability = "{{ has_value('sensor.amtron_registers') }}"; + name = "Amtron Wallbox Name"; + state = '' + {% set ns = namespace(name = ''') -%} + {% set input = states('sensor.amtron_registers').split(',')[17:40] -%} + {% for i in range(0,11) -%} + {% set ns.name = ns.name ~ \"%c\"%input[i*2+1]|int ~ \"%c\"%input[i*2]|int -%} + {% endfor %} + {{ ns.name.replace('\\x00',''') }} + ''; + unique_id = "amtron_wallbox_name"; + } + ]; + } + { + sensor = [ + { + availability = "{{ has_value('sensor.amtron_registers') }}"; + device_class = "current"; + name = "Amtron Max Current T1"; + state = "{{ states('sensor.amtron_registers').split(',')[40] }}"; + state_class = "measurement"; + unique_id = "amtron_max_current_t1"; + unit_of_measurement = "A"; + } + ]; + } + { + sensor = [ + { + availability = "{{ has_value('sensor.amtron_registers') }}"; + device_class = "current"; + name = "Amtron Max Current T2"; + state = "{{ states('sensor.amtron_registers').split(',')[44] }}"; + state_class = "measurement"; + unique_id = "amtron_max_current_t2"; + unit_of_measurement = "A"; + } + ]; + } + ]; + }; +} diff --git a/hosts/sausebiene/home-assistant.nix b/hosts/sausebiene/home-assistant.nix index a79e2fa..dc1fc23 100644 --- a/hosts/sausebiene/home-assistant.nix +++ b/hosts/sausebiene/home-assistant.nix @@ -11,6 +11,8 @@ let fritzboxDomain = "fritzbox.${globals.domains.personal}"; in { + imports = [ ./hass-modbus/mennekes-amtron-xtra.nix ]; + wireguard.proxy-home.firewallRuleForNode.ward-web-proxy.allowedTCPPorts = [ config.services.home-assistant.config.http.server_port ]; @@ -105,17 +107,17 @@ in }; "automation ui" = "!include automations.yaml"; - # influxdb = { - # api_version = 2; - # host = globals.services.influxdb.domain; - # port = "443"; - # max_retries = 10; - # ssl = true; - # verify_ssl = true; - # token = "!secret influxdb_token"; - # organization = "home"; - # bucket = "home_assistant"; - # }; + influxdb = { + api_version = 2; + host = "localhost"; + port = "8086"; + max_retries = 10; + ssl = false; + verify_ssl = false; + token = "!secret influxdb_token"; + organization = "home"; + bucket = "hass"; + }; }; extraPackages = @@ -155,27 +157,6 @@ in ''; }; - age.secrets.hass-influxdb-token = { - generator.script = "alnum"; - mode = "440"; - group = "hass"; - }; - - # nodes.sire-influxdb = { - # # Mirror the original secret on the influx host - # age.secrets."hass-influxdb-token-${config.node.name}" = { - # inherit (config.age.secrets.hass-influxdb-token) rekeyFile; - # mode = "440"; - # group = "influxdb2"; - # }; - # - # services.influxdb2.provision.organizations.home.auths."home-assistant (${config.node.name})" = { - # readBuckets = [ "home_assistant" ]; - # writeBuckets = [ "home_assistant" ]; - # tokenFile = nodes.sire-influxdb.config.age.secrets."hass-influxdb-token-${config.node.name}".path; - # }; - # }; - # Connect to fritzbox via https proxy (to ensure valid cert) networking.hosts.${globals.net.home-lan.vlans.services.hosts.ward-web-proxy.ipv4} = [ fritzboxDomain diff --git a/hosts/sausebiene/influxdb.nix b/hosts/sausebiene/influxdb.nix new file mode 100644 index 0000000..fa006d4 --- /dev/null +++ b/hosts/sausebiene/influxdb.nix @@ -0,0 +1,62 @@ +{ + config, + pkgs, + ... +}: +{ + age.secrets.influxdb-admin-password = { + generator.script = "alnum"; + mode = "440"; + group = "influxdb2"; + }; + + age.secrets.influxdb-admin-token = { + generator.script = "alnum"; + mode = "440"; + group = "influxdb2"; + }; + + age.secrets.hass-influxdb-token = { + generator.script = "alnum"; + mode = "440"; + group = "hass"; + }; + + environment.persistence."/persist".directories = [ + { + directory = "/var/lib/influxdb2"; + user = "influxdb2"; + group = "influxdb2"; + mode = "0700"; + } + ]; + + environment.systemPackages = [ pkgs.influxdb2-cli ]; + + services.influxdb2 = { + enable = true; + settings = { + reporting-disabled = true; + http-bind-address = "127.0.0.1:8086"; + }; + provision = { + enable = true; + initialSetup = { + organization = "default"; + bucket = "default"; + passwordFile = config.age.secrets.influxdb-admin-password.path; + tokenFile = config.age.secrets.influxdb-admin-token.path; + }; + organizations.home = { + buckets.hass = { }; + auths.home-assistant = { + readBuckets = [ "hass" ]; + writeBuckets = [ "hass" ]; + tokenFile = config.age.secrets.hass-influxdb-token.path; + }; + }; + }; + }; + + systemd.services.influxdb2.serviceConfig.RestartSec = "60"; # Retry every minute +} diff --git a/hosts/sausebiene/net.nix b/hosts/sausebiene/net.nix index 53f50fa..2c5e8c3 100644 --- a/hosts/sausebiene/net.nix +++ b/hosts/sausebiene/net.nix @@ -5,9 +5,7 @@ ... }: let - localVlans = lib.genAttrs [ "services" "home" "devices" "iot" ] ( - x: globals.net.home-lan.vlans.${x} - ); + localVlans = lib.genAttrs [ "services" "devices" "iot" ] (x: globals.net.home-lan.vlans.${x}); in { networking.hostId = config.repo.secrets.local.networking.hostId; @@ -109,7 +107,6 @@ in # Allow devices to be discovered through various protocols discovery-protocols = { from = [ - "vlan-home" "vlan-devices" "vlan-iot" ]; diff --git a/hosts/sausebiene/wyoming.nix b/hosts/sausebiene/wyoming.nix index 54aca81..7c254fb 100644 --- a/hosts/sausebiene/wyoming.nix +++ b/hosts/sausebiene/wyoming.nix @@ -34,7 +34,4 @@ uri = "tcp://0.0.0.0:10200"; }; }; - - # needs access to /proc/cpuinfo - # systemd.services."wyoming-faster-whisper-en".serviceConfig.ProcSubset = lib.mkForce "all"; } diff --git a/hosts/sire/guests/influxdb.nix b/hosts/sire/guests/influxdb.nix index 929be04..b41b356 100644 --- a/hosts/sire/guests/influxdb.nix +++ b/hosts/sire/guests/influxdb.nix @@ -146,12 +146,6 @@ in group = "influxdb2"; }; - age.secrets.influxdb-user-telegraf-token = { - generator.script = "alnum"; - mode = "440"; - group = "influxdb2"; - }; - environment.persistence."/persist".directories = [ { directory = "/var/lib/influxdb2"; @@ -161,6 +155,8 @@ in } ]; + environment.systemPackages = [ pkgs.influxdb2-cli ]; + topology.self.services.influxdb2.info = "https://${influxdbDomain}"; services.influxdb2 = { enable = true; @@ -177,11 +173,8 @@ in tokenFile = config.age.secrets.influxdb-admin-token.path; }; organizations.machines.buckets.telegraf = { }; - organizations.home.buckets.home_assistant = { }; }; }; - environment.systemPackages = [ pkgs.influxdb2-cli ]; - - systemd.services.grafana.serviceConfig.RestartSec = "60"; # Retry every minute + systemd.services.influxdb2.serviceConfig.RestartSec = "60"; # Retry every minute } diff --git a/secrets/generated/sausebiene/influxdb-admin-password.age b/secrets/generated/sausebiene/influxdb-admin-password.age new file mode 100644 index 0000000..00d06fe --- /dev/null +++ b/secrets/generated/sausebiene/influxdb-admin-password.age @@ -0,0 +1,10 @@ +age-encryption.org/v1 +-> X25519 L0Slibbkasshnu6268+IP5Z1S5zucQtHPywq378M5U0 +6PwufE9qTbQ8P9wWZiG/TPUYFXNsVF17CBtlwhKWEGM +-> piv-p256 xqSe8Q A8ANRnX2kp7hliMEWEAh8uB2/sHl6wjIxSzFkxYcy2wq ++xt2+l3KwhtO96d8vQ9Z/tU7Jq6nT6k9ZGxfhvzDvds +-> uu>YID-grease +SHoq0PKqu3IxlON4pNDV48A/jEJRMaVPpbDz3eRLdtl+cHGJ72Q6Nz8C5Tv17iHz +SJcfzspkfru8wliyjZmUTERHr/WndOe/vI/VGAUyqyY2Z2WS +--- zKyI+4ZTIbCraJsL9INQezHtEBPdeOuy/B4dEo/S83U +-: !O(_'?zJωoc$ټ# 66_p6]0-2rúu9](@ \ No newline at end of file diff --git a/secrets/generated/sausebiene/influxdb-admin-token.age b/secrets/generated/sausebiene/influxdb-admin-token.age new file mode 100644 index 0000000..069273b --- /dev/null +++ b/secrets/generated/sausebiene/influxdb-admin-token.age @@ -0,0 +1,9 @@ +age-encryption.org/v1 +-> X25519 yg14WqdwsiCCgfqcTBzmx2gvahD9O3NvGCls71TgYzw +QHm7CBFkZSIJFVmxEwCQ3EqkKrRQ/XD2esfyshmm8Ig +-> piv-p256 xqSe8Q A8vqjFbe9FmRjyqYqgKvm12jFG/D9XP9kI7Qeb/W6gQf +eMxnzjlT4HAfvChGl3sottZvU6plmiACV5/a4PUYELI +-> 1wg-grease ?q GR-I F+Z8j#P za +PmRrKLnGU1BjfEVnglQ5Y1IG8RTt1MRfbto +--- 13v6BNcZ9PtFdidHJ2lpbS6dXhYCalVBZsv4BNC9tPc +;A/ūSYoS]^)s'us \ X25519 fa8woWj8FU9qcLWZ6fOxynA9Vebs4/I8iZJnUl/Xoio -NQC2aFU7ndVhcpKURoxW5pPg7rVHdsg42Ufqmn7IKFo --> piv-p256 xqSe8Q AutAPD4hFrfIsxyaUWmHmgIK2fyZvz6UeQIA56T+3y8H -HDiljHzGE3SV+zSI940OledXsGHh2cDGHqSTQ0Y3Kb4 --> 5lL{0#F-grease -FD5Q1N/RDC5c5uRaeQkfHUY ---- f/FxUfcp0gWHkUD8PyxGcchvUXvGdxKzVOw7HFEtnwU -eŘ%aϭ^9UeBc""n !9Nsn'oMEU*Ou޻ZWg|q \ No newline at end of file diff --git a/secrets/generated/sire-influxdb/influxdb-user-telegraf-token.age b/secrets/generated/sire-influxdb/influxdb-user-telegraf-token.age deleted file mode 100644 index 59d5194..0000000 --- a/secrets/generated/sire-influxdb/influxdb-user-telegraf-token.age +++ /dev/null @@ -1,11 +0,0 @@ -age-encryption.org/v1 --> X25519 UVjRIOF/JleFoikw5mhFDBupd63tKBDOvH28PgKqJio -cWcJiS46EVIMUZ7wOySl4V+8QRV+S/E2VbGRrw0S3/k --> piv-p256 xqSe8Q AjVc3tTad3j2Cs+Ka/sIciuuNfodySCyQbeZcsm4mueD -Ju2CdnTIqUtSA7ovH1lCTvUqNvDQGKdcPJ27hPIJgFA --> Y2R4/&~-grease 2s k%BM2z?%w tb' )9%BFcyB{wD>rauGE_lROF>C9d1zTnZ&EN}b4WpDOhigCcufj6c`GwFG(%Kn zb~$rVM@=+oc`##IMnX(TcvE+1NjYd#VQX`5QfzB6QAr9dJ|KQyEoX9NVRL05R98Vg zW@#WiYI;*3TwX(UO*KObaC1abV?;PtOJQ$0R5o}=W@SuaWMyqkT5EM^c4KpDFLp_I zQ!!Fxa&b&TS#Nn|cyntCEiEk|ay4XkIcj%VN;Xh7bx~M&G-5SbMrSWqVrxrFXjoD- zOL|#nIAv^fR#9&X4a7dM(J@uA&}cY6RjUY>$XqLB7hI36h$|^MqRdpZUVRYq%OVI6 s6aOQM+;JwvB531F2e;x6M+fBkij%JZ@@sJ|XR8EuRU@Q{K``6D`wsJZZvX%Q literal 0 HcmV?d00001 diff --git a/secrets/rekeyed/sausebiene/e2faf6f3896127b2cc652fd78483beb0-influxdb-admin-token.age b/secrets/rekeyed/sausebiene/e2faf6f3896127b2cc652fd78483beb0-influxdb-admin-token.age new file mode 100644 index 0000000000000000000000000000000000000000..fd1db3a410ae88da43f15d5e255ab8feb8947146 GIT binary patch literal 409 zcmWm7J&V&|003YShck-jDCp2pD6wsF$u$lKZPQ%7YSMfsPD%SV$>sY^dTBa{+;TVH zIXDRpf}n%L;UFT;t{$kjh>PeX;^HVif8cR_fP!=eo4g9M^iBr-&VCO;cUol`pkR&> zM2~9q_+lvetproXGBu}{yGCi$9BgA#yQ&w3X9$7C4sucqDkwY3-nx(I`lM;1IfLf} zJK)*1)Y+a+Fq>cTI1L7=6ZvXj$vHx%PcW$FT1a1kC(GVzvRal@JS;CA71=fzO zDXtr~nUo7*&oMl2h*hMlCSzeuZH4YwCP}f(NJ&gitX_56Kc!r4iZR9K z7`&zzOs&=4ipMlJ ssh-ed25519 yV7lcA Er1Vw7Jhk/D+GnBuhajXvilOF5KMS9t2jBXA6IpTrCA -1tWBxOOJTmojh0E4EK1mEgPqJQE6F3cG48E/Ak1ruGI --> ssh-ed25519 1tdZKQ PdKeUTvJ4uCQMfAUWRtkxJxv6F+i96/ceHReMX9jHzc -wWWaYCQh7bFYMbNJfFhazA4b3aV5TJIslH2w8NEhdVc --> 6]Q&h2o-grease #M%zB~d j|]=P -c20mvFzSqjY5QLQ2hSKZohEwW2961h1fLvca7EyD0vW0NY2xTvSf8UI0Z/El2VQ6 -RnaprZYSpnjpzYJU ---- J2ELFCtlW8K0dNUXUvGn/skBMOI1Yn17xJWDpeDENp0 -yY:l?\f9bHh1}:r'L? Xc[@S)ٙ2wTX$֚qРGE'{Fu E \ No newline at end of file