Documentation
¶
Overview ¶
Package blinkstick drives BlinkStick USB LED devices. The Nano and Square are supported on macOS and Linux.
Open a stick, set its LEDs and close it:
d, err := blinkstick.Open()
if err != nil {
log.Fatal(err)
}
defer d.Close()
err = d.SetAll(blinkstick.RGB{R: 255})
Use List to find every attached stick and OpenSerial to open a particular one. A stick can also be given a name with Device.SetName and opened by it with OpenName. Several sticks can be open at once, and a Device is safe for concurrent use.
Requirements ¶
The package uses cgo and a bundled copy of hidapi. On macOS, install the Xcode command line tools; macOS lets only one process open a stick at a time. On Linux, install libudev's development headers, and see the udev rule under "Linux" in the README for opening a stick without root.
EEPROM ¶
Device.SetInfoBlock, Device.SetName and Device.SetMode write to EEPROM on the device, which wears with use. Setting LEDs does not.
This package is unofficial and not affiliated with Agile Innovative.
Example ¶
package main
import (
"log"
"github.com/bawdo/go-blinkstick"
)
func main() {
d, err := blinkstick.Open()
if err != nil {
log.Fatal(err)
}
defer d.Close()
if err := d.SetAll(blinkstick.RGB{R: 255}); err != nil {
log.Fatal(err)
}
}
Output:
Index ¶
- Variables
- func ColourNames() []string
- type Device
- func (d *Device) Blink(ctx context.Context, c RGB, period time.Duration, repeats int) error
- func (d *Device) Close() error
- func (d *Device) Frame() ([]RGB, error)
- func (d *Device) Info() Info
- func (d *Device) InfoBlock(n int) ([]byte, error)
- func (d *Device) LED(i int) (RGB, error)
- func (d *Device) Mode() (Mode, error)
- func (d *Device) Morph(ctx context.Context, to RGB, duration time.Duration) error
- func (d *Device) Name() (string, error)
- func (d *Device) Off() error
- func (d *Device) Pulse(ctx context.Context, c RGB, duration time.Duration, repeats int) error
- func (d *Device) SetAll(c RGB) error
- func (d *Device) SetBrightnessLimit(limit uint8)
- func (d *Device) SetFrame(leds []RGB) error
- func (d *Device) SetInfoBlock(n int, data []byte) error
- func (d *Device) SetInverse(on bool)
- func (d *Device) SetLED(i int, c RGB) error
- func (d *Device) SetMode(m Mode) error
- func (d *Device) SetName(name string) error
- type Info
- type Mode
- type Model
- type NamedInfo
- type RGB
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( Off = RGB{} White = RGB{R: 255, G: 255, B: 255} )
Common values.
var ( ErrNotFound = errors.New("blinkstick: device not found") ErrUnsupported = errors.New("blinkstick: unsupported model") ErrOutOfRange = errors.New("blinkstick: out of range") ErrClosed = errors.New("blinkstick: device closed") ErrUnsupportedMode = errors.New("blinkstick: mode not supported by this model") ErrInvalidName = errors.New("blinkstick: invalid name") ErrDuplicateName = errors.New("blinkstick: name used by more than one stick") ErrDisconnected = error(&disconnectedError{}) )
Errors returned by this package. Check them with errors.Is. ErrNotFound is also returned when a stick is attached but cannot be opened, for example because another process holds it (macOS opens devices exclusively; Linux does not, so this does not happen there). ErrDisconnected means an open stick was unplugged and could not be reopened; errors.Is also matches it to ErrNotFound.
var ( Nano = Model{Name: "Nano", LEDs: 2, /* contains filtered or unexported fields */} Square = Model{Name: "Square", LEDs: 8, /* contains filtered or unexported fields */} )
Supported models.
Functions ¶
func ColourNames ¶ added in v0.3.0
func ColourNames() []string
ColourNames returns every CSS colour name that ParseRGB accepts, lower case and sorted. Each call returns a new slice, so callers may modify it. ParseRGB gives the value of a name.
Example ¶
package main
import (
"fmt"
"github.com/bawdo/go-blinkstick"
)
func main() {
// Offer names for shell completion, each described by its value.
for _, name := range blinkstick.ColourNames()[:3] {
c, _ := blinkstick.ParseRGB(name)
fmt.Printf("%s\t%s\n", name, c.Hex())
}
}
Output: aliceblue #f0f8ff antiquewhite #faebd7 aqua #00ffff
Types ¶
type Device ¶
type Device struct {
// contains filtered or unexported fields
}
Device is an open BlinkStick. Its methods are safe for concurrent use, but two effects running at once on one Device interleave their frames.
If the stick is unplugged, the next call that fails reopens it by serial, repaints the last frame written (a replugged stick comes back dark) and carries on. If the stick is still missing it returns ErrDisconnected, and the call after that tries again.
func Open ¶
Open opens the first BlinkStick found. If the first stick found is a model this package does not support, Open returns ErrUnsupported even when a supported stick is also attached; use List and OpenSerial to choose one.
func OpenName ¶ added in v0.2.0
OpenName opens the BlinkStick whose stored name is exactly name. It opens each attached stick in turn to read its name, and skips sticks it cannot open or read, including any this process already has open; if none matches, the error says why each was skipped. It returns ErrDuplicateName if more than one stick has the name.
Example ¶
package main
import (
"log"
"github.com/bawdo/go-blinkstick"
)
func main() {
d, err := blinkstick.OpenName("desk")
if err != nil {
log.Fatal(err)
}
defer d.Close()
d.SetAll(blinkstick.RGB{G: 255})
}
Output:
func OpenSerial ¶
OpenSerial opens the BlinkStick with the given serial, as reported by List.
Example ¶
package main
import (
"fmt"
"log"
"github.com/bawdo/go-blinkstick"
)
func main() {
d, err := blinkstick.OpenSerial("BS072777-3.0")
if err != nil {
log.Fatal(err)
}
defer d.Close()
fmt.Println(d.Info().Model.Name)
}
Output:
func (*Device) Blink ¶
Blink turns every LED to c for period/2, then off for period/2, repeats times. It ends with the LEDs off. If ctx is cancelled the LEDs are left as they are.
func (*Device) Frame ¶
Frame reads every LED back from the device. Values are those stored on the device, so they reflect any brightness limit in force when they were written. With SetInverse on they are flipped back.
func (*Device) InfoBlock ¶
InfoBlock reads user data block n (1 or 2) from the device's EEPROM, with trailing NUL bytes removed. Because trailing NUL bytes are trimmed, data that ends in NUL bytes does not round-trip. The bytes are whatever was last written, by this package or another tool, so treat them as untrusted.
func (*Device) Mode ¶ added in v0.5.0
Mode reads the device's current mode. It returns ModeRGB and an error if the read fails.
func (*Device) Morph ¶
Morph fades every LED from its current value to `to` over duration, in 20 ms steps. A duration under one step jumps straight to `to`. It ends with every LED at `to`. If ctx is cancelled the LEDs are left as they are.
func (*Device) Name ¶ added in v0.2.0
Name returns the name stored on the stick, or "" if none is set. Another tool may have stored bytes that are not valid UTF-8 or that include control characters, so sanitise the name before printing it to a terminal.
func (*Device) Pulse ¶
Pulse fades every LED from off up to c over duration/2 and back down over duration/2, repeats times. It ends with the LEDs off. If ctx is cancelled the LEDs are left as they are.
Example ¶
package main
import (
"context"
"log"
"time"
"github.com/bawdo/go-blinkstick"
)
func main() {
d, err := blinkstick.Open()
if err != nil {
log.Fatal(err)
}
defer d.Close()
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := d.Pulse(ctx, blinkstick.RGB{G: 255}, time.Second, 3); err != nil {
log.Fatal(err)
}
}
Output:
func (*Device) SetBrightnessLimit ¶
SetBrightnessLimit caps every channel written from now on, scaling each as v * limit / 255. 255, the default, means no limit. Frame and LED return the scaled values stored on the device.
Example ¶
package main
import (
"log"
"github.com/bawdo/go-blinkstick"
)
func main() {
d, err := blinkstick.Open()
if err != nil {
log.Fatal(err)
}
defer d.Close()
d.SetBrightnessLimit(64) // about a quarter of full brightness
d.SetAll(blinkstick.White)
}
Output:
func (*Device) SetInfoBlock ¶
SetInfoBlock writes up to 32 bytes to user data block n (1 or 2), padded with zeros. It writes EEPROM, which wears with use, so do not call it in a loop.
func (*Device) SetInverse ¶ added in v0.2.0
SetInverse flips every channel written from now on to 255 - v, after any brightness limit, for LEDs wired so that 255 means off. Frame and LED flip values back, so they return what was written. It does not repaint the LEDs, so call it before setting them.
func (*Device) SetLED ¶
SetLED sets LED i to c and leaves the others as they are. It sends one report (report 5), which takes about a millisecond. The first call on a Device that has written nothing also reads the frame back once, so a reconnect can repaint the other LEDs.
Example ¶
package main
import (
"log"
"github.com/bawdo/go-blinkstick"
)
func main() {
d, err := blinkstick.Open()
if err != nil {
log.Fatal(err)
}
defer d.Close()
// Top LED red, bottom LED blue on a Nano.
d.SetLED(0, blinkstick.RGB{R: 255})
d.SetLED(1, blinkstick.RGB{B: 255})
}
Output:
func (*Device) SetMode ¶ added in v0.5.0
SetMode switches the device to mode m. It returns ErrUnsupportedMode if the model does not allow m, which covers modes 0 and 1 on every model here.
SetMode writes EEPROM, which wears with use, so call it once and not in a loop. It skips the write when the stick is already in m. The change takes effect at once, with no replug. The stick stops answering for a short time after the write, so SetMode waits until it reads back m, typically 12 to 15 ms. If the stick has not answered after 250 ms it returns ErrDisconnected.
Mode 3 makes report 1 from other software colour every LED. This package's LED methods work the same in modes 2 and 3.
func (*Device) SetName ¶ added in v0.2.0
SetName stores name on the stick, replacing any name already there. name is UTF-8 of at most 32 bytes with no NUL characters; "" clears the name. Names are not checked for uniqueness, but OpenName fails if two attached sticks share one. It writes EEPROM, which wears with use, so do not call it in a loop.
type Info ¶
type Info struct {
Serial string // for example "BS072777-3.0"
Version string // firmware version from the serial, for example "3.0"
Manufacturer string
Product string
Model Model
}
Info identifies an attached BlinkStick.
func List ¶
List returns every attached BlinkStick, including models this package does not support yet (their Model.Name is "unknown").
Example ¶
package main
import (
"fmt"
"log"
"github.com/bawdo/go-blinkstick"
)
func main() {
infos, err := blinkstick.List()
if err != nil {
log.Fatal(err)
}
for _, info := range infos {
fmt.Println(info.Serial, info.Model.Name, info.Model.LEDs)
}
}
Output:
type Mode ¶ added in v0.5.0
type Mode uint8
Mode is the device's LED output mode, stored in EEPROM and read with report 4.
const ( // ModeRGB is normal mode for the BlinkStick Pro RGB outputs. ModeRGB Mode = 0 // ModeRGBInverse is inverse mode for the BlinkStick Pro RGB outputs. ModeRGBInverse Mode = 1 // ModeWS2812 drives the WS2812 LEDs, which is what every LED method here needs. ModeWS2812 Mode = 2 // ModeWS2812Mirror is ModeWS2812 where report 1 colours every LED, as sent by other BlinkStick software. ModeWS2812Mirror Mode = 3 )
type Model ¶
type Model struct {
Name string // "Nano", "Square" or "unknown"
LEDs int // addressable LEDs on channel 0
// contains filtered or unexported fields
}
Model describes a BlinkStick product. Models differ only in data, including which modes they allow, so supporting another product means adding a row to the models table.
func (Model) SupportsMode ¶ added in v0.5.0
SupportsMode reports whether SetMode accepts x on this model.
type NamedInfo ¶ added in v0.2.0
type NamedInfo struct {
Info
Name string // "" if none is set, or if Busy
Busy bool // the stick could not be opened or its name read, for example because another process holds it
}
NamedInfo is an attached stick and the name stored on it.
func ListNamed ¶ added in v0.2.0
ListNamed returns every attached BlinkStick with its name. It opens each stick in turn to read the name and closes it again, so it is slower than List. Sticks it cannot open or read, including any this process already has open, are listed with Busy set.
Example ¶
package main
import (
"fmt"
"log"
"github.com/bawdo/go-blinkstick"
)
func main() {
named, err := blinkstick.ListNamed()
if err != nil {
log.Fatal(err)
}
for _, n := range named {
fmt.Printf("%s %s %q busy=%v\n", n.Serial, n.Model.Name, n.Name, n.Busy)
}
}
Output:
type RGB ¶
type RGB struct{ R, G, B uint8 }
RGB is a colour with 8 bits per channel.
func ParseRGB ¶
ParseRGB parses a colour in any of these forms:
- hex "#rgb" or "#rrggbb", with or without the "#"
- "r,g,b" with decimal channels from 0 to 255
- a CSS colour name such as "cornflowerblue", in any case
Example ¶
package main
import (
"fmt"
"log"
"github.com/bawdo/go-blinkstick"
)
func main() {
c, err := blinkstick.ParseRGB("#ff8800")
if err != nil {
log.Fatal(err)
}
fmt.Println(c)
}
Output: {255 136 0}
func RandomRGB ¶ added in v0.2.0
func RandomRGB() RGB
RandomRGB returns a colour with each channel picked at random from 0 to 255. Many results are muted or greyish; use RandomVivid for bright ones. It is not suitable for anything security related.
func RandomVivid ¶ added in v0.2.0
func RandomVivid() RGB
RandomVivid returns a fully saturated colour at full brightness with a random hue: one channel is always 255 and another is always 0.
Example ¶
package main
import (
"log"
"github.com/bawdo/go-blinkstick"
)
func main() {
d, err := blinkstick.Open()
if err != nil {
log.Fatal(err)
}
defer d.Close()
d.SetAll(blinkstick.RandomVivid())
}
Output:
func (RGB) Hex ¶ added in v0.3.0
Hex returns c as lower case "#rrggbb".
Example ¶
package main
import (
"fmt"
"log"
"github.com/bawdo/go-blinkstick"
)
func main() {
c, err := blinkstick.ParseRGB("cornflowerblue")
if err != nil {
log.Fatal(err)
}
fmt.Println(c.Hex())
fmt.Println(blinkstick.RGB{R: 1}.Hex())
}
Output: #6495ed #010000