{"id":21945090,"url":"https://github.com/gurkengewuerz/micropython-sdcard-boot","last_synced_at":"2026-04-12T07:33:53.496Z","repository":{"id":143577465,"uuid":"580085797","full_name":"Gurkengewuerz/micropython-sdcard-boot","owner":"Gurkengewuerz","description":"SDCard bootloader with OTA support","archived":false,"fork":false,"pushed_at":"2022-12-27T01:27:59.000Z","size":32,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-05T00:39:01.632Z","etag":null,"topics":["bootloader","esp32","littlefs","micropython","ota"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Gurkengewuerz.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":"2022-12-19T17:23:14.000Z","updated_at":"2025-05-28T22:50:35.000Z","dependencies_parsed_at":null,"dependency_job_id":"142de009-4cc5-40d7-ab58-5abcca590345","html_url":"https://github.com/Gurkengewuerz/micropython-sdcard-boot","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Gurkengewuerz/micropython-sdcard-boot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Gurkengewuerz%2Fmicropython-sdcard-boot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Gurkengewuerz%2Fmicropython-sdcard-boot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Gurkengewuerz%2Fmicropython-sdcard-boot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Gurkengewuerz%2Fmicropython-sdcard-boot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Gurkengewuerz","download_url":"https://codeload.github.com/Gurkengewuerz/micropython-sdcard-boot/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Gurkengewuerz%2Fmicropython-sdcard-boot/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31707953,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-12T06:22:27.080Z","status":"ssl_error","status_checked_at":"2026-04-12T06:21:52.710Z","response_time":58,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["bootloader","esp32","littlefs","micropython","ota"],"created_at":"2024-11-29T04:17:44.722Z","updated_at":"2026-04-12T07:33:53.472Z","avatar_url":"https://github.com/Gurkengewuerz.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SDCard Boot with OTA\r\nMinimize accesses to the internal flash by using an external SD-Card as root directory. This way also OTA is available. I would not recommend OTA without an external flash because all these operations can contribute to degrade the flash and get to the maximum writes.  \r\nIf no external SD-Card should be used i would recommend eMMC ICs. With some changes also other Memory ICs can be used. Keep in mind that you maybe want to change the filesystem type from `FAT` to `LittleFS`.\r\n\r\n## Boot Sequence\r\nThe ESP32 initialize the SD-Card with a 1-width SDIO (slot 2) interface. In `boot.py` after the power-up the file system is checked for FAT. If an unknown or uninitialized filesystem was found the SD-Card will be formatted. After an successful initialisation the root `/` will be unmounted and the SD-Card will be mounted as root `/`. After a successful mount the `main.py` from the new root will be executed.\r\n\r\n## Flash\r\n1. Flash the `boot.py` to the internal filesystem.\r\n2. Power-up the board with an SD-Card\r\n3. Check if SD-Card was initialised\r\n4. Copy files as normal\r\n\r\nTo reflash the `boot.py` to the internal filesystem simply remove the SD-Card and power-up the board. This prevents the `main.py` from starting and you get a normal REPL.  \r\nAlternatively pull Pin `18` to GND. This way MicroPython enters the REPL after boot and mounts the SD-Card to `/sd` for browsing.\r\n\r\n## OTA\r\nThe OTA is heavily inspired by the great work of [mkomon/uota](https://github.com/mkomon/uota) and [rdehuyss/micropython-ota-updater](https://github.com/rdehuyss/micropython-ota-updater). Both projects didn't met my requirements. I wanted some kind of robust system with hash matching, undo on failing, replacing `main.py`, using my own server, etc.  \r\nWith my implementation you can do all of that but you need the folder structure like seen in `src/`. Everything can be replaced but only files in `/app` will be deleted if not needed anymore after an update. Any other file outside of `/app` will be replaced if changed to prevent any risk of corruption.\r\n\r\nThe bootloader (`boot.py`) can't be updated via OTA when booting from an SD-Card. This code must be robust as hell!\r\n\r\n### Workflow\r\nWhen `ota.install_update_if_available()` is called the following workflow is triggered\r\n\r\n1. Cleanup previous versions if something went wrong before\r\n2. Download newest version file with latest file name and hash\r\n3. Create folder structure for new version (Default in `next/`)\r\n4. Download latest file tar (Default in `firmware.tar`)\r\n5. Unpack downloaded tar file (start to get critical here - if something outside `/app` changed the file will be replaced and can't rolled back)\r\n6. Delete old `/app` folder\r\n7. Move `/next` to `/app`\r\n8. Cleanup if failed at any stage\r\n\r\n### OTA Files\r\nFiles are stored on your own webserver. The most important file is `versions` which contains all known versions. The latest version is always on the bottom. \r\n\r\n```csv\r\n0.0.1;0_0_1-firmware.tar;2988860ca0858eca16a795399148fca95b649784\r\n```\r\nExplanation: `Semantic Version;Filename relative to versions;sha1sum of filename`\r\n\r\n**Pack files**  \r\n`tar -cvf 0_0_1-firmware.tar app/ main.py # maybe other files`\r\n\r\n**Generate SHA1 hash**  \r\n`sha1sum *.tar`\r\n\r\n\r\n\r\n### LTE/GSM Access\r\nSome kind of implementation for LTE/GSM access is possible. For this a class can exists for WiFi and an external modem. A good example would be the OTA updater by [pycom](https://github.com/pycom/pycom-libraries/blob/96af79be7abcfca9f41a240decc6bd50b55bf5c4/examples/OTA/1.0.1/flash/lib/OTA.py).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgurkengewuerz%2Fmicropython-sdcard-boot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgurkengewuerz%2Fmicropython-sdcard-boot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgurkengewuerz%2Fmicropython-sdcard-boot/lists"}