Lámpara Zerynth: Control IoT de Luz Ambiental con NeoPixel y App Móvil
Componentes y materiales
| Zerynth Shield (multisensor: tacto, IR, micrófono, luz, temp) | 1 |
| Placa compatible: Arduino Due, STM32 Nucleo F401RE, Particle Photon, UDOO Dual, Flip&Click | 1 |
| Módulo Wi-Fi (si la placa no lo integra): shield CC3000 (Adafruit/TI) | 1 |
| Tira/anillo NeoPixel (Adafruit) | 1 |
| Base de lámpara (vidrio o impresión 3D) | 1 |
Software y apps
- Zerynth Studio (IDE Python multiplataforma, cloud sync) – descarga
- Zerynth App (iOS/Android – control remoto) – descarga
Descripción
Lámpara inteligente controlada desde móvil vía Zerynth App. Interfaz: selector de color (color picker) + menú de animaciones predefinidas (Little Snakes, Spinner, Rainbow, Pulse) + control de velocidad. Programada en Python con Zerynth Studio.
Montaje
- Apila (piggyback) shield Wi-Fi + Zerynth Shield sobre la placa base. Si usas Particle Photon, conéctalo directo al Zerynth Shield.
- Conecta NeoPixel al puerto dedicado del Zerynth Shield.
- Introduce todo en la base de lámpara.
Programación con Zerynth Studio
- Conecta placa → "Virtualiza" en Zerynth Studio.
- Nuevo proyecto → crea 4 archivos:
main.py,animation.py,template.html,project.md. - Copia el código de cada archivo (ver abajo).
- Uplink (flashea) → la lámpara conecta automáticamente a la Wi-Fi configurada.
- Abre Zerynth App → detecta "Zerynth Lamp" → controla color, animación, velocidad.
Código
main.py
################################################################################
# Zerynth Lamp - Created by Zerynth Team 2015 CC
# Authors: G. Baldi, D. Mazzei
################################################################################
import streams
from bcm43362 import bcm43362 as wifi_driver
from wireless import wifi
import animation
from toishield import toishield
from zerynthapp import zerynthapp
streams.serial()
# Conexión Wi-Fi
try:
wifi_driver.auto_init()
print("Establishing Link...")
wifi.link("SSID", wifi.WIFI_WPA2, "password")
print("Ok!")
except Exception as e:
print(e)
# Guarda template.html en flash
new_resource("template.html")
#### ZerynthApp Setup
# Callbacks JS → Python
def change_color(r, g, b):
animation.setup_color(r, g, b)
def change_animation(n):
animation.setup_anim(n)
def change_speed(n):
animation.setup_anim_speed(n)
# Configura app
vp = zerynthapp.ZerynthApp("Zerynth Lamp", "Try me!", "resource://template.html")
vp.on("change_color", change_color)
vp.on("change_animation", change_animation)
vp.on("change_speed", change_speed)
vp.run() # inicia hilo app
# Inicia animación NeoPixel (pin D6, 24 LEDs)
animation.start(D6, 24)
template.html (interfaz móvil)
<html>
<head>
<zerynth/> <zerynth-jquery/> <zerynth-jquery-mobile/> <zerynth-jqwidgets/>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div data-role="page">
<div data-role="header"><h1>Zerynth Lamp</h1></div>
<div role="main" class="ui-content" style="text-align:center">
<div style="margin: 3px; float: left;" id="dropDownButton">
<div style="padding: 3px;"><div id="colorPicker"></div></div>
</div>
<button class="ui-btn ui-btn-inline ui-shadow"
onclick="ZerynthApp.call('change_color',cur_color.r,cur_color.g,cur_color.b)">Colorize!</button>
<form>
<div data-role="fieldcontain">
<label for="animselect">Animation:</label>
<select name="animselect" id="animselect">
<option value="0">Little Snakes</option>
<option value="1">Spinner</option>
<option value="2">Rainbow</option>
<option value="3">Pulse</option>
</select>
</div>
</form>
<form>
<label for="speedslider">Animation Speed:</label>
<input type="range" name="speedslider" id="speedslider" data-highlight="true" min="0" max="100" value="50">
</form>
</div>
<div data-role="footer">Powered by Zerynth (www.zerynth.com)</div>
</div>
<script>
var cur_color = {r: 0x54, g: 0x9a, b:0x97};
function getTextElementByColor(color) { /* ... */ }
$(document).ready(function () {
$("#colorPicker").on('colorchange', function (event) {
$("#dropDownButton").jqxDropDownButton('setContent', getTextElementByColor(event.args.color));
});
$("#colorPicker").jqxColorPicker({ color: "5a9a97", colorMode: 'saturation', width: 220, height: 220 });
$("#dropDownButton").jqxDropDownButton({ width: 150, height: 22 });
$("#dropDownButton").jqxDropDownButton('setContent', getTextElementByColor(new $.jqx.color({ hex: "549a97" })));
ZerynthApp.jquerymobile_scalecontent();
$("#animselect").change(function() {
ZerynthApp.call('change_animation', parseInt($('#animselect').val()));
});
$("#speedslider").on('slidestop', function() {
ZerynthApp.call('change_speed', parseInt($('#speedslider').val()));
});
});
</script>
</body>
</html>
animation.py (lógica NeoPixel multicapa)
################################################################################
# Zerynth Lamp - Animation functions
################################################################################
from neopixel import ledstrips as neo
import threading
lock = threading.Lock()
color = [0x54, 0x9a, 0x97]
anim = 0
anim_speed = 50
leds = None
layer0 = layer1 = layer2 = None
npins = 0
stopped = False
stopcolor = [0xff, 0xff, 0xff]
animation_coefficients = [0, 0.2588, 0.5, 0.7071, 0.8660, 0.9659, 1,
0.9659, 0.8660, 0.7071, 0.5, 0.2588]
rainbow = [(0xff,0,0), (0xff,0x7f,0), (0xff,0xff,0), (0,0xff,0),
(0,0,0xff), (0x4b,0,0x82), (0x8f,0,0xff)]
def setup_anim(n):
global layer0, layer1, layer2, anim
lock.acquire()
leds.clear(); layer2.clear(); layer0.clear(); layer1.clear()
n = n % 4
if n == 0:
layer0[0]=layer0[1]=layer0[2]=(100,0,0)
layer1[0]=layer1[1]=layer1[2]=(0,100,0)
elif n == 1:
for x in range(npins//2):
layer0[x]=(100//(2*x+1),0,0)
layer1[npins-x-1]=(0,100//(2*x+1),0)
layer2.clear()
elif n == 2:
layer1.clear()
pstep = 0
for x in range(npins):
step = x*len(rainbow)/npins
rx = (rainbow[int(step)][0]+rainbow[int(pstep)][0])//4
gx = (rainbow[int(step)][1]+rainbow[int(pstep)][1])//4
bx = (rainbow[int(step)][2]+rainbow[int(pstep)][2])//4
layer0[x]=(rx,gx,bx)
pstep = step
elif n == 3:
layer0.clear(); layer1.clear()
anim = n
lock.release()
def setup_anim_speed(n):
global anim_speed
anim_speed = n
def setup_color(r,g,b):
global color
color[0]=r; color[1]=g; color[2]=b
def animate_background(delay):
global color
step = 0
while True:
if (anim==3 or anim==0) and not stopped:
lock.acquire()
layer2.setall(int(color[0]*animation_coefficients[step]/2),
int(color[1]*animation_coefficients[step]/2),
int(color[2]*animation_coefficients[step]/2))
lock.release()
step = (step + 1) % len(animation_coefficients)
else:
lock.acquire()
layer2.clear(); layer2.setall(stopcolor[0], stopcolor[1], stopcolor[2])
lock.release()
sleep(delay + 500 - 5*anim_speed)
def animate_foreground(delay):
while True:
if not stopped:
lock.acquire()
if anim == 0: layer0.lshift(); layer1.rshift()
elif anim == 1: layer0.rshift(); layer1.rshift()
elif anim == 2: layer0.rshift(); layer1.rshift()
elif anim == 3: layer0.lshift(); layer1.lshift()
lock.release()
else:
lock.acquire(); layer0.clear(); layer1.clear(); lock.release()
sleep(delay + 100 - anim_speed)
def start(pin, numpins):
global leds, layer0, layer1, layer2, npins
npins = numpins
leds = neo.LedStrip(pin, numpins)
layer0 = neo.LedStrip(pin, numpins)
layer1 = neo.LedStrip(pin, numpins)
layer2 = neo.LedStrip(pin, numpins)
setup_anim(0); setup_anim_speed(50)
thread(animate_background, 500)
thread(animate_foreground, 50)
while True:
leds.clear()
lock.acquire()
leds.merge(layer0); leds.merge(layer1)
leds.merge(layer2, neo.first_color) # solo donde sea transparente
lock.release()
leds.on()
sleep(50)
def stop(r,g,b):
global stopped, stopcolor
stopcolor = [r,g,b]; stopped = True
def resume():
global stopped
stopped = False
setup_anim(anim)
Esquemático
Ver imagen en sección "Schematics": conexiones NeoPixel → Zerynth Shield, Wi-Fi shield, placa base.
Extensiones sugeridas
- Usar sensores del Zerynth Shield: tacto (encender/apagar), micrófono (reactivo a sonido), luz ambiente (auto-brillo), temperatura (cambio de color).
- Añadir más animaciones en
animation.py. - Integrar con MQTT/HTTP para control remoto vía web.
- Comunidad Zerynth: foro.
Proceso de manufactura
- Faroles de Gas: Evolución, Diseño y Fabricación Moderna
- Puntero Láser: Diseño, Fabricación y Resumen de Seguridad
- Linterna: de su invención a la innovación moderna
- Lámparas Halógenas: Tecnología, Historia y Futuro – Perspectiva Experta
- El Caleidoscopio: De la Ciencia de Brewster al Diseño Moderno
- Semáforos: Ingeniería, Historia e Innovaciones Futuras
- Del Fuego al Filamento: Evolución y Producción de la Bombilla Moderna
- Construya un Sistema de Monitorización de Temperatura y Luz Multi‑Sensor con Raspberry Pi y DS18B20
- Semáforo Inteligente: Iluminación Vial Adaptativa con IoT
- Sensor de Luz Digital – Enciende un LED con Luz Ambiental usando Windows 10 IoT Core
- Propagación de Señales Eléctricas a Velocidad de la Luz: Experimento Mental de 186.000 Millas