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

Онлайн Ann

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

Объявляем список адресов куда будем сохранять
#define EE_RED_duration 0
#define EE_BLUE_duration 1
#define EE_POMPA_freq 2
#define EE_POMPA_dlit 3
#define EE_TDS_correct 4
#define EE_pechka 5
#define EE_C_temp 6
#define EE_C_np 7
#define EE_C_dp 8
#define EE_C_ep 9
#define EE_C_dlit 10
#define EE_C_freq 11

В Setup при старте программы мы их загружаем
 time_red_duration = EEPROM.read(EE_RED_duration);
  time_blue_duration = EEPROM.read(EE_BLUE_duration);
  pompa_freq = EEPROM.read(EE_POMPA_freq);
  pompa_dlit = EEPROM.read(EE_POMPA_dlit);
  tds_calibration = EEPROM.read(EE_TDS_correct) * 1000;
  pechka_rastvor_temp = EEPROM.read(EE_pechka);
  carlson_temperature = EEPROM.read(EE_C_temp);
  carlson_night_power = EEPROM.read(EE_C_np);
  carlson_day_power = EEPROM.read(EE_C_dp);
  carlson_extrime_power = EEPROM.read(EE_C_ep);
  carlson_freq = EEPROM.read(EE_C_freq);
  carlson_dlit  = EEPROM.read(EE_C_dlit);

А при изменении настроек (из предыдущего этапа) сохраняем. Не буду снова дублировать весь перечень команд, далее выложу весь скетч, будет видно.

Онлайн Ann

  • Глобальный модератор
  • Habanero
  • *****
  • Сообщений: 1533
  • Лойсы: +120/-0
    • Просмотр профиля
Этап 14. Итоговый скетч для Меги. Оценка производительности, необходимость оптимизации.
Итак, скетч для Меги можно считать оконченным. Получилось 580 строк грязного кода (если пробежать и повыкидывать лишнее, можно до 300-400 ужать).
Arduino IDE заболиво сообщает нам:
Скетч использует 20854 байт (8%) памяти устройства. Всего доступно 253952 байт.
Глобальные переменные используют 1511 байт (18%) динамической памяти, оставляя 6681 байт для локальных переменных. Максимум: 8192 байт.

Так что еще есть куда расти.
Не лишним будет глянуть, нет ли где затыков (провалов производительности). Для этого делаем счетчик в Лупе, каждый цикл инкрементируем его, раз в секунду выводим его в монитор. Вот примерно такая такая картина получилась
8778
8459
8764
8549
8766
8549
8699
8377
8688
8626
8688
8626
8686
8627
8777
8459
8699
8378
8776
8541
8700
8617
Т.е. наш главный цикл выполняется 8 тыс. раз в секунду. Запас производительности - порядки.

Вот итоговый скетч
#include <RTClib.h>
#include <Adafruit_BMP085.h>
#include "DHT.h"
#include <OneWire.h>
#include <EEPROM.h>

//***********BMP085***************************************
Adafruit_BMP085 bmp;
float baro_temperature;
float baro_pressure;
float baro_array[16];
int baro_array_index;

//******DHT-21*******************************************
#define DHTPIN 23
#define DHTTYPE DHT21
DHT dht(DHTPIN, DHTTYPE);
float DHT_temperature;                                           
float DHT_humidity;
float DHT_temperature_array[20];
float DHT_humidity_array[20];
int DHT_array_index;


//******Dallas*******************************************
OneWire  ds(27);
byte dallas_data[2];
byte addr[8] = {0x28, 0x95, 0x15, 0xAE, 0x8, 0x0, 0x0, 0x73};
long dallas_last_time;
boolean dallas_flag;
float DALLAS_temperature;
float DALLAS_array[10];
int DALLAS_array_index;

//************DS3231*************************************
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 = 12;
int time_blue_duration = 8;
boolean den;
unsigned long rtc_last_time;

//************Carlson*************************************
int carlson_pin = 5;
int carlson_temperature = 30;
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;
long carlson_last_time;

//************Pechka*************************************
int pechka_pin = 4;
int pechka_rastvor_temp = 25;
long pechka_last_time;

//************Pompa*************************************
int pompa_pin = 53;
long pompa_freq=60;
long pompa_dlit=5;
long pompa_last_time;
boolean pompa_flag = false;
boolean pompa_manual = false;

//************TDS*************************************
float tds = 0;                      //прочитанное значение из А10
int tds_1 = 0;
int tds_2 = 0;
float tds_volt = 0;               //в вольтах
float tds_res = 0;                //сопротивление
float tds_ppm = 0;                //ррм
long tds_calibration = 179000;
float tds_array[100];
int tds_array_index;
long TDS_last_time;

//************Svet*************************************
boolean red = 0;
boolean blue = 0;
boolean white = 0;
boolean manual = 0;

//************EEPROM*************************************
#define EE_RED_duration 0
#define EE_BLUE_duration 1
#define EE_POMPA_freq 2
#define EE_POMPA_dlit 3
#define EE_TDS_correct 4
#define EE_pechka 5
#define EE_C_temp 6
#define EE_C_np 7
#define EE_C_dp 8
#define EE_C_ep 9
#define EE_C_dlit 10
#define EE_C_freq 11

long klimat_last_time;
long data_last_time;
String receive_string;

//========================================================
//========================================================
void setup() {
  bmp.begin();
  rtc.begin();
  dht.begin();
  Serial.begin(115200);
  Serial1.begin(115200);
 
  pinMode(pechka_pin, OUTPUT);         //SLED
  pinMode(carlson_pin, OUTPUT);         //GND
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);

  pinMode(pompa_pin, OUTPUT);
 
  pinMode(A15, INPUT);                              //TDS-пины
  pinMode(49, OUTPUT);
  pinMode(51, OUTPUT);
  pinMode(A14, INPUT);

  pinMode(31, OUTPUT);                              //LED-пины
  pinMode(33, OUTPUT);
  pinMode(35, OUTPUT);
  pinMode(37, OUTPUT);
  pinMode(39, OUTPUT);
  pinMode(41, OUTPUT);

  time_red_duration = EEPROM.read(EE_RED_duration);
  time_blue_duration = EEPROM.read(EE_BLUE_duration);
  pompa_freq = EEPROM.read(EE_POMPA_freq);
  pompa_dlit = EEPROM.read(EE_POMPA_dlit);
  tds_calibration = EEPROM.read(EE_TDS_correct) * 1000;
  pechka_rastvor_temp = EEPROM.read(EE_pechka);
  carlson_temperature = EEPROM.read(EE_C_temp);
  carlson_night_power = EEPROM.read(EE_C_np);
  carlson_day_power = EEPROM.read(EE_C_dp);
  carlson_extrime_power = EEPROM.read(EE_C_ep);
  carlson_freq = EEPROM.read(EE_C_freq);
  carlson_dlit  = EEPROM.read(EE_C_dlit);
 
}
//========================================================
//========================================================
void loop() {
  Klimat(2000);
  Receive_from_Wemos();
  Dallas(2000);
  Carlson();
  Clock(1000);
  Pechka();
  Pompa();
  TDS(100);
  Rele();
}
//========================================================
//========================================================

void Klimat(float freq){
  if ((millis()-klimat_last_time)>freq){
    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);
      }
     
    //Serial.println( time_current_string );
    //Serial.println( "                                   baro: " + (String)baro_pressure);
    //Serial.println( "          " + (String)DHT_temperature + "gr " + (String)DHT_humidity+"%" );
    //Serial.println( "                   DALLAS_temperature - " + (String)DALLAS_temperature );
    //Serial.println("             tds_ppm:" + (String)tds_ppm );
    klimat_last_time = millis();
  }
}

//--------Часы---------------------------------------------------------
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 Receive_from_Wemos(){
  while (Serial1.available() > 0) {         
    char incomig_char = Serial1.read();                          //прием строки
    receive_string += (String)incomig_char;
    if ((String)incomig_char == ">") {
      String stroka = receive_string;
      receive_string = "";
      //Serial.println(stroka);
      stroka = stroka.substring(0,stroka.length()-1);
         
      String value[2];
      /*
      int index = 0;                                            //разбитие строки и занесение в массив
      char separator = '_';
      int strIndex[] = { 0, -1 };
      int maxIndex = stroka.length() - 1;
      for (int i = 0; i <= maxIndex; i++) {
        if (stroka.charAt(i) == separator || i == maxIndex) {
            strIndex[0] = strIndex[1] + 1;
            strIndex[1] = (i == maxIndex) ? i+1 : i;
            value[index] = stroka.substring(strIndex[0], strIndex[1]);
            index++;
        }
      }
*/
      int i = stroka.indexOf('_');
      value[0] = stroka.substring(0,i);
      value[1] = stroka.substring(i+1,stroka.length());
      //Serial.println(" value[0] " +  value[0]);
      //Serial.println(" value[1] " +  value[1]);
      if(value[0] == "Red"){
        time_red_duration = value[1].toInt();
        EEPROM.write(EE_RED_duration, time_red_duration);
      }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      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);
        EEPROM.write(EE_TDS_correct, (int)(tds_calibration/1000));
      }

      if(value[0] == "I"){
        Send_to_Wemos();
        //Serial.println(" sEND to Wemos ");
      }
    }
  }
}

void Send_to_Wemos(){
 
    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 + ">";
       
    Serial1.print(stroka);
}

//---------Dallas-------------------------------------------------------
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_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);
   
    dallas_flag = false;
    }
 }

//---------Carlson-------------------------------------------------------
void Carlson(){
  if(den && DHT_temperature < carlson_temperature ){
    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 >= carlson_temperature && DHT_temperature < carlson_temperature+1){
     analogWrite(carlson_pin, (int)(carlson_day_power*2.55));
    }

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

//---------Pechka-------------------------------------------------------
void Pechka(){
  if(den && DALLAS_temperature < pechka_rastvor_temp ){
     digitalWrite(pechka_pin, HIGH);
   }else{
    digitalWrite(pechka_pin, LOW);
   }
}

//----------Помпа-------------------------------------------------
void Pompa(){
  if(!pompa_manual){
    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;
    }
  }else{
      digitalWrite(pompa_pin, pompa_flag);
  }
}

//--------TDS---------------------------------------------------------
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 = 440.0*5.0/tds_volt-440.0;

      tds_array[tds_array_index] = tds_calibration / (tds_res);
      tds_array_index++;
      if(tds_array_index > 99) {
        tds_array_index = 0;
        tds_ppm = Mediana(tds_array, 100, 20);
        }     
     
     
      //Serial.println("          TDS1:" + (String)tds );
        //Serial.println("          tds_volt:" + (String)tds_volt );
          //Serial.println("          tds_res:" + (String)tds_res );
           
   
   TDS_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);
  }
}

//*******************************************************************************
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;         
}

Оффлайн alex_step

  • Serrano
  • ***
  • Сообщений: 181
  • Лойсы: +5/-2
  • Александр, Украина, Жмеринка
    • Просмотр профиля
