feat: add mennekes modbus, add influxdb for hass

This commit is contained in:
oddlama 2025-01-29 00:55:42 +01:00
parent 88b02ed0f3
commit f70e9e83f8
No known key found for this signature in database
GPG key ID: 14EFE510775FE39A
15 changed files with 367 additions and 85 deletions

View file

@ -22,6 +22,7 @@
./esphome.nix
./home-assistant.nix
./influxdb.nix
./mosquitto.nix
./wyoming.nix
];

View file

@ -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";
}
];
}
];
};
}

View file

@ -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

View file

@ -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
}

View file

@ -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"
];

View file

@ -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";
}

View file

@ -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
}