diff --git a/README.md b/README.md index cfd673a..88a8cea 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ +# Important Notice: +DO NOT USE RS485 ON THE BMS - PORT! This port only has a baudrate of 9600, which is too slow for regular updates. +Use the Modbus port. +Configure it to a baudrate (in the Advanced Menu) of 115200. This allows for updates every second. + # ESPhome for deye ESPhome configuration for monitoring and control of Deye inverters in Home Assistant. This include all addresses i could see relevant from the inverter. @@ -70,6 +75,7 @@ pip install --upgrade esphome ``` ## Hardware diagram + RX / TX between esp and ttl converter way have to be swapped. This seems to be a little different from espboard to espboard. Check Termination: check that 120 Ohm are between B+ and B- (short wire); for long wire use 120 Ohms on both sides. If it dosent communicate(RX/TX led both blinking) Try swap rx/tx on the esp. diff --git a/example/ct_ratio_automation.yaml b/example/ct_ratio_automation.yaml new file mode 100644 index 0000000..f53b9b7 --- /dev/null +++ b/example/ct_ratio_automation.yaml @@ -0,0 +1,36 @@ +alias: Set CT Ratio Based on Netzanschluss Leistung +description: Adjust sun12k_general_ct_ratio based on netzanschluss_leistung +triggers: + - entity_id: sensor.netzanschluss_leistung + below: -8000 + for: "00:00:10" + trigger: numeric_state + - entity_id: sensor.netzanschluss_leistung + above: -1000 + for: "00:00:10" + trigger: numeric_state + - trigger: time_pattern + seconds: "30" +actions: + - choose: + - conditions: + - condition: numeric_state + entity_id: sensor.netzanschluss_leistung + below: -8000 + sequence: + - target: + entity_id: number.sun12k_general_ct_ratio + data: + value: 1000 + action: number.set_value + - conditions: + - condition: numeric_state + entity_id: sensor.netzanschluss_leistung + above: -1000 + sequence: + - target: + entity_id: number.sun12k_general_ct_ratio + data: + value: 2000 + action: number.set_value +mode: restart diff --git a/example/deye.yaml b/example/deye.yaml new file mode 100644 index 0000000..643f09d --- /dev/null +++ b/example/deye.yaml @@ -0,0 +1,87 @@ +substitutions: + name: deye #name in ESPhome + esp_name: deye + device_description: "Esphome component for Deye sun-12k-sg04lp3" #Description in ESPhome + modbus_controller_id: deye_modbus_controller #just a random name for the modbus controler - this is the high frequency controller for live values + device_type: sun12k #all entities in Home Assistant will start with this text to help identify the entitys + entities_id_prefix: SUN12K + entities_name_prefix: SUN12K +esphome: + name: ${name} + +esp32: + board: wt32-eth01 + framework: + type: esp-idf + +# Enable logging +logger: + level: INFO + baud_rate: 0 + +# Enable Home Assistant API +ota: + platform: esphome + password: !secret ota_password + +# Enable Home Assistant API +api: + encryption: + key: !secret api_encryption + +ethernet: + type: LAN8720 + mdc_pin: GPIO23 + mdio_pin: GPIO18 + clk_mode: GPIO0_IN + phy_addr: 1 + power_pin: GPIO16 + +time: + - platform: homeassistant + +uart: + - id: uart_deye + tx_pin: GPIO17 + rx_pin: GPIO05 + baud_rate: 115200 + stop_bits: 1 + rx_buffer_size: 4096 + +modbus: + - id: modbus_deye + uart_id: uart_deye + +modbus_controller: + - id: ${modbus_controller_id} + address: 0x1 + modbus_id: modbus_deye + setup_priority: -10 + update_interval: 1sec + +packages: + # Different modules for the different sections of the inverter + solar: !include esphome-for-deye/modules/solar.yaml + battery: !include esphome-for-deye/modules/battery.yaml + + load: !include esphome-for-deye/modules/load.yaml + generator: !include esphome-for-deye/modules/generator.yaml # Generator, Micro Inverter or Smart Load + general: !include esphome-for-deye/modules/general.yaml + status: !include esphome-for-deye/modules/status.yaml + internal: !include esphome-for-deye/modules/internal.yaml # Internal CTs Current/Power Measurement + inverter: !include esphome-for-deye/modules/inverter.yaml + ups: !include esphome-for-deye/modules/ups.yaml + out-of-grid: !include esphome-for-deye/modules/out-of-grid.yaml + + # + # Enable for grid-connected systems + grid: !include esphome-for-deye/modules/grid.yaml + external: !include esphome-for-deye/modules/external.yaml # External CTs Current/Power Measurement + + + advanced: !include esphome-for-deye/modules/advanced_readwrite_select.yaml + # Time of Use for Grid-Connected Systems + time-of-use-common: !include esphome-for-deye/modules/time-of-use-common.yaml + # Only Include ONE of these (select OR number) + time-of-use-time-as-select: !include esphome-for-deye/modules/time-of-use-time-as-select.yaml + #time-of-use-time-as-number: !include modules/time-of-use-time-as-number.yaml diff --git a/example/template_sensor.yaml b/example/template_sensor.yaml new file mode 100644 index 0000000..4772232 --- /dev/null +++ b/example/template_sensor.yaml @@ -0,0 +1,10 @@ +template: + sensor: + - name: "Netzanschluss Leistung" + unit_of_measurement: "W" + state: > + {% set netz_deye = states('sensor.sun12k_external_ct_active_power_total') | float %} + {% set ratio = states('number.sun12k_general_ct_ratio') | float %} + + {{ (netz_deye * 2000 / ratio) | round(1, default=0) }} + device_class: power diff --git a/modules/advanced_readwrite_select.yaml b/modules/advanced_readwrite_select.yaml index 02c4126..17fccad 100644 --- a/modules/advanced_readwrite_select.yaml +++ b/modules/advanced_readwrite_select.yaml @@ -416,13 +416,13 @@ select: uint16_t select_value = uint16_t(value); // Debug - esphome::ESP_LOGI("main","Modbus: Write - Advanced_BMS_Err_Stop set to %d" , select_value); + ESP_LOGI("main","Modbus: Write - Advanced_BMS_Err_Stop set to %d" , select_value); // Current Value of the Register (all bits) uint16_t current_value = id(${entities_id_prefix}_Advanced_Register_178).state; // Debug - esphome::ESP_LOGI("main","Modbus: Write - Previous Register 178 Value (unmodified) = %d", current_value); + ESP_LOGI("main","Modbus: Write - Previous Register 178 Value (unmodified) = %d", current_value); // Declare Variable uint16_t write_value = 0; diff --git a/modules/battery.yaml b/modules/battery.yaml index 18b77cc..a0d5e43 100644 --- a/modules/battery.yaml +++ b/modules/battery.yaml @@ -10,18 +10,27 @@ select: "Lead Acid": 0 "Lithium (BMS)": 1 - # To be completed - #- platform: modbus_controller - # use_write_multiple: true - # modbus_controller_id: ${modbus_controller_id} - # id: "${entities_id_prefix}_Battery_Lithium_Type" - # name: "${entities_name_prefix}-Battery Lithium Type" - # address: 223 - # bitmask: 0x1 - # value_type: U_WORD - # optionsmap: - # "Pylon (CAN)": 0 - # "": 1 + + - platform: modbus_controller + use_write_multiple: true + modbus_controller_id: ${modbus_controller_id} + id: "${entities_id_prefix}_Battery_Lithium_Type" + name: "${entities_name_prefix}-Battery Lithium Type" + address: 223 + value_type: U_WORD + optionsmap: + "Pylon / Solax / Universal CAN Protocol (CAN)": 0x0000 + "Tianbangda RS485 Modbus": 0x0001 + "KOK Protocol": 0x0002 + "Keith Protocol": 0x0003 + "Topband Protocol": 0x0004 + "Pylontech 485 Protocol": 0x0005 + "Jelais 485 Protocol": 0x0006 + "Sunwoda 485 Protocol": 0x0007 + "Xinruineng 485 Protocol": 0x0008 + "Tianbangda 485 Protocol": 0x0009 + "Shenggao Electric CAN Protocol": 0x000A + number: - platform: modbus_controller @@ -90,8 +99,8 @@ number: modbus_controller_id: ${modbus_controller_id} id: "${entities_id_prefix}_Battery_capacity" name: "${entities_name_prefix}-Battery capacity" - address: 101 - unit_of_measurement: V + address: 102 + unit_of_measurement: Ah value_type: U_WORD multiply: 1.0 min_value: 0.00 @@ -133,6 +142,7 @@ sensor: value_type: S_WORD filters: - multiply: 0.1 + - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} skip_updates: 10 @@ -147,6 +157,7 @@ sensor: value_type: S_WORD filters: - multiply: 0.1 + - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} skip_updates: 5 @@ -185,7 +196,7 @@ sensor: address: 586 unit_of_measurement: "°C" accuracy_decimals: 1 - value_type: U_WORD + value_type: S_WORD filters: - offset: -1000 - multiply: 0.1 @@ -226,6 +237,7 @@ sensor: accuracy_decimals: 0 value_type: S_WORD + - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} name: "${entities_name_prefix}-Battery Output Current" diff --git a/modules/external.yaml b/modules/external.yaml index 4965f84..0936b82 100644 --- a/modules/external.yaml +++ b/modules/external.yaml @@ -11,6 +11,8 @@ sensor: accuracy_decimals: 0 value_type: S_WORD + + - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} skip_updates: 2 @@ -23,6 +25,8 @@ sensor: accuracy_decimals: 0 value_type: S_WORD + + - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} skip_updates: 2 @@ -35,6 +39,8 @@ sensor: accuracy_decimals: 0 value_type: S_WORD + + - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} skip_updates: 2 @@ -47,6 +53,8 @@ sensor: accuracy_decimals: 0 value_type: S_WORD + + # External Power Grid - Total Apparent Power - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} @@ -58,4 +66,4 @@ sensor: unit_of_measurement: "VA" state_class: "measurement" accuracy_decimals: 0 - value_type: S_WORD \ No newline at end of file + value_type: S_WORD diff --git a/modules/general.yaml b/modules/general.yaml index 38b5a7c..12e954a 100644 --- a/modules/general.yaml +++ b/modules/general.yaml @@ -45,7 +45,15 @@ binary_sensor: bitmask: 0x1 sensor: - # New - To be Tested + - platform: modbus_controller + modbus_controller_id: ${modbus_controller_id} + name: "${entities_name_prefix}-General - Grid check from Meter or CT" + id: "${entities_id_prefix}_General_Grid_Check_Source" + register_type: holding + address: 344 + unit_of_measurement: "" + value_type: U_WORD + - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} name: "${entities_name_prefix}-General - DC Transformer Temperature" @@ -138,3 +146,16 @@ select: "Selling first": 0 "Zero export to load": 1 "Zero export to CT": 2 + + +number: + - platform: modbus_controller + use_write_multiple: true + modbus_controller_id: ${modbus_controller_id} + id: "${entities_id_prefix}_General_CT_Ratio" + name: "${entities_name_prefix}-General - CT Ratio" + address: 347 + value_type: U_WORD + multiply: 1.0 + min_value: 100.00 + max_value: 10000.00 \ No newline at end of file diff --git a/modules/generator.yaml b/modules/generator.yaml index 32e63cb..1a784cf 100644 --- a/modules/generator.yaml +++ b/modules/generator.yaml @@ -47,9 +47,7 @@ sensor: unit_of_measurement: "W" state_class: "measurement" accuracy_decimals: 1 - filters: - - multiply: 0.1 - value_type: U_WORD + value_type: S_WORD - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} @@ -60,7 +58,7 @@ sensor: unit_of_measurement: "W" state_class: "measurement" accuracy_decimals: 1 - value_type: U_WORD + value_type: S_WORD - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} @@ -71,7 +69,7 @@ sensor: unit_of_measurement: "W" state_class: "measurement" accuracy_decimals: 1 - value_type: U_WORD + value_type: S_WORD - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} @@ -82,4 +80,16 @@ sensor: unit_of_measurement: "W" state_class: "measurement" accuracy_decimals: 1 - value_type: U_WORD \ No newline at end of file + value_type: S_WORD + +number: + - platform: modbus_controller + use_write_multiple: true + modbus_controller_id: ${modbus_controller_id} + id: "${entities_id_prefix}_Generator_Minimum_Solar_Power" + name: "${entities_name_prefix}-Generator Minimum Solar Power to Enable" + address: 139 + unit_of_measurement: W + value_type: U_WORD + min_value: 0 + max_value: 8000 \ No newline at end of file diff --git a/modules/grid.yaml b/modules/grid.yaml index 6c611c1..7d159dc 100644 --- a/modules/grid.yaml +++ b/modules/grid.yaml @@ -79,6 +79,8 @@ sensor: accuracy_decimals: 0 value_type: S_WORD + + - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} name: "${entities_name_prefix}-Grid Power L2" @@ -90,6 +92,8 @@ sensor: accuracy_decimals: 0 value_type: S_WORD + + - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} name: "${entities_name_prefix}-Grid Power L3" @@ -101,6 +105,8 @@ sensor: accuracy_decimals: 0 value_type: S_WORD + + - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} name: "${entities_name_prefix}-Grid Power Total" @@ -112,6 +118,8 @@ sensor: accuracy_decimals: 0 value_type: S_WORD + + - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} skip_updates: 10 diff --git a/modules/internal.yaml b/modules/internal.yaml index afe11e7..aa48975 100644 --- a/modules/internal.yaml +++ b/modules/internal.yaml @@ -80,6 +80,8 @@ sensor: accuracy_decimals: 0 value_type: S_WORD + + # Total Consumption # Disabled since an entity with this Register is already defined in load.yaml #- platform: modbus_controller diff --git a/modules/inverter.yaml b/modules/inverter.yaml index 7c5e182..9956860 100644 --- a/modules/inverter.yaml +++ b/modules/inverter.yaml @@ -70,7 +70,7 @@ sensor: id: "${entities_id_prefix}_Inverter_Output_Phase_Current_L3" register_type: holding address: 632 - unit_of_measurement: "V" + unit_of_measurement: "A" state_class: "measurement" accuracy_decimals: 0 filters: @@ -121,6 +121,8 @@ sensor: accuracy_decimals: 0 value_type: S_WORD + + - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} name: "${entities_name_prefix}-Inverter Output Apparent Power Total" @@ -132,6 +134,8 @@ sensor: accuracy_decimals: 0 value_type: S_WORD + + - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} name: "${entities_name_prefix}-Inverter-Frequency" diff --git a/modules/load.yaml b/modules/load.yaml index cbb7139..866dfc3 100644 --- a/modules/load.yaml +++ b/modules/load.yaml @@ -121,6 +121,8 @@ sensor: accuracy_decimals: 0 value_type: S_WORD + + - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} name: "${entities_name_prefix}-Load Active Power L2" @@ -132,6 +134,8 @@ sensor: accuracy_decimals: 0 value_type: S_WORD + + - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} name: "${entities_name_prefix}-Load Active Power L3" @@ -143,6 +147,8 @@ sensor: accuracy_decimals: 0 value_type: S_WORD + + - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} name: "${entities_name_prefix}-Load Active Power Total" @@ -154,6 +160,8 @@ sensor: accuracy_decimals: 0 value_type: S_WORD + + - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} name: "${entities_name_prefix}-Load Apparent Power Total" @@ -165,6 +173,8 @@ sensor: accuracy_decimals: 0 value_type: S_WORD + + - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} name: "${entities_name_prefix}-Load Frequency" diff --git a/modules/out-of-grid.yaml b/modules/out-of-grid.yaml index a947aaa..2cc14ba 100644 --- a/modules/out-of-grid.yaml +++ b/modules/out-of-grid.yaml @@ -49,6 +49,8 @@ sensor: accuracy_decimals: 0 value_type: S_WORD + + - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} name: "${entities_name_prefix}-Out-of-Grid Active Power L2" @@ -60,6 +62,8 @@ sensor: accuracy_decimals: 0 value_type: S_WORD + + - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} name: "${entities_name_prefix}-Out-of-Grid Active_Power L3" @@ -71,6 +75,8 @@ sensor: accuracy_decimals: 0 value_type: S_WORD + + - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} name: "${entities_name_prefix}-Out-of-Grid Active Power Total" @@ -81,6 +87,8 @@ sensor: state_class: "measurement" accuracy_decimals: 0 value_type: S_WORD + + - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} @@ -91,4 +99,4 @@ sensor: unit_of_measurement: "VA" state_class: "measurement" accuracy_decimals: 0 - value_type: S_WORD \ No newline at end of file + value_type: S_WORD diff --git a/modules/solar.yaml b/modules/solar.yaml index 78f7ee4..ea0c746 100644 --- a/modules/solar.yaml +++ b/modules/solar.yaml @@ -7,9 +7,12 @@ sensor: address: 672 unit_of_measurement: "W" state_class: "measurement" + device_class: power accuracy_decimals: 0 value_type: U_WORD + + - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} name: "${entities_name_prefix}-Solar Power PV2" @@ -18,9 +21,11 @@ sensor: address: 673 unit_of_measurement: "W" state_class: "measurement" + device_class: power accuracy_decimals: 0 value_type: U_WORD + - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} name: "${entities_name_prefix}-Solar Voltage PV1" diff --git a/modules/status.yaml b/modules/status.yaml index 318a846..47e86b8 100644 --- a/modules/status.yaml +++ b/modules/status.yaml @@ -1,24 +1,3 @@ -text_sensor: - - platform: modbus_controller - modbus_controller_id: ${modbus_controller_id} - skip_updates: 2 - bitmask: 0 - register_type: holding - address: 500 - raw_encode: HEXBYTES - id: "${entities_id_prefix}_Status_Running_Status" - name: "${entities_name_prefix}-Status - Running Status" - lambda: |- - uint16_t value = modbus_controller::word_from_hex_str(x, 0); - switch (value) { - case 0: return std::string("standby"); - case 1: return std::string("selfcheck"); - case 2: return std::string("normal"); - case 3: return std::string("alarm"); - case 4: return std::string("fault"); - default: return std::string("----"); - } - return x; sensor: - platform: modbus_controller @@ -44,8 +23,8 @@ sensor: - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} skip_updates: 2 - name: "${entities_name_prefix}-Status - Warning3" - id: "${entities_id_prefix}_Status_Warning3" + name: "${entities_name_prefix}-Status - Error1" + id: "${entities_id_prefix}_Status_Error1" register_type: holding address: 555 accuracy_decimals: 0 @@ -54,8 +33,8 @@ sensor: - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} skip_updates: 2 - name: "${entities_name_prefix}-Status - Error1" - id: "${entities_id_prefix}_Status_Error1" + name: "${entities_name_prefix}-Status - Error2" + id: "${entities_id_prefix}_Status_Error2" register_type: holding address: 556 accuracy_decimals: 0 @@ -64,8 +43,8 @@ sensor: - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} skip_updates: 2 - name: "${entities_name_prefix}-Status - Error2" - id: "${entities_id_prefix}_Status_Error2" + name: "${entities_name_prefix}-Status - Error3" + id: "${entities_id_prefix}_Status_Error3" register_type: holding address: 557 accuracy_decimals: 0 @@ -74,13 +53,14 @@ sensor: - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} skip_updates: 2 - name: "${entities_name_prefix}-Status - Error3" - id: "${entities_id_prefix}_Status_Error3" + name: "${entities_name_prefix}-Status - Error4" + id: "${entities_id_prefix}_Status_Error4" register_type: holding address: 558 accuracy_decimals: 0 value_type: U_WORD + - platform: modbus_controller modbus_controller_id: ${modbus_controller_id} name: "${entities_name_prefix}-Status - Failure Status of Communication Board" @@ -89,3 +69,80 @@ sensor: address: 548 accuracy_decimals: 0 value_type: U_WORD + + +text_sensor: + - platform: modbus_controller + modbus_controller_id: ${modbus_controller_id} + skip_updates: 2 + bitmask: 0 + register_type: holding + address: 500 + raw_encode: HEXBYTES + id: "${entities_id_prefix}_Status_Running_Status" + name: "${entities_name_prefix}-Status - Running Status" + lambda: |- + uint16_t value = modbus_controller::word_from_hex_str(x, 0); + switch (value) { + case 0: return std::string("standby"); + case 1: return std::string("selfcheck"); + case 2: return std::string("normal"); + case 3: return std::string("alarm"); + case 4: return std::string("fault"); + default: return std::string("----"); + } + return x; + + #new / untested + - platform: template + name: "${entities_name_prefix}-Status - Inverter Faults" + lambda: |- + static const std::map faults = { + {7, "DC/DC Soft Start Fault"}, + {10, "Auxiliary Power Supply Failure"}, + {13, "Working Mode Change"}, + {18, "AC Over Current"}, + {20, "DC Over Current"}, + {22, "Emergency Stop Fault"}, + {23, "AC Leakage Current or Transient Over Current"}, + {24, "DC Insulation Impedance Failure"}, + {26, "DC Busbar Imbalanced"}, + {29, "Parallel Communication Fault"}, + {35, "No AC Grid"}, + {41, "Parallel System Stop"}, + {42, "AC Line Low Voltage"}, + {46, "Backup Battery Fault"}, + {47, "AC Over Frequency"}, + {48, "AC Lower Frequency"}, + {49, "Backup Battery Fault"}, + {56, "DC Busbar Voltage Low"}, + {58, "BMS Communication Fault"}, + {63, "ARC Fault"}, + {64, "Heat Sink Temperature Failure"}, + }; + + std::vector errors; + uint16_t registers[4] = {id(${entities_id_prefix}_Status_Error1).state, id(${entities_id_prefix}_Status_Error1).state, id(${entities_id_prefix}_Status_Error3).state, id(${entities_id_prefix}_Status_Error4).state}; + int offset = 0; + + for (int i = 0; i < 4; i++) { + for (int bit = 0; bit < 16; bit++) { + if (registers[i] & (1 << bit)) { + int fault_code = offset + bit + 1; + if (faults.count(fault_code)) { + errors.push_back("F" + std::to_string(fault_code) + " " + faults.at(fault_code)); + } else { + errors.push_back("F" + std::to_string(fault_code)); + } + } + } + offset += 16; + } + std::string result; + for (size_t i = 0; i < errors.size(); i++) { + if (i > 0) result += ", "; + result += errors[i]; + } + + return errors.empty() ? "No Faults" : result; + update_interval: 10s diff --git a/modules/ups.yaml b/modules/ups.yaml index b2008eb..6ef17d4 100644 --- a/modules/ups.yaml +++ b/modules/ups.yaml @@ -41,4 +41,4 @@ sensor: unit_of_measurement: "W" state_class: "measurement" accuracy_decimals: 0 - value_type: U_WORD \ No newline at end of file + value_type: U_WORD