какие модификации нужны для отображения EC не в ppm, а в ms/cm (а лучше в μS/cm)?

(Как известно, ЕС в ppm приводят по шкале в 500 / 550 / 640 либо 700. А в миллисименсах-на-см таки однозначное значение...)
« Последнее редактирование: 24 Ноябрь 2017, 05:02:25 от alex_step »

Онлайн Ann

  • Глобальный модератор
  • Habanero
  • *****
  • Сообщений: 1533
  • Лойсы: +120/-0
    • Просмотр профиля
какие модификации нужны для отображения EC не в ppm, а в ms/cm?
Вот эта строка, которая меряет уже окончательный ррм.
tds_array[tds_array_index] = tds_calibration / (tds_res);
 tds_calibration - это тот коэф., который и определяет наши попугаи, подбирался опытным путем, при работе в момент калибровки будет сам изменятся.
В моем случае он 179000. Если бы я хотел видеть попугаи в виде ms/cm, то поделил бы его на 500. Ну или если бы у меня был прибор, отображающий ms/cm, то подобрал бы его опытным путем так, чтобы показания прибора и меги совпадали.

Онлайн Ann

  • Глобальный модератор
  • Habanero
  • *****
  • Сообщений: 1533
  • Лойсы: +120/-0
    • Просмотр профиля
(Как известно, ЕС в ppm приводят по шкале в 500 / 550 / 640 либо 700. А в миллисименсах-на-см таки однозначное значение...)
Ну, мой пипиметр кажет ррм и имеет коэф. 1:500, поэтому мне так удобней, привык.

Оффлайн alex_step

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

Онлайн Ann

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

Онлайн Ann

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

Онлайн Ann

  • Глобальный модератор
  • Habanero
  • *****
  • Сообщений: 1533
  • Лойсы: +120/-0
    • Просмотр профиля
Этап 16. Поднимаем сервер на Wemos.
Когда-то я описывал подробно как это осуществлять, поэтому отделаюсь копипастом.

Подключаем библиотеки
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
Вводим параметры сети либо для подключения к роутеру в режиме "клиент" (его параметры) либо для создания своей точки доступа в этими параметрами.
const char* ssid = "Wemos";
const char* password = "11111111";
Объявляем сервер. здесь важно объявить сервер библиотеки именно ESP8266WebServer.h. Сервер можно сделать и с библиотекой ESP8266WiFi, но с ним я намучался, то виснет, то связь пропадает, а вот с ESP8266WebServer.h работает очень стабильно, ни разу зависаний не было, пару раз пропадала связь, но то возможно из-за роутера, после перезагрузки роутера, связь налаживалась.
ESP8266WebServer server(80);
Далее идут функции обработки запросов, которые будут поступать на сервер.
Это функция при попадании на главную страницу сервера, т.е. если в браузере в главной строке введем 192.168.0.13. В ответ сервер посылает код успеха "200", тип ответных данных "text/html", в char temp можно записать любую html-страничку

void handleRoot() {
  char temp[2000];
  server.send(200, "text/html", temp);
}
Обработка "непонятного серверу" запроса. Ошибка 404.
void handleNotFound(){
  String message = "404. Not Found\n\n";
  server.send(404, "text/plain", message);
}
Обработка запроса с параметром /data. Т.е. если в браузере наберем 192.168.0.13/data, то в ответ сервер выдаст не страницу, а просто строку с данными. В данном случае с текущим временем. Удобно для обращения не из браузера, а из, например, программы Андроид-телефона.
void handleData() {

  String s = (String)millis();
  server.send(200, "text/plain", s);
}
Обработка запроса с параметром /set. Аргументы пишутся в таком виде 192.168.0.13/set?temp=30. В данном случае, если наберем в браузере такую строку, то переменная set_temp установится в значение 30. Т.е. мы будем управлять устройством, отдавать команды

void handleSet() {
  String a = server.arg(0);
  if(server.argName(0) == "temp") {
    set_temp = a.toFloat();
    }
  server.send ( 200, "text/plain", "Ok!" );
   }

void setup(void){
А вот здесь идут два блока.
Если написатьэтот, то ESP8266 подключится в качестве клиента к Вашему роутеру.

  WiFi.begin(ssid, password);
  Serial.println("");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
 
А если этот, то ESP8266 создаст точку доступа (вроде как сам станет роутером) и можно будет подключиться к нему напрямую с телефона.
  WiFi.softAP(ssid, password);
  IPAddress myIP = WiFi.softAPIP();
  Serial.print(myIP);

А здесь уже настройка сервера, назначаются функции, описанные выше (они должны идти перед стартом сервера) на разные запросы. 
  server.on("/", handleRoot);
  server.on("/data", handleData);
  server.on("/set", handleSet);
  server.onNotFound(handleNotFound);
Старт сервера
  server.begin();
}

В главный цикл нужно добавить одну функцию, которая и будет выполнять все задачи.
void loop(void){
   server.handleClient();
  }

Онлайн Ann

  • Глобальный модератор
  • Habanero
  • *****
  • Сообщений: 1533
  • Лойсы: +120/-0
    • Просмотр профиля
Этап 17. Веб-морда (веб-интерфейс) Wemos.
Скажу сразу: писать веб-морду, т.е. ту страничку, которая будет выдаваться Вемосом при заходе на его адрес, не самое приятное занятие.
Приходится ограничивать полет фантазии, все ж таки ресурсы лимитированы, тулить все в кучу, экранировать символы конца строки и кавычки, скурпулезно осуществлять "форматированный вывод" функцией snprintf, в общем бррр...
Вот для примера как выглядит в Вемосе простейшая страница одного из моих проектов (инкубатора для проращивания семян):
snprintf ( s, 2000,
"<html>\
<head>\
  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\
  <title>Инкубатор</title>\
  <style type=\"text/css\">\
    body {background-color:#565145}\
    #glav{width: 500px;margin: 50px auto;font-size: 180%;font-family: sans-serif;text-align: center;}\
    .block{width: 100%;height: 70px;margin-top: 10px;padding-top: 10px;background-color: #37434B;box-shadow: 0px 0px 5px #000000;}\
    .podpis{float: left;text-align: left;color:#111111;width: 45%;margin-top: 10px;margin-left: 10px;}\
    .data{width: 20%;float: left;font-size: 150%;text-shadow: 1px 1px 3px #000;}\
  </style>\
</head>\
<body>\
  <div id=\"glav\">\
    <div class=\"block\">\
      <div class=\"podpis\">Set temp:</div>\
      <div class=\"data\" style=\"color: #66D110\">%s</div>\
      <input id=\"inp_temp\" type=\"text\" size=\"2\">\
      <button style=\"background-color: #E26408; border-radius: 10px\" onclick=\"document.location.href = 'http://192.168.0.13/set?temp='+ document.getElementById('inp_temp').value;\">Set</button>\
    </div>\
    <div class=\"block\">\
      <div class=\"podpis\">Real temp:</div>\
      <div class=\"data\"  style=\"color: #EE710C\">%s</div>\
      <input id=\"cor_temp\" type=\"text\" size=\"2\">\
      <button style=\"background-color: #E26408; border-radius: 10px\" onclick=\"document.location.href = 'http://192.168.0.13/set?correct='+ document.getElementById('cor_temp').value;\">Set</button>\
    </div>\
    <div class=\"block\">\
      <div class=\"podpis\">Power:</div>\
      <div class=\"data\" style=\"color: #E5E200\">%d\%</div>\
      <input id=\"inp_power\" type=\"text\" size=\"2\">\
      <button style=\"background-color: #E26408; border-radius: 10px\" onclick=\"document.location.href = 'http://192.168.0.13/set?power='+ document.getElementById('inp_power').value;\">Set</button>\
    </div>\
    <div class=\"block\">\
      <div class=\"podpis\">Time:</div>\
      <div class=\"data\"  style=\"color: #75718F; font-size: 80%; margin-top: 15px\">%d:%02d:%02d</div>\
    </div>\
  </div>\
</body>\
</html>",
set_temp_c,
real_temp_c,
power,
hr,
min % 60,
sec % 60
);


Размышляя о том, как все прелести минимизировать, мне в голову пришло довольно элегантное решение:
Пускай Вемос выдает нам пустую страницу с одним только iframe (блок, на котором может отображаться страница с другого сайта), растянутым на весь экран, и в этом ифрейме будет отображаться веб-страница с моего облачного сервера, но с параметрами, переданными в виде GET-запросов.
Еще раз, на пальцах. Вемос отдает браузеру пустую страницу с ифреймом и говорит, что в этом ифрейме нужно отобразить страницу с облачного сервера. При этом ссылка на эту страницу содержит GET-параметры (данные прочитанные из Меги). Браузер обращается по этой ссылке, облачный сервер берет все параметры из GET-запроса, формирует с помощью РНР веб-страницу, расставляя полученные данные по нужным местам и отдает браузеру. Браузер отображает её в ифрейме.
Таким образом, написание веб на Вемосе сводится к абсолютному минимуму (что радует) и имеем неограниченные возможности РНР по созданию красивой и функциональной страницы (что вдохновляет).
Ближе к телу.
В массиве receive_array у нас содержатся переданные в строковом виде данные с Меги.
Формируем заголовок страницы:
String site;
site = "<!DOCTYPE html><html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"><title>Wemos</title>";
  site += "<style>#if{position: absolute;}</style></head><body>";

И далее идет ссылка на облачную страницу с GET-параметрами, из нашего массива receive_array
  site += "<iframe id=\"if\" src=\"http://collider.anndrew.ru/Wemos/index.php?";
  for (int i = 0; i < 30; i++){
    site += "P";
    site += (String)i;
    site += "=";
    site += receive_array [i ];
    site += "&";
    }
  site += "\" name=\"my-frame\" width=\"100%\" height=\"2000\" frameborder=\"0\" scrolling=\"no\"></iframe></body></html>";

Ну и теперь отдаем эту страницу юзеру.
  server.send(200, "text/html", site);
Ссылка получается вот такого вида, имя параметра в виде буквы Р с номером, значение параметра число после "="
http://collider.anndrew.ru/Wemos/index.php?   P0=27.2&   P1=68.4&   P2=775.1&P3=22.2&P4=1231.9&P5=14&P6=8&P11=25&P12=30&P13=30&P14=50&P15=80&P16=30&P17=5&P18=1&P19=120&P20=5&P21=23&P22=01&P23=53
Можете нажать на эту ссылку, увидете как будет выглядеть страница. Данные на ней будут вымышленные, т.е те, которые указаны в ссылке. Вемос же будет выдавать точно такую ссылку, но с реальными параметрами.
« Последнее редактирование: 24 Ноябрь 2017, 20:33:06 от Ann »

Оффлайн alex_step

  • Serrano
  • ***
  • Сообщений: 181
  • Лойсы: +5/-2
  • Александр, Украина, Жмеринка
    • Просмотр профиля
стабилизатор напряжения, более мелкий аналог LM1117, модель точно не знаю. В общем он довольно нежненький, при малейшем перегрузе моментально перегревается и сгорает.
Выход из ситуации - берем с Меги эти самые 3.3 вольта и подпаиваем к пину Вемоса 3.3 вольта, таким образом мы напрямую запитываем логику Вемоса, минуя сгоревший стабилизатор. В таком виде Вемос совершенно сохраняет работоспособность, определяется компом при подключении USB, принимает скетчи.
ну тут тебе кагбэ повезло...
в моем почившем Вемосе сгоревшим обнаружен SIL 2104 F01AL  :-\
а причины такие же  ;)

Онлайн Ann

  • Глобальный модератор
  • Habanero
  • *****
  • Сообщений: 1533
  • Лойсы: +120/-0
    • Просмотр профиля
Этап 18. Веб-морда Wemos (облачная часть).
В продолжение предыдущего этапа: а на кой нам вообще iframe? Еще проще сделать переадресацию на облачную страницу и все.
Переадресация делаетс так:
<HTML>
  <HEAD>
    <META HTTP-EQUIV="REFRESH" CONTENT="0; URL=http://www.softtime.ru">
  </HEAD>
  <BODY>
  </BODY>
</HTML>
Следовательно наш ответ в Вемосе примет вид:
 site = "<HTML><HEAD><META HTTP-EQUIV=\"REFRESH\" CONTENT=\"0; URL=http://collider.anndrew.ru/Wemos/index.php?";
  for (int i = 0; i < 30; i++){
    site += "P";
    site += (String)i;
    site += "=";
    site += receive_array [ i ];
    site += "&";
    }
  site +=  "\"</HEAD><BODY></BODY></HTML>";
Проще уже некуда.

Теперь серверная часть. Здесь уже можно разгуляться на все деньги, сделать отдельные скриптовые и стилевые файлы, вставку изображений и т.д. и т.п.
Вот файл index.php. Здесь мы на РНР разбираем параметры GET-запроса, и вставляем их уже в нужные места страницы:
<?php
$temp $_GET['P0'];
$hum $_GET['P1'];
$baro $_GET['P2'];
$dallas $_GET['P3'];
$ppm $_GET['P4'];

$red $_GET['P5'];
$blue $_GET['P6'];
$manual $_GET['P10'];
$r $_GET['P7'];
$b $_GET['P8'];
$w $_GET['p9'];

$calibration $_GET['calibration'];

$rastvor $_GET['P11'];

$c_temp $_GET['P12'];
$c_night $_GET['P13'];
$c_day $_GET['P14'];
$c_extrime $_GET['P15'];
$c_freq $_GET['P16'];
$c_dlit $_GET['P17'];
$c_on $_GET['P18'];

$p_freq $_GET['P19'];
$p_dlit $_GET['P20'];

$time_h $_GET['P21'];
$time_m $_GET['P22'];
$time_s $_GET['P23'];

?>


<!DOCTYPE html>
<html>
 <head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <title>Wemos</title>
  <link rel="icon" href="images/favicon.ico" type="image/x-icon">
<link rel="stylesheet" type="text/css" href="style.css">
<script type="text/javascript" src="script.js"></script>
 </head>
 <body>
<div id="glav">
<div class="razdel" id="klimat">
<div class="block klimat">
<div class="podpis">Температура:</div>
<div class="data" id="temp"><?php echo $temp ?> °С</div>
</div>
<div class="block klimat">
<div class="podpis">Влажность:</div>
<div class="data" id="hum"><?php echo $hum ?> %</div>
</div>
<div class="block klimat">
<div class="podpis">Давление:</div>
<div class="data" id="baro"><?php echo $baro ?> mm</div>
</div>
<div class="block klimat">
<div class="podpis">Раствор:</div>
<div class="data" id="temp"><?php echo $dallas ?> °С</div>
</div>
<div class="block klimat">
<div class="podpis">TDS:</div>
<div class="data" id="ppm"><?php echo $ppm ?> ppm</div>
<input class="pole_vvoda" id="inp_calibr" type="text" size="2">
</div>
</div>
<div class="razdel" id="svet">
<div class="block svet">
<div class="podpis">Красные диоды:</div>
<div class="data" id="red"><?php echo $red  ?> часов</div>
<input class="pole_vvoda" id="inp_red" type="text" size="2">
</div>
<div class="block svet">
<div class="podpis">Синие диоды:</div>
<div class="data" id="blue"><?php echo $blue ?> часов</div>
<input class="pole_vvoda" id="inp_blue" type="text" size="2">
</div>
</div>

<div class="razdel" id="carlson">
<div class="block carlson">
<div class="podpis">Температура:</div>
<div class="data" id="carlson_temp"><?php echo $c_temp  ?> °С</div>
<input class="pole_vvoda" id="inp_c_temp" type="text" size="2">
</div>
<div class="block carlson">
<div class="podpis">Мощность ночная:</div>
<div class="data" id="carlson_np"><?php echo $c_night ?> %</div>
<input class="pole_vvoda" id="inp_c_night" type="text" size="2">
</div>
<div class="block carlson">
<div class="podpis">Мощность дневная:</div>
<div class="data" id="carlson_dp"><?php echo $c_day  ?> %</div>
<input class="pole_vvoda" id="inp_c_day" type="text" size="2">
</div>
<div class="block carlson">
<div class="podpis">Мощность extrime:</div>
<div class="data" id="carlson_ep"><?php echo $c_extrime ?> %</div>
<input class="pole_vvoda" id="inp_c_extrime" type="text" size="2">
</div>
<div class="block carlson">
<div class="podpis">Частота:</div>
<div class="data" id="carlson_f"><?php echo $c_freq  ?> минут</div>
<input class="pole_vvoda" id="inp_c_freq" type="text" size="2">
</div>
<div class="block carlson">
<div class="podpis">Длительность:</div>
<div class="data" id="carlson_d"><?php echo $c_dlit ?> минут</div>
<input class="pole_vvoda" id="inp_c_dlit" type="text" size="2">
</div>

