├── .gitignore ├── DTU.bin ├── components └── inv_8851 │ ├── __init__.py │ ├── binary_sensor.py │ ├── inv_8851.cpp │ ├── inv_8851.h │ ├── inv_8851_number.cpp │ ├── inv_8851_number.h │ ├── inv_8851_select.cpp │ ├── inv_8851_select.h │ ├── number.py │ ├── select.py │ ├── sensor.py │ └── text_sensor.py ├── dtu-wbs1-v001-24v-example-local.yaml ├── dtu-wbs1-v001-24v-example.yaml ├── dtu-wbs1-v001-48v-example-local-my.yaml ├── dtu-wbs1-v001-48v-example-local.yaml ├── dtu-wbs1-v001-48v-example.yaml ├── esp32-24v-example-local.yaml ├── esp32-24v-example.yaml ├── esp32-48v-example-local.yaml ├── esp32-48v-example.yaml ├── esp8266-24v-example-local.yaml ├── esp8266-24v-example.yaml ├── esp8266-48v-example-local.yaml ├── esp8266-48v-example.yaml ├── packages ├── battery-24v.yaml ├── battery-48v.yaml ├── battery.yaml ├── bms-24v.yaml ├── bms-48v.yaml ├── core-local.yaml ├── core.yaml ├── dtu_wbs1_v001.yaml ├── grid.yaml ├── inverter.yaml ├── parallel.yaml ├── pv.yaml ├── temperature.yaml └── wifi-plug-pro-05.yaml ├── readme.md ├── resources ├── WBS1-V001.jpg ├── WBS1-V001.svg ├── WBS1-V001_PCB_bottom.jpg ├── WBS1-V001_PCB_top.jpg ├── WBS1-V001_parts.jpg └── WBS1-V001_screws.jpg ├── secrets.yaml ├── wifi-plug-pro-05-24v-example-local.yaml └── wifi-plug-pro-05-24v-example.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | /.esphome/ 2 | /.vscode/ 3 | /components/inv_8851/esphome/ 4 | /secrets.yaml 5 | *.pyc 6 | __pycache__ 7 | -------------------------------------------------------------------------------- /DTU.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lufton/esphome-inv-8851/1aeae3ac672e268ff1032a66a962abef8737fcc4/DTU.bin -------------------------------------------------------------------------------- /components/inv_8851/__init__.py: -------------------------------------------------------------------------------- 1 | import esphome.codegen as cg 2 | import esphome.config_validation as cv, voluptuous as vol 3 | from esphome.components import uart 4 | from esphome.const import CONF_ID, CONF_VERSION 5 | 6 | DEPENDENCIES = ["uart"] 7 | 8 | CODEOWNERS = ["@lufton"] 9 | 10 | CONF_INV_8851_ID = "inv_8851_id" 11 | ALLOWED_VERSIONS = [1, 2] 12 | 13 | inv_8851_ns = cg.esphome_ns.namespace("inv_8851") 14 | Inv8851 = inv_8851_ns.class_("Inv8851", cg.PollingComponent, uart.UARTDevice) 15 | 16 | CONFIG_SCHEMA = ( 17 | cv.Schema( 18 | { 19 | cv.GenerateID(): cv.declare_id(Inv8851), 20 | cv.Required(CONF_VERSION): vol.All(vol.Coerce(int), vol.In(ALLOWED_VERSIONS)) 21 | } 22 | ) 23 | .extend(cv.polling_component_schema("5s")) 24 | .extend(uart.UART_DEVICE_SCHEMA) 25 | ) 26 | 27 | async def to_code(config): 28 | cg.add_define("INV8851_VERSION", config[CONF_VERSION]) 29 | var = cg.new_Pvariable(config.get(CONF_ID)) 30 | await cg.register_component(var, config) 31 | await uart.register_uart_device(var, config) 32 | -------------------------------------------------------------------------------- /components/inv_8851/binary_sensor.py: -------------------------------------------------------------------------------- 1 | import esphome.codegen as cg 2 | import esphome.config_validation as cv 3 | from esphome.components import binary_sensor 4 | from esphome.const import ( 5 | CONF_PLATFORM, 6 | DEVICE_CLASS_BATTERY_CHARGING, 7 | DEVICE_CLASS_CONNECTIVITY, 8 | DEVICE_CLASS_POWER, 9 | ) 10 | 11 | from . import ( 12 | Inv8851, 13 | CONF_INV_8851_ID, 14 | ) 15 | 16 | DEPENDENCIES = ["inv_8851"] 17 | 18 | CODEOWNERS = ["@lufton"] 19 | 20 | CONF_BATTERY = "battery" 21 | CONF_BUCK_TOPOLOGY_INITIALIZATION = "buck_topology_initialization" 22 | CONF_BUS = "bus" 23 | CONF_BUS_AND_GRID_VOLTAGE_MATCH = "bus_and_grid_voltage_match" 24 | CONF_CHARGING = "charging" 25 | CONF_DISABLE_UTILITY = "disable_utility" 26 | CONF_EQUALIZATION_FINISHED = "equalization_finished" 27 | CONF_EQUALIZATION_STARTED = "equalization_started" 28 | CONF_FLOAT_CHARGING = "float_charging" 29 | CONF_GRID_PLL = "grid_pll" 30 | CONF_INVERTER_TOPOLOGY_INITIALIZATION = "inverter_topology_initialization" 31 | CONF_LLC_TOPOLOGY_INITIALIZATION = "llc_topology_initialization" 32 | CONF_PARALLEL_LOCK_PHASE = "parallel_lock_phase" 33 | CONF_PV_EXCESS = "pv_excess" 34 | CONF_PV_INPUT = "pv_input" 35 | CONF_PV_TOPOLOGY_INITIALIZATION = "pv_topology_initialization" 36 | CONF_SYSTEM_INITIALIZATION = "system_initialization" 37 | CONF_SYSTEM_POWER = "system_power" 38 | 39 | CONFIG_SCHEMA = ( 40 | cv.Schema( 41 | { 42 | cv.GenerateID(CONF_INV_8851_ID): cv.use_id(Inv8851), 43 | cv.Optional(CONF_BATTERY): binary_sensor.binary_sensor_schema( 44 | device_class=DEVICE_CLASS_CONNECTIVITY 45 | ), 46 | cv.Optional(CONF_BUCK_TOPOLOGY_INITIALIZATION): binary_sensor.binary_sensor_schema(), 47 | cv.Optional(CONF_BUS): binary_sensor.binary_sensor_schema( 48 | device_class=DEVICE_CLASS_CONNECTIVITY 49 | ), 50 | cv.Optional(CONF_BUS_AND_GRID_VOLTAGE_MATCH): binary_sensor.binary_sensor_schema(), 51 | cv.Optional(CONF_CHARGING): binary_sensor.binary_sensor_schema( 52 | device_class=DEVICE_CLASS_BATTERY_CHARGING 53 | ), 54 | cv.Optional(CONF_DISABLE_UTILITY): binary_sensor.binary_sensor_schema(), 55 | cv.Optional(CONF_EQUALIZATION_FINISHED): binary_sensor.binary_sensor_schema(), 56 | cv.Optional(CONF_EQUALIZATION_STARTED): binary_sensor.binary_sensor_schema(), 57 | cv.Optional(CONF_FLOAT_CHARGING): binary_sensor.binary_sensor_schema( 58 | device_class=DEVICE_CLASS_BATTERY_CHARGING 59 | ), 60 | cv.Optional(CONF_GRID_PLL): binary_sensor.binary_sensor_schema(), 61 | cv.Optional(CONF_INVERTER_TOPOLOGY_INITIALIZATION): binary_sensor.binary_sensor_schema(), 62 | cv.Optional(CONF_LLC_TOPOLOGY_INITIALIZATION): binary_sensor.binary_sensor_schema(), 63 | cv.Optional(CONF_PARALLEL_LOCK_PHASE): binary_sensor.binary_sensor_schema(), 64 | cv.Optional(CONF_PV_EXCESS): binary_sensor.binary_sensor_schema(), 65 | cv.Optional(CONF_PV_INPUT): binary_sensor.binary_sensor_schema( 66 | device_class=DEVICE_CLASS_CONNECTIVITY 67 | ), 68 | cv.Optional(CONF_PV_TOPOLOGY_INITIALIZATION): binary_sensor.binary_sensor_schema(), 69 | cv.Optional(CONF_SYSTEM_INITIALIZATION): binary_sensor.binary_sensor_schema(), 70 | cv.Optional(CONF_SYSTEM_POWER): binary_sensor.binary_sensor_schema( 71 | device_class=DEVICE_CLASS_POWER 72 | ), 73 | } 74 | ) 75 | ) 76 | 77 | 78 | async def to_code(config): 79 | parent = await cg.get_variable(config.get(CONF_INV_8851_ID)) 80 | for option in config: 81 | if option not in [CONF_PLATFORM, CONF_INV_8851_ID] and (c := config.get(option)): 82 | bin_sens = await binary_sensor.new_binary_sensor(c) 83 | cg.add(getattr(parent, f"set_{option}_binary_sensor")(bin_sens)) 84 | -------------------------------------------------------------------------------- /components/inv_8851/inv_8851.cpp: -------------------------------------------------------------------------------- 1 | #include "esphome/core/defines.h" 2 | #include "inv_8851.h" 3 | #include "esphome/core/log.h" 4 | #include "esphome/components/uart/uart_component.h" 5 | #include "esphome/components/uart/uart_debugger.h" 6 | #include 7 | 8 | namespace esphome { 9 | namespace inv_8851 { 10 | 11 | const uint8_t protocol_size = 2; 12 | const uint8_t command_size = 2; 13 | const uint8_t address_size = 2; 14 | const uint8_t data_size_size = 2; 15 | const uint8_t header_size = protocol_size + command_size + address_size + data_size_size; 16 | const uint8_t crc_size = 2; 17 | const uint8_t inv8851_state_data_size = inv8851_state_pkt_len - header_size - crc_size; 18 | const uint8_t inv8851_config_data_size = inv8851_config_pkt_len - header_size - crc_size; 19 | const uint8_t inv8851_protocol[protocol_size] = {0x88, 0x51}; 20 | const uint8_t read_command[command_size] = {0x00, 0x03}; 21 | const uint8_t write_command[command_size] = {0x00, 0x10}; 22 | const uint8_t state_address[address_size] = {0x00, 0x00}; 23 | const uint8_t config_address[address_size] = {0x02, 0x00}; 24 | const char *battery_type_options[] = { [AGM] = "AGM", [FLOODED] = "Flooded", [USER] = "User-defined", [LIB] = "Library" }; 25 | const char *charge_energy_priority_options[] = { [CSO] = "PV & Grid", [SNU] = "PV > Grid", [OSO] = "PV only" }; 26 | const char *frequency_options[] = { [FIFTY] = "50Hz", [SIXTY] = "60Hz" }; 27 | const char *grid_voltage_range_options[] = { [UPS] = "UPS", [APL] = "APL" }; 28 | const char *off_on_options[] = { [OFF] = "Off", [ON] = "On" }; 29 | const char *output_energy_priority_options[] = { [SUB] = "PV > Grid > Battery", [SBU] = "PV > Battery > Grid" }; 30 | const char *phase_options[] = { [A] = "A", [B] = "B", [C] = "C" }; 31 | const char *run_mode_options[] = { [standby_mode] = "standby", [fault_mode] = "fault", [shutdown_mode] = "shutdown", [normal_mode] = "normal", [no_battery_mode] = "no_battery", [discharge_mode] = "discharge", [parallel_discharge] = "parallel_disc", [bypass_mode] = "bypass", [charge_mode] = "charge", [grid_discharge_mode] = "grid_discharge", [micro_grid_discharge_mode] = "micro_grid_discharge" }; 32 | 33 | void Inv8851::clear_buffer_() { 34 | while (this->available()) this->read(); 35 | this->last_read_ = millis(); 36 | } 37 | 38 | uint16_t convert_le_(const uint8_t* data) { 39 | return data[1] << 8 | data[0]; 40 | } 41 | 42 | std::string bytes_to_string(const uint8_t *data, const uint16_t len) { 43 | std::string hex_string; 44 | for (size_t i = 0; i < len; ++i) { 45 | char buf[5]; 46 | snprintf(buf, sizeof(buf), "%02X ", data[i]); 47 | hex_string += buf; 48 | } 49 | return hex_string; 50 | } 51 | 52 | Protocol Inv8851::read_protocol_() { 53 | uint8_t data[protocol_size]; 54 | if (!this->read_array(data, protocol_size)) { 55 | ESP_LOGW(TAG, "Can't read protocol from buffer"); 56 | return UNKNOWN_PROTOCOL; 57 | } 58 | ESP_LOGV(TAG, "Protocol: %02X %02X", data[0], data[1]); 59 | if (memcmp(data, inv8851_protocol, protocol_size) == 0) { 60 | ESP_LOGVV(TAG, "Protocol matches expected %02X %02X", inv8851_protocol[0], inv8851_protocol[1]); 61 | return INV8851_PROTOCOL; 62 | } 63 | ESP_LOGW(TAG, "Protocol %02X %02X doesn't match expected %02X %02X", data[0], data[1], inv8851_protocol[0], inv8851_protocol[1]); 64 | return UNKNOWN_PROTOCOL; 65 | } 66 | 67 | Command Inv8851::read_command_() { 68 | uint8_t data[protocol_size]; 69 | if (!this->read_array(data, command_size)) { 70 | ESP_LOGW(TAG, "Can't read command from buffer"); 71 | return UNKNOWN_COMMAND; 72 | } 73 | ESP_LOGV(TAG, "Command: %02X %02X", data[0], data[1]); 74 | if (memcmp(data, read_command, command_size) == 0) { 75 | ESP_LOGV(TAG, "This is read command"); 76 | return READ_COMMAND; 77 | } else if (memcmp(data, write_command, command_size) == 0) { 78 | ESP_LOGV(TAG, "This is write command"); 79 | return WRITE_COMMAND; 80 | } 81 | ESP_LOGW(TAG, "%02X %02X is neither read nor write command", data[0], data[1]); 82 | return UNKNOWN_COMMAND; 83 | } 84 | 85 | Address Inv8851::read_address_() { 86 | uint8_t data[address_size]; 87 | if (!this->read_array(data, address_size)) { 88 | ESP_LOGW(TAG, "Can't read address from buffer"); 89 | return UNKNOWN_ADDRESS; 90 | } 91 | ESP_LOGV(TAG, "Address: %02X %02X", data[0], data[1]); 92 | if (memcmp(data, state_address, address_size) == 0) { 93 | ESP_LOGV(TAG, "This is state address"); 94 | return STATE_ADDRESS; 95 | } else if (memcmp(data, config_address, address_size) == 0) { 96 | ESP_LOGV(TAG, "This is config address"); 97 | return CONFIG_ADDRESS; 98 | } 99 | ESP_LOGW(TAG, "%02X %02X is neither state or config address", data[0], data[1]); 100 | return UNKNOWN_ADDRESS; 101 | } 102 | 103 | esphome::optional Inv8851::read_data_size_() { 104 | uint8_t data[data_size_size]; 105 | if (!this->read_array(data, data_size_size)) { 106 | ESP_LOGW(TAG, "Can't read data size from buffer"); 107 | return {}; 108 | } 109 | auto data_size = convert_le_(data); 110 | ESP_LOGV(TAG, "Data size: %d", data_size); 111 | return data_size; 112 | } 113 | 114 | esphome::optional> Inv8851::read_data_(const uint16_t size) { 115 | while (this->available() < size + crc_size && millis() - this->last_read_ < 1000) { 116 | ESP_LOGVV(TAG, "Buffer available data size (%d bytes) is less than expected data size (%d bytes), waiting for data to arrive", this->available(), size); 117 | delay(10); 118 | } 119 | if (this->available() < size + crc_size) { 120 | ESP_LOGW(TAG, "Can't read data block from buffer"); 121 | return {}; 122 | } 123 | std::vector data(size); 124 | if (!this->read_array(data.data(), size)) { 125 | ESP_LOGW(TAG, "Can't read data block from buffer"); 126 | return {}; 127 | } 128 | ESP_LOGV(TAG, "Data: %s", bytes_to_string(data.data(), size).c_str()); 129 | return data; 130 | } 131 | 132 | bool Inv8851::read_crc16_(const uint8_t *data, const uint8_t len) { 133 | uint8_t crc16_data[crc_size]; 134 | if (!this->read_array(crc16_data, crc_size)) { 135 | ESP_LOGW(TAG, "Can't read CRC16 from buffer"); 136 | return false; 137 | } 138 | auto actual_crc16 = convert_le_(crc16_data); 139 | ESP_LOGV(TAG, "CRC16: 0x%04X (%d)", actual_crc16, actual_crc16); 140 | auto expected_crc16 = crc16(data, len); 141 | if (actual_crc16 == expected_crc16) { 142 | ESP_LOGVV(TAG, "Actual CRC16 0x%04X (%d) matches expected CRC16 0x%04X (%d)", actual_crc16, actual_crc16, expected_crc16, expected_crc16); 143 | return true; 144 | } 145 | ESP_LOGW(TAG, "Actual CRC16 0x%04X (%d) doesn't match expected CRC16 0x%04X (%d)", actual_crc16, actual_crc16, expected_crc16, expected_crc16); 146 | ESP_LOGW(TAG, "Input for CRC16: %s", bytes_to_string(data, len).c_str()); 147 | return false; 148 | } 149 | 150 | void Inv8851::write_config_() { 151 | inv8851_config_s config; 152 | uint8_t *buff = (uint8_t *) &config; 153 | memcpy(&config, &this->config_, inv8851_config_pkt_len); 154 | config.command = INV8851_CONFIG_CMD_WRITE; 155 | config.data_size = inv8851_config_pkt_len - header_size - crc_size; 156 | config.crc = crc16(buff, inv8851_config_pkt_len - crc_size); 157 | this->write_array(buff, inv8851_config_pkt_len); 158 | publish_config_((uint8_t *) &config); 159 | } 160 | 161 | void Inv8851::setup() { 162 | this->clear_buffer_(); 163 | this->update(); 164 | } 165 | 166 | void Inv8851::loop() { 167 | if (millis() - this->last_read_ < 100 || this->available() < 100) return delay(10); 168 | this->last_read_ = millis(); 169 | auto protocol = this->read_protocol_(); 170 | if (protocol == UNKNOWN_PROTOCOL) return this->clear_buffer_(); 171 | auto command = this->read_command_(); 172 | if (command == UNKNOWN_COMMAND || command == WRITE_COMMAND) return this->clear_buffer_(); 173 | auto address = this->read_address_(); 174 | if (address == UNKNOWN_ADDRESS) return this->clear_buffer_(); 175 | auto data_size = this->read_data_size_(); 176 | if (!data_size.has_value()) return this->clear_buffer_(); 177 | if (address == STATE_ADDRESS && data_size.value() != inv8851_state_data_size) 178 | ESP_LOGW( 179 | TAG, 180 | "It looks like your inverter has version other than defined (%d). Expected state data size for this version is %d, but %d provided. Consider setting version parameter of inv_8851 component to something else.", 181 | INV8851_VERSION, 182 | inv8851_state_data_size, 183 | data_size.value() 184 | ); 185 | if (address == CONFIG_ADDRESS && data_size.value() != inv8851_config_data_size) 186 | ESP_LOGW( 187 | TAG, 188 | "It looks like your inverter has version other than defined (%d). Expected config data size for this version is %d, but %d provided. Consider setting version parameter of inv_8851 component to something else.", 189 | INV8851_VERSION, 190 | inv8851_config_data_size, 191 | data_size.value() 192 | ); 193 | auto data = this->read_data_(data_size.value()); 194 | if (!data.has_value()) return this->clear_buffer_(); 195 | uint8_t *packet = new uint8_t[header_size + data_size.value()]; 196 | uint8_t offset = 0; 197 | std::memcpy(packet + offset, inv8851_protocol, protocol_size); offset += protocol_size; 198 | std::memcpy(packet + offset, read_command, command_size); offset += command_size; 199 | std::memcpy(packet + offset, address == STATE_ADDRESS ? state_address : config_address, address_size); offset += address_size; 200 | std::memcpy(packet + offset, reinterpret_cast(&data_size.value()), data_size_size); offset += data_size_size; 201 | std::memcpy(packet + offset, data.value().data(), data_size.value()); offset += data_size.value(); 202 | if (!this->read_crc16_(packet, header_size + data_size.value())) return this->clear_buffer_(); 203 | if (address == STATE_ADDRESS) this->publish_state_(packet); 204 | else this->publish_config_(packet); 205 | } 206 | 207 | void Inv8851::update() { 208 | if (this->state_update_) this->request_state_(); 209 | else this->request_config_(); 210 | this->state_update_ = !this->state_update_; 211 | } 212 | 213 | void Inv8851::dump_config() { 214 | ESP_LOGCONFIG(TAG, "INV_8851:"); 215 | #ifdef USE_BINARY_SENSOR 216 | LOG_BINARY_SENSOR("", "Battery connected", this->battery_binary_sensor_); 217 | LOG_BINARY_SENSOR("", "Buck topology initialization", this->buck_topology_initialization_binary_sensor_); 218 | LOG_BINARY_SENSOR("", "Bus", this->bus_binary_sensor_); 219 | LOG_BINARY_SENSOR("", "Bus and grid voltage match", this->bus_and_grid_voltage_match_binary_sensor_); 220 | LOG_BINARY_SENSOR("", "Charging", this->charging_binary_sensor_); 221 | LOG_BINARY_SENSOR("", "Disable utility", this->disable_utility_binary_sensor_); 222 | LOG_BINARY_SENSOR("", "Equalization finished", this->equalization_finished_binary_sensor_); 223 | LOG_BINARY_SENSOR("", "Equalization started", this->equalization_started_binary_sensor_); 224 | LOG_BINARY_SENSOR("", "Float charging", this->float_charging_binary_sensor_); 225 | LOG_BINARY_SENSOR("", "Grid PLL", this->grid_pll_binary_sensor_); 226 | LOG_BINARY_SENSOR("", "Inverter topology initialization", this->inverter_topology_initialization_binary_sensor_); 227 | LOG_BINARY_SENSOR("", "LLC topology initialization", this->llc_topology_initialization_binary_sensor_); 228 | LOG_BINARY_SENSOR("", "Parallel lock phase problem", this->parallel_lock_phase_binary_sensor_); 229 | LOG_BINARY_SENSOR("", "PV excess", this->pv_excess_binary_sensor_); 230 | LOG_BINARY_SENSOR("", "PV input", this->pv_input_binary_sensor_); 231 | LOG_BINARY_SENSOR("", "PV topology initialization", this->pv_topology_initialization_binary_sensor_); 232 | LOG_BINARY_SENSOR("", "System power", this->system_power_binary_sensor_); 233 | #endif 234 | 235 | #ifdef USE_TEXT_SENSOR 236 | LOG_TEXT_SENSOR("", "Buck topology", this->buck_topology_text_sensor_); 237 | LOG_TEXT_SENSOR("", "Inverter topology", this->inverter_topology_text_sensor_); 238 | LOG_TEXT_SENSOR("", "LLC topology", this->llc_topology_text_sensor_); 239 | LOG_TEXT_SENSOR("", "PV topology", this->pv_topology_text_sensor_); 240 | #endif 241 | 242 | #ifdef USE_SENSOR 243 | LOG_SENSOR("", "Battery charge current", this->battery_charge_current_sensor_); 244 | LOG_SENSOR("", "Battery voltage", this->battery_voltage_sensor_); 245 | LOG_SENSOR("", "BMS battery current", this->bms_battery_current_sensor_); 246 | LOG_SENSOR("", "BMS battery SOC", this->bms_battery_soc_sensor_); 247 | LOG_SENSOR("", "BMS battery voltage", this->bms_battery_voltage_sensor_); 248 | LOG_SENSOR("", "BMS cell 01 voltage", this->bms_cell_01_voltage_sensor_); 249 | LOG_SENSOR("", "BMS cell 02 voltage", this->bms_cell_02_voltage_sensor_); 250 | LOG_SENSOR("", "BMS cell 03 voltage", this->bms_cell_03_voltage_sensor_); 251 | LOG_SENSOR("", "BMS cell 04 voltage", this->bms_cell_04_voltage_sensor_); 252 | LOG_SENSOR("", "BMS cell 05 voltage", this->bms_cell_05_voltage_sensor_); 253 | LOG_SENSOR("", "BMS cell 06 voltage", this->bms_cell_06_voltage_sensor_); 254 | LOG_SENSOR("", "BMS cell 07 voltage", this->bms_cell_07_voltage_sensor_); 255 | LOG_SENSOR("", "BMS cell 08 voltage", this->bms_cell_08_voltage_sensor_); 256 | LOG_SENSOR("", "BMS cell 09 voltage", this->bms_cell_09_voltage_sensor_); 257 | LOG_SENSOR("", "BMS cell 10 voltage", this->bms_cell_10_voltage_sensor_); 258 | LOG_SENSOR("", "BMS cell 11 voltage", this->bms_cell_11_voltage_sensor_); 259 | LOG_SENSOR("", "BMS cell 12 voltage", this->bms_cell_12_voltage_sensor_); 260 | LOG_SENSOR("", "BMS cell 13 voltage", this->bms_cell_13_voltage_sensor_); 261 | LOG_SENSOR("", "BMS cell 14 voltage", this->bms_cell_14_voltage_sensor_); 262 | LOG_SENSOR("", "BMS cell 15 voltage", this->bms_cell_15_voltage_sensor_); 263 | LOG_SENSOR("", "BMS cell 16 voltage", this->bms_cell_16_voltage_sensor_); 264 | LOG_SENSOR("", "BTS temperature", this->bts_temperature_sensor_); 265 | LOG_SENSOR("", "Bus voltage", this->bus_voltage_sensor_); 266 | LOG_SENSOR("", "Fan 1 speed percentage", this->fan1_speed_percentage_sensor_); 267 | LOG_SENSOR("", "Fan 2 speed percentage", this->fan2_speed_percentage_sensor_); 268 | LOG_SENSOR("", "Grid current", this->grid_current_sensor_); 269 | LOG_SENSOR("", "Grid frequency", this->grid_frequency_sensor_); 270 | LOG_SENSOR("", "Grid voltage", this->grid_voltage_sensor_); 271 | LOG_SENSOR("", "Inverter apparent power", this->inverter_apparent_power_sensor_); 272 | LOG_SENSOR("", "Inverter apparent power percentage", this->inverter_apparent_power_percentage_sensor_); 273 | LOG_SENSOR("", "Inverter current", this->inverter_current_sensor_); 274 | LOG_SENSOR("", "Inverter frequency", this->inverter_frequency_sensor_); 275 | LOG_SENSOR("", "Inverter power percentage", this->inverter_power_percentage_sensor_); 276 | LOG_SENSOR("", "Inverter software version", this->inverter_software_version_sensor_); 277 | LOG_SENSOR("", "Inverter voltage", this->inverter_voltage_sensor_); 278 | LOG_SENSOR("", "Inverter voltage DC component", this->inverter_voltage_dc_component_sensor_); 279 | LOG_SENSOR("", "Load apparent power", this->load_apparent_power_sensor_); 280 | LOG_SENSOR("", "Load current", this->load_current_sensor_); 281 | LOG_SENSOR("", "Load power", this->load_power_sensor_); 282 | LOG_SENSOR("", "Log number", this->log_number_sensor_); 283 | LOG_SENSOR("", "Low load current", this->low_load_current_sensor_); 284 | LOG_SENSOR("", "NTC2 temperature", this->ntc2_temperature_sensor_); 285 | LOG_SENSOR("", "NTC3 temperature", this->ntc3_temperature_sensor_); 286 | LOG_SENSOR("", "NTC4 temperature", this->ntc4_temperature_sensor_); 287 | LOG_SENSOR("", "Parallel current", this->parallel_current_sensor_); 288 | LOG_SENSOR("", "Parallel frequency", this->parallel_frequency_sensor_); 289 | LOG_SENSOR("", "Parallel voltage", this->parallel_voltage_sensor_); 290 | LOG_SENSOR("", "PV current", this->pv_current_sensor_); 291 | LOG_SENSOR("", "PV power", this->pv_power_sensor_); 292 | LOG_SENSOR("", "PV voltage", this->pv_voltage_sensor_); 293 | #endif 294 | 295 | #ifdef USE_SELECT 296 | LOG_SELECT("", "Auto return", this->auto_return_select_); 297 | LOG_SELECT("", "Backlight", this->backlight_select_); 298 | LOG_SELECT("", "Battery equalization", this->battery_equalization_select_); 299 | LOG_SELECT("", "Battery type", this->battery_type_select_); 300 | LOG_SELECT("", "Buzzer", this->buzzer_select_); 301 | LOG_SELECT("", "Charge energy priority", this->charge_energy_priority_select_); 302 | LOG_SELECT("", "Fault record", this->fault_record_select_); 303 | LOG_SELECT("", "Frequency", this->frequency_select_); 304 | LOG_SELECT("", "Grid voltage range", this->grid_voltage_range_select_); 305 | LOG_SELECT("", "On grid", this->on_grid_select_); 306 | LOG_SELECT("", "Output energy priority", this->output_energy_priority_select_); 307 | LOG_SELECT("", "Overload restart", this->overload_restart_select_); 308 | LOG_SELECT("", "Overtemp restart", this->overtemp_restart_select_); 309 | LOG_SELECT("", "Parallel operation", this->parallel_operation_select_); 310 | LOG_SELECT("", "Phase", this->phase_select_); 311 | LOG_SELECT("", "Power buzzer", this->power_buzzer_select_); 312 | LOG_SELECT("", "Powersave mode", this->powersave_mode_select_); 313 | LOG_SELECT("", "Warning buzer", this->warning_buzer_select_); 314 | #endif 315 | 316 | #ifdef USE_NUMBER 317 | LOG_NUMBER("", "Battery back to util voltage", this->battery_back_to_util_voltage_number_); 318 | LOG_NUMBER("", "Battery bulk voltage", this->battery_bulk_voltage_number_); 319 | LOG_NUMBER("", "Battery float voltage", this->battery_float_voltage_number_); 320 | LOG_NUMBER("", "Battery charge cut-off current", this->battery_charge_cut_off_current_number_); 321 | LOG_NUMBER("", "Battery cut-off voltage", this->battery_cut_off_voltage_number_); 322 | LOG_NUMBER("", "Battery equalization interval", this->battery_equalization_interval_number_); 323 | LOG_NUMBER("", "Battery equalization time", this->battery_equalization_time_number_); 324 | LOG_NUMBER("", "Battery equalization timeout", this->battery_equalization_timeout_number_); 325 | LOG_NUMBER("", "Battery equalization voltage", this->battery_equalization_voltage_number_); 326 | LOG_NUMBER("", "Inverter maximum power", this->inverter_maximum_power_number_); 327 | LOG_NUMBER("", "Output frequency", this->output_frequency_number_); 328 | LOG_NUMBER("", "Output voltage", this->output_voltage_number_); 329 | LOG_NUMBER("", "Total charge current", this->total_charge_current_number_); 330 | LOG_NUMBER("", "Util charge current", this->util_charge_current_number_); 331 | #endif 332 | } 333 | 334 | void Inv8851::request_state_() { 335 | this->write_array({0x88, 0x51, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x08}); 336 | } 337 | 338 | void Inv8851::request_config_() { 339 | this->write_array({0x88, 0x51, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x4c, 0xb0}); 340 | } 341 | 342 | void Inv8851::publish_state_(const uint8_t *resp) { 343 | inv8851_state_s *state = (inv8851_state_s *) resp; 344 | #ifdef USE_BINARY_SENSOR 345 | PUBLISH_STATE(this->battery_binary_sensor_, !state->no_battery); 346 | PUBLISH_STATE(this->buck_topology_initialization_binary_sensor_, !!state->buck_topology_initial_finished); 347 | PUBLISH_STATE(this->bus_binary_sensor_, !!state->bus_ok); 348 | PUBLISH_STATE(this->bus_and_grid_voltage_match_binary_sensor_, !!state->bus_n_grid_voltage_match); 349 | PUBLISH_STATE(this->charging_binary_sensor_, !state->charge_finish); 350 | PUBLISH_STATE(this->disable_utility_binary_sensor_, !!state->disable_utility); 351 | PUBLISH_STATE(this->equalization_finished_binary_sensor_, !!state->eq_charge_ready); 352 | PUBLISH_STATE(this->equalization_started_binary_sensor_, !!state->eq_charge_start); 353 | PUBLISH_STATE(this->float_charging_binary_sensor_, !!state->floating_charge); 354 | PUBLISH_STATE(this->grid_pll_binary_sensor_, !!state->grid_pll_ok); 355 | PUBLISH_STATE(this->inverter_topology_initialization_binary_sensor_, !!state->inverter_topology_initial_finished); 356 | PUBLISH_STATE(this->llc_topology_initialization_binary_sensor_, !!state->llc_topology_initial_finished); 357 | PUBLISH_STATE(this->parallel_lock_phase_binary_sensor_, !!state->parallel_lock_phase_ok); 358 | PUBLISH_STATE(this->pv_excess_binary_sensor_, !!state->pv_excess); 359 | PUBLISH_STATE(this->pv_input_binary_sensor_, !!state->pv_input_ok); 360 | PUBLISH_STATE(this->pv_topology_initialization_binary_sensor_, !!state->pv_topology_initial_finished); 361 | PUBLISH_STATE(this->system_initialization_binary_sensor_, !!state->system_initial_finished); 362 | PUBLISH_STATE(this->system_power_binary_sensor_, !!state->system_power); 363 | #endif 364 | 365 | #ifdef USE_TEXT_SENSOR 366 | PUBLISH_STATE(this->buck_topology_text_sensor_, run_mode_options[state->buck_topology]); 367 | PUBLISH_STATE(this->inverter_topology_text_sensor_, run_mode_options[state->inverter_topology]); 368 | PUBLISH_STATE(this->llc_topology_text_sensor_, run_mode_options[state->llc_topology]); 369 | PUBLISH_STATE(this->pv_topology_text_sensor_, run_mode_options[state->pv_topology]); 370 | #endif 371 | 372 | #ifdef USE_SENSOR 373 | PUBLISH_STATE(this->battery_charge_current_sensor_, state->batt_charge_current / 10.0f); 374 | PUBLISH_STATE(this->battery_voltage_sensor_, state->batt_voltage / 100.0f); 375 | PUBLISH_STATE(this->bms_battery_current_sensor_, state->bms_battery_current / 10.0f); 376 | PUBLISH_STATE(this->bms_battery_soc_sensor_, state->bms_battery_soc); 377 | PUBLISH_STATE(this->bms_battery_voltage_sensor_, state->bms_battery_voltage / 100.0f); 378 | PUBLISH_STATE(this->bms_cell_01_voltage_sensor_, state->bms_01cell_voltage / 100.0f); 379 | PUBLISH_STATE(this->bms_cell_02_voltage_sensor_, state->bms_02cell_voltage / 100.0f); 380 | PUBLISH_STATE(this->bms_cell_03_voltage_sensor_, state->bms_03cell_voltage / 100.0f); 381 | PUBLISH_STATE(this->bms_cell_04_voltage_sensor_, state->bms_04cell_voltage / 100.0f); 382 | PUBLISH_STATE(this->bms_cell_05_voltage_sensor_, state->bms_05cell_voltage / 100.0f); 383 | PUBLISH_STATE(this->bms_cell_06_voltage_sensor_, state->bms_06cell_voltage / 100.0f); 384 | PUBLISH_STATE(this->bms_cell_07_voltage_sensor_, state->bms_07cell_voltage / 100.0f); 385 | PUBLISH_STATE(this->bms_cell_08_voltage_sensor_, state->bms_08cell_voltage / 100.0f); 386 | PUBLISH_STATE(this->bms_cell_09_voltage_sensor_, state->bms_09cell_voltage / 100.0f); 387 | PUBLISH_STATE(this->bms_cell_10_voltage_sensor_, state->bms_10cell_voltage / 100.0f); 388 | PUBLISH_STATE(this->bms_cell_11_voltage_sensor_, state->bms_11cell_voltage / 100.0f); 389 | PUBLISH_STATE(this->bms_cell_12_voltage_sensor_, state->bms_12cell_voltage / 100.0f); 390 | PUBLISH_STATE(this->bms_cell_13_voltage_sensor_, state->bms_13cell_voltage / 100.0f); 391 | PUBLISH_STATE(this->bms_cell_14_voltage_sensor_, state->bms_14cell_voltage / 100.0f); 392 | PUBLISH_STATE(this->bms_cell_15_voltage_sensor_, state->bms_15cell_voltage / 100.0f); 393 | PUBLISH_STATE(this->bms_cell_16_voltage_sensor_, state->bms_16cell_voltage / 100.0f); 394 | PUBLISH_STATE(this->bts_temperature_sensor_, state->bts_temperature); 395 | PUBLISH_STATE(this->bus_voltage_sensor_, state->bus_voltage / 10.0f); 396 | PUBLISH_STATE(this->fan1_speed_percentage_sensor_, state->fan1_speed_percent); 397 | PUBLISH_STATE(this->fan2_speed_percentage_sensor_, state->fan2_speed_percent); 398 | PUBLISH_STATE(this->grid_current_sensor_, state->grid_current / 100.0f); 399 | PUBLISH_STATE(this->grid_frequency_sensor_, state->grid_freq / 100.0f); 400 | PUBLISH_STATE(this->grid_voltage_sensor_, state->grid_voltage / 10.0f); 401 | PUBLISH_STATE(this->inverter_apparent_power_sensor_, state->inv_va); 402 | PUBLISH_STATE(this->inverter_apparent_power_percentage_sensor_, state->inverter_va_percent); 403 | PUBLISH_STATE(this->inverter_current_sensor_, state->inv_current / 100.0f); 404 | PUBLISH_STATE(this->inverter_frequency_sensor_, state->inv_freq / 100.0f); 405 | PUBLISH_STATE(this->inverter_power_percentage_sensor_, state->inverter_watt_percent); 406 | PUBLISH_STATE(this->inverter_software_version_sensor_, state->software_version); 407 | PUBLISH_STATE(this->inverter_voltage_sensor_, state->inv_voltage / 10.0f); 408 | PUBLISH_STATE(this->inverter_voltage_dc_component_sensor_, state->inverter_voltage_dc_component); 409 | PUBLISH_STATE(this->load_apparent_power_sensor_, state->load_va); 410 | PUBLISH_STATE(this->load_current_sensor_, state->load_current / 100.0f); 411 | PUBLISH_STATE(this->load_power_sensor_, state->load_watt); 412 | PUBLISH_STATE(this->log_number_sensor_, state->log_number); 413 | PUBLISH_STATE(this->low_load_current_sensor_, state->low_load_current / 100.0f); 414 | PUBLISH_STATE(this->ntc2_temperature_sensor_, state->ntc2_temperature); 415 | PUBLISH_STATE(this->ntc3_temperature_sensor_, state->ntc3_temperature); 416 | PUBLISH_STATE(this->ntc4_temperature_sensor_, state->ntc4_temperature); 417 | PUBLISH_STATE(this->parallel_current_sensor_, state->parallel_current / 100.0f); 418 | PUBLISH_STATE(this->parallel_frequency_sensor_, state->parallel_frequency / 100.0f); 419 | PUBLISH_STATE(this->parallel_voltage_sensor_, state->parallel_voltage / 10.0f); 420 | PUBLISH_STATE(this->pv_current_sensor_, state->pv_current / 100.0f); 421 | PUBLISH_STATE(this->pv_power_sensor_, state->pv_power); 422 | PUBLISH_STATE(this->pv_voltage_sensor_, state->pv_voltage / 10.0f); 423 | #endif 424 | } 425 | 426 | void Inv8851::publish_config_(const uint8_t *resp) { 427 | memcpy(&this->config_, resp, inv8851_config_pkt_len); 428 | inv8851_config_s *config = (inv8851_config_s *) resp; 429 | #ifdef USE_SELECT 430 | PUBLISH_STATE(this->auto_return_select_, off_on_options[config->auto_return_to_default_screen]); 431 | PUBLISH_STATE(this->backlight_select_, off_on_options[config->backlight_on]); 432 | PUBLISH_STATE(this->battery_equalization_select_, off_on_options[config->battery_equalization]); 433 | PUBLISH_STATE(this->battery_type_select_, battery_type_options[config->battery_type]); 434 | PUBLISH_STATE(this->buzzer_select_, off_on_options[config->alarm_control]); 435 | PUBLISH_STATE(this->charge_energy_priority_select_, charge_energy_priority_options[config->charge_energy_priority]); 436 | PUBLISH_STATE(this->fault_record_select_, off_on_options[config->fault_record_enable]); 437 | PUBLISH_STATE(this->frequency_select_, frequency_options[config->frequency]); 438 | PUBLISH_STATE(this->grid_voltage_range_select_, grid_voltage_range_options[config->grid_voltage_range]); 439 | PUBLISH_STATE(this->on_grid_select_, off_on_options[config->grid_enable]); 440 | PUBLISH_STATE(this->output_energy_priority_select_, output_energy_priority_options[config->output_energy_priority]); 441 | PUBLISH_STATE(this->overload_restart_select_, off_on_options[config->output_OPP_auto_restart]); 442 | PUBLISH_STATE(this->overtemp_restart_select_, off_on_options[config->otp_auto_restart]); 443 | PUBLISH_STATE(this->parallel_operation_select_, off_on_options[config->parallel_operation]); 444 | PUBLISH_STATE(this->phase_select_, phase_options[config->phase]); 445 | PUBLISH_STATE(this->power_buzzer_select_, off_on_options[config->energy_interrupt_buzzer_on]); 446 | PUBLISH_STATE(this->powersave_mode_select_, off_on_options[config->powersave_on]); 447 | PUBLISH_STATE(this->warning_buzer_select_, off_on_options[config->warning_flag_buzer_on]); 448 | #endif 449 | 450 | #ifdef USE_NUMBER 451 | PUBLISH_STATE(this->battery_back_to_util_voltage_number_, config->batt_pont_back_to_util_volt / 100.0f); 452 | PUBLISH_STATE(this->battery_bulk_voltage_number_, config->batt_bulk_chg_voltage / 100.0f); 453 | PUBLISH_STATE(this->battery_float_voltage_number_, config->batt_float_chg_voltage / 100.0f); 454 | PUBLISH_STATE(this->battery_charge_cut_off_current_number_, config->batt_chg_cut_off_current / 10.0f); 455 | PUBLISH_STATE(this->battery_cut_off_voltage_number_, config->batt_cut_off_voltage / 100.0f); 456 | PUBLISH_STATE(this->battery_equalization_interval_number_, config->batt_eq_interval); 457 | PUBLISH_STATE(this->battery_equalization_time_number_, config->batt_eq_time); 458 | PUBLISH_STATE(this->battery_equalization_timeout_number_, config->batt_eq_timeout); 459 | PUBLISH_STATE(this->battery_equalization_voltage_number_, config->batt_eq_voltage / 100.0f); 460 | PUBLISH_STATE(this->inverter_maximum_power_number_, config->inverter_max_power); 461 | PUBLISH_STATE(this->output_frequency_number_, config->output_freq / 100.f); 462 | PUBLISH_STATE(this->output_voltage_number_, config->output_voltage / 10.0f); 463 | PUBLISH_STATE(this->total_charge_current_number_, config->total_chg_current / 10.0f); 464 | PUBLISH_STATE(this->util_charge_current_number_, config->util_chg_current / 10.0f); 465 | #endif 466 | } 467 | 468 | void Inv8851::set_select_value(const std::string type, size_t index) { 469 | if (type == "auto_return") this->config_.auto_return_to_default_screen = index; 470 | else if (type == "backlight") this->config_.backlight_on = index; 471 | else if (type == "battery_equalization") this->config_.battery_equalization = index; 472 | else if (type == "battery_type") this->config_.battery_type = index; 473 | else if (type == "buzzer") this->config_.alarm_control = index; 474 | else if (type == "charge_energy_priority") this->config_.charge_energy_priority = index; 475 | else if (type == "fault_record") this->config_.fault_record_enable = index; 476 | else if (type == "frequency") this->config_.frequency = index; 477 | else if (type == "grid_voltage_range") this->config_.grid_voltage_range = index; 478 | else if (type == "on_grid") this->config_.grid_enable = index; 479 | else if (type == "output_energy_priority") this->config_.output_energy_priority = index; 480 | else if (type == "overload_restart") this->config_.output_OPP_auto_restart = index; 481 | else if (type == "overtemp_restart") this->config_.otp_auto_restart = index; 482 | else if (type == "parallel_operation") this->config_.parallel_operation = index; 483 | else if (type == "phase") this->config_.phase = index; 484 | else if (type == "power_buzzer") this->config_.energy_interrupt_buzzer_on = index; 485 | else if (type == "powersave_mode") this->config_.powersave_on = index; 486 | else if (type == "warning_buzer") this->config_.warning_flag_buzer_on = index; 487 | else return; 488 | 489 | this->write_config_(); 490 | } 491 | 492 | void Inv8851::set_number_value(const std::string type, float value) { 493 | if (type == "battery_back_to_util_voltage") this->config_.batt_pont_back_to_util_volt = value * 100.0f; 494 | else if (type == "battery_bulk_voltage") this->config_.batt_bulk_chg_voltage = value * 100.0f; 495 | else if (type == "battery_float_voltage") this->config_.batt_float_chg_voltage = value * 100.0f; 496 | else if (type == "battery_charge_cut_off_current") this->config_.batt_chg_cut_off_current = value * 10.0f; 497 | else if (type == "battery_cut_off_voltage") this->config_.batt_cut_off_voltage = value * 100.0f; 498 | else if (type == "battery_equalization_interval") this->config_.batt_eq_interval = value; 499 | else if (type == "battery_equalization_time") this->config_.batt_eq_time = value; 500 | else if (type == "battery_equalization_timeout") this->config_.batt_eq_timeout = value; 501 | else if (type == "battery_equalization_voltage") this->config_.batt_eq_voltage = value * 100.0f; 502 | else if (type == "inverter_maximum_power") this->config_.inverter_max_power = value; 503 | else if (type == "output_frequency") this->config_.output_freq = value * 100.0f; 504 | else if (type == "output_voltage") this->config_.output_voltage = value * 10.0f; 505 | else if (type == "total_charge_current") this->config_.total_chg_current = value * 10.0f; 506 | else if (type == "util_charge_current") this->config_.util_chg_current = value * 10.0f; 507 | else return; 508 | 509 | this->write_config_(); 510 | } 511 | 512 | } // namespace inv_8851 513 | } // namespace esphome 514 | -------------------------------------------------------------------------------- /components/inv_8851/inv_8851.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "inv8851.h" 4 | #include "esphome/core/component.h" 5 | #include "esphome/components/uart/uart.h" 6 | 7 | #ifdef USE_BINARY_SENSOR 8 | #include "esphome/components/binary_sensor/binary_sensor.h" 9 | #endif 10 | #ifdef USE_TEXT_SENSOR 11 | #include "esphome/components/text_sensor/text_sensor.h" 12 | #endif 13 | #ifdef USE_SENSOR 14 | #include "esphome/components/sensor/sensor.h" 15 | #endif 16 | #ifdef USE_SELECT 17 | #include "esphome/components/select/select.h" 18 | #endif 19 | #ifdef USE_NUMBER 20 | #include "esphome/components/number/number.h" 21 | #endif 22 | 23 | namespace esphome { 24 | namespace inv_8851 { 25 | 26 | static const char *const TAG = "inv_8851"; 27 | enum Protocol { INV8851_PROTOCOL, UNKNOWN_PROTOCOL }; 28 | enum Command { READ_COMMAND, WRITE_COMMAND, UNKNOWN_COMMAND }; 29 | enum Address { STATE_ADDRESS, CONFIG_ADDRESS, UNKNOWN_ADDRESS }; 30 | enum BatteryType { AGM = 0, FLOODED = 1, USER = 2, LIB = 3 }; 31 | enum ChargeEnergyPriority { CSO = 0, SNU = 1, OSO = 2 }; 32 | enum Frequency { FIFTY = 0, SIXTY = 1 }; 33 | enum GridVoltageRange { UPS = 0, APL = 1 }; 34 | enum OffOn { OFF = 0, ON = 1 }; 35 | enum OutputEnergyPriority { SUB = 0, SBU = 1 }; 36 | enum Phase { A = 0, B = 1, C = 2 }; 37 | 38 | class Inv8851 : public PollingComponent, public uart::UARTDevice { 39 | public: 40 | #ifdef USE_BINARY_SENSOR 41 | SUB_BINARY_SENSOR(battery) 42 | SUB_BINARY_SENSOR(buck_topology_initialization) 43 | SUB_BINARY_SENSOR(bus) 44 | SUB_BINARY_SENSOR(bus_and_grid_voltage_match) 45 | SUB_BINARY_SENSOR(charging) 46 | SUB_BINARY_SENSOR(disable_utility) 47 | SUB_BINARY_SENSOR(equalization_finished) 48 | SUB_BINARY_SENSOR(equalization_started) 49 | SUB_BINARY_SENSOR(float_charging) 50 | SUB_BINARY_SENSOR(grid_pll) 51 | SUB_BINARY_SENSOR(inverter_topology_initialization) 52 | SUB_BINARY_SENSOR(llc_topology_initialization) 53 | SUB_BINARY_SENSOR(parallel_lock_phase) 54 | SUB_BINARY_SENSOR(pv_excess) 55 | SUB_BINARY_SENSOR(pv_input) 56 | SUB_BINARY_SENSOR(pv_topology_initialization) 57 | SUB_BINARY_SENSOR(system_initialization) 58 | SUB_BINARY_SENSOR(system_power) 59 | #endif 60 | 61 | #ifdef USE_TEXT_SENSOR 62 | SUB_TEXT_SENSOR(buck_topology) 63 | SUB_TEXT_SENSOR(inverter_topology) 64 | SUB_TEXT_SENSOR(llc_topology) 65 | SUB_TEXT_SENSOR(pv_topology) 66 | #endif 67 | 68 | #ifdef USE_SENSOR 69 | SUB_SENSOR(battery_charge_current) 70 | SUB_SENSOR(battery_voltage) 71 | SUB_SENSOR(bms_battery_current) 72 | SUB_SENSOR(bms_battery_soc) 73 | SUB_SENSOR(bms_battery_voltage) 74 | SUB_SENSOR(bms_cell_01_voltage) 75 | SUB_SENSOR(bms_cell_02_voltage) 76 | SUB_SENSOR(bms_cell_03_voltage) 77 | SUB_SENSOR(bms_cell_04_voltage) 78 | SUB_SENSOR(bms_cell_05_voltage) 79 | SUB_SENSOR(bms_cell_06_voltage) 80 | SUB_SENSOR(bms_cell_07_voltage) 81 | SUB_SENSOR(bms_cell_08_voltage) 82 | SUB_SENSOR(bms_cell_09_voltage) 83 | SUB_SENSOR(bms_cell_10_voltage) 84 | SUB_SENSOR(bms_cell_11_voltage) 85 | SUB_SENSOR(bms_cell_12_voltage) 86 | SUB_SENSOR(bms_cell_13_voltage) 87 | SUB_SENSOR(bms_cell_14_voltage) 88 | SUB_SENSOR(bms_cell_15_voltage) 89 | SUB_SENSOR(bms_cell_16_voltage) 90 | SUB_SENSOR(bts_temperature) 91 | SUB_SENSOR(bus_voltage) 92 | SUB_SENSOR(fan1_speed_percentage) 93 | SUB_SENSOR(fan2_speed_percentage) 94 | SUB_SENSOR(grid_current) 95 | SUB_SENSOR(grid_frequency) 96 | SUB_SENSOR(grid_voltage) 97 | SUB_SENSOR(inverter_apparent_power) 98 | SUB_SENSOR(inverter_apparent_power_percentage) 99 | SUB_SENSOR(inverter_current) 100 | SUB_SENSOR(inverter_frequency) 101 | SUB_SENSOR(inverter_power_percentage) 102 | SUB_SENSOR(inverter_software_version) 103 | SUB_SENSOR(inverter_voltage) 104 | SUB_SENSOR(inverter_voltage_dc_component) 105 | SUB_SENSOR(load_apparent_power) 106 | SUB_SENSOR(load_current) 107 | SUB_SENSOR(load_power) 108 | SUB_SENSOR(log_number) 109 | SUB_SENSOR(low_load_current) 110 | SUB_SENSOR(ntc2_temperature) 111 | SUB_SENSOR(ntc3_temperature) 112 | SUB_SENSOR(ntc4_temperature) 113 | SUB_SENSOR(parallel_current) 114 | SUB_SENSOR(parallel_frequency) 115 | SUB_SENSOR(parallel_voltage) 116 | SUB_SENSOR(pv_current) 117 | SUB_SENSOR(pv_power) 118 | SUB_SENSOR(pv_voltage) 119 | #endif 120 | 121 | #ifdef USE_SELECT 122 | SUB_SELECT(auto_return) 123 | SUB_SELECT(backlight) 124 | SUB_SELECT(battery_equalization) 125 | SUB_SELECT(battery_type) 126 | SUB_SELECT(buzzer) 127 | SUB_SELECT(charge_energy_priority) 128 | SUB_SELECT(fault_record) 129 | SUB_SELECT(frequency) 130 | SUB_SELECT(grid_voltage_range) 131 | SUB_SELECT(on_grid) 132 | SUB_SELECT(output_energy_priority) 133 | SUB_SELECT(overload_restart) 134 | SUB_SELECT(overtemp_restart) 135 | SUB_SELECT(parallel_operation) 136 | SUB_SELECT(phase) 137 | SUB_SELECT(power_buzzer) 138 | SUB_SELECT(powersave_mode) 139 | SUB_SELECT(warning_buzer) 140 | #endif 141 | 142 | #ifdef USE_NUMBER 143 | SUB_NUMBER(battery_back_to_util_voltage) 144 | SUB_NUMBER(battery_bulk_voltage) 145 | SUB_NUMBER(battery_float_voltage) 146 | SUB_NUMBER(battery_charge_cut_off_current) 147 | SUB_NUMBER(battery_cut_off_voltage) 148 | SUB_NUMBER(battery_equalization_interval) 149 | SUB_NUMBER(battery_equalization_time) 150 | SUB_NUMBER(battery_equalization_timeout) 151 | SUB_NUMBER(battery_equalization_voltage) 152 | SUB_NUMBER(inverter_maximum_power) 153 | SUB_NUMBER(output_frequency) 154 | SUB_NUMBER(output_voltage) 155 | SUB_NUMBER(total_charge_current) 156 | SUB_NUMBER(util_charge_current) 157 | #endif 158 | 159 | void setup() override; 160 | 161 | void loop() override; 162 | 163 | void update() override; 164 | 165 | void dump_config() override; 166 | 167 | void set_select_value(const std::string type, size_t index); 168 | 169 | void set_number_value(const std::string type, float value); 170 | 171 | protected: 172 | #define PUBLISH_STATE(entity, state) \ 173 | if (entity != nullptr) entity->publish_state(state); 174 | 175 | void clear_buffer_(); 176 | 177 | Protocol read_protocol_(); 178 | 179 | Command read_command_(); 180 | 181 | Address read_address_(); 182 | 183 | esphome::optional read_data_size_(); 184 | 185 | esphome::optional>read_data_(const uint16_t size); 186 | 187 | bool read_crc16_(const uint8_t *data, const uint8_t len); 188 | 189 | void write_config_(); 190 | 191 | void request_state_(); 192 | 193 | void request_config_(); 194 | 195 | void publish_state_(const uint8_t *resp); 196 | 197 | void publish_config_(const uint8_t *resp); 198 | 199 | inv8851_config_s config_; 200 | 201 | bool state_update_ = true; 202 | 203 | uint32_t last_read_{0}; 204 | }; 205 | 206 | } // namespace inv_8851 207 | } // namespace esphome 208 | -------------------------------------------------------------------------------- /components/inv_8851/inv_8851_number.cpp: -------------------------------------------------------------------------------- 1 | #include "inv_8851_number.h" 2 | #include "esphome/core/log.h" 3 | 4 | namespace esphome { 5 | namespace inv_8851 { 6 | 7 | void Inv8851Number::control(float value) { 8 | this->parent_->set_number_value(this->type_, value); 9 | } 10 | 11 | } // namespace inv_8851 12 | } // namespace esphome 13 | -------------------------------------------------------------------------------- /components/inv_8851/inv_8851_number.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "inv_8851.h" 4 | #include "esphome/core/component.h" 5 | #include "esphome/components/number/number.h" 6 | 7 | namespace esphome { 8 | namespace inv_8851 { 9 | 10 | class Inv8851Number : public number::Number { 11 | public: 12 | void set_parent(Inv8851 *parent) { this->parent_ = parent; } 13 | void set_type(const std::string type) { this->type_ = type; } 14 | 15 | protected: 16 | void control(float value) override; 17 | 18 | Inv8851 *parent_; 19 | std::string type_; 20 | }; 21 | 22 | } // namespace inv_8851 23 | } // namespace esphome 24 | -------------------------------------------------------------------------------- /components/inv_8851/inv_8851_select.cpp: -------------------------------------------------------------------------------- 1 | #include "inv_8851_select.h" 2 | #include "esphome/core/log.h" 3 | 4 | namespace esphome { 5 | namespace inv_8851 { 6 | 7 | void Inv8851Select::control(const std::string &value) { 8 | auto index = this->index_of(value); 9 | if (index.has_value()) this->parent_->set_select_value(this->type_, index.value()); 10 | else ESP_LOGE(TAG, "There is no %s option for %s select.", value, this->type_); 11 | } 12 | 13 | } // namespace inv_8851 14 | } // namespace esphome 15 | -------------------------------------------------------------------------------- /components/inv_8851/inv_8851_select.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "inv_8851.h" 4 | #include "esphome/core/component.h" 5 | #include "esphome/components/select/select.h" 6 | 7 | namespace esphome { 8 | namespace inv_8851 { 9 | 10 | class Inv8851Select : public select::Select { 11 | public: 12 | void set_parent(Inv8851 *parent) { this->parent_ = parent; } 13 | void set_type(const std::string type) { this->type_ = type; } 14 | 15 | protected: 16 | void control(const std::string &value) override; 17 | 18 | Inv8851 *parent_; 19 | std::string type_; 20 | }; 21 | 22 | } // namespace inv_8851 23 | } // namespace esphome 24 | -------------------------------------------------------------------------------- /components/inv_8851/number.py: -------------------------------------------------------------------------------- 1 | import esphome.codegen as cg 2 | import esphome.config_validation as cv 3 | from esphome.components import number 4 | from esphome.const import ( 5 | CONF_MAX_VALUE, 6 | CONF_MIN_VALUE, 7 | CONF_PLATFORM, 8 | CONF_STEP, 9 | DEVICE_CLASS_CURRENT, 10 | DEVICE_CLASS_FREQUENCY, 11 | DEVICE_CLASS_POWER, 12 | DEVICE_CLASS_VOLTAGE, 13 | ENTITY_CATEGORY_CONFIG, 14 | UNIT_AMPERE, 15 | UNIT_HERTZ, 16 | UNIT_MINUTE, 17 | UNIT_VOLT, 18 | UNIT_WATT, 19 | ) 20 | 21 | from . import ( 22 | inv_8851_ns, 23 | Inv8851, 24 | CONF_INV_8851_ID, 25 | ) 26 | 27 | DEPENDENCIES = ["inv_8851"] 28 | 29 | CODEOWNERS = ["@lufton"] 30 | 31 | CONF_BATTERY_BACK_TO_UTIL_VOLTAGE = "battery_back_to_util_voltage" 32 | CONF_BATTERY_BULK_VOLTAGE = "battery_bulk_voltage" 33 | CONF_BATTERY_FLOAT_VOLTAGE = "battery_float_voltage" 34 | CONF_BATTERY_CUT_OFF_CURRENT = "battery_charge_cut_off_current" 35 | CONF_BATTERY_CUT_OFF_VOLTAGE = "battery_cut_off_voltage" 36 | CONF_BATTERY_EQUALIZATION_INTERVAL = "battery_equalization_interval" 37 | CONF_BATTERY_EQUALIZATION_TIME = "battery_equalization_time" 38 | CONF_BATTERY_EQUALIZATION_TIMEOUT = "battery_equalization_timeout" 39 | CONF_BATTERY_EQUALIZATION_VOLTAGE = "battery_equalization_voltage" 40 | CONF_INVERTER_MAXIMUM_POWER = "inverter_maximum_power" 41 | CONF_OUTPUT_FREQUENCY = "output_frequency" 42 | CONF_OUTPUT_VOLTAGE = "output_voltage" 43 | CONF_TOTAL_CHARGE_CURRENT = "total_charge_current" 44 | CONF_UTIL_CHARGE_CURRENT = "util_charge_current" 45 | 46 | Inv8851Number = inv_8851_ns.class_("Inv8851Number", number.Number, cg.Component) 47 | 48 | NUMBER_SCHEMA = cv.Schema( 49 | { 50 | cv.Required(CONF_MAX_VALUE): cv.positive_float, 51 | cv.Required(CONF_MIN_VALUE): cv.positive_float, 52 | cv.Required(CONF_STEP): cv.positive_float, 53 | } 54 | ) 55 | 56 | CONFIG_SCHEMA = ( 57 | cv.Schema( 58 | { 59 | cv.GenerateID(CONF_INV_8851_ID): cv.use_id(Inv8851), 60 | cv.Optional(CONF_BATTERY_BACK_TO_UTIL_VOLTAGE): number.number_schema(Inv8851Number, 61 | unit_of_measurement=UNIT_VOLT, 62 | device_class=DEVICE_CLASS_VOLTAGE, 63 | entity_category=ENTITY_CATEGORY_CONFIG, 64 | ).extend(NUMBER_SCHEMA), 65 | cv.Optional(CONF_BATTERY_BULK_VOLTAGE): number.number_schema(Inv8851Number, 66 | unit_of_measurement=UNIT_VOLT, 67 | device_class=DEVICE_CLASS_VOLTAGE, 68 | entity_category=ENTITY_CATEGORY_CONFIG, 69 | ).extend(NUMBER_SCHEMA), 70 | cv.Optional(CONF_BATTERY_FLOAT_VOLTAGE): number.number_schema(Inv8851Number, 71 | unit_of_measurement=UNIT_VOLT, 72 | device_class=DEVICE_CLASS_VOLTAGE, 73 | entity_category=ENTITY_CATEGORY_CONFIG, 74 | ).extend(NUMBER_SCHEMA), 75 | cv.Optional(CONF_BATTERY_CUT_OFF_CURRENT): number.number_schema(Inv8851Number, 76 | unit_of_measurement=UNIT_AMPERE, 77 | device_class=DEVICE_CLASS_CURRENT, 78 | entity_category=ENTITY_CATEGORY_CONFIG, 79 | ).extend(NUMBER_SCHEMA), 80 | cv.Optional(CONF_BATTERY_CUT_OFF_VOLTAGE): number.number_schema(Inv8851Number, 81 | unit_of_measurement=UNIT_VOLT, 82 | device_class=DEVICE_CLASS_VOLTAGE, 83 | entity_category=ENTITY_CATEGORY_CONFIG, 84 | ).extend(NUMBER_SCHEMA), 85 | cv.Optional(CONF_BATTERY_EQUALIZATION_INTERVAL): number.number_schema(Inv8851Number, 86 | entity_category=ENTITY_CATEGORY_CONFIG, 87 | ).extend(NUMBER_SCHEMA), 88 | cv.Optional(CONF_BATTERY_EQUALIZATION_TIME): number.number_schema(Inv8851Number, 89 | unit_of_measurement=UNIT_MINUTE, 90 | entity_category=ENTITY_CATEGORY_CONFIG, 91 | ).extend(NUMBER_SCHEMA), 92 | cv.Optional(CONF_BATTERY_EQUALIZATION_TIMEOUT): number.number_schema(Inv8851Number, 93 | unit_of_measurement=UNIT_MINUTE, 94 | entity_category=ENTITY_CATEGORY_CONFIG, 95 | ).extend(NUMBER_SCHEMA), 96 | cv.Optional(CONF_BATTERY_EQUALIZATION_VOLTAGE): number.number_schema(Inv8851Number, 97 | unit_of_measurement=UNIT_VOLT, 98 | device_class=DEVICE_CLASS_VOLTAGE, 99 | entity_category=ENTITY_CATEGORY_CONFIG, 100 | ).extend(NUMBER_SCHEMA), 101 | cv.Optional(CONF_INVERTER_MAXIMUM_POWER): number.number_schema(Inv8851Number, 102 | unit_of_measurement=UNIT_WATT, 103 | device_class=DEVICE_CLASS_POWER, 104 | entity_category=ENTITY_CATEGORY_CONFIG, 105 | ).extend(NUMBER_SCHEMA), 106 | cv.Optional(CONF_OUTPUT_FREQUENCY): number.number_schema(Inv8851Number, 107 | unit_of_measurement=UNIT_HERTZ, 108 | device_class=DEVICE_CLASS_FREQUENCY, 109 | entity_category=ENTITY_CATEGORY_CONFIG, 110 | ).extend(NUMBER_SCHEMA), 111 | cv.Optional(CONF_OUTPUT_VOLTAGE): number.number_schema(Inv8851Number, 112 | unit_of_measurement=UNIT_VOLT, 113 | device_class=DEVICE_CLASS_VOLTAGE, 114 | entity_category=ENTITY_CATEGORY_CONFIG, 115 | ).extend(NUMBER_SCHEMA), 116 | cv.Optional(CONF_TOTAL_CHARGE_CURRENT): number.number_schema(Inv8851Number, 117 | unit_of_measurement=UNIT_AMPERE, 118 | device_class=DEVICE_CLASS_CURRENT, 119 | entity_category=ENTITY_CATEGORY_CONFIG, 120 | ).extend(NUMBER_SCHEMA), 121 | cv.Optional(CONF_UTIL_CHARGE_CURRENT): number.number_schema(Inv8851Number, 122 | unit_of_measurement=UNIT_AMPERE, 123 | device_class=DEVICE_CLASS_CURRENT, 124 | entity_category=ENTITY_CATEGORY_CONFIG, 125 | ).extend(NUMBER_SCHEMA), 126 | } 127 | ) 128 | ) 129 | 130 | 131 | async def to_code(config): 132 | parent = await cg.get_variable(config.get(CONF_INV_8851_ID)) 133 | for option in config: 134 | if option not in [CONF_PLATFORM, CONF_INV_8851_ID] and (c := config.get(option)): 135 | num = await number.new_number(c, min_value=c.get(CONF_MIN_VALUE), max_value=c.get(CONF_MAX_VALUE), step=c.get(CONF_STEP)) 136 | cg.add(getattr(num, "set_parent")(parent)) 137 | cg.add(getattr(num, "set_type")(option)) 138 | cg.add(getattr(parent, f"set_{option}_number")(num)) 139 | -------------------------------------------------------------------------------- /components/inv_8851/select.py: -------------------------------------------------------------------------------- 1 | import esphome.codegen as cg 2 | import esphome.config_validation as cv 3 | from esphome.components import select 4 | from esphome.const import ( 5 | CONF_PLATFORM, 6 | ENTITY_CATEGORY_CONFIG, 7 | ) 8 | 9 | from . import ( 10 | inv_8851_ns, 11 | Inv8851, 12 | CONF_INV_8851_ID, 13 | ) 14 | 15 | DEPENDENCIES = ["inv_8851"] 16 | 17 | CODEOWNERS = ["@lufton"] 18 | 19 | CONF_AUTO_RETURN = "auto_return" 20 | CONF_BACKLIGHT = "backlight" 21 | CONF_BATTERY_EQUALIZATION = "battery_equalization" 22 | CONF_BATTERY_TYPE = "battery_type" 23 | CONF_BUZZER = "buzzer" 24 | CONF_CHARGE_ENERGY_PRIORITY = "charge_energy_priority" 25 | CONF_FAULT_RECORD = "fault_record" 26 | CONF_FREQUENCY = "frequency" 27 | CONF_GRID_VOLTAGE_RANGE = "grid_voltage_range" 28 | CONF_ON_GRID = "on_grid" 29 | CONF_OUTPUT_ENERGY_PRIORITY = "output_energy_priority" 30 | CONF_OVERLOAD_RESTART = "overload_restart" 31 | CONF_OVERTEMP_RESTART = "overtemp_restart" 32 | CONF_PARALLEL_OPERATION = "parallel_operation" 33 | CONF_PHASE = "phase" 34 | CONF_POWER_BUZZER = "power_buzzer" 35 | CONF_POWERSAVE_MODE = "powersave_mode" 36 | CONF_WARNING_BUZER = "warning_buzer" 37 | 38 | OFF_ON_OPTIONS = ["Off", "On"] 39 | OPTIONS = { 40 | CONF_AUTO_RETURN: OFF_ON_OPTIONS, 41 | CONF_BACKLIGHT: OFF_ON_OPTIONS, 42 | CONF_BATTERY_EQUALIZATION: OFF_ON_OPTIONS, 43 | CONF_BATTERY_TYPE: ["AGM", "Flooded", "User-defined", "Library"], 44 | CONF_BUZZER: OFF_ON_OPTIONS, 45 | CONF_CHARGE_ENERGY_PRIORITY: ["PV & Grid", "PV > Grid", "PV only"], 46 | CONF_FAULT_RECORD: OFF_ON_OPTIONS, 47 | CONF_FREQUENCY: ["50Hz", "60Hz"], 48 | CONF_GRID_VOLTAGE_RANGE: ["UPS", "APL"], 49 | CONF_ON_GRID: OFF_ON_OPTIONS, 50 | CONF_OUTPUT_ENERGY_PRIORITY: ["PV > Grid > Battery", "PV > Battery > Grid"], 51 | CONF_OVERLOAD_RESTART: OFF_ON_OPTIONS, 52 | CONF_OVERTEMP_RESTART: OFF_ON_OPTIONS, 53 | CONF_PARALLEL_OPERATION: OFF_ON_OPTIONS, 54 | CONF_PHASE: ["A", "B", "C"], 55 | CONF_POWER_BUZZER: OFF_ON_OPTIONS, 56 | CONF_POWERSAVE_MODE: OFF_ON_OPTIONS, 57 | CONF_WARNING_BUZER: OFF_ON_OPTIONS, 58 | } 59 | 60 | Inv8851Select = inv_8851_ns.class_("Inv8851Select", select.Select, cg.Component) 61 | 62 | CONFIG_SCHEMA = ( 63 | cv.Schema( 64 | { 65 | cv.GenerateID(CONF_INV_8851_ID): cv.use_id(Inv8851), 66 | cv.Optional(CONF_AUTO_RETURN): select.select_schema(Inv8851Select, 67 | entity_category=ENTITY_CATEGORY_CONFIG 68 | ), 69 | cv.Optional(CONF_BACKLIGHT): select.select_schema(Inv8851Select, 70 | entity_category=ENTITY_CATEGORY_CONFIG 71 | ), 72 | cv.Optional(CONF_BATTERY_EQUALIZATION): select.select_schema(Inv8851Select, 73 | entity_category=ENTITY_CATEGORY_CONFIG 74 | ), 75 | cv.Optional(CONF_BATTERY_TYPE): select.select_schema(Inv8851Select, 76 | entity_category=ENTITY_CATEGORY_CONFIG 77 | ), 78 | cv.Optional(CONF_BUZZER): select.select_schema(Inv8851Select, 79 | entity_category=ENTITY_CATEGORY_CONFIG 80 | ), 81 | cv.Optional(CONF_CHARGE_ENERGY_PRIORITY): select.select_schema(Inv8851Select, 82 | entity_category=ENTITY_CATEGORY_CONFIG 83 | ), 84 | cv.Optional(CONF_FAULT_RECORD): select.select_schema(Inv8851Select, 85 | entity_category=ENTITY_CATEGORY_CONFIG 86 | ), 87 | cv.Optional(CONF_FREQUENCY): select.select_schema(Inv8851Select, 88 | entity_category=ENTITY_CATEGORY_CONFIG 89 | ), 90 | cv.Optional(CONF_GRID_VOLTAGE_RANGE): select.select_schema(Inv8851Select, 91 | entity_category=ENTITY_CATEGORY_CONFIG 92 | ), 93 | cv.Optional(CONF_ON_GRID): select.select_schema(Inv8851Select, 94 | entity_category=ENTITY_CATEGORY_CONFIG 95 | ), 96 | cv.Optional(CONF_OUTPUT_ENERGY_PRIORITY): select.select_schema(Inv8851Select, 97 | entity_category=ENTITY_CATEGORY_CONFIG 98 | ), 99 | cv.Optional(CONF_OVERLOAD_RESTART): select.select_schema(Inv8851Select, 100 | entity_category=ENTITY_CATEGORY_CONFIG 101 | ), 102 | cv.Optional(CONF_OVERTEMP_RESTART): select.select_schema(Inv8851Select, 103 | entity_category=ENTITY_CATEGORY_CONFIG 104 | ), 105 | cv.Optional(CONF_PARALLEL_OPERATION): select.select_schema(Inv8851Select, 106 | entity_category=ENTITY_CATEGORY_CONFIG 107 | ), 108 | cv.Optional(CONF_PHASE): select.select_schema(Inv8851Select, 109 | entity_category=ENTITY_CATEGORY_CONFIG 110 | ), 111 | cv.Optional(CONF_POWER_BUZZER): select.select_schema(Inv8851Select, 112 | entity_category=ENTITY_CATEGORY_CONFIG 113 | ), 114 | cv.Optional(CONF_POWERSAVE_MODE): select.select_schema(Inv8851Select, 115 | entity_category=ENTITY_CATEGORY_CONFIG 116 | ), 117 | cv.Optional(CONF_WARNING_BUZER): select.select_schema(Inv8851Select, 118 | entity_category=ENTITY_CATEGORY_CONFIG 119 | ), 120 | } 121 | ) 122 | ) 123 | 124 | 125 | async def to_code(config): 126 | parent = await cg.get_variable(config.get(CONF_INV_8851_ID)) 127 | for option in config: 128 | if option not in [CONF_PLATFORM, CONF_INV_8851_ID] and (c := config.get(option)): 129 | sel = await select.new_select(c, options=OPTIONS[option]) 130 | cg.add(getattr(sel, "set_parent")(parent)) 131 | cg.add(getattr(sel, "set_type")(option)) 132 | cg.add(getattr(parent, f"set_{option}_select")(sel)) 133 | -------------------------------------------------------------------------------- /components/inv_8851/sensor.py: -------------------------------------------------------------------------------- 1 | import esphome.codegen as cg 2 | import esphome.config_validation as cv 3 | from esphome.components import sensor 4 | from esphome.const import ( 5 | CONF_BATTERY_VOLTAGE, 6 | CONF_BUS_VOLTAGE, 7 | CONF_PLATFORM, 8 | DEVICE_CLASS_APPARENT_POWER, 9 | DEVICE_CLASS_BATTERY, 10 | DEVICE_CLASS_CURRENT, 11 | DEVICE_CLASS_FREQUENCY, 12 | DEVICE_CLASS_POWER, 13 | DEVICE_CLASS_SPEED, 14 | DEVICE_CLASS_TEMPERATURE, 15 | DEVICE_CLASS_VOLTAGE, 16 | STATE_CLASS_MEASUREMENT, 17 | UNIT_AMPERE, 18 | UNIT_CELSIUS, 19 | UNIT_HERTZ, 20 | UNIT_PERCENT, 21 | UNIT_VOLT, 22 | UNIT_VOLT_AMPS, 23 | UNIT_WATT, 24 | ) 25 | from . import ( 26 | Inv8851, 27 | CONF_INV_8851_ID, 28 | ) 29 | 30 | DEPENDENCIES = ["inv_8851"] 31 | 32 | CODEOWNERS = ["@lufton"] 33 | 34 | CONF_BATTERY_CHARCHE_CURRENT = "battery_charge_current" 35 | CONF_BATTERY_TYPE = "battery_type" 36 | CONF_BMS_BATTERY_CURRENT = "bms_battery_current" 37 | CONF_BMS_BATTERY_SOC = "bms_battery_soc" 38 | CONF_BMS_BATTERY_VOLTAGE = "bms_battery_voltage" 39 | CONF_BMS_CELL_01_VOLTAGE = "bms_cell_01_voltage" 40 | CONF_BMS_CELL_02_VOLTAGE = "bms_cell_02_voltage" 41 | CONF_BMS_CELL_03_VOLTAGE = "bms_cell_03_voltage" 42 | CONF_BMS_CELL_04_VOLTAGE = "bms_cell_04_voltage" 43 | CONF_BMS_CELL_05_VOLTAGE = "bms_cell_05_voltage" 44 | CONF_BMS_CELL_06_VOLTAGE = "bms_cell_06_voltage" 45 | CONF_BMS_CELL_07_VOLTAGE = "bms_cell_07_voltage" 46 | CONF_BMS_CELL_08_VOLTAGE = "bms_cell_08_voltage" 47 | CONF_BMS_CELL_09_VOLTAGE = "bms_cell_09_voltage" 48 | CONF_BMS_CELL_10_VOLTAGE = "bms_cell_10_voltage" 49 | CONF_BMS_CELL_11_VOLTAGE = "bms_cell_11_voltage" 50 | CONF_BMS_CELL_12_VOLTAGE = "bms_cell_12_voltage" 51 | CONF_BMS_CELL_13_VOLTAGE = "bms_cell_13_voltage" 52 | CONF_BMS_CELL_14_VOLTAGE = "bms_cell_14_voltage" 53 | CONF_BMS_CELL_15_VOLTAGE = "bms_cell_15_voltage" 54 | CONF_BMS_CELL_16_VOLTAGE = "bms_cell_16_voltage" 55 | CONF_BTS_TEMPERATURE = "bts_temperature" 56 | CONF_FAN1_SPEED_PERCENTAGE = "fan1_speed_percentage" 57 | CONF_FAN2_SPEED_PERCENTAGE = "fan2_speed_percentage" 58 | CONF_GRID_CURRENT = "grid_current" 59 | CONF_GRID_FREQUENCY = "grid_frequency" 60 | CONF_GRID_VOLTAGE = "grid_voltage" 61 | CONF_INVERTER_APPARENT_POWER = "inverter_apparent_power" 62 | CONF_INVERTER_APPARENT_POWER_PERCENTAGE = "inverter_apparent_power_percentage" 63 | CONF_INVERTER_CURRENT = "inverter_current" 64 | CONF_INVERTER_FREQUENCY = "inverter_frequency" 65 | CONF_INVERTER_POWER_PERCENTAGE = "inverter_power_percentage" 66 | CONF_INVERTER_SOFTWARE_VERSION = "inverter_software_version" 67 | CONF_INVERTER_VOLTAGE = "inverter_voltage" 68 | CONF_INVERTER_VOLTAGE_DC_COMPONENT = "inverter_voltage_dc_component" 69 | CONF_LOAD_APPARENT_POWER = "load_apparent_power" 70 | CONF_LOAD_CURRENT = "load_current" 71 | CONF_LOAD_POWER = "load_power" 72 | CONF_LOG_NUMBER = "log_number" 73 | CONF_LOW_LOAD_CURRENT = "low_load_current" 74 | CONF_NTC2_TEMPERATURE = "ntc2_temperature" 75 | CONF_NTC3_TEMPERATURE = "ntc3_temperature" 76 | CONF_NTC4_TEMPERATURE = "ntc4_temperature" 77 | CONF_PARALLEL_CURRENT = "parallel_current" 78 | CONF_PARALLEL_FREQUENCY = "parallel_frequency" 79 | CONF_PARALLEL_VOLTAGE = "parallel_voltage" 80 | CONF_PV_CURRENT = "pv_current" 81 | CONF_PV_POWER = "pv_power" 82 | CONF_PV_VOLTAGE = "pv_voltage" 83 | 84 | CONFIG_SCHEMA = ( 85 | cv.Schema( 86 | { 87 | cv.GenerateID(CONF_INV_8851_ID): cv.use_id(Inv8851), 88 | cv.Optional(CONF_BATTERY_CHARCHE_CURRENT): sensor.sensor_schema( 89 | unit_of_measurement=UNIT_AMPERE, 90 | accuracy_decimals=1, 91 | device_class=DEVICE_CLASS_CURRENT, 92 | state_class=STATE_CLASS_MEASUREMENT, 93 | ), 94 | cv.Optional(CONF_BATTERY_VOLTAGE): sensor.sensor_schema( 95 | unit_of_measurement=UNIT_VOLT, 96 | accuracy_decimals=2, 97 | device_class=DEVICE_CLASS_VOLTAGE, 98 | state_class=STATE_CLASS_MEASUREMENT, 99 | ), 100 | cv.Optional(CONF_BMS_BATTERY_CURRENT): sensor.sensor_schema( 101 | unit_of_measurement=UNIT_AMPERE, 102 | accuracy_decimals=1, 103 | device_class=DEVICE_CLASS_CURRENT, 104 | state_class=STATE_CLASS_MEASUREMENT, 105 | ), 106 | cv.Optional(CONF_BMS_BATTERY_SOC): sensor.sensor_schema( 107 | unit_of_measurement=UNIT_PERCENT, 108 | accuracy_decimals=0, 109 | device_class=DEVICE_CLASS_BATTERY, 110 | state_class=STATE_CLASS_MEASUREMENT, 111 | ), 112 | cv.Optional(CONF_BMS_BATTERY_VOLTAGE): sensor.sensor_schema( 113 | unit_of_measurement=UNIT_VOLT, 114 | accuracy_decimals=2, 115 | device_class=DEVICE_CLASS_VOLTAGE, 116 | state_class=STATE_CLASS_MEASUREMENT, 117 | ), 118 | cv.Optional(CONF_BMS_CELL_01_VOLTAGE): sensor.sensor_schema( 119 | unit_of_measurement=UNIT_VOLT, 120 | accuracy_decimals=2, 121 | device_class=DEVICE_CLASS_VOLTAGE, 122 | state_class=STATE_CLASS_MEASUREMENT, 123 | ), 124 | cv.Optional(CONF_BMS_CELL_02_VOLTAGE): sensor.sensor_schema( 125 | unit_of_measurement=UNIT_VOLT, 126 | accuracy_decimals=2, 127 | device_class=DEVICE_CLASS_VOLTAGE, 128 | state_class=STATE_CLASS_MEASUREMENT, 129 | ), 130 | cv.Optional(CONF_BMS_CELL_03_VOLTAGE): sensor.sensor_schema( 131 | unit_of_measurement=UNIT_VOLT, 132 | accuracy_decimals=2, 133 | device_class=DEVICE_CLASS_VOLTAGE, 134 | state_class=STATE_CLASS_MEASUREMENT, 135 | ), 136 | cv.Optional(CONF_BMS_CELL_04_VOLTAGE): sensor.sensor_schema( 137 | unit_of_measurement=UNIT_VOLT, 138 | accuracy_decimals=2, 139 | device_class=DEVICE_CLASS_VOLTAGE, 140 | state_class=STATE_CLASS_MEASUREMENT, 141 | ), 142 | cv.Optional(CONF_BMS_CELL_05_VOLTAGE): sensor.sensor_schema( 143 | unit_of_measurement=UNIT_VOLT, 144 | accuracy_decimals=2, 145 | device_class=DEVICE_CLASS_VOLTAGE, 146 | state_class=STATE_CLASS_MEASUREMENT, 147 | ), 148 | cv.Optional(CONF_BMS_CELL_06_VOLTAGE): sensor.sensor_schema( 149 | unit_of_measurement=UNIT_VOLT, 150 | accuracy_decimals=2, 151 | device_class=DEVICE_CLASS_VOLTAGE, 152 | state_class=STATE_CLASS_MEASUREMENT, 153 | ), 154 | cv.Optional(CONF_BMS_CELL_07_VOLTAGE): sensor.sensor_schema( 155 | unit_of_measurement=UNIT_VOLT, 156 | accuracy_decimals=2, 157 | device_class=DEVICE_CLASS_VOLTAGE, 158 | state_class=STATE_CLASS_MEASUREMENT, 159 | ), 160 | cv.Optional(CONF_BMS_CELL_08_VOLTAGE): sensor.sensor_schema( 161 | unit_of_measurement=UNIT_VOLT, 162 | accuracy_decimals=2, 163 | device_class=DEVICE_CLASS_VOLTAGE, 164 | state_class=STATE_CLASS_MEASUREMENT, 165 | ), 166 | cv.Optional(CONF_BMS_CELL_09_VOLTAGE): sensor.sensor_schema( 167 | unit_of_measurement=UNIT_VOLT, 168 | accuracy_decimals=2, 169 | device_class=DEVICE_CLASS_VOLTAGE, 170 | state_class=STATE_CLASS_MEASUREMENT, 171 | ), 172 | cv.Optional(CONF_BMS_CELL_10_VOLTAGE): sensor.sensor_schema( 173 | unit_of_measurement=UNIT_VOLT, 174 | accuracy_decimals=2, 175 | device_class=DEVICE_CLASS_VOLTAGE, 176 | state_class=STATE_CLASS_MEASUREMENT, 177 | ), 178 | cv.Optional(CONF_BMS_CELL_11_VOLTAGE): sensor.sensor_schema( 179 | unit_of_measurement=UNIT_VOLT, 180 | accuracy_decimals=2, 181 | device_class=DEVICE_CLASS_VOLTAGE, 182 | state_class=STATE_CLASS_MEASUREMENT, 183 | ), 184 | cv.Optional(CONF_BMS_CELL_12_VOLTAGE): sensor.sensor_schema( 185 | unit_of_measurement=UNIT_VOLT, 186 | accuracy_decimals=2, 187 | device_class=DEVICE_CLASS_VOLTAGE, 188 | state_class=STATE_CLASS_MEASUREMENT, 189 | ), 190 | cv.Optional(CONF_BMS_CELL_13_VOLTAGE): sensor.sensor_schema( 191 | unit_of_measurement=UNIT_VOLT, 192 | accuracy_decimals=2, 193 | device_class=DEVICE_CLASS_VOLTAGE, 194 | state_class=STATE_CLASS_MEASUREMENT, 195 | ), 196 | cv.Optional(CONF_BMS_CELL_14_VOLTAGE): sensor.sensor_schema( 197 | unit_of_measurement=UNIT_VOLT, 198 | accuracy_decimals=2, 199 | device_class=DEVICE_CLASS_VOLTAGE, 200 | state_class=STATE_CLASS_MEASUREMENT, 201 | ), 202 | cv.Optional(CONF_BMS_CELL_15_VOLTAGE): sensor.sensor_schema( 203 | unit_of_measurement=UNIT_VOLT, 204 | accuracy_decimals=2, 205 | device_class=DEVICE_CLASS_VOLTAGE, 206 | state_class=STATE_CLASS_MEASUREMENT, 207 | ), 208 | cv.Optional(CONF_BMS_CELL_16_VOLTAGE): sensor.sensor_schema( 209 | unit_of_measurement=UNIT_VOLT, 210 | accuracy_decimals=2, 211 | device_class=DEVICE_CLASS_VOLTAGE, 212 | state_class=STATE_CLASS_MEASUREMENT, 213 | ), 214 | cv.Optional(CONF_BTS_TEMPERATURE): sensor.sensor_schema( 215 | unit_of_measurement=UNIT_CELSIUS, 216 | accuracy_decimals=0, 217 | device_class=DEVICE_CLASS_TEMPERATURE, 218 | state_class=STATE_CLASS_MEASUREMENT, 219 | ), 220 | cv.Optional(CONF_BUS_VOLTAGE): sensor.sensor_schema( 221 | unit_of_measurement=UNIT_VOLT, 222 | accuracy_decimals=1, 223 | device_class=DEVICE_CLASS_VOLTAGE, 224 | state_class=STATE_CLASS_MEASUREMENT, 225 | ), 226 | cv.Optional(CONF_FAN1_SPEED_PERCENTAGE): sensor.sensor_schema( 227 | unit_of_measurement=UNIT_PERCENT, 228 | accuracy_decimals=0, 229 | device_class=DEVICE_CLASS_SPEED, 230 | state_class=STATE_CLASS_MEASUREMENT, 231 | ), 232 | cv.Optional(CONF_FAN2_SPEED_PERCENTAGE): sensor.sensor_schema( 233 | unit_of_measurement=UNIT_PERCENT, 234 | accuracy_decimals=0, 235 | device_class=DEVICE_CLASS_SPEED, 236 | state_class=STATE_CLASS_MEASUREMENT, 237 | ), 238 | cv.Optional(CONF_GRID_CURRENT): sensor.sensor_schema( 239 | unit_of_measurement=UNIT_AMPERE, 240 | accuracy_decimals=2, 241 | device_class=DEVICE_CLASS_CURRENT, 242 | state_class=STATE_CLASS_MEASUREMENT, 243 | ), 244 | cv.Optional(CONF_GRID_FREQUENCY): sensor.sensor_schema( 245 | unit_of_measurement=UNIT_HERTZ, 246 | accuracy_decimals=2, 247 | device_class=DEVICE_CLASS_FREQUENCY, 248 | state_class=STATE_CLASS_MEASUREMENT, 249 | ), 250 | cv.Optional(CONF_GRID_VOLTAGE): sensor.sensor_schema( 251 | unit_of_measurement=UNIT_VOLT, 252 | accuracy_decimals=1, 253 | device_class=DEVICE_CLASS_VOLTAGE, 254 | state_class=STATE_CLASS_MEASUREMENT, 255 | ), 256 | cv.Optional(CONF_INVERTER_APPARENT_POWER): sensor.sensor_schema( 257 | unit_of_measurement=UNIT_VOLT_AMPS, 258 | accuracy_decimals=0, 259 | device_class=DEVICE_CLASS_APPARENT_POWER, 260 | state_class=STATE_CLASS_MEASUREMENT, 261 | ), 262 | cv.Optional(CONF_INVERTER_APPARENT_POWER_PERCENTAGE): sensor.sensor_schema( 263 | unit_of_measurement=UNIT_PERCENT, 264 | accuracy_decimals=0, 265 | state_class=STATE_CLASS_MEASUREMENT, 266 | ), 267 | cv.Optional(CONF_INVERTER_CURRENT): sensor.sensor_schema( 268 | unit_of_measurement=UNIT_AMPERE, 269 | accuracy_decimals=2, 270 | device_class=DEVICE_CLASS_CURRENT, 271 | state_class=STATE_CLASS_MEASUREMENT, 272 | ), 273 | cv.Optional(CONF_INVERTER_FREQUENCY): sensor.sensor_schema( 274 | unit_of_measurement=UNIT_HERTZ, 275 | accuracy_decimals=2, 276 | device_class=DEVICE_CLASS_FREQUENCY, 277 | state_class=STATE_CLASS_MEASUREMENT, 278 | ), 279 | cv.Optional(CONF_INVERTER_POWER_PERCENTAGE): sensor.sensor_schema( 280 | unit_of_measurement=UNIT_PERCENT, 281 | accuracy_decimals=0, 282 | state_class=STATE_CLASS_MEASUREMENT, 283 | ), 284 | cv.Optional(CONF_INVERTER_SOFTWARE_VERSION): sensor.sensor_schema(), 285 | cv.Optional(CONF_INVERTER_VOLTAGE): sensor.sensor_schema( 286 | unit_of_measurement=UNIT_VOLT, 287 | accuracy_decimals=1, 288 | device_class=DEVICE_CLASS_VOLTAGE, 289 | state_class=STATE_CLASS_MEASUREMENT, 290 | ), 291 | cv.Optional(CONF_INVERTER_VOLTAGE_DC_COMPONENT): sensor.sensor_schema(), 292 | cv.Optional(CONF_LOAD_APPARENT_POWER): sensor.sensor_schema( 293 | unit_of_measurement=UNIT_VOLT_AMPS, 294 | accuracy_decimals=0, 295 | device_class=DEVICE_CLASS_APPARENT_POWER, 296 | state_class=STATE_CLASS_MEASUREMENT, 297 | ), 298 | cv.Optional(CONF_LOAD_CURRENT): sensor.sensor_schema( 299 | unit_of_measurement=UNIT_AMPERE, 300 | accuracy_decimals=2, 301 | device_class=DEVICE_CLASS_CURRENT, 302 | state_class=STATE_CLASS_MEASUREMENT, 303 | ), 304 | cv.Optional(CONF_LOAD_POWER): sensor.sensor_schema( 305 | unit_of_measurement=UNIT_WATT, 306 | accuracy_decimals=0, 307 | device_class=DEVICE_CLASS_POWER, 308 | state_class=STATE_CLASS_MEASUREMENT, 309 | ), 310 | cv.Optional(CONF_LOG_NUMBER): sensor.sensor_schema(), 311 | cv.Optional(CONF_LOW_LOAD_CURRENT): sensor.sensor_schema( 312 | unit_of_measurement=UNIT_AMPERE, 313 | accuracy_decimals=2, 314 | device_class=DEVICE_CLASS_CURRENT, 315 | state_class=STATE_CLASS_MEASUREMENT, 316 | ), 317 | cv.Optional(CONF_NTC2_TEMPERATURE): sensor.sensor_schema( 318 | unit_of_measurement=UNIT_CELSIUS, 319 | accuracy_decimals=0, 320 | device_class=DEVICE_CLASS_TEMPERATURE, 321 | state_class=STATE_CLASS_MEASUREMENT, 322 | ), 323 | cv.Optional(CONF_NTC3_TEMPERATURE): sensor.sensor_schema( 324 | unit_of_measurement=UNIT_CELSIUS, 325 | accuracy_decimals=0, 326 | device_class=DEVICE_CLASS_TEMPERATURE, 327 | state_class=STATE_CLASS_MEASUREMENT, 328 | ), 329 | cv.Optional(CONF_NTC4_TEMPERATURE): sensor.sensor_schema( 330 | unit_of_measurement=UNIT_CELSIUS, 331 | accuracy_decimals=0, 332 | device_class=DEVICE_CLASS_TEMPERATURE, 333 | state_class=STATE_CLASS_MEASUREMENT, 334 | ), 335 | cv.Optional(CONF_PARALLEL_CURRENT): sensor.sensor_schema( 336 | unit_of_measurement=UNIT_AMPERE, 337 | accuracy_decimals=2, 338 | device_class=DEVICE_CLASS_CURRENT, 339 | state_class=STATE_CLASS_MEASUREMENT, 340 | ), 341 | cv.Optional(CONF_PARALLEL_FREQUENCY): sensor.sensor_schema( 342 | unit_of_measurement=UNIT_HERTZ, 343 | accuracy_decimals=2, 344 | device_class=DEVICE_CLASS_FREQUENCY, 345 | state_class=STATE_CLASS_MEASUREMENT, 346 | ), 347 | cv.Optional(CONF_PARALLEL_VOLTAGE): sensor.sensor_schema( 348 | unit_of_measurement=UNIT_VOLT, 349 | accuracy_decimals=1, 350 | device_class=DEVICE_CLASS_VOLTAGE, 351 | state_class=STATE_CLASS_MEASUREMENT, 352 | ), 353 | cv.Optional(CONF_PV_CURRENT): sensor.sensor_schema( 354 | unit_of_measurement=UNIT_AMPERE, 355 | accuracy_decimals=2, 356 | device_class=DEVICE_CLASS_CURRENT, 357 | state_class=STATE_CLASS_MEASUREMENT, 358 | ), 359 | cv.Optional(CONF_PV_POWER): sensor.sensor_schema( 360 | unit_of_measurement=UNIT_WATT, 361 | accuracy_decimals=0, 362 | device_class=DEVICE_CLASS_POWER, 363 | state_class=STATE_CLASS_MEASUREMENT, 364 | ), 365 | cv.Optional(CONF_PV_VOLTAGE): sensor.sensor_schema( 366 | unit_of_measurement=UNIT_VOLT, 367 | accuracy_decimals=1, 368 | device_class=DEVICE_CLASS_VOLTAGE, 369 | state_class=STATE_CLASS_MEASUREMENT, 370 | ), 371 | } 372 | ) 373 | ) 374 | 375 | 376 | async def to_code(config): 377 | parent = await cg.get_variable(config.get(CONF_INV_8851_ID)) 378 | for option in config: 379 | if option not in [CONF_PLATFORM, CONF_INV_8851_ID] and (c := config.get(option)): 380 | sens = await sensor.new_sensor(c) 381 | cg.add(getattr(parent, f"set_{option}_sensor")(sens)) 382 | -------------------------------------------------------------------------------- /components/inv_8851/text_sensor.py: -------------------------------------------------------------------------------- 1 | import esphome.codegen as cg 2 | import esphome.config_validation as cv 3 | from esphome.components import text_sensor 4 | from esphome.const import ( 5 | CONF_PLATFORM, 6 | ) 7 | 8 | from . import ( 9 | Inv8851, 10 | CONF_INV_8851_ID, 11 | ) 12 | 13 | DEPENDENCIES = ["inv_8851"] 14 | 15 | CODEOWNERS = ["@lufton"] 16 | 17 | CONF_BUCK_TOPOLOGY = "buck_topology" 18 | CONF_INVERTER_TOPOLOGY = "inverter_topology" 19 | CONF_LLC_TOPOLOGY = "llc_topology" 20 | CONF_PV_TOPOLOGY = "pv_topology" 21 | 22 | CONFIG_SCHEMA = ( 23 | cv.Schema( 24 | { 25 | cv.GenerateID(CONF_INV_8851_ID): cv.use_id(Inv8851), 26 | cv.Optional(CONF_BUCK_TOPOLOGY): text_sensor.text_sensor_schema(), 27 | cv.Optional(CONF_INVERTER_TOPOLOGY): text_sensor.text_sensor_schema(), 28 | cv.Optional(CONF_LLC_TOPOLOGY): text_sensor.text_sensor_schema(), 29 | cv.Optional(CONF_PV_TOPOLOGY): text_sensor.text_sensor_schema(), 30 | } 31 | ) 32 | ) 33 | 34 | 35 | async def to_code(config): 36 | parent = await cg.get_variable(config.get(CONF_INV_8851_ID)) 37 | for option in config: 38 | if option not in [CONF_PLATFORM, CONF_INV_8851_ID] and (c := config.get(option)): 39 | sens = await text_sensor.new_text_sensor(c) 40 | cg.add(getattr(parent, f"set_{option}_text_sensor")(sens)) 41 | -------------------------------------------------------------------------------- /dtu-wbs1-v001-24v-example-local.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | inverter_maximum_power: "4500" 3 | version: "2" 4 | name: dtu-wbs1-v001 5 | friendly_name: DTU WBS1-V001 6 | 7 | esp32: 8 | board: esp32-c3-devkitm-1 9 | 10 | packages: 11 | core: !include packages/core-local.yaml 12 | inverter: !include packages/inverter.yaml 13 | grid: !include packages/grid.yaml 14 | temperature: !include packages/temperature.yaml 15 | battery: !include packages/battery.yaml 16 | battery-24v: !include packages/battery-24v.yaml 17 | # pv: !include packages/pv.yaml 18 | # parallel: !include packages/parallel.yaml 19 | # bms-24v: !include packages/bms-24v.yaml 20 | dtu_wbs1_v001: !include packages/dtu_wbs1_v001.yaml 21 | 22 | wifi: 23 | ssid: !secret wifi_ssid 24 | password: !secret wifi_password 25 | 26 | ap: 27 | ssid: ${friendly_name} 28 | password: !secret ap_password 29 | 30 | api: 31 | encryption: 32 | key: !secret api_encryption_key 33 | 34 | ota: 35 | - platform: esphome 36 | password: !secret ota_password 37 | -------------------------------------------------------------------------------- /dtu-wbs1-v001-24v-example.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | inverter_maximum_power: "4500" 3 | version: "2" 4 | name: dtu-wbs1-v001 5 | friendly_name: DTU WBS1-V001 6 | 7 | esp32: 8 | board: esp32-c3-devkitm-1 9 | 10 | packages: 11 | inv_8851: 12 | url: https://github.com/lufton/esphome-inv-8851 13 | ref: main 14 | files: 15 | - packages/core.yaml 16 | - packages/inverter.yaml 17 | - packages/grid.yaml 18 | - packages/temperature.yaml 19 | - packages/battery.yaml 20 | - packages/battery-24v.yaml 21 | # - packages/pv.yaml 22 | # - packages/parallel.yaml 23 | # - packages/bms-24v.yaml 24 | - packages/dtu_wbs1_v001.yaml 25 | refresh: 0s 26 | 27 | wifi: 28 | ssid: !secret wifi_ssid 29 | password: !secret wifi_password 30 | 31 | ap: 32 | ssid: ${friendly_name} 33 | password: !secret ap_password 34 | 35 | api: 36 | encryption: 37 | key: !secret api_encryption_key 38 | 39 | ota: 40 | - platform: esphome 41 | password: !secret ota_password 42 | -------------------------------------------------------------------------------- /dtu-wbs1-v001-48v-example-local-my.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | inverter_maximum_power: "6500" 3 | version: "1" 4 | name: dtu-wbs1-v001 5 | friendly_name: DTU WBS1-V001 6 | 7 | esp32: 8 | board: esp32-c3-devkitm-1 9 | 10 | packages: 11 | core: !include packages/core-local.yaml 12 | inverter: !include packages/inverter.yaml 13 | grid: !include packages/grid.yaml 14 | temperature: !include packages/temperature.yaml 15 | battery: !include packages/battery.yaml 16 | battery-48v: !include packages/battery-48v.yaml 17 | # pv: !include packages/pv.yaml 18 | # parallel: !include packages/parallel.yaml 19 | # bms-48v: !include packages/bms-48v.yaml 20 | dtu_wbs1_v001: !include packages/dtu_wbs1_v001.yaml 21 | 22 | wifi: 23 | ssid: !secret wifi_ssid 24 | password: !secret wifi_password 25 | 26 | ap: 27 | ssid: ${friendly_name} 28 | password: !secret ap_password 29 | 30 | api: 31 | encryption: 32 | key: !secret api_encryption_key 33 | 34 | ota: 35 | - platform: esphome 36 | password: !secret ota_password 37 | -------------------------------------------------------------------------------- /dtu-wbs1-v001-48v-example-local.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | inverter_maximum_power: "6500" 3 | version: "2" 4 | name: dtu-wbs1-v001 5 | friendly_name: DTU WBS1-V001 6 | 7 | esp32: 8 | board: esp32-c3-devkitm-1 9 | 10 | packages: 11 | core: !include packages/core-local.yaml 12 | inverter: !include packages/inverter.yaml 13 | grid: !include packages/grid.yaml 14 | temperature: !include packages/temperature.yaml 15 | battery: !include packages/battery.yaml 16 | battery-48v: !include packages/battery-48v.yaml 17 | pv: !include packages/pv.yaml 18 | parallel: !include packages/parallel.yaml 19 | bms-48v: !include packages/bms-48v.yaml 20 | dtu_wbs1_v001: !include packages/dtu_wbs1_v001.yaml 21 | 22 | wifi: 23 | ssid: !secret wifi_ssid 24 | password: !secret wifi_password 25 | 26 | ap: 27 | ssid: ${friendly_name} 28 | password: !secret ap_password 29 | 30 | api: 31 | encryption: 32 | key: !secret api_encryption_key 33 | 34 | ota: 35 | - platform: esphome 36 | password: !secret ota_password 37 | -------------------------------------------------------------------------------- /dtu-wbs1-v001-48v-example.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | inverter_maximum_power: "6500" 3 | version: "2" 4 | name: dtu-wbs1-v001 5 | friendly_name: DTU WBS1-V001 6 | 7 | esp32: 8 | board: esp32-c3-devkitm-1 9 | 10 | packages: 11 | inv_8851: 12 | url: https://github.com/lufton/esphome-inv-8851 13 | ref: main 14 | files: 15 | - packages/core.yaml 16 | - packages/inverter.yaml 17 | - packages/grid.yaml 18 | - packages/temperature.yaml 19 | - packages/battery.yaml 20 | - packages/battery-48v.yaml 21 | # - packages/pv.yaml 22 | # - packages/parallel.yaml 23 | # - packages/bms-48v.yaml 24 | - packages/dtu_wbs1_v001.yaml 25 | refresh: 0s 26 | 27 | wifi: 28 | ssid: !secret wifi_ssid 29 | password: !secret wifi_password 30 | 31 | ap: 32 | ssid: ${friendly_name} 33 | password: !secret ap_password 34 | 35 | api: 36 | encryption: 37 | key: !secret api_encryption_key 38 | 39 | ota: 40 | - platform: esphome 41 | password: !secret ota_password 42 | -------------------------------------------------------------------------------- /esp32-24v-example-local.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | inverter_maximum_power: "4500" 3 | version: "2" 4 | name: inverter 5 | friendly_name: Inverter 6 | uart_tx_pin: GPIO16 7 | uart_rx_pin: GPIO17 8 | 9 | esp32: 10 | board: wemos_d1_mini32 11 | 12 | packages: 13 | core: !include packages/core-local.yaml 14 | inverter: !include packages/inverter.yaml 15 | grid: !include packages/grid.yaml 16 | temperature: !include packages/temperature.yaml 17 | battery: !include packages/battery.yaml 18 | battery-24v: !include packages/battery-24v.yaml 19 | # pv: !include packages/pv.yaml 20 | # parallel: !include packages/parallel.yaml 21 | # bms-24v: !include packages/bms-24v.yaml 22 | 23 | wifi: 24 | ssid: !secret wifi_ssid 25 | password: !secret wifi_password 26 | 27 | ap: 28 | ssid: ${friendly_name} 29 | password: !secret ap_password 30 | 31 | api: 32 | encryption: 33 | key: !secret api_encryption_key 34 | 35 | ota: 36 | - platform: esphome 37 | password: !secret ota_password 38 | -------------------------------------------------------------------------------- /esp32-24v-example.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | inverter_maximum_power: "4500" 3 | version: "2" 4 | name: inverter 5 | friendly_name: Inverter 6 | uart_tx_pin: GPIO16 7 | uart_rx_pin: GPIO17 8 | 9 | esp32: 10 | board: wemos_d1_mini32 11 | 12 | packages: 13 | inv_8851: 14 | url: https://github.com/lufton/esphome-inv-8851 15 | ref: main 16 | files: 17 | - packages/core.yaml 18 | - packages/inverter.yaml 19 | - packages/grid.yaml 20 | - packages/temperature.yaml 21 | - packages/battery.yaml 22 | - packages/battery-24v.yaml 23 | # - packages/pv.yaml 24 | # - packages/parallel.yaml 25 | # - packages/bms-24v.yaml 26 | refresh: 0s 27 | 28 | wifi: 29 | ssid: !secret wifi_ssid 30 | password: !secret wifi_password 31 | 32 | ap: 33 | ssid: ${friendly_name} 34 | password: !secret ap_password 35 | 36 | api: 37 | encryption: 38 | key: !secret api_encryption_key 39 | 40 | ota: 41 | - platform: esphome 42 | password: !secret ota_password 43 | -------------------------------------------------------------------------------- /esp32-48v-example-local.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | inverter_maximum_power: "6500" 3 | version: "2" 4 | name: inverter 5 | friendly_name: Inverter 6 | uart_tx_pin: GPIO16 7 | uart_rx_pin: GPIO17 8 | 9 | esp32: 10 | board: wemos_d1_mini32 11 | 12 | packages: 13 | core: !include packages/core-local.yaml 14 | inverter: !include packages/inverter.yaml 15 | grid: !include packages/grid.yaml 16 | temperature: !include packages/temperature.yaml 17 | battery: !include packages/battery.yaml 18 | battery-48v: !include packages/battery-48v.yaml 19 | # pv: !include packages/pv.yaml 20 | # parallel: !include packages/parallel.yaml 21 | # bms-48v: !include packages/bms-48v.yaml 22 | 23 | wifi: 24 | ssid: !secret wifi_ssid 25 | password: !secret wifi_password 26 | 27 | ap: 28 | ssid: ${friendly_name} 29 | password: !secret ap_password 30 | 31 | api: 32 | encryption: 33 | key: !secret api_encryption_key 34 | 35 | ota: 36 | - platform: esphome 37 | password: !secret ota_password 38 | -------------------------------------------------------------------------------- /esp32-48v-example.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | inverter_maximum_power: "6500" 3 | version: "2" 4 | name: inverter 5 | friendly_name: Inverter 6 | uart_tx_pin: GPIO16 7 | uart_rx_pin: GPIO17 8 | 9 | esp32: 10 | board: wemos_d1_mini32 11 | 12 | packages: 13 | inv_8851: 14 | url: https://github.com/lufton/esphome-inv-8851 15 | ref: main 16 | files: 17 | - packages/core.yaml 18 | - packages/inverter.yaml 19 | - packages/grid.yaml 20 | - packages/temperature.yaml 21 | - packages/battery.yaml 22 | - packages/battery-48v.yaml 23 | # - packages/pv.yaml 24 | # - packages/parallel.yaml 25 | # - packages/bms-48v.yaml 26 | refresh: 0s 27 | 28 | wifi: 29 | ssid: !secret wifi_ssid 30 | password: !secret wifi_password 31 | 32 | ap: 33 | ssid: ${friendly_name} 34 | password: !secret ap_password 35 | 36 | api: 37 | encryption: 38 | key: !secret api_encryption_key 39 | 40 | ota: 41 | - platform: esphome 42 | password: !secret ota_password 43 | -------------------------------------------------------------------------------- /esp8266-24v-example-local.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | inverter_maximum_power: "4500" 3 | version: "2" 4 | name: inverter 5 | friendly_name: Inverter 6 | uart_tx_pin: GPIO1 7 | uart_rx_pin: GPIO3 8 | 9 | esp32: 10 | board: d1_mini 11 | 12 | packages: 13 | core: !include packages/core-local.yaml 14 | inverter: !include packages/inverter.yaml 15 | grid: !include packages/grid.yaml 16 | temperature: !include packages/temperature.yaml 17 | battery: !include packages/battery.yaml 18 | battery-24v: !include packages/battery-24v.yaml 19 | # pv: !include packages/pv.yaml 20 | # parallel: !include packages/parallel.yaml 21 | # bms-24v: !include packages/bms-24v.yaml 22 | 23 | wifi: 24 | ssid: !secret wifi_ssid 25 | password: !secret wifi_password 26 | 27 | ap: 28 | ssid: ${friendly_name} 29 | password: !secret ap_password 30 | 31 | api: 32 | encryption: 33 | key: !secret api_encryption_key 34 | 35 | ota: 36 | - platform: esphome 37 | password: !secret ota_password 38 | -------------------------------------------------------------------------------- /esp8266-24v-example.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | inverter_maximum_power: "4500" 3 | version: "2" 4 | name: inverter 5 | friendly_name: Inverter 6 | uart_tx_pin: GPIO1 7 | uart_rx_pin: GPIO3 8 | 9 | esp32: 10 | board: d1_mini 11 | 12 | packages: 13 | inv_8851: 14 | url: https://github.com/lufton/esphome-inv-8851 15 | ref: main 16 | files: 17 | - packages/core.yaml 18 | - packages/inverter.yaml 19 | - packages/grid.yaml 20 | - packages/temperature.yaml 21 | - packages/battery.yaml 22 | - packages/battery-24v.yaml 23 | # - packages/pv.yaml 24 | # - packages/parallel.yaml 25 | # - packages/bms-24v.yaml 26 | refresh: 0s 27 | 28 | wifi: 29 | ssid: !secret wifi_ssid 30 | password: !secret wifi_password 31 | 32 | ap: 33 | ssid: ${friendly_name} 34 | password: !secret ap_password 35 | 36 | api: 37 | encryption: 38 | key: !secret api_encryption_key 39 | 40 | ota: 41 | - platform: esphome 42 | password: !secret ota_password 43 | -------------------------------------------------------------------------------- /esp8266-48v-example-local.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | inverter_maximum_power: "6500" 3 | version: "2" 4 | name: inverter 5 | friendly_name: Inverter 6 | uart_tx_pin: GPIO1 7 | uart_rx_pin: GPIO3 8 | 9 | esp32: 10 | board: d1_mini 11 | 12 | packages: 13 | core: !include packages/core-local.yaml 14 | inverter: !include packages/inverter.yaml 15 | grid: !include packages/grid.yaml 16 | temperature: !include packages/temperature.yaml 17 | battery: !include packages/battery.yaml 18 | battery-48v: !include packages/battery-48v.yaml 19 | # pv: !include packages/pv.yaml 20 | # parallel: !include packages/parallel.yaml 21 | # bms-48v: !include packages/bms-48v.yaml 22 | 23 | wifi: 24 | ssid: !secret wifi_ssid 25 | password: !secret wifi_password 26 | 27 | ap: 28 | ssid: ${friendly_name} 29 | password: !secret ap_password 30 | 31 | api: 32 | encryption: 33 | key: !secret api_encryption_key 34 | 35 | ota: 36 | - platform: esphome 37 | password: !secret ota_password 38 | -------------------------------------------------------------------------------- /esp8266-48v-example.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | inverter_maximum_power: "6500" 3 | version: "2" 4 | name: inverter 5 | friendly_name: Inverter 6 | uart_tx_pin: GPIO1 7 | uart_rx_pin: GPIO3 8 | 9 | esp32: 10 | board: d1_mini 11 | 12 | packages: 13 | inv_8851: 14 | url: https://github.com/lufton/esphome-inv-8851 15 | ref: main 16 | files: 17 | - packages/core.yaml 18 | - packages/inverter.yaml 19 | - packages/grid.yaml 20 | - packages/temperature.yaml 21 | - packages/battery.yaml 22 | - packages/battery-48v.yaml 23 | # - packages/pv.yaml 24 | # - packages/parallel.yaml 25 | # - packages/bms-48v.yaml 26 | refresh: 0s 27 | 28 | wifi: 29 | ssid: !secret wifi_ssid 30 | password: !secret wifi_password 31 | 32 | ap: 33 | ssid: ${friendly_name} 34 | password: !secret ap_password 35 | 36 | api: 37 | encryption: 38 | key: !secret api_encryption_key 39 | 40 | ota: 41 | - platform: esphome 42 | password: !secret ota_password 43 | -------------------------------------------------------------------------------- /packages/battery-24v.yaml: -------------------------------------------------------------------------------- 1 | number: 2 | - platform: inv_8851 3 | battery_back_to_util_voltage: 4 | name: "Battery back to util voltage" 5 | mode: box 6 | min_value: 20 7 | max_value: 29.2 8 | step: 0.1 9 | battery_bulk_voltage: 10 | name: "Battery bulk voltage" 11 | mode: box 12 | min_value: 24 13 | max_value: 29.2 14 | step: 0.1 15 | battery_float_voltage: 16 | name: "Battery float voltage" 17 | mode: box 18 | min_value: 24 19 | max_value: 29.2 20 | step: 0.1 21 | battery_cut_off_voltage: 22 | name: "Battery cut-off voltage" 23 | mode: box 24 | min_value: 20 25 | max_value: 24 26 | step: 0.1 27 | battery_equalization_voltage: 28 | name: "Battery equalization voltage" 29 | mode: box 30 | min_value: 25 31 | max_value: 29.5 32 | step: 0.1 33 | total_charge_current: 34 | name: "Total charge current" 35 | mode: box 36 | min_value: 0 37 | max_value: 150 38 | step: 0.1 39 | util_charge_current: 40 | name: "Util charge current" 41 | mode: box 42 | min_value: 0 43 | max_value: 140 44 | step: 0.1 45 | -------------------------------------------------------------------------------- /packages/battery-48v.yaml: -------------------------------------------------------------------------------- 1 | number: 2 | - platform: inv_8851 3 | battery_back_to_util_voltage: 4 | name: "Battery back to util voltage" 5 | mode: box 6 | min_value: 40 7 | max_value: 58.4 8 | step: 0.1 9 | battery_bulk_voltage: 10 | name: "Battery bulk voltage" 11 | mode: box 12 | min_value: 48 13 | max_value: 58.4 14 | step: 0.1 15 | battery_float_voltage: 16 | name: "Battery float voltage" 17 | mode: box 18 | min_value: 48 19 | max_value: 58.4 20 | step: 0.1 21 | battery_cut_off_voltage: 22 | name: "Battery cut-off voltage" 23 | mode: box 24 | min_value: 40 25 | max_value: 48 26 | step: 0.1 27 | battery_equalization_voltage: 28 | name: "Battery equalization voltage" 29 | mode: box 30 | min_value: 50 31 | max_value: 59 32 | step: 0.1 33 | total_charge_current: 34 | name: "Total charge current" 35 | mode: box 36 | min_value: 0 37 | max_value: 130 38 | step: 0.1 39 | util_charge_current: 40 | name: "Util charge current" 41 | mode: box 42 | min_value: 0 43 | max_value: 110 44 | step: 0.1 45 | -------------------------------------------------------------------------------- /packages/battery.yaml: -------------------------------------------------------------------------------- 1 | binary_sensor: 2 | - platform: inv_8851 3 | battery: 4 | name: "Battery" 5 | charging: 6 | name: "Charging" 7 | equalization_finished: 8 | name: "Equalization finished" 9 | equalization_started: 10 | name: "Equalization started" 11 | float_charging: 12 | name: "Float charging" 13 | 14 | sensor: 15 | - platform: inv_8851 16 | battery_charge_current: 17 | name: "Battery charge current" 18 | battery_voltage: 19 | name: "Battery voltage" 20 | 21 | select: 22 | - platform: inv_8851 23 | battery_equalization: 24 | name: "Battery equalization" 25 | battery_type: 26 | name: "Battery type" 27 | charge_energy_priority: 28 | name: "Charge energy priority" 29 | output_energy_priority: 30 | name: "Output energy priority" 31 | 32 | number: 33 | - platform: inv_8851 34 | battery_charge_cut_off_current: 35 | name: "Battery charge cut-off current" 36 | mode: box 37 | min_value: 2 38 | max_value: 20 39 | step: 0.1 40 | battery_equalization_interval: 41 | name: "Battery equalization interval" 42 | mode: box 43 | min_value: 0 44 | max_value: 90 45 | step: 1 46 | battery_equalization_time: 47 | name: "Battery equalization time" 48 | mode: box 49 | min_value: 5 50 | max_value: 900 51 | step: 1 52 | battery_equalization_timeout: 53 | name: "Battery equalization timeout" 54 | mode: box 55 | min_value: 5 56 | max_value: 900 57 | step: 1 58 | -------------------------------------------------------------------------------- /packages/bms-24v.yaml: -------------------------------------------------------------------------------- 1 | sensor: 2 | - platform: inv_8851 3 | bms_battery_current: 4 | name: "BMS battery current" 5 | bms_battery_soc: 6 | name: "BMS battery SOC" 7 | bms_battery_voltage: 8 | name: "BMS battery voltage" 9 | bms_cell_01_voltage: 10 | name: "BMS cell 01 voltage" 11 | bms_cell_02_voltage: 12 | name: "BMS cell 02 voltage" 13 | bms_cell_03_voltage: 14 | name: "BMS cell 03 voltage" 15 | bms_cell_04_voltage: 16 | name: "BMS cell 04 voltage" 17 | bms_cell_05_voltage: 18 | name: "BMS cell 05 voltage" 19 | bms_cell_06_voltage: 20 | name: "BMS cell 06 voltage" 21 | bms_cell_07_voltage: 22 | name: "BMS cell 07 voltage" 23 | bms_cell_08_voltage: 24 | name: "BMS cell 08 voltage" 25 | -------------------------------------------------------------------------------- /packages/bms-48v.yaml: -------------------------------------------------------------------------------- 1 | sensor: 2 | - platform: inv_8851 3 | bms_battery_current: 4 | name: "BMS battery current" 5 | bms_battery_soc: 6 | name: "BMS battery SOC" 7 | bms_battery_voltage: 8 | name: "BMS battery voltage" 9 | bms_cell_01_voltage: 10 | name: "BMS cell 01 voltage" 11 | bms_cell_02_voltage: 12 | name: "BMS cell 02 voltage" 13 | bms_cell_03_voltage: 14 | name: "BMS cell 03 voltage" 15 | bms_cell_04_voltage: 16 | name: "BMS cell 04 voltage" 17 | bms_cell_05_voltage: 18 | name: "BMS cell 05 voltage" 19 | bms_cell_06_voltage: 20 | name: "BMS cell 06 voltage" 21 | bms_cell_07_voltage: 22 | name: "BMS cell 07 voltage" 23 | bms_cell_08_voltage: 24 | name: "BMS cell 08 voltage" 25 | bms_cell_09_voltage: 26 | name: "BMS cell 09 voltage" 27 | bms_cell_10_voltage: 28 | name: "BMS cell 10 voltage" 29 | bms_cell_11_voltage: 30 | name: "BMS cell 11 voltage" 31 | bms_cell_12_voltage: 32 | name: "BMS cell 12 voltage" 33 | bms_cell_13_voltage: 34 | name: "BMS cell 13 voltage" 35 | bms_cell_14_voltage: 36 | name: "BMS cell 14 voltage" 37 | bms_cell_15_voltage: 38 | name: "BMS cell 15 voltage" 39 | bms_cell_16_voltage: 40 | name: "BMS cell 16 voltage" -------------------------------------------------------------------------------- /packages/core-local.yaml: -------------------------------------------------------------------------------- 1 | esphome: 2 | name: ${name} 3 | friendly_name: ${friendly_name} 4 | comment: "Inverter DTU" 5 | project: 6 | name: "lufton.esphome-inv-8851" 7 | version: 1.0.0 8 | libraries: 9 | - leodesigner/PowMr_4500_regmap 10 | 11 | logger: 12 | level: VERY_VERBOSE 13 | logs: 14 | api: NONE 15 | api.connection: NONE 16 | api.service: NONE 17 | api.socket: NONE 18 | app: NONE 19 | captive_portal: NONE 20 | component: NONE 21 | esphome.ota: NONE 22 | gpio.output: NONE 23 | light: NONE 24 | logger: NONE 25 | mdns: NONE 26 | number: NONE 27 | safe_mode: NONE 28 | scheduler: NONE 29 | script: NONE 30 | select: NONE 31 | sensor: NONE 32 | text_sensor: NONE 33 | uart.arduino_esp32: NONE 34 | wifi: NONE 35 | 36 | captive_portal: 37 | 38 | uart: 39 | - id: inv_8851_uart 40 | baud_rate: 9600 41 | tx_pin: ${uart_tx_pin} 42 | rx_pin: ${uart_rx_pin} 43 | debug: 44 | direction: BOTH 45 | dummy_receiver: false 46 | after: 47 | delimiter: "\n" 48 | sequence: 49 | - lambda: UARTDebug::log_hex(direction, bytes, ' '); 50 | 51 | external_components: 52 | - source: components 53 | 54 | inv_8851: 55 | version: ${version} 56 | update_interval: 5s 57 | -------------------------------------------------------------------------------- /packages/core.yaml: -------------------------------------------------------------------------------- 1 | esphome: 2 | name: ${name} 3 | friendly_name: ${friendly_name} 4 | comment: "Inverter DTU" 5 | project: 6 | name: "lufton.esphome-inv-8851" 7 | version: 1.0.0 8 | libraries: 9 | - leodesigner/PowMr_4500_regmap 10 | 11 | logger: 12 | 13 | captive_portal: 14 | 15 | uart: 16 | - id: inv_8851_uart 17 | baud_rate: 9600 18 | tx_pin: ${uart_tx_pin} 19 | rx_pin: ${uart_rx_pin} 20 | 21 | external_components: 22 | - source: github://lufton/esphome-inv-8851@main 23 | refresh: 0s 24 | 25 | inv_8851: 26 | version: ${version} 27 | update_interval: 5s 28 | -------------------------------------------------------------------------------- /packages/dtu_wbs1_v001.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | uart_tx_pin: GPIO4 3 | uart_rx_pin: GPIO5 4 | 5 | esphome: 6 | on_boot: 7 | then: 8 | - light.turn_on: pow_green_led 9 | 10 | globals: 11 | - id: updating_ota 12 | type: bool 13 | initial_value: 'false' 14 | 15 | ota: 16 | on_begin: 17 | - globals.set: 18 | id: updating_ota 19 | value: 'true' 20 | - light.turn_off: pow_green_led 21 | - while: 22 | condition: 23 | lambda: return id(updating_ota); 24 | then: 25 | - light.turn_on: pow_red_led 26 | - delay: 200ms 27 | - light.turn_off: pow_red_led 28 | - delay: 200ms 29 | - light.turn_on: pow_green_led 30 | on_end: 31 | - globals.set: 32 | id: updating_ota 33 | value: 'false' 34 | 35 | interval: 36 | - interval: 1s 37 | then: 38 | - if: 39 | condition: wifi.connected 40 | then: 41 | if: 42 | condition: 43 | - light.is_off: net_led 44 | then: 45 | - light.turn_on: net_led 46 | else: 47 | - light.turn_on: net_led 48 | - delay: 500ms 49 | - light.turn_off: net_led 50 | 51 | uart: 52 | - id: !extend inv_8851_uart 53 | debug: 54 | sequence: 55 | - script.execute: blink_comm_led 56 | 57 | script: 58 | - id: blink_comm_led 59 | mode: restart 60 | then: 61 | - light.turn_on: comm_led 62 | - delay: 200ms 63 | - light.turn_off: comm_led 64 | - id: blink_update_ota_led 65 | mode: single 66 | then: 67 | 68 | 69 | output: 70 | - platform: gpio 71 | id: comm_led_output 72 | pin: GPIO18 73 | - platform: gpio 74 | id: net_led_output 75 | pin: GPIO1 76 | - platform: gpio 77 | id: pow_green_led_output 78 | pin: GPIO0 79 | - platform: gpio 80 | id: pow_red_led_output 81 | pin: GPIO3 82 | 83 | light: 84 | - platform: binary 85 | id: comm_led 86 | output: comm_led_output 87 | - platform: binary 88 | id: net_led 89 | output: net_led_output 90 | - platform: binary 91 | id: pow_green_led 92 | output: pow_green_led_output 93 | - platform: binary 94 | id: pow_red_led 95 | output: pow_red_led_output 96 | -------------------------------------------------------------------------------- /packages/grid.yaml: -------------------------------------------------------------------------------- 1 | binary_sensor: 2 | - platform: inv_8851 3 | bus_and_grid_voltage_match: 4 | name: "Bus and grid voltage match" 5 | 6 | sensor: 7 | - platform: inv_8851 8 | grid_current: 9 | name: "Grid current" 10 | grid_frequency: 11 | name: "Grid frequency" 12 | grid_voltage: 13 | name: "Grid voltage" 14 | 15 | select: 16 | - platform: inv_8851 17 | grid_voltage_range: 18 | name: "Grid voltage range" 19 | on_grid: 20 | name: "On grid" 21 | power_buzzer: 22 | name: "Power buzzer" 23 | -------------------------------------------------------------------------------- /packages/inverter.yaml: -------------------------------------------------------------------------------- 1 | binary_sensor: 2 | - platform: inv_8851 3 | buck_topology_initialization: 4 | name: "Buck topology initialization" 5 | disable_utility: 6 | name: "Disable utility" 7 | inverter_topology_initialization: 8 | name: "Inverter topology initialization" 9 | llc_topology_initialization: 10 | name: "LLC topology initialization" 11 | system_initialization: 12 | name: "System initialization" 13 | system_power: 14 | name: "System power" 15 | 16 | text_sensor: 17 | - platform: inv_8851 18 | buck_topology: 19 | name: "Buck topology" 20 | inverter_topology: 21 | name: "Inverter topology" 22 | llc_topology: 23 | name: "LLC topology" 24 | 25 | sensor: 26 | - platform: inv_8851 27 | bus_voltage: 28 | name: "Bus voltage" 29 | inverter_apparent_power: 30 | name: "Inverter apparent power" 31 | inverter_apparent_power_percentage: 32 | name: "Inverter apparent power percentage" 33 | inverter_current: 34 | name: "Inverter current" 35 | inverter_frequency: 36 | name: "Inverter frequency" 37 | inverter_power_percentage: 38 | name: "Inverter power percentage" 39 | inverter_software_version: 40 | name: "Inverter software version" 41 | inverter_voltage: 42 | name: "Inverter voltage" 43 | inverter_voltage_dc_component: 44 | name: "Inverter voltage DC component" 45 | load_apparent_power: 46 | name: "Load apparent power" 47 | load_current: 48 | name: "Load current" 49 | load_power: 50 | name: "Load power" 51 | log_number: 52 | name: "Log number" 53 | low_load_current: 54 | name: "Low load current" 55 | 56 | select: 57 | - platform: inv_8851 58 | auto_return: 59 | name: "Auto return" 60 | backlight: 61 | name: "Backlight" 62 | buzzer: 63 | name: "Buzzer" 64 | fault_record: 65 | name: "Fault record" 66 | frequency: 67 | name: "Frequency" 68 | overload_restart: 69 | name: "Overload restart" 70 | overtemp_restart: 71 | name: "Overtemp restart" 72 | powersave_mode: 73 | name: "Powersave mode" 74 | warning_buzer: 75 | name: "Warning buzer" 76 | 77 | number: 78 | - platform: inv_8851 79 | inverter_maximum_power: 80 | name: "Inverter maximum power" 81 | mode: box 82 | min_value: 0 83 | max_value: ${inverter_maximum_power} 84 | step: 1 85 | output_frequency: 86 | name: "Output frequency" 87 | mode: box 88 | min_value: 50 89 | max_value: 60 90 | step: 1 91 | output_voltage: 92 | name: "Output voltage" 93 | mode: box 94 | min_value: 100 95 | max_value: 240 96 | step: 1 97 | -------------------------------------------------------------------------------- /packages/parallel.yaml: -------------------------------------------------------------------------------- 1 | binary_sensor: 2 | - platform: inv_8851 3 | bus: 4 | name: "Bus" 5 | grid_pll: 6 | name: "Grid PLL" 7 | parallel_lock_phase: 8 | name: "Parallel lock phase" 9 | 10 | sensor: 11 | - platform: inv_8851 12 | parallel_current: 13 | name: "Parallel current" 14 | parallel_frequency: 15 | name: "Parallel frequency" 16 | parallel_voltage: 17 | name: "Parallel voltage" 18 | 19 | select: 20 | - platform: inv_8851 21 | parallel_operation: 22 | name: "Parallel operation" 23 | phase: 24 | name: "Phase" 25 | -------------------------------------------------------------------------------- /packages/pv.yaml: -------------------------------------------------------------------------------- 1 | binary_sensor: 2 | - platform: inv_8851 3 | pv_excess: 4 | name: "PV excess" 5 | pv_input: 6 | name: "PV input" 7 | pv_topology_initialization: 8 | name: "PV topology initialization" 9 | 10 | text_sensor: 11 | - platform: inv_8851 12 | pv_topology: 13 | name: "PV topology" 14 | 15 | sensor: 16 | - platform: inv_8851 17 | pv_current: 18 | name: "PV current" 19 | pv_power: 20 | name: "PV power" 21 | pv_voltage: 22 | name: "PV voltage" 23 | -------------------------------------------------------------------------------- /packages/temperature.yaml: -------------------------------------------------------------------------------- 1 | sensor: 2 | - platform: inv_8851 3 | bts_temperature: 4 | name: "BTS temperature" 5 | fan1_speed_percentage: 6 | name: "Fan 1 speed percentage" 7 | fan2_speed_percentage: 8 | name: "Fan 2 speed percentage" 9 | ntc2_temperature: 10 | name: "NTC2 temperature" 11 | ntc3_temperature: 12 | name: "NTC3 temperature" 13 | ntc4_temperature: 14 | name: "NTC4 temperature" 15 | -------------------------------------------------------------------------------- /packages/wifi-plug-pro-05.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | uart_tx_pin: GPIO1 3 | uart_rx_pin: GPIO3 4 | 5 | esphome: 6 | on_boot: 7 | then: 8 | - light.turn_off: srv_led 9 | 10 | globals: 11 | - id: updating_ota 12 | type: bool 13 | initial_value: 'false' 14 | 15 | ota: 16 | on_begin: 17 | - globals.set: 18 | id: updating_ota 19 | value: 'true' 20 | - while: 21 | condition: 22 | lambda: return id(updating_ota); 23 | then: 24 | - light.turn_on: srv_led 25 | - delay: 200ms 26 | - light.turn_off: srv_led 27 | - delay: 200ms 28 | on_end: 29 | - globals.set: 30 | id: updating_ota 31 | value: 'false' 32 | 33 | interval: 34 | - interval: 1s 35 | then: 36 | - switch.toggle: keep_alive_switch 37 | - if: 38 | condition: wifi.connected 39 | then: 40 | if: 41 | condition: 42 | - light.is_off: net_led 43 | then: 44 | - light.turn_on: net_led 45 | else: 46 | - light.turn_on: net_led 47 | - delay: 500ms 48 | - light.turn_off: net_led 49 | 50 | uart: 51 | - id: !extend inv_8851_uart 52 | debug: 53 | sequence: 54 | - script.execute: blink_comm_led 55 | 56 | script: 57 | - id: blink_comm_led 58 | mode: restart 59 | then: 60 | - light.turn_on: comm_led 61 | - delay: 200ms 62 | - light.turn_off: comm_led 63 | - id: blink_update_ota_led 64 | mode: single 65 | then: 66 | 67 | 68 | output: 69 | - platform: gpio 70 | id: comm_led_output 71 | pin: GPIO5 72 | - platform: gpio 73 | id: net_led_output 74 | pin: GPIO0 75 | - platform: gpio 76 | id: srv_led_output 77 | pin: GPIO4 78 | 79 | light: 80 | - platform: binary 81 | id: comm_led 82 | output: comm_led_output 83 | - platform: binary 84 | id: net_led 85 | output: net_led_output 86 | - platform: binary 87 | id: srv_led 88 | output: srv_led_output 89 | 90 | switch: 91 | - platform: gpio 92 | id: keep_alive_switch 93 | pin: GPIO13 94 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # 8851 inverter protocol integration ESPHome component 2 | 3 | ## Denial of Responsibility 4 | 5 | **Disclaimer:** Messing up with inverter parameters could lead to inverter or battery failure. Please make sure you understand what you are doing. This project is provided "as-is" without any warranty or support of any kind. By using this software, you agree that: 6 | 7 | 1. **No Warranty:** The project is provided without any warranty, expressed or implied. The entire risk of using the project is assumed by you, the user. 8 | 2. **No Support:** The author(s) of this project are under no obligation to provide support, updates, or maintenance. Issues and pull requests may be addressed at the sole discretion of the project contributors. 9 | 3. **Use at Your Own Risk:** The project may involve experimental features or third-party dependencies, and the user is responsible for ensuring its compatibility with their system. The author(s) are not responsible for any damage, data loss, or other consequences that may arise from the use of this project. 10 | 4. **No Guarantee of Compatibility:** The project may not be compatible with all environments, hardware, or software configurations. It is the user's responsibility to verify compatibility before use. 11 | 5. **Security Considerations:** The project may not have undergone a comprehensive security review. Users are advised to exercise caution and not use this project in critical or security-sensitive applications. 12 | 6. **Third-Party Dependencies:** This project may rely on third-party libraries, frameworks, or tools. The user is responsible for complying with the licenses and terms associated with these dependencies. 13 | 14 | By using this project, you acknowledge and agree to these terms. If you do not agree with these terms, do not use or contribute to this project. 15 | 16 | ## Compatible inverters 17 | 18 | * PowMr POW-HVM6.5K-48V (tested by [@lufton](https://github.com/lufton)) 19 | * PowMr POW-HVM4.5K-24V 20 | * Simular inverters that utilize the same DTU (WBS1-V001) 21 | 22 | ## Capabilities 23 | 24 | This component will let you monitor (sensors, binary sensors and text sensors) and control (numbers and selects) compatible inverter without need of installing Chinese software and depend on any third-party services. 25 | 26 | ## Why to use this component 27 | 28 | * No need to use original software. Chinese mobile app doen't work stable, is slow and not reliable. 29 | * No need to send you data to custom server. All data sent from DTU with original firmware are stored with open access MQTT server. That is potential security breach, that can lead to data leak and even your inverter configuration changes witch can damage you hardware. 30 | * Some extra configuration parameters that are absent in the app, like `output_frequency`, `warning_buzzer`, `inverter_maximum_power`. 31 | * Possiblity to set some configuration parameters more accurately, like `battery_charge_cut_off_current`, `output_voltage`, `total_charge_current`, `util_charge_current`. You can set tham as any number from the range in comparison to inverter's menu where you can only select values from predefined options. 32 | * Simple integration with 3rd party services like Home Assistant. 33 | * Local automations. 34 | 35 | ### Minimal configuration 36 | 37 | ```yaml 38 | uart: 39 | - baud_rate: 9600 40 | 41 | inv_8851: 42 | version: 1 # read about this parameter below 43 | 44 | sensor: 45 | - platform: inv_8851 46 | battery_voltage: 47 | name: "Battery voltage" 48 | ... 49 | ``` 50 | 51 | Full list of available entities [is here](#available-entities). 52 | 53 | ### Options 54 | 55 | There are several options you may need to set: 56 | 57 | * `update_interval` 58 | * `version` 59 | 60 | `update_interval` tells how often to request state and configuration from inverter, default value is 5s and should suite most situations. 61 | 62 | ```yaml 63 | inv_8851: 64 | update_interval: 30s 65 | ``` 66 | 67 | `version` should be one of `1` (confirmed firmware version: 0005) or `2` (confirmed firmware version: 8100). Right now there are several protocol versions. They are pretty similar except they have a bit different packets length. `144/90` bytes for version=1 and `148/94` bytes for version=2 (state and config data block length respectively). If you experience problems with changing parameters it could mean that you should try other value (you can use `substitutions→version` parameter). It's only my guess, but it looks like version 1 is not compatible with newer firmware, so try using version 2 for newer models. Also you should see warning messages in logs if you peaked wrong version. 68 | 69 | ## 24v vs 48v version 70 | 71 | 24v and 48v files are different only in configuration of some entities witch has no sense for 24v version (bms_cell_09_voltage — bms_cell_16_voltage) and minimum/maximum values for some number entities (as they depend on voltage). So in theory flashing "wrong" configuration shouldn't make any harm to ESP or inverter. 72 | 73 | ## ...-local.yaml 74 | 75 | This project build to be as simple is possible, so in most cases you woudn't need those files. Regular `.yaml` file will download latest stable version from this repository and use it upon build process. But if you want to customize configuration or you plan to change files in `packages` or `components` directories, than you probably want to use those. Also `-local.yaml` files include debugging by default. 76 | 77 | ## inverter_maximum_power 78 | 79 | First of all there are two places you can find `inverter_maximum_power` parameter: 80 | 81 | * Under `substitutions` section of example files 82 | * Under `number` configuration section 83 | 84 | The reason for that parameter present in `substitutions` section is to limit `max_value` parameter for `inverter_maximum_power` number entity. This is needed to prevent user from setting to high value for that entity. 85 | 86 | Number entity `inverter_maximum_power` sets software limitaion for inverter's maximum power (total power inverter consumes from grid including battery charging power). Setting value that is higher than factory-default (4500W for 4.5kW inverter version and 6500W for 6.5kW inverter version) for that number entity can lead to potential damage. From other hand you can set software limitaion lower than factory-default to protect your inverter from working in conditions close to maximum possible and prolong it's life. In case of exceeding 110% of `inverter_maximum_power` value, inverter will turn off with error code of `07`. 87 | 88 | **Please make sure you understand what you're doing before adjusting this parameter.** 89 | 90 | ## Flashing DTU WBS1-V001 91 | 92 | You can flash WBS1-V001 using this component (use corresponding `dtu-wbs1-v001...-example.yaml` file). This way you can use original DTU with much more comfortable and easy way. This configuration also supports onboard LED indication. 93 | In order to flash original DTU follow next steps: 94 | 95 | 1. Disassemble DTU (it has 4 screws in the corners under the foamy sticker on the bottom) 96 | 2. Solder pin headers of jump wires to +5V, GND1, BOOT1, RXD1, TXD1 pads (they are labeled) 97 | 3. Connect USB to TTL module VCC → +5V, RX → TXD1, TX → RXD1 and GND → GND1 with BOOT1 pin connected to GND1 98 | 4. Dump and store original firmware using [esptool](https://github.com/espressif/esptool/releases/latest) (replace `COM1` with valid port number):
99 | `esptool.exe -p COM1 -b 460800 read_flash 0x0 0x400000 DTU.bin` 100 | 5. Flash ESPHome with corresponding configuration 101 | 6. Disconnect USB to TTL module, assemble DTU and connect to inverter 102 | 7. In order to restore original firmware connect DTU and USB to TTL module with BOOT1 pin connected to GND1 and run command (replace `COM1` and `DTU.bin` with valid port number and firmware dump file backed up in step 4 path):
103 | `esptool.exe -p COM1 -b 460800 write_flash 0x0 DTU.bin` 104 | 105 | ## Flashing ESP32 or ESP8266 106 | 107 | You can flash ESP32 or ESP8266 using this component the same way you flash your other ESPHome projects. Read [official guides](https://esphome.io/guides/) if you have any questions. 108 | 109 | ## Debugging 110 | 111 | If you have data retrival issues consider enabling debugging. In order to do so: 112 | 113 | 1. Clone this repo locally ```git clone https://github.com/lufton/esphome-inv-8851.git``` 114 | 2. Change `secrets.yaml` file accordingly 115 | 3. Flash your device with `...-local.yaml` file that matches your hardware 116 | 4. Check sireal port output, you should see: 117 | * Packets sent (`>>> 88 51 ...`) to inverter (should be present in any case) 118 | * Packets received (`<<< 88 51 ...`) from inverter (could be missing if there is an issue with communication between inverter and ESP8266/ESP32) 119 | 5. Packets should start with `88 51 ...` (that's why this project and protocol was called `8851`): 120 | * If you see incoming packets witch starts with `88 51 ...`, then it means your connection is correct, even though if you don't receive any values from inverter. That could mean you have other protocol revision witch could be analized and implemented. In this case just [create an issue](https://github.com/lufton/esphome-inv-8851/issues/new/choose) with your findings. 121 | * If you see incoming packets witch starts with somesing else, then it means you definetly have an issue with wiring and noise. Check connection once again and try to use shorter wires. 122 | * If you don't see any incoming packets, then it could mean that there is something wrong with wiring or hardware. Check connection once again and make sure hardware you use is working corectly. 123 | 124 | ## Available entities 125 | 126 | ### Sensors 127 | 128 | | ID | Description | Unit | Res. | 129 | |------------------------------------ |-------------------------------------------------------------------------------------------------- |------ |------ | 130 | | battery_charge_current | Maximum current to charge battery. It will start decreasing when battery enter absorption stage. | A | 0.1 | 131 | | battery_voltage | | V | 0.01 | 132 | | bms_battery_current | | A | 0.1 | 133 | | bms_battery_soc | | % | 1 | 134 | | bms_battery_voltage | | V | 0.01 | 135 | | bms_cell_01_voltage | | V | 0.01 | 136 | | bms_cell_02_voltage | | V | 0.01 | 137 | | bms_cell_03_voltage | | V | 0.01 | 138 | | bms_cell_04_voltage | | V | 0.01 | 139 | | bms_cell_05_voltage | | V | 0.01 | 140 | | bms_cell_06_voltage | | V | 0.01 | 141 | | bms_cell_07_voltage | | V | 0.01 | 142 | | bms_cell_08_voltage | | V | 0.01 | 143 | | bms_cell_09_voltage | | V | 0.01 | 144 | | bms_cell_10_voltage | | V | 0.01 | 145 | | bms_cell_11_voltage | | V | 0.01 | 146 | | bms_cell_12_voltage | | V | 0.01 | 147 | | bms_cell_13_voltage | | V | 0.01 | 148 | | bms_cell_14_voltage | | V | 0.01 | 149 | | bms_cell_15_voltage | | V | 0.01 | 150 | | bms_cell_16_voltage | | V | 0.01 | 151 | | bts_temperature | | °C | 1 | 152 | | bus_voltage | | V | 0.1 | 153 | | fan1_speed_percentage | | % | 1 | 154 | | fan2_speed_percentage | | % | 1 | 155 | | grid_current | | A | 0.01 | 156 | | grid_frequency | | Hz | 0.01 | 157 | | grid_voltage | | V | 0.1 | 158 | | inverter_apparent_power | | VA | 1 | 159 | | inverter_apparent_power_percentage | | % | 1 | 160 | | inverter_current | | A | 0.01 | 161 | | inverter_frequency | | Hz | 0.01 | 162 | | inverter_power_percentage | | % | 1 | 163 | | inverter_software_version | | N/A | 1 | 164 | | inverter_voltage | | V | 0.1 | 165 | | inverter_voltage_dc_component | | ? | ? | 166 | | load_apparent_power | | VA | 1 | 167 | | load_current | | A | 0.01 | 168 | | load_power | | W | 1 | 169 | | log_number | | N/A | 1 | 170 | | low_load_current | | A | 0.01 | 171 | | ntc2_temperature | | °C | 1 | 172 | | ntc3_temperature | | °C | 1 | 173 | | ntc4_temperature | | °C | 1 | 174 | | parallel_current | | A | 0.01 | 175 | | parallel_frequency | | Hz | 0.01 | 176 | | parallel_voltage | | V | 0.1 | 177 | | pv_current | | A | 0.01 | 178 | | pv_power | | W | 1 | 179 | | pv_voltage | | V | 0.1 | 180 | 181 | ### Binary sensors 182 | | ID | Description | 183 | |---------------------------------- |------------------------------------------------------------------- | 184 | | battery | Indicates if battery is connected | 185 | | buck_topology_initialization | Indicates if buck topology is initialized | 186 | | bus | ? | 187 | | bus_and_grid_voltage_match | ? | 188 | | charging | Indicates if battery is still charging | 189 | | disable_utility | ? Indicates if inverter works in bypass mode | 190 | | equalization_finished | Indicates if battery equalization program is finished | 191 | | equalization_started | Indicates if battery equalization program is started | 192 | | float_charging | Indeicates if battery is in float charging mode | 193 | | grid_pll | Indicates if inverter phase is locked | 194 | | inverter_topology_initialization | Indicates if inverter's topology is initialized | 195 | | llc_topology_initialization | Indicates if LLC topology is initialized | 196 | | parallel_lock_phase | Indicates if phases of inverters connected in parallel are locked | 197 | | pv_excess | Indicates if there is PV power excess avaiable | 198 | | pv_input | Indicates if PV is connected | 199 | | pv_topology_initialization | Indicates if PV topology is initialized | 200 | | system_initialization | Indicates if all inverter's systems are initialized | 201 | | system_power | Indicates if inverter is turned on using button on left side | 202 | 203 | ### Text sensors 204 | | ID | Description | 205 | |------------------- |------------------------- | 206 | | buck_topology | Buck topology state | 207 | | inverter_topology | Inverter topology state | 208 | | llc_topology | LLC topology state | 209 | | pv_topology | PV topology state | 210 | 211 | ### Selects 212 | | ID | Description | Options | Menu | 213 | |------------------------ |------------------------------------------------------------------------------------------------------------ |--------------------------------------------------------------------------------------------------------------------- |------ | 214 | | auto_return | Auto return to home screen after 1 minute of inactivity | OFF
ON | 19 | 215 | | backlight | Backlight always ON mode | OFF
ON | 20 | 216 | | battery_equalization | Battery equalization program activation | OFF
ON | 33 | 217 | | battery_type | Battery type selection. If User-defined type is selected, then additional voltage parameters can be set. | AGM
Flooded
User-defined
Library | 05 | 218 | | buzzer | Buzzer that beep every time you press any screen button | OFF
ON | 18 | 219 | | charge_energy_priority | Charger source priority | PV & Grid — PV and Grid at the same time
PV > Grid — Priority for PV, then Grid
PV only — Only PV | 16 | 220 | | fault_record | Record fault code | OFF
ON | 25 | 221 | | frequency | Default frequency output mode, can be adjusted with `output_frequency` number | 50Hz
60Hz | 09 | 222 | | grid_voltage_range | Grid voltage range in witch inverter will work, otherwise will switch to battery | APL — 90-265V
UPS — 170-265V | 03 | 223 | | on_grid | Send produced enery to Grid | OFF
ON | 10 | 224 | | output_energy_priority | Which source to use first: Grid or PV | PV > Grid > Battery — Grid over battery
PV > Battery > Grid — Battery over grid | 01 | 225 | | overload_restart | Automatic restart after overload protection | OFF
ON | 06 | 226 | | overtemp_restart | Automatic restart after over temperature protection | OFF
ON | 07 | 227 | | parallel_operation | Parallel operation mode | OFF
ON | 14 | 228 | | phase | Witch phase inverter is connected to | A
B
C | 15 | 229 | | power_buzzer | Buzzer that beep every time Grid becomes unavailable | OFF
ON | 22 | 230 | | powersave_mode | Power save mode, will pulse output voltage to determine and start if load is connected | OFF
ON | 04 | 231 | | warning_buzzer | Buzzer that beep every time inverter raise warning | OFF
ON | N/A | 232 | 233 | ### Numbers 234 | | ID | Description | Unit | Res. | Range | Menu | 235 | |-------------------------------- |---------------------------------------------------------------------------------------------------------------------- |------ |------ |------------------------- |------ | 236 | | battery_back_to_util_voltage | Voltage point at witch inverter will switch to Grid in PV > Battery > Grid mode | V | 0.1 | 20…29.2
40…58.4 | 13 | 237 | | battery_bulk_voltage | Fully charged battery voltage | V | 0.1 | 24…29.2
48…58.4 | 26 | 238 | | battery_float_voltage | Floating charging mode voltage | V | 0.1 | 24…29.2
48…58.4 | 27 | 239 | | battery_charge_cut_off_current | Charge current at witch inverted assumes that battery is fully charged and switches into floating charging mode | A | 0.1 | 2…20 | 12 | 240 | | battery_cut_off_voltage | Minimum battery voltage, inverter will disconnect battery at this point | V | 0.1 | 20…24
40…48 | 29 | 241 | | battery_equalization_interval | How often battery equalization program will be triggered | Day | 1 | 0…90 | 37 | 242 | | battery_equalization_time | How long battery equalization program will run | Min. | 1 | 5…900 | 35 | 243 | | battery_equalization_timeout | How long battery equalization program can run before terminating | Min. | 1 | 5…900 | 36 | 244 | | battery_equalization_voltage | Battery equalization voltage | V | 0.1 | 25…29.5
50…59 | 34 | 245 | | inverter_maximum_power | Inverter maximum output power | W | 1 | 0…4500
0…6500 | N/A | 246 | | output_frequency | Output frequency, that can be in range 50-55Hz for 50Hz mode and 60-55Hz for 60Hz mode | Hz | 1 | 50…55
60…55 | N/A | 247 | | output_voltage | Output voltage, resets to closest lower number that is multiple of 5 (234V → 230V, 229V → 225V) after exiting menu | V | 1 | 100…240 | 08 | 248 | | total_charge_current | Maximum battery charge current equals PV current + Grid current | A | 0.1 | 0…130
0…150 | 02 | 249 | | util_charge_current | Maximum current used from Grid to charge battery | A | 0.1 | 0…110
0…140 | 11 | 250 | 251 | ## WBS1-V001 simplified schematics 252 | ![WBS1-V001 simplified schematics](resources/WBS1-V001.svg?raw=true "WBS1-V001") 253 |
254 | WBS1-V001 module pictures 255 | WBS1-V001 256 | WBS1-V001 screws 257 | WBS1-V001 parts 258 | WBS1-V001 PCB (top) 259 | WBS1-V001 PCB (bottom) 260 |
261 | 262 | ## Original firmware dump 263 | [Here](https://github.com/lufton/esphome-inv-8851/blob/main/DTU.bin) you can find original firmware dump file. Restore procedure described in the last step of [Flashing DTU WBS1-V001](#flashing-dtu-wbs1-v001) section. 264 | 265 | ## Thanks 266 | * [@leodesigner](https://github.com/leodesigner) for his work on [powmr4500_comm](https://github.com/leodesigner/powmr4500_comm) 267 | * [@aquaforum](https://github.com/aquaforum) for his work on [c++ header file](https://github.com/leodesigner/powmr4500_comm/blob/main/include/inv8851.h) and protocol reverse engineering 268 | -------------------------------------------------------------------------------- /resources/WBS1-V001.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lufton/esphome-inv-8851/1aeae3ac672e268ff1032a66a962abef8737fcc4/resources/WBS1-V001.jpg -------------------------------------------------------------------------------- /resources/WBS1-V001_PCB_bottom.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lufton/esphome-inv-8851/1aeae3ac672e268ff1032a66a962abef8737fcc4/resources/WBS1-V001_PCB_bottom.jpg -------------------------------------------------------------------------------- /resources/WBS1-V001_PCB_top.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lufton/esphome-inv-8851/1aeae3ac672e268ff1032a66a962abef8737fcc4/resources/WBS1-V001_PCB_top.jpg -------------------------------------------------------------------------------- /resources/WBS1-V001_parts.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lufton/esphome-inv-8851/1aeae3ac672e268ff1032a66a962abef8737fcc4/resources/WBS1-V001_parts.jpg -------------------------------------------------------------------------------- /resources/WBS1-V001_screws.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lufton/esphome-inv-8851/1aeae3ac672e268ff1032a66a962abef8737fcc4/resources/WBS1-V001_screws.jpg -------------------------------------------------------------------------------- /secrets.yaml: -------------------------------------------------------------------------------- 1 | wifi_ssid: changeme 2 | wifi_password: changeme 3 | ap_password: changeme 4 | ota_password: changeme 5 | api_encryption_key: changeme 6 | -------------------------------------------------------------------------------- /wifi-plug-pro-05-24v-example-local.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | inverter_maximum_power: "4500" 3 | version: "2" 4 | name: wifi-plug-pro-05 5 | friendly_name: Wi-Fi Plug Pro-05 6 | 7 | esp8266: 8 | board: d1_mini 9 | 10 | packages: 11 | core: !include packages/core-local.yaml 12 | inverter: !include packages/inverter.yaml 13 | grid: !include packages/grid.yaml 14 | temperature: !include packages/temperature.yaml 15 | battery: !include packages/battery.yaml 16 | battery-24v: !include packages/battery-24v.yaml 17 | # pv: !include packages/pv.yaml 18 | # parallel: !include packages/parallel.yaml 19 | # bms-24v: !include packages/bms-24v.yaml 20 | wifi-plug-pro-05: !include packages/wifi-plug-pro-05.yaml 21 | 22 | wifi: 23 | ssid: !secret wifi_ssid 24 | password: !secret wifi_password 25 | 26 | ap: 27 | ssid: ${friendly_name} 28 | password: !secret ap_password 29 | 30 | api: 31 | encryption: 32 | key: !secret api_encryption_key 33 | 34 | ota: 35 | - platform: esphome 36 | password: !secret ota_password 37 | 38 | interval: 39 | interval: 1s 40 | then: 41 | if: 42 | condition: api.connected # mqtt.connected 43 | then: 44 | if: 45 | condition: 46 | light.is_off: srv_led 47 | then: 48 | light.turn_on: srv_led 49 | else: 50 | - light.turn_on: srv_led 51 | - delay: 500ms 52 | - light.turn_off: srv_led 53 | -------------------------------------------------------------------------------- /wifi-plug-pro-05-24v-example.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | inverter_maximum_power: "4500" 3 | version: "2" 4 | name: wifi-plug-pro-05 5 | friendly_name: Wi-Fi Plug Pro-05 6 | 7 | esp8266: 8 | board: d1_mini 9 | 10 | packages: 11 | inv_8851: 12 | url: https://github.com/lufton/esphome-inv-8851 13 | ref: main 14 | files: 15 | - packages/core.yaml 16 | - packages/inverter.yaml 17 | - packages/grid.yaml 18 | - packages/temperature.yaml 19 | - packages/battery.yaml 20 | - packages/battery-24v.yaml 21 | # - packages/pv.yaml 22 | # - packages/parallel.yaml 23 | # - packages/bms-24v.yaml 24 | - packages/wifi-plug-pro-05.yaml 25 | refresh: 0s 26 | 27 | wifi: 28 | ssid: !secret wifi_ssid 29 | password: !secret wifi_password 30 | 31 | ap: 32 | ssid: ${friendly_name} 33 | password: !secret ap_password 34 | 35 | api: 36 | encryption: 37 | key: !secret api_encryption_key 38 | 39 | ota: 40 | - platform: esphome 41 | password: !secret ota_password 42 | 43 | interval: 44 | interval: 1s 45 | then: 46 | if: 47 | condition: api.connected # mqtt.connected 48 | then: 49 | if: 50 | condition: 51 | light.is_off: srv_led 52 | then: 53 | light.turn_on: srv_led 54 | else: 55 | - light.turn_on: srv_led 56 | - delay: 500ms 57 | - light.turn_off: srv_led 58 | --------------------------------------------------------------------------------