Solarman modbus integration

Hi all,
I have a Deye hybrid inverter with a LSW3 logger, I’d like to access through modbus of the logger but I cannot have success configuring it. I started from the HA custom plugin and in the HA system is working well (I use the deye_sg04lp3.yaml ), somebody had success configuring it?

Asuming solarman means a lsw logger and appropriate inverter like sofar.

Not modbus per se, but using logger api (which is a wrapped modbus) is here [new binding] Logger LSW for Sofar/Omnik/IE for SolarmanPV based on protocol v5 (iGEN tech) - #46 by Grzegorz_Golec.

Thanks for the reply,
I have a Deye inverter with LSW3 serial starts with 2389XXXXXX, which bind can I use?

Ouch, the future one mentioned in my link. However 23xxx support is being under development Handle loggers with SN 23xxxx · Issue #1 · ptrbojko/openhab-lsw4inverter-binding · GitHub

I tried to put the org.openhab.binding.lswlogger-3.3.0.jar in the addons but nothing happen

Meanwhile I solved in this way (I used the code from git repo ha plugin ) adding a main:

def main():
    inverter = Inverter("/home/openhabian/solarman/inverter_definitions/", <your-loggger-sn>, <ip-of-the-logger>, 8899, 1, "deye_sg04lp3.yaml")
    inverter.update()
    val = inverter.get_current_val()
    mqtt_client = paho.Client("deye_inverter")
    mqtt_client.enable_logger()
    mqtt_timeout = 3 # seconds
    mqtt_client.connect(<mqtt-address>, 1883)
    mqtt_client.loop_start()
    mqtt_topic = "deye/measurements"
    value = str(val)
    json_object = json.dumps(val) 
    info = mqtt_client.publish(mqtt_topic, json_object, qos=1)
    info.wait_for_publish(mqtt_timeout)
    info = mqtt_client.publish("deye/last_update", inverter.status_lastUpdate, qos=1)
    info.wait_for_publish(mqtt_timeout)

then a rule to update the mqtt queue:

rule "Deye update"
		when
			Time cron "0/20 * * ? * * *"
		then
			executeCommandLine(Duration.ofSeconds(10), "/usr/bin/python3.9","/home/openhabian/solarman/solarman.py")
end

and the channel of the thing:

UID: mqtt:topic:MQTTBroker:deye-mqtt
label: Deye inverter
thingTypeUID: mqtt:topic
configuration: {}
bridgeUID: mqtt:broker:MQTTBroker
channels:
  - id: pv1_power
    channelTypeUID: mqtt:number
    label: PV1 Power
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.pv1_power
      unit: W
  - id: pv2_power
    channelTypeUID: mqtt:number
    label: PV2 Power
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.pv2_power
      unit: W
  - id: pv1_voltage
    channelTypeUID: mqtt:number
    label: PV1 Voltage
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.pv1_voltage
      unit: V
  - id: pv2_voltage
    channelTypeUID: mqtt:number
    label: PV2 Voltage
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.pv2_voltage
      unit: V
  - id: pv1_current
    channelTypeUID: mqtt:number
    label: PV1 Current
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.pv1_current
      unit: A
  - id: pv2_current
    channelTypeUID: mqtt:number
    label: PV2 Current
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.pv2_current
      unit: A
  - id: daily_production
    channelTypeUID: mqtt:number
    label: Daily Production
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.daily_production
      unit: kWh
  - id: total_production
    channelTypeUID: mqtt:number
    label: Total Production
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.total_production
      unit: kWh
  - id: daily_battery_charge
    channelTypeUID: mqtt:number
    label: Daily Battery Charge
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.daily_battery_charge
      unit: kWh
  - id: daily_battery_discharge
    channelTypeUID: mqtt:number
    label: Daily Battery Discharge
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.daily_battery_discharge
      unit: kWh
  - id: total_battery_charge
    channelTypeUID: mqtt:number
    label: Total Battery Charge
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.total_battery_charge
      unit: kWh
  - id: total_battery_discharge
    channelTypeUID: mqtt:number
    label: Total Battery Discharge
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.total_battery_discharge
      unit: kWh
  - id: battery_power
    channelTypeUID: mqtt:number
    label: Battery Power
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.battery_power
      unit: W
  - id: battery_voltage
    channelTypeUID: mqtt:number
    label: Battery Voltage
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.battery_voltage
      unit: V
  - id: battery_soc
    channelTypeUID: mqtt:number
    label: Battery SOC
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.battery_soc
  - id: battery_current
    channelTypeUID: mqtt:number
    label: Battery Current
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.battery_current
      unit: A
  - id: battery_temperature
    channelTypeUID: mqtt:number
    label: Battery Temperature
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.battery_temperature
      unit: °C
  - id: total_grid_power
    channelTypeUID: mqtt:number
    label: Total Grid Power
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.total_grid_power
      unit: W
  - id: grid_voltage_l1
    channelTypeUID: mqtt:number
    label: Grid Voltage L1
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.grid_voltage_l1
      unit: V
  - id: grid_voltage_l2
    channelTypeUID: mqtt:number
    label: Grid Voltage L2
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.grid_voltage_l2
      unit: V
  - id: grid_voltage_l3
    channelTypeUID: mqtt:number
    label: Grid Voltage L3
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.grid_voltage_l3
      unit: V
  - id: internal_ct_l1_power
    channelTypeUID: mqtt:number
    label: Internal CT L1 Power
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.internal_ct_l1_power
      unit: W
  - id: internal_ct_l2_power
    channelTypeUID: mqtt:number
    label: Internal CT L2 Power
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.internal_ct_l2_power
      unit: W
  - id: internal_ct_l3_power
    channelTypeUID: mqtt:number
    label: Internal CT L3 Power
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.internal_ct_l3_power
      unit: W
  - id: external_ct_l1_power
    channelTypeUID: mqtt:number
    label: External CT L1 Power
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.external_ct_l1_power
      unit: W
  - id: external_ct_l2_power
    channelTypeUID: mqtt:number
    label: External CT L2 Power
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.external_ct_l2_power
      unit: W
  - id: external_ct_l3_power
    channelTypeUID: mqtt:number
    label: External CT L3 Power
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.external_ct_l3_power
      unit: W
  - id: daily_energy_bought
    channelTypeUID: mqtt:number
    label: Daily Energy Bought
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.daily_energy_bought
      unit: kWh
  - id: total_energy_bought
    channelTypeUID: mqtt:number
    label: Total Energy Bought
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.total_energy_bought
      unit: kWh
  - id: daily_energy_sold
    channelTypeUID: mqtt:number
    label: Daily Energy Sold
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.daily_energy_sold
      unit: kWh
  - id: total_energy_sold
    channelTypeUID: mqtt:number
    label: Total Energy Sold
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.total_energy_sold
      unit: kWh
  - id: total_grid_production
    channelTypeUID: mqtt:number
    label: Total Grid Production
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.total_grid_production
      unit: kWh
  - id: total_load_power
    channelTypeUID: mqtt:number
    label: Total Load Power
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.total_load_power
      unit: W
  - id: load_l1_power
    channelTypeUID: mqtt:number
    label: Load L1 Power
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.load_l1_power
      unit: W
  - id: load_l2_power
    channelTypeUID: mqtt:number
    label: Load L2 Power
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.load_l2_power
      unit: W
  - id: load_l3_power
    channelTypeUID: mqtt:number
    label: Load L3 Power
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.load_l3_power
      unit: W
  - id: load_voltage_l1
    channelTypeUID: mqtt:number
    label: Load Voltage L1
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.load_voltage_l1
      unit: V
  - id: load_voltage_l2
    channelTypeUID: mqtt:number
    label: Load Voltage L2
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.load_voltage_l2
      unit: V
  - id: load_voltage_l3
    channelTypeUID: mqtt:number
    label: Load Voltage L3
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.load_voltage_l3
      unit: V
  - id: daily_load_consumption
    channelTypeUID: mqtt:number
    label: Daily Load Consumption
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.daily_load_consumption
      unit: kWh
  - id: total_load_consumption
    channelTypeUID: mqtt:number
    label: Total Load Consumption
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.total_load_consumption
      unit: kWh
  - id: current_l1
    channelTypeUID: mqtt:number
    label: Current L1
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.current_l1
      unit: A
  - id: current_l2
    channelTypeUID: mqtt:number
    label: Current L2
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.current_l2
      unit: A
  - id: current_l3
    channelTypeUID: mqtt:number
    label: Current L3
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.current_l3
      unit: A
  - id: inverter_l1_power
    channelTypeUID: mqtt:number
    label: Inverter L1 Power
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.inverter_l1_power
      unit: W
  - id: inverter_l2_power
    channelTypeUID: mqtt:number
    label: Inverter L2 Power
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.inverter_l2_power
      unit: W
  - id: inverter_l3_power
    channelTypeUID: mqtt:number
    label: Inverter L3 Power
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.inverter_l3_power
      unit: W
  - id: dc_temperature
    channelTypeUID: mqtt:number
    label: DC Temperature
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.dc_temperature
      unit: °C
  - id: ac_temperature
    channelTypeUID: mqtt:number
    label: AC Temperature
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.ac_temperature
      unit: °C
  - id: communication_board_version_no
    channelTypeUID: mqtt:number
    label: Communication Board Version No.
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.communication_board_version_no
  - id: control_board_version_no
    channelTypeUID: mqtt:number
    label: Control Board Version No.
    description: null
    configuration:
      stateTopic: deye/measurements
      transformationPattern: JSONPATH:$.control_board_version_no

all is working good without using the solarman api.

Hi @giorginus80 , that’s in interesting solution since this gives more real time data than the cloud api option.
However, I am not a coder and I am struggling to get this to work. I added the main to solarman.py right above the class definition. When calling “python3 solarman.py” from the shell directly, first problem are the IP addresses. I guess, they need to be with quotation marks?

Next problem is the missing homeassistant.util. I get an error “ModuleNotFoundError: No module named ‘homeassistant’”. I just copied the code from your link above to my server. Do I need to install the whole homeassistant system?

Thanks a lot for your support

Hello @Falk
yes you have to add const.py and parser.py and the directory /inverter_definitions, you have just to add the main (I attach a new ‘full’ version because I forgot to put retained prop to mqtt). It’s just a fast solution, working very well by the way.

Sorry I forgot to explain to remove all ha ref

import socket
import yaml
import logging
import struct
import paho.mqtt.client as paho
import json
from datetime import datetime
from parser import ParameterParser
from const import *

log = logging.getLogger(__name__)

START_OF_MESSAGE = 0xA5
END_OF_MESSAGE = 0x15
CONTROL_CODE = [0x10, 0x45]
SERIAL_NO = [0x00, 0x00]
SEND_DATA_FIELD = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
QUERY_RETRY_ATTEMPTS = 6

class Inverter:
    def __init__(self, path, serial, host, port, mb_slaveid, lookup_file):
        self._serial = serial
        self.path = path
        self._host = host
        self._port = port
        self._mb_slaveid = mb_slaveid
        self._current_val = None
        self.status_connection = "Disconnected"
        self.status_lastUpdate = "N/A"
        self.lookup_file = lookup_file
        if not self.lookup_file or lookup_file == 'parameters.yaml':
            self.lookup_file = 'deye_hybrid.yaml'

        with open(self.path + self.lookup_file) as f:
            self.parameter_definition = yaml.full_load(f)

    def modbus(self, data):
        POLY = 0xA001

        crc = 0xFFFF
        for byte in data:
            crc ^= byte
            for _ in range(8):
                crc = ((crc >> 1) ^ POLY
                if (crc & 0x0001)
                else crc >> 1)
        return crc

    def get_serial_hex(self):
        serial_hex = hex(self._serial)[2:]
        serial_bytes = bytearray.fromhex(serial_hex)
        serial_bytes.reverse()
        return serial_bytes

    def get_read_business_field(self, start, length, mb_fc):
        request_data = bytearray([self._mb_slaveid, mb_fc]) # Function Code
        request_data.extend(start.to_bytes(2, 'big'))
        request_data.extend(length.to_bytes(2, 'big'))
        crc = self.modbus(request_data)
        request_data.extend(crc.to_bytes(2, 'little'))
        return request_data

    def generate_request(self, start, length, mb_fc):
        packet = bytearray([START_OF_MESSAGE])

        packet_data = []
        packet_data.extend (SEND_DATA_FIELD)
        buisiness_field = self.get_read_business_field(start, length, mb_fc)
        packet_data.extend(buisiness_field)
        length = packet_data.__len__()
        packet.extend(length.to_bytes(2, "little"))
        packet.extend(CONTROL_CODE)
        packet.extend(SERIAL_NO)
        packet.extend(self.get_serial_hex())
        packet.extend(packet_data)
        #Checksum
        checksum = 0
        for i in range(1,len(packet),1):
            checksum += packet[i]
        packet.append(checksum & 0xFF)
        packet.append(END_OF_MESSAGE)

        del packet_data
        del buisiness_field
        return packet

    def validate_packet(self, packet):
        # Perform some checks to ensure the received packet is correct
        # Start with the outer V5 logger packet and work inwards towards the embedded modbus frame

        # Does the v5 packet start and end with what we expect?
        if packet[0] != 0xa5 or packet[len(packet) - 1] != 0x15:
            log.debug("unexpected v5 packet start/stop")
            return 0
        # Does the v5 packet have the correct checksum?
        elif self.validate_v5_checksum(packet) == 0:
            log.debug("invalid v5 checksum")
            return 0
        # Is the control code what we expect?  Note: We sometimes see keepalives appear (0x4710)
        elif packet[3:5] != struct.pack("<H", 0x1510):
            log.debug("unexpected v5 control code")
            return 0
        # Is the v5 packet of the expected type?
        elif packet[11] != 0x02:
            log.debug("unexpected v5 frame type")
            return 0

        # Move onto the encapsulated modbus frame
        modbus_frame = packet[25:len(packet) - 2]

        # Is the modbus CRC correct?
        if self.validate_modbus_crc(modbus_frame) == 0:
            log.debug("invalid modbus crc")
            return 0

        # Validation compelted successfully
        return 1


    def validate_modbus_crc(self, frame):
        # Calculate crc with all but the last 2 bytes of the frame (they contain the crc)
        calc_crc = 0xFFFF
        for pos in frame[:-2]:
            calc_crc ^= pos
            for i in range(8):
                if (calc_crc & 1) != 0:
                    calc_crc >>= 1
                    calc_crc ^= 0xA001  # bitwise 'or' with modbus magic number (0xa001 == bitwise reverse of 0x8005)
                else:
                    calc_crc >>= 1

        # Compare calculated crc with the one supplied in the frame....
        frame_crc, = struct.unpack('<H', frame[-2:])
        if calc_crc == frame_crc:
            return 1
        else:
            return 0


    def validate_v5_checksum(self, packet):
        checksum = 0
        length = len(packet)
        # Don't include the checksum and END OF MESSAGE (-2)
        for i in range(1, length - 2, 1):
            checksum += packet[i]
        checksum &= 0xFF
        if checksum == packet[length - 2]:
            return 1
        else:
            return 0


    def send_request(self, params, start, end, mb_fc, sock):
        result = 0
        length = end - start + 1
        request = self.generate_request(start, length, mb_fc)
        try:
            log.debug(request.hex())
            sock.sendall(request)
            raw_msg = sock.recv(1024)
            log.debug(raw_msg.hex())
            if self.validate_packet(raw_msg) == 1:
                result = 1
                params.parse(raw_msg, start, length)
            else:
                log.debug(f"Querying [{start} - {end}] failed, invalid response packet.")
            del raw_msg
        finally:
            del request
        return result

    def update (self):
        self.get_statistics()
        return


    def get_statistics(self):
        result = 1
        params = ParameterParser(self.parameter_definition)
        requests = self.parameter_definition['requests']
        log.debug(f"Starting to query for [{len(requests)}] ranges...")

        def connect_to_server():
            server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            server.settimeout(6)
            server.connect((self._host, self._port))
            return server

        sock = None
        try:
            sock = connect_to_server()

            for request in requests:
                start = request['start']
                end = request['end']
                mb_fc = request['mb_functioncode']
                log.debug(f"Querying [{start} - {end}]...")

                attempts_left = QUERY_RETRY_ATTEMPTS
                while attempts_left > 0:
                    attempts_left -= 1
                    result = 0
                    try:
                        result = self.send_request(params, start, end, mb_fc, sock)
                    except ConnectionResetError:
                        log.debug(f"Querying [{start} - {end}] failed as client closed stream, trying to re-open.")
                        sock.close()
                        sock = connect_to_server()
                    except TimeoutError:
                        log.debug(f"Querying [{start} - {end}] failed with timeout")
                    except Exception as e:
                        log.debug(f"Querying [{start} - {end}] failed with exception [{type(e).__name__}]")
                    if result == 0:
                        log.debug(f"Querying [{start} - {end}] failed, [{attempts_left}] retry attempts left")
                    else:
                        log.debug(f"Querying [{start} - {end}] succeeded")
                        break
                if result == 0:
                    log.warning(f"Querying registers [{start} - {end}] failed, aborting.")
                    break

            if result == 1:
                log.debug(f"All queries succeeded, exposing updated values.")
                self.status_lastUpdate = datetime.now().strftime("%m/%d/%Y, %H:%M:%S")
                self.status_connection = "Connected"
                self._current_val = params.get_result()
            else:
                self.status_connection = "Disconnected"
        except Exception as e:
            log.warning(f"Querying inverter {self._serial} at {self._host}:{self._port} failed on connection start with exception [{type(e).__name__}]")
            self.status_connection = "Disconnected"
        finally:
            if sock:
                sock.close()

    def get_current_val(self):
        return self._current_val

    def get_sensors(self):
        params = ParameterParser(self.parameter_definition)
        return params.get_sensors ()
    