</div>

<div class="razdel" id="poliv">
<div class="block poliv">
<div class="podpis">Частота полива:</div>
<div class="data" id="freq"><?php echo $p_freq ?> минут</div>
<input class="pole_vvoda" id="inp_freq" type="text" size="2">
</div>
<div class="block poliv">
<div class="podpis">Длительность:</div>
<div class="data" id="dlit"><?php echo $p_dlit  ?> минут</div>
<input class="pole_vvoda" id="inp_dlit" type="text" size="2">
</div>
</div>

<div class="razdel" id="podogrev">
<div class="block podogrev">
<div class="podpis">Подогрев до:</div>
<div class="data" id="podogrev_data"><?php echo $rastvor  ?> °С</div>
<input class="pole_vvoda" id="inp_podogrev" type="text" size="2">
</div>
</div>

<div class="razdel" id="time_razdel">
<div class="block time">
<div class="podpis">Время:</div>
<div class="data" id="time"><?php echo $time_h ?>:<?php echo $time_m ?>:<?php echo $time_s ?></div>
</div>
</div>
<button class="button_set" onclick="click_setup()">Setup</button>
</div>


</body>
</html>

Файл стиля style.css
html, body{
    height: 100%;
}
body {background-color:#2D3741}
#glav{
width: 100%;
max-width: 720px;
min-width: 600px;
margin: 0px auto;
font-size: 30px;
font-family: sans-serif;
text-align: center;
}
.razdel{
margin-top: 10px;
background-color: #009688;
box-shadow: 0px 0px 5px #000000;
}
#klimat{
background-color: #E6B213;
}
#svet{
background-color: #FDBCBC;
}
#poliv{
background-color: #686CC6;
}
#time_razdel{
background-color: #A2A2A2;
}

.block{
border-style: solid;
padding-top: 20px;
height: 50px;
clear: both;
}
.klimat{
background-image: url(images/green2.png);
}
.svet{
background-image: url(images/orange.png);
}
.poliv{
background-image: url(images/blue3.png);
}
.carlson{
background-image: url(images/green.png);
}

.podogrev{
background-image: url(images/auto2.png);
}

.time{
background-image: url(images/grey.png);
}
.podpis{
float: left;
text-align: left;
width: 40%;
margin-left: 10px;
}
.data{
width: 25%;
text-align: center;
float: left;
text-shadow: 1px 1px 3px #000;
}
.pole_vvoda{
width: 7%;
font-size: 70%;
margin: auto;
}
.button_set{
background-image: url(images/auto2.png);
font-size: 120%;
color: #C8C8C8;
text-shadow: 1px 1px 3px #000;
margin: 10px 0px;
background-color: #E26408;
border-radius: 5px;
height: 70px;
padding: 10px;
width: 30%;
}
#temp{
color: #B00303;
}
#hum{
color: #0CAEEA;
}
#baro{
color: #D18F10;
}
#red{
color: #ff0000;
}
#blue{
color: #0000ff;
}
#carlson_temp{
color: #FF9E21;
}
#carlson_np{
color: #000000;
}
#carlson_dp{
color: #fff;
}
#carlson_ep{
color: #f00;
}
#carlson_f{
color: #9B0ED6;
}
#carlson_d{
color: #15E4BF;
}

#freq{
color: #9B0ED6;
}
#dlit{
color: #15E4BF;
}
#podogrev_data{
color: #FFF4C7;
}
#time{
color: #75718F;
}

Скриптовый script.js. Здесь остановлюсь подробнее. Файл содержит одну единственную функцию - обработчик нажания кнопки Setup. При нажатии происходит сбор данных с полей для изменения настроек, если они не пустые, берется текущее системное время (чтоб подстроить под него время Меги), формируется строка с GET-запросом на адрес Вемоса (в моем случае это 192.168.0.44) и делается переход по этому адресу с GET-параметрами. Разумеется это будет работать только у меня в квартире, поскольку 192.168.0.44 - это локальный адрес моего Вемоса.
function click_setup(){

var date = new Date();
var s =
'Th='+date.getHours()+'&'+
'Tm='+date.getMinutes()+'&'+
'Ts='+date.getSeconds()+'&';
if(document.getElementById('inp_red').value != "") s+='Red='+document.getElementById('inp_red').value+'&';
if(document.getElementById('inp_blue').value != "") s+='Blue='+document.getElementById('inp_blue').value+'&';
if(document.getElementById('inp_freq').value != "") s+='Pf='+document.getElementById('inp_freq').value+'&';
if(document.getElementById('inp_dlit').value != "") s+='Pd='+document.getElementById('inp_dlit').value+'&';

if(document.getElementById('inp_calibr').value != "") s+='calibration='+document.getElementById('inp_calibr').value+'&';
if(document.getElementById('inp_podogrev').value != "") s+='rastvor='+document.getElementById('inp_podogrev').value+'&';

if(document.getElementById('inp_c_temp').value != "") s+='Ct='+document.getElementById('inp_c_temp').value+'&';
if(document.getElementById('inp_c_night').value != "") s+='Cnp='+document.getElementById('inp_c_night').value+'&';
if(document.getElementById('inp_c_day').value != "") s+='Cdp='+document.getElementById('inp_c_day').value+'&';
if(document.getElementById('inp_c_extrime').value != "") s+='Cep='+document.getElementById('inp_c_extrime').value+'&';
if(document.getElementById('inp_c_freq').value != "") s+='Cf='+document.getElementById('inp_c_freq').value+'&';
if(document.getElementById('inp_c_dlit').value != "") s+='Cd='+document.getElementById('inp_c_dlit').value+'&';

document.location.href = 'http://192.168.0.44/set?'+s;
};

