{"id":42509595,"url":"https://github.com/obeezzy/lpminimk3","last_synced_at":"2026-01-28T14:07:20.530Z","repository":{"id":39656260,"uuid":"345510814","full_name":"obeezzy/lpminimk3","owner":"obeezzy","description":"Python API for the Launchpad Mini MK3","archived":false,"fork":false,"pushed_at":"2025-07-30T00:30:31.000Z","size":2137,"stargazers_count":39,"open_issues_count":3,"forks_count":4,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-11-30T23:36:51.060Z","etag":null,"topics":["midi","python3"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/lpminimk3/","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/obeezzy.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}},"created_at":"2021-03-08T02:45:49.000Z","updated_at":"2025-10-27T02:28:15.000Z","dependencies_parsed_at":"2024-05-02T21:36:50.384Z","dependency_job_id":"b6886f2b-657e-4deb-9640-d95d9135ff18","html_url":"https://github.com/obeezzy/lpminimk3","commit_stats":{"total_commits":204,"total_committers":2,"mean_commits":102.0,"dds":0.004901960784313708,"last_synced_commit":"2041f0ea04594eaf8461e9f884944556b2d9d5ee"},"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"purl":"pkg:github/obeezzy/lpminimk3","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/obeezzy%2Flpminimk3","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/obeezzy%2Flpminimk3/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/obeezzy%2Flpminimk3/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/obeezzy%2Flpminimk3/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/obeezzy","download_url":"https://codeload.github.com/obeezzy/lpminimk3/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/obeezzy%2Flpminimk3/sbom","scorecard":{"id":700823,"data":{"date":"2025-08-11","repo":{"name":"github.com/obeezzy/lpminimk3","commit":"1633721ff43aaa1629850141155fc4b54f0613f1"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.7,"checks":[{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 0/10 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":9,"reason":"10 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 9","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/deploy.yml:1","Warn: no topLevel permission defined: .github/workflows/main.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/deploy.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/obeezzy/lpminimk3/deploy.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/deploy.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/obeezzy/lpminimk3/deploy.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/obeezzy/lpminimk3/main.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:23: update your workflow using https://app.stepsecurity.io/secureworkflow/obeezzy/lpminimk3/main.yml/main?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/deploy.yml:23","Warn: pipCommand not pinned by hash: .github/workflows/deploy.yml:24","Warn: pipCommand not pinned by hash: .github/workflows/main.yml:30","Warn: pipCommand not pinned by hash: .github/workflows/main.yml:31","Warn: pipCommand not pinned by hash: .github/workflows/main.yml:32","Info:   0 out of   4 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   5 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 29 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-22T05:10:32.684Z","repository_id":39656260,"created_at":"2025-08-22T05:10:32.684Z","updated_at":"2025-08-22T05:10:32.684Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28846058,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-28T13:02:32.985Z","status":"ssl_error","status_checked_at":"2026-01-28T13:02:04.945Z","response_time":57,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6: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":["midi","python3"],"created_at":"2026-01-28T14:07:19.891Z","updated_at":"2026-01-28T14:07:20.522Z","avatar_url":"https://github.com/obeezzy.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# lpminimk3\n\nPython API for the [Novation Launchpad Mini MK3](https://us.novationmusic.com/products/launchpad-mini-mk3)\n\n[![CI](https://github.com/obeezzy/lpminimk3/actions/workflows/main.yml/badge.svg)](https://github.com/obeezzy/lpminimk3/actions/workflows/main.yml)\n[![Deployment to PyPI](https://github.com/obeezzy/lpminimk3/actions/workflows/deploy.yml/badge.svg?branch=v0.6.4)](https://github.com/obeezzy/lpminimk3/actions/workflows/deploy.yml)\n[![Documentation Status](https://readthedocs.org/projects/lpminimk3/badge/?version=latest)](https://lpminimk3.readthedocs.io/en/latest/?badge=latest)\n\n![Launchpad displaying common logos](https://github.com/obeezzy/lpminimk3/blob/main/media/logos.gif)\n\nThe goals of this project are as follows:\n* Intuitive, object-oriented design\n* Convenient for use in script and shell\n* Access to all (or most) of the Launchpad Mini MK3 MIDI features\n\n\n## Installation\nTo install the most stable version of this package, run:\n```bash\n$ pip install lpminimk3\n```\nTo test the installation, connect your Launchpad to your computer and run:\n```bash\n$ python -m lpminimk3.examples.hello\n```\n\n\n## Usage example\nMake sure your Launchpad is connected to your computer.\n\n### In script\nControl LEDs individually:\n```python\n\"\"\"Display a random array of colors for 5 seconds.\n\"\"\"\n\nfrom lpminimk3 import Mode, find_launchpads\nimport random\nimport time\n\nlp = find_launchpads()[0]  # Get the first available launchpad\nlp.open()  # Open device for reading and writing on MIDI interface (by default)\n\nlp.mode = Mode.PROG  # Switch to the programmer mode\n\nfor led in lp.panel.led_range():  # Loop through all LEDs\n    led.color = random.randint(1, 127)  # Set LED to a random color\n\ntime.sleep(5)  # Keep LEDs on for a while\n\nfor led in lp.panel.led_range():\n    del led.color  # Turn off LED\n```\nRender text on Launchpad's surface:\n```python\n\"\"\"Scroll text from right to left across the Launchpad's surface.\n\"\"\"\n\nfrom lpminimk3 import Mode, find_launchpads\nfrom lpminimk3.graphics import Text\n\nlp = find_launchpads()[0]  # Get the first available launchpad\nlp.open()  # Open device for reading and writing on MIDI interface (by default)\n\nlp.mode = Mode.PROG  # Switch to the programmer mode\n\nlp.grid.render(Text(' Hello, world!').scroll())  # Scroll text once\n```\nSee more examples [here](https://github.com/obeezzy/lpminimk3/tree/main/lpminimk3/examples).\n\n### In shell\nStart by finding a connected device and opening the device for reading and writing:\n```bash\n$ python\n\u003e\u003e\u003e import lpminimk3\n\u003e\u003e\u003e lp = lpminimk3.find_launchpads()[0]\n\u003e\u003e\u003e lp.open()\n```\nQuery the device to ensure we can read and write to it:\n```python\n\u003e\u003e\u003e lp.device_inquiry()  # Query device\nMidiEvent(message=[240, 0, 32, 41, 2, 13, 14, 1, 247], deltatime=150.938086752)\n```\nSwitch to `programmer` mode to start manipulating button LEDs:\n```python\n\u003e\u003e\u003e lp.mode = 'prog'  # Switch to programmer mode\n\u003e\u003e\u003e lp.grid.led(0).color = 10  # Set color of LED at grid position 0 to yellow (Valid values: 0 - 127)\n\u003e\u003e\u003e lp.grid.led(1,0).color = lpminimk3.colors.ColorPalette.Red.SHADE_1  # Set from palette\n\u003e\u003e\u003e lp.grid.led('0x1').color = lpminimk3.colors.WebColor(\"amethyst\")  # Set color from web colors\n\u003e\u003e\u003e lp.panel.led('logo').color = 'violet'  # Set logo LED color to violet\n\u003e\u003e\u003e lp.panel.led('drums').color = 'green2'  # Set 'Drums' LED color to second shade of green\n\u003e\u003e\u003e lp.panel.led('stop').color = 'w1'  # Set 'Stop/Solo/Mute' LED color to first shade of white\n\u003e\u003e\u003e lp.panel.led('mute').color = 'o3'  # Set 'Stop/Solo/Mute' LED color to third shade of orange\n\u003e\u003e\u003e lp.panel.led('mute').color = 'r0'  # Invalid but okay, will default to 'r1'\n\u003e\u003e\u003e lp.panel.led('scene_launch_1').color = '#ff0000'  # Set color to red using hex\n\u003e\u003e\u003e lp.panel.led('scene_launch_2').color = (0, 0, 255)  # Set color to blue using rgb\n\u003e\u003e\u003e lp.panel.led('mute').color = 0  # Turn off LED\n\u003e\u003e\u003e lp.panel.led('logo').reset()  # Another way to turn off LED\n\u003e\u003e\u003e del lp.panel.led('stop').color  # Another way to turn off LED\n\u003e\u003e\u003e lp.panel.reset()  # Turn off all LEDs\n```\nNote in the above snippet that `lp.grid` only contains the __*grid*__ buttons\n(i.e. the translucent, faceless buttons) and `lp.panel` contains all buttons\n(including the __*logo*__ LED at the top right corner).  \n\nWait for and respond to button presses and releases:\n```python\n\u003e\u003e\u003e ev = lp.panel.buttons().poll_for_event()  # Block until any button is pressed/released\n\u003e\u003e\u003e ev\nButtonEvent(button='7x5', type='press', deltatime=0.0)\n```\nOr only button releases instead:\n```python\n\u003e\u003e\u003e ev = lp.panel.buttons().poll_for_event(type='release')  # Block until released\n\u003e\u003e\u003e ev\nButtonEvent(button='up', type='release', deltatime=0.0)\n```\nPass button names as arguments to wait for specific button events:\n```python\n\u003e\u003e\u003e lp.panel.buttons('up', '0x0', 'stop').poll_for_event()\n```\nRender `A` on Launchpad's surface:\n```python\n\u003e\u003e\u003e from lpminimk3.graphics import Text\n\u003e\u003e\u003e lp.grid.render(Text('A'))\n```\nPrint `A` in console:\n```python\n\u003e\u003e\u003e Text('A').print()\n  XX    \n XXXX   \nXX  XX  \nXX  XX  \nXXXXXX  \nXX  XX  \nXX  XX  \n```\nScroll `Hello, world!` on Launchpad's surface indefinitely:\n```python\n\u003e\u003e\u003e lp.grid.render(Text(' Hello, world!').scroll(count=-1))\n```\n\n\n## Extended graphics support\n`lpminimk3` is also capable of rendering graphics from _**bitmaps**_ and _**movies**_. These are JSON files that describe the rendering data in a high-level format. Data in these files are grouped as _**frames**_. A **frame** is a sequence of bits and their color configurations. A **bitmap** file consists of a single frame while a **movie** file consists of a sequence of frames. \n\n### Syncing with LP Sketch\nIf you want to create and edit bitmaps and/or movies with a graphical tool, try [LP Sketch](https://www.github.com/obeezzy/lpsketch). LP Sketch is a free online Launchpad editor specifically designed for use with `lpminimk3`. You can also sync your Launchpad with LP Sketch by starting `lpminimk3`'s sync server:\n```bash\n$ python -m lpminimk3.graphics.sync\n```\nOnce the server is running, visit the [LP Sketch](https://www.github.com/obeezzy/lpsketch) website to start creating bitmaps and movies live.\n\n### Rendering bitmaps and movies\nRender `smiley.bitmap.json` on Launchpad's surface:\n```python\n\"\"\"Render \"Smiley\" bitmap.\n\"\"\"\n\nfrom lpminimk3 import Mode, find_launchpads\nfrom lpminimk3.graphics import Bitmap\nfrom lpminimk3.graphics.art import Bitmaps\n\nlp = find_launchpads()[0]  # Get the first available launchpad\nlp.open()  # Open device for reading and writing on MIDI interface (by default)\n\nlp.mode = Mode.PROG  # Switch to the programmer mode\n\nlp.grid.render(Bitmap(Bitmaps.SMILEY))  # Display bitmap\n# OR\n# lp.grid.render(Bitmap(\"/path/to/smiley.bitmap.json\"))\n```\nRender `ping_pong.movie.json` on Launchpad's surface:\n```python\n\"\"\"Render \"Ping/Pong\" movie.\n\"\"\"\n\nfrom lpminimk3 import Mode, find_launchpads\nfrom lpminimk3.graphics import Movie\nfrom lpminimk3.graphics.art import Movies\n\nlp = find_launchpads()[0]  # Get the first available launchpad\nlp.open()  # Open device for reading and writing on MIDI interface (by default)\n\nlp.mode = Mode.PROG  # Switch to the programmer mode\n\nlp.grid.render(Movie(Movies.PING_PONG).play())  # Play movie once\n# OR\n# lp.grid.render(Movie(\"/path/to/ping_pong.movie.json\").play())\n```\nFor convenience, you can use the render script, `render.py`:\n```bash\n$ python -m lpminimk3.graphics.render -f /path/to/bitmap/or/movie.json\n```\n`render.py` can be used to render text, bitmaps and movies on the Launchpad and on the console. For more options, run:\n```bash\n$ python -m lpminimk3.graphics.render -h\n```\n\n\n## License\n[MIT](https://choosealicense.com/licenses/mit/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fobeezzy%2Flpminimk3","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fobeezzy%2Flpminimk3","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fobeezzy%2Flpminimk3/lists"}