xdubx / Solax-Pocket-USB-reverse-engineering

Port of the Solax-Pocket USB to a generic ESP8266/ESP32.
13 stars 4 forks source link

Contribution #4

Open 70p4z opened 1 year ago

70p4z commented 1 year ago

After a few dump of the serial interface and reverse to get the mapping here are some results I got. I hope this would help.

Query: r
AA55: Header
07:   Length
0110: Func+ID   (alternate 0113)
1701: CRC       (alternate CRC 1A01)

Reply: 
off value
0   AA55: Header
2   97:   Length %256  (alternate 0x5F => total length 0x25F)
3   0190: Func+ID      (alternate 8190)
5   3709:     U2LE grid voltage  (0.1V)
7   1600:     U2LE grid current (0.1A)
9   FD01:     U2LE grid power (1W)
11  8913:     U2LE grid frequency (0.01Hz)
13  940E:     U2LE PV1 voltage (0.1V)
15  0000:     U2LE PV2 voltage (0.1V)
17  0B00:     U2LE PV1 current (0.1A)
19  0000:     U2LE PV2 current (0.1A)
21  AE01:     U2LE PV1 power (1W)
23  0000:     U2LE PV2 power (1W)
25  0200:     U2 Mode (0:off, 1:checking, 2:normal, 3:fault, 5:update?, 7:offgrid, 9:idle, 0xA:standby)
27  29000000: U4LE E Total (0.1kwh)
31  2200:     U2LE E Today (0.1kwh)
33  364C:     U2LE batt voltage (0.01V)
35  0000: 
37  4C00:     U2LE bat power (1W)
39  1E00:     U2LE bms temp (1°C)
41  4300:     U2LE bms charge percentage
43  0400: 
45  0000
47  37010000
51  04        U1 batt SoH / 10
52  00        U1 batt SoH / 2560
53  6400
55  0000
57  2700
59  A60E 
61  0000      U2LE EPS power (1W)
63  0000      U2LE EPS voltage (0.1V)
65  1600      U2LE EPS current? (0.1A)
67  0000      U2LE EPS frequency (0.01Hz)
69  00000000  S4LE Meter/CT (1W)
73  17010000: U4LE On-grid yield
77  1F010000: U4LE Grid consumed
81  FD01:     S2LE grid power - grid_meter_ct (1W)
83  2700
85  00
86  01
87  7008:     U2LE bms max voltage (0.1V)
89  CC06:     U2LE bms min voltage (0.1V)
91  0A00:     U2LE bat max charge current (0.1A)
93  FA00      U2LE bms max discharge current (0.1A)
95  F000      
97  DC00
99  2100
101 2100
103 0200
105 0100
107 01
108 00       const fixed 0
109 14010000
113 17000000
117 0FFEFFFF
121 3DFFFFFF
125 00000000
129 00       const fixed 0
130 00       const fixed 0
131 00       const fixed 0
132 00       const fixed 0
133 0000
135 0000
137 0000
139 0000
141 0000
143 0000
145 0000
147 0000
149 33010000: U4LE 
153 67FEFFFF: U4LE 
157 94110000: U4LE 
161 6CEEFFFF: U4LE 
163 0000
165 0000
167 6400
169 0000
171 0000
173 0000
175 0000
177 1600
179 0200
181 0800
183 0000
185 0000
187 0000
189 0000
191 0000
193 0000
195 0000
197 0000
199 0000
201 0000
203 13: RTC seconds
204 08: RTC minutes
205 0D: RTC hours
206 1E: RTC day
207 02: RTC month
208 16: RTC year
209 52
210 04
211 0000
213 00
214 00
215 00
216 00
217 00
218 00
219 00
220 00
221 00
222 00
223 00
224 00
225 01
226 00 const fixed 0
227 C707: U2LE bms voltage (0.1V)
229 FAFF: S2LE bms current (0.1A)
231 89FF: S2LE bms power (1W)
...

Check with some values on your side to validate, but that sounds about right on my interpreter.

tuxmike commented 1 year ago

Solax X1 Hybrid G4 ? The commands in the Readme are coming from an X1-Mini 1.5, so there seems to be some difference. What does "(alternate ...)" refer to?

70p4z commented 1 year ago

Oh, thanks pretty dumb actually, the command to send to the x1 could be:

Either command, the first 0x197 bytes are containing the same information. Hope that helped.

70p4z commented 1 year ago

Additionally, I think each inverter of the solax product line are somewhat implementing different command set.

xdubx commented 1 year ago

Additionally, I think each inverter of the solax product line are somewhat implementing different command set.

Yes. If you take a look in the data sheets https://github.com/xdubx/Solax-Pocket-USB-reverse-engineering/tree/refactor/Modbus%20stuff they have a very weird implementation. Modbus is different from the usb implementation.

70p4z commented 1 year ago

I'm not familiar with modbus, only CAN and the pocketwifi serial link (it's not USB at all :s)

tuxmike commented 1 year ago

Hi @70p4z, can you confirm the below cmd table for you / X1 Hybrid?

Commands

