Skip to content

Commit

Permalink
Set up auto discovery for Home Assistant
Browse files Browse the repository at this point in the history
  • Loading branch information
infertux committed Dec 7, 2023
1 parent 3fe4c31 commit c8267f3
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 98 deletions.
76 changes: 38 additions & 38 deletions src/growatt.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,67 +21,67 @@ typedef struct __attribute__((aligned(MAX_METRIC_LENGTH * 2))) {
uint8_t address;
char human_name[MAX_METRIC_LENGTH];
char metric_name[MAX_METRIC_LENGTH];
enum { REGISTER_SINGLE, REGISTER_DOUBLE } register_size;
double scale;
char device_class[MAX_METRIC_LENGTH];
char unit[MAX_METRIC_LENGTH];
enum { REGISTER_SINGLE, REGISTER_DOUBLE } register_size;
double scale;
} REGISTER;

const REGISTER holding_registers[] = {
// NOLINTBEGIN(readability-magic-numbers)
{34, "max charging current", "settings_max_charging_amps", REGISTER_SINGLE, 1},
{35, "bulk charging voltage", "settings_bulk_charging_volts", REGISTER_SINGLE, 0.1},
{36, "float charging voltage", "settings_float_charging_volts", REGISTER_SINGLE, 0.1},
{37, "battery voltage switch to utility", "settings_switch_to_utility_volts", REGISTER_SINGLE, 0.1},
{34, "max charging current", "settings_max_charging_amps", "current", "A", REGISTER_SINGLE, 1},
{35, "bulk charging voltage", "settings_bulk_charging_volts", "voltage", "V", REGISTER_SINGLE, 0.1},
{36, "float charging voltage", "settings_float_charging_volts", "voltage", "V", REGISTER_SINGLE, 0.1},
{37, "battery voltage switch to utility", "settings_switch_to_utility_volts", "voltage", "V", REGISTER_SINGLE, 0.1},
// {76, "rated active power", "rated_active_power_watts", REGISTER_DOUBLE, 0.1}, // XXX: not needed
// {78, "rated apparant power", "rated_apparant_power_va", REGISTER_DOUBLE, 0.1}, // XXX: not needed
// NOLINTEND(readability-magic-numbers)
};

