Create a gist now

Instantly share code, notes, and snippets.

Using a pebble watch to control NeoPixel (WS2812 ) LEDs via an ESP8266 controller

This is the general instructions for how to get a pebble watch to talk to an ESP8266 and turn NeoPixels different colours.

Pebble Controlled NeoPixels

Video: https://www.youtube.com/watch?v=BeIQ47WBVXs

Prereqs

  • Pebble watch
  • ESP8266 ESP-01
  • NeoPixel strip (or ring or matrix or single pixel)

Software needed

  • ESPTool
  • ESPlora
  • Pebble SDK and command line tools

Acknowledgements

Thanks to Andy Gelme for his excellent workshop on the ESP8266 and getting me up to speed on the Lua side.

Directions

  • Using ESPTool, flash the ESP8266 with NodeMCU development branch (bins are in this gist) so it has WS8212 support.
  • Using ESPlora, change config.lua to have SSID / PASSWORD of your network in them - upload all lua files to the ESP8266
  • Wire up the WS2812 strip so data line is connected to GPIO 2 (change this in server.lua if you use a different pin).
  • Reset the ESP8266 and note it's IP address in ESPlora when it comes up. You should now be able to hit the web server using
curl --data "red=255&green=0&blue=255" http://<IP address>
  • Using CloudPebble, copy app.js contents into the app.js file (make a watch app project and use Pebble JS)
  • Change the HOST IP address to that of your ESP8266
  • Compile and then download the PBW file
  • Use the developer configuration (as documented by Pebble SDK setup) to run:
pebble install watch_led.pbw

That's it - you should be able to hit it as expected.

/**
Pebble - ESP8266 - NeoPixel controller
Author: Andrew Fisher
Licence: MIT
**/
var UI = require('ui');
var ajax = require('ajax');
var HOST = '<<IP>>';
// Connect to the ESP8266 and post the data
function colour_request(r, g, b) {
//console.log("Making request");
//console.log("r:" + r + " g: " + g);
var req = {
url: HOST,
method: 'post',
data: {red:r, green:g, blue:b}
};
//console.log(JSON.stringify(req));
ajax(req,
function(data, status, request) {
console.log(data);
},
function(data, status, request) {
console.log('The ajax request failed: ' + data + status + JSON.stringify(request));
}
);
}
// Make a list of the colours to select
var colours = [
{ title: "OFF", r: 0, g: 0, b: 0, },
{ title: "RED", r: 255, g: 0, b: 0, },
{ title: "GREEN", r: 0, g: 255, b: 0, },
{ title: "BLUE", r: 0, g: 0, b: 255, },
{ title: "YELLOW", r: 255, g: 255, b: 0, },
{ title: "MAGENTA", r: 255, g: 0, b: 255, },
{ title: "CYAN", r: 0, g: 255, b: 255, },
{ title: "WHITE", r: 255, g: 255, b: 255, },
];
// Create the Menu
var menu = new UI.Menu({
sections: [{
title: 'Choose LED colour',
items: colours
}]
});
// Send command when menu item is selected
menu.on('select', function(e) {
colour_request(e.item.r, e.item.g, e.item.b);
});
menu.show();
local module = {}
function module.start()
print("application start")
print("IP address: " .. wifi.sta.getip())
dofile("server.lua")
end
return module
local module = {}
module.SSID = {}
module.SSID["SSID"] = "PASSWORD"
return module
app = require("application")
config = require("config")
require("setup").start()
local PORT = 80
local LED_PIN = 4 -- GPIO 2
local BRIGHTNESS = 0.2 -- NeoPixels are BRIGHT.
local NO_PIXELS = 17
if server then
print("Closing existing server")
server:close()
end
print("Starting server on: " .. wifi.sta.getip() .. ":" .. PORT)
server = net.createServer(net.TCP)
server:listen(PORT, function(conn)
conn:on("receive", function(client, payload)
-- print(payload)
local head = ""
local body = ""
local colours = {}
colours["red"] = 0
colours["green"] = 0
colours["blue"] = 0
if (string.sub(payload, 1, 4) == "POST") then
head = head .. "HTTP/1.1 200 OK\r\n"
head = head .. "Content-Type: application/json\r\n"
-- now we find the RGB components. Going to do this simply
-- by ripping them out with a find statement
for c, v in pairs(colours) do
local match = c .. "=(%d*)"
_, _, colours[c] = string.find(payload, match)
-- put in a catch here incase it goes nil
end
set_led_colour(colours, NO_PIXELS)
-- send the JSON back to confirm
body = body .. "{\"r\":" .. colours["red"] .. ", "
body = body .. "\"g\":" .. colours["green"] .. ", "
body = body .. "\"b\":" .. colours["blue"] .. "}"
else
head = head .. "HTTP/1.1 500 Server Error\r\n"
body = body .. "Please ensure you use a POST method"
end
body = body .. "\r\n" -- just tidy up the end of the file
head = head .. "Content-Length: " .. string.len(body) .. "\r\n\r\n"
--print(head .. body)
client:send(head .. body)
end)
conn:on("sent", function(client)
client:close()
end)
end)
function create_colour(red, green, blue)
-- takes the colours and makes single value for writing to the LEDs
local colour = string.char(green * BRIGHTNESS, red * BRIGHTNESS, blue * BRIGHTNESS)
return colour
end
function set_led_colour(colours, pixels)
-- takes the colour values and writes that to the number of pixels
-- assmues a table colours{"red":val, "green":val, "blue":val}
ws2812.write(LED_PIN, create_colour(colours["red"], colours["green"], colours["blue"]):rep(pixels))
end
local module = {}
local function wifi_wait_ip()
if wifi.sta.getip() then
tmr.stop(1)
-- print("wifi ready: " .. wifi.sta.getip())
app.start()
end
end
local function wifi_start(aps)
for key,value in pairs(aps) do
-- print("wifi AP: " .. key .. ": " .. value)
if config.SSID and config.SSID[key] then
wifi.sta.config(key, config.SSID[key])
wifi.sta.connect()
config.SSID = nil -- more secure and save memory
tmr.alarm(1, 2500, 1, wifi_wait_ip)
end
end
end
function module.start()
wifi.setmode(wifi.STATION);
wifi.sta.getap(wifi_start)
end
return module
@goliatone

@ajfisher: This is really cool, thank you! Could you also provide a simple schematic with the wiring?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment