From 0f4967d0df9b4aa69428bc329b0d01d4c4b6df82 Mon Sep 17 00:00:00 2001 From: Tatyana Date: Fri, 27 Oct 2023 16:22:11 +0200 Subject: [PATCH] feat(Deye/Sunsynk): add Modbus over RS-485 option --- .luacheckrc | 3 + .../deye_sun-10k-sg04lp3-eu_modbus/README.md | 16 ++ .../firmware.lua | 112 +++++++++++ .../manifest.yml | 184 ++++++++++++++++++ 4 files changed, 315 insertions(+) create mode 100644 solar_inverters/deye_sun-10k-sg04lp3-eu_modbus/README.md create mode 100644 solar_inverters/deye_sun-10k-sg04lp3-eu_modbus/firmware.lua create mode 100644 solar_inverters/deye_sun-10k-sg04lp3-eu_modbus/manifest.yml diff --git a/.luacheckrc b/.luacheckrc index 3ddc577d..310435c5 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -90,6 +90,9 @@ stds.vucm = { modbustcp = { fields = { 'new', 'err_to_str' }, }, + modbusrtu = { + fields = { 'new', 'err_to_str' }, + }, http = { fields = { 'get', 'post', 'post_form', 'client', 'request' }, }, diff --git a/solar_inverters/deye_sun-10k-sg04lp3-eu_modbus/README.md b/solar_inverters/deye_sun-10k-sg04lp3-eu_modbus/README.md new file mode 100644 index 00000000..035b65d6 --- /dev/null +++ b/solar_inverters/deye_sun-10k-sg04lp3-eu_modbus/README.md @@ -0,0 +1,16 @@ +# Deye SUN-10k-SG04LP3-EU (Modbus over RS-485) + +This [Enapter Device Blueprint](https://go.enapter.com/marketplace-readme) integrates **Deye Inverter SUN-10k-SG04LP3-EU** - three-phase hybrid inverter connected to Enapter Gateway via serial port. [Enapter Virtual UCM](https://go.enapter.com/handbook-vucm) handles RS-485 connection. + +## Connect to Enapter + +- Sign up to Enapter Cloud using [Web](https://cloud.enapter.com/) or mobile app ([iOS](https://apps.apple.com/app/id1388329910), [Android](https://play.google.com/store/apps/details?id=com.enapter&hl=en)). +- Use [Enapter Gateway](https://go.enapter.com/handbook-gateway-setup) to run Virtual UCM. +- Create [Enapter Virtual UCM](https://go.enapter.com/handbook-vucm). +- [Upload](https://go.enapter.com/developers-upload-blueprint) this blueprint to Enapter Virtual UCM. +- Use the `Set Up Modbus Connection` command in the Enapter mobile or Web app to set up the following communication parameters: + - Your Deye inverter's Modbus address + +## References + +- [Deye Inverter product page](https://www.deyeinverter.com/product/hybrid-inverter-1/sun5-6-8-10-12ksg04lp3.html) diff --git a/solar_inverters/deye_sun-10k-sg04lp3-eu_modbus/firmware.lua b/solar_inverters/deye_sun-10k-sg04lp3-eu_modbus/firmware.lua new file mode 100644 index 00000000..7416ecb8 --- /dev/null +++ b/solar_inverters/deye_sun-10k-sg04lp3-eu_modbus/firmware.lua @@ -0,0 +1,112 @@ +local config = require('enapter.ucm.config') + +-- Configuration variables must be also defined +-- in `write_configuration` command arguments in manifest.yml +ADDRESS = 'address' + +function main() + scheduler.add(1000, send_telemetry) + scheduler.add(30000, send_properties) + config.init({ + [ADDRESS] = { type = 'number', required = true, default = 1 }, + }) +end + +function send_properties() + enapter.send_properties({ + vendor = 'Deye', + model = 'SUN-10k-SG04LP3-EU' + }) +end + +function send_telemetry() + local modbus = modbusrtu.new("/dev/ttyUSB0", { + baud_rate=9600, data_bits=8, stop_bits=1, parity="N", read_timeout=1000 + }) + + local addr, err = config.read(ADDRESS) + if err ~= nil then + enapter.send_telemetry({ + status = 'warning', + alerts = {'config_read_error'} + }) + return + end + + local telemetry = {} + + local data, err = modbus:read_holdings(addr, 514, 13, 1000) + if err ~= 0 then + enapter.log('514-526: ' .. modbusrtu.err_to_str(err), 'error') + else + telemetry.total_battery_charge = data[1] * 0.1 + telemetry.total_battery_discharge = data[515 - 514 + 1] * 0.1 + telemetry.day_gridbuy_power = data[520 - 514 + 1] * 0.1 + telemetry.day_gridsell_power = data[521 - 514 + 1] * 0.1 + telemetry.day_load_power = data[526 - 514 + 1] * 0.1 + end + + local data, err = modbus:read_holdings(addr, 587, 5, 1000) + if err ~= 0 then + enapter.log('587-591: ' .. modbusrtu.err_to_str(err), 'error') + else + telemetry.battery_voltage = data[1] * 0.01 + telemetry.battery_output_power = data[590 - 587 + 1] + telemetry.battery_output_current = data[591 - 587 + 1] + end + + local data, err = modbus:read_holdings(addr, 604, 6, 1000) + if err ~= 0 then + enapter.log('604-609: ' .. modbusrtu.err_to_str(err), 'error') + else + telemetry.inner_grid_power_a = data[1] + telemetry.inner_grid_power_b = data[605 - 604 + 1] + telemetry.inner_grid_power_c = data[606 - 604 + 1] + telemetry.total_active_power_side_to_side = data[607 - 604 + 1] + telemetry.grid_frequency = data[609 - 604 + 1] + end + + local data, err = modbus:read_holdings(addr, 616, 10, 1000) + if err ~= 0 then + enapter.log('616-619: ' .. modbusrtu.err_to_str(err), 'error') + else + telemetry.out_of_grid_power_a = data[1] + telemetry.out_of_grid_power_b = data[617 - 616 + 1] + telemetry.out_of_grid_power_c = data[618 - 616 + 1] + telemetry.total_out_of_grid_power = data[619 - 616 + 1] + end + + local data, err = modbus:read_holdings(addr, 622, 4, 1000) + if err ~= 0 then + enapter.log('622-625: ' .. modbusrtu.err_to_str(err), 'error') + else + telemetry.grid_power_a = data[1] + telemetry.grid_power_b = data[2] + telemetry.grid_power_c = data[3] + telemetry.total_grid_power = data[4] + end + + local data, err = modbus:read_holdings(addr, 633, 4, 1000) + if err ~= 0 then + enapter.log('633-636: ' .. modbusrtu.err_to_str(err), 'error') + else + telemetry.inverter_output_power_a = data[1] + telemetry.inverter_output_power_b = data[2] + telemetry.inverter_output_power_c = data[3] + telemetry.total_inverter_output_power = data[4] + end + + local data, err = modbus:read_holdings(addr, 650, 4, 1000) + if err ~= 0 then + enapter.log('650-653: ' .. modbusrtu.err_to_str(err), 'error') + else + telemetry.load_power_a = data[1] + telemetry.load_power_b = data[2] + telemetry.load_power_c = data[3] + telemetry.total_load_power = data[4] + end + + enapter.send_telemetry(telemetry) +end + +main() diff --git a/solar_inverters/deye_sun-10k-sg04lp3-eu_modbus/manifest.yml b/solar_inverters/deye_sun-10k-sg04lp3-eu_modbus/manifest.yml new file mode 100644 index 00000000..670453f3 --- /dev/null +++ b/solar_inverters/deye_sun-10k-sg04lp3-eu_modbus/manifest.yml @@ -0,0 +1,184 @@ +blueprint_spec: device/1.0 + +display_name: Deye / Sunsynk Inverter (via Modbus RTU) +description: Three phase hybrid inverter with low battery voltage 48V. +icon: enapter-solar-inverter +license: MIT +author: enapter +contributors: + - anataty +support: + url: https://go.enapter.com/enapter-blueprint-support + email: support@enapter.com +verification_level: verified + +communication_module: + product: ENP-VIRTUAL + lua: + file: firmware.lua + dependencies: + - enapter-ucm + allow_dev_dependencies: true + +properties: + serial_number: + type: string + display_name: Serial number + +telemetry: + status: + type: string + display_name: State + enum: + - ok + - warning + total_battery_charge: + display_name: Total Battery Charge + type: float + unit: kwatth + total_battery_discharge: + display_name: Total Battery Discharge + type: float + unit: kwatth + day_gridbuy_power: + display_name: Day Grid Buy Power + type: float + unit: kwatth + day_gridsell_power: + display_name: Day Grid Sell Power + type: float + unit: kwatth + day_load_power: + display_name: Day Load Power + type: float + unit: kwatth + battery_voltage: + display_name: Battery Voltage + type: float + unit: volt + battery_output_power: + display_name: Battery Output Power + type: float + unit: watt + battery_output_current: + display_name: Battery Output Current + type: float + unit: amp + inner_grid_power_a: + display_name: Inner Grid Power Phase A + type: float + unit: watt + inner_grid_power_b: + display_name: Inner Grid Power Phase B + type: float + unit: watt + inner_grid_power_c: + display_name: Inner Grid Power Phase C + type: float + unit: watt + total_active_power_side_to_side: + display_name: Total Active Power from side to side of the grid + type: float + unit: watt + grid_frequency: + display_name: Grid Frequency + type: float + unit: hertz + out_of_grid_power_a: + display_name: Out-of-Grid Power Phase A + type: float + unit: watt + out_of_grid_power_b: + display_name: Out-of-Grid Power Phase B + type: float + unit: watt + out_of_grid_power_c: + display_name: Out-of-Grid Power Phase C + type: float + unit: watt + total_out_of_grid_power: + display_name: Total Out-of-Grid Power + type: float + unit: watt + grid_power_a: + display_name: Grid Power Phase A + type: float + unit: watt + grid_power_b: + display_name: Grid Power Phase B + type: float + unit: watt + grid_power_c: + display_name: Grid Power Phase C + type: float + unit: watt + total_grid_power: + display_name: Total Grid Power + type: float + unit: watt + inverter_output_power_a: + display_name: Inverter Output Power Phase A + type: float + unit: watt + inverter_output_power_b: + display_name: Inverter Output Power Phase B + type: float + unit: watt + inverter_output_power_c: + display_name: Inverter Output Power Phase C + type: float + unit: watt + total_inverter_output_power: + display_name: Total Inverter Output Power + type: float + unit: watt + load_power_a: + display_name: Load Power Phase A + type: float + unit: watt + load_power_b: + display_name: Load Power Phase B + type: float + unit: watt + load_power_c: + display_name: Load Power Phase C + type: float + unit: watt + total_load_power: + display_name: Total Load Power + type: float + unit: watt + +alerts: + config_read_error: + display_name: Configuration read error + severity: warning + +command_groups: + connection: + display_name: Connection + +commands: + write_configuration: + display_name: Set Up Modbus Connection + group: connection + populate_values_command: read_configuration + ui: + icon: file-document-edit-outline + arguments: + address: + display_name: Modbus address + type: integer + required: true + read_configuration: + display_name: Read Connection Parameters + group: connection + ui: + icon: file-check-outline + +.cloud: + category: renewable_energy_sources + mobile_main_chart: day_grid_sell_power + mobile_charts: + - total_load_power + - battery_voltage