{"id":13802623,"url":"https://github.com/ThinkTransit/micropython-aioschedule","last_synced_at":"2025-05-13T13:32:35.622Z","repository":{"id":54336210,"uuid":"521487135","full_name":"ThinkTransit/micropython-aioschedule","owner":"ThinkTransit","description":"Task scheduler with persistence for MicroPython","archived":false,"fork":false,"pushed_at":"2024-09-17T12:05:02.000Z","size":66,"stargazers_count":8,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-09-17T14:50:12.597Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/ThinkTransit.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-08-05T03:14:01.000Z","updated_at":"2024-09-17T12:05:06.000Z","dependencies_parsed_at":"2024-03-09T14:47:52.169Z","dependency_job_id":null,"html_url":"https://github.com/ThinkTransit/micropython-aioschedule","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ThinkTransit%2Fmicropython-aioschedule","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ThinkTransit%2Fmicropython-aioschedule/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ThinkTransit%2Fmicropython-aioschedule/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ThinkTransit%2Fmicropython-aioschedule/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ThinkTransit","download_url":"https://codeload.github.com/ThinkTransit/micropython-aioschedule/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225229879,"owners_count":17441336,"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","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":[],"created_at":"2024-08-04T00:01:48.768Z","updated_at":"2024-11-18T18:30:31.406Z","avatar_url":"https://github.com/ThinkTransit.png","language":"Python","readme":"# micropython-aioschedule\n\nOverview\n-----\n\nRun Python coroutines periodically using a friendly syntax.\n\n- Asynchronous using asyncio\n- A simple to use API for scheduling jobs\n- In-process scheduler for periodic jobs\n- Persistence, tasks survive reboot/restart/crash\n- Tested on MicroPython 1.19\n\nBased on the python schedule library by dbader https://github.com/dbader/schedule\n\nBackground\n-----\n\nThis project is very much a work in progress, having been ported from CPython it is not very \"micro\" and the codebase needs to be reduced. All issues/pr's welcome.\n\nThe goal of this library is to create a simple micropython scheduler that is asynchronous and persistent (tasks are stored in flash and can be reloaded after a reboot/restart/crash). This is important for devices that operate on battery power and need to conserve power. Devices can be put to deep sleep when no tasks are scheduled to run.\n\nAt this point in the time the library is designed to call async coroutines, in future non-async calls may be supported.\n\n\nRequirements\n-----\n\nRequires datetime and functools from micropython-lib\n\nAutomatic installation, requires MicroPython from github (later than 30-09-2022)\n```python\n\u003e\u003e\u003e import mip\n\u003e\u003e\u003e mip.install(\"github:ThinkTransit/micropython-aioschedule\")\n\nInstalling github:ThinkTransit/micropython-aioschedule/package.json to /lib\nCopying: /lib/schedule/schedule.py\nInstalling functools (latest) from https://micropython.org/pi/v2 to /lib\nCopying: /lib/functools.mpy\nInstalling datetime (latest) from https://micropython.org/pi/v2 to /lib\nCopying: /lib/datetime.mpy\nDone\n\u003e\u003e\u003e \n \n```\nManual installation\n```\nCopy schedule.py to your micropython lib directory\nCopy functools.py and datetime.py to your lib directory from micropython-lib\n```\n\nUsage\n-----\n\nCreate some tasks.\n\n```python\nimport schedule\n\nasync def job():\n    print(\"I'm working...\")\nschedule.every(1).minutes.do(job)\n\nasync def job_with_argument(name):\n    print(f\"I am {name}\")\nschedule.every(10).seconds.do(job_with_argument, name=\"MicroPython\")\n\n```\n\nIf you have an existing async application, add the scheduler task to your main event loop.\n```python\nimport schedule\nimport uasyncio as asyncio\n\nasyncio.create_task(schedule.run_forever())\n```\n\nFull simplified working example code.\n```python\nimport schedule\nimport uasyncio as asyncio\n\n\nasync def job():\n    print(\"I'm working...\")\nschedule.every(1).minutes.do(job)\n\n\nasync def job_with_argument(name):\n    print(f\"I am {name}\")\nschedule.every(10).seconds.do(job_with_argument, name=\"MicroPython\")\n\n\nasync def main_loop():\n    # Create the scheduling task\n    t = asyncio.create_task(schedule.run_forever())\n    await t\n\ntry:\n    asyncio.run(main_loop())\nexcept KeyboardInterrupt:\n    print('Interrupted')\nexcept Exception as e:\n    print(\"caught\")\n    print(e)\nfinally:\n    asyncio.new_event_loop()\n\n```\nPersistence\n-----\n\nTo persist the schedule it must be saved to flash by calling save_flash(). Typically this should be done before your microcontroller goes to sleep so that the last run times are saved.\n\n```python\nimport schedule\n\n# Save schedule to flash\nschedule.save_flash()\n```\n\nTo load from flash call load_flash(). Typically this should be done when your program first boots.\n```python\nimport schedule\n\n# Load schedule from flash\nschedule.load_flash()\n```\n\nIf your device is permanently running it is still a good idea to save the schedule to flash periodically so that in the event of a crash, last run times will be preserved. You can use a scheduled task to do this.\n```python\nimport schedule\n\nasync def save_schedule():\n    schedule.save_flash()\n\nschedule.every(30).minutes.do(save_schedule)\n```\n\nIt is important to note that when using persistence, the scheduled tasks only need to be created and saved to flash once. The easiest way to do this is to write a deployment function that creates the scheduled tasks, this function would be called once when the board is deployed, or when code is updated.\n```python\nimport schedule\n\nasync def job():\n    print(\"I'm working...\")\n\ndef create_schedule():\n    schedule.clear()\n    \n    schedule.every(30).minutes.do(job)\n    schedule.every().hour.do(job)\n    schedule.every().day.at(\"10:30\").do(job)\n    schedule.every().wednesday.at(\"13:15\").do(job)\n\n    schedule.save_flash()\n```\n\nDeepsleep support \n-----\nOne of the key advantages of a persistent scheduler is the ability for the device to sleep or enter low power mode when no tasks are scheduled to run. This is important for devices that operate on battery power.\n\nThe library includes a helper function idle_seconds() which can be used to determine how long to sleep for.\n\n```python\nimport schedule\nimport machine\n\nsleep_time = schedule.idle_seconds()\n\nmachine.deepsleep(int(sleep_time*1000))\n```\n\nWhen using deep sleep functionality there is no need to run a scheduling task in the main event loop. The device will simply boot, run pending tasks and then go back to sleep.\nIn this situation the simplifed example from above will now look like this.\n\n```python\nimport schedule\nimport machine\nimport uasyncio as asyncio\n\nasync def job():\n    print(\"I'm working...\")\n\nasync def job_with_argument(name):\n    print(f\"I am {name}\")\n    \n# This function is only run once during device deployment\ndef create_schedule():\n    schedule.clear()\n    \n    schedule.every(1).minutes.do(job) \n    schedule.every(10).seconds.do(job_with_argument, name=\"MicroPython\")\n    \n    schedule.save_flash()\n    \nasync def main_loop():\n    # Load schedule from flash\n    schedule.load_flash()\n    \n    # Run pending tasks\n    await schedule.run_pending()\n    \n    # Save schedule, this step is important to make sure the last run time is preserved\n    schedule.save_flash()\n    \n    sleep_time = schedule.idle_seconds()\n    \n    print(f'Going to sleep for { sleep_time } seconds.')\n\n    machine.deepsleep(sleep_time*1000)\n    \n    \ntry:\n    asyncio.run(main_loop())\nexcept KeyboardInterrupt:\n    print('Interrupted')\nexcept Exception as e:\n    print(\"caught\")\n    print(e)\nfinally:\n    asyncio.new_event_loop()\n\n```\n\nLimitations \n-----\nThe following are know limitations that need to be addressed in future releases.\n\nCoros names and arguments are saved to flash and run using eval. This creates two limitations.\n\n1. Only in scope coros that exist inside main can be used\n2. There is a potential security risk if the schedule.json file is modified to run arbitary code\n\n\n----\n\nPatrick Joy `patrick@joytech.com.au`\n\nInspired by Daniel Bader and distributed under the MIT license. See `LICENSE.txt \u003chttps://github.com/ThinkTransit/schedule-micropython/blob/master/LICENSE.txt\u003e` for more information.\n\nhttps://github.com/ThinkTransit/schedule-micropython\n","funding_links":[],"categories":["Libraries"],"sub_categories":["Scheduling"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FThinkTransit%2Fmicropython-aioschedule","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FThinkTransit%2Fmicropython-aioschedule","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FThinkTransit%2Fmicropython-aioschedule/lists"}