const REGISTER input_registers[] = {
// NOLINTBEGIN(readability-magic-numbers)
{0, "system status", "system_status", REGISTER_SINGLE, 1},
{1, "PV1 voltage", "pv1_volts", REGISTER_SINGLE, 0.1},
{3, "PV1 power", "pv1_watts", REGISTER_DOUBLE, 0.1},
{7, "buck1 current", "buck1_amps", REGISTER_SINGLE, 0.1},
// {8, "buck2 current", "buck2_amps", REGISTER_SINGLE, 0.1}, // XXX: always zero
{9, "inverter active power", "inverter_active_power_watts", REGISTER_DOUBLE, 0.1},
{11, "inverter apparant power", "inverter_apparant_power_va", REGISTER_DOUBLE, 0.1},
{13, "grid charging power", "grid_charging_watts", REGISTER_DOUBLE, 0.1},
{17, "battery voltage", "battery_volts", REGISTER_SINGLE, 0.01},
{18, "battery SOC", "battery_soc", REGISTER_SINGLE, 1},
{0, "system status", "system_status", "None", "", REGISTER_SINGLE, 1},
{1, "PV1 voltage", "pv1_volts", "voltage", "V", REGISTER_SINGLE, 0.1},
{3, "PV1 power", "pv1_watts", "power", "W", REGISTER_DOUBLE, 0.1},
{7, "buck1 current", "buck1_amps", "current", "A", REGISTER_SINGLE, 0.1},
// {8, "buck2 current", "buck2_amps", "current", "A", REGISTER_SINGLE, 0.1}, // XXX: always zero
{9, "inverter active power", "inverter_active_power_watts", "power", "W", REGISTER_DOUBLE, 0.1},
{11, "inverter apparant power", "inverter_apparant_power_va", "apparent_power", "VA", REGISTER_DOUBLE, 0.1},
{13, "grid charging power", "grid_charging_watts", "power", "W", REGISTER_DOUBLE, 0.1},
{17, "battery voltage", "battery_volts", "voltage", "V", REGISTER_SINGLE, 0.01},
{18, "battery SOC", "battery_soc", "battery", "%", REGISTER_SINGLE, 1},
// {19, "bus voltage", "bus_volts", REGISTER_SINGLE, 0.1}, // irrelevant
{20, "grid voltage", "grid_volts", REGISTER_SINGLE, 0.1},
{21, "grid frequency", "grid_hz", REGISTER_SINGLE, 0.01},
{20, "grid voltage", "grid_volts", "voltage", "V", REGISTER_SINGLE, 0.1},
{21, "grid frequency", "grid_hz", "frequency", "Hz", REGISTER_SINGLE, 0.01},
// {24, "output DC voltage", "output_dc_volts", REGISTER_SINGLE, 0.1}, // XXX: always zero
{25, "inverter temperature", "temperature_inverter_celsius", REGISTER_SINGLE, 0.1},
{26, "DC-DC temperature", "temperature_dcdc_celsius", REGISTER_SINGLE, 0.1},
{27, "inverter load percent", "inverter_load_percent", REGISTER_SINGLE, 0.1},
{25, "inverter temperature", "temperature_inverter_celsius", "temperature", "°C", REGISTER_SINGLE, 0.1},
{26, "DC-DC temperature", "temperature_dcdc_celsius", "temperature", "°C", REGISTER_SINGLE, 0.1},
{27, "inverter load percent", "inverter_load_percent", "None", "%", REGISTER_SINGLE, 0.1},
// {30, "work time total", "work_time_total_seconds", REGISTER_DOUBLE, 0.5}, // XXX: always zero
{32, "buck1 temperature", "temperature_buck1_celsius", REGISTER_SINGLE, 0.1, "temperature", "0C"},
{32, "buck1 temperature", "temperature_buck1_celsius", "temperature", "°C", REGISTER_SINGLE, 0.1},
// {33, "buck2 temperature", "temperature_buck2_celsius", REGISTER_SINGLE, 0.1}, // irrelevant
{34, "output current", "output_amps", REGISTER_SINGLE, 0.1},
{35, "inverter current", "inverter_amps", REGISTER_SINGLE, 0.1},
{40, "fault bit", "fault_bit", REGISTER_SINGLE, 1},
{41, "warning bit", "warning_bit", REGISTER_SINGLE, 1},
{34, "output current", "output_amps", "current", "A", REGISTER_SINGLE, 0.1},
{35, "inverter current", "inverter_amps", "current", "A", REGISTER_SINGLE, 0.1},
{40, "fault bit", "fault_bit", "None", "", REGISTER_SINGLE, 1},
{41, "warning bit", "warning_bit", "None", "", REGISTER_SINGLE, 1},
// {42, "fault value", "fault_value", REGISTER_SINGLE, 1}, // XXX: always zero
// {43, "warning value", "warning_value", REGISTER_SINGLE, 1}, // XXX: always zero
// {45, "product check step", "product_check_step", REGISTER_SINGLE, 1}, // irrelevant
// {46, "production line mode", "production_line_mode", REGISTER_SINGLE, 1}, // XXX: always zero
// {47, "constant power OK flag", "constant_power_ok_flag", REGISTER_SINGLE, 1}, // XXX: always zero
{48, "PV energy today", "energy_pv_today_kwh", REGISTER_DOUBLE, 0.1, "energy", "kWh"},
{50, "PV energy total", "energy_pv_total_kwh", REGISTER_DOUBLE, 0.1},
{56, "grid energy today", "energy_grid_today_kwh", REGISTER_DOUBLE, 0.1},
{58, "grid energy total", "energy_grid_total_kwh", REGISTER_DOUBLE, 0.1},
{60, "battery discharging energy today", "battery_discharging_today_kwh", REGISTER_DOUBLE, 0.1},
{64, "grid discharging energy today", "grid_discharging_today_kwh", REGISTER_DOUBLE, 0.1},
{66, "grid discharging energy total", "grid_discharging_total_kwh", REGISTER_DOUBLE, 0.1},
{68, "grid charging current", "grid_charging_amps", REGISTER_SINGLE, 0.1},
{69, "inverter discharging power", "inverter_discharging_watts", REGISTER_DOUBLE, 0.1},
{73, "battery discharging power", "battery_discharging_watts", REGISTER_DOUBLE, 0.1},
{77, "battery net power (signed)", "battery_net_watts", REGISTER_DOUBLE, -0.1},
{48, "PV energy today", "energy_pv_today_kwh", "energy", "kWh", REGISTER_DOUBLE, 0.1},
{50, "PV energy total", "energy_pv_total_kwh", "energy", "kWh", REGISTER_DOUBLE, 0.1},
{56, "grid energy today", "energy_grid_today_kwh", "energy", "kWh", REGISTER_DOUBLE, 0.1},
{58, "grid energy total", "energy_grid_total_kwh", "energy", "kWh", REGISTER_DOUBLE, 0.1},
{60, "battery discharging energy today", "battery_discharging_today_kwh", "energy", "kWh", REGISTER_DOUBLE, 0.1},
{64, "grid discharging energy today", "grid_discharging_today_kwh", "energy", "kWh", REGISTER_DOUBLE, 0.1},
{66, "grid discharging energy total", "grid_discharging_total_kwh", "energy", "kWh", REGISTER_DOUBLE, 0.1},
{68, "grid charging current", "grid_charging_amps", "current", "A", REGISTER_SINGLE, 0.1},
{69, "inverter discharging power", "inverter_discharging_watts", "power", "W", REGISTER_DOUBLE, 0.1},
{73, "battery discharging power", "battery_discharging_watts", "power", "W", REGISTER_DOUBLE, 0.1},
{77, "battery net power (signed)", "battery_net_watts", "power", "W", REGISTER_DOUBLE, -0.1},
// {81, "fan speed MPPT", "fan_speed_mppt", REGISTER_SINGLE, 1}, // XXX: always zero
{82, "fan speed inverter", "fan_speed_inverter", REGISTER_SINGLE, 1},
{82, "fan speed inverter", "fan_speed_inverter", "wind_speed", "%", REGISTER_SINGLE, 1},
// {180, "solar charger status", "solar_status", REGISTER_SINGLE, 1}, // XXX: always zero
// NOLINTEND(readability-magic-numbers)
};
Expand Down
74 changes: 14 additions & 60 deletions src/mqtt.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <string.h>
#include <unistd.h> // sleep()

