Новогодняя SMS-ёлка

  • Платформы: Iskra Neo
  • Языки программирования: Arduino (C++)
  • Тэги: Merry Christmas, WS2811, GPRS, гирлянда, адресная светодиодная лента RGB, ёлка, IP-камера

Что это?

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

Сделаем гирлянду, цвет свечения которой может изменить каждый с помощью SMS. В сообщении достаточно отправить число от 0 до 360, которое определяет оттенок (Hue) по цветовому кругу, по модели HSV. Приняв сообщение, устройство переведёт цвет в нужное для ленты RGB-значение и с помощью незамысловатой анимации изменит цвет на новый.

Что нам понадобится?

  1. SIM-карта
  2. Блок питания (12 В, 12,5 А)
  3. Влагозащищенный корпус
  4. Евровилка сетевая с выключателем
  5. Герметичный разъём (розетка + вилка) 4pin
  6. Многожильный монтажный провод с сечением не менее 3×2,5 мм² (1 метр)
  7. Многожильный монтажный провод с сечением не менее 1 мм² (2 шт. разного цвета)

Как собрать?

  1. Вставьте сим-карту в GPRS Shield и установите его на платформу Iskra Neo.
  2. Установите в герметичный корпус блок питания (12 В, 12,5 А) и «бутерброд» из платы Iskra Neo и GPRS Shield’a, используя мегапластину от #структора.
  3. Сделайте два отверстия в корпусе и установите через них евровилку и герметичный разъём (розетка).
  4. Соедините клеммы входного напряжения блока питания L и N с евровилкой, используя монтажные провода из кабеля 3×2,5. А клеммы выходного напряжения −V и +V — с герметичным разъёмом для питания светодиодной ленты.
  5. Соедините цифровой пин 6 платформы Iskra Neo с герметичным разъёмом. По нему будут передаваться данные для контроллеров светодиодной ленты.
  6. Подключите выходное напряжение −V и +V от блока питания к плате Iskra Neo через внешний разъём, используя монтажные провода и штекер питания 2,1 мм.
  7. Используя многожильный монтажный провод с сечением 3×2,5 мм² и герметичный разъём (вилка), сделайте шнур для подключения RGB-ленты к блоку управления, по которому будет подаваться питание и данные для адресной светодиодной ленты:
    1. питание +V — коричневый;
    2. земля −V — синий;
    3. сигнальный — зелёный.
  8. Далее соедините полученные проводники с адресной светодиодной лентой через клеммы.
  9. В заключении подключите сетевой шнур в евровилку, а герметичный разъём со шнуром (вилка) — в герметичный разъём в корпусе (розетка)

    Внимание!

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

    Перегрев в свою очередь значительно сокращает срок службы светодиодов.

    Правильный вариант – выходной сигнальный провод первой ленты оставить соединённым с входным сигналом второй ленты, а выводы питания и земли каждой ленты подключить непосредственно к выводам блока питания.

Алгоритм

  • Сразу после подачи питания проверяем есть ли связь с GPRS устройством.
    • Если связи нет, повторяем запрос снова и ждём подтверждения связи.
  • Ожидаем приём новых сообщений.
    • Если их нет, повторяем запрос снова и снова.
  • Читаем сообщение и проверяем содержимое его текста:
    • Если в тексте число 0–360, меняем по сегментам цвет гирлянды по шкале HSV и отчитываемся об изменении обратным смс.
    • Если текст не распознан, отправляем обратное смс об ошибке распознавания команды.

Исходный код

christmastree.ino
// библиотека для эмуляции Serial-порта
// она нужна для работы библиотеки GPRS_Shield_Arduino
#include <SoftwareSerial.h>
// библиотека для работы с GPRS устройством
#include <GPRS_Shield_Arduino.h>
 
// библиотека для работы с адресной RGB-лентой
#include <Adafruit_NeoPixel.h>
 
// номер пина, к которому подключен сигнальный провод ленты
#define PIXEL_PIN    6
// количество сегментов в ленте
#define PIXEL_COUNT 200
 
// текст сообщения, об удачном изменении цвета ленты
#define MESSAGE_OK  "Well done! "\
"You are hacked our Christmas Tree. Happy New Year 2016!"
// текст сообщения, об ошибки ввода смс
#define MESSAGE_ERROR  "Whoops! Something wrong."\
"Your attempt is failed."
// текст сообщения, о включении секретного режима
#define MESSAGE_BONUS  "You are hacked our Christmas Tree."\
"Secret mod has been activated. Happy New Year 2016!"
 
// длина входящего сообщения сообщения
#define MESSAGE_LENGTH 160
 
// массив текста сообщения
char message[MESSAGE_LENGTH];
// номер, с которого пришло сообщение
char phone[16];
// дата отправки сообщения
char datetime[24];
 
// создаём объект класса GPRS и передаём в него объект Serial1 
GPRS gprs(Serial1);
// можно указать дополнительные параметры — пины PK и ST
// по умолчанию: PK = 2, ST = 3
// GPRS gprs(Serial1, 2, 3);
// если используете плату Arduino Uno или Arduino Mega2560
// прочтите внимательно статью о GPRS Shield, что бы сделать некоторые исправления
 
// создаём объект класса Adafruit_NeoPixel
Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, NEO_BRG + NEO_KHZ800);
 
// переменные, содержащие насыщенность красного, синего и зелёного цветов
int r, g, b;
 
void setup()
{
  // инициализация светодиодной ленты
  strip.begin();
  strip.show();
  // включаем GPRS шилд
  gprs.powerOn();
  // проверяем, есть ли связь с GPRS-устройством
  while (!gprs.init()) {
    // если связи нет, ждём 1 секунду
    // процесс повторяется в цикле,
    // пока не появится ответ от GPRS устройства
    delay(1000);
  }
  // заполняем RGB-ленту по сегментам «бегущий огонь»
  colorWipe(strip.Color(190, 0, 255), 50);
  // гасим RGB-ленту по сегментам «бегущая тень»
  colorWipe(strip.Color(0, 0, 0), 50);
}
 
void loop()
{
  // если пришло новое сообщение
  if (gprs.ifSMSNow()) {
    // сохраняем текст, номер с которого пришло и дату приёмки в переменные
    gprs.readSMS(message, phone, datetime);
    // проверяем подходит ли текст сообщения по нужный формат
    if (checkSMS() == 0) {
      // если нет, отправляем на номер с которого пришло сообщение
      // о неправильном формате смс
      gprs.sendSMS(phone, MESSAGE_ERROR);
      // возвращаемся в функцию loop и ожидаем нового сообщения
      return;
    }
    // переводим текст сообщения в целочисленную переменную
    int value = atoi(message);
    // проверка входит ли число в диапазон шкалы «HSV»
    if (value >= 0 && value <= 360) {
      // если да, отправляем на номер с которого пришло сообщение
      // об удачном смене цвета гирлянды
      gprs.sendSMS(phone, MESSAGE_OK);
      // переводим значение цвета из шкалы «HSV» в «RGB»
      f_HSV_to_RGB(value, 255, 255);
      // заполняем RGB-ленту по сегментам выбранным пользователем цветом
      colorWipe(strip.Color(r, g, b), 50);
    } else if (value == 2016) {
      // если число оказалось лотерейным
      // отправляем на номер с которого пришло сообщение
      // о включении секретного режима гирлянды
      gprs.sendSMS(phone, MESSAGE_BONUS);
      // включаем мигающий градиент цветов
      theaterChaseRainbow(50);
      // возвращаем предыдущий цвет RGB-ленты
      colorWipe(strip.Color(r, g, b), 50);
    } else {
      // если число не попало не в один диапазон чисел
      // отправляем на номер с которого пришло сообщение
      // о неправильном формате смс
      gprs.sendSMS(phone, MESSAGE_ERROR);
    }
  }
}
 
// функция проверки формата смс-сообщения
bool checkSMS()
{
  // создаём переменную и присваиваем ей длину текста сообщения
  int len = strlen(message);
  // если длина смс больше 4 символов или равна 0
  if (len == 0 || len > 4) {
    // выходим из функции и возвращаем «ложь»
    return false;
  }
 
  // проверка всех символов текста смс
  for (int i = 0; i < len; i++) {
    // если в тексте есть хотя бы одна не цифра
    if (message[i] < '0' || message[i] > '9') {
      // выходим из функции и возвращаем «ложь»
      return false;
    }
  }
 
  // если все условия выполнеы возвращаем «истину»
  return true;
}
 
// функция перевода цвета из шкалы «HSV» в «RGB»
void f_HSV_to_RGB(int hue, int sat, int val)
{
  int base;
  if (sat == 0) {
    r = val;
    g = val;
    b = val;
  } else {
    base = ((255 - sat) * val) >> 8;
    switch (hue / 60) {
      case 0: {
        r = val;
        g = (((val - base) * hue) / 60) + base;
        b = base;
        break;
      }
      case 1: {
        r = (((val - base) * (60 - (hue % 60))) / 60) + base;
        g = val;
        b = base;
        break;
      }
      case 2: {
        r = base;
        g = val;
        b = (((val - base) * (hue % 60)) / 60) + base;
        break;
      }
      case 3: {
        r = base;
        g = (((val - base) * (60 - (hue % 60))) / 60) + base;
        b = val;
        break;
      }
      case 4: {
        r = (((val - base) * (hue % 60)) / 60) + base;
        g = base;
        b = val;
        break;
      }
      case 5: {
        r = val;
        g = base;
        b = (((val - base) * (60 - (hue % 60))) / 60) + base;
        break;
      }
      case 6: {
        r = val;
        g = 0;
        b = base;
        break;
      }
    }
  }
}
 
// функция заполнения каждого сегмента
void colorWipe(uint32_t c, uint8_t wait)
{
  for (uint16_t i = 0; i < strip.numPixels(); i++) {
    // заполняем текущий сегмент выбранным цветом
    strip.setPixelColor(i, c);
    strip.show();
    // ждём
    delay(wait);
  }
}
 
// функция эффекта радуги
void theaterChaseRainbow(uint8_t wait)
{
  for (int j = 0; j < 256; j++) {
    for (int q = 0; q < 3; q++) {
      for (int i = 0; i < strip.numPixels(); i = i + 3) {
        // включаем каждый третий сегмент
        strip.setPixelColor(i + q, wheel((i+j) % 255));
      }
      strip.show();
      // ждём
      delay(wait);
      for (int i = 0; i < strip.numPixels(); i = i + 3) {
        // выключаем каждый третий сегмент
        strip.setPixelColor(i+q, 0);
      }
    }
  }
}
 
uint32_t wheel(byte wheelPos)
{
  wheelPos = 255 - wheelPos;
  if (wheelPos < 85) {
    return strip.Color(255 - wheelPos * 3, 0, wheelPos * 3);
  }
  if (wheelPos < 170) {
    wheelPos -= 85;
    return strip.Color(0, wheelPos * 3, 255 - wheelPos * 3);
  }
  wheelPos -= 170;
  return strip.Color(wheelPos * 3, 255 - wheelPos * 3, 0);
}

Для компиляции скетча вам понадобятся библиотеки GPRS-shield и Adafruit_NeoPixel.

Демонстрация работы устройства

Что дальше?

Заменив в своём проекте GPRS Shield на датчик шума вы дадите уши своему проекту. И получите из RGB-ленты — светомузыкальную установку.