Monitoring the Bluetti AC300 Power Supply

The only way to connect to the Bluetti AC300 is through the Bluetti app, either directly via Bluetooth or via WiFi, which goes through their cloud service. Unfortunately the device doesn't offer an HTML or SNMP interface that would allow the user to monitor it. Since the easiest way to collect data from the AC300 without any additional hardware would be via WiFi, I started this project, which aims at listening to the data transfer between the AC300 and Bluetti's IoT server. And since that data is most interesting in cases where there is an actual blackout (which, at least in my place, means that there is no Internet connection), I wanted to have a script that can emulate the IoT server to make the AC300 send its data locally. It's also a matter of privacy.

With this script, and a little RRDtool wizardry, you can generate graphs like this:

The image shows that there was a power outage between 11:00 and 12:00 (well, actually I pulled the plug for testing ;-).

Download

GIT archive

The official GIT archive is hosted at

https://git.tvdr.de

Use the command

git clone --branch stable/latest git://git.tvdr.de/bluetti-monitor.git

to clone the archive and check out the latest stable version.

ZIP archive

The source code for the latest version can be downloaded from

https://git.tvdr.de/?p=bluetti-monitor.git;a=snapshot;h=stable/latest;sf=zip

First contact

The first thing I did was to use tcpdump to see what goes on between the AC300 and the IoT server. The AC300 contacts iot.bluettipower.com, which is at 47.254.169.86 on port 18760. The data appeared to be mostly binary, with some readable parts, and not encrypted.

A simple proxy

So I wrote a small Perl script that acts as a proxy that connects to 47.254.169.86:18760, listens locally on port 18760, and forwards data packets between a local client and the IoT server. To make the AC300 connect to my script, I set up a local DNS entry that maps iot.bluettipower.com to the IP number of my PC running the script. The contents of the data packets is printed in the usual hex dump form.

And here's the opening dialog between the AC300 and the IoT server:

[C->S] 20251001-223619 Raw data (20 bytes):
  0000  00 01 00 10 49 4F 54 32 32 32 39 30 31 30 30 30   ....IOT222901000
  0010  35 30 35 37                                       5057

[S->C] 20251001-223619 Raw data (8 bytes):
  0000  00 01 00 04 68 DD 20 43                           ....h. C

[C->S] 20251001-223619 Raw data (68 bytes):
  0000  10 42 00 04 4D 51 54 54 04 C2 00 3C 00 1A 34 33   .B..MQTT...<..43
  0010  39 31 30 31 31 39 30 35 39 36 39 36 38 39 31 33   9101190596968913
  0020  31 34 30 37 35 37 32 39 00 10 49 4F 54 32 32 32   14075729..IOT222
  0030  39 30 31 30 30 30 35 30 35 37 00 08 34 33 38 30   9010005057..4380
  0040  31 36 35 31                                       1651

[S->C] 20251001-223619 Raw data (4 bytes):
  0000  20 02 00 00                                        ...

[C->S] 20251001-223619 Raw data (23 bytes):
  0000  00 02 00 13 41 43 33 30 30 26 32 32 33 32 30 30   ....AC300&223200
  0010  30 31 XX XX XX XX XX                              01XXXXX

[S->C] 20251001-223619 Raw data (5 bytes):
  0000  00 02 00 01 01                                    .....

[C->S] 20251001-223619 Raw data (49 bytes):
  0000  82 2F 00 01 00 10 50 55 42 4C 49 43 2F 49 4F 54   ./....PUBLIC/IOT
  0010  2F 50 4F 57 45 52 00 00 17 53 55 42 2F 41 43 33   /POWER...SUB/AC3
  0020  30 30 2F 32 32 33 32 30 30 30 31 XX XX XX XX XX   00/22320001XXXXX
  0030  00                                                .

[S->C] 20251001-223619 Raw data (6 bytes):
  0000  90 04 00 01 00 00                                 ......
