Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Report soyo inverter status #94

Closed
GWarsow opened this issue Jun 15, 2023 · 11 comments · Fixed by #85
Closed

Report soyo inverter status #94

GWarsow opened this issue Jun 15, 2023 · 11 comments · Fixed by #85

Comments

@GWarsow
Copy link

GWarsow commented Jun 15, 2023

Hi all

I use Esp-Soyosource-Controller in order to control 2 soyosource inverters with input from shelly3 em. I already made DBUS aware of the AC input for L1-3. Now I also would like to register both soyos (running on L1 and L2) as inverter/pvinverter via opendtu. The config.ini is set to use only templates and the respective config part looks like this:

Username =
Password =
DigestAuth = False
Host=192.168.x.y
CUST_SN = 12345678
CUST_API_PATH= data
CUST_POLLING = 2000
CUST_Total= none
CUST_Total_Mult = 1
CUST_Power= /WattsOut
CUST_Power_Mult = 1
CUST_Voltage=  none
CUST_Current=  none
Phase=L1
DeviceInstance=47
AcPosition=1
Name= Soyo1
Servicename=com.victronenergy.pvinverter

The idea is to use the json returned when calling 192.168.x.y/data
The json looks like
{ "L1L2L3" : "-4.51" , "ControllerName" : "SOYOSOURCE Controller" , "StartTime" : "Thu Jun 15 12:27:10 2023" , "NotAus" : "0" , "WaitSekunden" : "2" , "MaxPower" : "1000" , "SoyoCount" : "2" , "DCAmps" : "S>1" , "DCVolts" : "S>1" , "DCWatts" : "S>1" , "WattsOut" : "144"}

WattsOut carries the needed information. However, when I try to use CUST_Power= /WattsOut in the config, the received value is 0. The device is successfully registered with victron dbus but V/A/W value are all zero. But I would expect that due to setting of CUST_Power that I should see 144W in the victron console or the dashboard. If I ommit the leading slash (CUST_Power= WattsOut) it does not work at all. Could it be that the parser expects a nested structure and cannot use top level entries of the json?

Do you have any suggestion as of how to achieve what I am aming for?

Thank you
Gregor

@henne49
Copy link
Owner

henne49 commented Jun 16, 2023

let me check the code, yes I think we need a nested one...

@henne49
Copy link
Owner

henne49 commented Jun 16, 2023

Please try CUST_Power=WattsOut no space please. It should work:

>>> CUST_Power='WattsOut'
>>> CUST_Power.split("/")
['WattsOut']
>>> CUST_Power=' WattsOut'
>>> CUST_Power.split("/")
[' WattsOut']
>>>

@GWarsow
Copy link
Author

GWarsow commented Jun 16, 2023

Good idea! But unfortunately, it still does not work.

# Number ob Template Inverter to query
NumberOfTemplates=1

# Which DTU to be used ahoy, opendtu, template
DTU=template


[TEMPLATE0]
## Tasmota Example
##
## Username/Password leave empty if no authentication is required
Username =
Password =
DigestAuth = False
Host=192.168.x.y
CUST_SN = 12345678
CUST_API_PATH= data
CUST_POLLING = 2000
CUST_Total=none
CUST_Total_Mult = 1
CUST_Power=WattsOut
CUST_Power_Mult = 1
CUST_Voltage=none
CUST_Current=none
Phase=L1
DeviceInstance=47
AcPosition=1
Name= Soyo1
Servicename=com.victronenergy.pvinverter

dbus-spy output:

com.victronenergy.pvinverter.http_47
Ac/Energy/Forward                                              -
Ac/L1/Current                                                  -
Ac/L1/Energy/Forward                                           -
Ac/L1/Power                                                    -
Ac/L1/Voltage                                                  -
Ac/L2/Current                                                  -
Ac/L2/Energy/Forward                                           -
Ac/L2/Power                                                    -
Ac/L2/Voltage                                                  -
Ac/L3/Current                                                  -
Ac/L3/Energy/Forward                                           -
Ac/L3/Power                                                    -
Ac/L3/Voltage                                                  -
Ac/Out/L1/I                                                    -
Ac/Out/L1/V                                                    -
Ac/Power                                                       -
Connected                                                      1
CustomName                                                 Soyo1
Dc/0/Voltage                                                   -
DeviceInstance                                                47
FirmwareVersion                                              0.1
HardwareVersion                                                0

wget 192.168.x.y/data yields:
{ "L1L2L3" : "685.81" , "ControllerName" : "SOYOSOURCE Controller" , "StartTime" : "Fri Jun 16 04:29:44 2023" , "NotAus" : "0" , "WaitSekunden" : "2" , "MaxPower" : "1000" , "SoyoCount" : "2" , "DCAmps" : "S>1" , "DCVolts" : "S>1" , "DCWatts" : "S>1" , "WattsOut" : "533"}

