Автор Тема: Продвинутый контроллер для гидропоники на Arduino Mega + Wemos  (Прочитано 1243 раз)

Онлайн Ann

  • Глобальный модератор
  • Habanero
  • *****
  • Сообщений: 1533
  • Лойсы: +120/-0
    • Просмотр профиля
Этап 2. Пара слов о железе.
В процессе постройки устройства мы добавляем новые модули, подключая каждый ардуиновскими монтажными проводками. И в конечном итоге это может привести к такой картине (на фото первая версия моего коллайдера):


Кроме эстетического ужаса это сопровождается еще кучей технических проблем, чуть шевельнул, отошли или выдернулись контакты, сидишь потом час разбираешься, почему оно не работает. А однажды в партии все зеленые проводки вообще не звонились. В общем я категорически отказался от использования монтажных проводков даже в простейших проектах, только пайка и ничего больше.
Очень удобно использовать платы для прототипирования, минимум места и максимум надежности.
Вот я сделал такой шилд из платы (по размеру бОльших у меня не было, поэтому одевается лишь на половину Меги, питание и 2-3 ШИМ-выхода будут отдельными проводками подключаться). Здесь уже подпаяны разъемы для Вемоса, часов и датчика bmp085. Все легко снимается и собирается. Вид сверху и снизу:


А это уже в сборе.

Оффлайн PowerTech

  • Serrano
  • ***
  • Сообщений: 179
  • Лойсы: +12/-0
  • Василий
    • Просмотр профиля

Онлайн Ann

  • Глобальный модератор
  • Habanero
  • *****
  • Сообщений: 1533
  • Лойсы: +120/-0
    • Просмотр профиля
Этап 3. Часы.
У меня DS3231. Подключаю только пины SDA SCL и питание. Другие (для доп. EEPROM) мне не нужны.
Библиотеку использую RTClib. Найти можно прямо в среде Ардуино. Заходим Скетч > Подключить библиотеку > Управлять библиотеками... Там в поиске вводим RTClib и устанавливаем найденную.
Сделаем отдельную функцию, которая будет будет заниматься опросом датчиков и часов раз в 2 секунды. Назовем Klimat().
Добавляем в скетч
А.
#include <RTClib.h>
RTC_DS3231 rtc;
int time_current_h; //введем переменные для хранения времени для удобства
int time_current_m;
int time_current_s;
long klimat_last_time;
В.
rtc.begin();
С.
Klimat(2000);
D.
void Klimat(float freq){
  if ((millis()-klimat_last_time)>freq){
    DateTime now = rtc.now();
    time_current_h = now.hour();
    time_current_m = now.minute();
    time_current_s = now.second();
    klimat_last_time = millis();
  }
}

Онлайн Ann

  • Глобальный модератор
  • Habanero
  • *****
  • Сообщений: 1533
  • Лойсы: +120/-0
    • Просмотр профиля
Вот Вам идея для контроля pH
https://www.ebay.com/itm/Liquid-PH0-14-Value-Detect-Sensor-Module-PH-Electrode-Probe-BNC-for-Arduino/172462790633?hash=item28279557e9:m:myLED2pvE2RcmgHiZm2ZRew
Да видел я его. Саша даже брал, но завести не получилось.
Себе брать пока желания нет, капризные, недолговечные, дорогие. Хотя конечно с удовольствием бы глянул на суточный график.

Онлайн Ann

  • Глобальный модератор
  • Habanero
  • *****
  • Сообщений: 1533
  • Лойсы: +120/-0
    • Просмотр профиля
Этап 4. Датчик давления bmp 085.
К гидропонике он отношения конечно не имеет, но для меня интересен (метеочувствительность и т.д.).
Он, если не ошибаюсь, 3.3-вольтовый, я подключаю напрямую, что неправильно! (на свой страх и риск)
Аналогичным образом находим и устанавливаем либу (в поиске вводим Adafruit-BMP085-Library ).
Добавляем в скетч
А.
#include <Adafruit_BMP085.h>
Adafruit_BMP085 bmp;
float pressure;
В.
bmp.begin();
С.
D.
В функцию Klimat добавляем строку
baro_pressure = bmp.readPressure()/133.322;   // делить на 133.322 нужно, чтоб преобразовать паскали в мм ртутного столба
« Последнее редактирование: 20 Ноябрь 2017, 20:12:57 от Ann »

Онлайн Ann

  • Глобальный модератор
  • Habanero
  • *****
  • Сообщений: 1533
  • Лойсы: +120/-0
    • Просмотр профиля
Этап 5. Датчик DHT 21.
Разобрал, что подпаять более длинные проводки, вот, кому интересно, внутренности:

Пишут, что вывод данных нужно подтягивать к плюсу резистором 10кОм, но вроде бы там он уже подтянут, по крайней мере промерял, между плюсом и данными ровно 10кОм. Подключил без резистора, работает норм.
Либа "DHT.h", но она требует еще "Adafruit Unified Sensor", тоже поиском находится. Подключать в скетч её не нужно.
Добавляем в скетч
А.
#include "DHT.h"
#define DHTPIN 23
#define DHTTYPE DHT21
DHT dht(DHTPIN, DHTTYPE);
float DHT_temperature;                                            //Мгновенная температура
float DHT_humidity;                                            //Мгновенная влажность
В.
dht.begin();
С.
D.
В функцию Klimat добавляем
DHT_temperature = dht.readTemperature();
DHT_humidity = dht.readHumidity();

Оффлайн alex_step

  • Serrano
  • ***
  • Сообщений: 181
  • Лойсы: +5/-2
  • Александр, Украина, Жмеринка
    • Просмотр профиля
Да видел я его. Саша даже брал, но завести не получилось.
есть такое. он работал, а потом в очередной раз при подключении в другой проект в отказ ушел по неизвестной причине...

Онлайн Ann

  • Глобальный модератор
  • Habanero
  • *****
  • Сообщений: 1533
  • Лойсы: +120/-0
    • Просмотр профиля
Этап 5. Датчик Dallas DS18B20.
У меня герметичный. Будет измерять температуру раствора. Использую не библиотеку, а функцию прямого обращения к датчику, там особенности, поэтому вынесу его замеры в отдельную функцию. Точность выставлена максимальная. Следуюет отметить, что у каждого датчика есть свой уникальный ID, его нужно узнать с помощью тестовых скетчей, либо использовать либы.
А.
#include <OneWire.h>
OneWire  ds(27);
byte dallas_data[2];
byte addr[8] = {0x28, 0x95, 0x15, 0xAE, 0x8, 0x0, 0x0, 0x73};   //уникальный ID
long dallas_last_time;
boolean dallas_flag;
float DALLAS_temperature;
В.
С.
Dallas(2000);
D.
void Dallas(int freq){
  if((millis()-dallas_last_time)>freq){
    ds.reset();
    ds.select(addr);
    ds.write(0x44, 1);
    dallas_last_time = millis();
    dallas_flag = true;   
    }
  if((millis()-dallas_last_time)>1000 && dallas_flag){
    ds.reset();
    ds.select(addr);   
    ds.write(0xBE);       
 
    dallas_data[0] = ds.read();
    dallas_data[1] = ds.read();
   
    int16_t raw = (dallas_data[1] << 8 ) | dallas_data[0];
    DALLAS_temperature = (float)raw / 16.0;
   
    dallas_flag = false;
    }
 }


Вывод данных подтягивается к плюсу резистором 4.7кОм.

Онлайн Ann

  • Глобальный модератор
  • Habanero
  • *****
  • Сообщений: 1533
  • Лойсы: +120/-0
    • Просмотр профиля
Этап 6. Управление мощной нагрузкой. Подогрев раствора.
Буду использовать чрезвычайно приятную штуку - сборку Дарлингтона , маленькая, 7-канальная, 20-центовая. Может управлять нагрузкой до 50 вольт и 500мА на канал, каналы можно паралеллить, тогда до 2А.
Питаю я Мегу (да и весь коллайдер) БП на 12 вольт. Прямо с выхода Vin беру эти 12 вольт и завожу на сборку Дарлингтона.
Печка (кусок нихромовой проволоки, наклеенный на кусок ДСП) имеет сопротивление 23 Ом, т.е. при 12 вольтах будет потреблять 500мА, как раз одного канала хватит.
Вот схема подключения

Впаял в свободное место, вот она в правой части.

Справа к её выходам вывел двойную гребенку с тремя парами выходов для подключения нагрузок (будет подогрев раствора, вытяжной венилятор, одна запасная).