The connection is always initiated by the AC300, with a constant 20 byte packet, presumably telling the server something about the type of this device, or how it wishes to communicate with the server.

The server responds with an 8 byte packet, containing what appears to be a Unix time value in the last four bytes. However, it is about 18 hours behind UTC. Apparently the actual value doesn't matter, the AC300 doesn't set its clock to this value. Even random data works fine here.

Next, the AC300 (the "client") sends a packet indicating that this is going to be an MQTT protocol, which the server confirms with a constant 4 byte packet.

Following is the device type (AC300) and the device's serial number (partially XX'd here for obvious reasons), confirmed by the server with a constant 5 byte packet.

Finally the client sends some MQTT strings and the server confirms with a constant 6 byte packet.

After this initial data exchange, there is a valid connection between client and server, and from here on the client regularly sends data packets to the server every few seconds.

Impersonating

Once I knew how the communication between the AC300 and the IoT server is initiated, I extended my script so that it sends the client the proper responses.

clientserver
00 01 ...00 01 00 04 11 22 33 44
10 ... 20 02 00 00
00 02 ...00 02 00 01 01
82 ... 90 04 00 01 00 00
C0 00 D0 00
E0 00 n/a

Of the client packets only the first one or two bytes are significant to determine the proper server side response. "C0 00" is a ping packet, which the client sends from time to time, and to which the server responds with "D0 00". With "E0 00" the client tells the server to disconnect.

Unpacking

Now that the AC300 talked to my script, without involving the IoT server, I started collecting and analyzing the data packets from the client.

All data packets from the AC300 start with 0x30, which in MQTT lingo means "PUBLISH". They follow this layout:

30PUBLISH
C3 01remaining length (variable-length encoded, here: 195)
00 17length of topic
50 55 42 2F 41 43 33 30 30 2F 32 32 33 32 30 30 30 31 35 XX XX XX XXtopic (here: PUB/AC300/22320001XXXXX)
01tag1
01tag2
10 00 82 00 50 A0...00 00payload data
33 4ECRC16 checksum over tag2 and payload data

Collecting data

