В комнате где играет ребенок я установил дополнительную подсветку в виде LED ленты. Изначально я планировал, что буду управлять яркостью ленты, это удобно для настройки ночной подсветки. У меня уже был Z-Wave диммер на 220В, поэтому дешевле было докупить диммируемый трансформатор на 12В за 1000р, чем специальный RGBW контроллер от Fibaro за 5500р.
Это решение работает, но есть минусы:
- Задержка при диммировании
- Нельзя установить очень маленький уровень яркости
Спустя год использования, я решил изготовить свой Z-Wave LED контроллер, но с энкодером и в корпусе от диммера, для установки в подрозетник.
Принципиальная схема устройства элементарна, к Z-Uno напрямую подключается энкодер 3-мя пинами: пин A, пин B и кнопка. Мосфет подключается к PWM пину.
№ | Материал | Фото | Цена |
1 | Z-Wave плата Z-Uno | 3500 р | |
2 | MOSFET IRLR8729 | 27 р | |
3 | Encoder EC11 | 50 р |
Z-Wave плата Z-Uno программируется в среде Arduino, скетч для обработки сигналов от энкодера и управления мосфетом занимает всего 143 строчки кода с комментариями. Скетч работает следующим образом:
Каждые 128 мкс по прерыванию от таймера проверяем, в какую сторону крутят колесико, от дребезга защищаемся 4-х кратной проверкой состояния. В лупе проверяем нажатие кнопки, при каждом нажатии выключаем ленту или включаем на предыдущий уровень яркости. Яркость можно задавать как с энкодера, так и с телефона или другого Z-Wave выключателя.
#define PUSH_BUTTON 23 #define ENCODER_CHA_PIN 19 #define ENCODER_CHB_PIN 20 #define LEV_SHIFT 8 #define ENCODER_DEBONCE 4 #define STATE_IDLE 0xFF #define STATE_SKIP 0xFE ZUNO_SETUP_ISR_GPTIMER(gpt_handler); ZUNO_SETUP_CHANNELS(ZUNO_SWITCH_MULTILEVEL(getter, setter)); byte level = 0; byte last_reported_level = 0; byte g_state = STATE_IDLE; byte g_pins = 0; byte g_debounce_time = 0; byte last_push_button_state = HIGH; byte stored_level = 0; dword last_level_changed_time = 0; // Runs every 128 μs void gpt_handler() { byte pins = 0; pins = !digitalRead(ENCODER_CHA_PIN); if(!digitalRead(ENCODER_CHB_PIN)) pins |= 2; if(g_pins == pins) { // Is the state stable? g_debounce_time++; if(g_debounce_time>ENCODER_DEBONCE) { if(g_state == STATE_IDLE) { g_state = pins; } else if(g_state == STATE_SKIP) { if(pins == 0) g_state = 0; } else { if((g_state == 0 && pins == 1) || (g_state == 1 && pins == 3) || (g_state == 3 && pins == 2) || (g_state == 2 && pins == 0) ) { if (level < 39) { level++; } else if ((level + LEV_SHIFT) <= 255) { level += LEV_SHIFT; } else if ((level + LEV_SHIFT) > 255){ level = 255; } } else if((g_state == 0 && pins == 2) || (g_state == 2 && pins == 3) || (g_state == 3 && pins == 1) || (g_state == 1 && pins == 0) ) { if (level <= 39 && level !=0) { level--; } else if (level >= LEV_SHIFT) { level -= LEV_SHIFT; } else if (level < 0) { level = 0; } } if(g_state != pins) g_state = STATE_SKIP; } g_debounce_time = 0; } } else { g_debounce_time = 0; } g_pins = pins; } void setup() { Serial.begin(); pinMode(PUSH_BUTTON, INPUT_PULLUP); pinMode(ENCODER_CHA_PIN, INPUT); pinMode(ENCODER_CHB_PIN, INPUT_PULLUP); zunoGPTInit(ZUNO_GPT_SCALE1024|ZUNO_GPT_CYCLIC); // 32 MHz/1024 = 31.25 kHz (tick is 32 μs) zunoGPTSet(4); // 32 μs * 4 = 128 μs zunoGPTEnable(1); } void loop() { // Do we need to report the level? if(last_reported_level != level) { if (level > 0) { stored_level = level; } last_reported_level = level; analogWrite(PWM1, level); last_level_changed_time = millis(); Serial.print("Level: "); Serial.println(level); } // Button handler byte current_push_button_state = digitalRead(PUSH_BUTTON); if (current_push_button_state != last_push_button_state) { last_push_button_state = current_push_button_state; // if button pressed if (last_push_button_state == LOW) { // if LED turned ON, turn OFF if (level > 0) { analogWrite(PWM1, 0); level = 0; } // Restore last level else { analogWrite(PWM1, stored_level); level = stored_level; } } } // Send report if 2 seconds level not changed if (last_level_changed_time && millis() > last_level_changed_time + 2000) { last_level_changed_time = 0; zunoSendReport(1); } } void setter(byte value) { if (value > 99) { value = 99; } level = (long)value * 255 / 99; analogWrite(PWM1, level); } byte getter(void) { return last_reported_level * 99 / 255; }
Чтобы изменить яркость ленты с помощью диммера, который я раньше использовал, нужно было удерживать клавишу вверх или вниз, это не очень удобно, трудно подстроить нужный уровень яркости. Да и выглядит диммер, как обычный выключатель, а не как классический светорегулятор с колесиком к которому многие привыкли.
Для нового Z-Wave LED контроллера я модифицировал корпус диммера — просверлил отверстие для энкодера и немного поменял крепление рамки, чтобы использовать рамку от другого выключателя. За дизайн не пинайте, делал из подручных материалов. Можно использовать и готовый корпус от обычного диммера, чтобы выглядело эстетично.
ЛУТ решает! Для изготовления единичного экземпляра платы, лучше ЛУТА я не знаю технологии, поэтому изготовил 2 платы, которые идеально помещаются в корпусе старого диммера. В нижней части находится Z-Uno, мосфет и колодка для подключения питания и ленты, кстати мосфет рассчитан на напряжения до 30В, поэтому ленту можно использовать, как 12В, так и 24В, без радиатора ток лучше не превышать более 5А.
В верхней части расположен только энкодер.
Соединив бутерброд из плат и поместив его в корпус, получился Z-Wave LED контроллер.
На данный момент Z-Wave LED контроллер не установлен в подрозетник и лежит на тумбе под телевизор. Некоторое время еще потестирую работу.
Но уже сейчас удобство управления LED лентой сильно повысилось, при управлении с колесика или прикроватного выключателя яркость изменяется мгновенно. В Z-Wave шкала диммирования находится в диапазоне от 0 до 99, с помощью колесика можно выбрать уровень яркости от 0 до 255. При вращении на 1 деление после 0 светодиоды чуть светят, ночью это никого не разбудит, но поможет не наступать на случайно забытый кубик LEGO на полу.
На изготовление устройства ушло 3 вечера, 1 вечер — написание прошивки, 1 вечер ЛУТ, 1 вечер работа напильником.
Источник