Start properly documenting the protocol

This commit is contained in:
Odd Stråbø 2021-11-02 04:26:40 +01:00
parent c7e97aca84
commit c367d642d8
5 changed files with 137 additions and 14 deletions

View file

@ -11,8 +11,8 @@ charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.{py,yaml,yml}]
[*.{py,yaml,yml,md}]
indent_style = space
[*.{yaml,yml}]
[*.{yaml,yml,md}]
indent_size = 2

View file

@ -26,6 +26,8 @@ repos:
rev: 2.3.54
hooks:
- id: editorconfig-checker
args:
- "--exclude=Protocol.md"
- repo: https://github.com/PyCQA/flake8
rev: 4.0.1
@ -38,7 +40,7 @@ repos:
- id: mypy
- repo: https://github.com/psf/black
rev: 21.9b0
rev: 21.10b0
hooks:
- id: black

85
Protocol.md Normal file
View file

@ -0,0 +1,85 @@
# Protocol
The protocol checksum is litle-endian CRC16-MODBUS, but the data itself seems to be big-endian (network order).
It is structured around 16bit words (read 4 returns 8 bytes).
I have seen the "Transfer ID?" field containing 0xFF and 0x01, I am not yet sure of the putpose of this field. Most transactions it is set to 0xFF.
## Reading
### Read request
```text
┌──────────────┐
╔═╡ Transfer ID? │
║ └──────────────┘
║ ┌────────────────────┐
║ ╔═╡ Operation (3=read) │
║ ║ └────────────────────┘
║ ║ ┌───────────────┐
║ ║ ╔═╡ Start address │
║ ║ ║ └───────────────┘
║ ║ ║ ┌────────────────────────────────┐
║ ║ ║ ╔═╡ Number of 2-byte words to read │
║ ║ ║ ║ └────────────────────────────────┘
║ ║ ║ ║ ┌─────────────────┐
║ ║ ║ ║ ╔═╡ Transaction CRC │
║ ║ ║ ║ ║ └─────────────────┘
┌╨─┬╨─┬──╨──┬──╨──┬──╨──┐
│FF│03│00 0C│00 08│91 d1│
└──┴──┴─────┴─────┴─────┘
```
### Read response
```text
┌──────────────┐
╔═╡ Transfer ID? │
║ └──────────────┘
║ ┌────────────────────┐
║ ╔═╡ Operation (3=read) │
║ ║ └────────────────────┘
║ ║ ┌──────────────────────────┐
║ ║ ╔═╡ Number of bytes returned │
║ ║ ║ └──────────────────────────┘
║ ║ ║ ┌──────┐ ┌─────────────────┐
║ ║ ║ ╔═╡ Data │ │ Transaction CRC ╞═╗
║ ║ ║ ║ └──────┘ └─────────────────┘ ║
┌╨─┬╨─┬╨─┬╨──────────────────────────────────────────────┬──╨──┐
│FF│03│10│20 20 20 20 4D 4C 32 34 32 30 20 20 20 20 20 20│FD 17│
└──┴──┴──┴───────────────────────────────────────────────┴─────┘
```
This particular memory section contains the device SKU: ML2420
## Writing
### Write request
```text
┌──────────────┐
╔═╡ Transfer ID? │
║ └──────────────┘
║ ┌────────────────────┐
║ ╔═╡ Operation (6=read) │
║ ║ └────────────────────┘
║ ║ ┌─────────┐
║ ║ ╔═╡ Address │
║ ║ ║ └─────────┘
║ ║ ║ ┌──────┐
║ ║ ║ ╔═╡ Data │
║ ║ ║ ║ └──────┘
║ ║ ║ ║ ┌─────────────────┐
║ ║ ║ ║ ╔═╡ Transaction CRC │
║ ║ ║ ║ ║ └─────────────────┘
┌╨─┬╨─┬──╨──┬──╨──┬──╨──┐
│FF│06│01 0A│00 01│7C 2A│
└──┴──┴─────┴─────┴─────┘
```
The data at 0x010A is a boolean controlling the load output switch.
### Write response
Seems to return exactly the same as the data written,
presumably to allow verifying that the data did indeed get written.

15
Readme.md Normal file
View file