The first thing I observed after extracting the actual payload data was that the packets have different sizes. I therefore implemented option -F, which dumps the data into files named after the length of the respective payload data, one line per packet. In addition, option -O prints only those bytes that have actually changed since the last packet. The result is quite helpful in figuring out what the individual bytes mean. For instance, the packet with length 126 contains payload "10 00 46 00 3C 78", which look like this:
20251002-170741 10 00 46 00 3C 78 00 02 08 E7 00 01 FF FE 13 85 00 01 00 00 08 F0 00 00 00 00 13 85 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 02 14 00 03 00 63 00 45 00 01 00 00 14 C8 00 64 00 00 00 62 00 00 16 80 04 B0 01 4B 01 4B 01 4B 01 4B 01 4B 01 4B 01 4C 01 4B 01 4B 01 4B 01 4B 01 4B 01 4B 01 4B 01 4C 01 4C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
20251002-170806                            E8          FB    83                F1                83                                                                                              02                            65                      4C    4C    4C    4C    4C    4C          4C    4D    4C    4C    4C    4C    4C
20251002-170831                            EA    06    F6    84                F2 FF FC          84                                                                            05                03       00 00    00          00    1E             00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
20251002-170856                            C0    62 F7 6B    83                CA 00 64 08 9A    83                                                                      1F 01 77                04                               02 D0
20251002-170921                            BD          73    84    02          C7          96    84                                                                      2B    6E                01    01 15 40    63    01    62                   01 57 01 57 01 57 01 57 01 58 01 58 01 5A 01 57 01 57 01 57 01 58 01 57 01 58 01 57 01 5A 01 57
20251002-170946                            D0    37 FB 26          01          DA    39 04 E1                                                                            36 00 C9                02          B8    64          65 00 DC                62    60    60    5F    60    60    60    60    61    60    60    60    60    60    60    60
20251002-171011                      03    DD    01 FF FE    86                E5    00 00 00    86                                                                      2F    05    64          01       16 26    63          62    00                5C    59    5A    5A    5B    5A    63    5A    5B    5B    5C          5F    5A    62    5D
20251002-171036                            DF       00 00    8A                E7                8A                                                                      2B    02                02    00 15 CC    64    00    65                            5A                5A          5A          5C    5A    5A    5A    5A          5A    5A
20251002-171101                            E0    00 FF FC    86                E8    01          86                                                                      2A    04                01          A4                62                      59    56    57    57    57    57    5E    57    57    57    59    5B    5B    57    5E    59
20251002-171126                            E3          FD    85                EC                85                                                                      29                      02          9A                65                            58    58    59    58    58    58    58    5A    58          59    58    58    58    58
20251002-171151                            DF                84                E7                84                                                                      28                      01          86                62                      57    55    55    56    56    56    5C    55    56    56    57          59    56    5C
20251002-171216                            DE          FE    85                E6                85                                                                      27    02                02                            65                      58    57    57    58    57    57    57    57    59    57          57    57    57    57    57
20251002-171241                            D6          FC    84    02          DF                84                                                                      26                      01          72                62                      56    54    54    55    55    55    5B    55    55    55    56    58    58    55    5A
20251002-171306                                        FD    86                DE                86                                                                      25                      02                            65                      57    56    56    57    56    56    56    56    58    57    57    57    56    56    56
20251002-171331                            D7          FA    85    01          E0                85                                                                            04                01          68                62                      55    53    54    54    54    54    5A    54    54    54    55          57    54    59    56
20251002-171401                            D4    01    FD    84    02          DD    00          84                                                                      24    02                02                            65                      56    56    56    56    55    56    55    56    57    56    56    56    55    56    55
20251002-171426                            DC          FF                      E4    01                                                                                  23                      01          5E                62                      55    52    53    53    54    54    59    53    54    54    55          56    53    58    55
20251002-171451                                        FE    86                E5    00          86                                                                            04                02                            65                      56    55    55    56    55    55    55    55    57    55          55    55    55    54
20251002-171516                            DB    00    FC    8B                E3    01          8B                                                                      22    02                01          54                62                      54    52    52    53    53    53    58    53    53    53    54    56    56    53    57    54
20251002-171541                                                    01          E4                                                                                                                02                            65                      55    54    54    55    54    54    54    54    56    55    55    55    54    54    54    55
20251002-171606                            D7    01          8A    02          DF    00          8A                                                                            00                01          4A                62                      53    52    52    52    53    52    57    52    53    52    53          55    52    57    54
20251002-171631                            D3          FB    8B    01          DC                8B                                                                      21    02                02                            65                      55    54    54    55    54    54    53    54    56    54    54    54    53    54    53
20251002-171656                            D2          FC                      DA                                                                                                                01          40                62                      53    51    52    52    52    52    56    52    52    52    53          54    52    56    53
20251002-171726                            D9          FD          02          E1                                                                                        20                      02                            65                      54    53    53    54    53    53    53    53    55    53    54          53    53    53
20251002-171756                            D2    00    FB                      DA    01                                                                                                          01          36                62                      52    51    51    52    52    52    56    52    52    52    52          54    51    55
20251002-171821                            CB    01          8C    01          D3    00          8C                                                                      1F                      02          2C                65                      53    53    53    54    53    53    52    53    55    53    53    53    52    53    52
20251002-171846                            CD    00          85                D5                85                                                                            04                01                            62                      52    50    51    51    51    51    55    51    51    51    52          53    51    55    52
20251002-171911                            C8                                  D1    01                                                                                                          02                            65                      53    52    52    53    52    52    52    52    54    52    53          52    52    52
20251002-171936                                  01    FD                                                                                                                1E    02                01          22                62                      52    50    50    51    51    51    54    51    51    51    51                51    54
20251002-172001                            CE    00    FB    84                D7                84                                                                            00                02                            65                            52    52    53    52    52    51    52    54    52    52    52    51    52    51
20251002-172026                            CA    01    FA    83    02          D3    00          83                                                                            02                01                            62                      51    50    50    50    50    51    54    51    50    50    51          52    50    54    51
20251002-172051                            CD                85                D5    01          85                                                                      1D    04                02                            65                      52    52    51    52    51          51    52    53    52    52          51    52    51    52
20251002-172116                            CC    00    FB          01          D4                                                                                              02                01                            62                      51    4F    50    50    50    50    53    50    50    50    51          52    50    53    51
20251002-172146                            CA          FD    84    02          D2                84                                                                            04                02                            65                      52    51    51    52    51    51    51    51    53    51    52          51    51    51
20251002-172211                            C6          FC                      CE                                                                                        1C                      01          18                62                      50    4F    4F    50    50    50    53    50    50    50    50    51          4F    52    50
20251002-172236                            C9          FD          01          D1                                                                                                                02                            65                      51    51    51    52    51    51    50    51    53    51    51          50    51    50    51
20251002-172301                                                    02                00                                                                                        00                01          0E                62                      50    4F    4F    4F    4F    50    52    4F    4F    4F    50          51    4F    52    50
20251002-172326                            C8    01          82                                  82                                                                            02                02                            65                      51    50    50    51    50          50    50    52    51    51          50    51    50    51
20251002-172351                            CE          FE          01          D7                                                                                        1B    04                01                            62                      50    4E    4F    4F    4F    4F    52    4F    4F    4F    50    50          4F    52    50
20251002-172416                            CB          FB    81    02          D4    01          81                                                                                              02                            65                      51    50    50    51    50    50    50    50    52    50    51    51          50    50
20251002-172446                                        FC    80                D3                80                                                                                              01          04                62                      4F    4E    4E    4F    4F    4F    51    4F    4F    4F    4F    50          4F    51    4F
20251002-172516                                        FE          01                00                                                                                        02                02                            65                      50    50    50    51    50    50    4F    50    52    50    50          4F    50    4F    50
20251002-172541                            C8          FD                      D0                                                                                        1A    04                01                            62                      4F    4E    4E    4E    4F    4F    51    4F    4E    4E    4F          50    4E    51    4F
20251002-172606                            C6          FE    81                CE                81                                                                                              02       14 FA                65                      50    4F    4F    50                4F    50    51    50    50          4F    50    4F    50
20251002-172631                            C7    00    FB    80    02          D0    01          80                                                                                              01                            62                      4F    4E    4E    4E    4E    4E    51    4E    4E    4E    4F    4F          4E    50    4F
After observing this for a while, the meaning of several bytes could be identified. The most obvious thing here was the sequence of 16 two-byte words that range between 330 and 350, beginning at offset 76. Apparently these are the voltages of the individual battery cells, multiplied by 100.

