{"id":22120382,"url":"https://github.com/znitche/mppt-solar-regulator-btle-communication","last_synced_at":"2025-07-25T12:33:14.062Z","repository":{"id":242945120,"uuid":"810531645","full_name":"zNitche/mppt-solar-regulator-btle-communication","owner":"zNitche","description":"Exploration of communication methods with MPPT solar regulator using bluetooth (GATT) and modbus protocol","archived":true,"fork":false,"pushed_at":"2024-06-26T18:30:59.000Z","size":26,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-24T06:34:32.170Z","etag":null,"topics":["aioble","bluetooth","bluetooth-low-energy","bt","btle","micropython","mppt","mppt-charger","raspberry-pi-pico","solar","solar-system"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zNitche.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-06-04T22:01:11.000Z","updated_at":"2024-07-17T18:12:23.000Z","dependencies_parsed_at":"2024-06-25T23:24:05.976Z","dependency_job_id":"025d8111-9f95-4b63-8429-7bfa61e73695","html_url":"https://github.com/zNitche/mppt-solar-regulator-btle-communication","commit_stats":null,"previous_names":["znitche/mppt-solar-regulator-communication","znitche/mppt-solar-regulator-btle-communication"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/zNitche/mppt-solar-regulator-btle-communication","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zNitche%2Fmppt-solar-regulator-btle-communication","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zNitche%2Fmppt-solar-regulator-btle-communication/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zNitche%2Fmppt-solar-regulator-btle-communication/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zNitche%2Fmppt-solar-regulator-btle-communication/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zNitche","download_url":"https://codeload.github.com/zNitche/mppt-solar-regulator-btle-communication/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zNitche%2Fmppt-solar-regulator-btle-communication/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267007598,"owners_count":24020261,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-25T02:00:09.625Z","response_time":70,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aioble","bluetooth","bluetooth-low-energy","bt","btle","micropython","mppt","mppt-charger","raspberry-pi-pico","solar","solar-system"],"created_at":"2024-12-01T14:23:10.082Z","updated_at":"2025-07-25T12:33:13.741Z","avatar_url":"https://github.com/zNitche.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"### MPPT solar regulator - Bluetooth (GATT) communication \n\n#### Description\nExploration of communication methods with MPPT solar regulator using bluetooth and modbus protocol.\n\n#### Motivation\nI recently bought a MPPT solar regulator to use in my future off-grid projects. \nI set everything up, connected PV panel, 12V AGM battery\nadded some dummy load (in this case 6W LED) and everything worked like a charm.\n\nThen I discovered I can use the manufacturer's mobile app to view the regulator's parameters,\nwhich means that this device supports some communication protocol, so it can exchange data with mobile app.\n\nThat was perfect because before I decided to buy it I wanted to build MPPT solar regulator myself mostly because I\nwanted to have access to parameters such as PV voltage, load voltage etc. \n\nHaving a way to read and control this solar regulator was what I wanted to archive, so I started looking for a way to make\nit happen.\n\n#### Exploration\n\nI searched for a way to communicate with this solar regulator, found almost nothing, just this [repository](https://github.com/majki09/lumiax_solar_bt).\nI downloaded necessary dependencies, launched python script and to my surprise it worked, now I had proof it can be done.\nI started looking further.\n\nThen I thought to myself, maybe it supports modbus protocol, googled it and found official\n[documentation](https://www.lumiax.com/kindeditor/attached/file/User%20Manuals/Accessories/Lumiax%20Modbus%20Communication%20Protocol%20%20V4.3.pdf).\n\nFirst part is done, now I need a way to write and read data, let's take a closer look at device's bluetooth.\n\n```\n\u003e sudo bluetoothctl\n\u003e scan on\n```\n\nI got device MAC address (in the next parts referred to as [MAC])\n\n```\n\u003e scan off\n\u003e exit\n```\n\n```\n\u003e gatttool -b [MAC] -I\n\u003e connect\n\u003e characteristics\n```\n\ngot following output\n\n```\nhandle: 0x0002, char properties: 0x7b, char value handle: 0x0003, uuid: 00002a05-0000-1000-8000-00805f9b34fb\nhandle: 0x0005, char properties: 0x02, char value handle: 0x0006, uuid: 00002a00-0000-1000-8000-00805f9b34fb\nhandle: 0x0007, char properties: 0x02, char value handle: 0x0008, uuid: 00002a01-0000-1000-8000-00805f9b34fb\nhandle: 0x0009, char properties: 0x02, char value handle: 0x000a, uuid: 00002a02-0000-1000-8000-00805f9b34fb\nhandle: 0x000b, char properties: 0x02, char value handle: 0x000c, uuid: 00002a04-0000-1000-8000-00805f9b34fb\nhandle: 0x000d, char properties: 0x02, char value handle: 0x000e, uuid: 00002aa6-0000-1000-8000-00805f9b34fb\nhandle: 0x0010, char properties: 0x10, char value handle: 0x0011, uuid: 0000ff01-0000-1000-8000-00805f9b34fb\nhandle: 0x0013, char properties: 0x0c, char value handle: 0x0014, uuid: 0000ff02-0000-1000-8000-00805f9b34fb\nhandle: 0x0015, char properties: 0x1c, char value handle: 0x0016, uuid: 0000ff03-0000-1000-8000-00805f9b34fb\nhandle: 0x0018, char properties: 0x1e, char value handle: 0x0019, uuid: 0000ff04-0000-1000-8000-00805f9b34fb\n```\n\nalright now we have something to work with\n\n```\n\u003e exit\n\u003e sudo bluetoothctl\n\u003e menu gatt \n```\n\nnow let's look for `write` and `notify` characteristic, after some time (trial and error), I found\n\n```\n\u003e attribute-info 0000ff02-0000-1000-8000-00805f9b34fb\n```\n\n```\nCharacteristic - Unknown\n\tUUID: 0000ff02-0000-1000-8000-00805f9b34fb\n\tService: ...\n\tFlags: write-without-response\n\tFlags: write\n```\n\nand \n\n```\n\u003e attribute-info 0000ff01-0000-1000-8000-00805f9b34fb\n```\n\n```\nCharacteristic - Unknown\n    UUID: 0000ff01-0000-1000-8000-00805f9b34fb\n    Service: ...\n    Notifying: no\n    Flags: notify\n```\n\nWe got everything let's write some code.\n\nI decided to use `bleak` for bluetooth communication using GATT (`pygatt` is deprecated).\nAfter modifying the `bleak` example I created `read_parameters.py`\n\n```\n\u003e python3 scripts/read_parameters.py --address [MAC] --write_char \"0000ff02-0000-1000-8000-00805f9b34fb\" --notify_char \"0000ff01-0000-1000-8000-00805f9b34fb\" --read_target \"3046\"\n```\n\nWhere `3046` (hex) is target address to read, in this case battery voltage.\n\nIn response I got\n```\n010402055a3a5b \n```\n\nWhere according to documentation:\n- `01` - device id (always 01)\n- `04` - function code\n- `02` - bytes count\n- `055a` - value\n- `3a5b` - crc checksum\n\nconverting value to decimal I got `1370`, divided by `100` gives `13,7` which equals to current\nbattery voltage.\n\n`read_parameter.py` also supports reading multiple addresses, let's analyze this case\n```\n\u003e python3 read_parameters.py --address [MAC] --write_char \"0000ff02-0000-1000-8000-00805f9b34fb\" --notify_char \"0000ff01-0000-1000-8000-00805f9b34fb\" --read_target \"3046\" --targets_to_read 11\n```\n\nResponse\n```\n[Notification] Vendor specific: 01041605\n[Notification] Vendor specific: 5a002e02760000055a002101c400000ce4002504\n[Notification] Vendor specific: c53184\n```\n\nwhich gives\n```\n010416055a002e02760000055a002101c400000ce4002504c53184\n```\n\nwhere values we are looking for are\n```\n055a002a023f0000055a002401ed00000ce4002504c5\n```\n\njust in case we will check if crc is correct which means data is complete\n```\n\u003e python3 scripts/calc_crc.py --msg 010416055a002e02760000055a002101c400000ce4002504c5\n\n3184\n```\n\ndata is ok, now let's break it down and decode\n```\nhex value - address (dec) - value info - dec value - final value\n\n055a - 0d12358 - Current battery voltage - 1370 - 13,7 V\n002e - 0d12359 - Current battery current - 46 - 0,4 A\n0276 - 0d12360 - Battery power - 630 - 6,3 W\n0000 - 0d12361 - Battery power - 0\n055a - 0d12362 - Load Voltage - 1370 - 13,7 V\n0021 - 0d12363 - Load current - 33 0,3 A\n01c4 - 0d12364 - Load power - 452 = 4.52 W\n0000 - 0d12365 - Load power - 0\n0ce4 - 0d12366 - The voltage of the solar panel - 3300 - 33 V\n0025 - 0d12367 - The current of the solar panel - 37 - 0,37 A\n04c5 - 0d12368 - PV cell array current generated power - 1221 - 12,2 W\n```\n\nnow write script to automate the whole process\n```\n\u003e python3 read_mppt_data.py --address [MAC]\n\nBattery remaining capacity -\u003e 84.0 %\nBattery voltage -\u003e 13.1 V\nBattery current -\u003e 654.98 A\nBattery power -\u003e 650.39 W\nLoad voltage -\u003e 13.1 V\nLoad current -\u003e 0.45 A\nLoad power -\u003e 5.89 W\nSolar voltage -\u003e 16.8 V\nSolar current -\u003e 0.07 A\n```\n\nit works, well, kind of, it looks like there is a issue with parsing negative values.\n\nafter tweaking\n```\n\u003e python3 read_mppt_data.py --address [MAC]\n\nBattery remaining capacity -\u003e 99.0 %\nBattery voltage -\u003e 13.1 V\nBattery current -\u003e -0.31 A\nBattery power -\u003e -4.06 W\nLoad voltage -\u003e 13.1 V\nLoad current -\u003e 0.31 A\nLoad power -\u003e 4.06 W\nSolar voltage -\u003e 9.1 V\nSolar current -\u003e 0.0 A\n```\n\nAnd here we are, having foundations to build upon.\n\n#### Micropython (Raspberry Pi Pico W)\nAh here we go again, it is time to utilize MicroPython on RaspberryPi Pico W.\nThis time we will use following packages:\n\n- [aioble](https://github.com/micropython/micropython-lib/tree/master/micropython/bluetooth/aioble) - for working with async bluetooth.\n- [rshell](https://github.com/dhylands/rshell) - as MicroPython remote shell.\n\nFor local development:\n```\npip3 install -r micropython/requirements.txt\n```\n\nTo flash files\n```\nrshell -f micropython/commands/flash_w_repl\n```\n\nWe won't go into details as everything was nicely described above. As proof that it can be done using `aioble` I wrote simple bare reader without \nsupport for data parsing, this file is called `bare_mppt_reading.py`.\n\nI flashed microcontroller, run code, got following output\n\n```\n[Notification] CRC 938e | 0104160063055a001c017f0000055a002c025a00\ndata: 0104160063055a001c017f0000055a002c025a00000cc600222496\ndone\n```\n\nHaving proof that bluetooth library works fine I started porting Python `read_mppt_data.py` to MicroPython.\nThe result of this work is `mppt_reader.py`. Which produces following output.\n\n```\nBattery remaining capacity -\u003e 99.0 %\nBattery voltage -\u003e 13.7 V\nBattery current -\u003e 0.29 A\nBattery power -\u003e 3.97 W\nBattery power -\u003e 0.0 W\nLoad voltage -\u003e 13.7 V\nLoad current -\u003e 0.43 A\nLoad power -\u003e 5.89 W\nLoad power -\u003e 0.0 W\nSolar voltage -\u003e 32.4 V\nSolar current -\u003e 0.34 A\n```\n\nNow having both implementations allowing me to use any small factor board running Linux or microcontroller with WiFi and MicroPython support,\nI can't wait to build something with it.\n\n#### Resources\n- [communication proof of concept](https://github.com/majki09/lumiax_solar_bt)\n- [modbus documentation](https://www.lumiax.com/kindeditor/attached/file/User%20Manuals/Accessories/Lumiax%20Modbus%20Communication%20Protocol%20%20V4.3.pdf)\n- [GATT introduction](https://learn.adafruit.com/introduction-to-bluetooth-low-energy/gatt)\n- [modbus CRC checksum](https://stackoverflow.com/questions/69369408/calculating-crc16-in-python-for-modbus)\n- [signed dec in python](https://stackoverflow.com/questions/24563786/conversion-from-hex-to-signed-dec-in-python)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fznitche%2Fmppt-solar-regulator-btle-communication","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fznitche%2Fmppt-solar-regulator-btle-communication","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fznitche%2Fmppt-solar-regulator-btle-communication/lists"}