@@ -267,12 +267,12 @@ async def async_read_inverter_firmware_info(hub: Any) -> int:
267267 inverter_data = await hub .async_read_holding_registers (unit = hub ._modbus_addr , address = 0x7D , count = 8 )
268268 if inverter_data is not None and not inverter_data .isError ():
269269 registers = inverter_data .registers
270- data ["firmware_dsp " ] = int (registers [0 ])
270+ data ["firmware_dsp_minor " ] = int (registers [0 ])
271271 data ["firmware_DSP_hardware_version" ] = int (registers [1 ])
272272 data ["firmware_dsp_major" ] = int (registers [2 ])
273273 data ["firmware_arm_major" ] = int (registers [3 ])
274274 version = int (registers [5 ])
275- data ["firmware_arm " ] = int (registers [6 ])
275+ data ["firmware_arm_minor " ] = int (registers [6 ])
276276 data ["bootloader_version" ] = int (registers [7 ])
277277 except Exception :
278278 _LOGGER .debug (f"{ hub .name } : attempt to read inverter firmware info failed data: { inverter_data } " , exc_info = True )
@@ -284,8 +284,8 @@ async def async_read_inverter_firmware_info(hub: Any) -> int:
284284 else :
285285 hub .modbus_protocol_version = None
286286 data .pop ("modbus_protocol_version" , None )
287- data .pop ("firmware_version_dsp " , None )
288- data .pop ("firmware_version_arm " , None )
287+ data .pop ("firmware_dsp " , None )
288+ data .pop ("firmware_arm " , None )
289289 _LOGGER .debug (f"{ hub .name } : Modbus protocol document version unavailable" )
290290 return 0
291291
@@ -294,13 +294,13 @@ async def async_read_inverter_firmware_info(hub: Any) -> int:
294294 try :
295295 full_version_data = await hub .async_read_holding_registers (unit = hub ._modbus_addr , address = 0x7B , count = 2 )
296296 if full_version_data is not None and not full_version_data .isError ():
297- data ["firmware_version_dsp " ] = int (full_version_data .registers [0 ])
298- data ["firmware_version_arm " ] = int (full_version_data .registers [1 ])
297+ data ["firmware_dsp " ] = int (full_version_data .registers [0 ])
298+ data ["firmware_arm " ] = int (full_version_data .registers [1 ])
299299 except Exception :
300300 _LOGGER .debug (f"{ hub .name } : attempt to read full firmware version failed data: { full_version_data } " , exc_info = True )
301301 else :
302- data .pop ("firmware_version_dsp " , None )
303- data .pop ("firmware_version_arm " , None )
302+ data .pop ("firmware_dsp " , None )
303+ data .pop ("firmware_arm " , None )
304304
305305 return version
306306
@@ -1351,7 +1351,8 @@ def value_function_battery_capacity_gen5(initval: int, descr: Any, datadict: dic
13511351
13521352
13531353def value_function_software_version_g2 (initval : int , descr : Any , datadict : dict [str , Any ]) -> str | None :
1354- return f"DSP v2.{ datadict .get ('firmware_dsp' )} ARM v2.{ datadict .get ('firmware_arm' )} "
1354+ # AC/HYBRID GEN2: split registers hold raw minor versions with a fixed major of 2
1355+ return f"DSP v2.{ datadict .get ('firmware_dsp_minor' )} ARM v2.{ datadict .get ('firmware_arm_minor' )} "
13551356
13561357
13571358def value_function_firmware_major_default (val : Any , default : int ) -> Any :
@@ -1361,27 +1362,9 @@ def value_function_firmware_major_default(val: Any, default: int) -> Any:
13611362def value_function_software_version_g3 (initval : int , descr : Any , datadict : dict [str , Any ]) -> str | None :
13621363 return (
13631364 f"DSP v{ value_function_firmware_major_default (datadict .get ('firmware_dsp_major' ), 3 )} ."
1364- f"{ value_str_default (datadict .get ('firmware_dsp ' ), '??' ):>02} "
1365+ f"{ value_str_default (datadict .get ('firmware_dsp_minor ' ), '??' ):>02} "
13651366 f"ARM v{ value_function_firmware_major_default (datadict .get ('firmware_arm_major' ), 3 )} ."
1366- f"{ value_str_default (datadict .get ('firmware_arm' ), '??' ):>02} "
1367- )
1368-
1369-
1370- def value_function_software_version_g4 (initval : int , descr : Any , datadict : dict [str , Any ]) -> str | None :
1371- return (
1372- f"DSP { value_str_default (datadict .get ('firmware_dsp_major' ), '?' )} ."
1373- f"{ value_str_default (datadict .get ('firmware_dsp' ), '??' ):>02} "
1374- f"ARM { value_str_default (datadict .get ('firmware_arm_major' ), '?' )} ."
1375- f"{ value_str_default (datadict .get ('firmware_arm' ), '??' ):>02} "
1376- )
1377-
1378-
1379- def value_function_software_version_g5 (initval : int , descr : Any , datadict : dict [str , Any ]) -> str | None :
1380- return (
1381- f"DSP { value_str_default (datadict .get ('firmware_dsp_major' ), '???' ):>03} ."
1382- f"{ value_str_default (datadict .get ('firmware_dsp' ), '??' ):>02} "
1383- f"ARM { value_str_default (datadict .get ('firmware_arm_major' ), '???' ):>03} ."
1384- f"{ value_str_default (datadict .get ('firmware_arm' ), '??' ):>02} "
1367+ f"{ value_str_default (datadict .get ('firmware_arm_minor' ), '??' ):>02} "
13851368 )
13861369
13871370
@@ -1392,31 +1375,68 @@ def value_function_modbus_protocol_version(datadict: dict[str, Any]) -> int:
13921375 return 0
13931376
13941377
1395- def value_function_software_version_full (initval : int , descr : Any , datadict : dict [str , Any ]) -> str | None :
1396- dsp = datadict .get ("firmware_version_dsp" )
1397- arm = datadict .get ("firmware_version_arm" )
1398- dsp_str = f"{ dsp // 100 } .{ dsp % 100 :02d} " if dsp is not None else "?.??"
1399- arm_str = f"{ arm // 100 } .{ arm % 100 :02d} " if arm is not None else "?.??"
1378+ def value_function_software_version_mic (initval : int , descr : Any , datadict : dict [str , Any ]) -> str | None :
1379+ """MIC firmware version. firmware_dsp / firmware_arm hold the full version ÷100 encoded.
1380+
1381+ GEN1 — 0x33D/0x33E GEN2 — 0x352/0x353 (+ 0x354 ARM boot, ÷100) GEN4 — 0x394/0x390
1382+ Example (X3-MIC/PRO-G2): 136 → "DSP 1.36 ARM 1.36-1.00", matching SolaX Cloud.
1383+ """
1384+ dsp = datadict .get ("firmware_dsp" ) or 0
1385+ arm = datadict .get ("firmware_arm" ) or 0
1386+ dsp_str = f"{ dsp // 100 } .{ dsp % 100 :02d} " if dsp else "?.??"
1387+ arm_str = f"{ arm // 100 } .{ arm % 100 :02d} " if arm else "?.??"
1388+ arm_boot = datadict .get ("firmware_arm_boot" )
1389+ if arm_boot is not None :
1390+ arm_str += f"-{ arm_boot // 100 } .{ arm_boot % 100 :02d} " # 0x354 is ÷100 encoded
14001391 return f"DSP { dsp_str } ARM { arm_str } "
14011392
14021393
1403- def value_function_software_version_protocol_aware (initval : int , descr : Any , datadict : dict [str , Any ]) -> str | None :
1404- # FirmwareVersionModbus 100 means V001.00; newer protocol versions can use the combined 0x7B/0x7C registers.
1405- if (
1406- value_function_modbus_protocol_version (datadict ) >= 100
1407- and datadict .get ("firmware_version_dsp" ) is not None
1408- and datadict .get ("firmware_version_arm" ) is not None
1409- ):
1410- return value_function_software_version_full (initval , descr , datadict )
1411- return value_function_software_version_g4 (initval , descr , datadict )
1394+ def value_function_software_version_hybrid_legacy (initval : int , descr : Any , datadict : dict [str , Any ]) -> str | None :
1395+ """AC/HYBRID with modbus protocol < 100: version is major.minor from split registers.
1396+
1397+ DSP = firmware_dsp_major (0x7F) . firmware_dsp_minor (0x7D)
1398+ ARM = firmware_arm_major (0x80) . firmware_arm_minor (0x83), boot suffix from
1399+ bootloader_version (0x84, raw minor) — e.g. "ARM 1.58-1.15" (SolaX Cloud).
1400+ """
1401+ dsp_maj = datadict .get ("firmware_dsp_major" )
1402+ dsp_min = datadict .get ("firmware_dsp_minor" )
1403+ arm_maj = datadict .get ("firmware_arm_major" )
1404+ arm_min = datadict .get ("firmware_arm_minor" )
1405+ dsp_str = f"{ dsp_maj } .{ dsp_min :02d} " if dsp_maj is not None and dsp_min is not None else "?.??"
1406+ arm_str = f"{ arm_maj } .{ arm_min :02d} " if arm_maj is not None and arm_min is not None else "?.??"
1407+ arm_boot = datadict .get ("bootloader_version" )
1408+ if arm_maj is not None and arm_boot is not None :
1409+ arm_str += f"-{ arm_maj } .{ arm_boot :02d} "
1410+ return f"DSP { dsp_str } ARM { arm_str } "
14121411
14131412
1414- def value_function_software_version_air_g3 (initval : int , descr : Any , datadict : dict [str , Any ]) -> str | None :
1415- return f"DSP v2. { datadict . get ( 'firmware_dsp' ) } ARM v1. { datadict . get ( 'firmware_arm' ) } "
1413+ def value_function_software_version_hybrid_full (initval : int , descr : Any , datadict : dict [str , Any ]) -> str | None :
1414+ """AC/HYBRID with modbus protocol >= 100: full version ÷100 from combined registers.
14161415
1416+ DSP = firmware_dsp (0x7B), ARM = firmware_arm (0x7C), both ÷100 encoded.
1417+ ARM boot suffix from firmware_arm_major (0x80) + bootloader_version (0x84, raw minor).
1418+ """
1419+ dsp = datadict .get ("firmware_dsp" )
1420+ arm = datadict .get ("firmware_arm" )
1421+ dsp_str = f"{ dsp // 100 } .{ dsp % 100 :02d} " if dsp else "?.??"
1422+ arm_str = f"{ arm // 100 } .{ arm % 100 :02d} " if arm else "?.??"
1423+ arm_maj = datadict .get ("firmware_arm_major" )
1424+ arm_boot = datadict .get ("bootloader_version" )
1425+ if arm_maj is not None and arm_boot is not None :
1426+ arm_str += f"-{ arm_maj } .{ arm_boot :02d} "
1427+ return f"DSP { dsp_str } ARM { arm_str } "
14171428
1418- def value_function_software_version_air_g4 (initval : int , descr : Any , datadict : dict [str , Any ]) -> str | None :
1419- return f"DSP { datadict .get ('firmware_dsp' )} ARM { datadict .get ('firmware_arm' )} "
1429+
1430+ def value_function_software_version (initval : int , descr : Any , datadict : dict [str , Any ]) -> str | None :
1431+ """AC/HYBRID dispatcher: pick the full or legacy formatter by modbus protocol version.
1432+
1433+ Protocol >= 100 exposes the combined full-version registers (0x7B/0x7C); older
1434+ firmware only has the split major/minor registers.
1435+ """
1436+ proto = datadict .get ("modbus_protocol_version" ) or 0
1437+ if proto >= 100 and datadict .get ("firmware_dsp" ) is not None :
1438+ return value_function_software_version_hybrid_full (initval , descr , datadict )
1439+ return value_function_software_version_hybrid_legacy (initval , descr , datadict )
14201440
14211441
14221442def value_function_battery_voltage_cell_difference (initval : int , descr : Any , datadict : dict [str , Any ]) -> int | float :
@@ -3877,21 +3897,21 @@ def value_function_battery_voltage_cell_difference(initval: int, descr: Any, dat
38773897 icon = "mdi:solar-power-variant" ,
38783898 ),
38793899 SolaXModbusSensorEntityDescription (
3880- key = "firmware_version_dsp " ,
3900+ key = "firmware_dsp " ,
38813901 register = 0x7B ,
38823902 allowedtypes = AC | HYBRID | GEN4 | GEN5 | GEN6 ,
38833903 modbus_min = 100 ,
38843904 internal = True ,
38853905 ),
38863906 SolaXModbusSensorEntityDescription (
3887- key = "firmware_version_arm " ,
3907+ key = "firmware_arm " ,
38883908 register = 0x7C ,
38893909 allowedtypes = AC | HYBRID | GEN4 | GEN5 | GEN6 ,
38903910 modbus_min = 100 ,
38913911 internal = True ,
38923912 ),
38933913 SolaXModbusSensorEntityDescription (
3894- key = "firmware_dsp " ,
3914+ key = "firmware_dsp_minor " ,
38953915 register = 0x7D ,
38963916 allowedtypes = AC | HYBRID ,
38973917 internal = True ,
@@ -3925,7 +3945,7 @@ def value_function_battery_voltage_cell_difference(initval: int, descr: Any, dat
39253945 icon = "mdi:information" ,
39263946 ),
39273947 SolaXModbusSensorEntityDescription (
3928- key = "firmware_arm " ,
3948+ key = "firmware_arm_minor " ,
39293949 register = 0x83 ,
39303950 allowedtypes = AC | HYBRID ,
39313951 internal = True ,
@@ -9323,7 +9343,7 @@ def value_function_battery_voltage_cell_difference(initval: int, descr: Any, dat
93239343 SolaXModbusSensorEntityDescription (
93249344 name = "Software Version" ,
93259345 key = "software_version" ,
9326- value_function = value_function_software_version_protocol_aware ,
9346+ value_function = value_function_software_version ,
93279347 allowedtypes = AC | HYBRID | GEN4 | GEN5 | GEN6 ,
93289348 entity_category = EntityCategory .DIAGNOSTIC ,
93299349 icon = "mdi:information" ,
@@ -9430,6 +9450,12 @@ def value_function_battery_voltage_cell_difference(initval: int, descr: Any, dat
94309450 allowedtypes = MIC | GEN2 ,
94319451 internal = True ,
94329452 ),
9453+ SolaXModbusSensorEntityDescription (
9454+ key = "firmware_arm_boot" ,
9455+ register = 0x354 ,
9456+ allowedtypes = MIC | GEN2 ,
9457+ internal = True ,
9458+ ),
94339459 SolaXModbusSensorEntityDescription (
94349460 key = "lock_state" ,
94359461 register = 0x367 ,
@@ -10781,38 +10807,14 @@ def value_function_battery_voltage_cell_difference(initval: int, descr: Any, dat
1078110807 SolaXModbusSensorEntityDescription (
1078210808 name = "Software Version" ,
1078310809 key = "software_version" ,
10784- value_function = value_function_software_version_air_g3 ,
10785- allowedtypes = MIC | GEN2 | X1 ,
10786- entity_category = EntityCategory .DIAGNOSTIC ,
10787- icon = "mdi:information" ,
10788- ),
10789- SolaXModbusSensorEntityDescription (
10790- name = "Software Version" ,
10791- key = "software_version" ,
10792- value_function = value_function_software_version_air_g4 ,
10793- allowedtypes = MIC | GEN4 | X1 ,
10794- entity_category = EntityCategory .DIAGNOSTIC ,
10795- icon = "mdi:information" ,
10796- ),
10797- SolaXModbusSensorEntityDescription (
10798- name = "Software Version" ,
10799- key = "software_version" ,
10800- value_function = value_function_software_version_air_g4 ,
10801- allowedtypes = MIC | GEN | X3 ,
10810+ value_function = value_function_software_version_mic ,
10811+ allowedtypes = MIC ,
1080210812 blacklist = [
1080310813 "MU802T" ,
1080410814 ],
1080510815 entity_category = EntityCategory .DIAGNOSTIC ,
1080610816 icon = "mdi:information" ,
1080710817 ),
10808- SolaXModbusSensorEntityDescription (
10809- name = "Software Version" ,
10810- key = "software_version" ,
10811- value_function = value_function_software_version_g2 ,
10812- allowedtypes = MIC | GEN2 | X3 ,
10813- entity_category = EntityCategory .DIAGNOSTIC ,
10814- icon = "mdi:information" ,
10815- ),
1081610818]
1081710819
1081810820TIME_TYPES = [
@@ -11673,8 +11675,8 @@ async def async_determineInverterType(self, hub: Any, configdict: dict[str, Any]
1167311675 hub .data ["hardware_version" ] = value_function_hardware_version_g5 (0 , None , hub .data )
1167411676 elif invertertype & GEN6 :
1167511677 hub .data ["hardware_version" ] = value_function_hardware_version_g6 (0 , None , hub .data )
11676- if "firmware_dsp" in hub .data or "firmware_version_dsp " in hub .data :
11677- hub .data ["software_version" ] = value_function_software_version_protocol_aware (0 , None , hub .data )
11678+ if "firmware_dsp" in hub .data or "firmware_dsp_minor " in hub .data :
11679+ hub .data ["software_version" ] = value_function_software_version (0 , None , hub .data )
1167811680
1167911681 read_eps = configdict .get (CONF_READ_EPS , DEFAULT_READ_EPS )
1168011682 read_dcb = configdict .get (CONF_READ_DCB , DEFAULT_READ_DCB )
0 commit comments