syssi / esphome-soyosource-gtn-virtual-meter

ESPHome component to simulate the current clamp to control the Soyosource GTN1200 limiter
Apache License 2.0
78 stars 21 forks source link

Add display protocol support of the "Soyosource with display" version #102

Closed derFrickler closed 1 year ago

derFrickler commented 1 year ago

Well, not a bug, just a question. Do I get it right, I can use that example to replace my broken Display in the soyo to change the settings via HA? So far I only use the rs485 to set the power.

Thanks a lot!

syssi commented 1 year ago

@ButschFPV Could you collect some more frames? I'm bit confused because of the second byte (lets call it function). The function values of your recorded frames doesn't match with the one of Pepe:

https://github.com/PepeTheFroggie/Soyosource-GridTie-inverter-24V-LCD-replacement/blob/main/SoyoGraph_24v/soyo.ino#L111-L142

Could you set your Soyosource into "PV mode" and set the start and stop voltage again? I assume the function is 0x0A in this case. Could you collect all "change operation mode" frames and the resulting "operation mode" (status & settings frame)?

derFrickler commented 1 year ago

As said, the settings code from Pepe is not working that good, setting the limit mode does not seem to work at all, not in PV not in Bat.

syssi commented 1 year ago

I know but I would like to understand the root cause. I assume the second byte does change depending on the operation mode.

syssi commented 1 year ago

The feature branch is able to decode the operation modes now probably. This updated YAML could be used for testing:

https://github.com/syssi/esphome-soyosource-gtn-virtual-meter/blob/improve-display-support/esp8266-display-example.yaml

https://github.com/syssi/esphome-soyosource-gtn-virtual-meter/blob/improve-display-support/components/soyosource_display/soyosource_display.cpp#L587-L618

There are at least two values (0x05, 0x06) which aren't mapped yet because the meaning is unknown.

ButschFPV commented 1 year ago

I had a "quick" look and recorded some more data.

Access menu:
>>> 55:03:00:00:00:FC
<<< A6:01:01:C3:02:D2:18:17:16:00:DA:64:03:3C:A4

Set PV Mode
>>> 55:03:00:00:01:FB
<<< A6:01:01:63:02:D2:18:17:16:00:D9:64:03:3C:05

Set BatCP Mode
>>> 55:03:00:00:02:FA
<<< A6:01:01:63:02:D2:18:17:16:00:D9:64:03:3C:05

Set BatLimit Mode
>>> 55:03:00:00:10:EC
<<< A6:01:01:C3:02:D2:18:17:16:00:D8:64:03:3C:A6

The Following changes are done in PV Mode
Set Bat start voltage to 26V
>>> 55:0B:1A:15:00:C5
<<< A6:01:01:63:02:D2:18:1A:15:00:DA:64:3C:3C:C9

Set Bat start voltage to 27V
>>> 55:0B:1B:15:00:C4
<<< A6:01:01:63:02:D2:18:1B:15:00:DA:64:3C:3C:C8

Set Bat stop voltage to 22V
>>> 55:0B:18:16:00:C6
<<< A6:01:01:63:02:D2:18:18:16:00:DA:64:3C:3C:CA

Set Bat stop voltage to 21V
>>> 55:0B:18:15:00:C7
<<< A6:01:01:63:02:D2:18:18:15:00:DA:64:3C:3C:CB

Set Bat CP Mode Power to 40W
>>> 55:13:04:64:00:84
<<< A6:01:01:63:02:D2:18:18:17:00:DA:64:04:3C:01

Set Bat CP Mode Power to 600W
>>> 55:13:3C:64:00:4C
<<< A6:01:01:63:02:D2:18:18:17:00:DA:64:3C:3C:C9

Set Delay Start to 59s
>>> 55:83:3B:00:00:41
<<< A6:01:01:63:02:D2:18:1A:15:00:DA:64:3C:3B:CA

Set Delay Start to 60s
>>> 55:83:3C:00:00:40
<<< A6:01:01:63:02:D2:18:1A:15:00:DA:64:3C:3C:C9

The Following changes are done in BatLimit Mode
Set Bat start voltage to 25V
>>> 55:0B:19:15:00:C6
<<< A6:01:01:C3:02:D2:18:19:15:00:D9:64:3C:3C:6B