Пока у меня слабое представление об алгоритме работы подогрева раствора, для начала сделаем только подогрев днем до температуры 25 градусов, потом разберемся, если что.
А.
int pechka_pin = 4;
int pechka_rastvor_temp = 25;
В.
pinMode(pechka_pin, OUTPUT);
С.
Pechka();
D.
void Pechka(){
  if(den && DALLAS_temperature < pechka_rastvor_temp ){
     digitalWrite(pechka_pin, HIGH);
   }else{
    digitalWrite(pechka_pin, LOW);
   }
}

Оффлайн alex_step

  • Serrano
  • ***
  • Сообщений: 181
  • Лойсы: +5/-2
  • Александр, Украина, Жмеринка
    • Просмотр профиля
ну это ведь далеко не мощная нагрузка...
мощная - это, как я понимаю, 12В 300Ватт, или 220В 500Ватт  ;)

Онлайн Ann

  • Глобальный модератор
  • Habanero
  • *****
  • Сообщений: 1533
  • Лойсы: +120/-0
    • Просмотр профиля
ну это ведь далеко не мощная нагрузка...
мощная - это, как я понимаю, 12В 300Ватт, или 220В 500Ватт  ;)
В масштабах Ардуины мощная :) Ардуина может только 5 вольт и до 40мА. Для питания мелкой периферии (двигатели, вентиляторы и т.д.) 500мА хватает. Для 500+ватт существуют реле.

Онлайн Ann

  • Глобальный модератор
  • Habanero
  • *****
  • Сообщений: 1533
  • Лойсы: +120/-0
    • Просмотр профиля
Этап 6. Управление мощной нагрузкой. Вентилятор вытяжки.
Юзаем второй вывод со сборки Дарлингтона. Используем ШИМ.
Пока я тоже слабо представляю режим его работы (какая получится производительность, скорость понижения температуры и т.д.), но пока сделаем примерно такой режим, потом уже подкорректируем:
Ночь - вентилятор крутится постоянно на мощности 30%.
День и температура меньше 30 градусов - вентилятор включается раз 30 минут на 5 минут на 50% мощности
День и температура 30-31 градус - вентилятор крутится постоянно на 50% мощности (пока не понизит температуру)
День и температура выше 31 градуса - вентилятор крутится постоянно на 80% мощности (пока не понизит температуру)
А.
int carlson_pin = 5;
int carlson_night_power = 30;
int carlson_day_power = 50;
int carlson_extrime_power = 80;
int carlson_freq = 30;
int carlson_dlit = 5;
boolean carlson_flag = false;
В.
pinMode(carlson_pin, OUTPUT);
С.
Carlson();
D.
void Carlson(){
  if(den && DHT_temperature < 30 ){
    if(  (millis()-carlson_last_time)>(carlson_freq*60000) && !carlson_flag ){
      analogWrite(carlson_pin, (int)(carlson_day_power*2.55));
      carlson_flag = true;
      carlson_last_time = millis();
      }
    if(  (millis()-carlson_last_time)>(carlson_dlit*60000) && carlson_flag ){
      analogWrite(carlson_pin, 0);
      carlson_flag = false;
      }
   }

   if (den && DHT_temperature >= 30 && DHT_temperature < 31){
     analogWrite(carlson_pin, (int)(carlson_day_power*2.55));
    }

   if (den && DHT_temperature >= 31){
     analogWrite(carlson_pin, (int)(carlson_extrime_power*2.55));
    }
   
   if(!den){
    analogWrite(carlson_pin, (int)(carlson_night_power*2.55));
    }
}

Онлайн Ann

  • Глобальный модератор
  • Habanero
  • *****
  • Сообщений: 1533
  • Лойсы: +120/-0
    • Просмотр профиля
Этап 7. Управление твердотельным реле помпы.
На помпу установил твердотельное реле вот такое:

Шикарная штука, маленькая, бесшумная (обычное реле немного напрягало своими щелчками, слышно было в соседней комнате), не нужно дополнительно тянуть для неё доп. питание, цена доллар с небольшим. Внутри стоит оптрон с резистором, для управления потребляет 7мА, поэтому управлять можно прямо с пина.
А.
int pompa_pin = 53;
long pompa_freq=60;
long pompa_dlit=5;
long pompa_last_time;
boolean pompa_flag = false;
В.
pinMode(pompa_pin, OUTPUT);
С.
Pompa();
D.
void Pompa(){
  if(  (millis()-pompa_last_time)>(pompa_freq*60000) && !pompa_flag ){
     digitalWrite(pompa_pin, HIGH);
     pompa_flag=true;
     pompa_last_time=millis();
    }
  if(  (millis()-pompa_last_time)>(pompa_dlit*60000) && pompa_flag ){
     digitalWrite(pompa_pin, LOW);
     pompa_flag=false;
    }
  }

Онлайн Ann

  • Глобальный модератор
  • Habanero
  • *****
  • Сообщений: 1533
  • Лойсы: +120/-0
    • Просмотр профиля
Этап 8. TDS-метр.
Есть способ измерения TDS простой и правильный. Правильный - это замерять сопротивление между электродами при переменном напряжении 1кГц.
Простой - просто замерять сопротивление между электродами.
У меня простой, но желающий выглядеть правильным.
Меряю сопротивление между электродами сначала в одну сторону, затем меняю полярность и меряю в другую. Результатом будет среднеарифметическое между двумя замерами.
Вот схема подключения (сорри, я не сенсей Paint-а):

Принцип следующий: подаем +5вольт на 49 цифровом пине. Электроды и нижний резистор составляют делитель напряжения, между ними А15-ым пином меряем падение напряжения на нижнем резисторе. Зная его, по формулам вычисляем сопротивление между электродами. Затем переводим 49-й пин в режим INPUT (физически это означает подключение внутреннего 100МОм-ного резистора), запирая его, чтобы через него не шел ток при обратном замере. Далее подаем напряжение на 51-й пин. Теперь уже электрод с верхним резистором образует делитель напряжения и мы замеряем падение на верхнем резисторе пином А14. Ну и снова находим сопротивление. Получается слабое подобие переменного напряжения.
Электропроводность есть величина, обратная сопротивлению, поэтому далее вычисляем ррм формулой К*1/R, где К - коэффициент, подбираемый опытным путем. В моем случае он равен 179000. Калибровка производится с помощью китайского TDS-метра.
А.
float tds = 0;                     
int tds_1 = 0;
int tds_2 = 0;
float tds_volt = 0;               //в вольтах
float tds_res = 0;                //сопротивление
float tds_ppm = 0;                //ррм
long TDS_last_time;
В.
pinMode(A15, INPUT);                              //TDS-пины
pinMode(49, OUTPUT);
pinMode(51, OUTPUT);
pinMode(A14, INPUT);
С.
TDS(1000);
D.
void TDS(int freq){
  if((millis()-TDS_last_time)>freq){

      pinMode(49, OUTPUT);
      digitalWrite(49, 1);
      tds_1 = analogRead(A15);
      digitalWrite(49, 0);
      pinMode(49, INPUT);

      pinMode(51, OUTPUT);
      digitalWrite(51, 1);
      tds_2 = analogRead(A14);
      digitalWrite(51, 0);
      pinMode(51, INPUT);
       
      tds = (float)tds_1 + ((float)(tds_2-tds_1)) / 2;
      tds_volt = (float)tds*5/1023;
      tds_res = 1000.0*5.0/tds_volt-1000.0;
      tds_ppm = 179000 / (tds_res);
     
   TDS_last_time = millis();
  }
}
« Последнее редактирование: 22 Ноябрь 2017, 03:30:31 от Ann »

Онлайн Ann

  • Глобальный модератор
  • Habanero
  • *****
  • Сообщений: 1533
  • Лойсы: +120/-0
    • Просмотр профиля
Этап 8. Реле LED-освещения.
Поскольку со светом у меня разброд и шатание, то использоваться будет 5 каналов:
Одна лампа красный, синий, белый - 19 вольтовая.
Одна преимущественно красный - 42 вольтовая
Одна - смешанная 220 вольтовая.
Поскольку напряжение у всех разное то и управлять будем 5 каналами.
Напомню, я люблю использовать рассветы и закаты, в начале и конце дня у меня включаются только красные, в середине дня ним добавляются синие.
Время выключения жестко привязано к 21 часу вечера, время влючения вычисляется в зависимости от установленной продолжительности работы.
Кроме того, нужна работа в ручном режиме, для "полюбоваться и селфи", возможность отключать каналы по желанию, и включать только белый.
Еще опрос часов я вывел в отдельную функцию для удобства и добавил туда вычисление времени включения и выключения.
А.
RTC_DS3231 rtc;
int time_current_h;
int time_current_m;
int time_current_s;
String time_current_string;
int time_red_on;
int time_red_off=21;
int time_blue_on;
int time_blue_off;
int time_red_duration;
int time_blue_duration;
boolean den;
unsigned long rtc_last_time;