#include "growatt.h"
#include "log.h"
#include "modbus.h"

Expand Down Expand Up @@ -84,70 +85,23 @@ int start_mqtt_thread(void *config_ptr) {

LOG(LOG_INFO, "Connected to the MQTT broker");

// TODO:
char payload[MQTT_METRIC_PAYLOAD_SIZE];
char metric_id[MQTT_METRIC_ID_SIZE];
char unique_id[MQTT_METRIC_ID_SIZE];
char topic[MQTT_METRIC_ID_SIZE * 2];

sprintf(metric_id, "battery_volts");
sprintf(unique_id, "growatt_%s", metric_id);
sprintf(payload,
"{\"device_class\":\"voltage\",\"state_topic\":\"%s\",\"unit_of_measurement\":\"V\",\"value_template\":\"{{"
"value_json.%s}}\",\"name\":\"Battery "
"voltage\",\"unique_id\":\"%s\",\"device\":{\"identifiers\":[\"1\"],\"name\":\"Growatt\",\"manufacturer\":"
"\"Growatt\"}}",
TOPIC_STATE, metric_id, unique_id);

sprintf(topic, "homeassistant/sensor/%s/config", unique_id);
mosquitto_publish(client, NULL, topic, (int)strlen(payload), payload, 0, true);

sprintf(metric_id, "pv1_watts");
sprintf(unique_id, "growatt_%s", metric_id);
sprintf(payload,
"{\"device_class\":\"power\",\"state_topic\":\"%s\",\"unit_of_measurement\":\"W\",\"value_template\":\"{{"
"value_json.%s}}\",\"name\":\"PV1 "
"power\",\"unique_id\":\"%s\",\"device\":{\"identifiers\":[\"1\"],\"name\":\"Growatt\",\"manufacturer\":"
"\"Growatt\"}}",
TOPIC_STATE, metric_id, unique_id);

sprintf(topic, "homeassistant/sensor/%s/config", unique_id);
mosquitto_publish(client, NULL, topic, (int)strlen(payload), payload, 0, true);

sprintf(metric_id, "pv1_volts");
sprintf(unique_id, "growatt_%s", metric_id);
sprintf(payload,
"{\"device_class\":\"voltage\",\"state_topic\":\"%s\",\"unit_of_measurement\":\"V\",\"value_template\":\"{{"
"value_json.%s}}\",\"name\":\"PV1 "
"voltage\",\"unique_id\":\"%s\",\"device\":{\"identifiers\":[\"1\"],\"name\":\"Growatt\",\"manufacturer\":"
"\"Growatt\"}}",
TOPIC_STATE, metric_id, unique_id);

sprintf(topic, "homeassistant/sensor/%s/config", unique_id);
mosquitto_publish(client, NULL, topic, (int)strlen(payload), payload, 0, false);

sprintf(metric_id, "energy_pv_today_kwh");
sprintf(unique_id, "growatt_%s", metric_id); // should be on Energy Dashboard because of "device_class: energy"
sprintf(payload,
"{\"device_class\":\"energy\",\"state_topic\":\"%s\",\"unit_of_measurement\":\"kWh\",\"value_template\":\"{{"
"value_json.%s}}\",\"name\":\"PV production "
"today\",\"unique_id\":\"%s\",\"device\":{\"identifiers\":[\"1\"],\"name\":\"Growatt\",\"manufacturer\":"
"\"Growatt\"}}",
TOPIC_STATE, metric_id, unique_id);

sprintf(metric_id, "energy_pv_total_kwh");
sprintf(unique_id, "growatt_%s",
metric_id); // should be on Energy Dashboard because of "device_class: energy" and state_class
sprintf(payload,
"{\"device_class\":\"energy\",\"state_class\":\"total_increasing\",\"state_topic\":\"%s\",\"unit_of_"
"measurement\":\"kWh\",\"value_template\":\"{{"
"value_json.%s}}\",\"name\":\"PV production "
"total\",\"unique_id\":\"%s\",\"device\":{\"identifiers\":[\"1\"],\"name\":\"Growatt\",\"manufacturer\":"
"\"Growatt\"}}",
TOPIC_STATE, metric_id, unique_id);

sprintf(topic, "homeassistant/sensor/%s/config", unique_id);
mosquitto_publish(client, NULL, topic, (int)strlen(payload), payload, 0, false);
for (size_t index = 0; index < COUNT(input_registers); index++) {
const REGISTER reg = input_registers[index];

sprintf(unique_id, "growatt_%s", reg.metric_name);
sprintf(payload,
"{\"device_class\":\"%s\",\"state_topic\":\"%s\",\"unit_of_measurement\":\"%s\","
"\"value_template\":\"{{value_json.%s}}\",\"name\":\"%s\",\"unique_id\":\"%s\","
"\"device\":{\"identifiers\":[\"1\"],\"name\":\"Growatt\",\"manufacturer\":\"Growatt\"}}",
reg.device_class, TOPIC_STATE, reg.unit, reg.metric_name, reg.human_name, unique_id);

sprintf(topic, "homeassistant/sensor/%s/config", unique_id);
mosquitto_publish(client, NULL, topic, (int)strlen(payload), payload, 0, true);
}

char metrics[RESPONSE_SIZE] = {0};
char buffer[RESPONSE_SIZE] = {0};
Expand Down

0 comments on commit c8267f3

Please sign in to comment.