Set Bat start voltage to 26V
>>> 55:0B:1A:15:00:C5
<<< A6:01:01:C3:02:D2:18:1A:15:00:D9:64:3C:3C:6A

I assume the other settings are identical throughout the modes.

I was a little bit confused about my previously recorded frames. Set PV Mode looked like this: 55:03:17:18:01:CC And now like this: 55:03:00:00:01:FB Well turns out Byte 02 & 03 shows the last changed value(s). In my previously recorded frame the last change was Battery start/stop voltage. Hence the 17:18. This is then also visible in the normal status request: 55:01:17:18:00:XX. If i had changed the BatCP Mode Power to 30W, then the status request looked like: 55:01:03:64:00:XX or sometimes 55:01:03:63:00:XX. I'm not completely sure if Byte 03 is the last received Mains-Frequency value.

The question is, does it even matter? Is it just gap filler?

syssi commented 1 year ago

I assume in some cases it matters in some not. For example:

0x0B is the command to update the start/stop voltage. The first byte of the data is the start voltage, the second byte stop voltage and it looks like the third byte should be always 0x00. There is no instruction which one of the voltages should be updated to we have to pass both voltages always.

0x03 is the "change operation mode" command. The third byte indicates the new operation mode. If we pass 0x00 as third byte the settings frame is requested / nothing gets changed. Could you repeat the "change operation mode" tests? These responses must not be equal:

Set PV Mode
>>> 55:03:00:00:01:FB
<<< A6:01:01:63:02:D2:18:17:16:00:D9:64:03:3C:05 <--

Set BatCP Mode
>>> 55:03:00:00:02:FA
<<< A6:01:01:63:02:D2:18:17:16:00:D9:64:03:3C:05 <--

0x83 is the command to change the start delay.

0x13 the command to set the "output power limit" (please keep in mind this affects the CP mode and the Limiter mode. In both cases its the upper bound) Let's pass the grid frequency here too. It's pretty similar to the display protocol of the WiFi version.

syssi commented 1 year ago

Could you do me another favour? If you have changed to operation mode to "PV" please go back to the status page to retrieve a status frame. The operation mode should change here too. I would like to know these operation mode values are equal to the settings frame or shifted.

ButschFPV commented 1 year ago

Hm this is strange. I was focused on the request, so I didn't noticed. I did run the same test again:

Set BatLimit Mode
>>> 55:03:00:00:10:EC
<<< A6:01:01:63:02:D2:18:17:16:00:DB:64:02:3C:04

Set PV Mode
>>> 55:03:00:00:01:FB
<<< A6:01:01:63:02:D2:18:17:16:00:DC:64:02:3C:03

Set BatCP Mode
>>> 55:03:00:00:02:FA
<<< A6:01:01:C3:02:D2:18:17:16:00:D9:64:02:3C:A6

Again different values. If I had to guess, maybe another random value. I discovered some frames every time I exited the configuration menu. So maybe this is where you get the confirmation of the actual mode:

Exit menu in BatCP Mode
>>> 55:03:00:00:00:FC
<<< A6:01:01:53:02:D2:18:17:16:00:D9:64:02:3C:16

Exit Menu in PV Mode
>>> 55:03:00:00:00:FC
<<< A6:01:01:63:02:D2:18:17:16:00:DC:64:02:3C:03

Exit Menu in BatLimit Mode
>>> 55:03:00:00:00:FC
<<< A6:01:01:C3:02:D2:18:17:16:00:DB:64:02:3C:A4

Here are the status page responses:

Status page response in BatCP Mode
<<< A6:01:01:51:02:00:00:00:00:00:DA:64:01:BC:AF

Status page response in PV Mode
<<< A6:01:01:61:02:00:00:00:00:00:DC:64:01:BE:9B

Status page response in BatLimit Mode
<<< A6:01:01:C1:02:00:00:00:00:00:DA:64:01:C0:3B
syssi commented 1 year ago

This is my new test setup to study the behaviour of the display.

display

syssi commented 1 year ago

The display protocol support for the "Soyosource display version" is ready and merged into main.

derFrickler commented 1 year ago

Thanks a lot for the great work! Its doing just fine now! Just one remark, the example file is still using the now non existing dev-branch, it should now use main: https://github.com/syssi/esphome-soyosource-gtn-virtual-meter/blob/446e41735fe8d2baa7a8a96704f45114f29f67f9/esp8266-display-display-version-example.yaml#L4

and i did a working config for the display version including the limiting via rs485:

esp8266-display-display-version-limiter-example.yaml

substitutions:
  name: soyosource-gtn-display
  device_description: "Monitor and control the Soyosource GTN (WiFi version) via the display port and control the power output on demand via RS485"
  external_components_source: github://syssi/esphome-soyosource-gtn-virtual-meter@main
  tx_pin_ttl_wifi: GPIO4
  rx_pin_ttl_wifi: GPIO5
  tx_pin_rs485: GPIO14
  rx_pin_rs485: GPIO12

esphome:
  name: ${name}
  comment: ${device_description}
  project:
    name: "syssi.esphome-soyosource-gtn-virtual-meter"
    version: 2.1.0

esp8266:
  board: d1_mini

external_components:
  - source: ${external_components_source}
    refresh: 0s

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

ota:

# If you use Home Assistant please remove this `mqtt` section and uncomment the `api` component!
mqtt:
  broker: !secret mqtt_host
  username: !secret mqtt_username
  password: !secret mqtt_password
  id: mqtt_client

# api:

logger:
  level: INFO

# Please be careful: The display port has a logic level of 5V.
uart:
  - id: uart0
    baud_rate: 9600
    tx_pin: ${tx_pin_ttl_wifi}
    rx_pin: ${rx_pin_ttl_wifi}

  - id: uart1
    baud_rate: 4800
    tx_pin: ${tx_pin_rs485}
    rx_pin: ${rx_pin_rs485}

soyosource_modbus:
  - id: modbus0
    uart_id: uart1

soyosource_virtual_meter:
  - id: virtualmeter0
    soyosource_modbus_id: modbus0

    # The state of this sensor (instantaneous power in watt) is used as source
    power_id: powermeter0

    # Optional settings
    power_sensor_inactivity_timeout: 20s
    power_demand_calculation: NEGATIVE_MEASUREMENTS_REQUIRED
    min_power_demand: 0
    max_power_demand: 900
    # Split/distribute the power demand if you have multiple inverters attached to the same RS485 bus
    power_demand_divider: 1
    # A positive buffer value (10) tries to avoid exporting power to the grid (demand - 10 watts)
    # A negative buffer value (-10) exports power to the grid (demand + 10 watts)
    buffer: 10
    # The operation_status_id sensor is expected here. Passing the operation_status won't work
    # The state is used to suspend the limiter if the operation status of the inverter isn't 0x0 (normal)
    operation_status_id: operation_status_id0

    # The update interval is important and defaults to 3 seconds. If the demand is sent too frequently
    # or rarely the interverter stops. TODO: Identify and validate the lower and upper update limit
    update_interval: 3s

soyosource_display:
  - id: display0
    uart_id: uart0
    update_interval: 5s
    protocol_version: SOYOSOURCE_DISPLAY_VERSION

binary_sensor:
  - platform: soyosource_display
    fan_running:
      name: "${name} fan running"
    limiter_connected:
      name: "${name} limiter connected"

button:
  - platform: soyosource_display
    restart:
      name: "${name} restart"

number:
  - platform: soyosource_virtual_meter
    soyosource_virtual_meter_id: virtualmeter0
    buffer:
      name: "${name} buffer"
      initial_value: 10
      restore_value: true
    manual_power_demand:
      name: "${name} manual power demand"
      max_value: 900
    max_power_demand:
      name: "${name} max power demand"
      initial_value: 600
      max_value: 900
      restore_value: true
    power_demand_divider:
      name: "${name} power demand divider"
      initial_value: 1
      restore_value: true

  - platform: soyosource_display
    start_voltage:
      name: "${name} start voltage"
    shutdown_voltage:
      name: "${name} shutdown voltage"
    # Maximum output power in limiter mode / Output power in constant power mode
    output_power_limit:
      name: "${name} output power limit"
    start_delay:
      name: "${name} start delay"

