Пришел новый русский в магазин, чтобы сдать новогоднюю гирлянду.
– Не работает? – спрашивает его продавец.
– Почему? Очень даже работает, – отвечает тот.
– А в чем тогда дело?
Покупатель вздохнул и ответил:
– Не радует.
Привет, друзья!
Очень надеемся, что гирлянда, изготовление которой мы опишем в статье, порадует вас и своим видом, и тем фактом, что вы можете ее сделать сами. Совсем не претендуя на то, что эта гирлянда станет серьезным конкурентом недорогих китайских вариантов, мы все же считаем, что такой небольшой DIY в преддверии новогоднего праздника может стать прекрасным развлечением для всей семьи, ведь тут и сборка “железочек”, и программирование, и составление сценария логики работы гирлянды, и, в конечном счете, созидание красоты, сделанной собственной руками!
Под катом:
- Собираем прототип гирлянды
- Пишем код для нескольких режимов работы
- Подключаем к платформе Rightech IoT Cloud
- Придумываем и реализовываем сценарий работы гирлянды
- Создаем праздничное настроение
Идея сделать гирлянду возникла не случайно. Украшая офис, мы нашли в мешке маленькую елочку, которой совершенно не холодно в офисе зимой, но совсем одиноко без огоньков, тем более что основной елке в офисе достались и игрушки, и гирлянды, а маленькой — ничего. Но мы посчитали, что это не беда, а даже ее преимущество. Значит сделаем для нее не только уникальную гирлянду своими руками, но и сами выберем ей цвета светодиодов (возьмем цвета нашей компании: белый и голубой) и даже организуем ей беспроводное управление режимами по Zigbee-кнопке. А для гарантии безопасности еще и добавим автоматическое выключение по расписанию.
Модели устройств, файлы со сценариями автоматов, код для NodeMCU — в конце статьи (
Собираем прототип
Создание прототипов — это процесс сборки простой рабочей модели продукта или системы. Для начала построим его на макетной плате, а затем, как водится, красиво спаяем.
Итак, для маленькой гирлянды нам понадобится:
- 12 белых и 6 голубых светодиодов, управление которыми производится независимо (назначение: гореть и радовать)
- 2 резистора на 220 Ом, подбираемые исходя из расчета сопротивления и мощности по закону Ома (назначение: защита светодиодов от перегрева и выхода из строя)
- 2 биполярных NPN транзистора (назначение: управляем транзистором маленьким током от управляющего пина, а пропускаем на диоды — большой ток с выхода 3.3 В, так мы защищаем управляющий пин платы)
- 2 резистора на 1 кОм на базу транзистора (назначение аналогичное, ограничиваем ток)
- плата NodeMCU (назначение: подключение к IoT-платформе и управление транзисторами)
- батарейки или блок питания (назначение: источник питания для платы)
Все светодиоды подключаем параллельно друг другу. Это значит, что все длинные выводы всех светодиодов должны быть соединены вместе и подключаться к общему плюсу; все короткие выводы — также соединены и подключаются к общему минусу.
Если изобразить на схеме, то это выглядит так:
При таком соединении повреждение и перегорание одного светодиода не приведёт к поломке всей гирлянды, всё будет работать, только без «выбывшего» диода. Управляющие пины платы подключаем к базе транзисторов через резисторы.
Обратите внимание, на фото добавлено по одному резистору на каждую группу светодиодов. Однако гораздо лучше и надежнее будет использовать отдельный ограничительный резистор для каждого светодиода. Светодиоды могут чуть отличаться своей вольт-амперной характеристикой друг от друга. Первый открывшийся пропустит через себя ток, предназначенный для всех. Из-за чего он может выйти из строя, и «эстафета» перейдёт к следующему.
Пишем код
Ниже представлен код для управления режимами гирлянды. Его функции:
- установить Wi-Fi соединение и подключиться к платформе;
- подписаться на команды — сообщения с топиками “led_on”, “led_off”, “led_attenuation”, “led_flashing” — и выполнять соответствующие действия по управлению светодиодами.
Команды “led_on” и “led_off” включают и выключают гирлянду, а команды “led_attenuation” и “led_flashing” задают режимы плавного горения и быстрого мигания с периодом, указанным в payload команды.
Обратите внимание, в коде мы используем библиотеку Sheduler, которая нужна для того, чтобы одновременно запускать несколько потоков с задачами. Если этого не сделать, то при запуске бесконечного цикла горения светодиодов параллельно получать команды с платформы уже не получится.
#include "Arduino.h"
#include "Scheduler.h" /* https://github.com/nrwiersma/ESP8266Scheduler */
#include "EspMQTTClient.h" /* https://github.com/plapointe6/EspMQTTClient */
/* https://github.com/knolleary/pubsubclient */
// Даем разумные имена для пинов, управляемых светодиодами
#define BLUE_LED_PIN 12
#define WHITE_LED_PIN 13
EspMQTTClient client(
"<wifi-ssid>",
"<wifi-password>"
"dev.rightech.io",
"<ric-mqtt-client-id>"
);
// Задача для обработки поступающих команд
class ClientTask : public Task {
public:
void loop() {
client.loop();
}
} client_task;
// Задача для включения светодиодов
class LedOnTask : public Task {
protected:
void loop()
{
digitalWrite(WHITE_LED_PIN, HIGH);
digitalWrite(BLUE_LED_PIN, HIGH);
shouldRunValue = false; // останавливаем этот цикл сразу после включения
}
bool shouldRun()
{
return shouldRunValue;
}
public:
bool shouldRunValue = false;
} led_on_task;
// Задача для выключения светодиодов
class LedOffTask : public Task {
protected:
void loop()
{
digitalWrite(WHITE_LED_PIN, LOW);
digitalWrite(BLUE_LED_PIN, LOW);
shouldRunValue = false; // останавливаем этот цикл сразу после выключения
}
bool shouldRun()
{
return shouldRunValue;
}
public:
bool shouldRunValue = false;
} led_off_task;
// Задача для плавного горения светодиодов в противофазе
class LedAttenuationTask : public Task {
protected:
void loop()
{
// Вычисляем задержку на один проход цикла в зависимости от полученного в payload значения
float delayValue = period.toInt() * 1000 /*в миллисекунды*/ / 2 /*на два цикла*/ / 1024 /*на каждую итерацию в цикле*/;
for (int i = 0; i <= 1023; i++) {
analogWrite(WHITE_LED_PIN, i); // горит ярче
analogWrite(BLUE_LED_PIN, 1023 - i); // тускнеет
delay(delayValue);
}
for (int i = 1023; i >= 0; i--) {
analogWrite(WHITE_LED_PIN, i); // тускнеет
analogWrite(BLUE_LED_PIN, 1023 - i); // горит ярче
delay(delayValue);
}
}
bool shouldRun()
{
updateDelayTimer();
if (isDelayed()) return false;
if (!run_group_active) return false;
return shouldRunValue;
}
public:
bool shouldRunValue = false;
String period;
} led_attenuation_task;
// Задача для быстрого мигания светодиодов в противофазе
class LedFlashingTask : public Task {
protected:
void loop()
{
float delayValue = period.toInt() * 1000 /*в миллисекунды*/;
digitalWrite(WHITE_LED_PIN, HIGH);
digitalWrite(BLUE_LED_PIN, LOW);
delay(delayValue);
digitalWrite(WHITE_LED_PIN, LOW);
digitalWrite(BLUE_LED_PIN, HIGH);
delay(delayValue);
}
bool shouldRun()
{
updateDelayTimer();
if (isDelayed()) return false;
if (!run_group_active) return false;
return shouldRunValue;
}
public:
bool shouldRunValue = false;
String period;
} led_flashing_task;
void setup() {
// Настраиваем пины в режим выхода, т.е. в режим источника напряжения
pinMode(WHITE_LED_PIN, OUTPUT);
pinMode(BLUE_LED_PIN, OUTPUT);
// Библиотека «Scheduler» позволяет при необходимости запустить несколько потоков
Scheduler.start(&led_on_task);
Scheduler.start(&led_off_task);
Scheduler.start(&led_attenuation_task);
Scheduler.start(&led_flashing_task);
Scheduler.start(&client_task);
Scheduler.begin();
}
void onConnectionEstablished() {
// Подписываемся на команды и запускаем нужный поток путем изменения переменной shouldRunValue
client.subscribe("led_on", [] (const String & payload) {
client.publish("base/state/light", "on");
led_off_task.shouldRunValue = false;
led_attenuation_task.shouldRunValue = false;
led_flashing_task.shouldRunValue = false;
led_on_task.shouldRunValue = true;
});
client.subscribe("led_off", [] (const String & payload) {
client.publish("base/state/light", "off");
led_on_task.shouldRunValue = false;
led_attenuation_task.shouldRunValue = false;
led_flashing_task.shouldRunValue = false;
led_off_task.shouldRunValue = true;
});
client.subscribe("led_attenuation", [] (const String & payload) {
client.publish("base/state/light", "attenuation " + payload + " sec");
led_on_task.shouldRunValue = false;
led_off_task.shouldRunValue = false;
led_flashing_task.shouldRunValue = false;
led_attenuation_task.period = payload;
led_attenuation_task.shouldRunValue = true;
});
client.subscribe("led_flashing", [] (const String & payload) {
client.publish("base/state/light", "flashing " + payload + " sec");
led_on_task.shouldRunValue = false;
led_off_task.shouldRunValue = false;
led_attenuation_task.shouldRunValue = false;
led_flashing_task.period = payload;
led_flashing_task.shouldRunValue = true;
});
}
void loop() {
}
Подключаем к платформе Rightech IoT Cloud
Подключение гирлянды:
1) Создаем модель
2) Создаем объект с этой моделью
Подключение кнопки:
1) Создаем модель
2) Создаем объект с этой моделью
Подробнее о том, как подключать ZigBee устройства, можно посмотреть в видеоуроке и почитать в статье.
Разрабатываем сценарий работы
От сценария автоматизации мы хотим следующей логики:
1) один клик (single) — режим постоянного свечения и выключения;
2) два клика (double) — режим плавного свечения;
3) три клика (triple) — режим мигания;
4) после 20:00 — автоматическое выключение гирлянды (здесь также можно использовать не просто расписание, а данные еще из одного объекта — СКУДа, который собирает информацию о том, есть ли люди в офисе. Если вам интересен материал по такой теме, дайте обратную связь в комментариях ?).
Готовый автомат
Давайте вкратце разберем, что тут происходит и зачем:
- Первым делом при старте автомата запускаем планировщик, который выключит гирлянду по расписанию, обезопасив нас от забывчивости. Запустили и забыли, он будет срабатывать каждый день автоматически.
- В следующем состоянии не делаем ничего, просто ждем нажатия кнопки. В это состояние мы возвращаемся каждый раз после отработки определенного режима гирлянды. Из него есть переход по событию получения данных и срабатыванию планировщика.
- Если получили какой-то пакет от кнопки, то переходим в состояние “Получен пакет”, из которого по таймеру и типу клика переходим в соответствующие режимы. Вы можете спросить, зачем тут таймер. А причина в том, что кнопка работает довольно “интересненько”. При нажатии три раза, она сначала присылает пакет с double, а сразу за ним — triple. Такой нюанс мы и обходим таймером, иначе срабатывало бы по неактуальному клику.
- Также есть промежуточное состояние для одинарного клика. Как мы помним, вкл/выкл у нас работают по одному и тому же событию. Поэтому, если гирлянда не выключена (находится в любом из режимов активной работы), то мы ее выключаем, а если выключена, то включаем.
Запускаем автомат на наших объектах, проверяем — фуууух, работает! Время паять!
Собираем готовое устройство
Самый простой вариант пайки гирлянды — это один за другим спаивать светодиоды, предварительно надевая термоусадку. Примерно вот так:
Но можно пойти немного другим путем — сделать не просто гирлянду, которой мы обвяжем елку, облачив ее дополнительно во все эти провода. Вместо этого на каждую веточку посадим по светодиоду (в цветочках это смотрится особенно чудесно, см. итоговое фото), стянем провода по стеблю вниз и спаяем, спрятав всю электронику в горшочке. На выходе остается только разъем под кабель питания. Ювелирно, аккуратно и очень симпатично получается. Судите сами.
термоусадку нагреваем паяльным феном
помещаем провод перед пайкой в канифоль (в таком случае не образуется тонкой оксидной пленки на поверхности провода, в результате спайка проходит легче и получается надежнее) …
… и лудим (наносим небольшой слой припоя)
проводок готов воссоединяться со светодиодом
соединяем (паяем поверхности, на которых уже есть припой)
фиксируем на веточке, сгибая ножки (необходимо предварительно оставить не менее 10 мм) светодиода
на данном этапе проводим последнее тестирование
готово!
В заключение хотим сказать, что неважно, какие гирлянды именно в вашем доме — цветные или однотонные, ультрасовременные или, напротив, винтажные, светодиодные или галогеновые. Главное, чтобы они создавали праздничное настроение перед Новым годом, несли тепло и радость в сердца ваших близких.
С наступающим праздником!
Материалы к статье
REPISOT
КДПВ вызывает ужас! Только недавно пару гирлянд чинил. Самые дешевые, а значит — самые распространенные гирлянды собраны так, что получить разряд тока, играя с включенной гирляндой — дело времени.
Провода (в том числе провода сетевой вилки) никак не крепятся к корпусу блока управления. Они держатся только на пайке. А жилы там — три волосинки. Любое натяжение — и провод под током у вас в руках.
P.S. Светодиоды нельзя паять параллельно без выравнивающих резисторов. Неравномерность падения напряжения есть всегда. Она приведет к неравномерному распределению токов и поочередному выгоранию светодиодов.
P.P.S Странное ощущение: NodeMCU, Rightech IoT Cloud… И при этом нас учат лудить провода? Серьезно?
Rightech_IoT Автор
Да, это факт, вы не первый, кто говорит, что испугался за ребенка)) Но больно уж симпатичная картинка. К тому же, свою цель (ПВ как привлечение внимания) она все-таки выполнила
P.S Спасибо, хорошее замечание по светодиодам. Изучу и добавлю в статью материал
P.P.S Не сказать, что я там учу лудить… Но сейчас придет заядлый программист и скажет «Фиии, они дают такие подробные комментарии в коде! Не учи ученого!», потом придет мой коллега Диман и скажет «Хммм, зачем так подробно расписывать, что делает автомат? Очевидно же, ну что ты в самом деле...» К чему я это. К тому, что из статьи каждый возьмет то, что нужно, заполнит необходимые пробелы и, возможно, задаст уточняющие вопросы. Потому что статья действительно охватывает разный род деятельности, а хотелось сделать от и до целостно и понятно.
Albom
Зашёл сюда только для того, чтобы посмотреть комментарий насчёт КДПВ.