boolean red = 0;
boolean blue = 0;
boolean white = 0;
boolean manual = 0;
В.
pinMode(31, OUTPUT);                              //LED-пины
pinMode(33, OUTPUT);
pinMode(35, OUTPUT);
pinMode(37, OUTPUT);
pinMode(39, OUTPUT);
pinMode(41, OUTPUT); 
С.
Clock(1000);
Rele();
D.
void Clock(int freq){
  if((millis()-rtc_last_time)>freq){
    DateTime now = rtc.now();
    time_current_h = now.hour();
    time_current_m = now.minute();
    time_current_s = now.second();
    time_current_string = (String)time_current_h + ":" + (String)time_current_m + ":" + (String)time_current_s;

    time_red_on = 21 - time_red_duration;
    time_blue_on = (21 - time_red_duration/2) - time_blue_duration/2;
    time_blue_off = (21 - time_red_duration/2) + time_blue_duration/2;

    if(time_red_on < 21 && time_red_on >= (21 - time_red_duration) ) {den=true; }
    else{ den = false;}
    rtc_last_time = millis();
  }
}

void Rele(){
  if(!manual){
    if(time_current_h >= time_red_on && time_current_h <time_red_off) {
      digitalWrite(31, HIGH);
      digitalWrite(39, HIGH);
      red = 1;
    }else{
      digitalWrite(31, LOW);
      digitalWrite(39, LOW);
      red = 0;
    }

    if(time_current_h >= time_blue_on && time_current_h <time_blue_off) {
      digitalWrite(33, HIGH);
      digitalWrite(35, HIGH);
      digitalWrite(41, HIGH);
      blue= 1;
    }else{
      digitalWrite(33, LOW);
      digitalWrite(35, LOW);
      digitalWrite(41, LOW);
      blue= 0;
    }
  }else{
      digitalWrite(31, red);
      digitalWrite(39, red);
      digitalWrite(33, blue);
      digitalWrite(41, blue);
      digitalWrite(35, white);
  }
}

Онлайн Ann

  • Глобальный модератор
  • Habanero
  • *****
  • Сообщений: 1533
  • Лойсы: +120/-0
    • Просмотр профиля
Этап 9. Любуемся.
Итак, работа по железной части уже закончена, можно перекурить и полюбоваться результатом. На удивление компактно получилось.


Еще я заменил 1кОм-ные резисторы TDS-метра на 440 Ом (более подходят по диапазону), т.е. последовательно 2х220 Ом.
Также, поскольку осталось свободное место на плате, добавил фильтры по питанию на шину питания 12вольт (конденсатор 16вольт 1000мкФ) и 5вольт (конденсатор 6.3вольта 2200мкФ). Плохое питание часто приводит к проблемам, снижается точность датчиков, отваливается вайфай у Вемоса, поэтому будут не лишними.

Это виду снизу (осторожно, 18+):


И еще, как подсказывает мне мой опыт, крайне полезно зарисовать схему подключения с указанием распиновки и полюсовки, поскольку через пару лет, когда захочется что-то переделать, трудно потом вспоминать, что где куда и откуда.


Оффлайн vadkoff

  • Habanero
  • *****
  • Сообщений: 959
  • Лойсы: +75/-2
    • Просмотр профиля
Если бы я понимал что-то, то прокомментировал, но могу сказать что финальный результат визуальный очень компактный и минималистский через призму того, что это существо будет вытворять  :D

Онлайн Ann

  • Глобальный модератор
  • Habanero
  • *****
  • Сообщений: 1533
  • Лойсы: +120/-0
    • Просмотр профиля