Trial & error

By turning utility power off/on, connecting AC and DC loads, turning AC and DC on/off, and observing the changes in the data packets, several more parameters could be identified. Using the -c option to have the script work as a proxy that allows the AC300 to access the actual Bluetti IoT server unveiled even more data.

Here's the list of all the observed sequences of payload data the AC300 sends:

10 00 00 00 24 48 ...
10 00 24 00 22 44 ...
10 00 46 00 3C 78 ...
10 00 82 00 50 A0 ...
10 0B B8 00 3E 7C ...
10 0B BF 00 02 04 ...
These sequences are sent when connected to the server (some only when the Bluetti app accesses the device):
03 20 00 00 00 00 ...
03 76 41 43 33 30 ...
03 7C 00 00 00 03 ...
03 E6 00 04 02 ...
06 00 2B 00 ...
06 0B BE 00 ...
06 0B F5 00 ...
06 0B C0 00 ...
83 05 ...
86 02 ...

Usage

By default the script works fully local, just collecting data from the AC300. Several options can be given to define how the data is processed:
Options: -F DIR   dump into Files in DIR
         -L       Log also to stdout
         -M       Mark changed bytes in payload
         -O       dump Only changed packets
         -P       dump Payload
         -R       dump Raw data
         -T       dump Topic
         -V       dump Values
         -X       dump data eXchange between client/server
         -a SECS  Average values over SECS seconds (default: 300)
         -c       Connect to bluetti server
         -i IP    set IP number of bluetti IoT server (default: 47.254.169.86)
         -m MAIL  send status mails to MAIL (default: none)
         -p PORT  listen on PORT (default: 18760)
         -s DIR   store values in a file in DIR
         -t SECS  set timeout to SECS (default: 60 seconds)
