Нужна помощь в проекте (передача данных на сайт Народный мониторинг)

Тема в разделе "Arduino & Shields", создана пользователем DZent, 26 сен 2013.

  1. DZent

    DZent Нуб

    Всем доброго времени суток!

    Предисловие(можно не читать):Возникла недавно непреодолимое желание создать что-нибудь своими руками. Закупил все необходимые компоненты(Arduino,шаговые двигатели,датчик температуры и влажности - DHT21,датчик давления - BMP085,датчик движения и т.п.), опробовал небольшие примеры и решил сделать что нибудь посерьезнее. Долго читал в интернете различные статьи и наткнулся на интересную для себя тему - Отправка данных на сайт "Народный мониторинг".

    Суть: Взял скетч(второй) для отправки данных на сайт Народный мониторинг с этого сайта http://star-t-hinking.blogspot.ru/2013/06/diy.html для DHT22,

    Код (C):

    //
    //   FILE:  dht_test.pde
    // PURPOSE: DHT library test sketch for Arduino
    //

    #include <DHT.h>
    #include <Dhcp.h>
    #include <Dns.h>
    #include <Ethernet.h>
    #include <EthernetClient.h>
    #include <EthernetServer.h>
    #include <EthernetUdp.h>
    #include <util.h>
    #include <SPI.h>
    DHT dht;

    #define DHT21_PIN 7
    const unsigned long postingInterval = 600000;  // интервал между отправками данных в миллисекундах (10 минут)
    unsigned long lastConnectionTime = 0;          // время последней передачи данных
    boolean lastConnected = false;                // состояние подключения
    int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract;
    char replyBuffer[106];
    char CurTemp[6];

    // ========================Задаем данные сети======================
    byte mac[] = { 0x92, 0xA2, 0xDA, 0x0D, 0xD2, 0x3A }; //mac - адрес ethernet shielda ставим свой
    // byte ip[] = { 192, 168, 1, 177 };        // ip адрес ethernet shielda
    // byte subnet[] = { 255, 255, 255, 0 }; //маска подсети
    // EthernetServer server(80); //порт сервера
    EthernetClient client; //
    int ledPin = 9; // указываем что светодиод будет управляться через 9 Pin
    String readString = String(30); //string for fetching data from address
    boolean LEDON = false; //изначальный статус светодиода - выключен
    IPAddress server(94,19,113,221); // IP сервера
    // ===============================================================

    void setup()
    {
       delay(4000);
        // Ethernet connection:
        if (Ethernet.begin(mac) == 0) {
     Serial.println("Failed to configure Ethernet using DHCP");
     // ничего не делаем
            for(;;)
            ;
        }
        // секунда для инициализации Ethernet
      delay(2000);
      lastConnectionTime = millis()-postingInterval+15000; //первое соединение через 15 секунд после запуска
      //устанавливаем pin 9 на выход
      pinMode(ledPin, OUTPUT);
       
      Serial.begin(115200);
      Serial.println("DHT TEST PROGRAM ");
      Serial.print("LIBRARY VERSION: ");
      Serial.println("DHT_LIB_VERSION");
      Serial.println();
      Serial.println("Type,\tstatus,\tHumidity (%),\tTemperature (C)");
    }

    void loop()
    {
      // READ DATA
      Serial.print("DHT21, \t");
    int chk = dht.read21(DHT21_PIN);
      switch (chk)
      {
        case DHTLIB_OK:
      Serial.print("OK,\t");
      break;
        case DHTLIB_ERROR_CHECKSUM:
      Serial.print("Checksum error,\t");
      break;
        case DHTLIB_ERROR_TIMEOUT:
      Serial.print("Time out error,\t");
      break;
        default:
      Serial.print("Unknown error,\t");
      break;
      }
      // DISPLAY DATA
      Serial.print(DHT.humidity, 1);
      Serial.print(",\t");
      Serial.println(DHT.temperature, 1);

      delay(50000);

       if (client.available()) {
          char c = client.read();
        }

        if (!client.connected() && lastConnected)
        {
           
            client.stop();
        }
       
        if(!client.connected() && (millis() - lastConnectionTime > postingInterval))
        {
     //отправляем запрос
        int t = DHT.temperature;
        int h= DHT.humidity;
        char temp[3];
        char hum[2];
        //формирование HTTP-запроса
        memset(replyBuffer, 0, sizeof(replyBuffer));
        strcpy(replyBuffer,"ID=");
        //Конвертируем MAC-адрес
        for (int k=0; k<6; k++)
      {
       int b1=mac[k]/16;
       int b2=mac[k]%16;
       char c1[2],c2[2];

       if (b1>9) c1[0]=(char)(b1-10)+'A';
                else c1[0] = (char)(b1) + '0';
       if (b2>9) c2[0]=(char)(b2-10)+'A';
                else c2[0] = (char)(b2) + '0';

       c1[1]='\0';
       c2[1]='\0';

       strcat(replyBuffer,c1);
       strcat(replyBuffer,c2);
      }
         //конвертируем адрес термодатчика

        strcat(replyBuffer,"&");
        for (int k=0; k<6; k++)
      {
       int b1=mac[k]/16;
       int b2=mac[k]%16;
       char c1[2],c2[2];

       if (b1>9) c1[0]=(char)(b1-10)+'A';
                else c1[0] = (char)(b1) + '0';
       if (b2>9) c2[0]=(char)(b2-10)+'A';
                else c2[0] = (char)(b2) + '0';

       c1[1]='\0';
       c2[1]='\0';

       strcat(replyBuffer,c1);
       strcat(replyBuffer,c2);
      }
        strcat(replyBuffer,"01");
       
        //конвертируем адрес датчика влажности
        strcat(replyBuffer,"=");
        if (SignBit)
      {
       strcat(replyBuffer,"-");
      }
        itos(t,temp);
        strcat(replyBuffer,temp);
        strcat(replyBuffer,".");
        strcat(replyBuffer,"&");
        for (int k=0; k<6; k++)
      {
       int b1=mac[k]/16;
       int b2=mac[k]%16;
       char c1[2],c2[2];

       if (b1>9) c1[0]=(char)(b1-10)+'A';
                else c1[0] = (char)(b1) + '0';
       if (b2>9) c2[0]=(char)(b2-10)+'A';
                else c2[0] = (char)(b2) + '0';

       c1[1]='\0';
       c2[1]='\0';

       strcat(replyBuffer,c1);
       strcat(replyBuffer,c2);
      }
        strcat(replyBuffer,"02");
       
        strcat(replyBuffer,"=");
        itos(h,hum);
        strcat(replyBuffer,hum);
        strcat(replyBuffer,".");
       
        strcat(CurTemp,temp);
        httpRequest();         
        }
        lastConnected = client.connected();
    }

    void httpRequest() {
       if (client.connect(server, 80)) {
     
          // send the HTTP POST request:
       client.println("POST http://narodmon.ru/post.php HTTP/1.0");
          Serial.println("POST http://narodmon.ru/post.php HTTP/1.0");
          client.println("Host: narodmon.ru");
          Serial.println("Host: narodmon.ru");
          //client.println("User-Agent: arduino-ethernet");
          //client.println("Connection: close");
          client.println("Content-Type: application/x-www-form-urlencoded");
          Serial.println("Content-Type: application/x-www-form-urlencoded");
          client.println("Content-Length: 53");
          Serial.println("Content-Length: 53");
          client.println();
          Serial.println();
          client.println(replyBuffer);
          Serial.println(replyBuffer);
          client.println();
          lastConnectionTime = millis();
          delay(1000);
      }
      else {
          client.stop();
      }
    }
    void itos(int n, char bufp[3]) //int to string
    {
      char buf[3]={'0','0','\0'};
      int i = 1;

      while (n > 0) {
        buf[i] = (n % 10)+48;
        i--;
        n /= 10;
      }

      for (i=0; i<3; i++)
        bufp[i]=buf[i];
    }
    //
    // END OF FILE
    //
     

    дописал с горем пополам библиотеку DHT для своего датчика DHT21, начал компиляцию скетча и тут меня дуня огорчила ошибкой в строке "int chk = dht.read21(DHT21_PIN);"(выделена жирным) следующим текстом "'class DHT' has no member named 'read22'".

    Снова полез в библиотеку DHT и действительно нет никакого read22. Пробовал различные варианты того что автор сие скетча хотел прокомментировать в этой строке но ничего не получилось.

    Так же при компиляции существуют следующие ошибки:
    Arduino_narodmon:68: error: 'DHTLIB_OK' was not declared in this scope
    Arduino_narodmon:71: error: 'DHTLIB_ERROR_CHECKSUM' was not declared in this scope
    Arduino_narodmon:74: error: 'DHTLIB_ERROR_TIMEOUT' was not declared in this scope
    Arduino_narodmon:82: error: expected primary-expression before '.' token
    Arduino_narodmon:84: error: expected primary-expression before '.' token
    Arduino_narodmon.ino:89: warning: unused variable 'c'
    Arduino_narodmon:101: error: expected primary-expression before '.' token
    Arduino_narodmon:102: error: expected primary-expression before '.' token

    Уважаемые форумчане!Огромная просьба помогите кто может разобраться в этом коде. Дать подсказки, советы.Буду очень признателен.

    ЗЫ: Есть большое желание довести все таки все это до ума. (Пробовал такой вариант
    int chk = dht.readSensor(DHT21_PIN);
    но появилась следующая ошибка "expected `)' before ';' token")
     
  2. Максим B

    Максим B Гуру

    а если попробовать компилировать проект в среде другой - к примеру arduino-0022.
     
  3. DZent

    DZent Нуб

    Сейчас попробую.
    А чем обосновано ваше предположение что дело именно в среде?
     
  4. DZent

    DZent Нуб

    В среде 0022 тоже ошибки,причем еще больше,в этой строке аналогичная ошибка
    В среде 1.0 те же самые ошибки что и выше(
     
  5. lerik2703

    lerik2703 Гик

    а на библиотеку DHT.h можно взглянуть?
     
  6. DZent

    DZent Нуб

    Конечно,вот она

    Код (C):

    #ifndef dht_h
    #define dht_h

    #if ARDUINO < 100
      #include <WProgram.h>
    #else
      #include <Arduino.h>
    #endif


    class DHT
    {
    public:

      typedef enum {
        AUTO_DETECT,
        DHT11,
        DHT22,
        DHT21,  
        AM2301 
      }
      DHT_MODEL_t;

      typedef enum {
        ERROR_NONE = 0,
        ERROR_TIMEOUT,
        ERROR_CHECKSUM
      }
      DHT_ERROR_t;

      void setup(uint8_t pin, DHT_MODEL_t model=AUTO_DETECT);
      void resetTimer();

      float getTemperature();
      float getHumidity();

      DHT_ERROR_t getStatus() { return error; };
      const char* getStatusString();

      DHT_MODEL_t getModel() { return model; }

      int getMinimumSamplingPeriod() { return model == DHT11 ? 1000 : 2000; }

      int8_t getNumberOfDecimalsTemperature() { return model == DHT11 ? 0 : 1; };
      int8_t getLowerBoundTemperature() { return model == DHT11 ? 0 : -40; };
      int8_t getUpperBoundTemperature() { return model == DHT11 ? 50 : 125; };

      int8_t getNumberOfDecimalsHumidity() { return 0; };
      int8_t getLowerBoundHumidity() { return model == DHT11 ? 20 : 0; };
      int8_t getUpperBoundHumidity() { return model == DHT11 ? 90 : 100; };

      static float toFahrenheit(float fromCelcius) { return 1.8 * fromCelcius + 32.0; };
      static float toCelsius(float fromFahrenheit) { return (fromFahrenheit - 32.0) / 1.8; };

    protected:
      void readSensor();

      float temperature;
      float humidity;

      uint8_t pin;

    private:
      DHT_MODEL_t model;
      DHT_ERROR_t error;
      unsigned long lastReadTime;
    };

    #endif /*dht_h*/
     
    так же приложу и .cpp

    Код (C):

    #include "DHT.h"

    void DHT::setup(uint8_t pin, DHT_MODEL_t model)
    {
      DHT::pin = pin;
      DHT::model = model;
      DHT::resetTimer(); // Make sure we do read the sensor in the next readSensor()

      if ( model == AUTO_DETECT) {
        DHT::model = DHT21;
        readSensor();
        if ( error == ERROR_TIMEOUT ) {
          DHT::model = DHT11;
          // Warning: in case we auto detect a DHT11, you should wait at least 1000 msec
          // before your first read request. Otherwise you will get a time out error.
        }
      }
    }

    void DHT::resetTimer()
    {
      DHT::lastReadTime = millis() - 3000;
    }

    float DHT::getHumidity()
    {
      readSensor();
      return humidity;
    }

    float DHT::getTemperature()
    {
      readSensor();
      return temperature;
    }

    #ifndef OPTIMIZE_SRAM_SIZE

    const char* DHT::getStatusString()
    {
      switch ( error ) {
        case DHT::ERROR_TIMEOUT:
          return "TIMEOUT";

        case DHT::ERROR_CHECKSUM:
          return "CHECKSUM";

        default:
          return "OK";
      }
    }

    #else

    // At the expense of 26 bytes of extra PROGMEM, we save 11 bytes of
    // SRAM by using the following method:

    prog_char P_OK[]       PROGMEM = "OK";
    prog_char P_TIMEOUT[]  PROGMEM = "TIMEOUT";
    prog_char P_CHECKSUM[] PROGMEM = "CHECKSUM";

    const char *DHT::getStatusString() {
      prog_char *c;
      switch ( error ) {
        case DHT::ERROR_CHECKSUM:
          c = P_CHECKSUM; break;

        case DHT::ERROR_TIMEOUT:
          c = P_TIMEOUT; break;

        default:
          c = P_OK; break;
      }

      static char buffer[9];
      strcpy_P(buffer, c);

      return buffer;
    }

    #endif

    void DHT::readSensor()
    {
      // Make sure we don't poll the sensor too often
      // - Max sample rate DHT11 is 1 Hz   (duty cicle 1000 ms)
      // - Max sample rate DHT21 is 0.5 Hz (duty cicle 2000 ms)
      unsigned long startTime = millis();
      if ( (unsigned long)(startTime - lastReadTime) < (model == DHT11 ? 999L : 1999L) ) {
        return;
      }
      lastReadTime = startTime;

      temperature = NAN;
      humidity = NAN;

      // Request sample

      digitalWrite(pin, LOW); // Send start signal
      pinMode(pin, OUTPUT);
      if ( model == DHT11 ) {
        delay(18);
      }
      else {
        // This will fail for a DHT11 - that's how we can detect such a device
        delayMicroseconds(800);
      }

      pinMode(pin, INPUT);
      digitalWrite(pin, HIGH); // Switch bus to receive data

      // We're going to read 83 edges:
      // - First a FALLING, RISING, and FALLING edge for the start bit
      // - Then 40 bits: RISING and then a FALLING edge per bit
      // To keep our code simple, we accept any HIGH or LOW reading if it's max 85 usecs long

      word rawHumidity;
      word rawTemperature;
      word data;

      for ( int8_t i = -3 ; i < 2 * 40; i++ ) {
        byte age;
        startTime = micros();

        do {
          age = (unsigned long)(micros() - startTime);
          if ( age > 90 ) {
            error = ERROR_TIMEOUT;
            return;
          }
        }
        while ( digitalRead(pin) == (i & 1) ? HIGH : LOW );

        if ( i >= 0 && (i & 1) ) {
          // Now we are being fed our 40 bits
          data <<= 1;

          // A zero max 30 usecs, a one at least 68 usecs.
          if ( age > 30 ) {
            data |= 1; // we got a one
          }
        }

        switch ( i ) {
          case 31:
            rawHumidity = data;
            break;
          case 63:
            rawTemperature = data;
            data = 0;
            break;
        }
      }

      // Verify checksum

      if ( (byte)(((byte)rawHumidity) + (rawHumidity >> 8) + ((byte)rawTemperature) + (rawTemperature >> 8)) != data ) {
        error = ERROR_CHECKSUM;
        return;
      }

      // Store readings

      if ( model == DHT11 ) {
        humidity = rawHumidity >> 8;
        temperature = rawTemperature >> 8;
      }
      else {
        humidity = rawHumidity * 0.1;

        if ( rawTemperature & 0x8000 ) {
          rawTemperature = -(int16_t)(rawTemperature & 0x7FFF);
        }
        temperature = ((int16_t)rawTemperature) * 0.1;
      }

      error = ERROR_NONE;
    }

     
     
  7. lerik2703

    lerik2703 Гик

    ну на сколько я вижу тупо не совместимость библиотек!где в .ccp функция dht::read22?
     
  8. DZent

    DZent Нуб

    Понятно. Насколько я понял основной код, в этой части происходит опрос датчика для определения его типа (DHT11, DHT22, DHT21) и для этого существует функция readSensor в .cpp вот тут:
    Код (C):

    void DHT::readSensor()
    {
      // Make sure we don't poll the sensor too often
     
    И я уже попробовал такой вариант
    int chk = dht.readSensor(DHT21_PIN);
    При котором появляется следующая ошибка при компиляции - "expected `)' before ';' token"
    Что не так?
    Сможете направить в нужное русло? Где искать корень проблемы?
     
  9. lerik2703

    lerik2703 Гик

    DZent и Unixon нравится это.
  10. DZent

    DZent Нуб

    Ого!Спасибо огромное!;):rolleyes:
    Скетч скомпилировался без ошибок)
    На выходных залью его на свой Arduino, буду пробовать в работе) Отпишусь по результатам)))
     
  11. lerik2703

    lerik2703 Гик

  12. DZent

    DZent Нуб

    Залил сегодня скетч на плату,подключил датчик и тишина(
    В мониторинге порта при отправке цифры 1 выдало вот такой результат - Pp˶ZM
    А пока писал сообщение появились еще вот эти символы - ý¨ýÙØÀš{$ÞMð"0|'Íã]üó(ýñšý

    На сайте народного мониторинга зашел на страницу отладки и увидел следующее -
    Данные получены Sun, 29 Sep 2013 19:56:07 +0400 с IP 1**.1**.1**.** (Раменское, Московская область, Россия)

    POST http://narodmon.ru/post.php HTTP/1.0\r\n
    Host: narodmon.ru\r\n
    Content-Type: application/x-www-form-urlencoded\r\n
    Content-Length: 53\r\n
    \r\n
    ID=______________________________________________=25.________________=49.
    Последняя запись в СУБД Sun, 29 Sep 2013 19:56:07 +0400

    Ошибки в формате данных(если они есть):
    Первая строка должна содержать MAC устр-ва из 12-24 знаков hex(допускаются разделители '-' и ':')
    Каждая строка должна начинаться с символа '#'
    Пакет данных должен оканчиваться строкой '##'

    Как я понял неправильно задаю мак-адрес и данные не передаются в конечном счете(
    Сижу разбираюсь в скетче,завтра напишу что как:(
     
  13. lerik2703

    lerik2703 Гик

    а скорость порта установлена как и в скетче Serial.begin(115200); ?MAC адрес нужно указывать своего устройства!
     
  14. DZent

    DZent Нуб

    Поменял скорость порта теперь показывает следующее
    DHT TEST PROGRAM
    LIBRARY VERSION: DHT_LIB_VERSION

    Type, status, Humidity (%), Temperature (C)
    DHT21, OK, 42.8, 24.7
    POST http://narodmon.ru/post.php HTTP/1.0
    Host: narodmon.ru
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 53

    ID=***************&*****************=24.&*****************=42.
    DHT21, OK, 43.4, 24.8

    Мак адрес я задал, но на странице отладки точно такие же строки

    22.56 - Показания на сайт передались но только в 22.26 и с тех пор не обновляются. Причем на сайте показывает что у меня типо два датчика температуры +24 и +44 хотя второе значение это влажность( Буду разбираться

    23.28 - Настроил на сайте показания. Но все таки странная немного работа устройства - Данные на сайте показываются только те которые отправляются при запуске Arduino, а потом в мониторинге порта показывает обновленные данные через заданный интервал,но на сайт эти данные не передаются почему то(((пока не знаю почему(
    И еще один странный момент - в мониторинге порта значения отображаются с десятичным знаком а на сайт передаются только целые значения.
     
    Последнее редактирование: 30 сен 2013
  15. Megakoteyka

    Megakoteyka Оракул Модератор

    DHT.humidity и DHT.temperature имеют тип float - вещественное число.
    Их Вы и выводите в println(). Функция правильно понимает тип и выводит как надо.
    А потом Вы преобразовываете значения в тип int - целое. При таком преобразовании остается целая часть, дробная часть просто отбрасывается (т.е. даже округления не происходит).
    Посмотрите в сторону sprintf - эта функция "напечатает" число в строку в нужном формате. Останется вывести полученную строку.
     
  16. DZent

    DZent Нуб

    Спасибо за ответ) Сегодня вечером попробую.
    Появилось несколько вопросов:
    1) А если не преобразовывать значения в int и передавать их так же во float?
    Есть ли тогда необходимость в применении функции sprintf?

    2)На почту через час после того подаю питание на ардуино(т.е. запускаю с нуля) приходят такие сообщения:
    "На Вашем устройстве мониторинга «Arduino-W5100-DHT21» обнаружены неактивные датчики:

    Датчик «DHT21-Температура» неактивен с 01/10 07:54.
    Датчик «DHT21-Влажность» неактивен с 01/10 07:54.
    ...
    01/10 00:38 ID of the device is missing: #ID=************&***********F01=26.&***********F02=38"

    Вместо звездочек стоит мой мак-адрес.
    Вот и получается что ардуино отправляет данные только в самом начале при запуске,а потом данные не передаются. Вы сможете подсказать почему?
     
  17. Megakoteyka

    Megakoteyka Оракул Модератор

    1) Вы же отсылаете данные в виде строки - значит, придется все же преобразовать float в его строковое представление. Можно для этого использовать sprintf, можно самостоятельно написать код, который сформирует строку нужного вида - суть не изменится.
    2) Возможно, программа в каком-то месте зависает. Вставьте в код отладочный вывод на терминал из различных мест программы. Если программа зависнет - по последнему сообщению узнаете, в каком месте это произошло. Дальше - отлаживать код. Очень распространенная ошибка - код лезет в чужую память. Например, при формировании строки может происходить выход за границы массива и порча соседней переменной, что нарушает работу алгоритма.
     
    DZent нравится это.
  18. Megakoteyka

    Megakoteyka Оракул Модератор

    Хороший вариант - перенести основной алгоритм в среду разработки с отладчиком на ПК (VisualStudio, например) и погонять его на различных тестовых данных. Когда код будет работать правильно - переносите обратно в контроллер. Либо по ходу работы выводите на терминал состояние различных переменных и анализируйте, верно ли все работает.
     
    DZent и Unixon нравится это.
  19. DZent

    DZent Нуб

    Спасибо за советы. Буду разбираться)
    (Возможно теперь надолго проект встанет, познаний в языке пока не достаточно для поиска проблем и отладки кода, надо читать материалы по C++)

    Появился вопрос - а что делает вот это часть кода? не то же что и функция sprintf?
    Код (C):
    void itos(int n, char bufp[3]) //int to string
    {
      char buf[3]={'0','0','\0'};
      int i = 1;

      while (n > 0) {
        buf[i] = (n % 10)+48;
        i--;
        n /= 10;
      }

      for (i=0; i<3; i++)
        bufp[i]=buf[i];
    }
     
    Последнее редактирование: 2 окт 2013
  20. DZent

    DZent Нуб

    По второму пункту - нашел ошибку в скетче,а точнее лишнее отрицание)))Теперь данные отправляются раз в 10 минут как положено)))
    Осталось разобраться почему отправляются только целые значения на сайт, а не десятичные