Простейшая DIY интернет-метеостанция за 5$

  • Цена: $1.38
  • Сегодня будем делать простейшую интернет-метеостанцию. Никаких выносных датчиков, никаких дисплеев — просто измеряет температуру-влажность-давление и отправляет в интернет, на сайты narodmon.ru и www.wunderground.com. Как говорится, добавь и свою могучую кучку в гору мировой бигдаты!!!

    Нам понадобится платка Wemos D1 Mini (клоник за 2$), платка с датчиком BME280 (2.55$), какой-нибудь корпус и wi-fi-роутер с интернетом.

    Схема простая до безобразия.

    Простейшая DIY интернет-метеостанция за 5$

    Главное выполнить всё на пайке, а не на штырьках, а то от дребезга контактов у BME280 иногда сносит крышу и он начинает выдавать полный бред, пока ему питание не передернешь.

    Вот так выглядит функционально полностью рабочий полуфабрикат метеостанции.

    Простейшая DIY интернет-метеостанция за 5$

    Далее нужно упаковать это в корпус и повесить за окно. Если есть возможность разместить метеостанцию на западной стороне — никаких проблем. Но у меня такой возможности нет и примерно 4ч в день метеостанция будет на солнце, поэтому я пока еще в раздумьях — как-бы снизить погрешность без громоздкой жалюзийной защиты датчика? Если знаете хорошие варианты — предлагайте в каментах. Питается вся конструкция от USB-порта wifi-роутера — это позволяет, при необходимости, удаленно перезагрузить метеостанцию вместе с роутером.

    Теперь по софту — будем использовать Arduino IDE. Там всё стандартно — устанавливаем, в меню выбираем: Инструменты->Плата->Lolin (Wemos) D1 R2 & mini, при необходимости, устанавливаем библиотеку Adafruit BME280 library и оукей. C китайскими платами на BME280 есть один нюанс — они могут быть с разным адресом. Обычно это 0x76 или 0x77, хотя бывают и более экзотичные варианты. В общем, если датчик вдруг не работает, то ищем на компе файл Adafruit_BME280.h, в нем ищем строчку #define BME280_ADDRESS (0x76) и в ней меняем 0x76 на 0x77, ну или наоборот.

    Скетч для Ардуинки
    #include <ESP8266WiFi.h>

    #include <Adafruit_BME280.h>

    #include <PubSubClient.h>

    Adafruit_BME280 bme; // I2C

    // Replace with your network details

    const char* ssid = «WIFINET»;

    const char* password = «пароль_вайфай»;

    float h, t, tF, p, pb, pin, dp, dpF;

    char temperatureString[6];

    char temperatureFString[6];

    char dpString[6];

    char dpFString[6];

    char humidityString[6];

    char pressureString[7];

    char pressureInString[6];

    #define SRV «narodmon.ru»

    #define MAC «хх:dd:c2: хх:a3: хх» //МАК-адрес метеостанции

    #define PASS «ххххх» // пароль для mqtt постинга на narodmon

    #define USERNAME «yyyyyyyyy» // логин на narodmon

    #define TOPIC «yyyyyyyy/BME280/»

    #define SRV2 «weatherstation.wunderground.com»

    #define StationID «ZZZZZZZ» // ID станции на сайте wunderground.com

    #define PASS2 «xxxxx» // Key станции на сайте wunderground.com

    //MQTT Narodmon

    char server[] = SRV;

    char authMethod[] = USERNAME;

    char token[] = PASS;

    char clientId[] = MAC;

    char conntopic[] = TOPIC «status»;

    //HTTP GET WUnderground

    char server2[] = SRV2;

    char authMethod2[] = StationID;

    char token2[] = PASS2;

    char webpage[] = «GET /weatherstation/updateweatherstation.php?»;

    WiFiClient nmClient;

    WiFiClient wuClient;

    PubSubClient clientMQ(server, 1883, nmClient);

    // only runs once on boot

    void setup() {

    // Initializing serial port for debugging purposes

    Serial.begin(115200);

    delay(10);

    // Connecting to WiFi network

    Serial.println();

    Serial.print(«Connecting to „);

    Serial.println(ssid);

    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {

    delay(500);

    Serial.print(“.»);

    }

    Serial.println("");

    Serial.println(«WiFi connected»);

    // Printing the ESP IP address

    Serial.println(WiFi.localIP());

    Serial.println(F(«BME280 start»));

    if (!bme.begin()) {

    Serial.println(«Could not find a valid BME280 sensor, check wiring!»);

    while (1);

    }

    }

    // runs over and over again

    void loop() {

    getWeather();

    doPublishNM(«humidity», String(h, 2));

    doPublishNM(«temperature», String(t, 2));

    doPublishNM(«pressure», String(p, 2));

    doPublishWU(temperatureFString, pressureInString, humidityString, dpFString);

    delay(600000);

    }

    void getWeather() {

    h = 0;

    float valh;

    for (int i=0; i<30; i++) {

    delay (random(50,500));

    valh = bme.readHumidity();

    Serial.print(valh);

    Serial.print("n");

    h = h+valh;

    }

    h=h/30;

    Serial.print("n");

    t = 0;

    float valt;

    for (int i=0; i<30; i++) {

    delay (random(50,500));

    valt = bme.readTemperature();

    Serial.print(valt);

    Serial.print("n");

    t = t+valt;

    }

    t=t/30;

    tF=(t*1.8)+32;

    Serial.print(tF);

    p = 0;

    float valp;

    for (int i=0; i<30; i++) {

    delay (random(50,500));

    valp = bme.readPressure();

    Serial.print(valp);

    Serial.print("n");

    p = p+valp;

    }

    p=p/30/100.0F;

    dp = t-((1-(h/100))/0.05);

    dpF = (dp*1.8)+32;

    pb = p/pow(2.718281828, -0.029*9.81*150/(8.31*(t+273.15))); // приводим абсолютное давление к уровню Балтийского моря (высота 150м)

    pin = p*0.0296133971008484;

    dtostrf(t, 5, 2, temperatureString);

    dtostrf(tF, 4, 2, temperatureFString);

    dtostrf(h, 5, 2, humidityString);

    dtostrf(p, 6, 2, pressureString);

    dtostrf(pin, 4, 2, pressureInString);

    dtostrf(dpF, 5, 2, dpFString);

    }

    // MQTT публикация Narodmon.ru

    void doPublishNM(String id, String value) {

    // если не подключен, то подключаемся. Висит пока не подключится!!!

    if (!!!clientMQ.connected()) {

    Serial.print(«Reconnecting client to „); Serial.println(server);

    while (!!!clientMQ.connect(clientId, authMethod, token, conntopic,0,0,“online»)) {

    Serial.print(".");

    delay(500);

    }

    Serial.print(«connected with: „); Serial.print(clientId); Serial.print(authMethod); Serial.print(token);

    Serial.println();

    }

    String topic = TOPIC;

    String payload = value;

    // String topic += id;

    topic.concat(id);

    Serial.print(“Publishing on: „); Serial.println(topic);

    Serial.print(“Publishing payload: „); Serial.println(payload);

    if (clientMQ.publish(topic.c_str(), (char*) payload.c_str())) {

    Serial.println(“Publish ok»);

    } else {

    Serial.println(«Publish failed»);

    }

    }

    // HTTP GET публикация WUnderground

    void doPublishWU(String temperatureFString, String pressureInString, String humidityString, String dpFString) {

    if (wuClient.connect(server2, 80)) {

    Serial.print(F("… Connected to server: "));

    Serial.print(server2);

    char c = wuClient.read();

    Serial.print(F(", Server response: "));

    Serial.write©;

    Serial.println(F(""));

    Serial.println(F("… Sending DATA "));

    Serial.println(F(""));

    wuClient.print(webpage);

    Serial.print(webpage);

    wuClient.print(«ID=»);

    Serial.print(«ID=»);

    wuClient.print(authMethod2);

    Serial.print(authMethod2);

    wuClient.print("&PASSWORD=");

    Serial.print("&PASSWORD=");

    wuClient.print(token2);

    Serial.print(token2);

    wuClient.print("&dateutc=");

    Serial.print("&dateutc=");

    wuClient.print(«now»);

    Serial.print(«now»);

    wuClient.print("&tempf=");

    Serial.print("&tempf=");

    wuClient.print(temperatureFString);

    Serial.print(temperatureFString);

    wuClient.print("&baromin=");

    Serial.print("&baromin=");

    wuClient.print(pressureInString);

    Serial.print(pressureInString);

    wuClient.print("&humidity=");

    Serial.print("&humidity=");

    wuClient.print(humidityString);

    Serial.print(humidityString);

    wuClient.print("&dewptf=");

    Serial.print("&dewptf=");

    wuClient.print(dpFString);

    Serial.print(dpFString);

    wuClient.print("&softwaretype=Arduino%20UNO%20version1&action=updateraw");

    Serial.print("&softwaretype=Arduino%20UNO%20version1&action=updateraw");

    //Finishing the communication

    wuClient.println("/ HTTP/1.1rnHost: host:portrnConnection: closernrn");

    Serial.println(F("… Server Response:"));

    while(wuClient.connected()) {

    while (wuClient.available()) {

    char c = wuClient.read();

    Serial.print©;

    }

    }

    wuClient.flush();

    wuClient.stop();

    }

    else {

    Serial.println(F(«Connection failed»));

    char c = wuClient.read();

    Serial.write©;

    wuClient.flush();

    wuClient.stop();}

    }

    Да, вот такой скетч — кривенький, но простой и рабочий. Раз в 10 минут делает по 30 отсчетов, усредняет и отправляет показания по протоколу MQTT на narodmon.ru и по протоколу HTTP на wunderground.com. Хотел еще добавить постинг на openweathermap.org, но ниасилил — в конце концов я же не настоящий сварщик и погроммист из меня примерно такой же, как балерина.

    Само собой, предварительно нужно зарегистрироваться на обоих сайтах, а также получить на narodmon.ru пароль для MQTT (в справке по API) и зарегистрировать погодную станцию на wunderground.com, чтобы получить ID и Key.

    На этом, пожалуй, всё. Думаю, тут всё просто и каждый, при желании, сможет модифицировать этот полуфабрикат под себя — добавить датчик освещенности или дождя, например. Можно подумать над deep sleep и автономным питанием на 4хАА или 5хАА и т.п…

Оцените статью