Появилось время написать тему про мой первый проект на MySensors в связке c MajorDoMo.
Нашёл как-то на форуме majordomo.smartliving.ru тему про Ароматизатор MySensors, тема заинтересовала, потыкался-помыкался, знаний не хватает, отложил ненадолго и начал изучать программирование Arduino и протокол MySensors.
На сегодняшний день, устройство работает отлично, по следующему алгоритму:
Если дома кто-то есть, устройство срабатывает каждые 30 мин. с 7-00 до 23-00
Если свет горел более 5 мин., после выключения срабатывает освежитель.
Также освежитель отсылает в MajorDoMo статус света (On/Off) и количество срабатываний (планируется сделать уведомление о приобретении нового баллона, когда узнаю на сколько срабатываний хватает зелья ).
Преимущества моей доработки освежителя в том, что сохраняется место для второго элемента питания и срабатывание реализуется за счёт имеющейся схемы управления.
И так: к встроенной плате нужно припаять два проводка и перерезать одну дорожку
Спаять бутерброд из Arduino ProMini, NRF24l01 и Датчика света на фототранзисторе и разместить его под моторчик
Освежитель воздуха
Re: Освежитель воздуха
Перед сборкой просверлить два отверстия одно для регулировки светочувствительности, второе для фототранзистора
Ну и сам Скетч
И код для MajorDoMO, который лучше добавить в метод onNewHour для подсчёта количества срабатываний в сутки и в месяц:
А эту часть надо прописать в метод который будет вызываться при изменении свойства, в которое приходят данные от AirWick.
П.С. Экономическая выгода: доработка обошлась менее двухсот рублей (не считая стоимости аккумуляторов), баллон зелья стоит двести с копейками, штатный AirWick работал на одном баллоне максимум два месяца, доработанный 3 месяца, т.к. жена сидит в дикретном отпуске и пауза у него только ночью, но думаю скоро будет работать 5-6 месяцев, поэтому "Выводы делать только вам".
После проделанных манипуляций должно получится так:
Питается данный девайс от двух 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();
Код: Выделить всё
$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);
}
Код: Выделить всё
$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);//Иначе обновляем предыдущее значение
Re: Освежитель воздуха
Немного поправил скетч, добавил в отправку время, которое был включен свет. И решил сообщить что прогноз сбылся, после замены баллона в январе, он прослужил 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();