Дизайн был выбран исходя из соображений удобства работы на телефоне.
В планах еще добавить туда кнопки-индикаторы работы каналов LED, помпы и вентилятора, чтоб при нажатии включать и отключать их, а они своим фоном показывали, что включено, что выключено. Но это позже.
Результат:


« Последнее редактирование: 24 Ноябрь 2017, 23:15:39 от Ann »

Онлайн Ann

  • Глобальный модератор
  • Habanero
  • *****
  • Сообщений: 1533
  • Лойсы: +120/-0
    • Просмотр профиля
Этап 19. Управление (изменение настроек).
Когда мы в предыдущем этапе отправляли GET-запросы с сайта в Вемос, мы сделали так, чтобы ключ параметра (его название, слева от равно) был точно таким же, как и префикс команды, которую ожидает Мега. Поэтому в Вемосе нам остается лишь параметр, имеющий вид "Red=14" привести к виду  "Red_14>" и сразу же его отправить в Мегу.
Вот такой вид примет функция
void handleSet() {
  for (uint8_t i=0; i<server.args(); i++){
       Serial.print(server.argName(i)+"_" + server.arg(i) + ">");
  }
  server.send ( 200, "text/html", "<HTML><HEAD><META HTTP-EQUIV=\"REFRESH\" CONTENT=\"1; URL=http://192.168.0.44\"></HEAD><BODY></BODY></HTML>" );
}

В конце добавлена строка, которая обновляет страницу. Но в ней есть параметр CONTENT=\"1, который обозначает, что страницу нужно обновить не сразу, а через секунду. Это сделано для того, чтобы параметры успели отправиться в Мегу, там изменились настройки и Мега прислала уже новое состояние своих настроек, таким образом на странице мы сразу же увидим, что изменения произошли.

Итоговый скетч Вемоса. Сейчас все работает, инфа отображается, настройки изменяются.
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
String receive_array[30];
String receive_string;

long monitor_last_time;
long data_last_time;
long command_last_time;

//*********Wi-Fi******************************************
const char* ssid = "DIR-615";
const char* password = "11111111";
ESP8266WebServer server(80);

//******SERVER******************************************************************
void handleRoot() {
  String site;
  site = "<HTML><HEAD><META HTTP-EQUIV=\"REFRESH\" CONTENT=\"0; URL=http://collider.anndrew.ru/Wemos/index.php?";
  for (int i = 0; i < 30; i++){
    site += "P";
    site += (String)i;
    site += "=";
    site += receive_array[i];
    site += "&";
    }
  site +=  "\"</HEAD><BODY></BODY></HTML>";
  server.send(200, "text/html", site);
}

void handleNotFound(){
  String message = "404. Not Found\n\n";
  server.send(404, "text/plain", message);
}

void handleSet() {
  for (uint8_t i=0; i<server.args(); i++){
    String a = server.arg(i);
    Serial.print(server.argName(i)+"_" + a + ">");
  }
  server.send ( 200, "text/html", "<HTML><HEAD><META HTTP-EQUIV=\"REFRESH\" CONTENT=\"1; URL=http://192.168.0.44\"></HEAD><BODY></BODY></HTML>" );
   
}


//========================================================
void setup() {
   Serial.begin(115200);
   WiFi.begin(ssid, password);
   Serial.println("");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  server.on("/", handleRoot);
  server.on("/set", handleSet);
  server.onNotFound(handleNotFound);

  server.begin();
  Serial.println("HTTP server started");
}
//========================================================
void loop() {
  server.handleClient();
  Receive_from_Mega();
  Command_to_Mega(2000);
}
//========================================================

void Command_to_Mega(float freq){
  if ((millis()-command_last_time)>freq){
    Serial.print("I_1>");
    command_last_time = millis();
  }
}

void Receive_from_Mega(){
  while (Serial.available() > 0) {         
    char incomig_char = Serial.read();                          //прием строки
    receive_string += (String)incomig_char;
    if ((String)incomig_char == ">") {
      String stroka = receive_string;
      receive_string = "";
      //Serial.println(stroka);
      stroka = stroka.substring(1,stroka.length()-1);
      //Serial.println(stroka);
     
      int index = 0;                                            //разбитие строки и занесение в массив
      char separator = ',';
      int strIndex[] = { 0, -1 };
      int maxIndex = stroka.length() - 1;
      for (int i = 0; i <= maxIndex; i++) {
        if (stroka.charAt(i) == separator || i == maxIndex) {
            strIndex[0] = strIndex[1] + 1;
            strIndex[1] = (i == maxIndex) ? i+1 : i;
            String value = stroka.substring(strIndex[0], strIndex[1]);
            receive_array[index]= value;
            index++;
        }
      }
       
    }
  }
}

Онлайн Ann

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

Здесь все просто, отправлять будет теми же GET-запросами.
Создадим вот такую функцию и будем её раз в 5 минут вызывать

 //-------------------GET-запрос на сервер------------------------------
