Ночник с выключением по расписанию

в 14:28, , рубрики: diy или сделай сам, z-wave, ZUNO, умный дом

image

С рождением ребёнка встал вопрос о ночнике. Где-то прочитали, что он необходим для спокойного сна. Быстро привыкли спать с тусклым светом. Очень удобно просыпаться от криков и воев среди ночи и видеть на что жалуется малыш (если удастся понять). Так же при тусклом свете можно укачать, перевернуть и продолжить спать.

Вначале был изготовлен тестовый образец светильника из куска жёлтой светодиодной ленты (12 вольт), который использовался 1,5 года.


image

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

Быстро собрал прототип на базе arduino nano. Отладил базовую функциональность.

image

Пользуясь случаем попробовал Fritzing. Не понравилось, но картинки получаются наглядные и «весёлые». Как видно ничего нового не изобрёл.

image

Заменил “nano” на малоизвестный, ардуино-совместимый модуль с встроенным радио приёмо-передатчиком (контроллер 8-ми битный, производительность и нафаршерованность сравнима с «наной»). Дома у меня уже есть одно устройство работающее на частоте 868 МГц, это будет второе. Краткие характеристики с сайта производителя:

Краткие характеристики

image

image

Не вижу больших проблем сделать тоже самое на ESP8266 (есть удобный онлайн сборщик прошивок для скриптов на LUA). Немного сложнее на Bluetooth (для перепрошивки модуля HM-10 нужен недорогой программатор, среда для разработки и понимание протокола). Хотя можно использовать Bluetooth модуль вместе с ардуиной. Но я использовал ZUNo, потому что уже давно лежит и ждёт меня, а также готова вся инфраструктура по соединению и управлению подобными устройствами в одну сеть (я про контроллер сети умного дома).
Для всех используемых ножек на ардуино нашлись аналоги в модуле.

image

Чтобы работать с модулем из Arduino IDE нужно её настроить (описание настройки есть на сайте производителя). Чуда не произошло. При попытке компиляции получил ошибку “doesn't support «for» statement with empty columns or without body!”. Я использовал библиотеку Adafruit_NeoPixel. Залез в неё увидел сколько в ней циклов и закрыл. Пришлось опять идти на сайт производителя и искать в примерах работу со светодиодами (пример быстро нашёлся). Значит, я не первый, кто столкнулся с подобной проблемой.

Чтобы данный светильник управлялся по радио в код ардуино нужно добавить макрос и реализовать несколько функций:

ZUNO_SETUP_CHANNELS(
      ZUNO_SWITCH_MULTILEVEL(getRed, setRed),
      ZUNO_SWITCH_MULTILEVEL(getGreen, setGreen),
      ZUNO_SWITCH_MULTILEVEL(getBlue, setBlue),
      ZUNO_SWITCH_BINARY(switch_getter, switch_setter)
);

Данный макрос описывает устройство Z-Wave c тремя многоуровневыми переключателями (управление RGB) и одним простым переключателем (простое включение/выключение).

Реализация функций у меня простейшая (как в примерах на сайте производителя). Посмотреть можно в прикреплённом листинге.

Подбор корпуса

Корпус у меня уже был. Герметичный с прозрачной крышкой. Под крышкой поместилось 25 светодиодов. Испытания прошли успешно. Светильник имеет большой запас по яркости, для моей комнаты. Крышка у данного корпуса прозрачная, поэтому решил немного рассеять свет.

image

Набросал цветных бусинок и акриловых кубиков, залил прозрачной эпоксидкой. Краска с цветных бусинок под воздействием смолы растворилась.

image

Самое интересное, что крышка от герметичного корпуса протекла и почти вся смола вытекла. Не знаю где я успел ударить крышку, но после высыхания трещина отчётливо видна.

image

Печатную плату изготовил фоторезистивным методом.

image

image

После травления и механической обработки

image

Модуль с микроконтроллером заменил на его прототип, валявшийся в шкафу (потому что не жалко, а ZUNo нужно беречь). Первая версия ZUNo, но габариты больше и хуже антенна, да и не купишь уже. Испытания прошли более-менее успешно. Последний сегмент пришлось перепаять. Изначально был впаян не той стороной. И скорректировать количество светодиодов в прошивке.

image

image

Вот что получилось:

image

Управление по радио

Главное окно с каналами управления светильника

image

Настройка яркости одного канала светодиодной ленты

image

Настройка утреннего отключения ночника

image

Заключение

