Пришел новый русский в магазин, чтобы сдать новогоднюю гирлянду.
– Не работает? – спрашивает его продавец.
– Почему? Очень даже работает, – отвечает тот.
– А в чем тогда дело?
Покупатель вздохнул и ответил:
– Не радует.

Привет, друзья!

Очень надеемся, что гирлянда, изготовление которой мы опишем в статье, порадует вас и своим видом, и тем фактом, что вы можете ее сделать сами. Совсем не претендуя на то, что эта гирлянда станет серьезным конкурентом недорогих китайских вариантов, мы все же считаем, что такой небольшой DIY в преддверии новогоднего праздника может стать прекрасным развлечением для всей семьи, ведь тут и сборка “железочек”, и программирование, и составление сценария логики работы гирлянды, и, в конечном счете, созидание красоты, сделанной собственной руками!

Под катом:

  1. Собираем прототип гирлянды
  2. Пишем код для нескольких режимов работы
  3. Подключаем к платформе Rightech IoT Cloud
  4. Придумываем и реализовываем сценарий работы гирлянды
  5. Создаем праздничное настроение

image

Идея сделать гирлянду возникла не случайно. Украшая офис, мы нашли в мешке маленькую елочку, которой совершенно не холодно в офисе зимой, но совсем одиноко без огоньков, тем более что основной елке в офисе достались и игрушки, и гирлянды, а маленькой — ничего. Но мы посчитали, что это не беда, а даже ее преимущество. Значит сделаем для нее не только уникальную гирлянду своими руками, но и сами выберем ей цвета светодиодов (возьмем цвета нашей компании: белый и голубой) и даже организуем ей беспроводное управление режимами по Zigbee-кнопке. А для гарантии безопасности еще и добавим автоматическое выключение по расписанию.

Модели устройств, файлы со сценариями автоматов, код для NodeMCU — в конце статьи (не пытайтесь повторить это дома попробуйте повторить это дома!).

image

Собираем прототип


Создание прототипов — это процесс сборки простой рабочей модели продукта или системы. Для начала построим его на макетной плате, а затем, как водится, красиво спаяем.

Итак, для маленькой гирлянды нам понадобится:

  • 12 белых и 6 голубых светодиодов, управление которыми производится независимо (назначение: гореть и радовать)
  • 2 резистора на 220 Ом, подбираемые исходя из расчета сопротивления и мощности по закону Ома (назначение: защита светодиодов от перегрева и выхода из строя)
  • 2 биполярных NPN транзистора (назначение: управляем транзистором маленьким током от управляющего пина, а пропускаем на диоды — большой ток с выхода 3.3 В, так мы защищаем управляющий пин платы)
  • 2 резистора на 1 кОм на базу транзистора (назначение аналогичное, ограничиваем ток)
  • плата NodeMCU (назначение: подключение к IoT-платформе и управление транзисторами)
  • батарейки или блок питания (назначение: источник питания для платы)

Все светодиоды подключаем параллельно друг другу. Это значит, что все длинные выводы всех светодиодов должны быть соединены вместе и подключаться к общему плюсу; все короткие выводы — также соединены и подключаются к общему минусу.

Если изобразить на схеме, то это выглядит так:

image

При таком соединении повреждение и перегорание одного светодиода не приведёт к поломке всей гирлянды, всё будет работать, только без «выбывшего» диода. Управляющие пины платы подключаем к базе транзисторов через резисторы.




Обратите внимание, на фото добавлено по одному резистору на каждую группу светодиодов. Однако гораздо лучше и надежнее будет использовать отдельный ограничительный резистор для каждого светодиода. Светодиоды могут чуть отличаться своей вольт-амперной характеристикой друг от друга. Первый открывшийся пропустит через себя ток, предназначенный для всех. Из-за чего он может выйти из строя, и «эстафета» перейдёт к следующему.

image

Пишем код


Ниже представлен код для управления режимами гирлянды. Его функции:

  1. установить Wi-Fi соединение и подключиться к платформе;
  2. подписаться на команды — сообщения с топиками “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 — автоматическое выключение гирлянды (здесь также можно использовать не просто расписание, а данные еще из одного объекта — СКУДа, который собирает информацию о том, есть ли люди в офисе. Если вам интересен материал по такой теме, дайте обратную связь в комментариях ?).

Готовый автомат




Давайте вкратце разберем, что тут происходит и зачем:

  1. Первым делом при старте автомата запускаем планировщик, который выключит гирлянду по расписанию, обезопасив нас от забывчивости. Запустили и забыли, он будет срабатывать каждый день автоматически.
  2. В следующем состоянии не делаем ничего, просто ждем нажатия кнопки. В это состояние мы возвращаемся каждый раз после отработки определенного режима гирлянды. Из него есть переход по событию получения данных и срабатыванию планировщика.
  3. Если получили какой-то пакет от кнопки, то переходим в состояние “Получен пакет”, из которого по таймеру и типу клика переходим в соответствующие режимы. Вы можете спросить, зачем тут таймер. А причина в том, что кнопка работает довольно “интересненько”. При нажатии три раза, она сначала присылает пакет с double, а сразу за ним — triple. Такой нюанс мы и обходим таймером, иначе срабатывало бы по неактуальному клику.
  4. Также есть промежуточное состояние для одинарного клика. Как мы помним, вкл/выкл у нас работают по одному и тому же событию. Поэтому, если гирлянда не выключена (находится в любом из режимов активной работы), то мы ее выключаем, а если выключена, то включаем.

Запускаем автомат на наших объектах, проверяем — фуууух, работает! Время паять!




Собираем готовое устройство


Самый простой вариант пайки гирлянды — это один за другим спаивать светодиоды, предварительно надевая термоусадку. Примерно вот так:

image

Но можно пойти немного другим путем — сделать не просто гирлянду, которой мы обвяжем елку, облачив ее дополнительно во все эти провода. Вместо этого на каждую веточку посадим по светодиоду (в цветочках это смотрится особенно чудесно, см. итоговое фото), стянем провода по стеблю вниз и спаяем, спрятав всю электронику в горшочке. На выходе остается только разъем под кабель питания. Ювелирно, аккуратно и очень симпатично получается. Судите сами.

image

термоусадку нагреваем паяльным феном

image

помещаем провод перед пайкой в канифоль (в таком случае не образуется тонкой оксидной пленки на поверхности провода, в результате спайка проходит легче и получается надежнее) …

image

… и лудим (наносим небольшой слой припоя)

image

проводок готов воссоединяться со светодиодом

image

соединяем (паяем поверхности, на которых уже есть припой)

image

фиксируем на веточке, сгибая ножки (необходимо предварительно оставить не менее 10 мм) светодиода

image

на данном этапе проводим последнее тестирование

image

готово!




В заключение хотим сказать, что неважно, какие гирлянды именно в вашем доме — цветные или однотонные, ультрасовременные или, напротив, винтажные, светодиодные или галогеновые. Главное, чтобы они создавали праздничное настроение перед Новым годом, несли тепло и радость в сердца ваших близких.

С наступающим праздником!

Материалы к статье


image