{"id":37758721,"url":"https://github.com/ddedalus/syringe-pump","last_synced_at":"2026-01-16T14:34:01.386Z","repository":{"id":196266306,"uuid":"637852114","full_name":"Ddedalus/syringe-pump","owner":"Ddedalus","description":"Controller for a Legato 100 syringe pump, commonly used in flow chemistry experiments","archived":false,"fork":false,"pushed_at":"2023-09-30T10:15:29.000Z","size":149,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-08-24T17:03:37.223Z","etag":null,"topics":["asyncio","automation","chemistry","legato","polymers","pump","serial-communication","syringe"],"latest_commit_sha":null,"homepage":"https://github.com/Ddedalus/syringe-pump","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Ddedalus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-05-08T14:44:48.000Z","updated_at":"2025-03-31T13:43:29.000Z","dependencies_parsed_at":null,"dependency_job_id":"b6f2b5ab-69b7-4382-9c6e-e82a40bf71aa","html_url":"https://github.com/Ddedalus/syringe-pump","commit_stats":{"total_commits":99,"total_committers":1,"mean_commits":99.0,"dds":0.0,"last_synced_commit":"906d01483652d39e31cd9bbc0ae43e1f652f29f3"},"previous_names":["ddedalus/syringe-pump"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/Ddedalus/syringe-pump","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ddedalus%2Fsyringe-pump","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ddedalus%2Fsyringe-pump/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ddedalus%2Fsyringe-pump/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ddedalus%2Fsyringe-pump/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Ddedalus","download_url":"https://codeload.github.com/Ddedalus/syringe-pump/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ddedalus%2Fsyringe-pump/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28479396,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T11:59:17.896Z","status":"ssl_error","status_checked_at":"2026-01-16T11:55:55.838Z","response_time":107,"last_error":"SSL_read: 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":["asyncio","automation","chemistry","legato","polymers","pump","serial-communication","syringe"],"created_at":"2026-01-16T14:34:00.673Z","updated_at":"2026-01-16T14:34:01.380Z","avatar_url":"https://github.com/Ddedalus.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ccenter\u003e\n\n_Python controller for Legato family of syringe pumps_\n\n\n\u003cimg src=\"https://raw.githubusercontent.com/Ddedalus/syringe-pump/main/assets/logo/syringe_icon.png\" width=\"100\" height=\"100\" alt=\"Syringe logo by Freepik @ Flaticon.com\" /\u003e\n\n| ![Tests](https://github.com/Ddedalus/syringe-pump/actions/workflows/test.yml/badge.svg) | [![Test Coverage](https://coveralls.io/repos/github/Ddedalus/syringe-pump/badge.svg?branch=main)](https://coveralls.io/github/Ddedalus/syringe-pump?branch=main) | [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) |\n|:-:|:-:|:-:|\n| [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) | [![Latest version](https://badge.fury.io/py/python-syringe-pump.svg)](https://pypi.org/project/python-syringe-pump/) | [![GitHub issues](https://img.shields.io/github/issues/ddedalus/syringe-pump)]()\n\n\u003c/center\u003e\n\nControl a syringe pumpt (e.g. Legato 100 / 101) using a computer.\nThis package uses a COM port to communicate with the pump via an USB cable.\nIt enables you to write python programs that control the pump, e.g. turn it on and off, set the flow rate, etc.\n\n# Installation\n\n```bash\npip install python-syringe-pump\n```\nor\n```bash\npoetry add python-syringe-pump\n```\n\n# Usage\n\n## Working example\n\nCopy-paste this to get going!\n\n```python\nimport asyncio\nimport aioserial\nfrom syringe_pump import Pump, Quantity\n\nasync def main():\n    serial = aioserial.AioSerial(port=\"COM4\", baudrate=115200, timeout=2)\n    async with Pump(serial=serial) as pump:\n        await pump.infusion_rate.set(Quantity(\"1 ml/min\"))\n        await pump.run()\n        await asyncio.sleep(10)\n    # pump will stop when exiting the context manager\n\nasyncio.run(main())\n```\n\nCurious about the pieces of code above? Read on!\n\n### Serial port connection\nThe `syringe_pump` uses [aioserial](https://pypi.org/project/aioserial/)\nto communicate with the pump via the COM port.\nTo use the controller, create a serial connection and pass it into the Pump class.\n\n```python\nimport aioserial\nserial = aioserial.AioSerial(port=\"COM4\", baudrate=115200, timeout=2)\n```\n\n### Async communication\nThis package uses [asyncio](https://realpython.com/async-io-python/#the-10000-foot-view-of-async-io) to communicate with the pump.\nAs a result, you need to add a few `await` statements to your code, which may seem like a pain.\nHowever, the benefits will be worth it, especially when working with multiple pumps or sending experiment results via a network.\n\n``` python\nfrom syringe_pump import Pump, Quantity\n\npump = await Pump.from_serial(serial=serial)\nawait pump.infusion_rate.set(Quantity(\"1 ml/min\"))\nawait pump.run()\n```\n\n**Note**: The `from_serial` class method will configure the pump to\nuse the correct communication protocol and disable NVRAM, following manufacturer's recommendations.\n\n### Async context manager\n\nIn python, it's common to use [context managers](https://www.pythontutorial.net/advanced-python/python-context-managers/)\nto handle external resources such as files, network connections, etc.\n\nInstead of the above examle, you can use the `Pump` as such context manager, which will\nautomatically stop the pump in case of an error or at the end of the program.\n\n```python\nfrom syringe_pump import Pump, Quantity\n\nasync with Pump(serial=serial) as pump:\n    await pump.infusion_rate.set(Quantity(\"1 ml/min\"))\n    await pump.run()\n```\n\n### Running async code\nTo run the async code in a normal python file,\nyou need to use the `asyncio.run` function or similar:\n\n```python\nimport asyncio\n# in regular python file:\n\nasync def main():\n    asyncio.sleep(1)\n\nasyncio.run(main())\n```\n\n**Note**: To benefit from non-blocking asyncio code, use `asyncio.sleep` instead of `time.sleep`.\n\n**Note**: in a jupyter notebook, you can use `await` directly in the cell:\n\n```python\n# in jupyter notebook only:\nawait main()\n```\n\n## API\n\n### Units\nThe pump controller uses the [quantiphy](https://pypi.org/project/quantiphy/) package to handle flow rates, volumes etc.\n\nExample usage:\n```python\nfrom syringe_pump import Quantity\nQuantity(\"1 ml/min\")\nQuantity(\"13.54 ml\")\n```\n\n### Pump class\nThe controller implements most of the functionality specified in\n[Legato user Commands](https://datasci.app.box.com/s/fkzmervnhyciy91hnn446eio7yazb7k2).\n\nThe methods and their parameters are easy to discover using autocomplete in your IDE.\n\nHere's a quick overview of the popular methods:\n * `run` \u0026 `stop`: control the pump operation\n * `set_brightness`: control the onboard display. Set to 0 to turn off.\n * `set_force` \u0026 `get_force`: control the force applied to the syringe\n\nNext, the pump controller has some properties that allow you to manage other parameters:\n\n### Pump.infusion_rate and Pump.withdrawal_rate\nThe pump flow rates can be controlled here, including ramping.\nCommon methods available are:\n * `set` and `get`\n * `set_ramp(start, end, duration)`\n\nExample:\n```python\nrate = await pump.infusion_rate.get_rate()\nawait pump.infusion_rate.set_rate(2 * rate)\nawait pump.infusion_rate.set_ramp(2 * rate, 0, 10)\n```\n\n### Pump.syringe\nThe syringe parameters can be controlled here.\nThe pump uses them to convert between flow rates and volumes.\n\nImportant methods:\n * `get_diameter` and `set_diameter`\n * `get_volume` and `set_volume`\n * `set_manufacturer` - to use pre-defined settings for common syringes\n\nExample:\n```python\nfrom syringe_pump import Manufacturer\nawait pump.syringe.set_manufacturer(Manufacturer.HOSHI, Quantity(\"1 ml\"))\n```\n\n# Examples\nSee the [examples](https://github.com/Ddedalus/syringe-pump/tree/main/examples) folder for more examples.\n\n### Pump.infusion_volume and Pump.withdrawal_volume\nAllows you to inspect and reset the volume dispensed by the pump.\nThe pump keeps track of the volume since last reset by itself.\n\nMethods:\n * `get`\n * `clear`\n\n### Pump.target_volume\nAllows you to set a volume after which the pump will stop by itself.\nThis is useful to prevent the pump from over-dispensing and damaging the syringe.\n\nMethods:\n * `set`\n * `clear`\n * `get` - returns the target volume or `None` if not set\n\nNote that there is only one target volume across infusion and withdrawal.\nNegative values are not allowed.\n\n### Pump.target_time\nAllows you to set a time after which the pump will stop by itself.\nThe time is represented as a `datetime.timedelta` object.\n\nMethods:\n * `set`\n * `clear`\n * `get` - returns the target time or `None` if not set\n\nExample:\n```python\nfrom datetime import timedelta\nawait pump.target_time.set(timedelta(hours=2, minutes=10))\n```\n\n**Note**: it seems the pumpt can only handle target time or target volume, but not both.\n\n# Development\n\nHave a look at [CONTRIBUTING.md](https://github.com/Ddedalus/syringe-pump/blob/main/CONTRIBUTING.md) for more information on the scope of the project and how to contribute.\n\n# Credits\n\nProject logo: [Freepik @ Flaticon.com](https://www.flaticon.com/free-icons/syringe)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fddedalus%2Fsyringe-pump","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fddedalus%2Fsyringe-pump","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fddedalus%2Fsyringe-pump/lists"}