├── .gitignore ├── experimental ├── .gitignore ├── requirements.txt └── main.py ├── commands ├── summary.md ├── 12v-off.md ├── 12v-on.md ├── ac-off.md ├── 1000w-charge-limit.md ├── 400w-charge-limit.md ├── 800w-charge-limit.md ├── ac-off2.md ├── ac-off3.md ├── ac-off4.md ├── ac-on.md ├── ac-on2.md ├── ac-on3.md ├── ac-on4.md ├── usb-on.md ├── usb-off.md └── README.md ├── states ├── all-off.md ├── all-on.md ├── 12v-out-on.md ├── ac-out-on.md ├── all-off2.md ├── usb-out-on.md ├── 400w-charge-limit.md ├── 800w-charge-limit.md ├── charge-limit-66p.md ├── 1000w-charge-limit.md ├── ac-out-on-later-at-1-32.md ├── summary.md └── README.md ├── states2 ├── all-off.md ├── all-off2.md └── all-off3.md ├── License.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | private/ 2 | -------------------------------------------------------------------------------- /experimental/.gitignore: -------------------------------------------------------------------------------- 1 | .venv 2 | -------------------------------------------------------------------------------- /commands/summary.md: -------------------------------------------------------------------------------- 1 | 0x002a 2 | SDP: UDP -------------------------------------------------------------------------------- /commands/12v-off.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 01 00 a0 0d 00 00 00 00 00 00 21 05 20 51 2 | 0010 00 f3 02 3 | -------------------------------------------------------------------------------- /commands/12v-on.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 01 00 a0 0d 00 00 00 00 00 00 21 05 20 51 2 | 0010 01 32 c2 3 | -------------------------------------------------------------------------------- /commands/ac-off.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 01 00 a0 0d 00 00 00 00 00 00 21 05 20 51 2 | 0010 01 32 c2 3 | -------------------------------------------------------------------------------- /commands/1000w-charge-limit.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 03 00 8a 0d 00 00 00 00 00 00 21 05 20 45 2 | 0010 e8 03 ff 0b 3a 3 | -------------------------------------------------------------------------------- /commands/400w-charge-limit.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 03 00 8a 0d 00 00 00 00 00 00 21 05 20 45 2 | 0010 90 01 ff 8a 43 3 | -------------------------------------------------------------------------------- /commands/800w-charge-limit.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 03 00 8a 0d 00 00 00 00 00 00 21 05 20 45 2 | 0010 20 03 ff 8a c4 3 | -------------------------------------------------------------------------------- /commands/ac-off2.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 07 00 de 0d 00 00 00 00 00 00 21 05 20 42 2 | 0010 00 ff ff ff ff ff ff 7b d1 3 | -------------------------------------------------------------------------------- /commands/ac-off3.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 07 00 de 0d 00 00 00 00 00 00 21 05 20 42 2 | 0010 00 ff ff ff ff ff ff 7b d1 3 | -------------------------------------------------------------------------------- /commands/ac-off4.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 07 00 de 0d 00 00 00 00 00 00 21 05 20 42 2 | 0010 00 ff ff ff ff ff ff 7b d1 3 | -------------------------------------------------------------------------------- /commands/ac-on.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 07 00 de 0d 00 00 00 00 00 00 21 05 20 42 2 | 0010 00 ff ff ff ff ff ff 7b d1 3 | -------------------------------------------------------------------------------- /commands/ac-on2.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 07 00 de 0d 00 00 00 00 00 00 21 05 20 42 2 | 0010 01 ff ff ff ff ff ff 6b 11 3 | -------------------------------------------------------------------------------- /commands/ac-on3.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 07 00 de 0d 00 00 00 00 00 00 21 05 20 42 2 | 0010 01 ff ff ff ff ff ff 6b 11 3 | -------------------------------------------------------------------------------- /commands/ac-on4.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 07 00 de 0d 00 00 00 00 00 00 21 05 20 42 2 | 0010 01 ff ff ff ff ff ff 6b 11 3 | -------------------------------------------------------------------------------- /commands/usb-on.md: -------------------------------------------------------------------------------- 1 | 0000 02 40 00 1a 00 16 00 04 00 52 2a 00 aa 02 01 00 2 | 0010 a0 0d 00 00 00 00 00 00 21 02 20 22 01 16 86 3 | -------------------------------------------------------------------------------- /experimental/requirements.txt: -------------------------------------------------------------------------------- 1 | PyBluez==0.23 2 | pkg-config 3 | libboost-python-dev 4 | libboost-thread-dev 5 | libbluetooth-dev >= 4.101 6 | libglib2.0-dev -------------------------------------------------------------------------------- /commands/usb-off.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 01 00 a0 0d 00 00 00 00 00 00 21 02 20 22 2 | 0010 00 d7 46 3 | 4 | OR (one of them is 12VDC off) 5 | 6 | 0000 aa 02 01 00 a0 0d 00 00 00 00 00 00 21 05 20 51 7 | 0010 00 f3 02 -------------------------------------------------------------------------------- /states/all-off.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 6f 00 83 2c 00 00 00 00 02 00 02 21 20 02 2 | 0010 50 00 00 00 00 4e 00 02 01 00 00 00 00 00 47 00 3 | 0020 00 00 00 cd e8 ff ff 00 00 00 00 00 00 00 00 00 4 | 0030 00 00 00 14 a0 05 2c 01 03 00 00 00 00 00 00 00 5 | 0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6 | 0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7 | 0060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8 | 0070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a5 9 | 0080 ed 10 | -------------------------------------------------------------------------------- /states/all-on.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 6f 00 83 2c 00 00 00 00 02 00 02 21 20 02 2 | 0010 50 00 00 00 00 4e 00 02 01 00 00 00 00 00 47 00 3 | 0020 00 00 00 c1 ef ff ff 00 01 00 00 00 00 00 00 00 4 | 0030 00 01 00 14 a0 05 2c 01 03 00 00 00 00 00 00 00 5 | 0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6 | 0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7 | 0060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8 | 0070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7f 9 | 0080 95 10 | -------------------------------------------------------------------------------- /states/12v-out-on.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 6f 00 83 2c 00 00 00 00 02 00 02 21 20 02 2 | 0010 50 00 00 00 00 4e 00 02 01 00 00 00 00 00 47 00 3 | 0020 00 00 00 cd e8 ff ff 00 00 00 00 00 00 00 00 00 4 | 0030 00 00 00 14 a0 05 2c 01 03 00 00 00 00 00 00 00 5 | 0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6 | 0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7 | 0060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8 | 0070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a5 9 | 0080 ed 10 | -------------------------------------------------------------------------------- /states/ac-out-on.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 6f 00 83 2c 00 00 00 00 02 00 02 21 20 02 2 | 0010 50 00 00 00 00 4e 00 02 01 00 00 00 00 00 47 00 3 | 0020 00 00 00 cd e8 ff ff 00 00 00 00 00 00 00 00 00 4 | 0030 00 01 00 14 a0 05 2c 01 03 00 00 00 00 00 00 00 5 | 0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6 | 0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7 | 0060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8 | 0070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 25 9 | 0080 1d 10 | -------------------------------------------------------------------------------- /states/all-off2.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 6f 00 83 2c 00 00 00 00 02 00 02 21 20 02 2 | 0010 50 00 00 00 00 4e 00 02 01 00 00 00 00 00 47 00 3 | 0020 00 00 00 cd e8 ff ff 00 00 00 00 00 00 00 00 00 4 | 0030 00 00 00 14 a0 05 2c 01 03 00 00 00 00 00 00 00 5 | 0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6 | 0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7 | 0060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8 | 0070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a5 9 | 0080 ed 10 | -------------------------------------------------------------------------------- /states/usb-out-on.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 6f 00 83 2c 00 00 00 00 02 00 02 21 20 02 2 | 0010 50 00 00 00 00 4e 00 02 01 00 00 00 00 00 47 00 3 | 0020 00 00 00 cd e8 ff ff 00 00 00 00 00 00 00 00 00 4 | 0030 00 00 00 14 a0 05 2c 01 03 00 00 00 00 00 00 00 5 | 0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6 | 0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7 | 0060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8 | 0070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a5 9 | 0080 ed 10 | -------------------------------------------------------------------------------- /states/400w-charge-limit.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 6f 00 83 2c 00 00 00 00 02 00 02 21 20 02 2 | 0010 50 00 00 00 00 4e 00 02 01 00 00 00 00 00 47 00 3 | 0020 00 00 00 cd e8 ff ff 00 00 00 00 00 00 00 00 00 4 | 0030 00 00 00 14 a0 05 2c 01 03 00 00 00 00 00 00 00 5 | 0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6 | 0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7 | 0060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8 | 0070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a5 9 | 0080 ed 10 | -------------------------------------------------------------------------------- /states/800w-charge-limit.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 6f 00 83 2c 00 00 00 00 02 00 02 21 20 02 2 | 0010 50 00 00 00 00 4e 00 02 01 00 00 00 00 00 47 00 3 | 0020 00 00 00 99 f5 ff ff 00 00 00 00 00 00 00 00 00 4 | 0030 00 00 00 14 a0 05 2c 01 03 00 00 00 00 00 00 00 5 | 0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6 | 0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7 | 0060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8 | 0070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f2 9 | 0080 ca 10 | -------------------------------------------------------------------------------- /states/charge-limit-66p.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 6f 00 83 2c 00 00 00 00 02 00 02 21 20 02 2 | 0010 50 00 00 00 00 4e 00 02 01 00 00 00 00 00 47 00 3 | 0020 00 00 00 cd e8 ff ff 00 00 00 00 00 00 00 00 00 4 | 0030 00 00 00 14 a0 05 2c 01 03 00 00 00 00 00 00 00 5 | 0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6 | 0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7 | 0060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8 | 0070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a5 9 | 0080 ed 10 | -------------------------------------------------------------------------------- /states/1000w-charge-limit.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 6f 00 83 2c 00 00 00 00 02 00 02 21 20 02 2 | 0010 50 00 00 00 00 4e 00 02 01 00 00 00 00 00 47 00 3 | 0020 00 00 00 cd e8 ff ff 00 00 00 00 00 00 00 00 00 4 | 0030 00 00 00 14 a0 05 2c 01 03 00 00 00 00 00 00 00 5 | 0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6 | 0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7 | 0060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8 | 0070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a5 9 | 0080 ed 10 | -------------------------------------------------------------------------------- /states/ac-out-on-later-at-1-32.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 6f 00 83 2c 00 00 00 00 02 00 02 21 20 02 2 | 0010 50 00 00 00 00 4e 00 02 01 00 00 00 00 00 47 00 3 | 0020 00 00 00 84 ee ff ff 00 00 00 00 00 00 00 00 00 4 | 0030 00 00 00 14 a0 05 2c 01 03 00 00 00 00 00 00 00 5 | 0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6 | 0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7 | 0060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8 | 0070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 c1 9 | 0080 e1 10 | -------------------------------------------------------------------------------- /states2/all-off.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 2e 00 cd 2c 00 00 00 00 00 00 03 21 20 02 2 | 0010 01 01 01 3f d8 00 00 a8 61 00 00 00 52 01 47 01 3 | 0020 00 33 17 00 00 33 17 00 00 01 c1 a3 8d 42 03 00 4 | 0030 00 01 01 8b cc 00 00 5b d4 00 00 00 03 5b 90 ea 5 | 0040 aa 02 45 00 af 2e 00 00 00 00 00 00 03 21 20 32 6 | 0050 00 01 02 00 00 00 00 3b 01 0b 02 47 70 d0 00 00 7 | 0060 df ff ff ff 13 01 20 4e 00 00 11 34 00 00 85 49 8 | 0070 00 00 03 00 00 00 00 07 0d 06 0d 13 13 13 13 00 9 | 0080 00 20 4e 00 00 5a a5 8d 42 00 00 00 00 00 00 00 10 | 0090 00 00 00 00 00 7b df 11 | -------------------------------------------------------------------------------- /states2/all-off2.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 2e 00 cd 2c 00 00 00 00 00 00 03 21 20 02 2 | 0010 01 01 01 3f d8 00 00 a8 61 00 00 00 52 01 47 01 3 | 0020 00 33 17 00 00 33 17 00 00 01 c1 a3 8d 42 03 00 4 | 0030 00 01 01 86 cc 00 00 56 d4 00 00 00 03 5b 77 86 5 | 0040 aa 02 45 00 af 2e 00 00 00 00 00 00 03 21 20 32 6 | 0050 00 01 02 00 00 00 00 3b 01 0b 02 47 70 d0 00 00 7 | 0060 bd ff ff ff 13 01 20 4e 00 00 11 34 00 00 85 49 8 | 0070 00 00 03 00 00 00 00 07 0d 06 0d 13 13 13 13 00 9 | 0080 00 20 4e 00 00 4f a5 8d 42 00 00 00 00 00 00 00 10 | 0090 00 00 00 00 00 d5 de 11 | -------------------------------------------------------------------------------- /states2/all-off3.md: -------------------------------------------------------------------------------- 1 | 0000 aa 02 2e 00 cd 2c 00 00 00 00 00 00 03 21 20 02 2 | 0010 01 01 01 3f d8 00 00 a8 61 00 00 00 52 01 47 01 3 | 0020 00 33 17 00 00 33 17 00 00 01 c1 a3 8d 42 03 00 4 | 0030 00 01 01 8c cc 00 00 5c d4 00 00 00 03 5b fc 5e 5 | 0040 aa 02 45 00 af 2e 00 00 00 00 00 00 03 21 20 32 6 | 0050 00 01 02 00 00 00 00 3b 01 0b 02 47 6d d0 00 00 7 | 0060 bd ff ff ff 13 01 20 4e 00 00 11 34 00 00 85 49 8 | 0070 00 00 03 00 00 00 00 07 0d 07 0d 13 13 13 13 00 9 | 0080 00 20 4e 00 00 47 a5 8d 42 00 00 00 00 00 00 00 10 | 0090 00 00 00 00 00 10 7d 11 | -------------------------------------------------------------------------------- /License.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 nielsole Skydev0h 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /states/summary.md: -------------------------------------------------------------------------------- 1 | Handle: 0x002c 2 | 3 | AC Out: 4 | Off: 5 | 0030 00 00 6 | On: 7 | 0030 00 01 8 | 9 | 12VDC or USB: (last byte) 10 | 0020 00 00 00 c1 ef ff ff 00 01 11 | 12 | Estimate: 13 | 0070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a5 14 | 0080 ed 15 | (last two bytes) 16 | 17 | AC charge limitation: (Pretty sure this has another meaning.) 18 | 300W: 19 | 0020 00 00 00 cd e8 20 | 800W: 21 | 0020 00 00 00 99 f5 22 | 23 | 0000 aa 02 6f 00 83 2c 00 00 00 00 02 00 02 21 20 02 24 | 0010 50 00 00 00 00 4e 00 02 01 00 00 00 00 00 47 00 25 | 0020 00 00 00 cd e8 ff ff 00 01 00 00 00 00 00 00 00 26 | 0030 00 01 00 1a a0 05 2c 01 03 00 00 00 00 00 00 00 27 | 0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 28 | 0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 29 | 0060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 30 | 0070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a7 31 | 0080 14 32 | 33 | 0000 aa 02 6f 00 83 2c 00 00 00 00 02 00 02 21 20 02 34 | 0010 50 00 00 00 00 4e 00 02 01 00 00 00 00 00 47 00 35 | 0020 00 00 00 86 f2 ff ff 00 00 00 00 00 00 00 00 00 36 | 0030 00 00 00 1a a0 05 2c 01 03 00 00 00 00 00 00 00 37 | 0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 38 | 0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 39 | 0060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 | 0070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 61 41 | 0080 85 42 | -------------------------------------------------------------------------------- /commands/README.md: -------------------------------------------------------------------------------- 1 | Analyzing commands and decompiled source code there was some success in understanding command structure. 2 | 3 | Lets take a look at provided command dumps: 4 | 5 | ``` 6 | Data < Flags (incl. encr, chk, ack) Cmd Func << Similar MQTT 7 | Filename Hdr Ver length CRC8 | Seq number Prod Src Dst | C.Id Data CRC16 command name 8 | 12v-off aa 02 01 00 a0 0d 00 00 00 00 00 00 21 05 20 51 00 f3 02 mpptCar 9 | 12v-on aa 02 01 00 a0 0d 00 00 00 00 00 00 21 05 20 51 01 32 c2 mpptCar 10 | 400w-chl aa 02 03 00 8a 0d 00 00 00 00 00 00 21 05 20 45 90 01 ff 8a 43 acChgCfg 11 | 800w-chl aa 02 03 00 8a 0d 00 00 00 00 00 00 21 05 20 45 20 03 ff 8a c4 acChgCfg 12 | 1000w-chl aa 02 03 00 8a 0d 00 00 00 00 00 00 21 05 20 45 e8 03 ff 0b 3a acChgCfg 13 | ac-off aa 02 01 00 a0 0d 00 00 00 00 00 00 21 05 20 51 01 32 c2 <-- is a 12v command! 14 | ac-off2 aa 02 07 00 de 0d 00 00 00 00 00 00 21 05 20 42 00 ff ff ff ff ff ff 7b d1 acOutCfg 15 | ac-off3 aa 02 07 00 de 0d 00 00 00 00 00 00 21 05 20 42 00 ff ff ff ff ff ff 7b d1 acOutCfg 16 | ac-off4 aa 02 07 00 de 0d 00 00 00 00 00 00 21 05 20 42 00 ff ff ff ff ff ff 7b d1 acOutCfg 17 | ac-on aa 02 07 00 de 0d 00 00 00 00 00 00 21 05 20 42 00 ff ff ff ff ff ff 7b d1 acOutCfg 18 | ac-on2 aa 02 07 00 de 0d 00 00 00 00 00 00 21 05 20 42 01 ff ff ff ff ff ff 6b 11 acOutCfg 19 | ac-on3 aa 02 07 00 de 0d 00 00 00 00 00 00 21 05 20 42 01 ff ff ff ff ff ff 6b 11 acOutCfg 20 | ac-on4 aa 02 07 00 de 0d 00 00 00 00 00 00 21 05 20 42 01 ff ff ff ff ff ff 6b 11 acOutCfg 21 | usb-off aa 02 01 00 a0 0d 00 00 00 00 00 00 21 02 20 22 00 d7 46 dcOutCfg 22 | usb-on aa 02 01 00 a0 0d 00 00 00 00 00 00 21 02 20 22 01 16 86 dcOutCfg 23 | ``` 24 | 25 | There was an extra part `02 40 00 1a 00 16 00 04 00 52 2a 00` in `usb-on` command not related to it. 26 | 27 | I have also tried to point out corresponding MQTT commands and outlined them after the binary part. 28 | -------------------------------------------------------------------------------- /experimental/main.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | 4 | from bluetooth.ble import GATTRequester 5 | 6 | class Requester(GATTRequester): 7 | def on_notification(self, handle: int, data: str): 8 | pass 9 | 10 | 11 | def main(address: str): 12 | requester = Requester(address, False) 13 | connect(requester) 14 | request_data(requester) 15 | print("characeristics:") 16 | # Sends read by type request instead of read by by group type (UUID 0x2803 vs 0x2800) 17 | print(requester.discover_characteristics(0x0001, 0xffff)) 18 | print(requester.exchange_mtu(500)) 19 | requester.set_mtu(500) 20 | actions = { 21 | "ac_on": "aa 02 07 00 de 0d 00 00 00 00 00 00 21 05 20 42 01 ff ff ff ff ff ff 6b 11", 22 | "ac_off": "aa 02 07 00 de 0d 00 00 00 00 00 00 21 05 20 42 00 ff ff ff ff ff ff 7b d1", 23 | "12v_on": "aa 02 01 00 a0 0d 00 00 00 00 00 00 21 05 20 51 01 32 c2", 24 | "12v_off": "aa 02 01 00 a0 0d 00 00 00 00 00 00 21 05 20 51 00 f3 02", 25 | "usb_on": "aa 02 01 00 a0 0d 00 00 00 00 00 00 21 02 20 22 01 16 86", 26 | "usb_off": "aa 02 01 00 a0 0d 00 00 00 00 00 00 21 02 20 22 00 d7 46", 27 | } 28 | while True: 29 | print("Available actions:") 30 | for action in actions.keys(): 31 | print("{}".format(action)) 32 | selected_action = input("Which action to send? Leave empty and press return to exit. ") 33 | if len(selected_action) == 0: 34 | break 35 | try: 36 | trimmed_hex_string = actions[selected_action].replace(" ", "") 37 | data = bytes.fromhex(trimmed_hex_string) 38 | requester.write_cmd(0x002a, data) 39 | except KeyError as e: 40 | break 41 | 42 | def connect(requester): 43 | print("Connecting...", end=" ") 44 | sys.stdout.flush() 45 | 46 | requester.connect(True) 47 | print("OK.") 48 | 49 | def request_data(requester): 50 | data = requester.read_by_uuid( 51 | "00002a00-0000-1000-8000-00805f9b34fb")[0] 52 | try: 53 | print("Device name:", data.decode("utf-8")) 54 | except AttributeError: 55 | print("Device name:", data) 56 | 57 | 58 | if __name__ == "__main__": 59 | from gattlib import DiscoveryService 60 | 61 | if len(sys.argv) < 2: 62 | print("Usage: {} ".format(sys.argv[0])) 63 | service = DiscoveryService("hci0") 64 | devices = service.discover(2) 65 | 66 | for address, name in devices.items(): 67 | if address.startswith("34:B4"): 68 | print("name: {}, addr: {}".format(name, address)) 69 | print("^-- This might be an ecoflow device") 70 | sys.exit(1) 71 | main(sys.argv[1]) 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Delta 2 Bluetooth 2 | 3 | Reverse engineering of Delta 2 Bluetooth interface. 4 | No affiliation with Ecoflow. 5 | 6 | What currently works: 7 | * Turn on/off: 8 | * USB 9 | * AC 10 | * 12VDC output 11 | 12 | ## Demo 13 | 14 | The `experimental/main.py` script connects to the Delta 2 and let's you toggle the outputs. 15 | Follow the installation instructions for pybluez. 16 | The script must run as root. 17 | This is experimental. 18 | This might brick your device. 19 | I use linux, no other OS is tested, but it might just work for you. 20 | 21 | ## Overview 22 | 23 | The Delta 2 uses an Espressif bluetooth MAC Address (mine starts with 34:b4). 24 | 25 | The Delta 2 offers up 3 attributes: 26 | 27 | ``` 28 | Bluetooth Attribute Protocol 29 | Opcode: Read By Group Type Response (0x11) 30 | Length: 6 31 | Attribute Data, Handle: 0x0001, Group End Handle: 0x0005, UUID: Generic Attribute Profile 32 | Attribute Data, Handle: 0x0014, Group End Handle: 0x001c, UUID: Generic Access Profile 33 | Attribute Data, Handle: 0x0028, Group End Handle: 0xffff, UUID: SDP 34 | [UUID: GATT Primary Service Declaration (0x2800)] 35 | [Request in Frame: 726] 36 | ``` 37 | 38 | In my traces the following handles were used: 39 | * 0x002d SDP: RFCOMM Delta2->Phone 40 | * 0x002a SDP: UDP Phone -> Delta2 41 | 42 | 43 | ### RFCOMM status 44 | 45 | The Delta 2 sends out a beacon every 500ms that likely contains all current information, such as charge, discharge, port states etc. 46 | I tried decoding this beacon in `states` and `states2` but haven't had much success yet. 47 | 48 | ### UDP Commands 49 | 50 | Every action on the Delta 2 sends a UDP packet. 51 | I started labelling sample packets in commands. I have gotten some of them wrong, focussing on the data points I care about most rn. 52 | 53 | ## Contributing 54 | 55 | If you want to reverse engineer the connection from your Android phone to your bluetooth device, use the following process: 56 | 57 | Prerequisites: 58 | * An android phone with the app installed 59 | * A way to record your screen 60 | * A computer ideally with linux with wireshark and adb installed 61 | 62 | Process: 63 | * Connect phone via USB with Debugging turned on 64 | * Enable HCI snooping 65 | * (re-)enable Bluetooth 66 | * Film your actions e.g. with a second phone or screen recording 67 | * Open the app and do the thing you want to investigate 68 | * Optionally: turn off blueooth and HCI snooping 69 | * Retrieve the Blueooth snoop log 70 | * Either it is on the sd_card (wasn't for me), then do `adb pull ...` from the device 71 | * retrieve it via `adb bugreport` 72 | * open the file in wireshark 73 | * Try to establish a match between the video and the wireshark data. Tip: Jot down the times and their offsets on a piece of paper together with the performed action. 74 | 75 | In rare cases the app is stuck for up to 3 seconds after pressing a button before sending the packet, introducing an offset. 76 | -------------------------------------------------------------------------------- /states/README.md: -------------------------------------------------------------------------------- 1 | Applying the same analysis for commands but diving deeper into structure I analyzed states as well: 2 | 3 | ``` 4 | Data < Flags (incl. encrypt, check) Cmd Func << 5 | Filename Hdr Ver length CRC8 | Seq number Prod Src Dst | C.Id Data CRC16 6 | 12v-out-on aa 02 6f 00 83 2c 00 00 00 00 02 00 02 21 20 02 50 00 00 00 00 4e 00 02 01 00 00 00 00 00 47 00 00 00 00 cd e8 ff ff 00 00 00 00 00 00 00 00 00 00 00 00 14 a0 05 2c 01 03 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 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 00 00 00 00 00 00 a5 ed 7 | 400w-chrl aa 02 6f 00 83 2c 00 00 00 00 02 00 02 21 20 02 50 00 00 00 00 4e 00 02 01 00 00 00 00 00 47 00 00 00 00 cd e8 ff ff 00 00 00 00 00 00 00 00 00 00 00 00 14 a0 05 2c 01 03 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 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 00 00 00 00 00 00 a5 ed 8 | 800w-chrl aa 02 6f 00 83 2c 00 00 00 00 02 00 02 21 20 02 50 00 00 00 00 4e 00 02 01 00 00 00 00 00 47 00 00 00 00 99 f5 ff ff 00 00 00 00 00 00 00 00 00 00 00 00 14 a0 05 2c 01 03 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 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 00 00 00 00 00 00 f2 ca 9 | 1000w-chrl aa 02 6f 00 83 2c 00 00 00 00 02 00 02 21 20 02 50 00 00 00 00 4e 00 02 01 00 00 00 00 00 47 00 00 00 00 cd e8 ff ff 00 00 00 00 00 00 00 00 00 00 00 00 14 a0 05 2c 01 03 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 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 00 00 00 00 00 00 a5 ed 10 | ac-out-on-l aa 02 6f 00 83 2c 00 00 00 00 02 00 02 21 20 02 50 00 00 00 00 4e 00 02 01 00 00 00 00 00 47 00 00 00 00 84 ee ff ff 00 00 00 00 00 00 00 00 00 00 00 00 14 a0 05 2c 01 03 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 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 00 00 00 00 00 00 c1 e1 11 | ac-out-on aa 02 6f 00 83 2c 00 00 00 00 02 00 02 21 20 02 50 00 00 00 00 4e 00 02 01 00 00 00 00 00 47 00 00 00 00 cd e8 ff ff 00 00 00 00 00 00 00 00 00 00 01 00 14 a0 05 2c 01 03 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 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 00 00 00 00 00 00 25 1d 12 | all-off aa 02 6f 00 83 2c 00 00 00 00 02 00 02 21 20 02 50 00 00 00 00 4e 00 02 01 00 00 00 00 00 47 00 00 00 00 cd e8 ff ff 00 00 00 00 00 00 00 00 00 00 00 00 14 a0 05 2c 01 03 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 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 00 00 00 00 00 00 a5 ed 13 | all-off2 aa 02 6f 00 83 2c 00 00 00 00 02 00 02 21 20 02 50 00 00 00 00 4e 00 02 01 00 00 00 00 00 47 00 00 00 00 cd e8 ff ff 00 00 00 00 00 00 00 00 00 00 00 00 14 a0 05 2c 01 03 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 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 00 00 00 00 00 00 a5 ed 14 | all-on aa 02 6f 00 83 2c 00 00 00 00 02 00 02 21 20 02 50 00 00 00 00 4e 00 02 01 00 00 00 00 00 47 00 00 00 00 c1 ef ff ff 00 01 00 00 00 00 00 00 00 00 01 00 14 a0 05 2c 01 03 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 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 00 00 00 00 00 00 7f 95 15 | chrl-66p aa 02 6f 00 83 2c 00 00 00 00 02 00 02 21 20 02 50 00 00 00 00 4e 00 02 01 00 00 00 00 00 47 00 00 00 00 cd e8 ff ff 00 00 00 00 00 00 00 00 00 00 00 00 14 a0 05 2c 01 03 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 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 00 00 00 00 00 00 a5 ed 16 | summary aa 02 6f 00 83 2c 00 00 00 00 02 00 02 21 20 02 50 00 00 00 00 4e 00 02 01 00 00 00 00 00 47 00 00 00 00 86 f2 ff ff 00 00 00 00 00 00 00 00 00 00 00 00 1a a0 05 2c 01 03 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 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 00 00 00 00 00 00 61 85 17 | usb-out-on aa 02 6f 00 83 2c 00 00 00 00 02 00 02 21 20 02 50 00 00 00 00 4e 00 02 01 00 00 00 00 00 47 00 00 00 00 cd e8 ff ff 00 00 00 00 00 00 00 00 00 00 00 00 14 a0 05 2c 01 03 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 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 00 00 00 00 00 00 a5 ed 18 | | [Error ] [Version ] [Wifi Ver ] | | OutPw InPwr RemainDispl Be An U1 U2 U1 U2 U1 U2 U1 U2 St Pw Te Stand | Brig-/ [Car (12V)] [MPPT/Sol ] [ AC ] [Car (12V)] [ AC ] [ USB ] [ TypeC ] [Car out ] [ AC Out ] [ AC In ] [Car in ] [ MPPT/Sol] ?? ?? | Inf [ ??? Unknown ??? ] 19 | \-Model Wifi autorecovery-/ Battery level (may be neg)ep dW Wt Wt qW qW cW cW cT cT [Car12V] by TO LCD TO \- Input energy -/ \- Output energy -/ \- Time counters -/ RJ45-/ 20 | ``` 21 | 22 | But this time it was important to analyze the Data part as well. 23 | 24 | Most part, the packets have matched the Delta structure, present in hassio-ecoflow: https://github.com/vwt12eh8/hassio-ecoflow/blob/main/custom_components/ecoflow/ecoflow/receive.py 25 | 26 | All present packets are (2, 32, 2) that are PD module packets and can be parsed using `parse_pd_delta`. 27 | 28 | In my experience, you can also receive following type of packets: 29 | 30 | ``` 31 | (2, 32, 2) -> pd (len: 123) 32 | (3, 32, 2) -> ems (len: 46) 33 | (3, 32, 50) -> bms (len: 69) - primary battery 34 | (4, 32, 2) -> inv (len: 70) 35 | (5, 32, 2) -> mppt (len: 94) 36 | (6, 32, 50) -> bms (len: 69) - extra battery 37 | ``` 38 | 39 | And mostly their structure matches with some quirks and extra tails. --------------------------------------------------------------------------------