Освежитель воздуха

Показывайте и делитесь своими замечательными проектами здесь! Мы любим картинки!
Ответить
Mikhail72
Сообщения: 18
Зарегистрирован: 04 окт 2017, 06:02
Откуда: Тюмень
Контактная информация:

Освежитель воздуха

Сообщение Mikhail72 »

Появилось время написать тему про мой первый проект на MySensors в связке c MajorDoMo.
Нашёл как-то на форуме majordomo.smartliving.ru тему про Ароматизатор MySensors, тема заинтересовала, потыкался-помыкался, знаний не хватает, отложил ненадолго и начал изучать программирование Arduino и протокол MySensors.
На сегодняшний день, устройство работает отлично, по следующему алгоритму:
Если дома кто-то есть, устройство срабатывает каждые 30 мин. с 7-00 до 23-00
Если свет горел более 5 мин., после выключения срабатывает освежитель.
Также освежитель отсылает в MajorDoMo статус света (On/Off) и количество срабатываний (планируется сделать уведомление о приобретении нового баллона, когда узнаю на сколько срабатываний хватает зелья :D ).
Преимущества моей доработки освежителя в том, что сохраняется место для второго элемента питания и срабатывание реализуется за счёт имеющейся схемы управления.
И так: к встроенной плате
Фото1.jpg
Фото1.jpg (41.37 КБ) 15414 просмотров
нужно припаять два проводка и перерезать одну дорожку
Фото2.jpg
Фото2.jpg (40.54 КБ) 15414 просмотров

Спаять бутерброд из Arduino ProMini, NRF24l01 и Датчика света на фототранзисторе и разместить его под моторчик
Фото3.jpg
Фото3.jpg (49.45 КБ) 15414 просмотров
Mikhail72
Сообщения: 18
Зарегистрирован: 04 окт 2017, 06:02
Откуда: Тюмень
Контактная информация:

Re: Освежитель воздуха

Сообщение Mikhail72 »

Перед сборкой просверлить два отверстия одно для регулировки светочувствительности, второе для фототранзистора
Фото4.jpg
Фото4.jpg (37.33 КБ) 15413 просмотров
После проделанных манипуляций должно получится так:
Фото5.jpg
Фото5.jpg (35.81 КБ) 15413 просмотров
Питается данный девайс от двух Li-Ion аккумуляторов 14500 включенных параллельно, а для снижения напряжения с 4,2 до 3,6 (максимальное для NRF24) в цепь питания включены последовательно 3 диода 1N4007.

Ну и сам Скетч

Код: Выделить всё

// Enable debug prints to serial monitor
//#define MY_DEBUG 
//#define MY_SPECIAL_DEBUG
// Enable and select radio type attached
#define MY_RADIO_NRF24
//#define MY_RADIO_RFM69
#define MY_NODE_ID 1                // Номер ноды
// Enabled repeater feature for this node
//#define MY_REPEATER_FEATURE
#include <SPI.h>
#include <MySensors.h>

int BATTERY_SENSE_PIN = A0;         // Аналоговый пин к которому подключен + батареи
unsigned long SLEEP_TIME = 1800;    // Время сна, в секундах
unsigned long LIGHT_ON = 300;       // Минимальное время горения света, после выключения которого "ПШИК", в секундах
#define RELAY_PIN  4                // Выход активации механизма
#define DIGITAL_INPUT_SENSOR 3      // Вход с прерыванием для датчика света
#define CHILD_ID_STATE 1            // Id сенсоры ноды (0-254)
#define CHILD_ID_LIGHT 2
#define CHILD_ID_VOLUME 3
#define RELAY_ON 1
#define RELAY_OFF 0

int8_t wu = 0;
bool state = 1;
int light = 0;
int value = 0;
int x = 0;
bool w = 0;
int t = 0;
int oldBatteryPcnt = 0;

MyMessage lmsg(CHILD_ID_LIGHT, V_STATUS);
MyMessage vmsg(CHILD_ID_VOLUME, V_CUSTOM);

void setup()  
{  
wdt_disable();
    // use the 1.1 V internal reference
#if defined(__AVR_ATmega2560__)
  analogReference(INTERNAL1V1);
#else
  analogReference(INTERNAL);
#endif
  pinMode(RELAY_PIN, OUTPUT);
  pinMode(DIGITAL_INPUT_SENSOR, INPUT_PULLUP);
}

void presentation()  {
  // Send the sketch version information to the gateway and Controller
  sendSketchInfo("AirWick", "3.0");

  // Register all sensors to gw (they will be created as child devices)
  present(CHILD_ID_STATE, S_BINARY);
  present(CHILD_ID_LIGHT, S_BINARY);
  present(CHILD_ID_VOLUME, S_CUSTOM);
}

/*
*  Example on how to asynchronously check for new messages from gw
*/
void loop() 
{
 wu = smartSleep(digitalPinToInterrupt(DIGITAL_INPUT_SENSOR), LOW, SLEEP_TIME * 1000); // Засыпаем
  
 request(CHILD_ID_STATE, V_STATUS);               // Запрашиваем статус присутствия кого-либо дома
 
 w = wait(100, 1, V_STATUS);                      // Ждём 500 мс сообщение типа V_STATUS
 while (w == 0){                                  // Если ответ не получен повторяем 3 раза
  t++;                                            // После пропускаем и продолжаем выполнение кода
  w = wait(500, 1, V_STATUS);                     
  if (t == 3){                                    
    t = 0;                                        
    w = 1;                                        
  }
  }
 if ((wu == 1) && (state == 1)){                  // Если проснулись по прерыванию и дома кто-то есть
  light = digitalRead(DIGITAL_INPUT_SENSOR);      // Проверяем включен ли свет
  send(lmsg.set(HIGH));                            // Отправка Свет - ON
  wait(50);
  while (light == 0){                             // Пока включен свет
   value++;                                       // Считаем секунды пока горит лампочка
   wait(1000);
   light = digitalRead(DIGITAL_INPUT_SENSOR);     // Ждём пока потухнет
  }
  if ((value > LIGHT_ON) && (light == 1)){        // Если свет потух и счётчик превысил установленное время для "ПШИКА"
   refreshing();                                  // Освежаем
   value = 0;                                     // Обнуляем счётчик
   state = 0;                                     // Сбрасываем статус
   send(lmsg.set(LOW));                           // Отправка Свет - OFF
   wait(50);
  } else value = 0; send(lmsg.set(LOW)); wait(50);// Если свет погас до минимально установленного времени "ПШИКА", обнуляем счётчик, отправляем Свет - OFF
 } else if ((wu == -1) && (state == 1)){          // Если проснулись по истенчение времени сна и дома кто-то есть
                                                  // Определение заряда батареи
 int sensorValue = analogRead(BATTERY_SENSE_PIN);
 int batteryPcnt = sensorValue / 10;
 if (oldBatteryPcnt != batteryPcnt) {
    // Power up radio after sleep
    sendBatteryLevel(batteryPcnt);
    oldBatteryPcnt = batteryPcnt;
    }
    refreshing();                                 // Освежаем
    state = 0;                                    // Сбрасываем статус
  }
}
void refreshing(){                                // Функция освежения, активации AirWick и отправки количества срабатываний
 digitalWrite(RELAY_PIN, RELAY_ON);
 wait(750);
 digitalWrite(RELAY_PIN, RELAY_OFF);
 x++;
 send(vmsg.set(x));
 wait(20);
}

void receive(const MyMessage &message) {          // Функция запроса, есть ли кто дома
    if (message.type == V_STATUS) {
     state = message.getBool();
     }
}
void sendHeartbeat();
И код для MajorDoMO, который лучше добавить в метод onNewHour для подсчёта количества срабатываний в сутки и в месяц:

Код: Выделить всё