@henne49
Copy link
Owner

henne49 commented Jun 16, 2023

Will have a look in the next days and then we fix it.

@GWarsow
Copy link
Author

GWarsow commented Jun 16, 2023

sounds great! thank you so much!

@GWarsow
Copy link
Author

GWarsow commented Jun 16, 2023

I added
logging.info("meter data: %s", meter_data); after line 363 of dbus_service.py and got:
2023-06-16 13:15:41,725 root INFO meter data: {'L1L2L3': '-2.29', 'ControllerName': 'SOYOSOURCE Controller', 'StartTime': 'Fri Jun 16 04:29:44 2023', 'NotAus': '0', 'WaitSekunden': '2', 'MaxPower': '1000', 'SoyoCount': '2', 'DCAmps': 'S>1', 'DCVolts': 'S>1', 'DCWatts': 'S>1', 'WattsOut': '271'}
So the json was fetched correctly.

@0x7878
Copy link
Collaborator

0x7878 commented Jun 16, 2023

Check line 599 in dbus_service.py

elif self.dtuvariant == constants.DTUVARIANT_TEMPLATE:
            # logging.debug("JSON data: %s" % meter_data)
            power = float(get_nested(meter_data, self.custpower) * float(self.custpower_factor))
            pvyield = float(get_nested(meter_data, self.custtotal) * float(self.custtotal_factor))
            voltage = float(get_nested(meter_data, self.custvoltage))
            dc_voltage = float(get_nested(meter_data, self.custdcvoltage))
            current = float(get_nested(meter_data, self.custcurrent))

        return (power, pvyield, current, voltage, dc_voltage)

Every value goes to the "get_nested" function

def get_nested(meter_data, path):
    '''Try to extract 'path' from nested array 'meter_data' (derived from json document) and return the found value'''
    value = meter_data
    for path_entry in path:
        try:
            value = value[path_entry]
        except Exception:
            try:
                value = value[int(path_entry)]
            except Exception:
                value = 0
    return value

which returns 0 if there is a problem.

This is a good place to start debugging.

@GWarsow
Copy link
Author

GWarsow commented Jun 16, 2023

I added some log lines in line 600:

            logging.info("JSON data: %s" % meter_data)
            logging.info("custpower: %s", self.custpower)
            logging.info("nested power: '%s'", get_nested(meter_data, self.custpower));
            #logging.info("float power: %s", float(get_nested(meter_data, self.custpower));
            logging.info("power factor: %s", self.custpower_factor);
            logging.info("float power factor: %s", float(self.custpower_factor));

the one line I commented out seems to cause problems, hence, casting e.g. 200 to float does not work

output of above code:

2023-06-16 14:00:31,169 root INFO JSON data: {'L1L2L3': '-9.95', 'ControllerName': 'SOYOSOURCE Controller', 'StartTime': 'Fri Jun 16 04:29:44 2023', 'NotAus': '0', 'WaitSekunden': '2', 'MaxPower': '1000', 'SoyoCount': '2', 'DCAmps': 'S>1', 'DCVolts': 'S>1', 'DCWatts': 'S>1', 'WattsOut': '326'}
2023-06-16 14:00:31,172 root INFO custpower: ['WattsOut']
2023-06-16 14:00:31,174 root INFO nested power: '326'
2023-06-16 14:00:31,175 root INFO power factor: 1
2023-06-16 14:00:31,176 root INFO float power factor: 1.0

@GWarsow
Copy link
Author

GWarsow commented Jun 16, 2023

Assigning the value of get_nested(meter_data, self.custpower) to a variable and casting it to float works well:

custpower = get_nested(meter_data, self.custpower)
custpower = float(custpower)
power = float(custpower * float(self.custpower_factor))

@0x7878
Copy link
Collaborator

0x7878 commented Jun 16, 2023

I'm sorry for the trouble. Exactly this type of problem is already fixed in my Pullrequest which is not merged yet. There all values goes to the function like this:

 @staticmethod
    def get_processed_meter_value(meter_data: dict, value: str, default_value: any, factor: int = 1) -> any:
        '''return the processed meter value by applying the factor and return a default value due an Exception'''
        get_raw_value = get_value_by_path(meter_data, value)
        raw_value = convert_to_expected_type(get_raw_value, float, default_value)
        if isinstance(raw_value, (float, int)):
            value = float(raw_value * float(factor))
        else:
            value = default_value

        return value
 Maybe we should keep that issue open for others. 

@dsteinkopf
Copy link
Collaborator

For reference: This is the mentioned PR which is expected to fix the above problem: #85

@0x7878 0x7878 linked a pull request Jun 23, 2023 that will close this issue
@0x7878 0x7878 closed this as completed Jun 23, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants