{"id":20205366,"url":"https://github.com/cgxeiji/ring","last_synced_at":"2026-05-11T15:41:38.385Z","repository":{"id":57538211,"uuid":"286646195","full_name":"cgxeiji/ring","owner":"cgxeiji","description":"Go library for controlling ws2811 LED ring on a Raspberry Pi","archived":false,"fork":false,"pushed_at":"2020-08-13T06:45:25.000Z","size":1346,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-13T20:46:29.111Z","etag":null,"topics":["go","golang","led","raspberry-pi","ring","ws2811","ws281x"],"latest_commit_sha":null,"homepage":"","language":"Go","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/cgxeiji.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}},"created_at":"2020-08-11T04:34:29.000Z","updated_at":"2023-10-29T00:07:32.000Z","dependencies_parsed_at":"2022-09-07T17:35:27.820Z","dependency_job_id":null,"html_url":"https://github.com/cgxeiji/ring","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cgxeiji%2Fring","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cgxeiji%2Fring/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cgxeiji%2Fring/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cgxeiji%2Fring/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cgxeiji","download_url":"https://codeload.github.com/cgxeiji/ring/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241644545,"owners_count":19996177,"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":["go","golang","led","raspberry-pi","ring","ws2811","ws281x"],"created_at":"2024-11-14T05:17:07.689Z","updated_at":"2026-05-11T15:41:33.365Z","avatar_url":"https://github.com/cgxeiji.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ring\n\n[![Version](https://img.shields.io/github/v/tag/cgxeiji/ring?sort=semver)](https://github.com/cgxeiji/ring/releases)\n[![PkgGoDev](https://pkg.go.dev/badge/github.com/cgxeiji/ring)](https://pkg.go.dev/github.com/cgxeiji/ring)\n[![License](https://img.shields.io/github/license/cgxeiji/ring)](https://github.com/cgxeiji/ring/blob/master/LICENSE)\n![Go version](https://img.shields.io/github/go-mod/go-version/cgxeiji/ring)\n\nRing is a wrapper of\n[rpi-ws281x-go](https://github.com/rpi-ws281x/rpi-ws281x-go) specialized in\ncontrolling ring-shaped LEDs.\n\nThe library adds the ability to use `layers` to do complex animations. Each\n`layer` supports color transparency and blending is handled automatically.\n\n## Compilation\n\nCompiling directly on a Raspberry Pi might take too long. The recommended way\nto compile this library is to cross-compile using a Docker container.\n\nFollow the [guide from\nrpi-ws281x-go](https://github.com/rpi-ws281x/rpi-ws281x-go#cross-compiling) to\nlearn how.\n\n### Running\n\nBecause `rpi-ws281x` needs to access `/dev/mem` to create correct pwm timings,\nyou will need to run the compiled binary with root permissions.\n\n\n## Example\n\n\u003e *Boss: \"Can you make a pulsating white background with colorful rotating lights and a blinking cyan light?\"*\n\u003e\n\u003e *You:*\n\u003e\n\u003e ![ring.gif](./img/ring.gif)\n\nTo create the animation above, try the following code:\n\n```go\npackage main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"image/color\"\n\t\"log\"\n\t\"math\"\n\t\"os\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/cgxeiji/ring\"\n)\n\nfunc main() {\n\t// Initialize the ring.\n\tr, err := ring.New(\u0026ring.Options{\n\t\tLedCount:      12,  // adjust this to the number of LEDs you have\n\t\tMaxBrightness: 180, // value from 0 to 255\n\t})\n\tr.Offset(-math.Pi / 3) // you can set a rotation offset for the ring\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\t// Make sure to properly close the ring.\n\tdefer r.Close()\n\n\t// Create a new layer.  This will be a static white background.\n\tbg, err := ring.NewLayer(\u0026ring.LayerOptions{\n\t\tResolution:  1,                 // set to 1 pixel because it is a uniform color background\n\t\tContentMode: ring.ContentScale, // this scales the pixel to the whole ring\n\t})\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\t// Set all pixels of the layer to white.\n\tbg.SetAll(color.White)\n\t// Add the layer to the ring.\n\tr.AddLayer(bg)\n\n\t// Create a mask layer.  This will fade the background.\n\tbgMask, err := ring.NewLayer(\u0026ring.LayerOptions{\n\t\tResolution: 1, // set to 1 pixel because it is a uniform mask\n\t})\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tr.AddLayer(bgMask)\n\n\t// Render the ring.\n\tif err := r.Render(); err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\t// Wait for 1 second to see the beauty of the freshly rendered layer.\n\ttime.Sleep(1 * time.Second)\n\n\t// Create another layer.  This will set 3 pixels to red, green and blue,\n\t// and a hidden purple pixel with transparency of 200, that rotate\n\t// counter-clockwise.\n\ttriRotate, err := ring.NewLayer(\u0026ring.LayerOptions{\n\t\tResolution: 48,\n\t})\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\t// We can immediately add the layer to the ring.  By default, new layers\n\t// are initialized with transparent pixels.  The new layer is added on top\n\t// of the previous layers.\n\tr.AddLayer(triRotate)\n\n\t// Set the colors.\n\ttriRotate.SetPixel(0, color.NRGBA{128, 0, 0, 200})    // dark red\n\ttriRotate.SetPixel(3, color.NRGBA{0, 128, 0, 200})    // dark green\n\ttriRotate.SetPixel(6, color.NRGBA{0, 0, 128, 200})    // dark blue\n\ttriRotate.SetPixel(24, color.NRGBA{128, 0, 255, 200}) // purple\n\t// Render the ring.\n\tif err := r.Render(); err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\t// Wait for 1 second to see the beauty of both layers.\n\ttime.Sleep(1 * time.Second)\n\n\t// Create another layer. This will set a pixel that will blink every 500ms.\n\tblink, err := ring.NewLayer(\u0026ring.LayerOptions{\n\t\tResolution:  3,                // we are going to set the 3rd pixel (index: 2) to blink\n\t\tContentMode: ring.ContentCrop, // this crops the layer to avoid repetition\n\t})\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\t// Add the layer to the ring. This will be on top of the previous two\n\t// layers.\n\tr.AddLayer(blink)\n\n\t// Set the color. We can use any variable that implements the color.Color\n\t// interface.\n\tblink.SetPixel(2, color.CMYK{255, 0, 0, 0})\n\t// Render the ring.\n\tif err := r.Render(); err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\t// Wait for 1 second and enjoy the view.\n\ttime.Sleep(1 * time.Second)\n\n\t/* ANIMATION SETUP */\n\tdone := make(chan struct{})   // this will cancel all animations\n\trender := make(chan struct{}) // this will request a concurrent-safe render\n\tvar ws sync.WaitGroup         // this makes sure we close all goroutines\n\n\t/* render goroutine */\n\tws.Add(1)\n\tgo func() {\n\t\tdefer ws.Done()\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase \u003c-done:\n\t\t\t\treturn\n\t\t\tcase \u003c-render:\n\t\t\t\tif err := r.Render(); err != nil {\n\t\t\t\t\tlog.Fatal(err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n\n\t/* fading goroutine */\n\tws.Add(1)\n\tgo func() {\n\t\tdefer ws.Done()\n\t\tc := color.NRGBA{0, 0, 0, 0}\n\t\tstep := uint8(5)\n\t\tfor {\n\t\t\tfor a := uint8(0); a \u003c 255; a += step {\n\t\t\t\tc.A = a\n\t\t\t\tbgMask.SetAll(c)\n\t\t\t\tselect {\n\t\t\t\tcase \u003c-done:\n\t\t\t\t\treturn\n\t\t\t\tcase render \u003c- struct{}{}:\n\t\t\t\t}\n\t\t\t\ttime.Sleep(20 * time.Millisecond)\n\t\t\t}\n\t\t\tfor a := uint8(255); a \u003e 0; a -= step {\n\t\t\t\tc.A = a\n\t\t\t\tbgMask.SetAll(c)\n\t\t\t\tselect {\n\t\t\t\tcase \u003c-done:\n\t\t\t\t\treturn\n\t\t\t\tcase render \u003c- struct{}{}:\n\t\t\t\t}\n\t\t\t\ttime.Sleep(20 * time.Millisecond)\n\t\t\t}\n\t\t}\n\t}()\n\n\t/* rotation goroutine */\n\tws.Add(1)\n\tgo func() {\n\t\tdefer ws.Done()\n\t\tfor {\n\t\t\tfor a := 0.0; a \u003c math.Pi*2; a += 0.01 {\n\t\t\t\ttriRotate.Rotate(a)\n\t\t\t\tselect {\n\t\t\t\tcase \u003c-done:\n\t\t\t\t\treturn\n\t\t\t\tcase render \u003c- struct{}{}:\n\t\t\t\t}\n\t\t\t\ttime.Sleep(20 * time.Millisecond)\n\t\t\t}\n\t\t}\n\t}()\n\n\t/* blinking goroutine */\n\tws.Add(1)\n\tgo func() {\n\t\tdefer ws.Done()\n\t\tc := color.CMYK{255, 0, 0, 0}\n\t\ttimer := time.NewTicker(500 * time.Millisecond)\n\t\ton := true\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase \u003c-done:\n\t\t\t\treturn\n\t\t\tcase \u003c-timer.C:\n\t\t\t\tif on {\n\t\t\t\t\tblink.SetPixel(2, color.Transparent)\n\t\t\t\t\ton = false\n\t\t\t\t} else {\n\t\t\t\t\tblink.SetPixel(2, c)\n\t\t\t\t\ton = true\n\t\t\t\t}\n\t\t\t\tselect {\n\t\t\t\tcase \u003c-done:\n\t\t\t\t\treturn\n\t\t\t\tcase render \u003c- struct{}{}:\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n\n\tfmt.Println(\"Press [ENTER] to exit\")\n\tstdin := bufio.NewReader(os.Stdin)\n\tstdin.ReadString('\\n')\n\n\t// Stop all animations\n\tclose(done)\n\t// Wait for goroutines to exit\n\tws.Wait()\n\n\t// Remember that we called a defer `r.Close()` at the beginning of the\n\t// code. This will turn off the LEDs and clean up the resources used by the\n\t// ring before exiting. Otherwise, the ring will stay on with the latest\n\t// render.\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcgxeiji%2Fring","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcgxeiji%2Fring","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcgxeiji%2Fring/lists"}