Устройство работает. Оно компактное и аккуратное. Питается от зарядки мобильного телефона.
Из замеченных проблем:

  • во время сборки оторвал часть дорожек на переменных резисторах, поэтому в ручном режиме можно управлять только одним каналом.
  • из 25 светодиодов нормально работают только 20. Мне и этого много, поэтому, скорее всего, оставлю до выявления более серьёзных недостатков

Скетч ночника

#include "ZUNO_NeoPixel.h"

#define MAX_PIXELS 20 // NB! Z-Uno can not control more than 25 WS2811 without harming RF communications
#define PIXEL_SIZE 3  // Three colors per pixel
#define BUFF_SIZE (MAX_PIXELS * PIXEL_SIZE)

byte pixel_buff[BUFF_SIZE];

NeoPixel pixels(pixel_buff, BUFF_SIZE);

#define B_PRESSED 1
#define BUTTON_PIN   1    // Digital IO pin connected to the button.  This will be

#define DEF_RED 30
#define DEF_GREEN 20

byte red = DEF_RED;
byte green = DEF_GREEN;
byte blue = 0;

#define POWER_ON 1
#define POWER_OFF 0
byte light_power = POWER_ON;
byte last_light_power = POWER_OFF;


ZUNO_SETUP_CHANNELS(
      ZUNO_SWITCH_MULTILEVEL(getRed, setRed),
      ZUNO_SWITCH_MULTILEVEL(getGreen, setGreen),
      ZUNO_SWITCH_MULTILEVEL(getBlue, setBlue),
      ZUNO_SWITCH_BINARY(switch_getter, switch_setter)
);


void switch_setter(byte value) 
{
  Serial.println("switch");
  Serial.print("value= ");
  Serial.println(value);
  if(value > 1)
    light_power = POWER_ON;
  else
    light_power = POWER_OFF;
}

byte switch_getter() 
{
  return light_power;
}

int getRed() {
  return red/2.56;
}

int getGreen() {
  return green/2.56;
}

int getBlue() {
  return blue/2.56;
}

void setRed(byte value) {
  red = value * 2,56;
  for(uint8_t i = 0; i < MAX_PIXELS; i++) 
    pixels.setPixelColor(i, pixels.Color(red, green, blue)); 
  pixels.show();
  Serial.print("set red = ");
  Serial.println(value);
}

void setGreen(byte value) {
  green = value * 2,56;
  for(uint8_t i = 0; i < MAX_PIXELS; i++) 
    pixels.setPixelColor(i, pixels.Color(red, green, blue)); 
  pixels.show();
  Serial.print("set red = ");
  Serial.println(value);
}

void setBlue(byte value) {
  blue = value * 2,56;
  for(uint8_t i = 0; i < MAX_PIXELS; i++) 
    pixels.setPixelColor(i, pixels.Color(red, green, blue)); 
  pixels.show();
  Serial.print("set red = ");
  Serial.println(value);
}

void set_LEDS()
{
   for(uint8_t i = 0; i < MAX_PIXELS; i++) 
    pixels.setPixelColor(i, pixels.Color(red, green, blue)); 
   pixels.show();
}

void read_resistors()
{
  red = (analogRead(A0) >> 2) & 0xff;
  green = (analogRead(A1) >> 2) & 0xff;
  blue =  (analogRead(A3) >> 2) & 0xff;
  Serial.print(red);
  Serial.print(" ");
  Serial.print(green);
  Serial.print(" ");
  Serial.print(blue);
  Serial.print(" ");
  Serial.println();
  set_LEDS();
}

#define DEBOUNCE_ACK 10
byte check_button()
{
  static bool oldState = HIGH;
  byte debounce_cnt = 0;
  static byte ret = 0;
  if(digitalRead(BUTTON_PIN) == LOW)
  {
    if(ret != B_PRESSED)
      while(digitalRead(BUTTON_PIN) == LOW)
      {
        if(debounce_cnt == DEBOUNCE_ACK)
        {
          ret = B_PRESSED;
          break;
        }
        else
          debounce_cnt++;
       delay(10);
      } 
  }
  else
  {
    debounce_cnt = 0;
    ret = 0;
  }
    
  return ret;
}

void setup() {
  Serial.begin(9600);
  pixels.begin();
  pixels.clear();
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  
}


void loop() 
{
  if(check_button() == B_PRESSED)
    read_resistors();
  if(last_light_power != light_power)
  {
    Serial.println("set power");
    if(light_power == POWER_OFF)
    {
      Serial.println("power off");
      red = 0;
      green = 0;
      blue = 0;
    }
    else
    {
      Serial.println("power on");
      red = DEF_RED;
      green = DEF_GREEN;
      blue = 0;
    }
    set_LEDS();
    last_light_power = light_power;
  }  
}

Автор: sergeyvass

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js