{"id":25431933,"url":"https://github.com/jkorte-dev/mpy-dtu","last_synced_at":"2026-05-01T06:34:27.401Z","repository":{"id":277814751,"uuid":"910908653","full_name":"jkorte-dev/mpy-dtu","owner":"jkorte-dev","description":"Micropython tool for communicating with Hoymiles microinverters","archived":false,"fork":false,"pushed_at":"2025-12-25T15:59:29.000Z","size":1736,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-27T02:51:58.642Z","etag":null,"topics":["dtu","hoymiles","inverter","micropython"],"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/jkorte-dev.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-01-01T18:52:40.000Z","updated_at":"2025-12-25T15:57:52.000Z","dependencies_parsed_at":"2025-03-11T18:35:20.343Z","dependency_job_id":null,"html_url":"https://github.com/jkorte-dev/mpy-dtu","commit_stats":null,"previous_names":["jkorte-dev/mpy-dtu"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/jkorte-dev/mpy-dtu","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jkorte-dev%2Fmpy-dtu","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jkorte-dev%2Fmpy-dtu/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jkorte-dev%2Fmpy-dtu/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jkorte-dev%2Fmpy-dtu/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jkorte-dev","download_url":"https://codeload.github.com/jkorte-dev/mpy-dtu/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jkorte-dev%2Fmpy-dtu/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32487645,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-30T13:12:12.517Z","status":"online","status_checked_at":"2026-05-01T02:00:05.856Z","response_time":64,"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":["dtu","hoymiles","inverter","micropython"],"created_at":"2025-02-17T04:30:30.204Z","updated_at":"2026-05-01T06:34:27.395Z","avatar_url":"https://github.com/jkorte-dev.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"mpy-DTU \n=======================================================================\n\nA simple Micropython DTU for Hoymiles solar inverters. Live data from your inverter is shown on a display and send via MQTT for integration in home automation.\n\n\n![display](images/mpy-dtu.png) \n![display](images/mpy-dtu-web-light-sm2.png)\n![display](images/mpy-dtu-web-dark-sm2.png)\n![display](images/mpy-dtu-splash.png)\n![display](images/mpy-dtu-lcd.png)\n![display](images/mpy-dtu-esp32.png)\n\nIt's a fun project for people like me who like hacking with micropython. \n\nCommunicating with Hoymiles Micro-Inverters using Micropython\n------------------------\n\nThe `hoymiles` package in this directory is an adopted version of Ahoy CPython tools to communicate with Hoymiles micro-inverters [0].\nIt has been modified, refactored and extended to run on Micropython (tested so far on esp32c3, esp32s2, esp32, rp2350 (pico2 w), esp32c6, wemos w600 (console output only, not enough ram for more!)\nIt even runs on microcontrollers without wifi support, though it might not be very useful.\nI haven't tried esp8266 and do not recommend it because of hardware limitations, thought it might work.\nParts of the code is shared between CPython and Micropython. The code runs on Linux based Raspberry Pi hardware as well but this might change (Tested with Raspberry Pi Zero W so far).\nIf you want to run this code on a Linux based Raspberry Pi SBC see README.md [1] for hardware setup.\n\n*The following documentation assumes that you are familiar with Micropython and the tools `mpremote` [6] and `mpy-cross` [7]*\n\nRequired Hardware Setup\n-----------------------\nThe hardware setup on microcontrollers is the same as with regular Ahoy-DTU. [2]\n\nRequired Hardware:\n\n- ESP32x with Micropython (any esp32x is OK e.g. esp32s2, esp32s3, esp32c3, esp32c6). RP2350 W basically worked but nrf communication wasn't good. esp32 and w600 worked only with console output due to lack of ram (unless you use romfs, see instructions below.\n- nRF24L01+ Module\n- Optional: I2C OLED Display (128x64 ssd1306) or SPI LCD (128x64 st7567)\n- Hoymiles HM series solar inverter with panel ;-)\n- stable power supply for the microcontroller\n\nRequired Python Modules\n-----------------------\n\nSome modules are not installed by default on Micropython, therefore you have to add them manually:\n\n```code\nmpremote mip install logging\nmpremote mip install datetime\n```\n\nDependencies for output plugins:\n\n```code\nmpremote mip install umqtt.simple\nmpremote mip install umqtt.robust\nmpremote mip install ssd1306\nmpremote cp micropython-lib/ST7567.mpy :lib/ # optional for ST7567 LCD display\n```\n\nAn alternative way to install these dependencies is:\n\n```\nmpremote mip install github:jkorte-dev/mpy-dtu/micropython-lib/package.json\n```\n\n\n\nWiFi Setup\n----------\n\nYou also need some scripts to set up wifi\n```code\nmpremote mkdir :lib\nmpremote cp micropython-lib/wlan.py :lib/\n```\n\nEdit your wifi credentials `ssid` and `password` in `micropython-lib/secrets.py`\n\n```code\nsecrets = {\n    'ssid': 'SSID',\n    'password': 'PASSWORD',\n}\n```\n\nand copy the file to your device:\n\n```code\nmpremote cp micropython-lib/secrets.py :lib/\n```\n\nWith older micropython version you may get an import error when importing asyncio module.\n```\nmpremote cp micropython-lib/asyncio.py :lib/\n```\n\nwill fix it.\n\n\nnRF24L01 Driver\n---------------\n\nThe nRF24L01 driver for inverter communication requires support for `auto acknowledge` and `dynamic payloads`.\nUnfortunately the official Micropython driver does not support this features.\nTherefore, I included a driver which I ported from CircuitPython to Micropython.\nThe source of the original CircuitPython driver is [3]. See documentation from Adafruit [4]. The API is unchanged except initialization. \nAs the driver (and other code) consumes a lot of memory I recommend installing the driver\n`nrf24.py` as a mpy module using the micropython tool `mpy-cross` or use \n\n```code\n mpremote mip install --index https://raw.githubusercontent.com/jkorte-dev/mpy-dtu/master/nrf24 nrf24\n```\n\nConfiguration\n-------------\n\nLocal settings are read from `ahoy_cfg.py`  \nAn example is provided as `ahoy_cfg.example`\nEdit this file to your needs (**inverter serial number is required!**) and copy it to your device.\n\n```code\nmpremote cp ahoy_cfg.py :\n```\n\n\nModule Installation\n--------------------------\n\nManual installation using `mpremote`:\n\n```code \nmpremote mkdir hoymiles\nmpremote cp hoymiles/__init__.py           :hoymiles/\n\nmpremote mkdir hoymiles/decoders\nmpremote cp hoymiles/decoders/__init__.py  :hoymiles/decoders/\nmpremote cp hoymiles/decoders/ucrcmod.py   :hoymiles/decoders/\n\nmpremote mkdir hoymiles/uradio/\nmpremote cp hoymiles/uradio/__init__.py  :hoymiles/uradio/\nmpremote cp hoymiles/uradio/nrf24.py  :hoymiles/uradio/\n\nmpremote cp hoymiles/uoutputs.py           :hoymiles/\nmpremote cp hoymiles/dtu.py                :hoymiles/\nmpremote cp hoymiles/ulogo.py              :hoymiles/    # optional \nmpremote cp hoymiles/websunsethandler.py   :hoymiles/\nmpremote cp hoymiles/usunsethandler.py     :hoymiles/    # usunsethandler.py + sun_moon.py can replace websunsethandler.py \nmpremote cp hoymiles/sun_moon.py           :hoymiles/    # usunsethandler.py + sun_moon.py can replace websunsethandler.py \nmpremote cp hoymiles/uwebserver.py         :hoymiles/\n```\n\nAlternative Installation \n-------------------------\n\nThe module can also be installed as mip package [8] from the repo with \n\n```\nmpremote mip install --target / github:jkorte-dev/mpy-dtu/package.json\n```\n\nExample Run\n-----------\nMinimal code to communicate with a hoymiles inverter is:\n\n```code \nfrom hoymiles import HoymilesDTU\nimport asyncio\n\nahoy_config = {'interval': 5,\n               'transmit_retries': 5,\n               'nrf': [{'spi_num': 1, 'cs': 12, 'ce': 16}],  # esp32s2 wemos mini\n               'dtu': {'serial': 99978563001, 'name': 'mpy-dtu'},\n               'inverters': [\n                   {'name': 'HM_XXX',\n                    'serial': 114182912345,\n                    'strings': [\n                        {'s_name': 'Panel_1', 's_maxpower': 380},\n                        {'s_name': 'Panel_2', 's_maxpower': 380},\n                    ]\n                    }\n                ]\n               }\n\n\ndef result_handler(result, inverter): print(result.to_dict())\n\ndtu = HoymilesDTU(ahoy_cfg=ahoy_config,\n                  status_handler=result_handler,\n                  info_handler=lambda result, inverter: print(\"hw_info\", result, result.to_dict()))\n\nasyncio.run(dtu.start())\n```\nChange your SPI/Pin configuration according to your setup and do not forget to change the inverter serial number.\n\nThe following command will run a micropython script to poll the inverter and output to the configured outputs (display, mqtt).\n\n\n```code\nmpremote run hoymiles_mpy.py\n```\n\n### Web Page\nTo start a simple webserver serving a page which displays the inverters live data run:\n\n```code\nmpremote run hoymiles_exp.py\n```\n\n`hoymiles_exp.py` requires a lot of memory. You will need to install parts as mpy modules, at least the nrf24 driver. The script calls\n `gc.connect()` to free some memory.\n\n### Daytime / Nighttime Mode:\n\nIf you enable suntimes support in ahoy_cfg.py e.g:\n\n```\n'sunset': {'disabled': False, 'latitude': 51.799118, 'longitude': 10.615523, 'altitude': 1142}\n```\n\nthe inverter will be polled only during daytime of given location and time.\nThe web page will turn grey and a moon symbol is shown on the display during nighttime.\nDefault sunset handler is `websunsethandler.py` which requires network connection and consumes a lot of ram.\nAn experimental alternative is `usunsethandler.py` which needs `sun_moon.py` from Peter Hinch and a small config change (add `'mod': 'usunsethandler'`):\n\n```\n'sunset': {'disabled': False, 'latitude': 51.799118, 'longitude': 10.615523, 'altitude': 1142, 'mod': 'usunsethandler'}\n```\n\n\nOnce you are happy with `hoymiles_exp.py` or `hoymiles_mpy.py` you can start your mpy dtu on boot by importing one of the scrips in `main.py`.\nE.g.\n\n```\nimport hoymiles_exp\n```\n\nCaveats\n-------\n\n**This is work in progress and documentation is incomplete.**\n\nI have been running the code on an esp32c6 board for several days/weeks now without any issues, even with the web server enabled.\nImportant is, as I mentioned before stable power supply. I have enabled the Watchdog timer in `hoymiles_exp.py` to be sure to survive network outages.\n\nIf you run out of memory (e.g. you see `OSError: [Errno 12] ENOMEM`) install parts of the hoymiles modules as mpy modules using `mpy-cross`. \nStart with the `nrf24.py` driver and `hoymiles/decoder/__init.py`.\nI think esp32s2 is a good choice to start with as it has plenty of ram, esp32c6 works also very well.\nInverter polling is very bad on rp2350, but runs OK on esp32c6.\nWhile spending a lot of time on stability, I discovered that a stable power supply is crucial.\nOn the USB port the microcontroller stopped operating after some time. Do not use the cheapest power supply,\nbecause bad designed power supplies may interfere with the nrf24l01 module.\n\n*Only Hoymiles HM series supported. The communication with the inverter is readonly*\n\n\nRunning on ESP32 with romfs\n----------------------------\n\nI had success running the fully featured version of the dtu on esp32 with micropython 1.26.1. \nThis requires a custom build with romfs [9] / [10] support to deploy the ``hoymiles`` module in a romfs partition.\nOnce you have flashed micropython with romfs support you can try.\n\n1. prepare a directory ``./romfs`` with the following files:\n\n````\nromfs/logging.mpy\nromfs/ST7567.mpy\nromfs/ssd1306.mpy\nromfs/datetime.mpy\nromfs/crcmod.mpy\nromfs/hoymiles\nromfs/hoymiles/dtu.py\nromfs/hoymiles/ulogo.py\nromfs/hoymiles/uoutputs.py\nromfs/hoymiles/__init__.py\nromfs/hoymiles/uoutputs.py\nromfs/hoymiles/uwebserver.py\nromfs/hoymiles/decoders\nromfs/hoymiles/decoders/__init__.py\nromfs/hoymiles/websunsethandler.py\nromfs/hoymiles/usunsethandler.py\nromfs/hoymiles/sun_moon.py\nromfs/hoymiles/uradio\nromfs/hoymiles/uradio/__init__.py\nromfs/nrf24.mpy\nromfs/wlan.mpy\n````\n2. make image with:\n\n``mpremote romfs --output dtu.romfs build dtu_romfs``\n\n3. deploy the romfs with `mpremote` (latest mpremote with romfs support required):\n\n`` mpremote romfs deploy dtu.romfs`` or skipping step 2 with ``mpremote romfs deploy dtu_romfs``\n\nadditionally you need ``ahoy_cfg.py`` (the config file) , ``secrets.py`` for wifi setup and the main script ``hoymiles_mpy.py``\n\nModifications\n-------------\n\nModification made based on the original work from lumapu ahoy dtu:\n\n- moved all Linux/CPython specific code to `__main__.py`. All shared code to `hoymiles/__init__.py` and `decoders/__init__.py`\n- extracted actual DTU code to module dtu.py\n- extracted NFR24 communication code to new subpackage radio (Linux/CPython only)\n- NRF communication code for Micropython in subpackage uradio including driver ported from CircuitPython (Micropython only)\n- extracted sunset handler to module `sunsethandler.py`(Linux/CPython only)\n- added `websunsethandler.py` for Micropython because precision of used calculation was not sufficient on Micropython to calculate sunset, later added `usunsethandler.py` which uses sun set/rise calculation from Peter Hinch[11] .\n- added `uoutputs.py` for Micropython output plugins (Micropython only)\n- added `decoders/ucrcmod.py` minimal crc functions needed. Stripped down from [5] for Micropython (works on CPython as well)\n- used asyncio to be able to run webserver in parallel\n\nAll files starting with `u` are Micropython specific. `hoymiles/__main__.py` is not needed and will not run on Micropython.\n\nOutputs\n-------\n\nOutput plugins so far:\n\n- SSD1306 I2C display\n- ST7567 SPI display\n- MQTT\n- Blink LED / WS2812 NeoPixel\n- Web GUI\n\nTODOs\n------\n- make HoymilesNRF.receive() non-blocking\n- yield more time for async webserver\n- find out why polling inverter is so bad with rp2350\n- try async mqtt\n- remove logging to reduce size\n\nReferences\n----------\n\n- [0] https://github.com/lumapu/ahoy/blob/main/tools/rpi/hoymiles\n- [1] https://github.com/lumapu/ahoy/blob/main/tools/rpi/README.md\n- [2] https://github.com/lumapu/ahoy/\n- [3] https://github.com/nRF24/CircuitPython_nRF24L01\n- [4] https://circuitpython-nrf24l01.readthedocs.io/en/latest/\n- [5] https://crcmod.sourceforge.net/intro.html\n- [6] https://docs.micropython.org/en/latest/reference/mpremote.html\n- [7] https://docs.micropython.org/en/latest/reference/mpyfiles.html\n- [8] https://docs.micropython.org/en/latest/reference/packages.html\n- [9] https://github.com/micropython/micropython/wiki/Board-profile-configuration-for-RomFS\n- [10] https://github.com/orgs/micropython/discussions/17873\n- [11] https://github.com/peterhinch/micropython-samples/tree/master/astronomy\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjkorte-dev%2Fmpy-dtu","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjkorte-dev%2Fmpy-dtu","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjkorte-dev%2Fmpy-dtu/lists"}