Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 64 additions & 31 deletions solax/inverters/x1_lite_lv.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,21 @@
import voluptuous as vol

from solax.inverter import Inverter
from solax.units import DailyTotal, Total, Units
from solax.utils import div10, div100, pack_u16, to_signed, to_signed32, twoway_div10
from solax.units import Total, Units
from solax.utils import div10, div100, pack_u16, to_signed, twoway_div10


class X1LiteLV(Inverter):
# pylint: disable=duplicate-code
_schema = vol.Schema(
{
vol.Required("type"): int,
vol.Required(
"sn",
): str,
vol.Required("sn"): str,
vol.Required("ver"): str,
vol.Required("data"): vol.Schema(
vol.All(
[vol.Coerce(float)],
vol.Length(min=200, max=200),
vol.Length(min=200, max=300),
)
),
vol.Required("information"): vol.Schema(vol.All(vol.Length(min=1, max=15))),
Expand All @@ -29,7 +27,7 @@ class X1LiteLV(Inverter):

@classmethod
def build_all_variants(cls, host, port, pwd=""):
versions = [cls._build(host, port, pwd)]
versions = [cls._build(host, port, pwd), cls._build(host, port, pwd, False)]
return versions

@classmethod
Expand All @@ -39,22 +37,22 @@ def response_decoder(cls):
"""
return {
"AC Voltage": (0, Units.V, div10),
"AC Output Current": (1, Units.A, twoway_div10),
"AC Output Power": (2, Units.W, to_signed),
"AC Current": (1, Units.A, twoway_div10),
"AC Power": (2, Units.W, to_signed),
"AC Frequency": (3, Units.HZ, div100),
"Grid PF": (4, Units.PERCENT, div10),
###################################
"AC Voltage Out": (97, Units.V, div10),
# "AC current Out": (98, Units.A, twoway_div10),
# "AC power Out": (99, Units.W, to_signed),
# "AC Current Out": (98, Units.A, twoway_div10),
# "AC Power Out": (99, Units.W, to_signed),
"AC Frequency Out": (101, Units.HZ, div10),
# "Inverter Status 1 ?": (15, Units.NONE), # 2 - Normal Mode, 7 - EPSMode
# "Inverter Status 2 ?": (16, Units.NONE), # 4 - Normal Mode, 5 - EPSMode
##################################
"Grid Power": (32, Units.W, twoway_div10),
# "Grid power 1": (33, Units.W, twoway_div10),
# "Grid power 2": (34, Units.W, twoway_div10),
"Hourly Energy": (51, DailyTotal(Units.KWH), div100),
"Hourly Energy": (51, Total(Units.KWH), div100),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why has this changed from daily total to total?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did this changes because had a warning from a HA.
So when I'll use the DailyTotal there I will get this warning: 2025-09-12 10:39:09.320 WARNING (MainThread) [homeassistant.components.sensor] Entity sensor.solax_xxxxxxx_hourly_energy (<class 'custom_components.custom_solax.sensor.InverterSensorEntity'>) is using state class 'measurement' which is impossible considering device class ('energy') it is using; expected None or one of 'total', 'total_increasing'; Please update your configuration if your entity is manually configured, otherwise report it to the author of the 'solax' integration

according the async_setup_entry

for the tupple lookup
SENSOR_DESCRIPTIONS[(measurement.unit, measurement.is_monotonic)]

and this sensor setup

    (Units.KWH, False): SensorEntityDescription(
        key=f"{Units.KWH}_{False}",
        device_class=SensorDeviceClass.ENERGY,
        native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
        state_class=SensorStateClass.MEASUREMENT,
    ),
    (Units.KWH, True): SensorEntityDescription(
        key=f"{Units.KWH}_{True}",
        device_class=SensorDeviceClass.ENERGY,
        native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
        state_class=SensorStateClass.TOTAL_INCREASING,
    ),

better to use the Total instead of DailyTotal there or need to change
from

class DailyTotal(Measurement):

to

class DailyTotal(Total):

But this is unsafe

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, as a side note it looks like we never use resets_daily? Wonder why I implemented that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But the TOTAL_INCREASE also support the reset_daily state value + sum

###############################
"PV1 Voltage": (5, Units.V, div10),
"PV2 Voltage": (7, Units.V, div10),
Expand All @@ -65,13 +63,18 @@ def response_decoder(cls):
"PV1 Power": (11, Units.W),
"PV2 Power": (12, Units.W),
"PV3 Power": (13, Units.W),
"Total PV Power": (14, Total(Units.KWH), to_signed),
"Today's PV Energy": (52, DailyTotal(Units.KWH), twoway_div10),
"Total PV Power": (14, Units.W),
"Daily PV Energy": (52, Total(Units.KWH), twoway_div10),
"Total PV Energy": (53, Total(Units.KWH), twoway_div10),
################################
"Inverter Temperature": (68, Units.C, div10),
"Inverter Temperature 1": (69, Units.C, div10),
"Inverter Temperature 2": (70, Units.C, div10),
"Inverter Temperature 3": (71, Units.C, div10),
################################
"Battery Type": (27, Units.NONE), # Undefined
"Battery voltage": (23, Units.V, div10),
"Battery current": (24, Units.A, twoway_div10),
"Battery Voltage": (23, Units.V, div10),
"Battery Current": (24, Units.A, twoway_div10),
"Total Battery power": (25, Units.W, twoway_div10),
###########################
"Battery SoC": (75, Units.PERCENT, div10),
Expand All @@ -80,28 +83,58 @@ def response_decoder(cls):
"Battery Temperature 3": (74, Units.C),
"Battery Temperature 4": (78, Units.C),
"Battery Temperature": (79, Units.C),
"Battery Charge total": (pack_u16(26, 27), Units.KWH, div10),
"Battery Discharge total": (pack_u16(28, 29), Units.KWH, div10),
"Battery Charge today": (30, Units.KWH, div10),
"Battery Discharge today": (31, Units.KWH, div10),
"Charging Duration": (pack_u16(80, 81), Units.NONE, to_signed32),
"Today's Battery Discharge": (30, DailyTotal(Units.KWH), div10),
####################################
"Daily Battery Charge": (30, Total(Units.KWH), div10),
"Total Battery Charge": (
pack_u16(26, 27),
Total(Units.KWH),
twoway_div10,
),
"Daily Battery Discharge": (31, Total(Units.KWH), div10),
"Total Battery Discharge": (
pack_u16(28, 29),
Total(Units.KWH),
twoway_div10,
),
"Today's Battery Charge": (31, DailyTotal(Units.KWH), div10),
"Total Battery Charge": (pack_u16(26, 27), Total(Units.KWH), twoway_div10),
################
"Today's Generated Energy": (21, DailyTotal(Units.KWH), div10),
"Total Generated Energy": (pack_u16(17, 18), Total(Units.KWH), div10),
"Today's EPS Energy": (46, DailyTotal(Units.KWH), div10),
"Total EPS Energy": (pack_u16(47, 48), Total(Units.KWH), div10),
"Today's Import Energy": (40, DailyTotal(Units.KWH), div10),
"Total Import Energy": (pack_u16(36, 37), Total(Units.KWH), div10),
"Daily Inverter Output": (21, Total(Units.KWH), div10),
"Total Inverter Output": (
pack_u16(17, 18),
Total(Units.KWH),
div10,
),
"Daily Inverter EPS Energy": (46, Total(Units.KWH), div10),
"Total Inverter EPS Energy": (
pack_u16(47, 48),
Total(Units.KWH),
div10,
),
"Daily Imported Energy": (40, Total(Units.KWH), div10),
"Total Imported Energy": (
pack_u16(36, 37),
Total(Units.KWH),
div10,
),
}

@classmethod
def dongle_serial_number_getter(cls, response: Dict[str, Any]) -> Optional[str]:
info = response.get("information", [])
return info[2] if len(info) > 2 else None

@classmethod
def inverter_serial_number_getter(cls, response: Dict[str, Any]) -> Optional[str]:
return response["information"][2]
info = response.get("information", [])
return info[2] if len(info) > 2 else None

# @classmethod
# def inverter_versions_getter(
# cls, response: Dict[str, Any]
# ) -> Optional[Dict[str, str]]:
# i = response["information"]
# return {
# "Main DSP": f"{i[4]:03.2f}",
# "Slave DSP": f"{i[5]:03.2f}",
# "ARM": f"{i[6]:03.2f}-{i[7]:03.2f}",
# "Module version": response["ver"],
# }
20 changes: 16 additions & 4 deletions tests/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
X1_BOOST_VALUES_V3,
X1_HYBRID_G4_V_3_018_VALUES,
X1_HYBRID_G4_VALUES,
X1_LITE_LV_80_VALUES,
X1_MINI_G4_VALUES,
X1_MINI_VALUES,
X1_MINI_VALUES_V34,
Expand All @@ -30,6 +29,8 @@
X3V34_HYBRID_VALUES_EPS_MODE,
X3V34_HYBRID_VALUES_NEGATIVE_POWER,
XHYBRID_VALUES,
X1_LITE_LV_80_v002_VALUES,
X1_LITE_LV_80_v005_VALUES,
)
from tests.samples.responses import (
QVOLTHYBG33P_RESPONSE_V34,
Expand All @@ -42,7 +43,6 @@
X1_HYBRID_G3_RESPONSE,
X1_HYBRID_G4_RESPONSE,
X1_HYBRID_G4_V_3_018_RESPONSE,
X1_LITE_LV_80_RESPONSE,
X1_MINI_G4,
X1_MINI_RESPONSE_V34,
X1_MINI_RESPONSE_V34_VER3,
Expand All @@ -60,6 +60,8 @@
X3_ULTRA_RESPONSE,
XHYBRID_DE01_RESPONSE,
XHYBRID_DE02_RESPONSE,
X1_LITE_LV_80_v002_RESPONSE,
X1_LITE_LV_80_v005_RESPONSE,
)

X_FORWARDED_HEADER = {"X-Forwarded-For": "5.8.8.8"}
Expand Down Expand Up @@ -203,9 +205,19 @@ def simple_http_fixture(httpserver):
uri="/",
method="POST",
query_string="optType=ReadRealTimeData",
response=X1_LITE_LV_80_RESPONSE,
response=X1_LITE_LV_80_v002_RESPONSE,
inverter=inverter.X1LiteLV,
values=X1_LITE_LV_80_VALUES,
values=X1_LITE_LV_80_v002_VALUES,
headers=None,
data=None,
),
InverterUnderTest(
uri="/",
method="POST",
query_string="optType=ReadRealTimeData",
response=X1_LITE_LV_80_v005_RESPONSE,
inverter=inverter.X1LiteLV,
values=X1_LITE_LV_80_v005_VALUES,
headers=None,
data=None,
),
Expand Down
86 changes: 66 additions & 20 deletions tests/samples/expected_values.py
Original file line number Diff line number Diff line change
Expand Up @@ -558,10 +558,10 @@
"Total Import Energy": 0.0,
}

X1_LITE_LV_80_VALUES = {
X1_LITE_LV_80_v002_VALUES = {
"AC Voltage": 239.7,
"AC Output Current": 0.9,
"AC Output Power": 1280,
"AC Current": 0.9,
"AC Power": 1280,
"AC Frequency": 50.02,
"Grid PF": 100.0,
"AC Voltage Out": 229.5,
Expand All @@ -578,33 +578,79 @@
"PV2 Power": 985.0,
"PV3 Power": 0.0,
"Total PV Power": 0.0,
"Today's PV Energy": 0.2,
"Daily PV Energy": 0.2,
"Total PV Energy": 255.0,
"Inverter Temperature": 41.0,
"Inverter Temperature 1": 35.0,
"Inverter Temperature 2": 33.0,
"Inverter Temperature 3": 41.0,
"Battery Type": 0.0,
"Battery voltage": 52.6,
"Battery current": -7.3,
"Battery Voltage": 52.6,
"Battery Current": -7.3,
"Total Battery power": -38.8,
"Battery SoC": 62.0,
"Battery Temperature 1": 19.0,
"Battery Temperature 2": 21.0,
"Battery Temperature 3": 22.0,
"Battery Temperature 4": 19.0,
"Battery Temperature": 19.0,
"Battery Charge total": 111.4,
"Battery Discharge total": 163.0,
"Battery Charge today": 0.0,
"Battery Discharge today": 4.0,
"Charging Duration": 0.0,
"Today's Battery Discharge": 0.0,
"Total Battery Discharge": 163.0,
"Today's Battery Charge": 4.0,
"Daily Battery Charge": 0.0,
"Total Battery Charge": 111.4,
"Today's Generated Energy": 0.0,
"Total Generated Energy": 120.6,
"Today's EPS Energy": 4.7,
"Total EPS Energy": 224.5,
"Today's Import Energy": 3.2,
"Total Import Energy": 282.9,
"Daily Battery Discharge": 4.0,
"Total Battery Discharge": 163.0,
"Daily Inverter Output": 0.0,
"Total Inverter Output": 120.6,
"Daily Inverter EPS Energy": 4.7,
"Total Inverter EPS Energy": 224.5,
"Daily Imported Energy": 3.2,
"Total Imported Energy": 282.9,
}
X1_LITE_LV_80_v005_VALUES = {
"AC Voltage": 0,
"AC Current": 0,
"AC Power": 0,
"AC Frequency": 0,
"Grid PF": 100.0,
"AC Voltage Out": 228.5,
"AC Frequency Out": 49.9,
"Grid Power": 0.0,
"Hourly Energy": 97.28,
"PV1 Voltage": 346.6,
"PV2 Voltage": 287.5,
"PV3 Voltage": 0.0,
"PV1 Current": 7.3,
"PV2 Current": 0.6,
"PV3 Current": 0.0,
"PV1 Power": 2544.0,
"PV2 Power": 182.0,
"PV3 Power": 0.0,
"Total PV Power": 2726.0,
"Daily PV Energy": 5.2,
"Total PV Energy": 1560.4,
"Inverter Temperature": 43.0,
"Inverter Temperature 1": 45.0,
"Inverter Temperature 2": 45.0,
"Inverter Temperature 3": 51.0,
"Battery Type": 0.0,
"Battery Voltage": 53.8,
"Battery Current": 48.0,
"Total Battery power": 258.7,
"Battery SoC": 94.0,
"Battery Temperature 1": 26.0,
"Battery Temperature 2": 37.0,
"Battery Temperature 3": 39.0,
"Battery Temperature 4": 26.0,
"Battery Temperature": 26.0,
"Daily Battery Charge": 5.2,
"Total Battery Charge": 919.0,
"Daily Battery Discharge": 0.1,
"Total Battery Discharge": 346.5,
"Daily Inverter Output": 0.0,
"Total Inverter Output": 581.0,
"Daily Inverter EPS Energy": 6.3,
"Total Inverter EPS Energy": 1143.9,
"Daily Imported Energy": 0.0,
"Total Imported Energy": 116.1,
}

QVOLTHYBG33P_VALUES = {
Expand Down
Loading