select:
  - platform: soyosource_display
    operation_mode:
      name: "${name} operation mode"
      optionsmap:
        1: "Battery Constant Power"
        2: "PV"
        16: "Battery Limit"

sensor:
  - platform: soyosource_virtual_meter
    soyosource_virtual_meter_id: virtualmeter0
    power_demand:
      name: "${name} power demand"

  - platform: soyosource_display
    error_bitmask:
      name: "${name} error bitmask"
    operation_mode_id:
      name: "${name} operation mode id"
    operation_status_id:
      name: "${name} operation status id"
      id: operation_status_id0
    battery_voltage:
      name: "${name} battery voltage"
    battery_current:
      name: "${name} battery current"
    battery_power:
      name: "${name} battery power"
    ac_voltage:
      name: "${name} ac voltage"
    ac_frequency:
      name: "${name} ac frequency"
    temperature:
      name: "${name} temperature"
    output_power:
      name: "${name} output power"

  # mqtt subscribe example
  - id: powermeter0
    internal: true
    platform: mqtt_subscribe
    name: "${name} instantaneous power consumption"
    topic: "PV/L1L2L3"
    accuracy_decimals: 2
    unit_of_measurement: W
    device_class: power
    filters:
      - throttle_average: 15s

#   # import smartmeter reading from homeassistant
#   # requires the "api" component see above
#   - platform: homeassistant
#     id: powermeter0
#     name: "${name} smartmeter instantaneous power"
#     entity_id: sensor.firstfloor_smartmeter_instantaneous_power
#     filters:
#       - throttle_average: 15s

switch:
  - platform: soyosource_virtual_meter
    soyosource_virtual_meter_id: virtualmeter0
    manual_mode:
      name: "${name} manual mode"
      restore_mode: RESTORE_DEFAULT_ON
    emergency_power_off:
      name: "${name} emergency power off"
      restore_mode: RESTORE_DEFAULT_OFF

text_sensor:
  - platform: soyosource_virtual_meter
    soyosource_virtual_meter_id: virtualmeter0
    operation_mode:
      name: "${name} limiter operation mode"

  - platform: soyosource_display
    errors:
      name: "${name} errors"
    operation_mode:
      name: "${name} operation mode"
    operation_status:
      name: "${name} operation status"
syssi commented 1 year ago

Pinout and isolated data cable example for the internal display port:

https://github.com/syssi/esphome-soyosource-gtn-virtual-meter/blob/main/docs/display-version/README.md

ButschFPV commented 1 year ago

Nice work. For me the connector looks like XH 2.54.

syssi commented 1 year ago

It looks like I mixed up my aliexpress orders. ;-) Thanks for the hint! It's fixed.

derFrickler commented 1 year ago

Thanks! Mine is directly powered by the display connector and just using a 1k resistor in the Rx line of the wemos board.. works fine, just do not connect to USB while connected to the inverter.

kev300 commented 1 year ago

Hey, can I leave the display connected and just solder the esp in between? Did anybody test that?

syssi commented 1 year ago

In my case it wasn't successful. If I connect both (RX & TX + disable polling) my display did complain about not being connected to the mainboard. As soon as I remove the piggy back cables the display recovers. The issue is probably the opto-coupler (ADUM1201) pulling one of the lines to high/low.

If I remember correctly here are some guys which did attach the RX line of the ESP only to listen to the traffic passively. In this case you cannot change settings using the ESP logically.

derFrickler commented 1 year ago

2 RX Lines in parallel should be fine, for the TX, you can only use the one from the display or from the ESP. So settings can only be made from the display OR the esp.

ButschFPV commented 1 year ago

This should work with some buffer ic at the opto isolator input. In my tests i used a 100k base resistor and a npn transistor. With a 10k base resistor it was pulling to hard on the serial lines.

DaddoDoc92 commented 7 months ago

Good morning everyone, I have been using the integration for 6 months to regulate the output automatically through the home assistant and a shelly, but I don't have any information received from the inverter, I use the version that has the display, but I am connected to the RS485 port, Can you tell me if it's normal for this to have no outgoing information?

syssi commented 7 months ago

@DaddoDoc92 This is normal. You could unplug the display and attach the same ESP to the display lines if you like. The decoder of the display traffic is part of the project.