From d9e111470a15ea03c2f48a2f8510dec5958eb773 Mon Sep 17 00:00:00 2001 From: biver Date: Mon, 7 Mar 2022 11:54:25 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D1=8F?= =?UTF-8?q?=D0=B5=D0=BC=20MHZ19=20=D0=B8=20Sds011?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data_svelte/items.json | 148 ++++++++- platformio.ini | 2 + src/modules/API.cpp | 4 + src/modules/Mhz19.cpp | 689 +++++++++++++++++++++++++++++++++++++++++ src/modules/Sds011.cpp | 209 +++++++++++++ 5 files changed, 1038 insertions(+), 14 deletions(-) create mode 100644 src/modules/Mhz19.cpp create mode 100644 src/modules/Sds011.cpp diff --git a/data_svelte/items.json b/data_svelte/items.json index d161eec1..52db34f6 100644 --- a/data_svelte/items.json +++ b/data_svelte/items.json @@ -228,12 +228,132 @@ "round": 1, "int": 15 }, + { + "name": "18. Датчик пыли SDS011 PM25", + "num": 18, + "type": "Reading", + "subtype": "Sds011_25", + "id": "pmuart25", + "widget": "anydataPpm", + "page": "Сенсоры", + "descr": "PM-2.5", + "plus": 0, + "multiply": 1, + "round": 10, + "rxPin": 13, + "txPin": 12, + "int": 15, + "warmUp": 30, + "period": 300 + }, + { + "name": "19. Датчик пыли SDS011 PM10", + "num": 19, + "type": "Reading", + "subtype": "Sds011_10", + "id": "pmuart10", + "widget": "anydataPpm", + "page": "Сенсоры", + "descr": "PM-10", + "plus": 0, + "multiply": 1, + "round": 10, + "rxPin": 13, + "txPin": 12, + "int": 15, + "warmUp": 30, + "period": 300 + }, + { + "name": "20. Датчик CO2 MHZ-19 UART", + "num": 20, + "type": "Reading", + "subtype": "Mhz19uart", + "id": "co2uart", + "widget": "anydataPpm", + "page": "Сенсоры", + "descr": "CO2uart", + "plus": 0, + "multiply": 1, + "round": 1, + "pin": 0, + "rxPin": 14, + "txPin": 16, + "int": 15, + "range": 5000, + "ABC": 1 + }, + { + "name": "21. Датчик CO2 MHZ-19 PWM", + "num": 21, + "type": "Reading", + "subtype": "Mhz19pwm", + "id": "co2pwm", + "widget": "anydataPpm", + "page": "Сенсоры", + "descr": "CO2pwm", + "plus": 0, + "multiply": 1, + "round": 1, + "pin": 16, + "int": 300 + }, + { + "name": "22. Cенсор температуры от MHZ-19 UART", + "num": 22, + "type": "Reading", + "subtype": "Mhz19temp", + "id": "Mhz19temp", + "widget": "anydataTmp", + "page": "Сенсоры", + "descr": "Температура", + "plus": 0, + "multiply": 1, + "round": 1, + "rxPin": 14, + "txPin": 16, + "ABC": 1, + "int": 30 + }, + { + "name": "23. Рабочий диапазон от MHZ-19 UART", + "num": 23, + "type": "Reading", + "subtype": "Mhz19range", + "id": "Mhz19range", + "widget": "anydataPpm", + "page": "Сенсоры", + "descr": "Диапазон", + "plus": 0, + "multiply": 1, + "round": 1, + "rxPin": 14, + "txPin": 16, + "range": 5000, + "ABC": 1, + "int": 30 + }, + { + "name": "24. Автокалибровка от MHZ-19 UART", + "num": 24, + "type": "Reading", + "subtype": "Mhz19ABC", + "id": "Mhz19ABC", + "widget": "anydataDef", + "page": "Сенсоры", + "descr": "ABC", + "rxPin": 14, + "txPin": 16, + "range": 5000, + "ABC": 1, + "int": 30 + }, { "header": "Экраны" }, { - "name": "18. LCD экран 2004", - "num": 18, + "name": "25. LCD экран 2004", + "num": 25, "type": "Reading", "subtype": "Lcd2004", "id": "Lcd", @@ -247,8 +367,8 @@ "id2show": "id датчика" }, { - "name": "19. LCD экран 1602", - "num": 19, + "name": "26. LCD экран 1602", + "num": 26, "type": "Reading", "subtype": "Lcd2004", "id": "Lcd", @@ -265,8 +385,8 @@ "header": "Расширения" }, { - "name": "20. Доп. функции системы", - "num": 20, + "name": "27. Доп. функции системы", + "num": 27, "type": "Reading", "subtype": "SysExt", "id": "SysExt", @@ -276,8 +396,8 @@ "int": 15 }, { - "name": "21. Датчик напряжения ADS1115", - "num": 21, + "name": "28. Датчик напряжения ADS1115", + "num": 28, "type": "Reading", "subtype": "Ads1115", "id": "Ads3", @@ -295,8 +415,8 @@ "int": 10 }, { - "name": "22. Расширитель портов Mcp23017", - "num": 22, + "name": "29. Расширитель портов Mcp23017", + "num": 29, "type": "Reading", "subtype": "Mcp23017", "id": "Mcp", @@ -309,8 +429,8 @@ "index": 1 }, { - "name": "23. Переменная", - "num": 23, + "name": "30. Переменная", + "num": 30, "type": "Reading", "subtype": "Variable", "id": "var", @@ -325,8 +445,8 @@ "header": "Исполнительные устройства" }, { - "name": "24. Кнопка управляющая пином (Реле с кнопкой)", - "num": 24, + "name": "31. Кнопка управляющая пином (Реле с кнопкой)", + "num": 31, "type": "Writing", "subtype": "ButtonOut", "id": "btn", diff --git a/platformio.ini b/platformio.ini index 25a94fd4..54224f82 100644 --- a/platformio.ini +++ b/platformio.ini @@ -39,6 +39,7 @@ lib_deps = https://github.com/JonasGMorsch/GY-21.git adafruit/Adafruit ADS1X15 @ ^2.3.0 adafruit/Adafruit MCP23017 Arduino Library@^2.0.2 + Nova Fitness Sds dust sensors library@1.5.1 monitor_filters = esp8266_exception_decoder upload_speed = 921600 monitor_speed = 115200 @@ -62,6 +63,7 @@ lib_deps = https://github.com/JonasGMorsch/GY-21.git adafruit/Adafruit ADS1X15 @ ^2.3.0 adafruit/Adafruit MCP23017 Arduino Library@^2.0.2 + Nova Fitness Sds dust sensors library@1.5.1 monitor_filters = esp32_exception_decoder upload_speed = 921600 monitor_speed = 115200 diff --git a/src/modules/API.cpp b/src/modules/API.cpp index df878315..b08d148d 100644 --- a/src/modules/API.cpp +++ b/src/modules/API.cpp @@ -17,6 +17,8 @@ void* getAPI_Ads1115(String subtype, String params); void* getAPI_Mcp23017(String subtype, String params); void* getAPI_ButtonOut(String subtype, String params); void* getAPI_Variable(String subtype, String params); +void* getAPI_Sds011(String subtype, String params); +void* getAPI_Mhz19(String subtype, String params); //============================================================================================ void* getAPI(String subtype, String params) { @@ -38,6 +40,8 @@ void* getAPI(String subtype, String params) { if ((tmpAPI = getAPI_Mcp23017(subtype, params)) != nullptr) return tmpAPI; if ((tmpAPI = getAPI_ButtonOut(subtype, params)) != nullptr) return tmpAPI; if ((tmpAPI = getAPI_Variable(subtype, params)) != nullptr) return tmpAPI; + if ((tmpAPI = getAPI_Sds011(subtype, params)) != nullptr) return tmpAPI; + if ((tmpAPI = getAPI_Mhz19(subtype, params)) != nullptr) return tmpAPI; //================================================================================================================ return nullptr; diff --git a/src/modules/Mhz19.cpp b/src/modules/Mhz19.cpp new file mode 100644 index 00000000..5fa92ae1 --- /dev/null +++ b/src/modules/Mhz19.cpp @@ -0,0 +1,689 @@ +/****************************************************************** + Support for MHZ19 + + adapted for version 4 @cmche + ******************************************************************/ +#include "Global.h" +#include "classes/IoTItem.h" +#include + +extern IoTGpio IoTgpio; + +int rxPinCO2 = 14; // D5 // зеленый провод сенсора к D2 / 4 +int txPinCO2 = 16; // D0 // синий провод сенсора к D1/5 +SoftwareSerial swSerialCO2(rxPinCO2, txPinCO2); // RX, TX// ESP8266 D7 / D6 Blue/Green + +int MHZ19_request(int request); + +void MHZ19uart_init(); + +bool MHZ19uart_flag = true; +// int MHZ19C_PREHEATING_TIME = 2 * 60 * 1000;// покажет реальные данные после прогрева, через 2 мин. +int MHZ19C_PREHEATING_TIME = 2 * 30 * 1000; // покажет реальные данные после прогрева, через 2 мин. + +//int prevTemperature = 0; +int temperature = 0; +bool temperatureUpdated = false; +int prevRange = 5000; +int range = 5000; // по умолнчанию стоит шкала 5000 (не 2000 как в мануале) +bool rangeChaged = false; +int prevABC = 1; +int ABC = 1; +bool ABCchanged = false; + + +//Это файл сенсора, в нем осуществляется чтение сенсора. + +class Mhz19uart : public IoTItem +{ +private: + //======================================================================================================= + // Секция переменных. + +public: + //======================================================================================================= + + Mhz19uart(String parameters) : IoTItem(parameters) + { + rxPinCO2 = jsonReadInt(parameters, "rxPin"); + txPinCO2 = jsonReadInt(parameters, "txPin"); + range = jsonReadInt(parameters, "range"); + ABC = jsonReadInt(parameters, "ABC"); + } + //======================================================================================================= + // doByInterval() + + void doByInterval() + { + MHZ19uart_init(); + if (millis() > MHZ19C_PREHEATING_TIME) + { + Serial.println("Start checkUARTCO2"); + value.valD = MHZ19_request(1); + } + regEvent(value.valD, "Mhz19uart"); //обязательный вызов хотяб один + } + //======================================================================================================= + + ~Mhz19uart() {}; +}; + +//после замены названия сенсора, на функцию можно не обращать внимания +//если сенсор предполагает использование общего объекта библиотеки для нескольких экземпляров сенсора, то в данной функции необходимо предусмотреть +//создание и контроль соответствующих глобальных переменных + +class Mhz19pwm : public IoTItem +{ +private: + //======================================================================================================= + // Секция переменных. + int pwmPin; ///// желтый провод сенсора к D8 (14-D5 ok) + +public: + //======================================================================================================= + + Mhz19pwm(String parameters) : IoTItem(parameters) + { + pwmPin = jsonReadInt(parameters, "pin"); + } + //======================================================================================================= + + void doByInterval() + { + MHZ19pwm_init(); + if (millis() > MHZ19C_PREHEATING_TIME) // + { + Serial.println("Start checkPWM_CO2"); + value.valD = MHZ19pwm_request(); + } + regEvent(value.valD, "Mhz19pwm"); //обязательный вызов хотяб один + } + //======================================================================================================= + + void MHZ19pwm_init() + { + static bool MHZ19pwm_flag = true; + if (MHZ19pwm_flag) + { + pinMode(pwmPin, INPUT); + MHZ19pwm_flag = false; + } + } + + int MHZ19pwm_request() + { + int reply; + Serial.println("Запрос замера по PWM запущен"); + unsigned long th, tl, ppm = 0, ppm2 = 0, ppm3 = 0; + do + { + th = pulseIn(pwmPin, HIGH, 1004000) / 1000; + tl = 1004 - th; + ppm2 = 2000 * (th - 2) / (th + tl - 4); // расчёт для диапазона от 0 до 2000ppm + ppm3 = 5000 * (th - 2) / (th + tl - 4); // расчёт для диапазона от 0 до 5000ppm + } while (th == 0); + + // Serial.print(th); + // Serial.println(" <- Milliseconds PWM is HIGH"); + + if (range == 2000) + { + reply = ppm2; + Serial.print(ppm2); + Serial.println(" <- ppm2 (PWM) with 2000ppm as limit"); + } + else + { + reply = ppm3; + Serial.print(ppm3); + Serial.println(" <- ppm3 (PWM) with 5000ppm as limit"); + } + Serial.println("Completed checkPwmCO2"); + return reply; + } + + ~Mhz19pwm() {}; +}; + +//====================TEMP=================================================================================== + +class Mhz19temp : public IoTItem +{ +private: + //======================================================================================================= + // Секция переменных. +public: + //====================TEMP=================================================================================== + + Mhz19temp(String parameters) : IoTItem(parameters) + { + rxPinCO2 = jsonReadInt(parameters, "rxPin"); + txPinCO2 = jsonReadInt(parameters, "txPin"); + range = jsonReadInt(parameters, "range"); + ABC = jsonReadInt(parameters, "ABC"); + } + //======================================================================================================= + + void doByInterval() + { + // Serial.println("Start Mhz19temp doByInterval"); + if (temperatureUpdated) + { + value.valD = temperature; + temperatureUpdated = false; + } + else + { + MHZ19uart_init(); + Serial.println("Start temperature request"); + if (MHZ19_request(13)) + { + value.valD = temperature; + }; // change + } + regEvent(value.valD, "Mhz19temp"); //обязательный вызов хотяб один + } + //======================================================================================================= + + //======================================================================================================= + + ~Mhz19temp() {}; +}; + +//=======================Range================ +class Mhz19range : public IoTItem +{ + +private: +public: + Mhz19range(String parameters) : IoTItem(parameters) + { + rxPinCO2 = jsonReadInt(parameters, "rxPin"); + txPinCO2 = jsonReadInt(parameters, "txPin"); + range = jsonReadInt(parameters, "range"); + ABC = jsonReadInt(parameters, "ABC"); + } + + void doByInterval() + { + if (range != prevRange) + { + MHZ19uart_init(); + Serial.println("Start change range"); + + if (range == 2000) + { + if (MHZ19_request(9)) + { + prevRange = 2000; + value.valD = 2000; + } // change range to 2000 + } + else + { + if (MHZ19_request(10)) + { + prevRange = 5000; + value.valD = 5000; + } // change range to 5000 + } + } + else + { + value.valD = prevRange; + } + regEvent(value.valD, "Mhz19range"); //обязательный вызов хотяб один + } + + ~Mhz19range() {}; +}; + +//===================ABC================= + +class Mhz19ABC : public IoTItem +{ + +private: +public: + Mhz19ABC(String parameters) : IoTItem(parameters) + { + rxPinCO2 = jsonReadInt(parameters, "rxPin"); + txPinCO2 = jsonReadInt(parameters, "txPin"); + range = jsonReadInt(parameters, "range"); + ABC = jsonReadInt(parameters, "ABC"); + } + + void doByInterval() + { + if (ABC != prevABC) + { + if (ABC == 1) + { + if (MHZ19_request(7)) + { + prevABC = 1; + value.valD = 1; + } // change ABC to 1 + } + else + { + if (MHZ19_request(8)) + { + prevABC = 0; + value.valD = 0; + } // change ABC to 0 + } + } + else + { + value.valD = prevABC; + } + regEvent(value.valD, "Mhz19ABC"); //обязательный вызов хотяб один + } + + ~Mhz19ABC() {}; +}; + +///============== end of classes========================== + +void *getAPI_Mhz19(String subtype, String param) +{ + + if (subtype == F("Mhz19uart")) + { + return new Mhz19uart(param); + } + else if (subtype == F("Mhz19pwm")) + { + return new Mhz19pwm(param); + } + else if (subtype == F("Mhz19temp")) + { + return new Mhz19temp(param); + } + else if (subtype == F("Mhz19range")) + { + return new Mhz19range(param); + } + else if (subtype == F("Mhz19ABC")) + { + return new Mhz19ABC(param); + } + else + { + return nullptr; + } +} + +void MHZ19uart_init() +{ + + if (MHZ19uart_flag) + { + int reply; + swSerialCO2.begin(9600); + + delay(50); + + reply = MHZ19_request(2); // show range, for test of uart only + Serial.print("show range reply = "); + Serial.println(reply); + + if (reply) + { + MHZ19uart_flag = false; + } + + } + + if (!MHZ19uart_flag) + { + static int prevABC; + int reply; + + if (ABC != prevABC) + { + if (ABC) + { + reply = MHZ19_request(7); // ABC on + } + else + { + reply = MHZ19_request(8); // ABC off + } + Serial.print("ABC change reply = "); + Serial.println(reply); + } + if (reply) + { + prevABC = ABC; + } + } + + static bool MHZ19_range_flag = true; + if (MHZ19_range_flag && !MHZ19uart_flag && (millis() > 30 * 1000)) + { + int reply; + if (range == 2000) + { + reply = MHZ19_request(9); // Установка шкалы 0-2000 + // 255 155 0 0 7 208 0 3 139 + } + else + { + reply = MHZ19_request(10); // Установка шкалы 0-5000 + // 255 155 0 0 19 136 0 3 199 + } + Serial.print("Scale change reply = "); + Serial.println(reply); + if (reply) + { + reply = MHZ19_request(2); // show range + Serial.print("show range reply = "); + Serial.println(reply); + + MHZ19_range_flag = false; + } + } +} + +int MHZ19_request(int request) +{ + int reply; + Serial.print("prevRange = "); + Serial.println(prevRange); + + byte uartReqSamplePpm[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79}; // PPM + // 255 1 134 0 0 0 0 0 121 +// Response 255 134 1 148 67 0 0 0 162 + + byte uartReqSampleABCon[9] = {0xFF, 0x01, 0x79, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xE6}; // ABC logic on + // 255 1 121 160 0 0 0 0 230 +//Response 255 121 1 0 0 0 0 0 134 + byte uartReqSampleABCoff[9] = {0xFF, 0x01, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86}; // ABC logic off + byte uartReqSampleABCstatus[9] = {0xFF, 0x01, 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82}; // ABC logic status + + byte uartReqSample1000Range[9] = {0xFF, 0x01, 0x99, 0x00, 0x00, 0x00, 0x03, 0xE8, 0x7B}; + byte uartReqSample2000Range[9] = {0xFF, 0x01, 0x99, 0x00, 0x00, 0x00, 0x07, 0xD0, 0x8F}; // задаёт диапазон 0 - 2000ppm + byte uartReqSample3000Range[9] = {0xFF, 0x01, 0x99, 0x00, 0x00, 0x00, 0x0B, 0xB8, 0xA3}; // задаёт диапазон 0 - 2000ppm + + byte uartReqSample5000Range[9] = {0xFF, 0x01, 0x99, 0x00, 0x00, 0x00, 0x13, 0x88, 0xCB}; // задаёт диапазон 0 - 5000ppm +// 255 1 153 0 0 0 19 136 203 +// Response 255 153 1 0 0 0 0 0 102 + byte uartReqSampleRequestRange[9] = {0xFF, 0x01, 0x9B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64}; // запрос диапазона + // request // 255 1 155 0 0 0 0 0 100 + //reply // 255 1 155 0 0 0 0 0 100 + byte uartReqSampleZeroPnt[9] = {0xFF, 0x01, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78}; // !!ZERO POINT CALIBRATION + byte uartReqSampleReset[9] = {0xFF, 0x01, 0x8D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72}; // reset + + byte uartReqSampleReset1[9] = {0xFF, 0x01, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87}; // reset - did not work out + + byte request_cmd[9]; + // byte c; + switch (request) + { + // случаи 3-7 для перезапуска сенсора + case 1: + { + Serial.println("Запрос No.1 - отправлен. Запрос замера по UART"); + for (int i = 0; i < 9; i++) + { + request_cmd[i] = uartReqSamplePpm[i]; + } + } + break; + + case 2: + { + for (int i = 0; i < 9; i++) + { + request_cmd[i] = uartReqSampleRequestRange[i]; + } + Serial.println("Запрос No.2 - отправлен. Запрос шкалы"); + } + break; + + case 3: + { + // код для запуска сенсора с работой по UART (запуск таймера) + Serial.println("Запрос No.3 - отправлен. Сенсор по UART запущен"); + } + break; + case 4: + { + // код для остановке сенсора с работой по UART (остановка таймера) + Serial.println("Запрос No.4 - отправлен. Сенсор по UART остановлен"); + } + break; + case 5: + { + // код для запуска сенсора с работой по PWM (запуск таймера) + Serial.println("Запрос No.5 - отправлен. Сенсор по PWM запущен"); + } + break; + case 6: + { + // код для остановки сенсора с работой по PWM (остановка таймера) + Serial.println("Запрос No.6 - отправлен. Сенсор по PWM остановлен"); + } + break; + case 7: + { + for (int i = 0; i < 9; i++) + { + request_cmd[i] = uartReqSampleABCon[i]; + } + Serial.println("Запрос No.7 - отправлен. Включаем функцию атокалибровки"); + } + break; + case 8: + { + for (int i = 0; i < 9; i++) + { + request_cmd[i] = uartReqSampleABCoff[i]; + } + Serial.println("Запрос No.8 - отправлен. Выключаем функцию атокалибровки"); + } + break; + case 9: + { + for (int i = 0; i < 9; i++) + { + request_cmd[i] = uartReqSample2000Range[i]; + } + Serial.println("Запрос No.9 - отправлен. Установливаем шкалу 0-2000"); + } + break; + case 10: + { + for (int i = 0; i < 9; i++) + { + request_cmd[i] = uartReqSample5000Range[i]; + } + Serial.println("Запрос No.10 - отправлен. Установливаем шкалу 0-5000"); + } + break; + case 11: + { + for (int i = 0; i < 9; i++) + { + request_cmd[i] = uartReqSampleZeroPnt[i]; + } + Serial.println("Запрос No.11 - отправлен. Калибровка. Установливаем нулевой уровень"); + } + break; + case 12: + { + for (int i = 0; i < 9; i++) + { + request_cmd[i] = uartReqSampleReset1[i]; + } + Serial.println("Запрос No.11 - отправлен. Запрос на Сброс"); + } + break; + case 13: + { + for (int i = 0; i < 9; i++) + { + request_cmd[i] = uartReqSamplePpm[i]; + } + Serial.println("Запрос No.13 - отправлен. Запрос по Температуре"); + } + break; + default: + // byte c = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79}; + // if nothing else matches, do the default + // default is optional + break; + } + + swSerialCO2.write(request_cmd, 9); + + Serial.print("Request : "); + for (int i = 0; i < 9; i++) + { + Serial.print(" "); + Serial.print(request_cmd[i]); + } + Serial.println(" "); + + delay(50); + + unsigned char response[9]; + + Serial.print("Response :"); + swSerialCO2.readBytes(response, 9); + + for (int i = 0; i < 9; i++) + { + Serial.print(" "); + Serial.print(response[i]); + } + Serial.println(" "); + + byte crc = 0; + for (int i = 1; i < 8; i++) crc += response[i]; + crc = 255 - crc; + crc += 1; + + if (!(response[0] == 0xFF && response[8] == crc)) + { + Serial.println("Range CRC error: " + String(crc) + " / " + String(response[8])); + reply = 0; + } + else + { + // Serial.println("No CRC errors"); + switch (request) + { + + case 1: + { + unsigned int responseHigh = (unsigned int)response[2]; + unsigned int responseLow = (unsigned int)response[3]; + unsigned int ppm = (256*responseHigh) + responseLow; + + Serial.print("CO2 UART = "); + Serial.println(ppm); + + temperature = response[4] - 44; // - 40; + Serial.print("Temperature = "); + Serial.println(temperature); + temperatureUpdated = true; + + reply = ppm; + } + break; + + case 2: + { + reply = 1; + Serial.println("Case 2 - OK. На запрос шкалы пришел ответ"); + } + break; + case 3: + { + // Serial.println("Case 3 - OK"); + reply = 1; + } + break; + case 4: + { + // Serial.println("Case 4 - OK"); + reply = 1; + } + break; + case 5: + { + // Serial.println("Case 5 - OK"); + reply = 1; + } + break; + case 6: + { + Serial.println("Case 6 - OK"); + reply = 1; + } + break; + case 7: + { + Serial.println("Case 7 - OK. ABC включен"); + reply = 1; + } + break; + case 8: + { + Serial.println("Case 8 - OK. ABC выключен"); + reply = 1; + } + break; + case 9: + { + Serial.println("Case 9 - OK. Установлена шкала 0-2000"); + reply = 1; + prevRange = 2000; + } + break; + case 10: + { + Serial.println("Case 9 - OK. Установлена шкала 0-5000"); + reply = 1; + prevRange = 5000; + } + break; + case 11: + { + reply = 1; + Serial.println("Запрос No.11 - сработал. Калибровка. Установлен нулевой уровень"); + } + break; + + case 12: + { + reply = 1; + Serial.println("Запрос No.12 - сработал. Сброс произошел"); + } + break; + + case 13: + { + reply = 1; + temperature = response[4] - 44; // - 40; + + Serial.println("Запрос No.12 - сработал. Температура получена"); + Serial.println(temperature); + } + break; + + default: + // byte c = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79}; + // if nothing else matches, do the default + // default is optional + + break; + } + } + // Serial.print("reply = "); + // Serial.println(reply); + return reply; +} diff --git a/src/modules/Sds011.cpp b/src/modules/Sds011.cpp new file mode 100644 index 00000000..b230312a --- /dev/null +++ b/src/modules/Sds011.cpp @@ -0,0 +1,209 @@ +/****************************************************************** + Supports Sds011, implements whole Laser Dust Sensor Control Protocol V1.3, + should also work with other Sds sensors. + + https://github.com/lewapek/sds-dust-sensors-arduino-library + + adapted for version 4 @cmche + ******************************************************************/ + +#include "Global.h" +#include "classes/IoTItem.h" + +extern IoTGpio IoTgpio; + +#include "SdsDustSensor.h" + +int rxPinSDS = 13; // D7 – подключаем к Tx сенсора +int txPinSDS = 12; // D6 – подключаем к Rx сенсора +SdsDustSensor sds(rxPinSDS, txPinSDS); + +unsigned int warmUp; +unsigned int period; + +bool SDS011_init_flag = true; +void SDS011_init(); +float Sds011request(int sensorID); + +//Это файл сенсора, в нем осуществляется чтение сенсора. +//для добавления сенсора вам нужно скопировать этот файл и заменить в нем текст AnalogAdc на название вашего сенсора +//Название должно быть уникальным, коротким и отражать суть сенсора. + +class Sds011_25 : public IoTItem +{ +private: + //======================================================================================================= + // Секция переменных. + //Это секция где Вы можете объявлять переменные и объекты arduino библиотек, что бы + //впоследствии использовать их в loop и setup + // unsigned int _pin; + +public: + //======================================================================================================= + // setup() + //это аналог setup из arduino. Здесь вы можете выполнять методы инициализации сенсора. + //Такие как ...begin и подставлять в них параметры полученные из web интерфейса. + //Все параметры хранятся в перемененной parameters, вы можете прочитать любой параметр используя jsonRead функции: + // jsonReadStr, jsonReadBool, jsonReadInt + Sds011_25(String parameters) : IoTItem(parameters) + { + // _pin = jsonReadInt(parameters, "pin"); + rxPinSDS = jsonReadInt(parameters, "rxPin"); + txPinSDS = jsonReadInt(parameters, "txPin"); + warmUp = jsonReadInt(parameters, "warmUp"); // сек. пробужнение должен быть больше + period = jsonReadInt(parameters, "period"); // сек. время зарогрева/продувки, затем идут замеры + } + //======================================================================================================= + // doByInterval() + //это аналог loop из arduino, но вызываемый каждые int секунд, заданные в настройках. Здесь вы должны выполнить чтение вашего сенсора + //а затем выполнить regEvent - это регистрация произошедшего события чтения + //здесь так же доступны все переменные из секции переменных, и полученные в setup + //если у сенсора несколько величин то делайте несколько regEvent + //не используйте delay - помните, что данный loop общий для всех модулей. Если у вас планируется длительная операция, постарайтесь разбить ее на порции + //и выполнить за несколько тактов + void doByInterval() + { + SDS011_init(); + Serial.println("request from 25"); + value.valD = Sds011request(25); + + regEvent(value.valD, "Sds011_25"); //обязательный вызов хотяб один + } + + ~Sds011_25() {}; +}; + +//////////////////////////////////// for PM 10//= + +class Sds011_10 : public IoTItem +{ +private: + //======================================================================================================= + // Секция переменных. + //Это секция где Вы можете объявлять переменные и объекты arduino библиотек, что бы + //впоследствии использовать их в loop и setup + +public: + //======================================================================================================= + // setup() + //это аналог setup из arduino. Здесь вы можете выполнять методы инициализации сенсора. + //Такие как ...begin и подставлять в них параметры полученные из web интерфейса. + //Все параметры хранятся в перемененной parameters, вы можете прочитать любой параметр используя jsonRead функции: + // jsonReadStr, jsonReadBool, jsonReadInt + Sds011_10(String parameters) : IoTItem(parameters) + { + // _pin = jsonReadInt(parameters, "pin"); + rxPinSDS = jsonReadInt(parameters, "rxPin"); + txPinSDS = jsonReadInt(parameters, "txPin"); + warmUp = jsonReadInt(parameters, "warmUp"); // сек. пробужнение должен быть больше + period = jsonReadInt(parameters, "period"); // сек. время зарогрева/продувки, затем идут замеры + } + //======================================================================================================= + // doByInterval() + //это аналог loop из arduino, но вызываемый каждые int секунд, заданные в настройках. Здесь вы должны выполнить чтение вашего сенсора + //а затем выполнить regEvent - это регистрация произошедшего события чтения + //здесь так же доступны все переменные из секции переменных, и полученные в setup + //если у сенсора несколько величин то делайте несколько regEvent + //не используйте delay - помните, что данный loop общий для всех модулей. Если у вас планируется длительная операция, постарайтесь разбить ее на порции + //и выполнить за несколько тактов + + void doByInterval() + { + SDS011_init(); + Serial.println("request from 10"); + value.valD = Sds011request(10); + + regEvent(value.valD, "Sds011_10"); //обязательный вызов хотяб один + } + ~Sds011_10() {}; +}; + +//после замены названия сенсора, на функцию можно не обращать внимания +//если сенсор предполагает использование общего объекта библиотеки для нескольких экземпляров сенсора, то в данной функции необходимо предусмотреть +//создание и контроль соответствующих глобальных переменных +void *getAPI_Sds011(String subtype, String param) +{ + if (subtype == F("Sds011_25")) + { + return new Sds011_25(param); + } + else if (subtype == F("Sds011_10")) + { + return new Sds011_10(param); + } + else + { + return nullptr; + } +} + +float Sds011request(int sensorID) +{ + float reply = 0; + static int a = 0; + static float pm25 = 0; + static float pm10 = 0; + static int startMillis = millis(); + + if (a == 0) + { + Serial.print("SDS011 ... warmUp = "); + Serial.print(warmUp); + Serial.print(" period = "); + Serial.println(period); + sds.wakeup(); + startMillis = millis(); + a = a + 1; + } + if (a == 1 && millis() >= (startMillis + warmUp * 1000)) + { + PmResult pm = sds.readPm(); + if (pm.isOk()) + { + pm25 = pm.pm25; + pm10 = pm.pm10; + Serial.print("PM2.5 = "); + Serial.print(pm25); + Serial.print(" PM10 = "); + Serial.println(pm10); + a = a + 1; + sds.sleep(); + } + else + { + Serial.print("Could not read values from sensor 25, reason: "); + Serial.println(pm.statusToString()); + a = a + 1; + } + } + if (a > 1 && millis() >= (startMillis + period * 1000)) + { + Serial.println("end of period for pm25"); + a = 0; + } + if (sensorID == 25) + { + reply = pm25; + } + if (sensorID == 10) + { + reply = pm10; + } + return reply; +} + +void SDS011_init() +{ + if (SDS011_init_flag) + { + sds.begin(); + Serial.println(sds.queryFirmwareVersion().toString()); // prints firmware version + // Serial.println(sds.setActiveReportingMode().toString()); // + String ReportingMode = sds.setActiveReportingMode().toString(); + Serial.println(ReportingMode); + if (ReportingMode == "Mode: active") + { + SDS011_init_flag = false; + } + } +}