$h=date('G',time());
$j=date('j');
$q3=gg('AirWick.Q3'); // Сумма срабатываний с перезагрузки
$q11=gg('AirWick.Q11'); // Сумма срабатываний на начало дня
$q21=gg('AirWick.Q21'); // Сумма срабатываний на текущую дату с начала месяца
$q31=gg('AirWick.Q31'); // количество срабатываний с начала дня до перезагрузки, если она была

if ($h=="23") { // Вычисления суммы срабатываний в сутки
  $q1=$q3-$q11+$q31;
  $q2=$q3-$q11+$q21;
  setGlobal('AirWick.Q1', $q1);
  setGlobal('AirWick.Q11', $q3);
  setGlobal('AirWick.Q21',$q2);
  setGlobal('AirWick.Q31', 0);
}

if (($j=="1") && ($h=="7")) { // Вычисление в месяц
  setGlobal('AirWick.Q2',$q21);
  setGlobal('AirWick.Q21', 0);
}
А эту часть надо прописать в метод который будет вызываться при изменении свойства, в которое приходят данные от AirWick.

Код: Выделить всё

$q=gg('AirWick.Quantity'); // Новое значение
$q3=gg('AirWick.Q3'); // Предыдущее значение 
$q11=gg('AirWick.Q11'); // Сумма срабатываний на начало дня

if ($q < $q3) {
  $q31 = $q3-$q11;                //Вычисляем количество срабатываний с
  setGlobal('AirWick.Q31', $q31); // начала дня до перезагрузки
  setGlobal('AirWick.Q11', 0);  // Обнуляем сумму на начало дня
  setGlobal('AirWick.Q3',$q);   // Обновляем предыдущее значение
} else setGlobal('AirWick.Q3',$q);//Иначе обновляем предыдущее значение
П.С. Экономическая выгода: доработка обошлась менее двухсот рублей (не считая стоимости аккумуляторов), баллон зелья стоит двести с копейками, штатный AirWick работал на одном баллоне максимум два месяца, доработанный 3 месяца, т.к. жена сидит в дикретном отпуске и пауза у него только ночью, но думаю скоро будет работать 5-6 месяцев, поэтому "Выводы делать только вам".
Mikhail72
Сообщения: 18
Зарегистрирован: 04 окт 2017, 06:02
Откуда: Тюмень
Контактная информация:

Re: Освежитель воздуха

Сообщение Mikhail72 »

Немного поправил скетч, добавил в отправку время, которое был включен свет. И решил сообщить что прогноз сбылся, после замены баллона в январе, он прослужил 6 месяцев, сейчас на тесте следующий :)

Код: Выделить всё

#define MY_SPECIAL_DEBUG
#define MY_RADIO_RF24
#define MY_NODE_ID 1                // Номер ноды

#include <MySensors.h>

int BATTERY_SENSE_PIN = A0;         // Аналоговый пин к которому подключен + батареи
unsigned long SLEEP_TIME = 1800;    // Время сна, в секундах
unsigned long LIGHT_ON = 300;       // Минимальное время горения света, после выключения которого "ПШИК", в секундах
#define RELAY_PIN  4                // Выход активации механизма
#define DIGITAL_INPUT_SENSOR 3      // Вход с прерыванием для датчика света
#define CHILD_ID_STATE 1            // Id сенсоры ноды (0-254)
#define CHILD_ID_LIGHT 2
#define CHILD_ID_VOLUME 3
#define CHILD_ID_TIME 4
#define RELAY_ON 1
#define RELAY_OFF 0

int8_t wu = 0;
bool state = 1;
int light = 0;
int value = 0;
int x = 0;
bool w = 0;
int t = 0;
int oldBatteryPcnt = 0;

MyMessage lmsg(CHILD_ID_LIGHT, V_STATUS);
MyMessage vmsg(CHILD_ID_VOLUME, V_CUSTOM);
MyMessage tmsg(CHILD_ID_TIME, V_CUSTOM);

void setup()  
{  
wdt_disable();
    // use the 1.1 V internal reference
#if defined(__AVR_ATmega2560__)
  analogReference(INTERNAL1V1);
#else
  analogReference(INTERNAL);
#endif
  pinMode(RELAY_PIN, OUTPUT);
  pinMode(DIGITAL_INPUT_SENSOR, INPUT_PULLUP);
}

void presentation()  {
  // Send the sketch version information to the gateway and Controller
  sendSketchInfo("AirWick", "1.0");

  // Register all sensors to gw (they will be created as child devices)
  present(CHILD_ID_STATE, S_BINARY, "Somebodyhome");
  present(CHILD_ID_LIGHT, S_BINARY, "Light_on/off");
  present(CHILD_ID_VOLUME, S_CUSTOM, "Quantity");
  present(CHILD_ID_TIME, S_CUSTOM, "Time_light_on");
}

void loop() 
{
 wu = smartSleep(digitalPinToInterrupt(DIGITAL_INPUT_SENSOR), LOW, SLEEP_TIME * 1000); // Засыпаем
  
 request(CHILD_ID_STATE, V_STATUS);               // Запрашиваем статус присутствия кого-либо дома
 
 w = wait(100, 1, V_STATUS);                      // Ждём 500 мс сообщение типа V_STATUS
 while (w == 0){                                  // Если ответ не получен повторяем 3 раза
  request(CHILD_ID_STATE, V_STATUS);              // После пропускаем и продолжаем выполнение кода
  t++;                                           
  w = wait(500, 1, V_STATUS);                     
  if (t == 3){                                    
    t = 0;                                        
    w = 1;                                        
  }
  }
 if (wu == 1){                                    // Если проснулись по прерыванию
  light = digitalRead(DIGITAL_INPUT_SENSOR);      // Проверяем включен ли свет
  send(lmsg.set(HIGH));                           // Отправка Свет - ON
  wait(50, 1, V_STATUS);
  while (light == 0){                             // Пока включен свет
   value++;                                       // Считаем секунды пока горит лампочка
   wait(1000);
   light = digitalRead(DIGITAL_INPUT_SENSOR);     // Ждём пока потухнет
  }
  if ((value > LIGHT_ON) && (light == 1)){        // Если свет потух, счётчик превысил установленное время для "ПШИКА"
   if(state == 1) refreshing();                   // и дома кто-то есть, освежаем
   send(tmsg.set(value));                         // Отправляем время, которое был включен свет в сек.
   value = 0;                                     // Обнуляем счётчик
   state = 0;                                     // Сбрасываем статус
   send(lmsg.set(LOW));                           // Отправка Свет - OFF
   wait(50, 1, V_STATUS);
   } else {                                       // Если свет погас до минимально установленного времени "ПШИКА",
      send(tmsg.set(value));                      // Отправляем время,
      value = 0;                                  // Обнуляем счётчик,
      send(lmsg.set(LOW));                        // Отправляем Свет - OFF
      wait(50, 1, V_STATUS);
   }
 } else if ((wu == -1) && (state == 1)){          // Если проснулись по истенчение времени сна и дома кто-то есть
                                                  // Определение заряда батареи
 int sensorValue = analogRead(BATTERY_SENSE_PIN);
 int batteryPcnt = sensorValue / 10;
 if (oldBatteryPcnt != batteryPcnt) {
    // Power up radio after sleep
    sendBatteryLevel(batteryPcnt);
    oldBatteryPcnt = batteryPcnt;
    }
    refreshing();                                 // Освежаем
    state = 0;                                    // Сбрасываем статус
  }
}
void refreshing(){                                // Функция освежения, активации AirWick и отправки количества срабатываний
 digitalWrite(RELAY_PIN, RELAY_ON);
 wait(750);
 digitalWrite(RELAY_PIN, RELAY_OFF);
 x++;
 send(vmsg.set(x));
 wait(20);
}

void receive(const MyMessage &message) {          // Функция запроса, есть ли кто дома
    if (message.type == V_STATUS) {
     state = message.getBool();
     }
}
void sendHeartbeat();
Ответить