Control code Function Code Payload length (byte) Checksum length (byte) Description
01 01 0 2 Request inverter data X1 Hybrid
01 90 400 2 Response inverter data X1 Hybrid (example you posted above)
01 13 0 2 Request inverter data2 X1 Hybrid
81 90 600 2 Response inverter data2 X1 Hybrid (what is in there, do you have an example?)
known X1 Mini (Pocket v2.0) as comparison
01 0C 0 2 Request inverter data X1 Mini
01 8C 200 2 Response inverter data X1 Mini
Are generic cmds below also the same for you / X1 Hybrid? Control code Function Code Payload length (byte) Checksum length (byte) Description
01 05 0 2 Request read serial numbers
01 85 40 2 Response read serial numbers
02 01 10 2 Request register pocket dongle serial number
02 01 10 0 (!) Response register pocket dongle serial number
tuxmike commented 1 year ago

@70p4z Are you using are black PocketWifi/LAN v3.0, or a white v2.0, or even v1.0?

70p4z commented 1 year ago

Hi @tuxmike, The only mistake in the table, is:

Hi @70p4z, can you confirm the below cmd table for you / X1 Hybrid?

Commands

Control code Function Code Payload length (byte) Checksum length (byte) Description 01 01 0 2 Request inverter data X1 Hybrid 01 90 400 2
01 13 0 2 Request inverter data2 X1 Hybrid 81 90 600 2 Response inverter data2 X1 Hybrid (what is in there, do you have an example?) known X1 Mini (Pocket v2.0) as comparison
01 0C 0 2 Request inverter data X1 Mini 01 8C 200 2 Response inverter data X1 Mini

Are generic cmds below also the same for you / X1 Hybrid? Control code Function Code Payload length (byte) Checksum length (byte) Description 01 05 0 2 Request read serial numbers 01 85 40 2 Response read serial numbers 02 01 10 2 Request register pocket dongle serial number 02 01 10 0 (!) Response register pocket dongle serial number

I haven't checked all those comman/func pairs, they are not needed to drive the inverter or get its status. I just discovered other commands though:

  - check pin : AA 55 09 09 00 DE 07 F6 01
                =====                      Start of packet
                      ==                   packet length (including start of packet and checksum)
                         =====             Command indication
                               =====       PIN value (U16LE)
                                     ===== checksum
   - check pin reply
                AA 55 07 09 80 8F 01

An extract from my tparse project may also be useful. Here are some other commands

const uint8_t solax_pw_cmd_mode_self_use[]= { 0xAA, 0x55, 0x09, 0x09, 0x1C, 0x00, 0x00, 0x2D, 0x01 };
const uint8_t solax_pw_cmd_mode_manual[]= { 0xAA, 0x55, 0x09, 0x09, 0x1C, 0x03, 0x00, 0x30, 0x01 };
// useless // const uint8_t solax_pw_cmd_mode_backup[]= { 0xAA, 0x55, 0x09, 0x09, 0x1C, 0x02, 0x00, 0x30, 0x01 };

const uint8_t solax_pw_cfg_manual_stop[]= { 0xAA, 0x55, 0x09, 0x09, 0x24, 0x00, 0x00, 0x35, 0x01 };
const uint8_t solax_pw_cfg_manual_charge[]= { 0xAA, 0x55, 0x09, 0x09, 0x24, 0x01, 0x00, 0x35, 0x01 };
// useless // const uint8_t solax_pw_cfg_manual_discharge[]= { 0xAA, 0x55, 0x09, 0x09, 0x24, 0x02, 0x00, 0x35, 0x01 };

And others I'm not using, but which can prove useful too

#set gmppt high
aa5509096a03007e01 aa550709eaf901
#set gmppt low
aa5509096a01007c01 aa550709eaf901
#set gmppt off
aa5509096a00007b01 aa550709eaf901

# set system off
aa5509092f00004001 aa550709afbe01
# set system on
aa5509092f01004101 aa550709afbe01

Also I've started listing all settings and create a map of what setting is at what index in the settings array (and therefore what SET commands is required to change it). If you're interested I'll share that too later on.

Finally, I'm using solax pocket wifi 2.0 (the white one), well, at least I was using it. Now that my bridge for pylontech compatibility is featuring a pocket wifi serial port, and an I2C monitoring port (to eventually reach home assistant), I'm not using it anymore.

Cheers,

70p4z commented 11 months ago

Few update, I've just reversed the Solax inverter states:

  #define INVERTER_STATUS_WAITING 0
  #define INVERTER_STATUS_CHECKING 1
  #define INVERTER_STATUS_NORMAL 2
  #define INVERTER_STATUS_FAULT 3
  #define INVERTER_STATUS_ERROR 4
  #define INVERTER_STATUS_UPDATE 5
  #define INVERTER_STATUS_EPS_WAIT 6
  #define INVERTER_STATUS_EPS 7
  #define INVERTER_STATUS_SELFTEST 8
  #define INVERTER_STATUS_IDLE 9
  #define INVERTER_STATUS_STANDBY 10

For anyone who might need such info