Сейчас куда не глянь везде всё умное. Умные розетки, кофеварки, телевизоры и конечно же лампочки. Одной из первых таких ламп я увидел Philips HUE, и загорелся идеей сделать свою управляемую RGB лампочку. У такой лампочки масса очевидных преимуществ: задание цвета под настроение, автоматическое включение/выключение, светобудильник, плюс неочевидные, как например светомузыка. Сказано сделано – начинаем копать.
Первое, что нужно решить – это каким будет источник света. Сейчас в моде светодиоды – они компактны и потребляют мало электричества, к тому же у меня завалялось 15 NeoPixel-ей от Adafruit на основе ws2812b.
Это 3 светодиода в одном плюс управляющая электроника. Особенность в том, что управляются они по одному проводу (вместе с напругой и землёй – три). Грубо говоря по проводу с данными вы передаёте сигнал, представляющий массив значений цветов. А дальше первый NeoPixel “откусывает” от этого массива первый элемент, выставляет его себе и передаёт остаток дальше и так далее по цепочке.
Второе – это какую беспроводную технологию использовать. WiFi мне кажется более универсальной и лучше масштабируемой в отличии от Bluetooth – это позволяет добавлять огромное количество таких ламп и заодно даёт возможность управления ими с помощью любого устройства, находящегося в этой же сети (да и за её пределами). Да и радиус действия у них гораздо больше. К тому же у меня валялось 3 модуля на основе esp8266.
Третье – это на чем реализовать управляющую логику. В наличии был Arduino Uno к нему и решил подключить NeoPixel-и, следуя инструкции на сайте Adafruit.
Однако Arduino Uno слишком большой, чтобы он мог поместиться в корпус стандартной лампочки. В интернете мне попалось видео, как уменьшить свои Arduino Uno проекты используя ATTiny45/85. К тому же на instructables есть guide, как заставить ATTiny работать с NeoPixel-ями. Не долго думая я купил ATTiny45 и перенёс пример с полноценной Arduino Uno на эту мелочь.
С другой стороны esp8266 – это очень мощная штука при малых размерах. Помимо WiFi этот SoC имеет ещё и GPIO. Я взял ESP-01 у которого есть два GPIO. К тому же Arduino IDE поддерживает это семейство начиная с версии 1.6.4 и у Adafruit даже есть гайд по настройке. Единственная проблема – это то, как заливать туда свой софт. Я купил USB-Serail converter который имеет выходной сигнал на 3.3 вольта, так как 5 вольт убьет esp8266 и сделал две кнопки на макетной плате, так как для заливки нового софта требуется перевести один из пинов в Low и затем RESET-нуть esp8266, более подробно о том как заливать свои программы можно прочитать тут:
Пусть вас не смущает наличие Arduino Uno на картинке справа – его я использовал исключительно, чтобы получить 3.3 вольта и запитать esp8266, а также чтобы получить 5 вольт для NeoPixel-ей.
Стандартный пример от Adafruit заработал и я бросился писать простенькую программку, которая бы коннектилась к моей домашней WiFi сети, поднимала сокет и ждала число, которое бы определяло цвет светодиодов. В интернете я наткнулся на хороший пример того, как общаться с esp8266 и на его основе с небольшими изменениями, используя Adafruit API для управление светодиодами, я добился чего хотел.
Для проверки накропал простенький скрипт на Perl-е, который бы и отправлял цвет для лампы:
use strict; use IO::Socket::INET; my $sock = new IO::Socket::INET(PeerAddr => '192.168.1.35', PeerPort => '6969', Proto => 'tcp') || die "Can't bind $@\n"; $sock->send(shift."\n");
И сама прошивка
#include <Adafruit_NeoPixel.h> #include <ESP8266WiFi.h> #define NEOPIXEL_DATA_PIN 0 #define PIXELS_NUM 7 Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXELS_NUM, NEOPIXEL_DATA_PIN, NEO_RGB + NEO_KHZ800); const char* ssid = "mynetworkssid"; const char* password = "mynetpass"; WiFiServer server(6969); void setup() { Serial.begin(115200); strip.begin(); strip.show(); WiFi.begin(ssid, password); server.begin(); while(WiFi.status() != WL_CONNECTED) { delay(500); } } void loop() { WiFiClient client = server.available(); if (client) { Serial.println("client connected."); while(client.connected()) { if (client.available()) { String command; char c = client.read(); while(c != '\n') { command += c; c = client.read(); } if (command != 0) { char** tmp; char colorcommand[10]; command.toCharArray(colorcommand, sizeof(colorcommand)); uint32_t iColor = strtoul(colorcommand, tmp, 10); SetStripColors(iColor); } } } Serial.println("Client disconnected."); client.stop(); } } void SetStripColors(uint32_t color) { for (uint16_t i=0; i< PIXELS_NUM; i++) { strip.setPixelColor(i, color); } strip.show(); delay(100); }
Теперь дело за спецэфектами!