package main // BLE LED color control example. // A mobile app writes 3 bytes (R, G, B) to the color characteristic // and both WS2812 LEDs light up with that color. // // Service UUID: BADA5501-B5A3-F393-E0A9-E50E24DCCA9E // Color char: BADA5502-B5A3-F393-E0A9-E50E24DCCA9E // // Compatible apps: nRF Connect, LightBlue (iOS/Android). // To set color: write 3 hex bytes to the color characteristic, e.g. FF0080 = red:255 green:0 blue:128. import ( "image/color" "machine" "strconv" "github.com/tinygo-org/bluetooth" "tinygo.org/x/drivers/st7789" "tinygo.org/x/drivers/ws2812" "tinygo.org/x/tinyfont" "tinygo.org/x/tinyfont/freesans" ) var ( adapter = bluetooth.DefaultAdapter ledServiceUUID = bluetooth.NewUUID([16]byte{ 0xBA, 0xDA, 0x55, 0x01, 0xB5, 0xA3, 0xF3, 0x93, 0xE0, 0xA9, 0xE5, 0x0E, 0x24, 0xDC, 0xCA, 0x9E, }) colorCharUUID = bluetooth.NewUUID([16]byte{ 0xBA, 0xDA, 0x55, 0x02, 0xB5, 0xA3, 0xF3, 0x93, 0xE0, 0xA9, 0xE5, 0x0E, 0x24, 0xDC, 0xCA, 0x9E, }) ) var ( display st7789.Device leds ws2812.Device connected bool ledColor color.RGBA ) var ( black = color.RGBA{0, 0, 0, 255} cyan = color.RGBA{0, 200, 255, 255} white = color.RGBA{255, 255, 255, 255} gray = color.RGBA{150, 150, 150, 255} ) func main() { initDisplay() initLEDs() drawStatus("Advertising...") drawColor(color.RGBA{0, 0, 0, 255}) must("enable BLE", adapter.Enable()) must("add service", adapter.AddService(&bluetooth.Service{ UUID: ledServiceUUID, Characteristics: []bluetooth.CharacteristicConfig{ { UUID: colorCharUUID, Flags: bluetooth.CharacteristicWritePermission | bluetooth.CharacteristicWriteWithoutResponsePermission, WriteEvent: func(client bluetooth.Connection, offset int, value []byte) { if len(value) < 3 { return } // value[0]=R, value[1]=G, value[2]=B ledColor = color.RGBA{value[0], value[1], value[2], 255} setLEDs(ledColor) drawColor(ledColor) if !connected { connected = true drawStatus("Connected ") } }, }, }, })) adv := adapter.DefaultAdvertisement() must("configure adv", adv.Configure(bluetooth.AdvertisementOptions{ LocalName: "NiceBadge", ServiceUUIDs: []bluetooth.UUID{ledServiceUUID}, })) must("start adv", adv.Start()) // wait forever; all logic is driven by the BLE WriteEvent callback select {} } func initDisplay() { machine.SPI0.Configure(machine.SPIConfig{ SCK: machine.P1_01, SDO: machine.P1_02, Frequency: 8000000, Mode: 0, }) display = st7789.New(machine.SPI0, machine.P1_15, machine.P1_13, machine.P0_10, machine.P0_09) display.Configure(st7789.Config{ Rotation: st7789.ROTATION_90, Width: 135, Height: 240, RowOffset: 40, ColumnOffset: 53, }) display.FillScreen(black) } func initLEDs() { neo := machine.P1_11 neo.Configure(machine.PinConfig{Mode: machine.PinOutput}) leds = ws2812.New(neo) } func setLEDs(c color.RGBA) { leds.WriteColors([]color.RGBA{c, c}) } func drawStatus(status string) { display.FillRectangle(0, 0, 240, 32, black) tinyfont.WriteLine(&display, &freesans.Regular9pt7b, 10, 22, "BLE: "+status, cyan) } func drawColor(c color.RGBA) { // show a filled rectangle with the current color and its RGB values below display.FillRectangle(0, 38, 240, 60, color.RGBA{c.R, c.G, c.B, 255}) display.FillRectangle(0, 100, 240, 35, black) rgb := "R:" + strconv.Itoa(int(c.R)) + " G:" + strconv.Itoa(int(c.G)) + " B:" + strconv.Itoa(int(c.B)) tinyfont.WriteLine(&display, &freesans.Regular9pt7b, 10, 122, rgb, white) } func must(action string, err error) { if err != nil { panic("failed to " + action + ": " + err.Error()) } }