def main():
    inverter = Inverter("/home/openhabian/solarman/inverter_definitions/", <logger-sn>, <logger-ip>, 8899, 1, "deye_sg04lp3.yaml")
    inverter.update()
    val = inverter.get_current_val()
    val["last_update"] = inverter.status_lastUpdate
    val["status"] = "ON"
    val["status_connection"] = inverter.status_connection
    mqtt_client = paho.Client("deye_inverter")
    mqtt_client.enable_logger()
    mqtt_client.connect(<mqtt-address>, 1883)
    #mqtt_client.loop_start()
    mqtt_topic = "deye/measurements"
    json_object = json.dumps(val)
    mqtt_client.publish(mqtt_topic, json_object, qos=1, retain=True)
    mqtt_client.disconnect()

if __name__ == "__main__":
    main()

1 Like

@giorginus80 , thanks a lot! That helped.

For my Deye SUN600G3-EU-230 I also needed to replace the inverter definition file. With “deye_4mppt.yaml” I can now see the data being posted to the MQTT broker.

Have a nice day!

1 Like

I successfully installed home assistant with my Deye SG04LP3. I would also try openhab. Can you recommend me a plugin?

Actually there isnt a plugin but can you use the python script used in this post

If you have logger stick with with requirements as follow:

Supported sticks:
wifi stick with firmware - LSW3_15_FFFF_1.0.57, those have serial number starting with 17xxx
wifi stick with firmware - LSW3_15_FFFF_1.0.65, those have serial number starting with 17xxx
eth stick with firmware - ME_08_2701_2.06, those have serial number starting with 21xxx

Then you probably may use this [new binding] Logger LSW for Sofar/Omnik/IE for SolarmanPV based on protocol v5 (iGEN tech)

Have you tried this project? GitHub - kbialek/deye-inverter-mqtt: Reads Deye solar inverter metrics and posts them over mqtt
I’ve written it exactly because I couldn’t make any binding working with my inverter.

How fast are the values updated?

Every 60 seconds by default. This can be changed in the configuration

Anybody knows if using the modbus rj45 port of the Deye inverter, is it possible with a Serial ethernet, with modbus binding, read values and which addresses? Without using and keep busy with network traffic the serial logger

Working like a charm with a HF2211. So you can use a direct wired connection to the network
my params:

so you can use the modbus binding, list of params was sent to me from Deye just today, and they working perfect.


HF2211 works with ethernet or wireless. I used it for my control unit of swimming pool too and it’s working very well. I prefer to use this, just to don’t overload requests to the logger, and to use the modbus binding integration

I attach the deye addresses for who is interested
MODBUS RTU-V102_compressed.pdf (490.4 KB)