Options with uppercase letters are mainly for testing and debugging, and to determine the meaning of certain bytes. Lowercase options are used for normal operation.

A typical call might look like this:

bluetti-monitor -m email -s directory
This will collect data from all AC300s in the local network and write the parameters into one file for each device, with the file name being the serial number of the device. No connection with the Bluetti IoT server is made, so the data never leaves the local betwork. Important events are reported via email to the given address.

Adding the -c option, as in

bluetti-monitor -m email -s directory -c
will establish a connection between the AC300 and the Bluetti IoT server, and "eavesdrop" on the data.

Parameter file format

With the -s option the data received from the AC300 is stored in a file that looks like this:
ACon = 1000,1000,1000
Cells1 = 332,332,332,332,332,332,333,332,332,332,332,332,332,332,333,332
Cells2 = 333,333,333,333,333,333,333,333,334,333,333,333,333,333,333,333
DCon = 0,0,0
Device = AC300
Grid = 0,0,0
LoadAC = 0,0,0
LoadDC = 0,0,0
MonitorVersion = 1.0.0
PDC1 = 0,0,0
Serial = 22320001XXXXX
Server = 42,0,1000
SoC = 1000,1000,1000
SoC1 = 1000,1000,1000
SoC2 = 1000,1000,1000
Time = 251002-214033
Utility = 1000,1000,1000
VDC1 = 0,0,0
Voltage1 = 534,534,534
Voltage2 = 534,534,534
Parameters with three comma separated numbers show the average, minimum and maximum value within the last five minutes (assuming the default -a option).

Percentage values are "times 10" for higher resolution.

Parameter names ending with 1, 2, 3 or 4 refer to that specific battery pack.

[AD]Con indicates whether the AC/DC output is on.

Cells[1234] shows the voltage of the 16 individual cells of that battery "times 10".

Device is the device type.

Grid is the input power drawn from the grid, in Watts.

Load[AD]C is the output power drawn on the AC/DC ports, in Watts.

MonitorVersion is the version number of the script that created this file.

[PV]DC[12] is the input power/voltage from the solar panel 1/2, in Watts/Volts.

Serial is the serial number of the device.

Server shows data packages from the server.

SoC is the "State of Charge" of the entire device.

SoC[1234] is the "State of Charge" of that specific battery pack.

Time is the system time of the device.

Voltage[1234] is the voltage of that specific battery pack "times 10".

Note that, especially right after starting a connection to the client, not all of these values may be present, yet.

TODO

There is surely a lot more data that might be interesting to monitor. If you can find out the location of additional parameters, please let me know.

I was able to locate the data for the voltage and power input of solar panel 1 (DC1), but couldn't find out where DC2 is published. Perhaps, like with the battery packs, it requires some trigger to switch between DC1 and DC2?

What also might be interesting are temperatures. I'm sure there must be some sensors in the device.

Other devices?

I only have an AC300 with two B300 batteries, so I can only test with that device type. If you have an other Bluetti power supply that you might want to monitor, try using this script as described and see what kind of data it can extract. You may need to add a device specific ExtractValues_* function (see the instructions in the script).

Links

Bluetti AC300
RRDtool

My other projects

Full Motion Flight Simulator
GeoTagger - Display and modify GPS location data in photos
Interface zur Verbindung einer digitalSTROM-Klemme GR-KL200 mit einem VELUX KLF 050x

Impressum
[counter]