@ -0,0 +1,15 @@
# SolarMPPT
<!-- TODO: Come up with a better name -->
Python library for interracting with the rather generic MPPT solar charge controller I got from the hardware store.
- [Biltema 25-5077](https://www.biltema.no/bil---mc/elektrisk-anlegg/solcellspaneler/mppt-regulator-20-a-2000045547)
The Android app suggested for the bluetooth interface is
[SolarApp](https://play.google.com/store/apps/details?id=com.shuori.gfv2.guangfu) by srne
(I'm not currently able to find the bluetooth bridge on Biltema's website?
It's got BT-1 printed on the front, and is basically just a RS-232 to BTLE UART GATT)
[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit)
![example workflow](https://github.com/oddstr13/SolarMPPT/actions/workflows/pre-commit/badge.svg)

View file

@ -15,24 +15,33 @@ INTERVAL = 15
write_device = "0000ffd1-0000-1000-8000-00805f9b34fb"
# read_device = "0000fff1-0000-1000-8000-00805f9b34fb"
# get(255, 12, 2)
# "ff 03 00 0c 00 02"
CMD_GET_1 = b"\xff\x03\x00\x0c\x00\x02"
# > ff 03 04 20 20 20 20
# get(255, 12, 8)
# ff 03 00 0c 00 08
CMD_GET_MODEL = b"\xff\x03\x00\x0c\x00\x08"
# > ff 03 10 20 20 20 20 4d 4c 32 34 32 30 20 20 20 20 20 20
# Device SKU: ML2420
# get(255, 20, 4)
# ff 03 00 14 00 04
CMD_GET_VERSION = b"\xff\x03\x00\x14\x00\x04"
# > ff 03 08 00 04 02 00 02 00 00 03
# CC ?? 11 22 33 ?? 44 55 66
# Version: 4.2.0
# get(255, 24, 3)
# ff 03 00 18 00 03
CMD_GET_SERIAL = b"\xff\x03\x00\x18\x00\x03"
# > ff 03 06 3c 13 02 67 00 01
# CC 11 22 33 33 ?? ??
# SN: 60-19-0615
# get(255, 256, 7)
# ff 03 01 00 00 07
CMD_GET_BATTERY_STATE = b"\xff\x03\x01\x00\x00\x07"
# > ff 03 0e 00 48 00 7e 00 1d 0e 0d 00 7e 00 1c 00 03
# CC 11 11 22 22 33 33 44 55 66 66 77 77 88 88
@ -45,6 +54,8 @@ CMD_GET_BATTERY_STATE = b"\xff\x03\x01\x00\x00\x07"
# 7: Load current: 0.28 A
# 8: Load power: 3 W
# get(255, 263, 4)
# ff 03 01 07 00 04
CMD_GET_PANEL_STATUS = b"\xff\x03\x01\x07\x00\x04"
# > ff 03 08 00 c8 00 14 00 04 00 01
# CC 11 11 22 22 33 33 ?? ??
@ -53,6 +64,21 @@ CMD_GET_PANEL_STATUS = b"\xff\x03\x01\x07\x00\x04"
# 3: Panel power: 4 W
# Charging status?
# set(255, 266, 1 or 0)
# ff 06 01 0a 00 01
CMD_ENABLE_LOAD = b"\xff\x06\x01\x0a\x00\x01"
CMD_DISABLE_LOAD = b"\xff\x06\x01\x0a\x00\x00"
REG_LOAD_ENABLE = 0x010A
# get(255, 267, 21)
# ff 03 01 0b 00 15
CMD_GET_LOAD_PARAMETERS = b"\xff\x03\x01\x0b\x00\x15"
# > ff 03 2a 00 7c 00 7f 00 51 00 20 00 0a 00 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
# get(255, 288, 3)
# ff 03 01 20 00 03
CMD_GET_2 = b"\xff\x03\x01\x20\x00\x03"
# > ff 03 06 80 02 00 00 00 00
# CC 11 22 33 33 33 33
@ -60,6 +86,8 @@ CMD_GET_2 = b"\xff\x03\x01\x20\x00\x03"
# 2: ?: 2
# 3: ?: 0
# get(255, 57345, 33)
# ff 03 e0 01 00 21
CMD_GET_BATTERY_PARAMETERS = b"\xff\x03\xe0\x01\x00\x21"
# > ff 03 42 07 d0 00 c8 ff 0c 00 02 00 a0 00 9b 00 92 00 90 00
# > 8a 00 84 00 7e 00 78 00 6f 00 6a 64 32 00 05 00 78 00 78 00
@ -67,13 +95,8 @@ CMD_GET_BATTERY_PARAMETERS = b"\xff\x03\xe0\x01\x00\x21"
# > 0f 00 05 00 05 00 04 01 00
# 33 * uint16
# (0xff, 267, 21)
CMD_GET_LOAD_PARAMETERS = b"\xff\x03\x01\x0b\x00\x15"
# > ff 03 2a 00 7c 00 7f 00 51 00 20 00 0a 00 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
# 01 03 f000 000a
# get(1, 61440, 10)
# 01 03 f0 00 00 0a
CMD_GET_HISTORICAL_TODAY = b"\x01\x03\xf0\x00\x00\x0a"
CMD_GET_HISTORICAL_YESTERDAY = b"\x01\x03\xf0\x01\x00\x0a"
CMD_GET_HISTORICAL_D2 = b"\x01\x03\xf0\x02\x00\x0a"
@ -103,9 +126,7 @@ CMD_GET_HISTORICAL_D3 = b"\x01\x03\xf0\x03\x00\x0a"
# production_power = 0 Wh
# consumption_power = 0 Wh
CMD_ENABLE_LOAD = b"\xff\x06\x01\x0a\x00\x01"
CMD_DISABLE_LOAD = b"\xff\x06\x01\x0a\x00\x00"
# ff 78 00 00 00 01
CMD_ = b"\xff\x78\x00\x00\x00\x01"
# CMD_GET_BATTERY_STATE = b'\xff\x03\x01\x00\x00\x07'