void Transmit_to_server (long freq){
   if((millis()-transmit_last_time)>freq){
   
        WiFiClient client;
        const uint16_t port = 80;
        const char * host = "collider.anndrew.ru";
        client.connect(host, port);
       
        url = "/data.php?pass=111111&";
        url.concat("temp="); url.concat(receive_array[0]);url.concat("&");
        url.concat("hum="); url.concat(receive_array[1]);url.concat("&");
        url.concat("bar="); url.concat(receive_array[2]);url.concat("&");
        url.concat("dallas="); url.concat(receive_array[3]);url.concat("&");
        url.concat("reboot="); url.concat(millis());url.concat("&");
        url.concat("count="); url.concat(count_reconnect);url.concat("&");
        url.concat("ppm="); url.concat(receive_array[4]);
       
       
        client.print(String("GET ") + url + " HTTP/1.1\r\n" +
                   "Host: " + host + "\r\n" +
                   "User-Agent: ESP8266\r\n" +
                   "Connection: close\r\n\r\n");
       
        delay(100);                                           //Получение ответа от сервера
        String line = client.readStringUntil('>');                   //Читаем строку до >
        char *y = new char[line.length() + 1];                //Создаем массив символов
        strcpy(y, line.c_str());                              //Помещаем строку в массив
       
        char * pch;
        pch = strtok (y,"<");                                 //Отсекаем все до <
        pch = strtok (NULL, ">");                             //Получаем нужное сообщение
        String pp = (String)pch;                              //Преобразовываем в строку
        Serial.println(pp);
        if(pp == "success") {
       
          }else{
            count_reconnect++;
            WiFi.disconnect();
            delay(1000);
            WiFi.begin(ssid, password);
            }
       
        delay(10);
       
        client.stop();
 
    transmit_last_time = millis();
    }
}


На этом, пожалуй, всё. Сделаем перерыв. Коллайдер по факту готов и бьет копытом. Когда уже подключу его и пойдут реальные данные, тогда подшаманю уже сайт с отображением графиков и потом уже расскажу.
Надеюсь вам это было так же интересно, как и мне.

Саш, всё увидел, что хотел? Вопросы какие-нибудь есть? Если хочешь, могу веб-морду твоего коллайдера на свой сервер закинуть, попользуешься пока.


Оффлайн alex_step

  • Serrano
  • ***
  • Сообщений: 181
  • Лойсы: +5/-2
  • Александр, Украина, Жмеринка
    • Просмотр профиля
здесь http://forum.ponics.ru/index.php?topic=2713.msg113610#msg113610 Джим намекал что millis - не есть гуд, и лучше юзать RTC вместо них

Саш, всё увидел, что хотел? Вопросы какие-нибудь есть? Если хочешь, могу веб-морду твоего коллайдера на свой сервер закинуть, попользуешься пока.
В принципе вроде как понятно В ОБЩЕМ... Нужно это всё переварить и подогнать под мои железо/потребности/условия
Вопросы будут... позже
Про веб-морду тоже опосля определюсь

Может запостишь скетчи в виде файлов?
« Последнее редактирование: 25 Ноябрь 2017, 00:29:02 от alex_step »

Онлайн Ann

  • Глобальный модератор
  • Habanero
  • *****
  • Сообщений: 1533
  • Лойсы: +120/-0
    • Просмотр профиля
здесь http://forum.ponics.ru/index.php?topic=2713.msg113610#msg113610 Джим намекал что millis - не есть гуд, и лучше юзать RTC вместо них
А как ты отмеряешь паузу 100мс RTC-ом ?  :D
Все под свои нужны. Для коротких пауз и там где не имеет значения точное время - millis, для включения светильника ровно в 21-00 RTC.
Не знаю, на что он там намекал, но все юзают millis и горя не знают.

Скетчи давай выложу, когда уже будет все в крейсерском режиме. Я ж еще не подключал ничего, все с головы писал, при подключении наверняка какие-нибудь косяки еще вылезут, придется править.
« Последнее редактирование: 25 Ноябрь 2017, 00:56:47 от Ann »

Оффлайн alex_step

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

ну и еще глубже в сторону геморроя на >|<опу:
к примеру у меня нет отдельного роутера, а инет раздает комп, который включен не всегда -> как бы для такого случая организовать такой вариант:
Вемос пытается подключиться клиентом пару раз, если безуспешно то поднимает точку доступа, и периодически снова пытается подключиться клиентом
когда клиентом - отправляет статистику (морда может гулять через i-фрейм или переадресацией), когда точкой - морда только на изменение настроек

Онлайн Ann

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

По веб-морде, посмотри в инкубаторе я там делал.

Оффлайн alex_step

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

Онлайн Ann

  • Глобальный модератор
  • Habanero
  • *****
  • Сообщений: 1533
  • Лойсы: +120/-0
    • Просмотр профиля
Ты предлагаешь комп никогда не выключать..?
Я ведь по факту... исхожу из условий
Как часто тебе управлять нужно? Лично я вмешиваюсь в настройки раз в месяц, не чаще, в крейсерском режиме (разве что в начале да, пока наиграешься клацаешь часто). Для этого раза не жалко нажать кнопку на компе.
По мониторингу, ну накапливать данные в памяти (или записывать в EEPROM), при появлении инета - сливать.
Ну и рассмотреть вопрос покупки роутера, вещь в общем-то полезная. Вай-фай - он ведь ведь на то и вай-фай, чтоб быть всегда на связи.
По веб-морде, можешь для начала выводить не сайт, а просто строку с данными, браузер их отобразит. А управлять GET-запросами (вручную вписывать параметры в адресную строку браузера), вполне юзабельно, мы так Вадиму (vadkoff) делали по началу, все прекрасно управлялось.