Files
shaggy-solar/eg4battery/bin/__pycache__/eg4-batterycpython-311.pyc

359 lines
64 KiB
Plaintext
Raw Normal View History

2026-06-23 18:49:47 -04:00
<EFBFBD>
S)0jo<6A><00><01><><00>UdZddlmZddlZddlZddlZddlZddlZddlZddl Z ddl
Z
ddl Z ddl m Z ddl mZddlmZmZddlmcmZddlZddlZejd<07><00>ZejGd<08>d <09><00><00><00>ZejGd
<EFBFBD>d <0B><00><00><00>ZejGd <0C>d <0A><00><00><00>ZejGd<0E>d<0F><00><00><00>Zd<>d<13>ZdZdZ dZ!d<>d<EFBFBD>d<1C>Z"d<>d <20>Z#d<>d!<21>Z$d<>d%<25>Z%hd&<26>Z&d<>d(<28>Z'ejGd)<29>d*<2A><00><00><00>Z(d<>d,<2C>Z)d<>d.<2E>Z*d<>d<EFBFBD>d3<64>Z+d<>d6<64>Z,Gd7<64>d8<64><00>Z-Gd9<64>d:<3A><00>Z.Gd;<3B>d<<3C><00>Z/Gd=<3D>d>e.<2E><00>Z0Gd?<3F>d@e.<2E><00>Z1GdA<64>dBe/<2F><00>Z2GdC<64>dDe/<2F><00>Z3dEdFdGdHdIdJdKdLdMdMdNdOdOdPdPdQ<64>Z4dRe5dS<e6ddT<64><00>D] Z7dEe4dUe7dV<64>dW<64><<00> e6ddX<64><00>D]
Z7dYe4dZe7<EFBFBD><00><<00> e4<65>8dFdYdYdYd[dMdMdNdMdHd\d]d^d_d`da<64><0F><00>d<>dd<64>Z9idedf<64>dgdf<64>dhd<01>did<01>djd<01>dkd<01>dld<01>dmdn<64>dodn<64>dpd<01>dqd<01>drd<01>dd<01>dsd<14>dtd<14>dud<01>dvd<14>Z:dwe5dx<e6ddy<64><00>D] Z7dne:dUe7dV<64>dW<64><<00> e6ddX<64><00>D]
Z7de:dZe7<65><00><<00> d<>d{<7B>Z;Gd|<7C>d}<7D><00>Z<ejGd~<7E>d<64><00><00><00>Z=d<>Z>e?d<>d<EFBFBD>d<EFBFBD>d<EFBFBD>d<EFBFBD>d<EFBFBD>d<EFBFBD>d<EFBFBD><64><EFBFBD><EFBFBD><00>Z@e@fd<>d<EFBFBD><64>ZAd<41>d<EFBFBD><64>ZB d<>d<EFBFBD>d<EFBFBD><64>ZC d<>d<EFBFBD>d<EFBFBD><64>ZD d<>d<EFBFBD>d<EFBFBD><64>ZEd<45>d<EFBFBD><64>ZFd<46>d<EFBFBD><64>ZGeHd<48>kre
jIeG<65><00><00><00>dSdS)<29>uq
eg4-battery — telemetry bridge from EG4 LifePower4 v2 BMSes to MQTT/HA.
Three modes, selected via `bus.mode` in the config:
modbus_per_pack — RECOMMENDED. One FTDI RS-485 adapter per pack. Each pack
has its own (port, address, baud) in the `packs:` list.
Uses Modbus RTU fn=0x03 read-47-regs at 0x0000. Decoder
extracts named fields (pack V, 16 cell voltages, temps,
SoC, SoH, Capacity, warnings, protections) — register
map reverse-engineered from the EG4 `lv_host.app` BMS
Tool's SQLite schema + UI labels.
active — LEGACY. Single FTDI adapter on a dedicated bus, EG4
7E/0D protocol at 9600 baud. Was ported from the V1
firmware via `battery/eg4_lifepower.py`; V2 hardware
doesn't speak this protocol in practice. Kept for
reference / possible V1 deployments.
passive — LEGACY. Listen-only Modbus-RTU sniffer at 19200 baud.
Originally targeted the LVX6048 BMS bus; LVX6048 doesn't
poll EG4 packs that way, so the mode is diagnostic only.
Usage:
eg4-battery -C <config.yaml>
eg4-battery -C <config.yaml> --dry-run # mock bus, print, exit
eg4-battery -C <config.yaml> --trace # log every frame
<EFBFBD>)<01> annotationsN)<01>Path<74><01> unpack_from)<02>Any<6E>Iterator<6F> eg4-batteryc<01>@<00>eZdZUded<ded<dZded<dZded <dS)
<EFBFBD>
PackConfig<EFBFBD>str<74>name<6D>int<6E>addressNz
str | None<6E>port<72>
int | None<6E>baud)<06>__name__<5F>
__module__<EFBFBD> __qualname__<5F>__annotations__rr<00><00><00>eg4battery/bin/eg4-batteryr r AsF<00><00><00><00><00><00><00> <0A>I<EFBFBD>I<EFBFBD>I<EFBFBD><10>L<EFBFBD>L<EFBFBD>L<EFBFBD><1B>D<EFBFBD><1B><1B><1B><1B><1B>D<EFBFBD><1B><1B><1B><1B><1B>rr c<01>n<00>eZdZUded<dZded<dZded<dZded <d
Zded <d Zd ed<dZ d ed<dS)<12> BusConfigr <00>mode<64>serial<61> transport<72>ri<>%rr<00><00>
read_chunkg<00>?<3F>float<61> timeout_s<5F>$@<40>poll_interval_sN)
rrrrrrrr!r#r%rrrrrIs}<00><00><00><00><00><00><00> <0A>I<EFBFBD>I<EFBFBD>I<EFBFBD><1D>I<EFBFBD><1D><1D><1D><1D><12>D<EFBFBD>N<EFBFBD>N<EFBFBD>N<EFBFBD>N<EFBFBD><14>D<EFBFBD><14><14><14><14><19>J<EFBFBD><19><19><19><19><1A>I<EFBFBD><1A><1A><1A><1A>!<21>O<EFBFBD>!<21>!<21>!<21>!<21>!<21>!rrc<01>T<00>eZdZUded<ded<ded<ded<dZded<d Zd
ed <d S) <0A>
MQTTConfigr <00>hostrr<00>username<6D>password<72> homeassistant<6E>discovery_prefixg <20>@r"<00>discovery_republish_interval_sN)rrrrr,r-rrrr'r'Ts\<00><00><00><00><00><00><00> <0A>I<EFBFBD>I<EFBFBD>I<EFBFBD> <0A>I<EFBFBD>I<EFBFBD>I<EFBFBD><11>M<EFBFBD>M<EFBFBD>M<EFBFBD><11>M<EFBFBD>M<EFBFBD>M<EFBFBD>+<2B><14>+<2B>+<2B>+<2B>+<2B>
-3<>"<22>2<>2<>2<>2<>2<>2rr'c<01>X<00>eZdZUded<ded<ded<dZded <d
Zd ed <d
Zd ed <dS)<0F> AppConfigr<00>busr'<00>mqtt<74>list[PackConfig]<5D>packs<6B>r<00>
cell_countF<EFBFBD>bool<6F>expose_raw_registers<72> soc_estimatorN)rrrrr5r7r8rrrr/r/bsg<00><00><00><00><00><00><00><12>N<EFBFBD>N<EFBFBD>N<EFBFBD><14><14><14><14><1B><1B><1B><1B><18>J<EFBFBD><18><18><18><18>!&<26><18>&<26>&<26>&<26>&<26><1F>M<EFBFBD><1F><1F><1F><1F><1F>rr/<00>pathr<00>returnc <01><><00>tj|<00><00><00><00><00>}ddl}t |d<00><00>}dD];\}}|j<00>|<05><00>}|<06>|dkrt|<06><00>n|||<<00><ttdi|d<00><01>tdi|<03><01>d<06>|dD<00><00>|<01>dd <09><00>|<01>d
d <0B><00>|<01>d d <0B><00><00> <0A><00>S)Nrr1))r(<00> MQTT_HOST)r<00> MQTT_PORT)r)<00> MQTT_USERNAME)r*<00> MQTT_PASSWORDrr0c<01>&<00>g|]}tdi|<01><01><01><02>S)r)r <00><02>.0<EFBFBD>ps r<00>
<listcomp>zload_config.<locals>.<listcomp><3E>s"<00><00>5<>5<>5<>1<EFBFBD>z<EFBFBD><EFBFBD><EFBFBD>A<EFBFBD><EFBFBD><EFBFBD>5<>5<>5rr3r5r4r7Fr8)r0r1r3r5r7r8r) <0B>yaml<6D> safe_load<61> read_text<78>os<6F>dict<63>environ<6F>getrr/rr')r9<00>rawrH<00>mqtt_raw<61>key<65>env_var<61>vs r<00> load_configrQls<00><00>
<0E>.<2E><14><1E><1E>)<29>)<29>
*<2A>
*<2A>C<EFBFBD>
<0E>I<EFBFBD>I<EFBFBD>I<EFBFBD><13>C<EFBFBD><06>K<EFBFBD> <20> <20>H<EFBFBD><06>;<3B>;<3B> <0C><03>W<EFBFBD> <0F>J<EFBFBD>N<EFBFBD>N<EFBFBD>7<EFBFBD> #<23> #<23><01> <0C>=<3D>&)<29>V<EFBFBD>m<EFBFBD>m<EFBFBD>C<EFBFBD><01>F<EFBFBD>F<EFBFBD>F<EFBFBD><11>H<EFBFBD>S<EFBFBD>M<EFBFBD><4D> <14> <15> #<23> #<23><03>E<EFBFBD>
<EFBFBD> #<23> #<23> <17> #<23> #<23>(<28> #<23> #<23>5<>5<><03>G<EFBFBD> <0C>5<>5<>5<><16>7<EFBFBD>7<EFBFBD><<3C><12>,<2C>,<2C> <20>W<EFBFBD>W<EFBFBD>%;<3B>U<EFBFBD>C<>C<><19>g<EFBFBD>g<EFBFBD>o<EFBFBD>u<EFBFBD>5<>5<>  <06> <06> <06>r<00><00>3<00>Brr<00>cmd<6D>length<74>bytesc<01>H<00>d||z|zz
dz}td||||dg<06><00>S)N<><00><><00>~<00> )rW)rrUrV<00>chks r<00>encode_eg4_requestr^<00>s5<00><00> <10>G<EFBFBD>c<EFBFBD>M<EFBFBD>F<EFBFBD>*<2A> +<2B>t<EFBFBD>
3<EFBFBD>C<EFBFBD> <10>$<24><07><13>f<EFBFBD>c<EFBFBD>4<EFBFBD>8<> 9<> 9<>9r<00>datar5<00>dict[str, Any]c <01><00><0F>|r+t|<00><00>dks|ddks |ddkr-td|<00>d<07><00>dd <09><00><00><02><00><00>g}d
}td <0B><00>D]<5D>}|d zt|<00><00>krtd t|<02><00><00><00><02><00><00>||dz}|d z|d zz}|t|<00><00>kr3tdt|<02><00><00>d|<06>dt|<00><00><00>d<12><07><00><00>||d z|<06><00>|<02><00>fd<13>tdt<00><0F><00>d <0C><00>D<00><00><00><00>|}<03><>i}d<14>|dd|<01>D<00><00>}t |d<0E><15><00>D]\} }
t |
d<16><00>|d| d<18>d<19><<00>|r<>t|<08><00>t|<08><00>} } t | d<16><00>|d<t | d<16><00>|d<t | | z
dz<00><00>|d<|<08> | <0B><00>dz|d<|<08> | <0C><00>dz|d<|dr%t d |ddz
d!z d <0C><00>|d"<|d r"t |d dd!z d<0E><00>|d#<|dr"t |ddd!z d <0C><00>|d$<t |d
dd<01>d<0E><15><00>D]\} } | d%zd&z
|d'| <09><00><<00>t|d(<00><00>dkr|d(dnd}|d)zrd*nd+|d,<|d-zrd*nd+|d.<|d/zrd*nd+|d0<|d1zrd*nd+|d2<|d3zrd*nd+|d4<|dr|dd|d5<|d6r"t |d6dd!z d <0C><00>|d7<|S)8z<38>Decode a fn=0x01 reply into a flat dict keyed for HA. Mirrors
`battery/eg4_lifepower.py::parse_status`. Permissive framing check
(header/footer); upstream doesn't validate the reply CRC and neither
do we until we know the algorithm.<2E>rr[<00><><EFBFBD><EFBFBD><EFBFBD>r\z bad framing: <20> N<>x<00><00>
<00>ztruncated payload at group rRzgroup z overruns frame (end=z, len=<3D>)c<01>><00><01>g|]}td<00>|<01><00>d<00><02>S)<02>>Hrr)rB<00>k<>payloads <20>rrDz-decode_eg4_general_status.<locals>.<listcomp><3E>s*<00><><00>[<5B>[<5B>[<5B>A<EFBFBD>{<7B>4<EFBFBD><17>!<21>4<>4<>Q<EFBFBD>7<>[<5B>[<5B>[rc<01><00>g|]
}|dzdz <00><02> S)<02><><00>@<40>@r<00>rBrPs rrDz-decode_eg4_general_status.<locals>.<listcomp><3E>s!<00><00> C<> C<> C<>q<EFBFBD>a<EFBFBD>&<26>j<EFBFBD>F<EFBFBD> "<22> C<> C<> Cr<00><01>start<72><00>cell_<6C>02d<32>_voltage<67>cell_voltage_min<69>cell_voltage_max<61><78><00>cell_voltage_delta_mv<6D> cell_lowest<73> cell_highest<73>0u<00>Y@<40>current<6E>soc<6F> capacity_ahrZ<00>2<00> temperature_<65><00><00>on<6F>off<66>alarm_current_overr4<00>alarm_voltage_high<67> <00>alarm_voltage_low<6F>@<00>alarm_temp_high_chg<68><67><00>alarm_temp_low_chg<68> cycle_count<6E><00> pack_voltage)
<EFBFBD>len<65>
ValueError<EFBFBD>hex<65>range<67>append<6E> enumerate<74>round<6E>min<69>max<61>index)r_r5<00>groups<70>i<>_<> group_len<65>end<6E>out<75>cells<6C>idx<64>cv<63>vmin<69>vmaxrL<00>flagsrms @r<00>decode_eg4_general_statusr<73><00>s6<00><><00>
<10>@<01>3<EFBFBD>t<EFBFBD>9<EFBFBD>9<EFBFBD>q<EFBFBD>=<3D>=<3D>D<EFBFBD><11>G<EFBFBD>t<EFBFBD>O<EFBFBD>O<EFBFBD>t<EFBFBD>B<EFBFBD>x<EFBFBD>4<EFBFBD>7G<37>7G<37><18>><3E><14><18><18>#<23><1D><1D>t<EFBFBD><03>t<EFBFBD>)<<3C>><3E>><3E>?<3F>?<3F>?<3F> <20>F<EFBFBD> <09>A<EFBFBD> <12>2<EFBFBD>Y<EFBFBD>Y<EFBFBD> <10> <10><01> <0C>q<EFBFBD>5<EFBFBD>3<EFBFBD>t<EFBFBD>9<EFBFBD>9<EFBFBD> <1C> <1C><1C>H<>3<EFBFBD>v<EFBFBD>;<3B>;<3B>H<>H<>I<>I<> I<><18><11>Q<EFBFBD><15>K<EFBFBD> <09><0F>!<21>e<EFBFBD>i<EFBFBD>!<21>m<EFBFBD>#<23><03> <0E><13>T<EFBFBD><19><19>?<3F>?<3F><1C>_<>c<EFBFBD>&<26>k<EFBFBD>k<EFBFBD>_<>_<><03>_<>_<>SV<53>W[<5B>S\<5C>S\<5C>_<>_<>_<>`<60>`<60> `<60><16>q<EFBFBD>1<EFBFBD>u<EFBFBD>S<EFBFBD>y<EFBFBD>/<2F><07><0E> <0A> <0A>[<5B>[<5B>[<5B>[<5B><15>q<EFBFBD>#<23>g<EFBFBD>,<2C>,<2C>XY<58>AZ<41>AZ<41>[<5B>[<5B>[<5B>\<5C>\<5C>\<5C> <0F><01><01><1C>C<EFBFBD> D<01> C<>F<EFBFBD>1<EFBFBD>I<EFBFBD>k<EFBFBD>z<EFBFBD>k<EFBFBD>,B<> C<> C<> C<>E<EFBFBD><1C>U<EFBFBD>!<21>,<2C>,<2C>,<2C>6<>6<><07><03>R<EFBFBD>).<2E>r<EFBFBD>1<EFBFBD><1C><1C><03> %<25>C<EFBFBD> %<25> %<25> %<25> %<25>&<26>&<26> <0C>=<3D><18><15>Z<EFBFBD>Z<EFBFBD><13>U<EFBFBD><1A><1A>d<EFBFBD><04>',<2C>T<EFBFBD>1<EFBFBD>~<7E>~<7E><03> <1E><1F>',<2C>T<EFBFBD>1<EFBFBD>~<7E>~<7E><03> <1E><1F>',<2C>d<EFBFBD>T<EFBFBD>k<EFBFBD>T<EFBFBD>-A<>'B<>'B<><03> #<23>$<24>',<2C>{<7B>{<7B>4<EFBFBD>'8<>'8<>1<EFBFBD>'<<3C><03>M<EFBFBD><1A>',<2C>{<7B>{<7B>4<EFBFBD>'8<>'8<>1<EFBFBD>'<<3C><03>N<EFBFBD><1B><0E>a<EFBFBD>y<EFBFBD>B<01><1E><05><06>q<EFBFBD> <09>!<21> <0C> 4<><05>=<3D>q<EFBFBD>A<>A<><03>I<EFBFBD><0E> <0A>a<EFBFBD>y<EFBFBD>4<><1A>6<EFBFBD>!<21>9<EFBFBD>Q<EFBFBD><<3C>%<25>/<2F><11>3<>3<><03>E<EFBFBD>
<EFBFBD> <0A>a<EFBFBD>y<EFBFBD><<3C>"<22>6<EFBFBD>!<21>9<EFBFBD>Q<EFBFBD><<3C>%<25>#7<><11>;<3B>;<3B><03>M<EFBFBD><1A><1D>f<EFBFBD>Q<EFBFBD>i<EFBFBD><02><11><02>m<EFBFBD>1<EFBFBD>5<>5<>5<>6<>6<><08><03>S<EFBFBD>%(<28>4<EFBFBD>Z<EFBFBD>2<EFBFBD>$5<><03> <20>3<EFBFBD> <20> <20>!<21>!<21><1F><06>q<EFBFBD> <09>N<EFBFBD>N<EFBFBD>Q<EFBFBD>.<2E>.<2E>F<EFBFBD>1<EFBFBD>I<EFBFBD>a<EFBFBD>L<EFBFBD>L<EFBFBD>A<EFBFBD>E<EFBFBD>).<2E><1A>);<3B>!F<><14><14><15>C<EFBFBD><1C><1D>).<2E><1A>);<3B>!F<><14><14><15>C<EFBFBD><1C><1D>).<2E><1A>);<3B>!F<><14><14><15>C<EFBFBD><1B><1C>).<2E><1A>);<3B>!F<><14><14><15>C<EFBFBD><1D><1E>).<2E><1A>);<3B>!F<><14><14><15>C<EFBFBD><1C><1D> <0A>a<EFBFBD>y<EFBFBD>*<2A>#<23>A<EFBFBD>Y<EFBFBD>q<EFBFBD>\<5C><03>M<EFBFBD><1A> <0A>a<EFBFBD>y<EFBFBD>=<3D>#<23>F<EFBFBD>1<EFBFBD>I<EFBFBD>a<EFBFBD>L<EFBFBD>5<EFBFBD>$8<>!<21><<3C><<3C><03>N<EFBFBD><1B> <0E>Jrc<01>h<00>d}|D],}||z}td<02><00>D]}|dzr |dz dz }<01>|dz}<01><16>-|S)N<><4E><EFBFBD>r<>rRi<01>)r<>)r_<00>crc<72>br<62>s r<00> crc16_modbusr<73><00>sg<00><00>
<10>C<EFBFBD> <11><1A><1A><01> <0B>q<EFBFBD><08><03><16>q<EFBFBD><18><18> <1A> <1A>A<EFBFBD><12>Q<EFBFBD>w<EFBFBD> <1A><1A>a<EFBFBD>x<EFBFBD>6<EFBFBD>)<29><03><03><13><01> <09><03><03>  <1A>
<0F>Jr<00>bufrsr6c<01><><00>||zt|<00><00>krdS||||zdz
<00>}|||zdz
|||zdz
dzz}t|<03><00>|kS)NFrhrRr<>)r<>r<>)r<>rsrV<00>body<64>expecteds r<00>_crc_okr<6B><00>sr<00><00> <0C>v<EFBFBD>~<7E><03>C<EFBFBD><08><08> <20> <20><14>u<EFBFBD> <0E>u<EFBFBD>U<EFBFBD>V<EFBFBD>^<5E>a<EFBFBD>'<27>'<27> (<28>D<EFBFBD><12>5<EFBFBD>6<EFBFBD>><3E>A<EFBFBD>%<25>&<26>#<23>e<EFBFBD>f<EFBFBD>n<EFBFBD>q<EFBFBD>.@<40>*A<>Q<EFBFBD>*F<>G<>H<EFBFBD> <17><04> <1D> <1D><18> )<29>)r>
rRrhrtrfr<>rb<00>r4<00><00><00>tuple[int, str] | Nonec<01><><00>|dzt|<00><00>krdS||dz}|dkrN|dztvrB|dzt|<00><00>kr,d||dzcxkrdkrnnt||d<05><00>rdS|d krjt||d
<EFBFBD><00>rd S|d zt|<00><00>krA||dz}d|cxkrd kr)nn&|dzd krd |zdz}t|||<04><00>r|dfSdS)NrfrRr<><00>r<>rh<00> )r<><00> exceptionrtr<>)r<><00>query<72><79>r<00>response)r<><00> _MODBUS_FUNCSr<53>)r<>rs<00>func<6E>
byte_count<EFBFBD>totals r<00>parse_modbus_frame_atr<74><00>s?<00><00> <0C>q<EFBFBD>y<EFBFBD>3<EFBFBD>s<EFBFBD>8<EFBFBD>8<EFBFBD><1B><1B><13>t<EFBFBD> <0E>u<EFBFBD>q<EFBFBD>y<EFBFBD>><3E>D<EFBFBD> <0B>t<EFBFBD>|<7C>|<7C><14><04><1B><1D>6<>6<><15><01> <09>S<EFBFBD><13>X<EFBFBD>X<EFBFBD>%<25>%<25>!<21>s<EFBFBD>5<EFBFBD>1<EFBFBD>9<EFBFBD>~<7E>*C<>*C<>*C<>*C<><12>*C<>*C<>*C<>*C<>*C<><17><03>U<EFBFBD>A<EFBFBD>&<26>&<26>+D<01><1F><1F> <0B>t<EFBFBD>|<7C>|<7C> <12>3<EFBFBD><05>q<EFBFBD> !<21> !<21> <20><1F><<3C> <10>1<EFBFBD>9<EFBFBD><03>C<EFBFBD><08><08> <20> <20><1C>U<EFBFBD>Q<EFBFBD>Y<EFBFBD><1E>J<EFBFBD><10>J<EFBFBD>%<25>%<25>%<25>%<25>#<23>%<25>%<25>%<25>%<25>%<25>*<2A>q<EFBFBD>.<2E>A<EFBFBD>*=<3D>*=<3D><19>J<EFBFBD><0E><11>*<2A><05><1A>3<EFBFBD><05>u<EFBFBD>-<2D>-<2D>/<2F>!<21>:<3A>.<2E>.<2E> <0F>4rc<01>P<00>eZdZUded<ded<ded<ded<ed d
<EFBFBD><04><00>Zd S) <0A> ModbusFramerr<00>functionr <00>kindrWrLr:<00> list[int]c<01><><00><02>|jdks |jdkrgS|jd}|jdd|z<00><00><02>fd<04>tdt <00><02><00>d<03><00>D<00><00>S)Nr<4E>rtrhc<01>><00><01>g|]}<01>|dz<00>|dzz<00><02>S<00>r<>rRr)rBr<><00>ds <20>rrDz)ModbusFrame.registers.<locals>.<listcomp>s.<00><><00>D<>D<>D<>1<EFBFBD><11>1<EFBFBD><14><11><19>a<EFBFBD><01>A<EFBFBD><05>h<EFBFBD>&<26>D<>D<>Drr)r<>r<>rLr<>r<>)<03>self<6C>bcr<63>s @r<00> registerszModbusFrame.registerssl<00><><00> <0F>9<EFBFBD>
<EFBFBD> "<22> "<22>d<EFBFBD>m<EFBFBD>t<EFBFBD>&;<3B>&;<3B><15>I<EFBFBD> <11>X<EFBFBD>a<EFBFBD>[<5B><02> <10>H<EFBFBD>Q<EFBFBD>q<EFBFBD>2<EFBFBD>v<EFBFBD>X<EFBFBD> <1E><01>D<>D<>D<>D<><05>a<EFBFBD><13>Q<EFBFBD><16><16><11>0C<30>0C<30>D<>D<>D<>DrN<>r:r<>)rrrr<00>propertyr<79>rrrr<>r<>s^<00><00><00><00><00><00><00><10>L<EFBFBD>L<EFBFBD>L<EFBFBD><11>M<EFBFBD>M<EFBFBD>M<EFBFBD> <0A>I<EFBFBD>I<EFBFBD>I<EFBFBD><0E>J<EFBFBD>J<EFBFBD>J<EFBFBD> <0A>E<01>E<01>E<01><0E>X<EFBFBD>E<01>E<01>Err<><00>framec<01>><00>d<01>t|j<00><00>D<00><00>S)zCRaw-register dump; promote to named fields once we know the layout.c<01>"<00>i|] \}}d|d<01><04>|<02><02> S)<02> register_rvr)rBr<>rPs r<00>
<dictcomp>z*decode_modbus_response.<locals>.<dictcomp>!s*<00><00> J<> J<> J<>t<EFBFBD>q<EFBFBD>!<21> <1F><01> <1F> <1F> <1F><11> J<> J<> Jr)r<>r<>)r<>s r<00>decode_modbus_responser<65>s <00><00> J<> J<>y<EFBFBD><15><1F>/I<>/I<> J<> J<> J<>JrrPc<01><00>|dzr|dz
n|S)Ni<00>ir)rPs r<00> _signed16r<36>7s<00><00><1B>f<EFBFBD>*<2A> +<2B>1<EFBFBD>w<EFBFBD>;<3B>;<3B>!<21>+rF<>regsr<73><00>
expose_rawc<01><><00><00>i}|rt<00><00><00>D]\}}||d|d<02><04><<00>t<00><00><00>dkr|St<00>ddz d<06><00>|d<tt<00>d<00><00>dz d<06><00>|d <<00>fd
<EFBFBD>t d <0B><00>D<00><00>}t|d<08> <0C><00>D]\}}t|d <0A><00>|d|d<02>d<0F><<00>t |<05><00>t |<05><00>}}t|d <0A><00>|d<t|d <0A><00>|d<t||z
dz<00><00>|d<|<05>|<07><00>dz|d<|<05>|<08><00>dz|d<<00>d|d<<00>d|d<<00>d|d<<00>d|d<<00>d|d<<00>d |d!<<00>d"|d#<<00>d$|d%<<00>d&|d'<t<00>d(d)z d<08><00>|d*<t<00>d+dz d<06><00>|d,<t<00><00><00>d-kr<t<00>d.d/<2F><00>|d0<t<00>d1d <0A><00>|d2<t<00>d3d4<64><00>|d5<|S)6uDecode the read-holding-regs response from an LP4V2 BMS.
Emits named HA entities. If `expose_raw` is True, also emits
`register_NN` entities for every position — useful when refining
the register map; defaults to off to keep HA Devices uncluttered.r<>rv<00>/rrrhr<>rR<00> pack_currentc<01>,<00><01>g|]}<01>d|zdz <00><02>S)rhrpr)rBr<>r<>s <20>rrDz*decode_eg4_modbus_regs.<locals>.<listcomp>Ms&<00><><00>7<>7<>7<><01>t<EFBFBD>A<EFBFBD><01>E<EFBFBD>{<7B>V<EFBFBD>#<23>7<>7<>7rr4rrrtrurwrxryrzr{r|r}<00><00>temperature_01<30><00>temperature_02<30><00>temperature_03<30>r<><00><00>soc_altr<74><00> bms_field_22r<32><00> bms_field_23<32>#<00>
error_code<EFBFBD>$r5<00>%r$r<><00>&<00> remaining_ah<61>|<00>irg<00>model<65>u<00>firmware_versionrerf<00> firmware_date) r<>r<>r<>r<>r<>r<>r<>r<><00>_ascii_from_regs) r<>r<>r<>r<>rP<00>cells_vr<76>r<>r<>s ` r<00>decode_eg4_modbus_regsr<73>;s<><00><><00>
<1D>C<EFBFBD><11>)<29><1D>d<EFBFBD>O<EFBFBD>O<EFBFBD> )<29> )<29>D<EFBFBD>A<EFBFBD>q<EFBFBD>'(<28>C<EFBFBD>#<23>A<EFBFBD>#<23>#<23>#<23> $<24> $<24>
<EFBFBD>4<EFBFBD>y<EFBFBD>y<EFBFBD>2<EFBFBD>~<7E>~<7E><12>
<EFBFBD> <20><04>Q<EFBFBD><07>%<25><0F><11>3<>3<>C<EFBFBD><0E><17><1F> <09>$<24>q<EFBFBD>'<27> 2<> 2<>U<EFBFBD> :<3A>A<EFBFBD>><3E>><3E>C<EFBFBD><0E><17>8<>7<>7<>7<>U<EFBFBD>2<EFBFBD>Y<EFBFBD>Y<EFBFBD>7<>7<>7<>G<EFBFBD><1A>7<EFBFBD>!<21>,<2C>,<2C>,<2C>4<>4<><05><01>2<EFBFBD>',<2C>R<EFBFBD><11>|<7C>|<7C><03> #<23>A<EFBFBD> #<23> #<23> #<23> #<23>$<24>$<24><14>W<EFBFBD><1C><1C>s<EFBFBD>7<EFBFBD>|<7C>|<7C>$<24>D<EFBFBD>#(<28><14>q<EFBFBD>><3E>><3E>C<EFBFBD><1A><1B>#(<28><14>q<EFBFBD>><3E>><3E>C<EFBFBD><1A><1B>#(<28>$<24><14>+<2B><14>)=<3D>#><3E>#><3E>C<EFBFBD><1F> <20>#*<2A>=<3D>=<3D><14>#6<>#6<><11>#:<3A>C<EFBFBD> <0A><16>#*<2A>=<3D>=<3D><14>#6<>#6<><11>#:<3A>C<EFBFBD><0E><17>!<21><12>H<EFBFBD>C<EFBFBD><18><19> <20><12>H<EFBFBD>C<EFBFBD><18><19> <20><12>H<EFBFBD>C<EFBFBD><18><19><16>b<EFBFBD><18>C<EFBFBD><05>J<EFBFBD><19>"<22>X<EFBFBD>C<EFBFBD> <09>N<EFBFBD><1E>r<EFBFBD>(<28>C<EFBFBD><0E><17><1E>r<EFBFBD>(<28>C<EFBFBD><0E><17> <1D>R<EFBFBD><08>C<EFBFBD> <0C><15><1D>R<EFBFBD><08>C<EFBFBD> <0C><15><1E>t<EFBFBD>B<EFBFBD>x<EFBFBD>$<24><EFBFBD><01>2<>2<>C<EFBFBD> <0A><16><1F><04>R<EFBFBD><08>5<EFBFBD> 0<>!<21>4<>4<>C<EFBFBD><0E><17>2 <0B>4<EFBFBD>y<EFBFBD>y<EFBFBD>C<EFBFBD><17><17>"2<>4<EFBFBD><13>b<EFBFBD>"A<>"A<><03>G<EFBFBD> <0C>"2<>4<EFBFBD><13>a<EFBFBD>"@<40>"@<40><03> <1E><1F>"2<>4<EFBFBD><13>a<EFBFBD>"@<40>"@<40><03>O<EFBFBD><1C> <0E>Jr<00>
count_regsr c<01>
<00>g}||||z<00>D]M}|dz dz|dzfD]<}|dkrn4d|cxkrdkr%n<00>|<03>t|<05><00><00><00><00>=<3D>Md<06>|<03><00><00><00><00>S)z<>Convert `count_regs` u16 values into an ASCII string (high byte first
per Modbus convention). Trailing nulls and non-printable trailing junk
are stripped.r<>rZrr<>r<>r)r<><00>chr<68>join<69>rstrip)r<>rsr<><00>chars<72>r<>chs rr<>r<><00>s<><00><00><1A>E<EFBFBD> <11>%<25><05>
<EFBFBD>*<2A>*<2A> +<2B><0E><0E><01><15><11>F<EFBFBD>d<EFBFBD>?<3F>A<EFBFBD><04>H<EFBFBD>-<2D> <15> <15>B<EFBFBD><11>Q<EFBFBD>w<EFBFBD>w<EFBFBD><15><05><11>R<EFBFBD>~<7E>~<7E>~<7E>~<7E>#<23>~<7E>~<7E>~<7E>~<7E>~<7E><15> <0C> <0C>S<EFBFBD><12>W<EFBFBD>W<EFBFBD>%<25>%<25>%<25><> <14> <0A> <0A>7<EFBFBD>7<EFBFBD>5<EFBFBD>><3E>><3E> <20> <20> "<22> "<22>"rc<01>Z<00>eZdZdZdZdZdZdZeezZddd<0E>Z dd<11>Z
dZ dd<16>Z dd<17>Z dd<18>ZdS)<1F>ModbusActivePolleru[One instance per pack. Opens its own serial port, issues two
read-holding-regs fn=0x03 queries per `poll()` call, and returns a
sparse 136-register list (indices 0-38 from the first read, 45-135
from the second, gap at 39-44 zero-padded).
The two reads mirror what lv_host.app's BMS Tool issues in its
monitoring loop:
block 1 — count=39 @ 0 (live status)
block 2 — count=91 @ 0x2d (counters + model + firmware strings)
Graceful: a pack whose port doesn't exist or whose BMS is off will
raise on poll, and the main loop catches + rate-limits the noise.r<00>'<00>-<00>[<00><00>?rr rrrr#r"c<01>L<00>||_||_||_||_d|_dS<00>N)<05>
_port_path<EFBFBD>_baud<75>_address<73>
_timeout_s<EFBFBD>_ser)r<>rrrr#s r<00>__init__zModbusActivePoller.__init__<5F>s)<00><00><1E><04><0F><19><04>
<EFBFBD><1F><04> <0A>#<23><04><0F>*.<2E><04> <09> <09> rr:<00>Nonec<01><><00>|j<00> |jjs+tj|j|jdddd<04><05><00>|_dSdS)Ng<4E><67><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?r<><00>NrR<00>r<00>baudrate<74>timeout<75>bytesize<7A>parity<74>stopbits)r<00>is_openr<00>Serialr r <00>r<>s r<00>_openzModbusActivePoller._open<65>sJ<00><00> <0F>9<EFBFBD> <1C>D<EFBFBD>I<EFBFBD>$5<> <1C><1E> <0A><19>_<EFBFBD>t<EFBFBD>z<EFBFBD>3<EFBFBD><1A>3<EFBFBD><11><0E><0E><0E>D<EFBFBD>I<EFBFBD>I<EFBFBD>I<EFBFBD> <1D> rrfrs<00>countr<74>c
<01><><00><0E>t|jd|dz |dz|dz |dzg<06><00>}t|<03><00>}|t|dz|dz g<02><00>z}|j<00>J<00>|j<00><00><00>|j<00>|<05><00>d|dzzdz|jz}t<00><00>}tj <00><00>|j
z}tj <00><00>|kr~t|<07><00>|krk|j<00> |t|<07><00>z
<00><00>} | r|<07> | <09><00>tj <00><00>|krt|<07><00>|k<00>kt|<07><00>}
t<00>d|j|||<05>d<06><00>|
<EFBFBD>d<06><00><00><00>t#t%|jdzt't|
<EFBFBD><00>dz
d <09><00><00><00><00><00>D]<5D>} |
| |jks|
| dzdkr<01>#|
| dz} | dz| zdz} | t|
<EFBFBD><00>kr<01>Mt)|
| d| zdz<00><00>s<01>e|
| dz| dz| z<00><00><0E>fd
<EFBFBD>t#d t<00><0E><00>d<04><00>D<00><00>cSt+d t|
<EFBFBD><00><00>d |<02>d |<01>d<0E><07><00><00>)Nrtr<>rZrhzpack 0x%02x [%d@%d] tx=%s rx=%srdrRrfrc<01>><00><01>g|]}<01>|dz<00>|dzz<00><02>Sr<>r)rBr<>r_s <20>rrDz2ModbusActivePoller._read_block.<locals>.<listcomp><3E>s.<00><><00>Q<>Q<>Q<>Q<EFBFBD>T<EFBFBD>!<21>W<EFBFBD><01>\<5C>T<EFBFBD>!<21>a<EFBFBD>%<25>[<5B>0<>Q<>Q<>Qrzno valid frame in z bytes for read(<28>@ri)rWr r<>r<00>reset_input_buffer<65>write<74>_MAX_LEADING_IDLE<4C> bytearray<61>time<6D> monotonicrr<><00>read<61>extend<6E>log<6F>debugr<67>r<>r<>r<>r<><00> RuntimeError)r<>rsrr<>r<>r<>r<>r<><00>deadline<6E>chunkrLr<>r<><00> frame_endr_s @r<00> _read_blockzModbusActivePoller._read_block<63>s<><00><><00><14>d<EFBFBD>m<EFBFBD>T<EFBFBD><1B>q<EFBFBD>j<EFBFBD>%<25>$<24>,<2C><05><11>
<EFBFBD>E<EFBFBD>D<EFBFBD>L<EFBFBD>J<01>K<01>K<01><04><1A>4<EFBFBD> <20> <20><03><14>u<EFBFBD>c<EFBFBD>D<EFBFBD>j<EFBFBD>#<23><11>(<28>3<>4<>4<>4<><05><13>y<EFBFBD>$<24>$<24>$<24> <0C> <09>$<24>$<24>&<26>&<26>&<26> <0C> <09><0F><0F><05><1E><1E><1E><15>u<EFBFBD>q<EFBFBD>y<EFBFBD>=<3D>1<EFBFBD>$<24>t<EFBFBD>'=<3D>=<3D><08><17>k<EFBFBD>k<EFBFBD><03><17>><3E>#<23>#<23>d<EFBFBD>o<EFBFBD>5<><08><12>n<EFBFBD><1E><1E><18>)<29>)<29>c<EFBFBD>#<23>h<EFBFBD>h<EFBFBD><18>.A<>.A<><18>I<EFBFBD>N<EFBFBD>N<EFBFBD>8<EFBFBD>c<EFBFBD>#<23>h<EFBFBD>h<EFBFBD>#6<>7<>7<>E<EFBFBD><14> "<22><13>
<EFBFBD>
<EFBFBD>5<EFBFBD>!<21>!<21>!<21><13>n<EFBFBD><1E><1E><18>)<29>)<29>c<EFBFBD>#<23>h<EFBFBD>h<EFBFBD><18>.A<>.A<><14>C<EFBFBD>j<EFBFBD>j<EFBFBD><03> <0B> <09> <09>3<><16>-<2D><15><05>u<EFBFBD>y<EFBFBD>y<EFBFBD><13>~<7E>~<7E>s<EFBFBD>w<EFBFBD>w<EFBFBD>s<EFBFBD>|<7C>|<7C> M<01> M<01> M<01>
<19><13>T<EFBFBD>3<>a<EFBFBD>7<><13>S<EFBFBD><13>X<EFBFBD>X<EFBFBD><01>\<5C>1<EFBFBD>9M<39>9M<39>N<>N<>O<>O<>
R<01>
R<01>C<EFBFBD><12>3<EFBFBD>x<EFBFBD>4<EFBFBD>=<3D>(<28>(<28>C<EFBFBD><03>a<EFBFBD><07>L<EFBFBD>D<EFBFBD>,@<40>,@<40><18><14>S<EFBFBD>1<EFBFBD>W<EFBFBD><1C>B<EFBFBD><1B>a<EFBFBD><07>"<22> <0C>q<EFBFBD>(<28>I<EFBFBD><18>3<EFBFBD>s<EFBFBD>8<EFBFBD>8<EFBFBD>#<23>#<23><18><1A>3<EFBFBD><03>Q<EFBFBD><12>V<EFBFBD>a<EFBFBD>Z<EFBFBD>0<>0<> <19><18><16>s<EFBFBD>Q<EFBFBD>w<EFBFBD>s<EFBFBD>Q<EFBFBD>w<EFBFBD><12>|<7C>+<2B>,<2C>D<EFBFBD>Q<>Q<>Q<>Q<>%<25><01>3<EFBFBD>t<EFBFBD>9<EFBFBD>9<EFBFBD>a<EFBFBD>:P<>:P<>Q<>Q<>Q<> Q<> Q<> Q<><1A>Z<><03>C<EFBFBD><08><08>Z<>Z<>%<25>Z<>Z<>RW<52>Z<>Z<>Z<>[<5B>[<5B>[rc<01>t<00>|<00><00><00>dg|jz}|<00>|j|j<00><00>}t |<02><00>D]\}}|||j|z<<00>t jd<02><00>|<00>|j|j <00><00>}t |<05><00>D]\}}|||j|z<<00>|S)Nr<><E79A99><EFBFBD><EFBFBD><EFBFBD>?)
r<00>TOTAL_REG_COUNTr0<00> BLOCK_1_START<52> BLOCK_1_COUNTr<54>r&<00>sleep<65> BLOCK_2_START<52> BLOCK_2_COUNT)r<>r<><00>block1r<31>rP<00>block2s r<00>pollzModbusActivePoller.poll<6C>s<><00><00> <0C>
<EFBFBD>
<EFBFBD> <0C> <0C> <0C><11>s<EFBFBD>T<EFBFBD>)<29>)<29><04><15>!<21>!<21>$<24>"4<>d<EFBFBD>6H<36>I<>I<><06><1D>f<EFBFBD>%<25>%<25> -<2D> -<2D>D<EFBFBD>A<EFBFBD>q<EFBFBD>+,<2C>D<EFBFBD><14>#<23>a<EFBFBD>'<27> (<28> (<28> <0C>
<EFBFBD>4<EFBFBD><18><18><18><15>!<21>!<21>$<24>"4<>d<EFBFBD>6H<36>I<>I<><06><1D>f<EFBFBD>%<25>%<25> -<2D> -<2D>D<EFBFBD>A<EFBFBD>q<EFBFBD>+,<2C>D<EFBFBD><14>#<23>a<EFBFBD>'<27> (<28> (<28><13> rc<01>f<00>|j<00>'|jjr|j<00><00><00>dSdSdSr
)rr<00>closers rr=zModbusActivePoller.closes:<00><00> <0F>9<EFBFBD> <20>T<EFBFBD>Y<EFBFBD>%6<> <20> <10>I<EFBFBD>O<EFBFBD>O<EFBFBD> <1D> <1D> <1D> <1D> <1D> !<21> <20> <20> rN)r)rr rrrrr#r"<00>r:r)rsrrrr:r<>r<>)rrr<00>__doc__r4r5r7r8r3rrr$r0r;r=rrrrr<00>s<><00><00><00><00><00><00> I<01> I<01><1B>M<EFBFBD><16>M<EFBFBD><1A>M<EFBFBD><16>M<EFBFBD>#<23>m<EFBFBD>3<>O<EFBFBD>/<2F>/<2F>/<2F>/<2F>/<2F><0E><0E><0E><0E><1A><15>$\<01>$\<01>$\<01>$\<01>L <14> <14> <14> <14><1E><1E><1E><1E><1E>rrc<01>"<00>eZdZdZd
d<06>Zd d<08>Zd S) <0C>ActiveTransportz+Request-response transport for active mode.rrr:rWc<01><00>t<00>r
<00><01>NotImplementedError)r<>rs r<00> query_generalzActiveTransport.query_general<00><00><00>!<21>!rrc<01><00>dSr
rrs rr=zActiveTransport.close<00><00><00> <0C>rN<>rrr:rWr>)rrrr?rEr=rrrrArA<00>B<00><00><00><00><00><00>5<>5<>"<22>"<22>"<22>"<22> <0A> <0A> <0A> <0A> <0A> rrAc<01>"<00>eZdZdZdd<04>Zd d<06>ZdS)
<EFBFBD>PassiveListenerz+Continuous frame-iterator for passive mode.r:<00>Iterator[ModbusFrame]c<01><00>t<00>r
rCrs r<00>frameszPassiveListener.framesrFrrc<01><00>dSr
rrs rr=zPassiveListener.close rHrN<>r:rMr>)rrrr?rOr=rrrrLrLrJrrLc<01>&<00>eZdZdd<07>Zdd <0B>Zdd <0A>ZdS)<12>SerialActiveTransportrr rrr#r"c<01>R<00>||_tj||dddd<04><05><00>|_dS)Ng<00>?r<>rrRr)rrrr)r<>rrr#s rrzSerialActiveTransport.__init__(s5<00><00>#<23><04><0F><1A>M<EFBFBD>t<EFBFBD>d<EFBFBD>D<EFBFBD>+,<2C>S<EFBFBD>1<EFBFBD>F<01>F<01>F<01><04> <09> <09> rrr:rWc<01><><00>t|t<00><00>}t<00>d||<02><00><00><00><00>|j<00><00><00>|j<00>|<02><00>t<00><00>}tj
<00><00>|j z}tj
<00><00>|krl|j<00> d<02><00>}|r9|<03> |<05><00>|dd<04>dkr|<03>d<06><00>rntj
<00><00>|k<00>lt<00>d|t|<03><00><00><00><00><00><00>t|<03><00>S)NzTX addr=0x%02x: %srYrrR<00>~<7E> zRX addr=0x%02x: %s)r^<00>CMD_GENERAL_STATUSr*r+r<>rr"r#r%r&r'rr(r)<00>endswithrW)r<>rr<>r<>r-r.s rrEz#SerialActiveTransport.query_general-s'<00><00>"<22>7<EFBFBD>,><3E>?<3F>?<3F><05> <0B> <09> <09>&<26><07><15><19><19><1B><1B>=<3D>=<3D>=<3D> <0C> <09>$<24>$<24>&<26>&<26>&<26> <0C> <09><0F><0F><05><1E><1E><1E><17>k<EFBFBD>k<EFBFBD><03><17>><3E>#<23>#<23>d<EFBFBD>o<EFBFBD>5<><08><12>n<EFBFBD><1E><1E><18>)<29>)<29><18>I<EFBFBD>N<EFBFBD>N<EFBFBD>3<EFBFBD>'<27>'<27>E<EFBFBD><14> <1A><13>
<EFBFBD>
<EFBFBD>5<EFBFBD>!<21>!<21>!<21><16>q<EFBFBD><11>s<EFBFBD>8<EFBFBD>w<EFBFBD>&<26>&<26>3<EFBFBD><<3C><<3C><07>+@<40>+@<40>&<26><19> <13>n<EFBFBD><1E><1E><18>)<29>)<29> <0C> <09> <09>&<26><07><15>s<EFBFBD><1A><1A><1E><1E>1A<31>1A<31>B<>B<>B<><14>S<EFBFBD>z<EFBFBD>z<EFBFBD>rrc<01>8<00>|j<00><00><00>dSr
<00>rr=rs rr=zSerialActiveTransport.close=<00><00><00> <0C> <09><0F><0F><19><19><19><19>rN)rr rrr#r"rIr>)rrrrrEr=rrrrSrS'sT<00><00><00><00><00><00>F<01>F<01>F<01>F<01>
<1A><1A><1A><1A> <1A><1A><1A><1A><1A>rrSc<01>$<00>eZdZdZd d d<05>Zd d <09>Zd
S)<0E>MockActiveTransportzdSynthesise EG4 7E/0D replies. Values drift per call so HA dashboards
look alive in dry-run mode.r4r5rc<01>"<00>||_d|_dS<00>Nr)<02> _cell_count<6E>_call)r<>r5s rrzMockActiveTransport.__init__Es<00><00>%<25><04><18><16><04>
<EFBFBD>
<EFBFBD>
rrr:rWc<01><><00> <0C> <0A>|xjdz c_tj|dz|jz<00><00><00> d<03> <0A>dd<05><00>z<00> <0C> <0C> fd<06>t |j<00><00>D<00><00>}<02> <0A>dd<08><00>}d |z
}d
<EFBFBD> <0A>d d <0C><00>zd z}d<0E> <0A>dd<10><00>z}<06> fd<11>t d<12><00>D<00><00>}d|z}t t|<02><00>dz <00><00>} d%d<1A>}
d<1B>|
d|<02><00>|
d |g<01><00>|
d|g<01><00>|
d|g<01><00>|
d|<07><00>|
dddg<02><00>|
d|g<01><00>|
d | g<01><00>|
d!g<00><00>|
dg<00><00>g
<EFBFBD><00>} td"|tt| <0B><00>d#zg<04><00>| ztdd$g<02><00>zS)&NrRrz<00><> <00><><EFBFBD><EFBFBD><EFBFBD>r<EFBFBD>c <01>z<00><02>g|]7}tdtd<01><02><03>dd<03><00>z<00><00><00><00><00><02>8S)rro<00><><EFBFBD><EFBFBD><EFBFBD>r<EFBFBD>)r<>r<><00>randint<6E>rBr<><00>base_mv<6D>rngs <20><>rrDz5MockActiveTransport.query_general.<locals>.<listcomp>MsP<00><><00>6<>6<>6<><19><18><01>3<EFBFBD>v<EFBFBD>w<EFBFBD><13><1B><1B>R<EFBFBD><11>1C<31>1C<31>'C<>D<>D<>E<>E<>6<>6<>6r<00> <0C><><EFBFBD><EFBFBD><EFBFBD>r~r<><00><><EFBFBD><EFBFBD><EFBFBD>rh<00>d<00><>i<><69><EFBFBD><EFBFBD>rgc<01>B<00><01>g|]}d<00><02>dd<02><00>z<00><02>S)<03>K<00><><EFBFBD><EFBFBD><EFBFBD>rt<00>rh<00>rBr<>rks <20>rrDz5MockActiveTransport.query_general.<locals>.<listcomp>Ss,<00><><00>D<>D<>D<>a<EFBFBD>W<EFBFBD>s<EFBFBD>{<7B>{<7B>2<EFBFBD>q<EFBFBD>1<>1<>1<>D<>D<>Drrf<00>*<00>gidr<00>valuesr<73>r:rWc<01>~<00>t|t|<01><00>g<02><00>d<01>d<02>|D<00><00><00><00>zS)Nrc3<01>FK<00>|]}tjd|dz<00><00>V<00><00>dS<00>rkr<>N<><02>struct<63>packrqs r<00> <genexpr>zAMockActiveTransport.query_general.<locals>.grp.<locals>.<genexpr>XsC<00><00><00><00>8<0E>8<0E>23<32><06> <0B>D<EFBFBD>!<21>f<EFBFBD>*<2A>-<2D>-<2D>8<0E>8<0E>8<0E>8<0E>8<0E>8r)rWr<>r<>)rwrxs r<00>grpz.MockActiveTransport.query_general.<locals>.grpWsN<00><00><18>#<23>s<EFBFBD>6<EFBFBD>{<7B>{<7B>+<2B>,<2C>,<2C>s<EFBFBD>x<EFBFBD>x<EFBFBD>8<0E>8<0E>7=<3D>8<0E>8<0E>8<0E>0<0E>0<0E><0E> rrrtrbrr<>r<><00> r[rZr\)rwrrxr<>r:rW) rb<00>random<6F>Randomrhr<>rar<><00>sumr<6D>rWrXr<>)r<>r<00>cells_mv<6D> current_x100<30> current_raw<61>soc_x100<30> cap_ah_x100<30> temps_raw<61>cycles<65> pack_v_x100r<30>r<>rjrks @@rrEz!MockActiveTransport.query_generalIs <00><><EFBFBD><00> <0C>
<EFBFBD>
<EFBFBD>a<EFBFBD><0F>
<EFBFBD>
<EFBFBD><14>m<EFBFBD>G<EFBFBD>d<EFBFBD>N<EFBFBD>T<EFBFBD>Z<EFBFBD>7<>8<>8<><03><16><13><1B><1B>R<EFBFBD><11>+<2B>+<2B>+<2B><07>6<>6<>6<>6<>6<>"<22>4<EFBFBD>#3<>4<>4<>6<>6<>6<><08><1A>{<7B>{<7B>4<EFBFBD><14>.<2E>.<2E> <0C><1B>l<EFBFBD>*<2A> <0B><16><13><1B><1B>R<EFBFBD><11>+<2B>+<2B>+<2B>s<EFBFBD>2<><08><1A>S<EFBFBD>[<5B>[<5B><13>b<EFBFBD>1<>1<>1<> <0B>D<>D<>D<>D<>5<EFBFBD><11>8<EFBFBD>8<EFBFBD>D<>D<>D<> <09><13>g<EFBFBD><1C><06><1B>C<EFBFBD><08>M<EFBFBD>M<EFBFBD>B<EFBFBD>.<2E>/<2F>/<2F> <0B> <0E> <0E> <0E> <0E>
<13>x<EFBFBD>x<EFBFBD> <0F>C<EFBFBD><04>h<EFBFBD> <1F> <1F> <0F>C<EFBFBD><04>{<7B>m<EFBFBD> $<24> $<24> <0F>C<EFBFBD><04>x<EFBFBD>j<EFBFBD> !<21> !<21> <0F>C<EFBFBD><04>{<7B>m<EFBFBD> $<24> $<24> <0F>C<EFBFBD><04>i<EFBFBD> <20> <20> <0F>C<EFBFBD><04>q<EFBFBD>!<21>f<EFBFBD> <1D> <1D> <0F>C<EFBFBD><04>v<EFBFBD>h<EFBFBD> <1F> <1F> <0F>C<EFBFBD><04>{<7B>m<EFBFBD> $<24> $<24> <0F>C<EFBFBD><04>b<EFBFBD>M<EFBFBD>M<EFBFBD> <0F>C<EFBFBD><04>b<EFBFBD>M<EFBFBD>M<EFBFBD> 
<EFBFBD>  <0B>  <0B><04><15>d<EFBFBD>G<EFBFBD>%7<><13>T<EFBFBD><19><19>T<EFBFBD>9I<39>J<>K<>K<><12><13><1A>D<EFBFBD>$<24><<3C>(<28>(<28>)<29> )rN)r4)r5rrI)rrrr?rrErrrr^r^AsK<00><00><00><00><00><00>#<23>#<23><17><17><17><17><17>!)<29>!)<29>!)<29>!)<29>!)<29>!)rr^c<01>4<00>eZdZdZddd<08>Zdd <0B>Zdd <0C>Zdd<0E>ZdS)<14>SerialPassiveListenerir rr rrr!c<01>x<00>||_tj||dddd<04><05><00>|_t <00><00>|_dS)Ng<4E><67><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?r<>rrRr)<06> _read_chunkrrrr%<00>_buf)r<>rrr!s rrzSerialPassiveListener.__init__ssA<00><00>%<25><04><18><1A>M<EFBFBD>t<EFBFBD>d<EFBFBD>C<EFBFBD>+,<2C>S<EFBFBD>1<EFBFBD>F<01>F<01>F<01><04> <09><1D>K<EFBFBD>K<EFBFBD><04> <09> <09> rr:rMc#<01>K<00> |j<00>|j<00><00>}|rc|j<00>|<01><00>t |j<00><00>|jkr|jd|jdz<00>=|<00><00><00>Ed{V<00><02><00><>)NTrh)rr(r<>r<>r)r<><00>_BUF_MAX<41>_extract)r<>r.s rrOzSerialPassiveListener.framesys<><00><00><00><00> +<2B><18>I<EFBFBD>N<EFBFBD>N<EFBFBD>4<EFBFBD>#3<>4<>4<>E<EFBFBD><14> +<2B><14> <09> <20> <20><15>'<27>'<27>'<27><16>t<EFBFBD>y<EFBFBD>><3E>><3E>D<EFBFBD>M<EFBFBD>1<>1<><1C> <09>"5<>4<EFBFBD>=<3D>A<EFBFBD>#5<>"5<>6<><1F>=<3D>=<3D>?<3F>?<3F>*<2A>*<2A>*<2A>*<2A>*<2A>*<2A>*<2A>  +rc#<01>`K<00>d}|t|j<00><00>dz
kr<>t|j|<01><00>}|<02>|dz }<01>8|\}}t|j|||z<00><00><00>}t |d|d||<05><04><00>V<00>|jd||z<00>=d}|t|j<00><00>dz
k<00><>dSdS)NrrfrR<00>rr<>r<>rL)r<>r<>r<>rWr<>)r<>r<>rrVr<>rLs rr<>zSerialPassiveListener._extract<63>s<><00><00><00><00> <0A><01><0F>#<23>d<EFBFBD>i<EFBFBD>.<2E>.<2E>1<EFBFBD>$<24>$<24>$<24>%<25>d<EFBFBD>i<EFBFBD><11>3<>3<>A<EFBFBD><10>y<EFBFBD><11>Q<EFBFBD><06><01><18><1C>L<EFBFBD>F<EFBFBD>D<EFBFBD><17><04> <09>!<21>A<EFBFBD><06>J<EFBFBD>,<2C>/<2F>0<>0<>C<EFBFBD><1D>c<EFBFBD>!<21>f<EFBFBD>s<EFBFBD>1<EFBFBD>v<EFBFBD>D<EFBFBD>c<EFBFBD>R<>R<>R<> R<> R<> R<><14> <09>+<2B>1<EFBFBD>v<EFBFBD>:<3A>+<2B>&<26><11>A<EFBFBD><10>#<23>d<EFBFBD>i<EFBFBD>.<2E>.<2E>1<EFBFBD>$<24>$<24>$<24>$<24>$<24>$<24>$rrc<01>8<00>|j<00><00><00>dSr
r[rs rr=zSerialPassiveListener.close<73>r\rN)r )rr rrr!rrQr>)rrrr<>rrOr<>r=rrrr<>r<>psn<00><00><00><00><00><00><13>H<EFBFBD> <20> <20> <20> <20> <20> +<2B>+<2B>+<2B>+<2B> <12> <12> <12> <12><1A><1A><1A><1A><1A>rr<>c<01>0<00>eZdZddd<06>Zdd <09>Zdd <0A>Zdd<0E>ZdS)<14>MockPassiveListener<65><00>?r3r2<00>gap_sr"c<01>0<00>||_||_d|_dSr`)<03>_packs<6B>_gap_s<5F>_tick)r<>r3r<>s rrzMockPassiveListener.__init__<5F>s<00><00><1B><04> <0B><1B><04> <0B><16><04>
<EFBFBD>
<EFBFBD>
rr:rMc#<01>hK<00> |jD]<5D>}|xjdz c_|<00>|j<00><00>}t |jdd|<02><05><00>V<00>t jd<06><00>|<00>|j<00><00>}t |jdd|<03><05><00>V<00>t j|j<00><00><00><><EFBFBD><EFBFBD>)NTrRrtr<>r<>r2r<>) r<>r<><00> _build_queryrr<>r&r6<00>_build_responser<65>)r<>r~<00>qrs rrOzMockPassiveListener.frames<65>s<><00><00><00><00> (<28><1C> <0B> (<28> (<28><04><14>
<EFBFBD>
<EFBFBD>a<EFBFBD><0F>
<EFBFBD>
<EFBFBD><18>%<25>%<25>d<EFBFBD>l<EFBFBD>3<>3<><01>!<21>$<24>,<2C><14>G<EFBFBD>YZ<59>[<5B>[<5B>[<5B>[<5B>[<5B>[<5B><14>
<EFBFBD>4<EFBFBD> <20> <20> <20><18>(<28>(<28><14><1C>6<>6<><01>!<21>$<24>,<2C><14>J<EFBFBD>\]<5D>^<5E>^<5E>^<5E>^<5E>^<5E>^<5E><14>
<EFBFBD>4<EFBFBD>;<3B>'<27>'<27>'<27>'<27> (r<00>addrrrWc<01>~<00>t|dddddg<06><00>}t|<02><00>}|t|dz|dz g<02><00>zS)Nrtrr<>rZr<>)rWr<>)r<>r<>r<>r<>s rr<>z MockPassiveListener._build_query<72>sI<00><00><14>d<EFBFBD>D<EFBFBD>$<24><04>d<EFBFBD>D<EFBFBD>9<>:<3A>:<3A><04><1A>4<EFBFBD> <20> <20><03><13>e<EFBFBD>S<EFBFBD>4<EFBFBD>Z<EFBFBD><13><01><18>2<>3<>3<>3<>3rc<01>><00><05>tj|dz|jz<00><00><00><05>fd<02>td<03><00>D<00><00>}|t d<04><00>d<05><05>dd<07><00>gz }t |<02><00>dkr<|<02><00><05>dd<07><00><00><00>t |<02><00>dk<00><t|d t |<02><00>d
zg<03><00>d <0B> d <0C>|D<00><00><00><00>z}t|<03><00>}|t|d z|dz g<02><00>zS)Nrzc<01>B<00><01>g|]}d<00><02>dd<02><00>z<00><02>S)rdrer<>rtrus <20>rrDz7MockPassiveListener._build_response.<locals>.<listcomp><3E>s,<00><><00>=<3D>=<3D>=<3D>a<EFBFBD><04>s<EFBFBD>{<7B>{<7B>2<EFBFBD>q<EFBFBD>)<29>)<29>)<29>=<3D>=<3D>=rr4g<00><>@rprror<>rtrhrc3<01>FK<00>|]}tjd|dz<00><00>V<00><00>dSr{r|)rBrs rrz6MockPassiveListener._build_response.<locals>.<genexpr><3E>sC<00><00><00><00>=
<EFBFBD>=
<EFBFBD>./<2F>F<EFBFBD>K<EFBFBD><04>a<EFBFBD>&<26>j<EFBFBD> )<29> )<29>=
<EFBFBD>=
<EFBFBD>=
<EFBFBD>=
<EFBFBD>=
<EFBFBD>=
rrZr<>) r<>r<>r<>r<>r<>rhr<>r<>rWr<>r<>)r<>r<>r<>r<>r<>rks @rr<>z#MockPassiveListener._build_response<73>s!<00><><00><14>m<EFBFBD>D<EFBFBD>4<EFBFBD>K<EFBFBD>$<24>*<2A>4<>5<>5<><03>=<3D>=<3D>=<3D>=<3D>5<EFBFBD><12>9<EFBFBD>9<EFBFBD>=<3D>=<3D>=<3D><04> <0C><15>{<7B>#<23>#<23>U<EFBFBD>C<EFBFBD>K<EFBFBD>K<EFBFBD><01>3<EFBFBD>,?<3F>,?<3F>@<40>@<40><04><11>$<24>i<EFBFBD>i<EFBFBD>"<22>n<EFBFBD>n<EFBFBD> <10>K<EFBFBD>K<EFBFBD><03> <0B> <0B>A<EFBFBD>s<EFBFBD>+<2B>+<2B> ,<2C> ,<2C> ,<2C><12>$<24>i<EFBFBD>i<EFBFBD>"<22>n<EFBFBD>n<EFBFBD><14>d<EFBFBD>D<EFBFBD>#<23>d<EFBFBD>)<29>)<29>a<EFBFBD>-<2D>0<>1<>1<>C<EFBFBD>H<EFBFBD>H<EFBFBD>=
<EFBFBD>=
<EFBFBD>37<EFBFBD>=
<EFBFBD>=
<EFBFBD>=
<EFBFBD>5
<EFBFBD>5
<EFBFBD>
<EFBFBD><04><1B>4<EFBFBD> <20> <20><03><13>e<EFBFBD>S<EFBFBD>4<EFBFBD>Z<EFBFBD><13><01><18>2<>3<>3<>3<>3rN)r<>)r3r2r<>r"rQ)r<>rr:rW)rrrrrOr<>r<>rrrr<>r<><00>si<00><00><00><00><00><00><17><17><17><17><17>
(<28> (<28> (<28> (<28>4<>4<>4<>4<>
4<>
4<>
4<>
4<>
4<>
4rr<>)<04>V<>voltage<67> measurement<6E>mdi:battery-outline)<04>Ar<41>r<>zmdi:current-dc)<04>%<25>batteryr<79>zmdi:battery-70)<04>AhNr<4E>zmdi:battery-clock)NNr<4E>z mdi:counter)r<>r<>r<>zmdi:arrow-down-bold)r<>r<>r<>zmdi:arrow-up-bold)<04>mVNr<4E>z mdi:sine-wave<76>NNr<4E>z mdi:numeric)NNNzmdi:alert-octagon)NNNz mdi:alert)NNNzmdi:thermometer-alert)r<>r<>r<>r<>r<>rxryr{r|r}r<>r<>r<>r<>r<>z@dict[str, tuple[str | None, str | None, str | None, str | None]]<5D> _FIELD_META<54>!rurvrwr<>)u°C<C2B0> temperaturer<65>zmdi:thermometerr<72>)r<>r<>r<>zmdi:battery-50)NNNr<4E>)NNNzmdi:chip)NNNz mdi:calendar)r<>r<>r<>zmdi:battery-sync)NNNz
mdi:anchor)r<>r<>r<>r<>r<>r<>r<>r<>r5r<>r<>r<>r<><00> soc_estimated<65>soc_est_anchorrN<00>5tuple[str | None, str | None, str | None, str | None]c<01>f<00>|<00>d<01><00>rdSt<00>|d<03><00>S)Nr<4E>r<>)NNNN)<03>
startswithr<EFBFBD>rK<00>rNs r<00>
field_metar<EFBFBD><00>s1<00><00>
<EFBFBD>~<7E>~<7E>k<EFBFBD>"<22>"<22>:<3A>9<>9<> <16>?<3F>?<3F>3<EFBFBD> 8<> 9<> 9<>9rr<>rhr<>r<>r<>r<>r<>r<>rxrtryr{r|r}r<>r<>r<>r<>zdict[str, int]<5D>_FIELD_PRECISION<4F>rc<01>6<00>t<00>|<00><00>S)zAHow many decimals HA's frontend should render. None = HA default.)r<>rKr<>s r<00>field_precisionr<6E>s<00><00> <1B> <1F> <1F><03> $<24> $<24>$rc<01>@<00>eZdZddd<06>Zdd <0A>Zdd<11>Zdd<12>Zdd<14>Zdd<15>ZdS)<1D> MQTTPublisherF<72>cfgr'<00>dry_runr6c<01><><00>||_||_d|_t<00><00>|_t j<00><00>|_|s<>tj tj
j d<01><02><00>}|<03> |j |j<00><00>|<03>|j|jd<03><04><00>|<03><00><00>||_t&<00>d|j|j<00><00>dSdS)Nr )<01> client_id<69><)<01> keepalivezconnected to MQTT %s:%d)<15>_cfg<66>_dry_run<75>_client<6E>set<65> _discoveredr&r'<00>_last_discovery_republish_atr1<00>Client<6E>CallbackAPIVersion<6F>VERSION2<4E>username_pw_setr)r*<00>connectr(r<00>
loop_startr*<00>info)r<>r<>r<><00>cs rrzMQTTPublisher.__init__ s<><00><00><17><04> <09><1F><04> <0A>+/<2F><04> <0C>14<31><15><15><04><18>37<33>><3E>3C<33>3C<33><04>)<29><16> D<01><14> <0B>D<EFBFBD>3<><<3C> <0A>V<>V<>V<>A<EFBFBD> <0A> <1D> <1D>c<EFBFBD>l<EFBFBD>C<EFBFBD>L<EFBFBD> 9<> 9<> 9<> <0A>I<EFBFBD>I<EFBFBD>c<EFBFBD>h<EFBFBD><03><08>B<EFBFBD>I<EFBFBD> 7<> 7<> 7<> <0A>L<EFBFBD>L<EFBFBD>N<EFBFBD>N<EFBFBD>N<EFBFBD><1C>D<EFBFBD>L<EFBFBD> <0F>H<EFBFBD>H<EFBFBD>.<2E><03><08>#<23>(<28> C<> C<> C<> C<> C<>  D<01> Dr<00> pack_namer <00>readingsr`r:rc<01>h<00>|<02><00><00>D]\}}|<00>|||<04><00><00>dSr
)<02>items<6D> _publish_one)r<>r<>r<>rN<00>values r<00> publish_packzMQTTPublisher.publish_packsD<00><00>"<22>.<2E>.<2E>*<2A>*<2A> 5<> 5<>J<EFBFBD>C<EFBFBD><15> <10> <1D> <1D>i<EFBFBD><13>e<EFBFBD> 4<> 4<> 4<> 4<> 5<> 5rrNr<>rc<01><><00>|<01>d|<02><00>}|jj<00>d|<04>d<03>}||f}||jvr1|<00>|||<05><00>|j<00>|<06><00>t |t tf<02><00>rtj |<03><00>nt|<03><00>}|j rtd|<05>d|<07><00><04><00>dS|j <00>||dd<06><07><00>dS)Nr<4E><00>/sensor/<2F>/state<74> rF<><02>qos<6F>retain)r<>r,r<><00>_publish_discovery<72>add<64>
isinstancerI<00>list<73>json<6F>dumpsr r<><00>printr<74><00>publish)r<>r<>rNr<><00> entity_id<69> state_topic<69> disco_keyrms rr<>zMQTTPublisher._publish_ones<><00><00> <20>(<28>(<28>3<EFBFBD>(<28>(<28> <09><1D><19>3<>N<>N<>Y<EFBFBD>N<>N<>N<> <0B><1E><03>$<24> <09> <14>D<EFBFBD>,<2C> ,<2C> ,<2C> <10> #<23> #<23>I<EFBFBD>s<EFBFBD>K<EFBFBD> @<40> @<40> @<40> <10> <1C> <20> <20><19> +<2B> +<2B> +<2B>'1<>%<25>$<24><04><1C>'F<>'F<>V<>$<24>*<2A>U<EFBFBD>#<23>#<23>#<23>C<EFBFBD>PU<50>J<EFBFBD>J<EFBFBD><07> <0F>=<3D> L<01> <11>/<2F>{<7B>/<2F>/<2F>g<EFBFBD>/<2F>/<2F> 0<> 0<> 0<> 0<> 0<> <10>L<EFBFBD> <20> <20><1B>g<EFBFBD>1<EFBFBD>U<EFBFBD> <20> K<> K<> K<> K<> Krc<01>\<00>|jj}|dks|jsdStj<00><00>}||jz
|krdS|jD]1\}}|jj<00>d|<03>d|<04>d<05>}|<00>|||<05><00><00>2||_t<00> dt|j<00><00><00><00>dS)z<>Heartbeat: re-emit every previously sent discovery config if the
configured interval has elapsed. Idempotent (retain=True), so HA
re-picks up any registrations it has lost without operator action.rNr<4E>r<>r<>z-re-published %d discovery configs (heartbeat)) r<>r-r<>r&r'r<>r,r<>r*r<>r<>)r<><00>interval<61>nowr<77>rNr<>s r<00>maybe_republish_discoveryz'MQTTPublisher.maybe_republish_discovery,s<><00><00><18>9<EFBFBD>;<3B><08> <13>q<EFBFBD>=<3D>=<3D><04> 0<>=<3D> <12>F<EFBFBD><12>n<EFBFBD><1E><1E><03> <0E><14>2<> 2<>X<EFBFBD> =<3D> =<3D> <12>F<EFBFBD>"<22>.<2E> A<01> A<01>N<EFBFBD>I<EFBFBD>s<EFBFBD>!<21>Y<EFBFBD>7<>X<>X<><19>X<>X<>S<EFBFBD>X<>X<>X<>K<EFBFBD> <10> #<23> #<23>I<EFBFBD>s<EFBFBD>K<EFBFBD> @<40> @<40> @<40> @<40>,/<2F><04>)<29> <0B><08><08>@<40>#<23>d<EFBFBD>FV<46>BW<42>BW<42>X<>X<>X<>X<>Xrr<>c<01><><00>t|<02><00>\}}}}|<01>d|<02><00>||<01>d|<02>d<03>d|<01><00>|gddd<07>d<08>}|<04>||d <|<05>||d
<|<06>||d <|<07>||d <t|<02><00>} | <09>| |d <|jj<00>d|<01>d|<02>d<0F>}
t j|<08><00>} |jrtd|
<EFBFBD>d| <0B><00><04><00>dS|j<00> |
| dd<13><14><00>dS)Nrdr<><00>_eg4zEG4 LifePower4 z'LifePower4 48V 100Ah v2 Auto-AddressingzEG4 Electronics)r <00> identifiersr<73><00> manufacturer)r r<><00> unique_id<69>device<63>unit_of_measurement<6E> device_class<73> state_class<73>icon<6F>suggested_display_precisionr<6E>z/configz [discovery] r<>rTr<54>)
r<EFBFBD>r<>r<>r,r<>r<>r<>r<>r<>r<>) r<>r<>rNr<><00>unitr<74>r<>r<>r<><00> precision<6F>topicrms rr<>z MQTTPublisher._publish_discovery<sJ<00><00>0:<3A>3<EFBFBD><0F><0F>-<2D><04>l<EFBFBD>K<EFBFBD><14> <20>(<28>(<28>3<EFBFBD>(<28>(<28>&<26>%<25>1<>1<><03>1<>1<>1<>5<>)<29>5<>5<> )<29>{<7B>B<> 1<> <0E><0E>

<EFBFBD>

<EFBFBD><03> <10> <1B>$<24>S<EFBFBD>)><3E>%?<3F> <17> #<23><<3C>S<EFBFBD><1E>%8<> <16> "<22>+<2B>S<EFBFBD><1D>%7<> <0F> <1B>4<EFBFBD>S<EFBFBD><16>[<5B>#<23>C<EFBFBD>(<28>(<28> <09> <14> <20>)<29>S<EFBFBD>)F<>%G<><17>9<EFBFBD>-<2D>O<>O<>y<EFBFBD>O<>O<>3<EFBFBD>O<>O<>O<><05><16>*<2A>S<EFBFBD>/<2F>/<2F><07> <0F>=<3D> E<01> <11>5<>5<EFBFBD>5<>5<>G<EFBFBD>5<>5<> 6<> 6<> 6<> 6<> 6<> <10>L<EFBFBD> <20> <20><15><07>Q<EFBFBD>t<EFBFBD> <20> D<> D<> D<> D<> Drc<01>|<00>|j<00>4|j<00><00><00>|j<00><00><00>dSdSr
)r<><00> loop_stop<6F>
disconnectrs rr=zMQTTPublisher.closeVs@<00><00> <0F><<3C> #<23> <10>L<EFBFBD> "<22> "<22> $<24> $<24> $<24> <10>L<EFBFBD> #<23> #<23> %<25> %<25> %<25> %<25> %<25> $<24> #rN<>F)r<>r'r<>r6)r<>r r<>r`r:r)r<>r rNr r<>rr:rr>)r<>r rNr r<>r r:r) rrrrr<>r<>r<>r<>r=rrrr<>r<> s<><00><00><00><00><00><00> D<01> D<01> D<01> D<01> D<01>5<>5<>5<>5<> L<01> L<01> L<01> L<01>Y<01>Y<01>Y<01>Y<01> E<01>E<01>E<01>E<01>4&<26>&<26>&<26>&<26>&<26>&rr<>c<01>r<00>eZdZUdZded<dZded<dZded <dZded
<dZded <d Z d ed<d Z
d ed<d S)<10>
_PackStateFr6<00>okrr <00>last_error_categoryrr<00>consecutive_errors<72>response_count<6E>first_seen_loggedNz float | None<6E>soc_est<73> last_est_ts) rrrrrr r
r r r rrrrrras<><00><00><00><00><00><00><00><14>B<EFBFBD><14><14><14><14>!<21><17>!<21>!<21>!<21>!<21><1F><16><1F><1F><1F><1F><1B>N<EFBFBD><1B><1B><1B><1B>#<23><15>#<23>#<23>#<23>#<23> <20>G<EFBFBD> <20> <20> <20> <20> $<24>K<EFBFBD>$<24>$<24>$<24>$<24>$<24>$rrihrg<>G<EFBFBD>z<14><>?g<><67><EFBFBD><EFBFBD><EFBFBD><EFBFBD> @g@g@g<00>r@)r<><00> coulombic_eff<66>v_full<6C>i_taper<65>soc_full<6C>v_empty<74> soc_empty<74> max_gap_sr<73><00>st<73> '_PackState'r<>r"r<>rIrc<01><00>|<00>d<01><00>}|<04>dS|<00>d<03><00>}|<00>d<04><00>}|j<00>4|<00>d<05><00>}|<07>t|<07><00>nd|_||_|j<00>dnt ||jz
|d<00><00>}||_|d kr5|d kr|d
nd } |xj|| z|zd z |d z dzz c_d}
|<05>3d|cxkr |dkr nn||dkr|ddc|_}
n|<06>||dkr|ddc|_}
t dt d|j<00><00><00><00>|_t |jd<17><00>|d<|
|d<dS)z<>Add `soc_estimated` + `soc_est_anchor` to `readings`, coulomb-counting
pack_current between cycles and re-anchoring at full / empty. No-op for the
cycle if pack_current is missing (can't integrate).r<>Nryrxr<>gI@<40>rrrrg <20>@r<>r<00>coulombrrr<00>fullrr<00>emptyrRr<>r<>)rKr r"rr<>r<>r<>) r<>rr<>r<><00>curr<72>r<><00>bms<6D>dt<64>eff<66>anchors r<00> estimate_socr"<00>s<><00><00>
<13>,<2C>,<2C>~<7E>
&<26>
&<26>C<EFBFBD>
<EFBFBD>{<7B><0E><06> <13><<3C><<3C>*<2A> +<2B> +<2B>D<EFBFBD> <13><<3C><<3C>*<2A> +<2B> +<2B>D<EFBFBD> <09>z<EFBFBD><19><16>l<EFBFBD>l<EFBFBD>5<EFBFBD>!<21>!<21><03>#&<26>?<3F>U<EFBFBD>3<EFBFBD>Z<EFBFBD>Z<EFBFBD>Z<EFBFBD><04><02>
<EFBFBD><1C><02><0E><12><0E>&<26><13><13>C<EFBFBD><03>b<EFBFBD>n<EFBFBD>0D<30>c<EFBFBD>+<2B>FV<46>,W<>,W<>B<EFBFBD><18>B<EFBFBD>N<EFBFBD> <09>A<EFBFBD>v<EFBFBD>v<EFBFBD>&)<29>A<EFBFBD>g<EFBFBD>g<EFBFBD>c<EFBFBD>/<2F>"<22>"<22>3<EFBFBD><03>
<EFBFBD>
<EFBFBD>
<EFBFBD>s<EFBFBD>S<EFBFBD>y<EFBFBD>2<EFBFBD>~<7E><06>.<2E>#<23>m<EFBFBD>2D<32>D<>u<EFBFBD>L<>L<>
<EFBFBD>
<EFBFBD> <16>F<EFBFBD> <0B><17>C<EFBFBD>3<EFBFBD>7<>7<>7<>7<><13>Y<EFBFBD><1E>7<>7<>7<>7<>7<>D<EFBFBD>C<EFBFBD><08>M<EFBFBD><Q<><Q<> <20><1A>_<EFBFBD>f<EFBFBD><1A><02>
<EFBFBD>F<EFBFBD>F<EFBFBD> <0A> <19>d<EFBFBD>c<EFBFBD>)<29>n<EFBFBD>4<>4<> <20><1B>-<2D>w<EFBFBD><1A><02>
<EFBFBD>F<EFBFBD><14>S<EFBFBD>#<23>e<EFBFBD>R<EFBFBD>Z<EFBFBD>0<>0<>1<>1<>B<EFBFBD>J<EFBFBD> %<25>b<EFBFBD>j<EFBFBD>!<21> 4<> 4<>H<EFBFBD>_<EFBFBD><1D>!'<27>H<EFBFBD> <1D><1E><1E>rr<>r3r2c<01>@<00>|D]}|j|kr |jcS<00>d|d<02><04>S)N<>lifepower4_addr_<72>02x)rr )r<>r3rCs r<00>_resolve_pack_namer&<00>s?<00><00> <12><1A><1A><01> <0C>9<EFBFBD><04> <1C> <1C><14>6<EFBFBD>M<EFBFBD>M<EFBFBD>M<EFBFBD> <1D> (<28>d<EFBFBD> (<28> (<28> (<28>(rr<00> publisher<65>states<65>dict[str, _PackState]<5D> one_cyclec <01><><00> tj<00><00>}|jD<00>]<5D>}|<03>|jt <00><00><00><00>} |<00>|j<00><00>}|std|jd<03><04><02><00><00>t||j
<00><04><00>} |<01> |j| <09><00>|xj dz c_ |j s7|jdkr,t<00>d|j|j|j<00><00>d|_ d|_<00><>#t"$r<>}
t%|
<EFBFBD><00>j<00>dt)|
<EFBFBD><00><00>dd<05><00>d<00><00>} |j s | |jkr(t<00>d |j|j|
<EFBFBD><00>nK|jdkr@|jt0zdkr-t<00>d
|j|j|j|
<EFBFBD><00>d |_ | |_|xjdz c_Yd }
~
<EFBFBD><01><>d }
~
wwxYw|<01><00><00>|rd Stj<00><00>|z
} tjt7d |jj| z
<00><00><00><00><00><02>a)z?Round-robin poll every configured pack; rate-limit error noise.Tzempty response from addr=0xr%<00>r5rRrz4pack %s (0x%02x): recovered after %d failed cycle(s)<29>:<3A>pack %s (0x%02x): %s<>/pack %s (0x%02x): still failing (%d cycles): %sFNr)r&r'r3<00>
setdefaultr rrErr,r<>r5r<>r rr
r*r<><00> Exception<6F>typerr <00>splitr <00>warning<6E>_FAIL_HEARTBEAT_CYCLESr<53>r6r<>r0r%) rr'r<>r(r*<00> cycle_startr~rrLr<><00>e<>category<72>elapseds r<00>
run_activer:<00>s<00><00>@<01><1A>n<EFBFBD>&<26>&<26> <0B><17>I<EFBFBD> +<2B> +<2B>D<EFBFBD><17>"<22>"<22>4<EFBFBD>9<EFBFBD>j<EFBFBD>l<EFBFBD>l<EFBFBD>;<3B>;<3B>B<EFBFBD> +<2B><1F>-<2D>-<2D>d<EFBFBD>l<EFBFBD>;<3B>;<3B><03><1A>Y<01>&<26>'W<>T<EFBFBD>\<5C>'W<>'W<>'W<>X<>X<>X<>4<>S<EFBFBD>S<EFBFBD>^<5E>T<>T<>T<><08><19>&<26>&<26>t<EFBFBD>y<EFBFBD>(<28>;<3B>;<3B>;<3B><12>!<21>!<21>Q<EFBFBD>&<26>!<21>!<21><19>u<EFBFBD>M<01><12>!6<><11>!:<3A>!:<3A><17>H<EFBFBD>H<EFBFBD>S<>!<21>Y<EFBFBD><04> <0C>b<EFBFBD>6K<36>M<01>M<01>M<01><1C><02><05>()<29><02>%<25>%<25><><1C> +<2B> +<2B> +<2B>"<22>1<EFBFBD>g<EFBFBD>g<EFBFBD>.<2E>J<>J<><13>Q<EFBFBD><16><16><1C><1C>c<EFBFBD>1<EFBFBD>1E<31>1E<31>a<EFBFBD>1H<31>J<>J<><08><15>5<EFBFBD>S<01>H<EFBFBD><02>(><3E>><3E>><3E><17>K<EFBFBD>K<EFBFBD> 6<><04> <09>4<EFBFBD><<3C>QR<51>S<>S<>S<>S<><17>*<2A>Q<EFBFBD>.<2E>.<2E>2<EFBFBD>3H<33>Ka<4B>3a<33>ef<65>3f<33>3f<33><17>K<EFBFBD>K<EFBFBD> Q<> $<24> <09>4<EFBFBD><<3C><12>9N<39>PQ<50>S<01>S<01>S<01><1D><02><05>)1<><02>&<26><12>%<25>%<25><11>*<2A>%<25>%<25>%<25>%<25>%<25>%<25>%<25><><EFBFBD><EFBFBD><EFBFBD> +<2B><><EFBFBD><EFBFBD> <12>+<2B>+<2B>-<2D>-<2D>-<2D> <14> <13> <12>F<EFBFBD><16>.<2E>"<22>"<22>[<5B>0<><07> <0C>
<EFBFBD>3<EFBFBD>s<EFBFBD>C<EFBFBD>G<EFBFBD>3<>g<EFBFBD>=<3D>><3E>><3E>?<3F>?<3F>?<3F>=@s<00>CD <02>
H<05>C#G<<05><H<05>listener<65>trace<63>
max_framesc
<01>`<00>i}t<00><00>}d<01>|jD<00><00>}d}|<00><00><00>D<00>]<5D>} |dz }|<01><00><00>|r4t<00>d| | j<00>d<05><00><00><00>| jdks | j dkr |<04> ||krdS<00>t|<05>
| j t<00><00><00><00>}
|
xj dz c_ |
js<>| j |vr:t<00>d | j t!| j |j<00><00><00><00>n\| j |vrSt<00>d
| j t!| j |j<00><00><00><00>|<06>| j <00><00>d |
_ t'| <09><00>} nR#t($rE} t<00>d | j | | j<00>d<05><00><00><00>Yd} ~ <0C><01><>d} ~ wwxYw|<01>t!| j |j<00><00>| <0B><00>|<04> ||krdS<00><01><>dS) zAConsume frames as they arrive; publish on every fn=0x03 response.c<01><00>h|] }|j<00><02>
Sr)rrAs r<00> <setcomp>zrun_passive.<locals>.<setcomp><3E>s<00><00>/<2F>/<2F>/<2F><01>!<21>)<29>/<2F>/<2F>/rrrRz %r raw=%srdr<>rtNz/first response from configured pack 0x%02x (%s)u=response from unconfigured slave 0x%02x — auto-naming as %sTz*decode failed for addr 0x%02x: %s (raw=%s))r<>r3rOr<>r*r+rLr<>r<>r<>r0rrr r r<>r&r4r<>r<>r1r<>) r;r'r<>r<r=r(<00>seen_unconfigured<65>
configured<EFBFBD>nr<6E>rr<>r7s r<00> run_passiverD<00>sP<00><00>%'<27>F<EFBFBD>"%<25>%<25>%<25><15>/<2F>/<2F>S<EFBFBD>Y<EFBFBD>/<2F>/<2F>/<2F>J<EFBFBD> <09>A<EFBFBD><19><1F><1F>"<22>"<22><13><13><05> <09>Q<EFBFBD><06><01><11>+<2B>+<2B>-<2D>-<2D>-<2D> <10> ><3E> <0F>I<EFBFBD>I<EFBFBD>k<EFBFBD>5<EFBFBD>%<25>)<29>-<2D>-<2D><03>*<<3C>*<<3C> =<3D> =<3D> =<3D> <10>:<3A><1A> #<23> #<23>u<EFBFBD>~<7E><14>'=<3D>'=<3D><19>%<25>!<21>z<EFBFBD>/<2F>/<2F><16><06><06> <14> <13> <1E> <1E>u<EFBFBD>}<7D>j<EFBFBD>l<EFBFBD>l<EFBFBD> ;<3B> ;<3B><02>
<EFBFBD><19><19>Q<EFBFBD><1E><19><19><11>#<23> (<28><14>}<7D>
<EFBFBD>*<2A>*<2A><13><08><08>J<><1E><1D>(:<3A>5<EFBFBD>=<3D>#<23>)<29>(T<>(T<>V<01>V<01>V<01>V<01><16><1D>&7<>7<>7<><13> <0B> <0B>[<5B>!<21>M<EFBFBD>+=<3D>e<EFBFBD>m<EFBFBD>S<EFBFBD>Y<EFBFBD>+W<>+W<>Y<01>Y<01>Y<01>!<21>%<25>%<25>e<EFBFBD>m<EFBFBD>4<>4<>4<>#'<27>B<EFBFBD> <20> <15>-<2D>e<EFBFBD>4<>4<>H<EFBFBD>H<EFBFBD><48><18> <15> <15> <15> <0F>K<EFBFBD>K<EFBFBD>D<><1D> <0A>q<EFBFBD>%<25>)<29>-<2D>-<2D><03>*<<3C>*<<3C> ><3E> ><3E> ><3E> <14>H<EFBFBD>H<EFBFBD>H<EFBFBD>H<EFBFBD><48><EFBFBD><EFBFBD><EFBFBD> <15><><EFBFBD><EFBFBD> <12><1E><1E>1<>%<25>-<2D><13><19>K<>K<>X<EFBFBD>V<>V<>V<> <15> !<21>a<EFBFBD>:<3A>o<EFBFBD>o<EFBFBD> <12>F<EFBFBD>F<EFBFBD><46>;<13>s<00>F!<02>!
G0<05>+:G+<05>+G0r<>c <01><><00><00><04>i}i}d<12><00>fd<05> }<07>jD]}||<08><00>} | <09>
| ||j<<00> tj<00><00>}
<EFBFBD>jD<00>]^}|<02>|jt <00><00><00><00>} <00>rG|<06>|jd<08><00>d z||j<t|j||j<00><00>} n?|j|vrtd
|j<00><00><02><00><00>||j<00>
<00><00>} t| <0C>j <00> <0B><00>} <0A>j r"t| | tj<00><00><00><00>|<01>|j| <0A><00>| xjd z c_| js1| jdkr&t&<00>d |j| j<00><00>d| _d| _<00><01>e#t*$r<>}t-|<0E><00>j<00>d t1|<0E><00><00>d d <09><00>d<00><00>}| js || jkr(t&<00>d|j|j|<0E><00>nK| jdkr@| jt8zdkr-t&<00>d|j|j| j|<0E><00>d| _|| _| xjd z c_Yd}~<0E><02>Xd}~wwxYw|<01><00><00>|r. |<05><00><00>D]} | <09><00><00><00>dStj<00><00>|
z
}tj tCd<11>j"j#|z
<00><00><00><00><00><03>#|<05><00><00>D]} | <09><00><00><00>wxYw)z<>One adapter per pack. Each `PackConfig` must have `port` and `baud`
set. Round-robin poll every pack on its own serial port; decode
Modbus response into named HA entities + raw register_NN dump.rCr r:<00>ModbusActivePoller | Nonec<01>P<00><02><00>rdS|js"t<00>d|j<00><00>dS|jp <0B>jj} t |j||j<00>jj<00><00>S#t$r2}t<00>d|j|j|<02><00>Yd}~dSd}~wwxYw)Nz*pack %s: no `port` set in config; skippingzpack %s: could not open %s: %s)
rr*r4r rr0rrr#r1)rCrr7r<>r<>s <20><>r<00> make_pollerz(run_modbus_per_pack.<locals>.make_pollers<><00><><00> <12> <18><17>4<EFBFBD><10>v<EFBFBD> <18> <0F>K<EFBFBD>K<EFBFBD>D<>a<EFBFBD>f<EFBFBD> M<> M<> M<><17>4<EFBFBD><10>v<EFBFBD>%<25><13><17><1C><04> <18>%<25>a<EFBFBD>f<EFBFBD>d<EFBFBD>A<EFBFBD>I<EFBFBD>s<EFBFBD>w<EFBFBD>?P<>Q<>Q<> Q<><51><18> <18> <18> <18> <0F>K<EFBFBD>K<EFBFBD>8<>!<21>&<26>!<21>&<26>!<21> L<> L<> L<><17>4<EFBFBD>4<EFBFBD>4<EFBFBD>4<EFBFBD>4<EFBFBD><34><EFBFBD><EFBFBD><EFBFBD> <18><><EFBFBD>s<00>%A)<00>)
B%<03>3'B <03> B%NTrrRzno poller configured for )r<>z+pack %s: recovered after %d failed cycle(s)r-r.r/Fr)rCr r:rF)$r3r r&r'r0rrK<00>_mock_modbus_regsrr,r;r<>r7r8r"r<>r rr
r*r<>r1r2rr r3r r4r5r<>rxr=r6r<>r0r%)r<>r'r(r*r<><00>pollers<72>mock_regs_callrHrC<00>plr6rr<>r<>r7r8r9s` ` r<00>run_modbus_per_packrM<00>s<><00><><EFBFBD><00> .0<EFBFBD>G<EFBFBD>%'<27>N<EFBFBD> <18> <18> <18> <18> <18> <18> <18><11>Y<EFBFBD>!<21>!<21><01> <18>[<5B><11>^<5E>^<5E><02> <0A>><3E> <20>G<EFBFBD>A<EFBFBD>F<EFBFBD>O<EFBFBD><4F>)<17>% D<01><1E>.<2E>*<2A>*<2A>K<EFBFBD><18>Y<EFBFBD> /<2F> /<2F><01><1B>&<26>&<26>q<EFBFBD>v<EFBFBD>z<EFBFBD>|<7C>|<7C><<3C><<3C><02>/<2F><1E>6<>1?<3F>1C<31>1C<31>A<EFBFBD>F<EFBFBD>A<EFBFBD>1N<31>1N<31>QR<51>1R<31><0E>q<EFBFBD>v<EFBFBD>.<2E>0<><11><19>N<EFBFBD>1<EFBFBD>6<EFBFBD><R<>S<>S<><04><04><1C>6<EFBFBD><17>0<>0<>".<2E>/S<>1<EFBFBD>6<EFBFBD>/S<>/S<>"T<>"T<>T<>&<26>q<EFBFBD>v<EFBFBD><EFBFBD>3<>3<>5<>5<><04>5<>d<EFBFBD>s<EFBFBD>G_<47>`<60>`<60>`<60>H<EFBFBD><1A>(<28>E<01>$<24>X<EFBFBD>r<EFBFBD>4<EFBFBD>><3E>3C<33>3C<33>D<>D<>D<><1D>*<2A>*<2A>1<EFBFBD>6<EFBFBD>8<EFBFBD><<3C><<3C><<3C><16>%<25>%<25><11>*<2A>%<25>%<25><1D>5<EFBFBD>@<01>R<EFBFBD>%:<3A>Q<EFBFBD>%><3E>%><3E><1B><08><08>!N<>!"<22><16><12>)><3E>@<01>@<01>@<01> <20>B<EFBFBD>E<EFBFBD>,-<2D>B<EFBFBD>)<29>)<29><> <20>
/<2F>
/<2F>
/<2F>"&<26>q<EFBFBD>'<27>'<27>"2<>N<>N<>S<EFBFBD><11>V<EFBFBD>V<EFBFBD>\<5C>\<5C>#<23>q<EFBFBD>5I<35>5I<35>!<21>5L<35>N<>N<>H<EFBFBD><19>u<EFBFBD>Q<01><08>B<EFBFBD>,B<> B<> B<><1B> <0B> <0B>$:<3A>A<EFBFBD>F<EFBFBD>A<EFBFBD>I<EFBFBD>q<EFBFBD>Q<>Q<>Q<>Q<><1B>.<2E><11>2<>2<> "<22> 5<>8N<38> N<>RS<52> S<> S<><1B> <0B> <0B>$U<>$%<25>F<EFBFBD>A<EFBFBD>I<EFBFBD>r<EFBFBD>7L<37>a<EFBFBD>Q<01>Q<01>Q<01>!<21>B<EFBFBD>E<EFBFBD>-5<>B<EFBFBD>*<2A><16>)<29>)<29>Q<EFBFBD>.<2E>)<29>)<29>)<29>)<29>)<29>)<29>)<29><><EFBFBD><EFBFBD><EFBFBD>
/<2F><><EFBFBD><EFBFBD> <16> /<2F> /<2F> 1<> 1<> 1<><18> <17><16><1A>.<2E>.<2E>"<22>"<22> <17> <17>B<EFBFBD> <0E>H<EFBFBD>H<EFBFBD>J<EFBFBD>J<EFBFBD>J<EFBFBD>J<EFBFBD> <17> <17><1B>n<EFBFBD>&<26>&<26><1B>4<>G<EFBFBD> <10>J<EFBFBD>s<EFBFBD>3<EFBFBD><03><07> 7<>'<27> A<>B<>B<> C<> C<> C<>K% D<01><>N<1A>.<2E>.<2E>"<22>"<22> <17> <17>B<EFBFBD> <0E>H<EFBFBD>H<EFBFBD>J<EFBFBD>J<EFBFBD>J<EFBFBD>J<EFBFBD> <17><><EFBFBD>s?<00>AL6<00>6D8F0<02>.L6<00>0
J(<05>:C#J#<05>L6<00>#J(<05>(L6<00>/AL6<00>6-M#<03>tickc<01><00><07><08>tj|dz|z<00><00><00>d<02><08>dd<04><00>z<00><07><07>fd<05>td<06><00>D<00><00>}dgdz}t |<02><00>d z|d<d
<EFBFBD><08>d d <0C><00>z
d z|d<t |d<0F><10><00>D]
\}}|||<<00> d<11><08>dd<0E><00>z|d<d<11><08>dd<0E><00>z|d<d<15><08>dd<0E><00>z|d<d<16><08>dd<0E><00>z|d<d|d<d|d<d|d<d|d<d|d<d|d <d|d!<d|d"<d|d#<d|d$<d|d%<|d&zd z|d'<d7d0<64>}||d1d2<64><00>||d3d4<64><00>||d5d6<64><00>|S)8z<38>Synthesise 136 realistic-looking registers for dry-run mode (covers
both block 1 [0..38] and block 2 [45..135] reads of the live daemon).rzrdrsrtc<01>B<00><02>g|]}<01><02><03>dd<01><00>z<00><02>S)rgr<>rtris <20><>rrDz%_mock_modbus_regs.<locals>.<listcomp>Ks,<00><><00>@<40>@<40>@<40><11><07>#<23>+<2B>+<2B>b<EFBFBD>!<21>,<2C>,<2C>,<2C>@<40>@<40>@rr4r<00><>rgr~rlrmr<>rRrhrrr<>rcr<>r<>r<><00>6ror<>r<><00>7r<><00>iu<00>i*r<>r<><00>"r<>r<>r<>r<><00>.<00>targetr<74><00>offsetr<00>sr r:rc<01><><00>tdt|<02><00>d<02><00>D]X}t||<00><00>}|dzt|<02><00>krt||dz<00><00>nd}|dz|z|||dzz<<00>YdS)NrrhrRr<>)r<>r<><00>ord)rXrYrZr<><00>hi<68>los r<00> _pack_strz$_mock_modbus_regs.<locals>._pack_strcs<><00><00><16>q<EFBFBD>#<23>a<EFBFBD>&<26>&<26>!<21>$<24>$<24> 5<> 5<>A<EFBFBD><14>Q<EFBFBD>q<EFBFBD>T<EFBFBD><19><19>B<EFBFBD>"#<23>a<EFBFBD>%<25>#<23>a<EFBFBD>&<26>&<26>.<2E>.<2E><13>Q<EFBFBD>q<EFBFBD>1<EFBFBD>u<EFBFBD>X<EFBFBD><1D><1D><1D>a<EFBFBD>B<EFBFBD>')<29>Q<EFBFBD>w<EFBFBD>"<22>n<EFBFBD>F<EFBFBD>6<EFBFBD>A<EFBFBD><11>F<EFBFBD>?<3F> #<23> #<23> 5<> 5rr<>zLFP-51.2V100Ah-V1.0r<EFBFBD><00>Z03T21re<00>20260206)rXr<>rYrrZr r:r)r<>r<>rhr<>r<>r<>) rrNr<>r<>r<><00>mvr_rjrks @@rrIrIFs<00><><EFBFBD><00> <11>-<2D><07>$<24><0E><14>-<2D>
.<2E>
.<2E>C<EFBFBD><12>S<EFBFBD>[<5B>[<5B><12>Q<EFBFBD>'<27>'<27>'<27>G<EFBFBD>@<40>@<40>@<40>@<40>@<40>e<EFBFBD>B<EFBFBD>i<EFBFBD>i<EFBFBD>@<40>@<40>@<40>H<EFBFBD><18>c<EFBFBD>C<EFBFBD>i<EFBFBD>D<EFBFBD><12>8<EFBFBD>}<7D>}<7D><02>"<22>D<EFBFBD><11>G<EFBFBD><15><03> <0B> <0B>D<EFBFBD>$<24>/<2F>/<2F>/<2F>6<EFBFBD>9<>D<EFBFBD><11>G<EFBFBD><1A>8<EFBFBD>1<EFBFBD>-<2D>-<2D>-<2D><15><15><05><01>2<EFBFBD><14><04>Q<EFBFBD><07><07><11>C<EFBFBD>K<EFBFBD>K<EFBFBD><02>A<EFBFBD>&<26>&<26>&<26>D<EFBFBD><12>H<EFBFBD><11>C<EFBFBD>K<EFBFBD>K<EFBFBD><02>A<EFBFBD>&<26>&<26>&<26>D<EFBFBD><12>H<EFBFBD><11>C<EFBFBD>K<EFBFBD>K<EFBFBD><02>A<EFBFBD>&<26>&<26>&<26>D<EFBFBD><12>H<EFBFBD><11>C<EFBFBD>K<EFBFBD>K<EFBFBD><02>A<EFBFBD>&<26>&<26>&<26>D<EFBFBD><12>H<EFBFBD><12>D<EFBFBD><12>H<EFBFBD><12>D<EFBFBD><12>H<EFBFBD><11>D<EFBFBD><12>H<EFBFBD><10>D<EFBFBD><12>H<EFBFBD><13>D<EFBFBD><12>H<EFBFBD><14>D<EFBFBD><12>H<EFBFBD><10>D<EFBFBD><12>H<EFBFBD><10>D<EFBFBD><12>H<EFBFBD><10>D<EFBFBD><12>H<EFBFBD><11>D<EFBFBD><12>H<EFBFBD><13>D<EFBFBD><12>H<EFBFBD><14>q<EFBFBD><08>F<EFBFBD>"<22>D<EFBFBD><12>H<EFBFBD>5<>5<>5<>5<> <0E>I<EFBFBD>d<EFBFBD>C<EFBFBD>.<2E>/<2F>/<2F>/<2F> <0A>I<EFBFBD>d<EFBFBD>C<EFBFBD><18>"<22>"<22>"<22> <0A>I<EFBFBD>d<EFBFBD>C<EFBFBD><1A>$<24>$<24>$<24> <0F>Krc
<01><><00>tjd<01><02><00>}|<00>dddt<00><06><00>|<00>ddd <09>
<EFBFBD><00>|<00>d dd <0C>
<EFBFBD><00>|<00><00><00>}t j|jr t
jn t
j d <0A><0E><00>t|j <00><00>}hd<0F>}|j j |vrtd|<03>d|j j <00><02><04><00><00>|j jdvrtd|j j<00><02><02><00><00>t!|j|j<00><14><00>}t&<00>d|j j t+|j<00><00><00><00>|jp|j jdk} |j j dkr t/||i|j|j<00><18><00><00>nI|j j dkr<>|rt1|j<00><1A><00>n.t5|j j|j j|j j<00><00>} t=|||i|j<00><1B><00>|<06><00><00>n<>#|<06><00><00>wxYw|rtA|j<00><00>n.tC|j j|j j|j j"<00><00>} tG||||j|jrdt+|j<00><00>znd<00><1D><00>|<07><00><00>n#|<07><00><00>wxYw |<04><00><00>dS#tH$rY|<04><00><00>dSwxYw#|<04><00><00>wxYw)Nu"EG4 LifePower4 v2 → MQTT bridge.)<01> descriptionz-Cz--configT)<02>requiredr2z --dry-run<75>
store_trueu/Mock-bus smoke test — one cycle, print, exit.)<02>action<6F>helpz--tracezLog every frame.z/%(asctime)s %(levelname)s %(name)s: %(message)s)<02>level<65>format><00>active<76>passive<76>modbus_per_packzbus.mode must be one of z, got ><00>mockrz.bus.transport must be 'serial' or 'mock', got )r<>z3eg4-battery starting: mode=%s %d configured pack(s)rnrm)r(r*r<>rkr,)r(r*rh)r<r=r)%<25>argparse<73>ArgumentParser<65> add_argumentr<00>
parse_args<EFBFBD>logging<6E> basicConfigr<<00>DEBUG<55>INFOrQ<00>configr0r<00>
SystemExitrr<>r1r<>r*r<>r<>r3rMr^r5rSrrr#r:r=r<>r<>r!rD<00>KeyboardInterrupt)<08>ap<61>argsr<73><00> valid_modesr'<00>use_mockrr;s r<00>mainr~osx<00><00> <11> <20>8<>
:<3A>
:<3A>
:<3A>B<EFBFBD><06>O<EFBFBD>O<EFBFBD>D<EFBFBD>*<2A>t<EFBFBD>$<24>O<EFBFBD>?<3F>?<3F>?<3F><06>O<EFBFBD>O<EFBFBD>K<EFBFBD> <0C>J<><14>L<01>L<01>L<01><06>O<EFBFBD>O<EFBFBD>I<EFBFBD>l<EFBFBD>9K<39>O<EFBFBD>L<>L<>L<> <0A>=<3D>=<3D>?<3F>?<3F>D<EFBFBD> <0B><17>#<23>z<EFBFBD>;<3B>g<EFBFBD>m<EFBFBD>m<EFBFBD>w<EFBFBD>|<7C>@<40><06><06><06><06>
<16>d<EFBFBD>k<EFBFBD>
"<22>
"<22>C<EFBFBD>:<3A>:<3A>:<3A>K<EFBFBD>
<EFBFBD>w<EFBFBD>|<7C>;<3B>&<26>&<26><18>W<>K<EFBFBD>W<>W<>s<EFBFBD>w<EFBFBD>|<7C>W<>W<>X<>X<>X<>
<EFBFBD>w<EFBFBD><18> 2<>2<>2<><18>_<>#<23>'<27>J[<5B>_<>_<>`<60>`<60>`<60><1D>c<EFBFBD>h<EFBFBD><04> <0C>=<3D>=<3D>=<3D>I<EFBFBD><07>H<EFBFBD>H<EFBFBD> B<> <10>W<EFBFBD>\<5C>3<EFBFBD>s<EFBFBD>y<EFBFBD>><3E>><3E>+<2B>+<2B>+<2B><14>|<7C>:<3A>s<EFBFBD>w<EFBFBD>0<>F<EFBFBD>:<3A>H<EFBFBD><1A> <0E>7<EFBFBD><<3C>,<2C> ,<2C> ,<2C> <1F><03>Y<EFBFBD>r<EFBFBD>*.<2E>,<2C><04> <0C> N<01> N<01> N<01> N<01> N<01> <10>W<EFBFBD>\<5C>X<EFBFBD> %<25> %<25>KS<4B>c<01>,<2C><03><0E>G<>G<>G<>G<>3<>C<EFBFBD>G<EFBFBD>L<EFBFBD>#<23>'<27>,<2C>PS<50>PW<50>Pa<50>b<>b<> <16> "<22><1A>9<EFBFBD>i<EFBFBD><13>R<EFBFBD>4<EFBFBD><<3C>X<>X<>X<>X<><19><0F><0F>!<21>!<21>!<21>!<21><> <09><0F><0F>!<21>!<21>!<21>!<21><><EFBFBD><EFBFBD>;C<01>c<01>+<2B>C<EFBFBD>I<EFBFBD>6<>6<>6<>2<>3<EFBFBD>7<EFBFBD><<3C><13><17><1C>s<EFBFBD>w<EFBFBD>Oa<4F>b<>b<> <15> !<21><1B>H<EFBFBD>i<EFBFBD><13>D<EFBFBD>J<EFBFBD>>B<>l<EFBFBD>(T<><01>C<EFBFBD><03> <09>N<EFBFBD>N<EFBFBD>(:<3A>(:<3A>PT<50>W<01>W<01>W<01>W<01><19><0E><0E> <20> <20> <20> <20><><08><0E><0E> <20> <20> <20> <20><><EFBFBD><EFBFBD><10> <12><0F><0F><19><19><19><19><19><> <1D><11><11><11><10><11><0F><0F><19><19><19><19><19><11><><EFBFBD><EFBFBD><EFBFBD> <12><0F><0F><19><19><19><19><><EFBFBD>sV<00>BL<00> H:<00>%L<00>:I<03>AL<00>7K%<00>L<00>%K;<03>;L<00>
L7<03>L:<00>6L7<03>7L:<00>:M<03>__main__)r9rr:r/)r)rrrUrrVrr:rW)r_rWr5rr:r`)r_rWr:r)r<>rWrsrrVrr:r6)r<>rWrsrr:r<>)r<>r<>r:r`)rPrr:rr)r<>r<>r<>r6r:r`)r<>r<>rsrr<>rr:r )rNr r:r<>)rNr r:r)
r<EFBFBD>r`rrr<>r"r<>rIr:r)r<>rr3r2r:r ) rrAr'r<>r<>r/r(r)r*r6r:rr
) r;rLr'r<>r<>r/r<r6r=rr:r)FF) r<>r/r'r<>r(r)r*r6r<>r6r:r)rrrNrr:r<>)r:r)Jr?<00>
__future__rro<00>asyncio<69> dataclassesr<73>rsr<>r}<00>sysr&<00>pathlibrr<00>typingrr<00>paho.mqtt.clientr1<00>clientrrE<00> getLoggerr*<00> dataclassr rr'r/rQrX<00>
CMD_FW_VER<EFBFBD>
CMD_HW_VERr^r<>r<>r<>r<>r<>r<>r<>r<>r<>r<>rrArLrSr^r<>r<>r<>rr<><00>_i<5F>updater<65>r<>r<>r<>rr5rI<00> SOC_EST_CFGr"r&r:rDrMrIr~r<00>exitrrr<00><module>r<>s_<00><01><04><04><04>8#<23>"<22>"<22>"<22>"<22>"<22><0F><0F><0F><0F><0E><0E><0E><0E><12><12><12><12> <0B> <0B> <0B> <0B><0E><0E><0E><0E> <0A> <0A> <0A> <0A> <0A> <0A> <0A> <0A>
<EFBFBD>
<EFBFBD>
<EFBFBD>
<EFBFBD> <0B> <0B> <0B> <0B><18><18><18><18><18><18><1E><1E><1E><1E><1E><1E> <20> <20> <20> <20> <20> <20> <20> <20><1F><1F><1F><1F><1F><1F><1F><1F><1F> <0A> <0A> <0A> <0A> <0B> <0B> <0B> <0B><17>g<EFBFBD><17> <0A>&<26>&<26><03> <0A><16><1C><1C><1C><1C><1C><1C><1C><17><16><1C> <0A><16>"<22>"<22>"<22>"<22>"<22>"<22>"<22><17><16>"<22> <0A><16>
3<>
3<>
3<>
3<>
3<>
3<>
3<><17><16>
3<> <0A><16> <20> <20> <20> <20> <20> <20> <20><17><16> <20><06><06><06><06>L<1A><12><19>
<EFBFBD><19>
<EFBFBD>:<3A>:<3A>:<3A>:<3A>:<3A>
=<0F>=<0F>=<0F>=<0F>J <0F> <0F> <0F> <0F>*<2A>*<2A>*<2A>*<2A>M<01>L<>L<> <0A><10><10><10><10>. <0A><16> E<01> E<01> E<01> E<01> E<01> E<01> E<01><17><16> E<01>K<01>K<01>K<01>K<01>0,<2C>,<2C>,<2C>,<2C>Z<0F>Z<0F>Z<0F>Z<0F>Z<0F>z#<23>#<23>#<23>#<23>"^<1E>^<1E>^<1E>^<1E>^<1E>^<1E>^<1E>^<1E>N <0A> <0A> <0A> <0A> <0A> <0A> <0A> <0A> <0A> <0A> <0A> <0A> <0A> <0A> <0A> <0A><1A><1A><1A><1A><1A>O<EFBFBD><1A><1A><1A>4))<29>))<29>))<29>))<29>))<29>/<2F>))<29>))<29>))<29>^ <1A> <1A> <1A> <1A> <1A>O<EFBFBD> <1A> <1A> <1A>F 4<> 4<> 4<> 4<> 4<>/<2F> 4<> 4<> 4<>XZ<01>T<>T<>W<>Q<>Y<>W<>S<>Q<>Q<>W<>O<>O<>[<5B>[<5B>!Q<02>Q<02> <0B><02><02><02><02>$ <10>%<25><01>2<EFBFBD>,<2C>,<2C>c<01>c<01>B<EFBFBD>,b<>K<EFBFBD>(<28><02>(<28>(<28>(<28>(<28>)<29>)<29>
<0F>%<25><01>1<EFBFBD>+<2B>+<2B>`<01>`<01>B<EFBFBD>'_<>K<EFBFBD>#<23>r<EFBFBD>#<23>#<23>$<24>$<24> <0B><12><12>S<>U<>U<>U<>S<>P<>P<>V<>P<>V<>X<>M<>Q<>U<>O<>!<02><02><03><03><03>$:<3A>:<3A>:<3A>:<3A>$<02><12>Q<EFBFBD>$<02><12>Q<EFBFBD>$<02>
<EFBFBD>Q<EFBFBD>$<02><0E>Q<EFBFBD> $<02>
<13>Q<EFBFBD> $<02> <13>Q<EFBFBD> $<02><12>Q<EFBFBD>$<02><17>Q<EFBFBD>$<02><17>Q<EFBFBD>$<02><1C>Q<EFBFBD>$<02><12>Q<EFBFBD>$<02><13>Q<EFBFBD>$<02><11>Q<EFBFBD>$<02><12>Q<EFBFBD>$<02><13>Q<EFBFBD>$<02> <11>Q<EFBFBD>!$<02>"<14>Q<EFBFBD>#$<02><10><02><02><02><02>& <10>%<25><01>2<EFBFBD>,<2C>,<2C>3<>3<>B<EFBFBD>12<31><14>-<2D>R<EFBFBD>-<2D>-<2D>-<2D>-<2D>.<2E>.<2E>
<0F>%<25><01>1<EFBFBD>+<2B>+<2B>.<2E>.<2E>B<EFBFBD>,-<2D><14>(<28>B<EFBFBD>(<28>(<28>)<29>)<29>%<25>%<25>%<25>%<25>
M&<26>M&<26>M&<26>M&<26>M&<26>M&<26>M&<26>M&<26>j <0A><16>%<25>%<25>%<25>%<25>%<25>%<25>%<25><17><16>%<25><1D><16><13>d<EFBFBD><15><16> <10> <0F> <12> <11><11><13> <02> <02> <02> <0B>)<29>(<28>(<28>(<28>(<28>(<28>B)<29>)<29>)<29>)<29>AF<01>!@<01>!@<01>!@<01>!@<01>!@<01>J7;<3B>$<13>$<13>$<13>$<13>$<13>PJO<01>(-<2D>D<17>D<17>D<17>D<17>D<17>N&<10>&<10>&<10>&<10>R4<1A>4<1A>4<1A>4<1A>n <0C>z<EFBFBD><19><19> <0C>C<EFBFBD>H<EFBFBD>T<EFBFBD>T<EFBFBD>V<EFBFBD>V<EFBFBD><14><14><14><14><14><1A>r