ESPHome 2026.6.0-dev
Loading...
Searching...
No Matches
growatt_solar.cpp
Go to the documentation of this file.
1#include "growatt_solar.h"
4#include "esphome/core/log.h"
5
7
8static const char *const TAG = "growatt_solar";
9
10static const uint8_t MODBUS_CMD_READ_IN_REGISTERS = 0x04;
11static const uint8_t MODBUS_REGISTER_COUNT[] = {33, 95}; // indexed with enum GrowattProtocolVersion
12
14 // If update() was unable to send we retry until we can send.
15 if (!this->waiting_to_update_)
16 return;
17 update();
18}
19
21 // If our last send has had no reply yet, and it wasn't that long ago, do nothing.
23 if (now - this->last_send_ < this->get_update_interval() / 2) {
24 return;
25 }
26
27 // The bus might be slow, or there might be other devices, or other components might be talking to our device.
28 if (!this->ready_for_immediate_send()) {
29 this->waiting_to_update_ = true;
30 return;
31 }
32
33 this->waiting_to_update_ = false;
34 this->send(MODBUS_CMD_READ_IN_REGISTERS, 0, MODBUS_REGISTER_COUNT[this->protocol_version_]);
35 this->last_send_ = millis();
36}
37
38void GrowattSolar::on_modbus_data(const std::vector<uint8_t> &data) {
39 // Other components might be sending commands to our device. But we don't get called with enough
40 // context to know what is what. So if we didn't do a send, we ignore the data.
41 if (!this->last_send_)
42 return;
43 this->last_send_ = 0;
44
45 // Also ignore the data if the message is too short. Otherwise we will publish invalid values.
46 if (data.size() < MODBUS_REGISTER_COUNT[this->protocol_version_] * 2)
47 return;
48
49 auto publish_1_reg_sensor_state = [&](sensor::Sensor *sensor, size_t i, float unit) -> void {
50 if (sensor == nullptr)
51 return;
52 float value = encode_uint16(data[i * 2], data[i * 2 + 1]) * unit;
53 sensor->publish_state(value);
54 };
55
56 auto publish_2_reg_sensor_state = [&](sensor::Sensor *sensor, size_t reg1, size_t reg2, float unit) -> void {
57 float value = ((encode_uint16(data[reg1 * 2], data[reg1 * 2 + 1]) << 16) +
58 encode_uint16(data[reg2 * 2], data[reg2 * 2 + 1])) *
59 unit;
60 if (sensor != nullptr)
61 sensor->publish_state(value);
62 };
63
64 switch (this->protocol_version_) {
65 case RTU: {
66 publish_1_reg_sensor_state(this->inverter_status_, RTU_INVERTER_STATUS, 1);
67
68 publish_2_reg_sensor_state(this->pv_active_power_sensor_, RTU_PV_ACTIVE_POWER, RTU_PV_ACTIVE_POWER + 1,
69 ONE_DEC_UNIT);
70
71 publish_1_reg_sensor_state(this->pvs_[0].voltage_sensor_, RTU_PV1_VOLTAGE, ONE_DEC_UNIT);
72 publish_1_reg_sensor_state(this->pvs_[0].current_sensor_, RTU_PV1_CURRENT, ONE_DEC_UNIT);
73 publish_2_reg_sensor_state(this->pvs_[0].active_power_sensor_, RTU_PV1_ACTIVE_POWER, RTU_PV1_ACTIVE_POWER + 1,
74 ONE_DEC_UNIT);
75
76 publish_1_reg_sensor_state(this->pvs_[1].voltage_sensor_, RTU_PV2_VOLTAGE, ONE_DEC_UNIT);
77 publish_1_reg_sensor_state(this->pvs_[1].current_sensor_, RTU_PV2_CURRENT, ONE_DEC_UNIT);
78 publish_2_reg_sensor_state(this->pvs_[1].active_power_sensor_, RTU_PV2_ACTIVE_POWER, RTU_PV2_ACTIVE_POWER + 1,
79 ONE_DEC_UNIT);
80
81 publish_2_reg_sensor_state(this->grid_active_power_sensor_, RTU_GRID_ACTIVE_POWER, RTU_GRID_ACTIVE_POWER + 1,
82 ONE_DEC_UNIT);
83 publish_1_reg_sensor_state(this->grid_frequency_sensor_, RTU_GRID_FREQUENCY, TWO_DEC_UNIT);
84
85 publish_1_reg_sensor_state(this->phases_[0].voltage_sensor_, RTU_PHASE1_VOLTAGE, ONE_DEC_UNIT);
86 publish_1_reg_sensor_state(this->phases_[0].current_sensor_, RTU_PHASE1_CURRENT, ONE_DEC_UNIT);
87 publish_2_reg_sensor_state(this->phases_[0].active_power_sensor_, RTU_PHASE1_ACTIVE_POWER,
88 RTU_PHASE1_ACTIVE_POWER + 1, ONE_DEC_UNIT);
89
90 publish_1_reg_sensor_state(this->phases_[1].voltage_sensor_, RTU_PHASE2_VOLTAGE, ONE_DEC_UNIT);
91 publish_1_reg_sensor_state(this->phases_[1].current_sensor_, RTU_PHASE2_CURRENT, ONE_DEC_UNIT);
92 publish_2_reg_sensor_state(this->phases_[1].active_power_sensor_, RTU_PHASE2_ACTIVE_POWER,
93 RTU_PHASE2_ACTIVE_POWER + 1, ONE_DEC_UNIT);
94
95 publish_1_reg_sensor_state(this->phases_[2].voltage_sensor_, RTU_PHASE3_VOLTAGE, ONE_DEC_UNIT);
96 publish_1_reg_sensor_state(this->phases_[2].current_sensor_, RTU_PHASE3_CURRENT, ONE_DEC_UNIT);
97 publish_2_reg_sensor_state(this->phases_[2].active_power_sensor_, RTU_PHASE3_ACTIVE_POWER,
98 RTU_PHASE3_ACTIVE_POWER + 1, ONE_DEC_UNIT);
99
100 publish_2_reg_sensor_state(this->today_production_, RTU_TODAY_PRODUCTION, RTU_TODAY_PRODUCTION + 1, ONE_DEC_UNIT);
101 publish_2_reg_sensor_state(this->total_energy_production_, RTU_TOTAL_ENERGY_PRODUCTION,
102 RTU_TOTAL_ENERGY_PRODUCTION + 1, ONE_DEC_UNIT);
103
104 publish_1_reg_sensor_state(this->inverter_module_temp_, RTU_INVERTER_MODULE_TEMP, ONE_DEC_UNIT);
105 break;
106 }
107 case RTU2: {
108 publish_1_reg_sensor_state(this->inverter_status_, RTU2_INVERTER_STATUS, 1);
109
110 publish_2_reg_sensor_state(this->pv_active_power_sensor_, RTU2_PV_ACTIVE_POWER, RTU2_PV_ACTIVE_POWER + 1,
111 ONE_DEC_UNIT);
112
113 publish_1_reg_sensor_state(this->pvs_[0].voltage_sensor_, RTU2_PV1_VOLTAGE, ONE_DEC_UNIT);
114 publish_1_reg_sensor_state(this->pvs_[0].current_sensor_, RTU2_PV1_CURRENT, ONE_DEC_UNIT);
115 publish_2_reg_sensor_state(this->pvs_[0].active_power_sensor_, RTU2_PV1_ACTIVE_POWER, RTU2_PV1_ACTIVE_POWER + 1,
116 ONE_DEC_UNIT);
117
118 publish_1_reg_sensor_state(this->pvs_[1].voltage_sensor_, RTU2_PV2_VOLTAGE, ONE_DEC_UNIT);
119 publish_1_reg_sensor_state(this->pvs_[1].current_sensor_, RTU2_PV2_CURRENT, ONE_DEC_UNIT);
120 publish_2_reg_sensor_state(this->pvs_[1].active_power_sensor_, RTU2_PV2_ACTIVE_POWER, RTU2_PV2_ACTIVE_POWER + 1,
121 ONE_DEC_UNIT);
122
123 publish_2_reg_sensor_state(this->grid_active_power_sensor_, RTU2_GRID_ACTIVE_POWER, RTU2_GRID_ACTIVE_POWER + 1,
124 ONE_DEC_UNIT);
125 publish_1_reg_sensor_state(this->grid_frequency_sensor_, RTU2_GRID_FREQUENCY, TWO_DEC_UNIT);
126
127 publish_1_reg_sensor_state(this->phases_[0].voltage_sensor_, RTU2_PHASE1_VOLTAGE, ONE_DEC_UNIT);
128 publish_1_reg_sensor_state(this->phases_[0].current_sensor_, RTU2_PHASE1_CURRENT, ONE_DEC_UNIT);
129 publish_2_reg_sensor_state(this->phases_[0].active_power_sensor_, RTU2_PHASE1_ACTIVE_POWER,
130 RTU2_PHASE1_ACTIVE_POWER + 1, ONE_DEC_UNIT);
131
132 publish_1_reg_sensor_state(this->phases_[1].voltage_sensor_, RTU2_PHASE2_VOLTAGE, ONE_DEC_UNIT);
133 publish_1_reg_sensor_state(this->phases_[1].current_sensor_, RTU2_PHASE2_CURRENT, ONE_DEC_UNIT);
134 publish_2_reg_sensor_state(this->phases_[1].active_power_sensor_, RTU2_PHASE2_ACTIVE_POWER,
135 RTU2_PHASE2_ACTIVE_POWER + 1, ONE_DEC_UNIT);
136
137 publish_1_reg_sensor_state(this->phases_[2].voltage_sensor_, RTU2_PHASE3_VOLTAGE, ONE_DEC_UNIT);
138 publish_1_reg_sensor_state(this->phases_[2].current_sensor_, RTU2_PHASE3_CURRENT, ONE_DEC_UNIT);
139 publish_2_reg_sensor_state(this->phases_[2].active_power_sensor_, RTU2_PHASE3_ACTIVE_POWER,
140 RTU2_PHASE3_ACTIVE_POWER + 1, ONE_DEC_UNIT);
141
142 publish_2_reg_sensor_state(this->today_production_, RTU2_TODAY_PRODUCTION, RTU2_TODAY_PRODUCTION + 1,
143 ONE_DEC_UNIT);
144 publish_2_reg_sensor_state(this->total_energy_production_, RTU2_TOTAL_ENERGY_PRODUCTION,
145 RTU2_TOTAL_ENERGY_PRODUCTION + 1, ONE_DEC_UNIT);
146
147 publish_1_reg_sensor_state(this->inverter_module_temp_, RTU2_INVERTER_MODULE_TEMP, ONE_DEC_UNIT);
148 break;
149 }
150 }
151}
152
154 ESP_LOGCONFIG(TAG,
155 "GROWATT Solar:\n"
156 " Address: 0x%02X",
157 this->address_);
158}
159
160} // namespace esphome::growatt_solar
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
virtual uint32_t get_update_interval() const
Get the update interval in ms of this sensor.
void on_modbus_data(const std::vector< uint8_t > &data) override
struct esphome::growatt_solar::GrowattSolar::GrowattPhase phases_[3]
GrowattProtocolVersion protocol_version_
struct esphome::growatt_solar::GrowattSolar::GrowattPV pvs_[2]
void send(uint8_t function, uint16_t start_address, uint16_t number_of_entities, uint8_t payload_len=0, const uint8_t *payload=nullptr)
Definition modbus.h:99
Base-class for all sensors.
Definition sensor.h:47
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:68
constexpr size_t RTU_PV1_CURRENT
constexpr size_t RTU2_PV1_CURRENT
constexpr size_t RTU2_GRID_FREQUENCY
constexpr size_t RTU_INVERTER_STATUS
constexpr size_t RTU_PHASE3_VOLTAGE
constexpr size_t RTU_PV2_CURRENT
constexpr size_t RTU2_PV_ACTIVE_POWER
constexpr size_t RTU2_PHASE3_ACTIVE_POWER
constexpr size_t RTU_PV2_ACTIVE_POWER
constexpr size_t RTU2_PHASE2_ACTIVE_POWER
constexpr size_t RTU_PHASE2_ACTIVE_POWER
constexpr size_t RTU_PHASE2_VOLTAGE
constexpr size_t RTU2_PV1_ACTIVE_POWER
constexpr size_t RTU2_PV2_VOLTAGE
constexpr size_t RTU_TOTAL_ENERGY_PRODUCTION
constexpr size_t RTU_GRID_ACTIVE_POWER
constexpr size_t RTU_PHASE3_CURRENT
constexpr size_t RTU2_PV1_VOLTAGE
constexpr size_t RTU2_PHASE1_ACTIVE_POWER
constexpr size_t RTU2_PHASE3_VOLTAGE
constexpr size_t RTU_PHASE1_CURRENT
constexpr size_t RTU2_PHASE1_CURRENT
constexpr size_t RTU2_TODAY_PRODUCTION
constexpr size_t RTU_PV2_VOLTAGE
constexpr size_t RTU_PV_ACTIVE_POWER
constexpr size_t RTU2_INVERTER_MODULE_TEMP
constexpr size_t RTU_PV1_VOLTAGE
constexpr size_t RTU2_PHASE2_CURRENT
constexpr size_t RTU2_TOTAL_ENERGY_PRODUCTION
constexpr size_t RTU2_GRID_ACTIVE_POWER
constexpr size_t RTU2_PHASE1_VOLTAGE
constexpr size_t RTU_PV1_ACTIVE_POWER
constexpr size_t RTU2_PHASE2_VOLTAGE
constexpr size_t RTU2_PHASE3_CURRENT
constexpr size_t RTU_PHASE1_VOLTAGE
constexpr size_t RTU2_PV2_CURRENT
constexpr size_t RTU_GRID_FREQUENCY
constexpr size_t RTU_PHASE1_ACTIVE_POWER
constexpr size_t RTU_PHASE2_CURRENT
constexpr size_t RTU2_PV2_ACTIVE_POWER
constexpr size_t RTU2_INVERTER_STATUS
constexpr size_t RTU_TODAY_PRODUCTION
constexpr size_t RTU_PHASE3_ACTIVE_POWER
constexpr size_t RTU_INVERTER_MODULE_TEMP
constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb)
Encode a 16-bit value given the most and least significant byte.
Definition helpers.h:859
uint32_t IRAM_ATTR HOT millis()
Definition hal.cpp:28
Application App
Global storage of Application pointer - only one Application can exist.
static void uint32_t