Этап 10. Повышаем точность датчиков.
Все датчики имеют разброс показаний, мой DHT-21, несмотря на то, что не самый дешевый, показывает температуру +/- 1 градус. TDS-метр тоже не отличается высокой повторяемостью показаний.
Для получения более стабильных и точных показателей будем делать несколько десятков замеров, а затем из них уже вычислять итоговое значение.
Здесь есть несколько вариантов. Я буду использовать медиану и скользящее среднеарифметическое.
Сделал три функции Mediana, Sort, Ariphmetic.
Mediana.
Ей мы скармливаем массив дробных чисел, указываем размер этого массива и "фактор" (для корректной работы они должны быть четными).
Она сортирует этот массив по возрастанию, затем берет несколько значений строго со средины уже отсортированного массива (сколько именно, указывает "фактор") и находит из них среднеарифметичское. Например Mediana(array, 20, 4) возьмет массив размером 20 значений, отсортирует его по возрастанию, затем возьмет с 9 по 12 значения из уже отсортированного массива и вернет их среднеарифметическое.
Функция Ariphmetic просто возвращает среднеарифметическое. Sort сортирует.
Для DHT-21, датчика давления и TDS-метр я буду использовать медиану. Dallas имеет высокую повторяемость показаний, единственный минус в их дискретности, поэтому для него будем использовать скользящее среднее.
Объявим для каждого датчика по массиву (для  DHT-21 два, для темп. и влажности), и там, где мы получали их значения, теперь будем заносить замеры в массив, а когда он заполнится, вызовем соотв. функции и найдем из массивов итоговое значение.
Результат получается прекрасный, повторяемость показаний увеличивается примерно на 2 порядка.

А.
float baro_array[16];
int baro_array_index;
float DALLAS_array[10];
int DALLAS_array_index;
float DHT_temperature_array[20];
float DHT_humidity_array[20];
int DHT_array_index;
float tds_array[100];
int tds_array_index;
В.
С.
D.
В функции Klimat, заменим на
 baro_array[baro_array_index] = bmp.readPressure()/133.322;
    baro_array_index++;
    if (baro_array_index > 15){
      baro_array_index = 0;
      baro_pressure = Mediana(baro_array, 16, 4);
      }

    DHT_temperature_array[DHT_array_index] = dht.readTemperature();
    DHT_humidity_array[DHT_array_index] = dht.readHumidity();
    DHT_array_index++;
    if(DHT_array_index > 19){
      DHT_array_index = 0;
      DHT_temperature = Mediana(DHT_temperature_array, 20, 6);
      DHT_humidity = Mediana(DHT_humidity_array, 20, 6);
      }

В TDS:
 tds_array[tds_array_index] = tds_calibration * 1000 / (tds_res);
      tds_array_index++;
      if(tds_array_index > 99) {
        tds_array_index = 0;
        tds_ppm = Mediana(tds_array, 100, 20);
        }   

В Dallas:
DALLAS_array[DALLAS_array_index] = (float)raw / 16.0;
    DALLAS_array_index++;
    if(DALLAS_array_index > 9) DALLAS_array_index = 0;
    DALLAS_temperature = Ariphmetic(DALLAS_array, 10);

В

И добавим эти функци:
float Mediana(float array[], int razmer, int factor){
 
  Sort(array, razmer);
  int start = razmer/2-factor/2;
  float summa =0;
    for (int n = start; n < start+factor ; n++){         
        summa += array[n];
    }
  return summa/factor;
}


void Sort(float array[], int razmer){
  int min;
  float smena;
  for (int n = 0; n <  razmer ; n++){                 
        min = n;
        for(int j = n+1; j <  razmer ; j++){             
            if(array[j] < array[min]){
                    min = j;
            }
        }
        smena = array[n];
        array[n] = array [min];
        array [min] = smena;
    }
}


float Ariphmetic(float array[], int razmer){
  float summa =0;
    for (int n = 0; n < razmer ; n++){         
        summa += array[n];
    }
    return summa / razmer;         
}

Онлайн Ann

  • Глобальный модератор
  • Habanero
  • *****
  • Сообщений: 1533
  • Лойсы: +120/-0
    • Просмотр профиля
Этап 11. Составляем карту настроек.
Теперь, поскольку наша Мега уже меряет все, что необходимо, пришла пора уже передавать в Вемос реальные данные. Заодно нужно определиться с кругом настроек, изменение которых нужно будет предусмотреть в системе.
Итак, будем формировать реальную строку информации, которая будет отправляться в Вемос.
Сначала у нас идут 5 данных с датчиков:
    String stroka = "<";   
    stroka += (String)DHT_temperature + ","; 
    stroka += (String)DHT_humidity + ",";
    stroka += (String)baro_pressure + ",";
    stroka += (String)DALLAS_temperature + ",";
    stroka += (String)tds_ppm + ",";

