2026-04-24 16:34:10 -04:00
""" powermon / protocols / pi18.py """
import logging
from powermon . commands . command import CommandType
from powermon . commands . command_definition import CommandDefinition
from powermon . commands . reading_definition import ReadingType , ResponseType
from powermon . commands . result import ResultType
from powermon . libs . errors import CommandDefinitionMissing , InvalidCRC , InvalidResponse
from powermon . ports import PortType
from powermon . protocols . abstractprotocol import AbstractProtocol
from powermon . protocols . helpers import crc_pi30 as crc
from powermon . protocols . pi30 import BATTERY_TYPE_LIST , OUTPUT_MODE_LIST
log = logging . getLogger ( " pi18 " )
SETTER_COMMANDS = {
" POP " : {
" name " : " POP " ,
" command_type " : CommandType . PI18_SETTER ,
" description " : " Set Device Output Source Priority " ,
" help " : " -- examples: POP0 (set utility first), POP01 (set solar first) " ,
" regex " : " POP([01])$ " ,
} ,
" PSP " : {
" name " : " PSP " ,
" command_type " : CommandType . PI18_SETTER ,
" description " : " Set Solar Power priority " ,
" help " : " -- examples: PSP0 (Battery-Load-Utility +AC Charge), PSP1 (Load-Battery-Utility) " ,
" regex " : " PSP([01])$ " ,
} ,
" PEI " : {
" name " : " PEI " ,
" command_type " : CommandType . PI18_SETTER ,
" description " : " Set Machine type, enable: Grid-Tie " ,
" help " : " -- examples: PEI (enable Grid-Tie) " ,
} ,
" PDI " : {
" name " : " PDI " ,
" command_type " : CommandType . PI18_SETTER ,
" description " : " Set Machine type, disable: Grid-Tie " ,
" help " : " -- examples: PDI (disable Grid-Tie) " ,
} ,
" PCP " : {
" name " : " PCP " ,
" command_type " : CommandType . PI18_SETTER ,
" description " : " Set Device Charger Priority " ,
" help " : " -- examples: PCP0,1 (set unit 0 [0-9] to Solar and Utility) PCP0,0 (set unit 0 to Solar first), PCP0,1 (set unit 0 to Solar and Utility), PCP0,2 (set unit 0 to solar only charging) " ,
" regex " : " PCP([0-9],[012])$ " ,
} ,
" MCHGC " : {
" name " : " MCHGC " ,
" command_type " : CommandType . PI18_SETTER ,
" description " : " Set Battery Max Charging Current Solar + AC " ,
" help " : " -- examples: MCHGC0,040 (set unit 0 to max charging current of 40A), MCHGC1,060 (set unit 1 to max charging current of 60A) [010 020 030 040 050 060 070 080] " ,
" regex " : " MCHGC([0-9],0[1-8]0)$ " ,
} ,
" MUCHGC " : {
" name " : " MUCHGC " ,
" command_type " : CommandType . PI18_SETTER ,
" description " : " Set Battery Max AC Charging Current " ,
" help " : " -- examples: MUCHGC0,040 (set unit 0 to max charging current of 40A), MUCHGC1,060 (set unit 1 to max charging current of 60A) [002 010 020 030 040 050 060 070 080] " ,
" regex " : " MUCHGC([0-9]),(002|0[1-8]0)$ " ,
} ,
" PBT " : {
" name " : " PBT " ,
" command_type " : CommandType . PI18_SETTER ,
" description " : " Set Battery Type " ,
" help " : " -- examples: PBT0 (set battery as AGM), PBT1 (set battery as FLOODED), PBT2 (set battery as USER) " ,
" regex " : " PBT([012])$ " ,
} ,
" MCHGV " : {
" name " : " MCHGV " ,
" command_type " : CommandType . PI18_SETTER ,
" description " : " Set Battery Bulk,Float Charging Voltages " ,
" help " : " -- example MCHGV552,540 - set battery charging voltage Bulk to 52.2V, float 54V (set Bulk Voltage [480~584] in 0.1V xxx, Float Voltage [480~584] in 0.1V yyy) " ,
# Regex 48.0 - 58.4 Volt
" regex " : " MCHGV(4[8-9][0-9]|5[0-7][0-9]|58[0-5]),(4[8-9][0-9]|5[0-7][0-9]|58[0-4])$ " ,
} ,
" PSDV " : {
" name " : " PSDV " ,
" command_type " : CommandType . PI18_SETTER ,
" description " : " Set Battery Cut-off Voltage " ,
" help " : " -- example PSDV400 - set battery cut-off voltage to 40V [400~480V] for 48V unit) " ,
# Regex 40 to 48V
" regex " : " PSDV(4[0-7][0-9]|480)$ " ,
} ,
" BUCD " : {
" name " : " BUCD " ,
" command_type " : CommandType . PI18_SETTER ,
" description " : " Set Battery Stop dis,charging when Grid is available " ,
" help " : " -- example BUCD440,480 - set Stop discharge Voltage [440~510] in 0.1V xxx, Stop Charge Voltage [000(Full) or 480~580] in 0.1V yyy " ,
# Regex 44 to 51V, Full|48V to 58V
" regex " : " BUCD((4[4-9]0|5[0-1]0),(000|4[8-9]0|5[0-8]0))$ " ,
} ,
}
QUERY_COMMANDS = {
" PI " : {
" name " : " PI " ,
" command_type " : CommandType . PI18_QUERY ,
" description " : " Protocol ID inquiry " ,
" help " : " -- queries the protocol ID " ,
" result_type " : ResultType . SINGLE ,
" reading_definitions " : [
{ " description " : " Protocol ID " } ,
] ,
" test_responses " : [
b " ^D00518m \xae \r "
]
} ,
" ID " : {
" name " : " ID " ,
" aliases " : [ " default " , " get_id " ] ,
" command_type " : CommandType . PI18_QUERY ,
" description " : " Device Serial Number inquiry " ,
" help " : " -- queries the device serial number " ,
" result_type " : ResultType . SINGLE ,
" reading_definitions " : [ { " description " : " Serial Number " } ] ,
" test_responses " : [
b " ^D02514012345678901234567 \r " ,
] ,
} ,
" ET " : {
" name " : " ET " ,
" command_type " : CommandType . PI18_QUERY ,
" description " : " Total PV Generated Energy Inquiry " ,
" result_type " : ResultType . SINGLE ,
" reading_definitions " : [
{ " description " : " Total PV Generated Energy " , " reading_type " : ReadingType . WATT_HOURS ,
" response_type " : ResponseType . INT , " icon " : " mdi:solar-power " , " device_class " : " energy " , " state_class " : " total " } ,
] ,
" test_responses " : [
b " "
] ,
} ,
" EY " : {
" name " : " EY " ,
" command_type " : CommandType . PI18_QUERY ,
" description " : " Yearly PV Generated Energy Inquiry " ,
" result_type " : ResultType . SINGLE ,
" reading_definitions " : [
{ " description " : " PV Generated Energy for Year " , " reading_type " : ReadingType . WATT_HOURS ,
" response_type " : ResponseType . INT , " icon " : " mdi:counter " , " device_class " : " energy " , " state_class " : " total " } ,
{ " description " : " Year " , " reading_type " : ReadingType . YEAR ,
" response_type " : ResponseType . INFO_FROM_COMMAND , " format_template " : " int(cn[3:]) " } ,
] ,
" test_responses " : [
b " ^D01105580051 \x0b \x9f \r " ,
] ,
" regex " : " EY( \\ d \\ d \\ d \\ d)$ " ,
} ,
" EM " : {
" name " : " EM " ,
" command_type " : CommandType . PI18_QUERY ,
" description " : " Monthly PV Generated Energy Inquiry " ,
" result_type " : ResultType . SINGLE ,
" reading_definitions " : [
{ " description " : " PV Generated Energy for Month " , " reading_type " : ReadingType . WATT_HOURS ,
" response_type " : ResponseType . INT , " icon " : " mdi:solar-power " , " device_class " : " energy " , " state_class " : " total " } ,
{ " description " : " Year " , " reading_type " : ReadingType . YEAR ,
" response_type " : ResponseType . INFO_FROM_COMMAND , " format_template " : " int(cn[3:7]) " } ,
{ " description " : " Month " , " reading_type " : ReadingType . MONTH ,
" response_type " : ResponseType . INFO_FROM_COMMAND , " format_template " : " calendar.month_name[int(cn[7:])] " } ,
] ,
" test_responses " : [
b " " ,
] ,
" regex " : " EM( \\ d \\ d \\ d \\ d \\ d \\ d)$ " ,
} ,
" ED " : {
" name " : " ED " ,
" command_type " : CommandType . PI18_QUERY ,
" description " : " Daily PV Generated Energy Inquiry " ,
" help " : " -- display daily generated energy, format is QEDyyyymmdd " ,
" result_type " : ResultType . SINGLE ,
" reading_definitions " : [
{ " description " : " PV Generated Energy for Day " , " reading_type " : ReadingType . WATT_HOURS ,
" response_type " : ResponseType . INT , " icon " : " mdi:solar-power " , " device_class " : " energy " , " state_class " : " total " } ,
{ " description " : " Year " , " reading_type " : ReadingType . YEAR ,
" response_type " : ResponseType . INFO_FROM_COMMAND , " format_template " : " int(cn[3:7]) " } ,
{ " description " : " Month " , " reading_type " : ReadingType . MONTH ,
" response_type " : ResponseType . INFO_FROM_COMMAND , " format_template " : " calendar.month_name[int(cn[7:9])] " } ,
{ " description " : " Day " , " reading_type " : ReadingType . DAY ,
" response_type " : ResponseType . INFO_FROM_COMMAND , " format_template " : " int(cn[9:11]) " } ,
] ,
" test_responses " : [
b " (00238800!J \r " ,
] ,
" regex " : " ED( \\ d \\ d \\ d \\ d \\ d \\ d \\ d \\ d)$ " ,
} ,
" PIRI " : {
" name " : " PIRI " ,
" command_type " : CommandType . PI18_QUERY ,
" description " : " Current Settings inquiry " ,
" help " : " -- queries the current settings from the Inverter " ,
" result_type " : ResultType . COMMA_DELIMITED ,
" reading_definitions " : [
{ " description " : " AC Input Voltage " , " reading_type " : ReadingType . VOLTS ,
" response_type " : ResponseType . TEMPLATE_INT , " format_template " : " r/10 " } ,
{ " description " : " AC Input Current " , " reading_type " : ReadingType . CURRENT ,
" response_type " : ResponseType . TEMPLATE_INT , " format_template " : " r/10 " } ,
{ " description " : " AC Output Voltage " , " reading_type " : ReadingType . VOLTS ,
" response_type " : ResponseType . TEMPLATE_INT , " format_template " : " r/10 " } ,
{ " description " : " AC Output Frequency " , " reading_type " : ReadingType . FREQUENCY ,
" response_type " : ResponseType . TEMPLATE_INT , " format_template " : " r/10 " } ,
{ " description " : " AC Output Current " , " reading_type " : ReadingType . CURRENT ,
" response_type " : ResponseType . TEMPLATE_INT , " format_template " : " r/10 " } ,
{ " description " : " AC Output Apparent Power " , " reading_type " : ReadingType . APPARENT_POWER } ,
{ " description " : " AC Output Active Power " , " reading_type " : ReadingType . WATTS } ,
{ " description " : " Battery Voltage " , " reading_type " : ReadingType . VOLTS ,
" response_type " : ResponseType . TEMPLATE_INT , " format_template " : " r/10 " } ,
{ " description " : " Battery re-charge Voltage " , " reading_type " : ReadingType . VOLTS ,
" response_type " : ResponseType . TEMPLATE_INT , " format_template " : " r/10 " } ,
{ " description " : " Battery re-discharge Voltage " , " reading_type " : ReadingType . VOLTS ,
" response_type " : ResponseType . TEMPLATE_INT , " format_template " : " r/10 " } ,
{ " description " : " Battery Under Voltage " , " reading_type " : ReadingType . VOLTS , " response_type " : ResponseType . TEMPLATE_INT , " format_template " : " r/10 " } ,
{ " description " : " Battery Bulk Charge Voltage " , " reading_type " : ReadingType . VOLTS , " response_type " : ResponseType . TEMPLATE_INT , " format_template " : " r/10 " } ,
{ " description " : " Battery Float Charge Voltage " , " reading_type " : ReadingType . VOLTS , " response_type " : ResponseType . TEMPLATE_INT , " format_template " : " r/10 " } ,
{ " description " : " Battery Type " , " reading_type " : ReadingType . MESSAGE , " response_type " : ResponseType . LIST , " options " : BATTERY_TYPE_LIST } ,
{ " description " : " Max AC Charging Current " , " reading_type " : ReadingType . CURRENT } ,
{ " description " : " Max Charging Current " , " reading_type " : ReadingType . CURRENT } ,
{ " description " : " Input Voltage Range " , " response_type " : ResponseType . LIST , " options " : [ " Appliance " , " UPS " ] } ,
{ " description " : " Output Source Priority " ,
" response_type " : ResponseType . LIST , " options " : [ " Solar - Utility - Battery " , " Solar - Battery - Utility " ] } ,
{ " description " : " Charger Source Priority " ,
" response_type " : ResponseType . LIST , " options " : [ " Solar First " , " Solar + Utility " , " Only solar charging permitted " ] } ,
{ " description " : " Max Parallel Units " } ,
{ " description " : " Machine Type " , " response_type " : ResponseType . LIST , " options " : [ " Off Grid " , " Grid Tie " ] } ,
{ " description " : " Topology " , " response_type " : ResponseType . LIST , " options " : [ " transformerless " , " transformer " ] } ,
{ " description " : " Output Mode " , " reading_type " : ReadingType . MESSAGE , " response_type " : ResponseType . LIST , " options " : OUTPUT_MODE_LIST } ,
{ " description " : " Solar power priority " , " response_type " : ResponseType . LIST , " options " : [ " Battery-Load-Utiliy + AC Charger " , " Load-Battery-Utiliy " ] } ,
{ " description " : " MPPT strings " } ,
{ " description " : " Unknown flags? " , " response_type " : ResponseType . STRING } ,
] ,
" test_responses " : [
b " ^D0882300,217,2300,500,217,5000,5000,480,480,530,440,570,570,2,10,070,1,1,1,9,0,0,0,0,1,00 \xe1 k \r " ,
]
} ,
" GS " : {
" name " : " GS " ,
" command_type " : CommandType . PI18_QUERY ,
" description " : " General Status Parameters inquiry " ,
" result_type " : ResultType . COMMA_DELIMITED ,
" reading_definitions " : [
{ " description " : " AC Input Voltage " , " reading_type " : ReadingType . VOLTS ,
" response_type " : ResponseType . TEMPLATE_INT , " format_template " : " r/10 " , " icon " : " mdi:transmission-tower-export " , " device_class " : " voltage " } ,
{ " description " : " AC Input Frequency " , " reading_type " : ReadingType . FREQUENCY ,
" response_type " : ResponseType . TEMPLATE_INT , " format_template " : " r/10 " , " icon " : " mdi:current-ac " , " device_class " : " frequency " } ,
{ " description " : " AC Output Voltage " , " reading_type " : ReadingType . VOLTS ,
" response_type " : ResponseType . TEMPLATE_INT , " format_template " : " r/10 " , " icon " : " mdi:transmission-tower-export " , " device_class " : " voltage " } ,
{ " description " : " AC Output Frequency " , " reading_type " : ReadingType . FREQUENCY ,
" response_type " : ResponseType . TEMPLATE_INT , " format_template " : " r/10 " , " icon " : " mdi:current-ac " , " device_class " : " frequency " } ,
{ " description " : " AC Output Apparent Power " , " reading_type " : ReadingType . APPARENT_POWER ,
" response_type " : ResponseType . INT , " icon " : " mdi:power-plug " , " device_class " : " apparent_power " } ,
{ " description " : " AC Output Active Power " , " reading_type " : ReadingType . WATTS ,
" response_type " : ResponseType . INT , " icon " : " mdi:power-plug " , " device_class " : " power " , " state_class " : " measurement " } ,
{ " description " : " AC Output Load " , " reading_type " : ReadingType . PERCENTAGE ,
" response_type " : ResponseType . INT , " icon " : " mdi:brightness-percent " } ,
{ " description " : " Battery Voltage " , " reading_type " : ReadingType . VOLTS ,
" response_type " : ResponseType . TEMPLATE_INT , " format_template " : " r/10 " , " icon " : " mdi:battery-outline " , " device_class " : " voltage " } ,
{ " description " : " Battery Voltage from SCC " , " reading_type " : ReadingType . VOLTS ,
" response_type " : ResponseType . TEMPLATE_INT , " format_template " : " r/10 " , " icon " : " mdi:battery-outline " , " device_class " : " voltage " } ,
{ " description " : " Battery Voltage from SCC2 " , " reading_type " : ReadingType . VOLTS ,
" response_type " : ResponseType . TEMPLATE_INT , " format_template " : " r/10 " , " icon " : " mdi:battery-outline " , " device_class " : " voltage " } ,
{ " description " : " Battery Discharge Current " , " reading_type " : ReadingType . CURRENT ,
" response_type " : ResponseType . INT , " icon " : " mdi:battery-negative " , " device_class " : " current " } ,
{ " description " : " Battery Charging Current " , " reading_type " : ReadingType . CURRENT ,
" response_type " : ResponseType . INT , " icon " : " mdi:current-dc " , " device_class " : " current " } ,
{ " description " : " Battery Capacity " , " reading_type " : ReadingType . PERCENTAGE ,
" response_type " : ResponseType . INT , " icon " : " mdi:brightness-percent " , " device_class " : " battery " } ,
{ " description " : " Inverter heat sink temperature " , " reading_type " : ReadingType . TEMPERATURE ,
" response_type " : ResponseType . INT , " icon " : " mdi:details " , " device_class " : " temperature " } ,
{ " description " : " MPPT1 charger temperature " , " reading_type " : ReadingType . TEMPERATURE ,
" response_type " : ResponseType . INT , " icon " : " mdi:details " , " device_class " : " temperature " } ,
{ " description " : " MPPT2 charger temperature " , " reading_type " : ReadingType . TEMPERATURE ,
" response_type " : ResponseType . INT , " icon " : " mdi:details " , " device_class " : " temperature " } ,
{ " description " : " MPPT1 Input Power " , " reading_type " : ReadingType . WATTS ,
" response_type " : ResponseType . INT , " icon " : " mdi:solar-power " , " device_class " : " power " , " state_class " : " measurement " } ,
{ " description " : " MPPT2 Input Power " , " reading_type " : ReadingType . WATTS ,
" response_type " : ResponseType . INT , " icon " : " mdi:solar-power " , " device_class " : " power " , " state_class " : " measurement " } ,
{ " description " : " MPPT1 Input Voltage " , " reading_type " : ReadingType . VOLTS ,
" response_type " : ResponseType . TEMPLATE_INT , " format_template " : " r/10 " , " icon " : " mdi:solar-power " , " device_class " : " voltage " } ,
{ " description " : " MPPT2 Input Voltage " , " reading_type " : ReadingType . VOLTS ,
" response_type " : ResponseType . TEMPLATE_INT , " format_template " : " r/10 " , " icon " : " mdi:solar-power " , " device_class " : " voltage " } ,
{ " description " : " Setting value configuration state " , " reading_type " : ReadingType . MESSAGE ,
" response_type " : ResponseType . OPTION ,
" options " : {
" 0 " : " Nothing changed " ,
" 1 " : " Something changed " ,
} ,
} ,
{ " description " : " MPPT1 charger status " , " reading_type " : ReadingType . MESSAGE ,
" response_type " : ResponseType . OPTION ,
" options " : {
" 0 " : " abnormal " ,
" 1 " : " normal but not charged " ,
" 2 " : " charging " ,
} ,
} ,
{ " description " : " MPPT2 charger status " , " reading_type " : ReadingType . MESSAGE ,
" response_type " : ResponseType . OPTION ,
" options " : {
" 0 " : " abnormal " ,
" 1 " : " normal but not charged " ,
" 2 " : " charging " ,
} ,
} ,
{ " description " : " Load connection " , " reading_type " : ReadingType . MESSAGE ,
" response_type " : ResponseType . OPTION ,
" options " : {
" 0 " : " disconnect " ,
" 1 " : " connect " ,
} ,
} ,
{ " description " : " Battery power direction " , " reading_type " : ReadingType . MESSAGE ,
" response_type " : ResponseType . OPTION ,
" options " : {
" 0 " : " donothing " ,
" 1 " : " charge " ,
" 2 " : " discharge " ,
} ,
} ,
2026-04-26 08:49:05 -04:00
{ " description " : " DC AC power direction " , " reading_type " : ReadingType . MESSAGE ,
2026-04-24 16:34:10 -04:00
" response_type " : ResponseType . OPTION ,
" options " : {
" 0 " : " donothing " ,
" 1 " : " AC-DC " ,
" 2 " : " DC-AC " ,
} ,
} ,
{ " description " : " Line power direction " , " reading_type " : ReadingType . MESSAGE ,
" response_type " : ResponseType . OPTION ,
" options " : {
" 0 " : " donothing " ,
" 1 " : " input " ,
" 2 " : " output " ,
} ,
} ,
{ " description " : " Parallel instance number " , " reading_type " : ReadingType . MESSAGE ,
" response_type " : ResponseType . LIST ,
" options " : [ " Not valid " , " valid " ] ,
} ,
] ,
" test_responses " : [
b " D1062232,499,2232,499,0971,0710,019,008,000,000,000,000,000,044,000,000,0520,0000,1941,0000,0,2,0,1,0,2,1,0 \x09 \x7b \r " ,
b " ^D1062232,499,2232,499,1406,1376,028,549,000,000,000,010,095,060,000,000,0082,0000,1604,0000,0,2,0,1,1,1,1,0D \x12 \r " ,
] ,
} ,
" MOD " : {
" name " : " MOD " ,
" command_type " : CommandType . PI18_QUERY ,
" description " : " Mode inquiry " ,
" result_type " : ResultType . SINGLE ,
" reading_definitions " : [
{ " description " : " Device Mode " , " reading_type " : ReadingType . MESSAGE ,
" response_type " : ResponseType . OPTION ,
" options " : {
" 00 " : " Power on " ,
" 01 " : " Standby " ,
" 02 " : " Bypass " ,
" 03 " : " Battery " ,
" 04 " : " Fault " ,
" 05 " : " Hybrid mode(Line mode, Grid mode) " ,
}
} ,
] ,
" test_responses " : [
b " ^D00505 \xd9 \x9f \r " ,
] ,
} ,
" MCHGCR " : {
" name " : " MCHGCR " ,
" command_type " : CommandType . PI18_QUERY ,
" description " : " Max Charging Current Options inquiry " ,
" help " : " -- queries the maximum charging current setting of the Inverter " ,
" result_type " : ResultType . MULTIVALUED ,
" reading_definitions " : [
{ " description " : " Max Charging Current Options " , " reading_type " : ReadingType . MESSAGE_AMPS ,
" response_type " : ResponseType . STRING
}
] ,
" test_responses " : [
b " ^D034010,020,030,040,050,060,070,080 \x16 1 \r " ,
] ,
} ,
" MUCHGCR " : {
" name " : " MUCHGCR " ,
" command_type " : CommandType . PI18_QUERY ,
" description " : " Max Utility Charging Current Options inquiry " ,
" help " : " -- queries the maximum utility charging current setting of the Inverter " ,
" result_type " : ResultType . MULTIVALUED ,
" reading_definitions " : [
{ " reading_type " : ReadingType . MESSAGE_AMPS , " description " : " Max Utility Charging Current " , " response_type " : ResponseType . STRING }
] ,
" test_responses " : [
b " ^D038002,010,020,030,040,050,060,070,080 \xd0 1 \r "
] ,
} ,
" FLAG " : {
" name " : " FLAG " ,
" command_type " : CommandType . PI18_QUERY ,
" description " : " Query enable/disable flag status " ,
" result_type " : ResultType . COMMA_DELIMITED ,
" reading_definitions " : [
{ " description " : " Buzzer beep " , " reading_type " : ReadingType . MESSAGE , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Overload bypass function " , " reading_type " : ReadingType . MESSAGE , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Display back to default page " , " reading_type " : ReadingType . MESSAGE , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Overload restart " , " reading_type " : ReadingType . MESSAGE , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Over temperature restart " , " reading_type " : ReadingType . MESSAGE , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Backlight on " , " reading_type " : ReadingType . MESSAGE , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Alarm primary source interrupt " , " reading_type " : ReadingType . MESSAGE , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Fault code record " , " reading_type " : ReadingType . MESSAGE , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Reserved " , " reading_type " : ReadingType . MESSAGE } ,
] ,
" test_responses " : [
b " ^D0200,0,0,0,0,1,0,0,12 \xc2 \x39 \r " ,
] ,
} ,
" VFW " : {
" name " : " VFW " ,
" description " : " Device CPU version inquiry " ,
" command_type " : CommandType . PI18_QUERY ,
" result_type " : ResultType . COMMA_DELIMITED ,
" reading_definitions " : [
{ " description " : " Main CPU Version " , " reading_type " : ReadingType . MESSAGE } ,
{ " description " : " Slave 1 CPU Version " , " reading_type " : ReadingType . MESSAGE } ,
{ " description " : " Slave 2 CPU Version " , " reading_type " : ReadingType . MESSAGE } ,
] ,
" test_responses " : [
b " ^D02005220,00000,00000 \x3e \xf8 \r " ,
] ,
} ,
# Fault + warning bitmap. 2-digit fault code followed by ~32 0/1 warning bits.
# Fault-code list cross-referenced with PI30 QPGS (same firmware family).
" FWS " : {
" name " : " FWS " ,
" description " : " Fault and warning status inquiry " ,
" command_type " : CommandType . PI18_QUERY ,
" result_type " : ResultType . COMMA_DELIMITED ,
" reading_definitions " : [
{ " description " : " Fault code " , " reading_type " : ReadingType . MESSAGE ,
" response_type " : ResponseType . OPTION ,
" options " : {
" 00 " : " No fault " ,
" 01 " : " Fan is locked " ,
" 02 " : " Over temperature " ,
" 03 " : " Battery voltage is too high " ,
" 04 " : " Battery voltage is too low " ,
" 05 " : " Output short circuited or Over temperature " ,
" 06 " : " Output voltage is too high " ,
" 07 " : " Over load time out " ,
" 08 " : " Bus voltage is too high " ,
" 09 " : " Bus soft start failed " ,
" 11 " : " Main relay failed " ,
" 51 " : " Over current inverter " ,
" 52 " : " Bus soft start failed " ,
" 53 " : " Inverter soft start failed " ,
" 54 " : " Self-test failed " ,
" 55 " : " Over DC voltage on output of inverter " ,
" 56 " : " Battery connection is open " ,
" 57 " : " Current sensor failed " ,
" 58 " : " Output voltage is too low " ,
" 60 " : " Inverter negative power " ,
" 71 " : " Parallel version different " ,
" 72 " : " Output circuit failed " ,
" 80 " : " CAN communication failed " ,
" 81 " : " Parallel host line lost " ,
" 82 " : " Parallel synchronized signal lost " ,
" 83 " : " Parallel battery voltage detect different " ,
" 84 " : " Parallel Line voltage or frequency detect different " ,
" 85 " : " Parallel Line input current unbalanced " ,
" 86 " : " Parallel output setting different " ,
} } ,
{ " description " : " PV loss warning " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Inverter fault " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Bus over " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Bus under " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Bus soft fail " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Line fail " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " OPV short " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Inverter voltage too low " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Inverter voltage too high " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Over temperature " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Fan locked " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Battery voltage high " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Battery low alarm " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Battery under shutdown " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Battery derating " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Overload " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " EEPROM fault " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Inverter over current " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Inverter soft fail " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Self test fail " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " OP DC voltage over " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Battery open " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Current sensor fail " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Battery short " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Power limit " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " PV voltage high " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " MPPT overload fault " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " MPPT overload warning " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Battery too low to charge " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Battery weak " , " response_type " : ResponseType . ENABLED_BOOL } ,
{ " description " : " Battery equalization " , " response_type " : ResponseType . ENABLED_BOOL } ,
] ,
" test_responses " : [
b " ^D07100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 \xaa \xaa \r " ,
] ,
} ,
# Per-unit parallel view. PGS<n>, n = 0..N-1 (0 is master).
# LVX6048 emits a 30-field layout that differs from the PI30 QPGS layout;
# only fields confirmed against live responses are semantically named here.
# The rest are exposed as raw strings so the command doesn't error out, and
# can be tightened later as more firmware rev responses are confirmed.
# Observed unit-1 response (Not valid + fault 71 "Parallel version different"):
# 0,4,71,2453,599,0000,000,0000,0000,00000,00000,000,211,005,000,000,000,
# 000,0008,0000,2925,0000,1,0,0,0,0,0,016
" PGS " : {
" name " : " PGS " ,
" description " : " Parallel general status inquiry " ,
" help " : " -- example: PGS0 queries parallel status for instance 0 (master) " ,
" command_type " : CommandType . PI18_QUERY ,
" result_type " : ResultType . COMMA_DELIMITED ,
" reading_definitions " : [
{ " description " : " Parallel instance number " , " reading_type " : ReadingType . MESSAGE ,
" response_type " : ResponseType . LIST , " options " : [ " Not valid " , " valid " ] } ,
{ " description " : " Parallel unit count " , " reading_type " : ReadingType . MESSAGE } ,
{ " description " : " Fault code " , " reading_type " : ReadingType . MESSAGE } ,
{ " description " : " Field 4 (raw) " , " reading_type " : ReadingType . MESSAGE } ,
{ " description " : " Grid frequency " , " reading_type " : ReadingType . FREQUENCY ,
" response_type " : ResponseType . TEMPLATE_INT , " format_template " : " r/10 " , " device_class " : " frequency " } ,
{ " description " : " AC output voltage " , " reading_type " : ReadingType . VOLTS ,
" response_type " : ResponseType . TEMPLATE_INT , " format_template " : " r/10 " , " device_class " : " voltage " } ,
{ " description " : " AC output frequency (raw) " , " reading_type " : ReadingType . MESSAGE } ,
{ " description " : " AC output apparent power " , " reading_type " : ReadingType . APPARENT_POWER ,
" response_type " : ResponseType . INT , " device_class " : " apparent_power " } ,
{ " description " : " AC output active power " , " reading_type " : ReadingType . WATTS ,
" response_type " : ResponseType . INT , " device_class " : " power " } ,
{ " description " : " Total AC output apparent power " , " reading_type " : ReadingType . APPARENT_POWER , " response_type " : ResponseType . INT } ,
{ " description " : " Total AC output active power " , " reading_type " : ReadingType . WATTS , " response_type " : ResponseType . INT } ,
{ " description " : " Load percentage " , " reading_type " : ReadingType . PERCENTAGE , " response_type " : ResponseType . INT } ,
{ " description " : " Field 13 (raw) " , " reading_type " : ReadingType . MESSAGE } ,
{ " description " : " Field 14 (raw) " , " reading_type " : ReadingType . MESSAGE } ,
{ " description " : " Field 15 (raw) " , " reading_type " : ReadingType . MESSAGE } ,
{ " description " : " Field 16 (raw) " , " reading_type " : ReadingType . MESSAGE } ,
{ " description " : " Field 17 (raw) " , " reading_type " : ReadingType . MESSAGE } ,
{ " description " : " Field 18 (raw) " , " reading_type " : ReadingType . MESSAGE } ,
{ " description " : " Field 19 (raw) " , " reading_type " : ReadingType . MESSAGE } ,
{ " description " : " Field 20 (raw) " , " reading_type " : ReadingType . MESSAGE } ,
{ " description " : " Field 21 (raw) " , " reading_type " : ReadingType . MESSAGE } ,
{ " description " : " Field 22 (raw) " , " reading_type " : ReadingType . MESSAGE } ,
{ " description " : " Flag 23 (raw) " , " reading_type " : ReadingType . MESSAGE } ,
{ " description " : " Flag 24 (raw) " , " reading_type " : ReadingType . MESSAGE } ,
{ " description " : " Flag 25 (raw) " , " reading_type " : ReadingType . MESSAGE } ,
{ " description " : " Flag 26 (raw) " , " reading_type " : ReadingType . MESSAGE } ,
{ " description " : " Flag 27 (raw) " , " reading_type " : ReadingType . MESSAGE } ,
{ " description " : " Flag 28 (raw) " , " reading_type " : ReadingType . MESSAGE } ,
{ " description " : " Field 30 (raw) " , " reading_type " : ReadingType . MESSAGE } ,
] ,
" test_responses " : [
b " ^D1130,4,71,2453,599,0000,000,0000,0000,00000,00000,000,211,005,000,000,000,000,0008,0000,2925,0000,1,0,0,0,0,0,016 \x8f \xad \r " ,
] ,
" regex " : " PGS( \\ d+)$ " ,
} ,
}
COMMANDS_TO_REMOVE = [ ]
class PI18 ( AbstractProtocol ) :
""" pi18 protocol handler """
def __str__ ( self ) :
return " PI18 protocol handler "
def __init__ ( self ) - > None :
super ( ) . __init__ ( )
self . protocol_id = b " PI18 "
self . add_command_definitions ( QUERY_COMMANDS )
self . add_command_definitions ( SETTER_COMMANDS , result_type = ResultType . PI18_ACK )
self . remove_command_definitions ( COMMANDS_TO_REMOVE )
self . check_definitions_count ( expected = 26 ) # Count of all Commands
self . add_supported_ports ( [ PortType . SERIAL , PortType . USB ] )
def check_crc ( self , response : str , command_definition : CommandDefinition = None ) :
""" crc check, override for now """
log . debug ( " check crc for %s in pi18 " , response )
if response . startswith ( b " ^D " ) or response . startswith ( b " ^1 " ) or response . startswith ( b " ^0 " ) :
# get response CRC
data_to_check = response [ : - 3 ]
crc_high , crc_low = crc ( data_to_check )
# print(crc_high, crc_low)
# print(response[-3], response[-2])
if ( crc_high , crc_low ) == ( response [ - 3 ] , response [ - 2 ] ) :
return True
else :
log . info ( " PI18 response check_crc doesnt match calc ( %x , %x ), got ( %x , %x ) " , crc_high , crc_low , response [ - 3 ] , response [ - 2 ] )
raise InvalidCRC ( f " PI18 response check_crc doesnt match calc ( { crc_high : 02x } , { crc_low : 02x } ), got ( { response [ - 3 ] : 02x } , { response [ - 2 ] : 02x } ) " )
else :
log . info ( " PI18 response doesnt start with ^D - check_crc fails " )
raise InvalidResponse ( " PI18 response starts with invalid character - crc check fails " )
log . info ( " PI18 response check_crc fall through " )
return False
def trim_response ( self , response : str , command_definition : CommandDefinition = None ) - > str :
""" Remove extra characters from response """
log . debug ( " trim %s , definition: %s " , response , command_definition )
if response . startswith ( b " ^D " ) :
# trim ^Dxxx where xxx is data length
response = response [ 5 : ]
if response . endswith ( b ' \r ' ) :
# has checksum, so trim last 3 chars
response = response [ : - 3 ]
if response . startswith ( b ' ( ' ) :
# pi30 style response
response = response [ 1 : ]
# if response.startswith(b'^1') or response.startswith(b'^0'):
# # ACK / NACK response
# response = response[1:]
return response
def get_full_command ( self , command : str ) - > bytes :
""" generate the full command including prefix, crc and \n as needed """
log . info ( " Using protocol: %s with %i commands " , self . protocol_id , len ( self . command_definitions ) )
command_defn = self . get_command_definition ( command )
# raise exception if no command definition is found
if command_defn is None :
raise CommandDefinitionMissing ( f " No definition found in PI18 for { command } " )
# full command is ^PlllCCCcrc\n or ^SlllCCCcrc\n
# lll = length of all except ^Dlll
# CCC = command
# crc = 2 bytes
length = len ( command ) + 3
# Determine prefix
match command_defn . command_type :
case CommandType . PI18_QUERY :
prefix = " ^P "
case CommandType . PI18_SETTER :
prefix = " ^S "
case _ :
# edge case / default PI30 command / maybe this should raise an error
prefix = " ( "
full_command = bytes ( f " { prefix } { length : #03d } { command } " , " utf-8 " )
crc_high , crc_low = crc ( full_command )
full_command + = bytes ( [ crc_high , crc_low , 13 ] )
log . debug ( " full command: %s " , full_command )
return full_command