Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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

This comment has been minimized.

Copy link

goliatone commented Nov 28, 2015

@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
You can’t perform that action at this time.