Далее настройки по свету
    stroka += (String)time_red_duration + ",";   //продолжительность светового дня красных
    stroka += (String)time_blue_duration + ",";  //продолжительность светового дня синих
    stroka += (String)red + ",";                           //флаг горения красного канала. Будут использоваться как для отображения, так и для управления в ручном режиме
    stroka += (String)blue + ",";                         //флаг горения синего канала
    stroka += (String)white + ",";                        //флаг горения белого канала
    stroka += (String)manual + ",";                     //флаг ручного режима

Далее одна настройка для целевой температуры подогрева раствора:
    stroka += (String)pechka_rastvor_temp + ",";
Затем блок настроек вентилятора, описывать не буду, из названий и так понятно:
    stroka += (String)carlson_temperature + ",";
    stroka += (String)carlson_night_power + ",";
    stroka += (String)carlson_day_power + ",";
    stroka += (String)carlson_extrime_power + ",";
    stroka += (String)carlson_freq + ",";
    stroka += (String)carlson_dlit + ",";
    stroka += (String)carlson_flag + ",";

То же для помпы:
    stroka += (String)pompa_freq + ",";
    stroka += (String)pompa_dlit + ",";
    stroka += (String)pompa_manual + ",";
    stroka += (String)pompa_flag + ",";

И время:
    stroka += (String)time_current_h + ",";
    stroka += (String)time_current_m + ",";
    stroka += (String)time_current_s + ">";


Онлайн Ann

  • Глобальный модератор
  • Habanero
  • *****
  • Сообщений: 1533
  • Лойсы: +120/-0
    • Просмотр профиля
Этап 12. Составлем карту команд на изменение настроек.
Теперь придумаем и пропишем команды, которые будет нам давать Вемос, а Мега принимать и соответственно менять свои настройки. В принципе все они корреспондируют карте настроек, но некоторые имеют свои особенности,  и также нужно еще добавить команду калибровки ТДС-метра, которая в настройках отсутствует. Сначала пропишем их прием в Меге, а затем продублируем отправку в Вемосе.
По калибровке ТДС-метра принцип такой: пользователь замеряет ррм реальным китайским ррм-метром, вводит значение и отправляет в Мегу. Мега сравнивает пользовательское значение со своим и корректирует коэфф. умножения, чтобы выйти на пользовательский уровень.
По часам прописаны команды точной настройки часов.

      if(value[0] == "Red"){        time_red_duration = value[1].toInt();      }

      if(value[0] == "Blue"){        time_blue_duration = value[1].toInt();      }

      if(value[0] == "r"){
        manual = 1;
        red = value[1].toInt();
      }

      if(value[0] == "b"){
         manual = 1;
        blue = value[1].toInt();
      }

      if(value[0] == "w"){
         manual = 1;
        white = value[1].toInt();
      }

      if(value[0] == "m"){
        manual = value[1].toInt();
      }

    if(value[0] == "rastvor"){
        pechka_rastvor_temp = value[1].toInt();
      }

      if(value[0] == "Ct"){
        carlson_temperature = value[1].toInt();
      }

      if(value[0] == "Cnp"){
        carlson_night_power = value[1].toInt();
      }

      if(value[0] == "Cdp"){
        carlson_day_power = value[1].toInt();
      }

      if(value[0] == "Cep"){
        carlson_extrime_power = value[1].toInt();
      }

      if(value[0] == "Cf"){
        carlson_freq = value[1].toInt();
      }

      if(value[0] == "Cd"){
        carlson_dlit = value[1].toInt();
      }

      if(value[0] == "Pf"){
        pompa_freq = value[1].toInt();
      }

      if(value[0] == "Pd"){
        pompa_dlit = value[1].toInt();
      }

      if(value[0] == "Pm"){
        pompa_manual = value[1].toInt();
      }

       if(value[0] == "Pflag"){
        pompa_flag = value[1].toInt();
      }

      if(value[0] == "Th"){
        int hh = value[1].toInt();
        DateTime now = rtc.now();
        rtc.adjust(DateTime(now.year(), now.month(), now.day(), hh, now.minute(), now.second()));
      }

      if(value[0] == "Tm"){
        int mm = value[1].toInt();
        DateTime now = rtc.now();
        rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), mm, now.second()));
      }

      if(value[0] == "Ts"){
        int ss = value[1].toInt();
        DateTime now = rtc.now();
        rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute(), ss));
      }

      if(value[0] == "cal"){
        tds_calibration = tds_calibration * (value[1].toInt()/tds_ppm);
      }

      if(value[0] == "I"){
        Send_to_Wemos();
        }