Раскладка по репозиториям
parent
a8b206c3a1
commit
d8a09949f6
|
@ -56,7 +56,7 @@
|
||||||
#define CCS811_ADDR 0x5B //Default I2C Address
|
#define CCS811_ADDR 0x5B //Default I2C Address
|
||||||
//#define CCS811_ADDR 0x5A //Alternate I2C Address
|
//#define CCS811_ADDR 0x5A //Alternate I2C Address
|
||||||
|
|
||||||
unsigned int VersionSW = 46; //65536 Версия прошивки
|
unsigned int VersionSW = 48; //65536 Версия прошивки
|
||||||
|
|
||||||
//15 - добавлено то, се, забыл вообще дописать что добавлено Serial
|
//15 - добавлено то, се, забыл вообще дописать что добавлено Serial
|
||||||
//19 - вывод в консоль всех действий, ошибки с обновлнеием - починил, прияногое мигание светодиодом, тест для поиска metrics.
|
//19 - вывод в консоль всех действий, ошибки с обновлнеием - починил, прияногое мигание светодиодом, тест для поиска metrics.
|
||||||
|
@ -83,6 +83,7 @@ unsigned int VersionSW = 46; //65536 Версия прошивки
|
||||||
//43 - Больше задержек для чтения i2c
|
//43 - Больше задержек для чтения i2c
|
||||||
//44 - Новая либа твок "maarten-pennings" Спаркфан и Адафрут суки - с ошибками изначально пишут на всех форумах.
|
//44 - Новая либа твок "maarten-pennings" Спаркфан и Адафрут суки - с ошибками изначально пишут на всех форумах.
|
||||||
//46 - Смена локального сервера времени, хрони на одроиде. Установка базовых линий по новой.
|
//46 - Смена локального сервера времени, хрони на одроиде. Установка базовых линий по новой.
|
||||||
|
//48 - алгоритм фильтрации
|
||||||
|
|
||||||
WiFiManager wm; // обьект менеджера
|
WiFiManager wm; // обьект менеджера
|
||||||
WiFiManagerParameter custom_field;
|
WiFiManagerParameter custom_field;
|
||||||
|
@ -93,7 +94,7 @@ Preferences OTApreferences; //Обьект хранения настроек х
|
||||||
CCS811 ccs811(23);
|
CCS811 ccs811(23);
|
||||||
|
|
||||||
ClosedCube_HDC1080 hdc1080;
|
ClosedCube_HDC1080 hdc1080;
|
||||||
StaticJsonDocument<200> doc;
|
StaticJsonDocument<200> doc;
|
||||||
|
|
||||||
WiFiClient espClient;
|
WiFiClient espClient;
|
||||||
PubSubClient MqttClient(espClient);
|
PubSubClient MqttClient(espClient);
|
||||||
|
@ -132,6 +133,15 @@ unsigned int cntWhile = 4;
|
||||||
bool mqttSendFlag = false;
|
bool mqttSendFlag = false;
|
||||||
bool flagblink = true;
|
bool flagblink = true;
|
||||||
|
|
||||||
|
|
||||||
|
float k = 0.1;
|
||||||
|
float expRunningAverage(float newVal) {
|
||||||
|
RTC_DATA_ATTR static float filVal = 0;
|
||||||
|
filVal += (newVal - filVal) * k;
|
||||||
|
return filVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ledset(byte color = 0, bool blink = false)
|
void ledset(byte color = 0, bool blink = false)
|
||||||
{
|
{
|
||||||
M5.dis.setBrightness(30); //Половина яркости
|
M5.dis.setBrightness(30); //Половина яркости
|
||||||
|
@ -620,7 +630,7 @@ int SendMqttReq(bool sendVal = true, bool sendStatus = true, byte statusConn = 1
|
||||||
|
|
||||||
if (sendVal == true)
|
if (sendVal == true)
|
||||||
{
|
{
|
||||||
doc["t"] = TempAv;
|
doc["t"] = expRunningAverage(TempAv);
|
||||||
doc["h"] = HumAv;
|
doc["h"] = HumAv;
|
||||||
doc["eco"] = (int)Eco2Av;
|
doc["eco"] = (int)Eco2Av;
|
||||||
doc["tvoc"] = (int)TvocAv;
|
doc["tvoc"] = (int)TvocAv;
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,253 +0,0 @@
|
||||||
//20.02.2019
|
|
||||||
//by Reptiloid software
|
|
||||||
|
|
||||||
#include "Arduino.h"
|
|
||||||
#include "AC_Dimmer.h"
|
|
||||||
|
|
||||||
#define DIMM_MAX 5
|
|
||||||
#define AC_FREQ 50
|
|
||||||
#define MAX_HEAT_DIV 10
|
|
||||||
|
|
||||||
//======================================
|
|
||||||
|
|
||||||
#define ZERO_VAL 19850
|
|
||||||
#define K 77
|
|
||||||
|
|
||||||
#define SSR 0
|
|
||||||
#define DIMM 1
|
|
||||||
#define HEAT 2
|
|
||||||
|
|
||||||
//=======================================
|
|
||||||
|
|
||||||
struct dimmer
|
|
||||||
{
|
|
||||||
unsigned char flag;
|
|
||||||
unsigned char val;
|
|
||||||
unsigned char pin;
|
|
||||||
unsigned char SSR_state;
|
|
||||||
unsigned char heat_val;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sort
|
|
||||||
{
|
|
||||||
unsigned char val;
|
|
||||||
unsigned char pin;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//==========================================
|
|
||||||
|
|
||||||
volatile unsigned char cnt;
|
|
||||||
volatile unsigned char dims;
|
|
||||||
volatile unsigned char lim;
|
|
||||||
volatile unsigned char not_z;
|
|
||||||
volatile unsigned char heat_cnt = 0;
|
|
||||||
|
|
||||||
dimmer dimmer[DIMM_MAX];
|
|
||||||
sort sort_vals[DIMM_MAX];
|
|
||||||
sort sort[DIMM_MAX*2];
|
|
||||||
|
|
||||||
//===============================================
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Dimmer_init_begin()
|
|
||||||
{
|
|
||||||
TCCR1A=0;
|
|
||||||
TCCR1B=2;
|
|
||||||
TIMSK1=1;
|
|
||||||
|
|
||||||
EICRA=3;
|
|
||||||
EIMSK=1;
|
|
||||||
EIFR=1;
|
|
||||||
|
|
||||||
for(unsigned char i=0; i<DIMM_MAX; i++)
|
|
||||||
{
|
|
||||||
dimmer[i].pin = 0xff;
|
|
||||||
dimmer[i].val = 0;
|
|
||||||
dimmer[i].flag = SSR;
|
|
||||||
dimmer[i].SSR_state = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(unsigned char i=0; i<DIMM_MAX*2; i++)
|
|
||||||
{
|
|
||||||
sort[i].pin = 0xff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Dimmer_pin_assign(unsigned char dim_num, unsigned char dim_pin)
|
|
||||||
{
|
|
||||||
dimmer[dim_num].pin = dim_pin;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Dimmer_init_end()
|
|
||||||
{
|
|
||||||
unsigned char j=0;
|
|
||||||
|
|
||||||
for(unsigned char i=0; i<DIMM_MAX; i++)
|
|
||||||
{
|
|
||||||
if(dimmer[i].pin != 0xff)
|
|
||||||
{
|
|
||||||
sort_vals[j].pin = dimmer[i].pin;
|
|
||||||
j++;
|
|
||||||
pinMode(dimmer[i].pin, OUTPUT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dims = j;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void tim_form()
|
|
||||||
{
|
|
||||||
unsigned char j;
|
|
||||||
|
|
||||||
not_z = 0;
|
|
||||||
for(j = 0; (sort_vals[j].val == 0 && j < dims); j++) not_z++;
|
|
||||||
|
|
||||||
lim = dims - not_z;
|
|
||||||
sort[lim*2-1] = sort_vals[dims-1];
|
|
||||||
|
|
||||||
for(j=0; j<lim-1; j++)
|
|
||||||
{
|
|
||||||
sort[lim*2-2-j].val = sort_vals[dims-1-j].val - sort_vals[dims-j-2].val;
|
|
||||||
sort[lim*2-2-j].pin = sort_vals[dims-j-2].pin;
|
|
||||||
}
|
|
||||||
|
|
||||||
sort[lim-1].val = 255 - sort_vals[dims-1].val + sort_vals[not_z].val;
|
|
||||||
sort[lim-1].pin = sort_vals[dims-1].pin;
|
|
||||||
|
|
||||||
for(j = 0; j<lim-1; j++)
|
|
||||||
{
|
|
||||||
sort[j] = sort[j+lim];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void SSR_switch(unsigned char dim_num, unsigned char state)
|
|
||||||
{
|
|
||||||
Dimm_value(dim_num, 0);
|
|
||||||
|
|
||||||
dimmer[dim_num].flag = SSR;
|
|
||||||
dimmer[dim_num].SSR_state = state;
|
|
||||||
|
|
||||||
if(state == 0) digitalWrite(dimmer[dim_num].pin, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Dimm_value(unsigned char dim_num, unsigned char power)
|
|
||||||
{
|
|
||||||
if(power > 240) power = 240;
|
|
||||||
|
|
||||||
dimmer[dim_num].flag = DIMM;
|
|
||||||
dimmer[dim_num].val = power;
|
|
||||||
unsigned char j;
|
|
||||||
|
|
||||||
for(unsigned char i = 0; i<dims; i++)
|
|
||||||
if(sort_vals[i].pin == dimmer[dim_num].pin)
|
|
||||||
{
|
|
||||||
if(power > sort_vals[i+1].val && i<dims-1)
|
|
||||||
{
|
|
||||||
for(j = 1; ((power > sort_vals[i+j].val) && (i+j<dims)); j++)
|
|
||||||
{
|
|
||||||
sort_vals[i+j-1] = sort_vals[i+j];
|
|
||||||
}
|
|
||||||
|
|
||||||
sort_vals[i+j-1].val = power;
|
|
||||||
sort_vals[i+j-1].pin = dimmer[dim_num].pin;
|
|
||||||
}
|
|
||||||
else if(power < sort_vals[i-1].val && i>0)
|
|
||||||
{
|
|
||||||
for(j = 1; ((power < sort_vals[i-j].val) && (i-j>=0)); j++)
|
|
||||||
{
|
|
||||||
sort_vals[i-j+1] = sort_vals[i-j];
|
|
||||||
}
|
|
||||||
|
|
||||||
sort_vals[i-j+1].val = power;
|
|
||||||
sort_vals[i-j+1].pin = dimmer[dim_num].pin;
|
|
||||||
}
|
|
||||||
else sort_vals[i].val = power;
|
|
||||||
|
|
||||||
i = dims;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Heater(unsigned char dim_num, unsigned char heat_power)
|
|
||||||
{
|
|
||||||
Dimm_value(dim_num, 0);
|
|
||||||
|
|
||||||
dimmer[dim_num].flag = HEAT;
|
|
||||||
dimmer[dim_num].heat_val = heat_power;
|
|
||||||
|
|
||||||
if(heat_power == 0) digitalWrite(dimmer[dim_num].pin, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//======================================================================
|
|
||||||
|
|
||||||
|
|
||||||
ISR(INT0_vect)
|
|
||||||
{
|
|
||||||
if(sort_vals[dims-1].val != 0 && dims > 0)
|
|
||||||
{
|
|
||||||
tim_form();
|
|
||||||
cnt=lim*2-1;
|
|
||||||
TCNT1 = 0xffff - (ZERO_VAL - K*sort[cnt].val);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(unsigned char i = 0; i<DIMM_MAX; i++)
|
|
||||||
{
|
|
||||||
if(dimmer[i].flag != DIMM)
|
|
||||||
{
|
|
||||||
if(dimmer[i].flag == HEAT)
|
|
||||||
{
|
|
||||||
if(dimmer[i].heat_val > heat_cnt) digitalWrite(dimmer[i].pin, 1);
|
|
||||||
else digitalWrite(dimmer[i].pin, 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(dimmer[i].SSR_state > 0) digitalWrite(dimmer[i].pin, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(heat_cnt < MAX_HEAT_DIV-1) heat_cnt++;
|
|
||||||
else heat_cnt = 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ISR(TIMER1_OVF_vect)
|
|
||||||
{
|
|
||||||
if(sort_vals[dims-1].val != 0 && dims > 0)
|
|
||||||
{
|
|
||||||
|
|
||||||
digitalWrite(sort[cnt].pin, 1);
|
|
||||||
delayMicroseconds(30);
|
|
||||||
digitalWrite(sort[cnt].pin, 0);
|
|
||||||
|
|
||||||
while(sort[cnt-1].val == 0)
|
|
||||||
{
|
|
||||||
cnt--;
|
|
||||||
digitalWrite(sort[cnt].pin, 1);
|
|
||||||
delayMicroseconds(30);
|
|
||||||
digitalWrite(sort[cnt].pin, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
cnt--;
|
|
||||||
TCNT1 = 0xffff - K*sort[cnt].val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
//20.02.2019
|
|
||||||
//by Reptiloid software
|
|
||||||
|
|
||||||
/*
|
|
||||||
Îãðàíè÷åíèÿ:
|
|
||||||
- Äëÿ êîíòðîëÿ ôàçû èñïîëüçîâàòü òîëüêî D2
|
|
||||||
- Íå èñïîëüçîâàòü ïèíû D9 è D10 äëÿ ØÈÌ (Analog.Write())
|
|
||||||
òîëüêî öèôðîâîé âûõîä/âõîä digitalWrite()
|
|
||||||
*/
|
|
||||||
|
|
||||||
//====================================================
|
|
||||||
|
|
||||||
#ifndef AC_Dimmer_h
|
|
||||||
#define AC_Dimmer_h
|
|
||||||
|
|
||||||
#include <avr/io.h>
|
|
||||||
#include <avr/interrupt.h>
|
|
||||||
|
|
||||||
#include "Arduino.h"
|
|
||||||
|
|
||||||
//=================================================
|
|
||||||
|
|
||||||
|
|
||||||
void Dimmer_init_begin();
|
|
||||||
void Dimmer_pin_assign(unsigned char dim_num, unsigned char dim_pin);
|
|
||||||
void Dimmer_init_end();
|
|
||||||
void Dimm_value(unsigned char dim_num, unsigned char power);
|
|
||||||
void SSR_switch(unsigned char dim_num, unsigned char state);
|
|
||||||
void Heater(unsigned char dim_num, unsigned char heat_power);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,110 +0,0 @@
|
||||||
//20.02.2019
|
|
||||||
//by Reptiloid software
|
|
||||||
|
|
||||||
/*
|
|
||||||
Ограничения:
|
|
||||||
- Для контроля фазы использовать только D2 (прерывание INT0)
|
|
||||||
(порт M2 диммера подключать к порту D2 АРДУИНО)!!!
|
|
||||||
- Не использовать пины D9 и D10 для ШИМ Analog.Write()!!!
|
|
||||||
только цифровой выход/вход digitalWrite() и digitalRead()
|
|
||||||
|
|
||||||
Функционал:
|
|
||||||
- Данная библиотека позволяет регулировать нагрузку(и),
|
|
||||||
подключенную в промышленную сеть 220В с помощью АУРДУИНО
|
|
||||||
различными встроенными функциями описанными ниже
|
|
||||||
|
|
||||||
Как работать:
|
|
||||||
1) Чтобы начать работу нужно подключить библиотеку AC_Dimmer.h
|
|
||||||
2) Обозначить и раздать номера диммерам (нумерация от 0!!!), используемым в проекте:
|
|
||||||
#define <"имя димера"> <"порядковый номер">
|
|
||||||
|
|
||||||
Например:
|
|
||||||
#include <AC_Dimmer.h>
|
|
||||||
|
|
||||||
#define Dimmer_1 0
|
|
||||||
#define Dimmer_2 1
|
|
||||||
#define Dimmer_3 2
|
|
||||||
|
|
||||||
3) Инициализировать димер(ы) в void setup().
|
|
||||||
- Инициализацию выполнять строго между функций Dimmer_init_begin() и Dimmer_init_end();
|
|
||||||
- Инициализировать с помощью функции Dimmer_pin_assign():
|
|
||||||
Dimmer_pin_assign(<"имя димера">, <"порт(пин) ардуино димера">);
|
|
||||||
|
|
||||||
Например:
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
Dimmer_init_begin();
|
|
||||||
|
|
||||||
Dimmer_pin_assign(Dimmer_1, 3);
|
|
||||||
Dimmer_pin_assign(Dimmer_2, A3);
|
|
||||||
Dimmer_pin_assign(Dimmer_3, A2);
|
|
||||||
|
|
||||||
Dimmer_init_end();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
3) В void loop() использовать нужную функцию:
|
|
||||||
|
|
||||||
- Dimm_value(<"имя димера">, <"значение мощности от 0 до 255">)
|
|
||||||
- Heater(<"имя димера">, <"значение мощности от 0 до 10">)
|
|
||||||
- SSR_switch(<"имя димера">, <значения 1 или 0 (HIGH/LOW)>)
|
|
||||||
|
|
||||||
Например: void loop()
|
|
||||||
{
|
|
||||||
Dimm_value(Dimmer_3, 64); // 25% мощность на диммере№3
|
|
||||||
Heater(Dimmer_2, 3); //30% мощности на диммере№2 (при условии что там ТЕН или другая низкоинерциооная нагрузка)
|
|
||||||
Dimm_value(Dimmer_1, 128); //50% мощности на диммере№1
|
|
||||||
|
|
||||||
delay(1000); //установленные высше параметры удерживаются 1сек
|
|
||||||
|
|
||||||
SSR_switch(Dimmer_3, LOW); // отключим все диммеры на 1сек
|
|
||||||
SSR_switch(Dimmer_2, LOW);
|
|
||||||
SSR_switch(Dimmer_1, LOW);
|
|
||||||
|
|
||||||
delay(1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
Код даного примера предполагает плавное поочередное зажигание и
|
|
||||||
и тушение трех ламп накаливания, подключенных к ардуино каждая через независимый диммер
|
|
||||||
|
|
||||||
Демонстрацию работы библиотеки на тестовом стенде и схему можно посмотреть здесь:
|
|
||||||
https://www.youtube.com/watch?v=9fhkJQIRmEA
|
|
||||||
|
|
||||||
Так же можно использовать для теста одиночного диммера
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include <AC_Dimmer.h>
|
|
||||||
#include <math.h> //если Вы хотите использовать данную библитеку в своем в проекте,
|
|
||||||
//математическая библиотека <math.h> не обязательна к включению
|
|
||||||
|
|
||||||
#define Dimmer_1 0
|
|
||||||
#define Dimmer_2 1
|
|
||||||
#define Dimmer_3 2
|
|
||||||
|
|
||||||
unsigned char i = 0;
|
|
||||||
unsigned char range = 70; // Диапазон регулировки
|
|
||||||
// (255 - максимальное значение)
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
Dimmer_init_begin();
|
|
||||||
|
|
||||||
Dimmer_pin_assign(Dimmer_1, 3);
|
|
||||||
Dimmer_pin_assign(Dimmer_2, A3);
|
|
||||||
Dimmer_pin_assign(Dimmer_3, A2);
|
|
||||||
|
|
||||||
Dimmer_init_end();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
i++;
|
|
||||||
|
|
||||||
Dimm_value(Dimmer_1, range*fabs(sin(i*2*3.14/255)));
|
|
||||||
Dimm_value(Dimmer_2, range*fabs(sin((i+(255/3))*2*3.14/255)));
|
|
||||||
Dimm_value(Dimmer_3, range*fabs(sin((i+(255*2/3))*2*3.14/255)));
|
|
||||||
|
|
||||||
delay(25);
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
//30.03.2019
|
|
||||||
//by Reptiloid software
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
Данный скетч реализует ручную независимую регулировку мощности для каждого диммера
|
|
||||||
с помощью соответствующего потенциометра на аналоговых пинах
|
|
||||||
(рекомендуемы номинал 1-100К)
|
|
||||||
|
|
||||||
Так же можно использовать для теста одиночного диммера
|
|
||||||
|
|
||||||
Подробное описание работы и синтаксиса библиотеки можете
|
|
||||||
посмотреть в примере AC_DIMMER_FADE
|
|
||||||
|
|
||||||
Демонстрацию работы библиотеки на тестовом стенде и схему можно посмотреть здесь:
|
|
||||||
https://www.youtube.com/watch?v=9fhkJQIRmEA
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include <AC_Dimmer.h>
|
|
||||||
|
|
||||||
#define Dimmer_1 0
|
|
||||||
#define Dimmer_2 1
|
|
||||||
#define Dimmer_3 2
|
|
||||||
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
Dimmer_init_begin();
|
|
||||||
|
|
||||||
Dimmer_pin_assign(Dimmer_1, 3);
|
|
||||||
Dimmer_pin_assign(Dimmer_2, A3);
|
|
||||||
Dimmer_pin_assign(Dimmer_3, A2);
|
|
||||||
|
|
||||||
Dimmer_init_end();
|
|
||||||
}
|
|
||||||
|
|
||||||
int adc_read;
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
adc_read = analogRead(A4)/4;
|
|
||||||
Dimm_value(Dimmer_1, adc_read); // потенциометры на пинах А4, А5, А6
|
|
||||||
adc_read = analogRead(A5)/4;
|
|
||||||
Dimm_value(Dimmer_2, adc_read); // для ручной регулировки мощности
|
|
||||||
adc_read = analogRead(A6)/4;
|
|
||||||
Dimm_value(Dimmer_3, adc_read); // на каждый диммер
|
|
||||||
|
|
||||||
delay(50);
|
|
||||||
}
|
|
|
@ -1,78 +0,0 @@
|
||||||
/*
|
|
||||||
Данный скетч позволяет запустить димер в режиме FADE для платы ESP8266
|
|
||||||
- 2сек диммер плавно увеличивает мощность
|
|
||||||
- 2сек диммер плавно уменьшает мощность
|
|
||||||
|
|
||||||
Для того чтобы успешно прошить даный скетч Вам нужно:
|
|
||||||
- скачать дистрибутив для работу с ESP8266 в Arduino IDE
|
|
||||||
- скачать библиоеки Ticker.h
|
|
||||||
- подключить димер на соответствующие пины или назначить свои
|
|
||||||
|
|
||||||
При работе с ESP8266 подключать библиотеку AC_Dimmer и использовать ее функции не нужно
|
|
||||||
Достаточно прошить лишь данный пример
|
|
||||||
Для управления можностью используется переменная val (смотрите ниже)
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ESP8266WiFi.h>
|
|
||||||
#include <Ticker.h>
|
|
||||||
|
|
||||||
Ticker blinker;
|
|
||||||
|
|
||||||
const byte interruptPin = D7; // пин диммера М2
|
|
||||||
const byte dimPin = D5; // пин диммера М1
|
|
||||||
int val = 0; // переменная, которая определяет мощность от 0 до 10000
|
|
||||||
|
|
||||||
int power = 0;
|
|
||||||
int rise = 0;
|
|
||||||
|
|
||||||
void ICACHE_RAM_ATTR handleInterrupt();
|
|
||||||
|
|
||||||
void ICACHE_RAM_ATTR onTimerISR() // обработчик прерывания таймера
|
|
||||||
{
|
|
||||||
digitalWrite(dimPin, HIGH);
|
|
||||||
delayMicroseconds(40);
|
|
||||||
digitalWrite(dimPin, LOW);
|
|
||||||
|
|
||||||
timer1_write(50000);//10мс
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void handleInterrupt() // обработчик прерывания по фронту (от пина детекции фазы димера)
|
|
||||||
{
|
|
||||||
power = 49000 - 4.785*val;
|
|
||||||
timer1_write(power);
|
|
||||||
|
|
||||||
if(val < 10000 && rise == 1) val = val + 100; // плавное наростание
|
|
||||||
else rise = 0;
|
|
||||||
|
|
||||||
if(val > 0 && rise == 0) val = val - 100; // плавное угасание
|
|
||||||
else rise = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
|
|
||||||
pinMode(interruptPin, INPUT_PULLUP);
|
|
||||||
pinMode(dimPin, OUTPUT);
|
|
||||||
|
|
||||||
attachInterrupt(digitalPinToInterrupt(interruptPin), handleInterrupt, RISING);
|
|
||||||
|
|
||||||
timer1_attachInterrupt(onTimerISR);
|
|
||||||
timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE);
|
|
||||||
|
|
||||||
// здесь можно писать свой код (setup())
|
|
||||||
//
|
|
||||||
// здесь можно писать свой код (setup())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
// здесь можно писать свой код
|
|
||||||
//
|
|
||||||
// здесь можно писать свой код
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,99 +0,0 @@
|
||||||
/*
|
|
||||||
|
|
||||||
Даный скетч позволяет управлять сетевым диммером DMR-02 через WiFi
|
|
||||||
с помощью ESP8266 и смартфона с любой точки планеты, где есть доступ в интернет
|
|
||||||
|
|
||||||
Скетч позволит управлять нагрузкой (лампой) с помощью ползунка на Вашем смартфоне по WiFi
|
|
||||||
|
|
||||||
Код работает в неблокирующем режиме (можно добавлять свой код)
|
|
||||||
|
|
||||||
Управление со смартфона будет происходить с помощью программы Blynk (Play market/APP store)
|
|
||||||
Перед началом работы рекомендуется разобраться с функионалом данного софта
|
|
||||||
|
|
||||||
пример работы (ВИДЕО)
|
|
||||||
https://www.youtube.com/watch?v=Z_Vvgx4QuSY
|
|
||||||
|
|
||||||
Для того чтобы успешно прошить даный скетч Вам нужно:
|
|
||||||
- скачать дистрибутив для работу с ESP8266 в Arduino IDE
|
|
||||||
- скачать библиоеки Blynk и Ticker.h
|
|
||||||
- скачать приложение Blynk на смартфон
|
|
||||||
- создать проект в приложении Blynk для управления димером
|
|
||||||
- получить на почту Ваш ЛИЧНЫЙ токен с приложения Blynk и вписать его ниже
|
|
||||||
- вписать имя и пароль WiFi для подключения ESP8266 (смотрите ниже)
|
|
||||||
- подключить димер на соответствующие пины или назначить свои
|
|
||||||
|
|
||||||
При работе с ESP8266 подключать библиотеку AC_Dimmer и использовать ее функции не нужно
|
|
||||||
Достаточно прошить лишь данный пример
|
|
||||||
Для управления можностью используется переменная val (смотрите ниже)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ESP8266WiFi.h>
|
|
||||||
#include <Ticker.h>
|
|
||||||
#include <BlynkSimpleEsp8266.h>
|
|
||||||
|
|
||||||
Ticker blinker;
|
|
||||||
|
|
||||||
const byte interruptPin = D7; // пин диммера М2
|
|
||||||
const byte dimPin = D5; // пин диммера М1
|
|
||||||
|
|
||||||
int power = 0;
|
|
||||||
int val = 0; // переменная задающая мощность от 0 до 10000
|
|
||||||
|
|
||||||
char auth[] = "7wE5GzzU2zs83pOZKSbMxfEu_G53y4V6"; // Ваш ЛИЧНЫЙ токен от приложения Blynk
|
|
||||||
char ssid[] = "AndroidAP"; // имя WiFi
|
|
||||||
char pass[] = "23412123"; // пароль WiFi
|
|
||||||
|
|
||||||
void ICACHE_RAM_ATTR handleInterrupt();
|
|
||||||
|
|
||||||
void ICACHE_RAM_ATTR onTimerISR() // обработчик прерывания таймера
|
|
||||||
{
|
|
||||||
digitalWrite(dimPin, HIGH);
|
|
||||||
delayMicroseconds(40);
|
|
||||||
digitalWrite(dimPin, LOW);
|
|
||||||
|
|
||||||
timer1_write(50000);//10мс
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void handleInterrupt() // обработчик прерывания по фронту (от пина детекции фазы димера)
|
|
||||||
{
|
|
||||||
power = 49000 - 4.75*val;
|
|
||||||
timer1_write(power);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
Serial.begin(9600);
|
|
||||||
Blynk.begin(auth, ssid, pass);
|
|
||||||
|
|
||||||
pinMode(interruptPin, INPUT_PULLUP);
|
|
||||||
pinMode(dimPin, OUTPUT);
|
|
||||||
|
|
||||||
attachInterrupt(digitalPinToInterrupt(interruptPin), handleInterrupt, RISING);
|
|
||||||
|
|
||||||
timer1_attachInterrupt(onTimerISR);
|
|
||||||
timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE);
|
|
||||||
|
|
||||||
// здесь можно писать свой код (setup())
|
|
||||||
//
|
|
||||||
// здесь можно писать свой код (setup())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
|
|
||||||
Blynk.run(); // функция поллинга данных по WiFi
|
|
||||||
|
|
||||||
// здесь можно писать свой код
|
|
||||||
//
|
|
||||||
// здесь можно писать свой код
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BLYNK_WRITE(V0) // функция считывания данных по WiFi
|
|
||||||
{
|
|
||||||
val = param.asInt();
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
#include <AC_Dimmer.h> KEYWORD1
|
|
||||||
Dimmer_pin_assign KEYWORD1
|
|
||||||
Dimmer_init_end KEYWORD1
|
|
||||||
Dimmer_init_begin KEYWORD1
|
|
||||||
Heater KEYWORD2
|
|
||||||
Dimm_value KEYWORD2
|
|
||||||
SSR_switch KEYWORD2
|
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -1,28 +0,0 @@
|
||||||
# AC_dimmer-dmr-0.2.1
|
|
||||||
|
|
||||||
Последняя версия библиотеки на сетевой диммер dmr-0.2.x
|
|
||||||
|
|
||||||
Пример работы (Demo-video): https://www.youtube.com/watch?v=9fhkJQIRmEA
|
|
||||||
|
|
||||||
Пример работы c ESP8266 (управление диммером через Wifi с помощью смартфона) (Demo-video): https://www.youtube.com/watch?v=Z_Vvgx4QuSY
|
|
||||||
|
|
||||||
- Работа в трех режимах:
|
|
||||||
- режим трердотелого реле (вкл/выкл с учетом фазы)
|
|
||||||
- фазовая регулировка (классический режим)
|
|
||||||
- полуволновый режим (для повышеных мощностей для мощных нагревателей)
|
|
||||||
|
|
||||||
- позволяет параллельную работу нескольких димеров на одной плате Ардуино
|
|
||||||
|
|
||||||
- Добавлен пример работы с ESP8266 по Wifi
|
|
||||||
|
|
||||||
Библиотека Ардуино: [AC_Dimmer.zip](https://github.com/serhiy23412/AC_dimmer-dmr-0.2.1/blob/master/AC_Dimmer.zip)
|
|
||||||
|
|
||||||
Простой пример на Raspberry Pi (by Andy): [Raspberry Pi example.txt](https://github.com/serhiy23412/AC_dimmer-dmr-0.2.1/blob/master/Raspberry_Pi_example.txt)
|
|
||||||
|
|
||||||
Более детальная информация: [AC_Dimmer_Docum.docx](https://github.com/serhiy23412/AC_dimmer-dmr-0.2.1/blob/master/AC_Dimmer_Docum.docx)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
import RPi.GPIO as GPIO
|
|
||||||
import time
|
|
||||||
import math
|
|
||||||
|
|
||||||
PHASE_DFREQ = 100
|
|
||||||
DRIVER_MIN = 0.3
|
|
||||||
DRIVER_MAX = 0.95
|
|
||||||
|
|
||||||
power = DRIVER_MIN
|
|
||||||
|
|
||||||
def phase_callback(channel):
|
|
||||||
global power
|
|
||||||
if power < DRIVER_MIN:
|
|
||||||
power = DRIVER_MIN
|
|
||||||
if power > DRIVER_MAX:
|
|
||||||
power = DRIVER_MAX
|
|
||||||
|
|
||||||
time.sleep(math.acos(2.0 * power - 1.0) / (math.pi * PHASE_DFREQ))
|
|
||||||
GPIO.output(23, GPIO.HIGH)
|
|
||||||
time.sleep(0.00003)
|
|
||||||
GPIO.output(23, GPIO.LOW)
|
|
||||||
|
|
||||||
GPIO.setmode(GPIO.BCM)
|
|
||||||
GPIO.setwarnings(False)
|
|
||||||
|
|
||||||
GPIO.setup(23, GPIO.OUT) # dimmer control
|
|
||||||
GPIO.setup(24, GPIO.IN) # phase control
|
|
||||||
|
|
||||||
GPIO.add_event_detect(24, GPIO.BOTH, callback=phase_callback, bouncetime=9)
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
|
||||||
print(power)
|
|
||||||
time.sleep(15)
|
|
||||||
|
|
||||||
while True:
|
|
||||||
power += 0.05
|
|
||||||
print(power)
|
|
||||||
time.sleep(10)
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
pass
|
|
||||||
|
|
||||||
finally:
|
|
||||||
GPIO.remove_event_detect(24)
|
|
||||||
GPIO.cleanup()
|
|
Binary file not shown.
BIN
anemostat/P1.stl
BIN
anemostat/P1.stl
Binary file not shown.
BIN
anemostat/P2.stl
BIN
anemostat/P2.stl
Binary file not shown.
Binary file not shown.
|
@ -1,5 +0,0 @@
|
||||||
[.ShellClassInfo]
|
|
||||||
InfoTip=Ê ýòîé ïàïêå îòêðûò ñîâìåñòíûé äîñòóï â Èíòåðíåòå.
|
|
||||||
IconFile=C:\Program Files\Google\Drive\googledrivesync.exe
|
|
||||||
IconIndex=16
|
|
||||||
|
|
Binary file not shown.
BIN
scd30mh/19.bin
BIN
scd30mh/19.bin
Binary file not shown.
BIN
scd30mh/CO2.bin
BIN
scd30mh/CO2.bin
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,743 +0,0 @@
|
||||||
/*
|
|
||||||
Отправка данных на MQTT про обновление
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <WiFiManager.h> // https://github.com/tzapu/WiFiManager
|
|
||||||
#include <Preferences.h> //Сохранение настроек хеша прошивки
|
|
||||||
|
|
||||||
#include <HTTPClient.h>
|
|
||||||
#include <ESP32httpUpdate.h> //Библиотека ОТА обновлений
|
|
||||||
#include "M5Atom.h" //Библиотека атома для функции Led и Кнопки, можно упразднить и убрать
|
|
||||||
|
|
||||||
#include <WiFiUdp.h> //Udp клиент
|
|
||||||
#include <NTPClient.h> //NTP запрос времени
|
|
||||||
#include <TimeLib.h> //Внутреннее время
|
|
||||||
#include <Wire.h> //Библиотека дял I2C
|
|
||||||
|
|
||||||
#include <PubSubClient.h> //Mtqq
|
|
||||||
#include <ArduinoJson.h> //Упакова в JSon - удобная библиотека
|
|
||||||
#include <ESPmDNS.h>
|
|
||||||
|
|
||||||
#include "MHZ19.h"
|
|
||||||
#include <SoftwareSerial.h>
|
|
||||||
#include "SparkFun_SCD30_Arduino_Library.h" //Click here to get the library: http://librarymanager/All#SparkFun_SCD30
|
|
||||||
|
|
||||||
#include <Adafruit_GFX.h>
|
|
||||||
#include <Adafruit_SSD1306.h>
|
|
||||||
|
|
||||||
#define SCREEN_WIDTH 128 // OLED display width, in pixels
|
|
||||||
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
|
|
||||||
#define OLED_RESET 4
|
|
||||||
|
|
||||||
//Наша кнопочка при нажатии на которую произойдет вызов wifi менеджера и перезагрузка в станцию
|
|
||||||
#define TRIGGER_PIN 39
|
|
||||||
|
|
||||||
#define RX_PIN 19
|
|
||||||
#define TX_PIN 22
|
|
||||||
#define BAUDRATE 9600
|
|
||||||
|
|
||||||
#define i2cSDA 25
|
|
||||||
#define i2cSCL 21
|
|
||||||
|
|
||||||
MHZ19 myMHZ19;
|
|
||||||
SoftwareSerial mySerial(RX_PIN, TX_PIN);
|
|
||||||
|
|
||||||
unsigned int VersionSW = 20;
|
|
||||||
|
|
||||||
//17 - локальный брокер
|
|
||||||
//19 - какие то траблы в офисе
|
|
||||||
//20 - Ручное удаление
|
|
||||||
|
|
||||||
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
|
|
||||||
|
|
||||||
WiFiManager wm; // обьект менеджера
|
|
||||||
Preferences OTApreferences; //Обьект хранения настроек хеша прошивки
|
|
||||||
|
|
||||||
String JsonData;
|
|
||||||
StaticJsonDocument<200> doc;
|
|
||||||
SCD30 airSens30;
|
|
||||||
|
|
||||||
WiFiClient espClient;
|
|
||||||
PubSubClient MqttClient(espClient);
|
|
||||||
IPAddress IpMqtt;
|
|
||||||
|
|
||||||
WiFiUDP ntpUDP;
|
|
||||||
NTPClient timeClient(ntpUDP, "192.168.89.210", 0, 20000); //Собственно сервер времени смещение и частоат запроса, но он вручную
|
|
||||||
const PROGMEM char *willmess = "{\"conn\":\"err\"}";
|
|
||||||
const char *mqttHostName = "metrics"; //Хостнейм брокера metrics.local cctv.automation.art //192.168.89.210
|
|
||||||
unsigned int mqttPort = 1883; //Порт брокера 1883 8889
|
|
||||||
|
|
||||||
String getMacAddress();
|
|
||||||
String macc = getMacAddress();
|
|
||||||
String topicTemp = "aastudio/sens/" + macc + "/data/0";
|
|
||||||
String willTopicTemp = "aastudio/sens/" + macc + "/status";
|
|
||||||
const PROGMEM char *mqttLogin = "AA_Lab", *mqttPass = "automation.art$";
|
|
||||||
|
|
||||||
const char *mqttIPHost; //тут хранится IP хоста по хостнейму
|
|
||||||
unsigned long timingUpdate=0, timingReqSensor=0, timingSendMqtt=0; //Таймеры для millis()
|
|
||||||
int PROGMEM nextM5Update = 450000, nextMqttSend = 60000; //каждые 7.5 минут запрос обновления с сервера
|
|
||||||
//Отправка
|
|
||||||
bool typeSensor = false, GlobalOled = false;
|
|
||||||
bool mqttSendFlag = false;
|
|
||||||
bool safetyStateNow = false, safetyStateOld = false;
|
|
||||||
int reqCounter = 0;
|
|
||||||
long rssi = 0;
|
|
||||||
int GlobalCo2 = 0;
|
|
||||||
char bufTopic[140], bufWillTopic[150], bufAngleTopic[150];
|
|
||||||
|
|
||||||
void ledset(byte color = 0)
|
|
||||||
{
|
|
||||||
M5.dis.setBrightness(60); //Половина яркости
|
|
||||||
switch (color)
|
|
||||||
{
|
|
||||||
case 2:
|
|
||||||
M5.dis.drawpix(0, 0xf00000); //Зеленый
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
M5.dis.drawpix(0, 0x00ff00); //Красный
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
M5.dis.drawpix(0, 0x0000ff); //Синий
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
M5.dis.drawpix(0, 0xffffff); //Белый
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
M5.dis.drawpix(0, 0xffec00); //желтый
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
M5.dis.clear();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Настройки
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
Serial.begin(115200);
|
|
||||||
Serial.setDebugOutput(true);
|
|
||||||
M5.begin(true, false, true);
|
|
||||||
Wire.begin(32, 26);
|
|
||||||
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C))
|
|
||||||
{ // Address 0x3D for 128x64
|
|
||||||
GlobalOled = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GlobalOled = true;
|
|
||||||
display.display();
|
|
||||||
display.clearDisplay();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1й - Просто датчик scd30
|
|
||||||
// 2й - Датчик золотой MH-z19
|
|
||||||
if (macc == "94B97EAD9EDC" || macc == "94B97E8ADF7C")
|
|
||||||
{
|
|
||||||
typeSensor = true;
|
|
||||||
}
|
|
||||||
else if (macc == "24A160542E48" || macc == "94B97E8ADF80")
|
|
||||||
{
|
|
||||||
typeSensor = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeSensor == true)
|
|
||||||
{
|
|
||||||
|
|
||||||
Wire.begin(i2cSDA, i2cSCL);
|
|
||||||
|
|
||||||
if (airSens30.begin() == false)
|
|
||||||
{
|
|
||||||
Serial.println("Air sensor not detected. Please check wiring. Freezing...");
|
|
||||||
}
|
|
||||||
|
|
||||||
airSens30.setMeasurementInterval(10); //Change number of seconds between measurements: 2 to 1800 (30 minutes)
|
|
||||||
airSens30.setAltitudeCompensation(324); //Set altitude of the sensor in m
|
|
||||||
// airSens30.setAmbientPressure(835); //Current ambient pressure in mBar: 700 to 1200
|
|
||||||
float offset = airSens30.getTemperatureOffset();
|
|
||||||
Serial.print("Current temp offset: ");
|
|
||||||
Serial.print(offset, 2);
|
|
||||||
Serial.println("C");
|
|
||||||
//airSens30.setTemperatureOffset(5);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mySerial.begin(BAUDRATE);
|
|
||||||
myMHZ19.begin(mySerial);
|
|
||||||
myMHZ19.autoCalibration(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
delay(50);
|
|
||||||
pinMode(TRIGGER_PIN, INPUT);
|
|
||||||
|
|
||||||
WiFi.mode(WIFI_STA);
|
|
||||||
|
|
||||||
delay(100);
|
|
||||||
|
|
||||||
Serial.println(topicTemp);
|
|
||||||
Serial.println(willTopicTemp);
|
|
||||||
|
|
||||||
topicTemp.toCharArray(bufTopic, topicTemp.length() + 1);
|
|
||||||
willTopicTemp.toCharArray(bufWillTopic, willTopicTemp.length() + 1);
|
|
||||||
|
|
||||||
// wm.resetSettings(); // wipe settings
|
|
||||||
|
|
||||||
std::vector<const char *> menu = {"wifi", "info", "param", "sep", "restart", "exit"};
|
|
||||||
wm.setMenu(menu);
|
|
||||||
// set dark theme
|
|
||||||
wm.setClass("invert");
|
|
||||||
//set static ip
|
|
||||||
// wm.setSTAStaticIPConfig(IPAddress(10,0,1,99), IPAddress(10,0,1,1), IPAddress(255,255,255,0)); // set static ip,gw,sn
|
|
||||||
// wm.setShowStaticFields(true); // force show static ip fields
|
|
||||||
// wm.setShowDnsFields(true); // force show dns field always
|
|
||||||
// wm.setConnectTimeout(20); // how long to try to connect for before continuing
|
|
||||||
wm.setConfigPortalTimeout(30); // auto close configportal after n seconds
|
|
||||||
wm.setMinimumSignalQuality(10); // set min RSSI (percentage) to show in scans, null = 8%
|
|
||||||
wm.setScanDispPerc(true); // show RSSI as percentage not graph icons
|
|
||||||
wm.setWiFiAutoReconnect(true); // if true, enable autoreconnecting
|
|
||||||
|
|
||||||
bool res;
|
|
||||||
|
|
||||||
res = wm.autoConnect("Co2M5Portal", "12345678"); // Подключение к анонимной точке доступа
|
|
||||||
if (!res)
|
|
||||||
{
|
|
||||||
Serial.println("Failed to connect or hit timeout");
|
|
||||||
ESP.restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
setMqttServer(mqttHostName, mqttPort);
|
|
||||||
|
|
||||||
if (reqNtpTime() == 1)
|
|
||||||
{
|
|
||||||
reqNtpTime();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IPAddress str2IP(String str)
|
|
||||||
{
|
|
||||||
IPAddress ret(getIpBlock(0, str), getIpBlock(1, str), getIpBlock(2, str), getIpBlock(3, str));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getIpBlock(int index, String str)
|
|
||||||
{
|
|
||||||
char separator = '.';
|
|
||||||
int found = 0;
|
|
||||||
int strIndex[] = {0, -1};
|
|
||||||
int maxIndex = str.length() - 1;
|
|
||||||
|
|
||||||
for (int i = 0; i <= maxIndex && found <= index; i++)
|
|
||||||
{
|
|
||||||
if (str.charAt(i) == separator || i == maxIndex)
|
|
||||||
{
|
|
||||||
found++;
|
|
||||||
strIndex[0] = strIndex[1] + 1;
|
|
||||||
strIndex[1] = (i == maxIndex) ? i + 1 : i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return found > index ? str.substring(strIndex[0], strIndex[1]).toInt() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int setMqttServer(const char *mqttHostNameF, unsigned int mqttPortF)
|
|
||||||
{
|
|
||||||
mdns_init();
|
|
||||||
|
|
||||||
IPAddress ipaddr;
|
|
||||||
OTApreferences.begin("ota-config");
|
|
||||||
|
|
||||||
OTApreferences.putString("mqttip", "0");
|
|
||||||
delay(1000);
|
|
||||||
String keyIpMqtt = OTApreferences.getString("mqttip", "0");
|
|
||||||
Serial.print("keyIpMqtt: ");
|
|
||||||
Serial.println(keyIpMqtt);
|
|
||||||
|
|
||||||
if (keyIpMqtt == "0")
|
|
||||||
{
|
|
||||||
//Запрос по хостнейму .local
|
|
||||||
ipaddr = MDNS.queryHost(mqttHostNameF, 4000);
|
|
||||||
//Таймаут 4 секунды
|
|
||||||
//Если не получили по хостнейму МДНС
|
|
||||||
Serial.print("mdns: ");
|
|
||||||
Serial.println(ipaddr);
|
|
||||||
|
|
||||||
if (ipaddr.toString() == "0.0.0.0")
|
|
||||||
{
|
|
||||||
//Запрос к ДНС по адресу сайта
|
|
||||||
int err = WiFi.hostByName(mqttHostNameF, ipaddr);
|
|
||||||
////real internal timeout in lwip library is 14[s]
|
|
||||||
//Если получили по хостнейму
|
|
||||||
if (err == 1)
|
|
||||||
{
|
|
||||||
Serial.print("hostByName: ");
|
|
||||||
Serial.println(ipaddr);
|
|
||||||
MqttClient.setServer(ipaddr, mqttPortF);
|
|
||||||
OTApreferences.putString("mqttip", ipaddr.toString());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Serial.print("All method not FOUND IP");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ //Если все хорошо
|
|
||||||
OTApreferences.putString("mqttip", ipaddr.toString());
|
|
||||||
MqttClient.setServer(ipaddr, mqttPortF);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MqttClient.setServer(str2IP(keyIpMqtt), mqttPortF);
|
|
||||||
}
|
|
||||||
|
|
||||||
OTApreferences.end();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setServCall(IPAddress SetIpaddr)
|
|
||||||
{
|
|
||||||
MqttClient.setServer(SetIpaddr, mqttPort);
|
|
||||||
// MqttClient.setCallback(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Функция получения данных из MQTT если мы подпишемся на топики
|
|
||||||
// void callback(char *topic, byte *payload, unsigned int length)
|
|
||||||
// {
|
|
||||||
// //Serial.print("Message arrived [");
|
|
||||||
// //Serial.print(topic);
|
|
||||||
// //Serial.print("] ");
|
|
||||||
// for (int i = 0; i < length; i++)
|
|
||||||
// {
|
|
||||||
// //Serial.print((char)payload[i]);
|
|
||||||
// }
|
|
||||||
// //Serial.println();
|
|
||||||
// }
|
|
||||||
|
|
||||||
//Запрос времени NTP и установка локлаьного времени
|
|
||||||
int reqNtpTime()
|
|
||||||
{
|
|
||||||
if (timeClient.update())
|
|
||||||
{
|
|
||||||
uint32_t timeEpoch = timeClient.getEpochTime();
|
|
||||||
if (timeEpoch < 1600000000)
|
|
||||||
{
|
|
||||||
Serial.println("Error reqNtpTime() Time");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
setTime(timeEpoch);
|
|
||||||
// Serial.print(timeEpoch);
|
|
||||||
// Serial.print(" <=ntp== ==device=> ");
|
|
||||||
// Serial.println(now());
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Нажатие кнопки для сброса
|
|
||||||
void checkButton()
|
|
||||||
{
|
|
||||||
Serial.println("Button RESET Pressed");
|
|
||||||
disconnectMQTT();
|
|
||||||
delay(100);
|
|
||||||
wm.resetSettings();
|
|
||||||
|
|
||||||
OTApreferences.begin("ota-config");
|
|
||||||
OTApreferences.putString("mqttip", "0");
|
|
||||||
OTApreferences.end();
|
|
||||||
|
|
||||||
ESP.restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Обновление прошивки, происходит проверка и загрузка
|
|
||||||
//Делается Get запрос на хостинг проверяется хеш, если хеш
|
|
||||||
void OTAUpdate()
|
|
||||||
{
|
|
||||||
////Serial.\println("OTAUpdate()");
|
|
||||||
bool flagOTA = false;
|
|
||||||
String keyOTA;
|
|
||||||
String payload;
|
|
||||||
OTApreferences.begin("ota-config");
|
|
||||||
if (WiFi.status() == WL_CONNECTED)
|
|
||||||
{
|
|
||||||
|
|
||||||
HTTPClient http;
|
|
||||||
String serverPath = "http://meteosence.s-host.net/airqa/airquality.php?meteopas=
|
|
||||||
&mac=" + macc + "&meteodata=gethash";
|
|
||||||
|
|
||||||
http.begin(serverPath.c_str());
|
|
||||||
int httpResponseCode = http.GET();
|
|
||||||
|
|
||||||
if (httpResponseCode > 0)
|
|
||||||
{
|
|
||||||
Serial.print("HTTP Response code: ");
|
|
||||||
Serial.println(httpResponseCode);
|
|
||||||
payload = http.getString();
|
|
||||||
Serial.println(payload);
|
|
||||||
|
|
||||||
if (payload != "errno" || payload != "errfi")
|
|
||||||
{
|
|
||||||
|
|
||||||
keyOTA = OTApreferences.getString("md5HashOTA");
|
|
||||||
|
|
||||||
if (keyOTA.length() <= 0)
|
|
||||||
{
|
|
||||||
OTApreferences.putString("md5HashOTA", "undifined");
|
|
||||||
}
|
|
||||||
|
|
||||||
keyOTA = OTApreferences.getString("md5HashOTA");
|
|
||||||
|
|
||||||
if (payload != keyOTA)
|
|
||||||
{
|
|
||||||
flagOTA = true;
|
|
||||||
OTApreferences.putString("md5HashOTA", payload);
|
|
||||||
//Serial.println("flagOTA = true;");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
Serial.print("Error code HTTP: ");
|
|
||||||
Serial.println(httpResponseCode);
|
|
||||||
}
|
|
||||||
// Free resources
|
|
||||||
http.end();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
|
|
||||||
Serial.println("WiFi Disconnected");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flagOTA == true)
|
|
||||||
{
|
|
||||||
flagOTA = false;
|
|
||||||
//Serial.println("flagOTA = false;");
|
|
||||||
|
|
||||||
t_httpUpdate_return ret = ESPhttpUpdate.update("http://meteosence.s-host.net/airqa/co2/co2.bin");
|
|
||||||
|
|
||||||
//После update ничего не происходит, такая вот особенность.
|
|
||||||
//Если все прошло хорошо, перезагрузка на новую прошивку
|
|
||||||
|
|
||||||
//Serial.print("ret ");
|
|
||||||
//Serial.println(ret);
|
|
||||||
|
|
||||||
switch (ret)
|
|
||||||
{
|
|
||||||
|
|
||||||
case HTTP_UPDATE_FAILED:
|
|
||||||
//Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
|
|
||||||
//Serial.println(ESPhttpUpdate.getLastError());
|
|
||||||
//Serial.println(ESPhttpUpdate.getLastErrorString().c_str());
|
|
||||||
//Serial.println("HTTP_UPDATE_FAILD Error");
|
|
||||||
|
|
||||||
ESP.restart();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HTTP_UPDATE_NO_UPDATES:
|
|
||||||
//Serial.println("HTTP_UPDATE_NO_UPDATES");
|
|
||||||
|
|
||||||
ESP.restart();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HTTP_UPDATE_OK:
|
|
||||||
//Serial.println("HTTP_UPDATE_OK");
|
|
||||||
|
|
||||||
ESP.restart();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OTApreferences.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Получение мак адреса
|
|
||||||
String getMacAddress()
|
|
||||||
{
|
|
||||||
uint8_t baseMac[6];
|
|
||||||
esp_read_mac(baseMac, ESP_MAC_WIFI_STA);
|
|
||||||
char baseMacChr[18] = {0};
|
|
||||||
sprintf(baseMacChr, "%02X%02X%02X%02X%02X%02X", baseMac[0], baseMac[1], baseMac[2], baseMac[3], baseMac[4], baseMac[5]);
|
|
||||||
return String(baseMacChr);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Отправка данных по MQTT
|
|
||||||
int SendMqttReq(bool sendVal = true, bool sendStatus = true, byte statusConn = 1)
|
|
||||||
{
|
|
||||||
if (mqttSendFlag == true)
|
|
||||||
{
|
|
||||||
|
|
||||||
char resultString[200];
|
|
||||||
String JsonData = "";
|
|
||||||
rssi = WiFi.RSSI();
|
|
||||||
unsigned long timeNow = now();
|
|
||||||
|
|
||||||
// {
|
|
||||||
// "val": 1,
|
|
||||||
// "ts": 1617194420
|
|
||||||
// }
|
|
||||||
// Last device status (ts=59s ago):
|
|
||||||
// {
|
|
||||||
// "conn": "on",
|
|
||||||
// "ts": 1617204271,
|
|
||||||
// "exp": 1617204871
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (sendVal == true)
|
|
||||||
{
|
|
||||||
if (typeSensor == true)
|
|
||||||
{
|
|
||||||
doc["t"] = airSens30.getTemperature();
|
|
||||||
doc["h"] = airSens30.getHumidity();
|
|
||||||
GlobalCo2 = airSens30.getCO2();
|
|
||||||
doc["co2"] = GlobalCo2;
|
|
||||||
|
|
||||||
doc["ts"] = timeNow;
|
|
||||||
|
|
||||||
serializeJson(doc, JsonData);
|
|
||||||
|
|
||||||
doc.remove("ts");
|
|
||||||
doc.remove("t");
|
|
||||||
doc.remove("h");
|
|
||||||
doc.remove("co2");
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
|
|
||||||
int CO2 = 0;
|
|
||||||
int8_t Tempz19 = 0;
|
|
||||||
/* note: getCO2() default is command "CO2 Unlimited". This returns the correct CO2 reading even
|
|
||||||
if below background CO2 levels or above range (useful to validate sensor). You can use the
|
|
||||||
usual documented command with getCO2(false) */
|
|
||||||
|
|
||||||
CO2 = myMHZ19.getCO2(); // Request CO2 (as ppm)
|
|
||||||
GlobalCo2 = CO2;
|
|
||||||
Serial.print("CO2 (ppm): ");
|
|
||||||
Serial.println(CO2);
|
|
||||||
Tempz19 = myMHZ19.getTemperature(); // Request Temperature (as Celsius)
|
|
||||||
Serial.print("Temperature (C): ");
|
|
||||||
Serial.println(Tempz19);
|
|
||||||
|
|
||||||
doc["t"] = Tempz19;
|
|
||||||
doc["co2"] = CO2;
|
|
||||||
doc["ts"] = timeNow;
|
|
||||||
|
|
||||||
serializeJson(doc, JsonData);
|
|
||||||
|
|
||||||
doc.remove("ts");
|
|
||||||
doc.remove("t");
|
|
||||||
doc.remove("co2");
|
|
||||||
}
|
|
||||||
|
|
||||||
doc.clear();
|
|
||||||
doc.garbageCollect();
|
|
||||||
|
|
||||||
Serial.println(JsonData); //Вывод JSON строки в консоль
|
|
||||||
JsonData.toCharArray(resultString, JsonData.length() + 1);
|
|
||||||
MqttClient.publish(bufTopic, resultString, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sendStatus == true)
|
|
||||||
{
|
|
||||||
const char *conn;
|
|
||||||
switch (statusConn)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
conn = "on";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
conn = "off";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
conn = "slp";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 4:
|
|
||||||
conn = "upd";
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
doc["conn"] = conn;
|
|
||||||
doc["rssi"] = rssi;
|
|
||||||
doc["bsid"] = WiFi.BSSIDstr();
|
|
||||||
doc["ts"] = timeNow;
|
|
||||||
doc["exp"] = timeNow + 600;
|
|
||||||
doc["sv"] = VersionSW;
|
|
||||||
|
|
||||||
JsonData = "";
|
|
||||||
serializeJson(doc, JsonData);
|
|
||||||
Serial.println(JsonData); //Вывод JSON строки в консоль
|
|
||||||
|
|
||||||
doc.clear();
|
|
||||||
doc.garbageCollect();
|
|
||||||
|
|
||||||
JsonData.toCharArray(resultString, JsonData.length() + 1);
|
|
||||||
MqttClient.publish(bufWillTopic, resultString, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Переподключение при петери связи с MQTT
|
|
||||||
//7 раз проверили и вернулись в общий цикл что бы вдруг что втянуть обновления
|
|
||||||
void reconnectMqtt()
|
|
||||||
{
|
|
||||||
byte circle = 0;
|
|
||||||
while (!MqttClient.connected())
|
|
||||||
{
|
|
||||||
circle++;
|
|
||||||
if (circle == 5)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
String maccrandom = macc + String(random(0xffff), HEX);
|
|
||||||
const char *clientId = maccrandom.c_str();
|
|
||||||
|
|
||||||
if (MqttClient.connect(clientId, mqttLogin, mqttPass, bufWillTopic, 2, true, willmess))
|
|
||||||
{
|
|
||||||
Serial.println("Mqttconnect - OK");
|
|
||||||
mqttSendFlag = true;
|
|
||||||
SendMqttReq(false, true, 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Serial.print("Mqtt.state() = ");
|
|
||||||
Serial.println(MqttClient.state());
|
|
||||||
/*
|
|
||||||
-4 : MQTT_CONNECTION_TIMEOUT - the server didn't respond within the keepalive time
|
|
||||||
-3 : MQTT_CONNECTION_LOST - the network connection was broken
|
|
||||||
-2 : MQTT_CONNECT_FAILED - the network connection failed
|
|
||||||
-1 : MQTT_DISCONNECTED - the client is disconnected cleanly
|
|
||||||
0 : MQTT_CONNECTED - the client is connected
|
|
||||||
1 : MQTT_CONNECT_BAD_PROTOCOL - the server doesn't support the requested version of MQTT
|
|
||||||
2 : MQTT_CONNECT_BAD_CLIENT_ID - the server rejected the client identifier
|
|
||||||
3 : MQTT_CONNECT_UNAVAILABLE - the server was unable to accept the connection
|
|
||||||
4 : MQTT_CONNECT_BAD_CREDENTIALS - the username/password were rejected
|
|
||||||
5 : MQTT_CONNECT_UNAUTHORIZED - the client was not authorized to connect
|
|
||||||
*/
|
|
||||||
mqttSendFlag = false;
|
|
||||||
delay(500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int printOled()
|
|
||||||
{
|
|
||||||
if (typeSensor == true)
|
|
||||||
{
|
|
||||||
Wire.begin(32, 26);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (display.begin(SSD1306_SWITCHCAPVCC, 0x3C))
|
|
||||||
// { // Address 0x3D for 128x64
|
|
||||||
Serial.println("PRINT OLED");
|
|
||||||
display.display();
|
|
||||||
delay(100);
|
|
||||||
|
|
||||||
// Clear the buffer
|
|
||||||
display.clearDisplay();
|
|
||||||
|
|
||||||
display.invertDisplay(true);
|
|
||||||
delay(500);
|
|
||||||
|
|
||||||
|
|
||||||
display.setTextSize(2);
|
|
||||||
display.setTextColor(SSD1306_WHITE);
|
|
||||||
display.setCursor(10, 20);
|
|
||||||
display.println(String(GlobalCo2)+String(" ppm"));
|
|
||||||
|
|
||||||
display.setTextSize(1);
|
|
||||||
display.setCursor(5, 5);
|
|
||||||
display.println(String("-CO2- "));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
display.display(); // Show initial text
|
|
||||||
delay(100);
|
|
||||||
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (typeSensor == true)
|
|
||||||
{
|
|
||||||
Wire.begin(i2cSDA, i2cSCL);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
M5.update();
|
|
||||||
|
|
||||||
if (WiFi.status() != WL_CONNECTED)
|
|
||||||
{
|
|
||||||
Serial.println(WiFi.status());
|
|
||||||
ESP.restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!MqttClient.connected())
|
|
||||||
{
|
|
||||||
reconnectMqtt();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (millis() - timingSendMqtt > nextMqttSend)
|
|
||||||
{
|
|
||||||
SendMqttReq();
|
|
||||||
|
|
||||||
if (GlobalCo2 <= 320)
|
|
||||||
{
|
|
||||||
ledset(4); //Белый
|
|
||||||
}
|
|
||||||
else if (GlobalCo2 > 320 && GlobalCo2 <= 1000)
|
|
||||||
{
|
|
||||||
ledset(2); //зеленый
|
|
||||||
}
|
|
||||||
else if (GlobalCo2 > 1000 && GlobalCo2 <= 2000)
|
|
||||||
{
|
|
||||||
ledset(5); //желтый
|
|
||||||
}
|
|
||||||
else if (GlobalCo2 > 2000 && GlobalCo2 <= 5000)
|
|
||||||
{
|
|
||||||
ledset(1); //красный
|
|
||||||
}
|
|
||||||
if (GlobalOled == true)
|
|
||||||
{
|
|
||||||
printOled();
|
|
||||||
}
|
|
||||||
timingSendMqtt = millis();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 40 секунд и происходит сброс настроек WIFI
|
|
||||||
if (M5.Btn.wasReleasefor(40000))
|
|
||||||
{
|
|
||||||
checkButton();
|
|
||||||
}
|
|
||||||
|
|
||||||
//По таймеру запруск обновления прошивки
|
|
||||||
if (millis() - timingUpdate > nextM5Update)
|
|
||||||
{
|
|
||||||
reqNtpTime();
|
|
||||||
SendMqttReq(false, true, 4);
|
|
||||||
OTAUpdate();
|
|
||||||
SendMqttReq(false, true, 1);
|
|
||||||
timingUpdate = millis();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Таймер отправки данных в брокер
|
|
||||||
MqttClient.loop();
|
|
||||||
}
|
|
||||||
|
|
||||||
int disconnectMQTT()
|
|
||||||
{
|
|
||||||
MqttClient.disconnect();
|
|
||||||
return 0;
|
|
||||||
}
|
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue