Skocz do zawartości

Obsługa DynamicDNS w serwisie FreeDNS::42 dla ESP8266 i Arduino


rziomber

Pomocna odpowiedź

Masz gotowy wspaniały bulbulator oparty na chipie ESP8266 (np na modułach WiFi ESP8266 Wemos NodeMCU V3 32MB, ArduCam ESP8266-12E WiFi IoT, Adafruit Feather Huzzah ESP8266, Adafruit Huzzah ESP8266, SparkFun Thing - Dev Board - moduł WiFi ESP8266).

DSLR_intervalometers_Bluetooth_and_WiFi.thumb.jpg.74b40913299723e30ff11d51cdc25f72.jpgDew_Heater_Controller.thumb.jpg.3babab467e5fa40b761499e8c3676bdf.jpg

Tworzy on stronę WWW, którą możesz zdalnie doglądać jego pracy.

Arduino_Weather_Station_Admin_Webpage.thumb.png.2da6c4323f1b4b4423c163899710842a.pngAquarium_controller_webpage.thumb.png.719d7bf525d922fcd3d14dff37965990.pngDSLR_remote_controller_screenshot.thumb.png.be81a7299f0de636763927bd2f150e96.png

Niestety posiadasz łącze stałe ze zmiennym IP. W jaki sposób możesz więc połączyć się z nim będąc poza domem? Z pomocą przychodzą usługi typu Dynamic DNS. Jedną z nich jest polski serwis https://freedns.42.pl, z którego od lat korzystam. Zapewnia on przykładowy skrypt Pythona do uaktualniania rekordów DNS. Niestety nie skorzystamy z niego bezpośrednio w Arduino. Musimy więc napisać własny szkic. Celem podejrzenia danych wysyłanych do serwera nieco zmodyfikowałem gotowy skrypt Pythona podmieniając

server = "https://freedns.42.pl/xmlrpc.php"

na adres localhost swojego własnego programu napisanego w C++, który zapisał nagłówek i dane przekazywane do serwera. Tak oto powstał szkic Arduino zawierający trzy funkcje:

  • publicIP() - sprawdzająca aktualne publiczne IP
  • gethostbyname(String host) - sprawdzająca IP przypisane do domeny w rekordach DNS - rekord adresów (A)
  • updateDynDNS() - odpowiedzialna za uaktualnienie wpisu w serwisie FreeDNS

Możemy teraz cyklicznie wywoływać w pętli loop polecenia:

    String myIP = publicIP();
    String hostIP = gethostbyname(dnsset.subdomain + "." + dnsset.domain);

    if (myIP != hostIP)
    {
      dnsset.newaddress = myIP;
      updateDynDNS();
      Serial.println("FreeDNS IP: " + hostIP);
      Serial.println("Public IP: " + myIP);
    }

Sprawdzamy więc nasze aktualne publiczne IP, potem IP przypisane do domeny w DNS. Jeśli się nie zgadzają - wtedy uruchamiamy "machinę" odpowiedzialną za komunikację z FreeDNS. Polecam użyć jakiegoś timera czy skorzystać z funkcji millis(), nie blokującego działanie innych funkcji delay()

FreeDNS.thumb.png.41ff4d902ff72ba831b9c2454847f891.png

Cały kod źródłowy programu:

#include <ESP8266HTTPClient.h>
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
struct FreeDNSsettings {
  String domain;
  String subdomain;
  String newaddress;
  String user;
  String password;
  String ttl;
} dnsset;

void setup() {
  dnsset.domain = "TwojaDomena.pl";
  dnsset.subdomain = "Nazwa subdomeny";
  dnsset.user = "Uzytkownik w serwisie freedns.42.pl";
  dnsset.password = "haslo uzytkownika";
  dnsset.ttl = "120";
  Serial.begin(9600);                                  //Serial connection
  WiFi.softAPdisconnect();
  WiFi.disconnect();
  WiFi.mode(WIFI_STA);
  WiFi.begin("Siec WiFi", "i haslo do niej");   //WiFi connection

  while (WiFi.status() != WL_CONNECTED) {  //Wait for the WiFI connection completion
    delay(500);
    Serial.println("Waiting for connection");
  }
}

void loop() {
  if (WiFi.status() == WL_CONNECTED) { //Check WiFi connection status
    String myIP = publicIP();
    String hostIP = gethostbyname(dnsset.subdomain + "." + dnsset.domain);

    if (myIP != hostIP)
    {
      dnsset.newaddress = myIP;
      updateDynDNS();
      Serial.println("FreeDNS IP: " + hostIP);
      Serial.println("Public IP: " + myIP);
    }
  } else {
    Serial.println("Error in WiFi connection");
  }
  delay(15 * 60 * 1000);
}

String publicIP() {
  String myIP;
  HTTPClient http;
  http.begin("http://ip.42.pl/raw"); //Specify request destination
  int httpCode = http.GET();                                                                  //Send the request

  if (httpCode > 0) { //Check the returning code
    myIP = http.getString();   //Get the request response payload
  }
  return myIP;
}

String gethostbyname(String host)
{
  IPAddress ipAddress;
  WiFi.hostByName(host.c_str(), ipAddress);
  return String(ipAddress[0]) + String(".") + \
         String(ipAddress[1]) + String(".") + \
         String(ipAddress[2]) + String(".") + \
         String(ipAddress[3]);
}

void updateDynDNS() {
  String xml = "<?xml version='1.0'?>\r\n"
               "<methodCall>\r\n"
               "<methodName>xname.updateArecord</methodName>\r\n"
               "<params>\r\n"
               "<param>\r\n"
               "<value><struct>\r\n"
               "<member>\r\n"
               "<name>name</name>\r\n"
               "<value><string>" + dnsset.subdomain + "</string></value>\r\n"
               "</member>\r\n"
               "<member>\r\n"
               "<name>zone</name>\r\n"
               "<value><string>" + dnsset.domain + "</string></value>\r\n"
               "</member>\r\n"
               "<member>\r\n"
               "<name>newaddress</name>\r\n"
               "<value><string>" + dnsset.newaddress + "</string></value>\r\n"
               "</member>\r\n"
               "<member>\r\n"
               "<name>oldaddress</name>\r\n"
               "<value><string>*</string></value>\r\n"
               "</member>\r\n"
               "<member>\r\n"
               "<name>updatereverse</name>\r\n"
               "<value><string>0</string></value>\r\n"
               "</member>\r\n"
               "<member>\r\n"
               "<name>user</name>\r\n"
               "<value><string>" + dnsset.user + "</string></value>\r\n"
               "</member>\r\n"
               "<member>\r\n"
               "<name>ttl</name>\r\n"
               "<value><string>" + dnsset.ttl + "</string></value>\r\n"
               "</member>\r\n"
               "<member>\r\n"
               "<name>password</name>\r\n"
               "<value><string>" + dnsset.password + "</string></value>\r\n"
               "</member>\r\n"
               "</struct></value>\r\n"
               "</param>\r\n"
               "</params>\r\n"
               "</methodCall>";

  String http = "POST /xmlrpc.php HTTP/1.1\r\n"
                "Host: freedns.42.pl\r\n"
                "Accept-Encoding: gzip\r\n"
                "Content-Type: text/xml\r\n"
                "User-Agent: Python-xmlrpc/3.5\r\n"
                "Content-Length: " + String(xml.length()) + "\r\n"
                "\r\n";

  xml = http + xml;

  WiFiClientSecure client;
  IPAddress ipAddress;
  WiFi.hostByName("freedns.42.pl", ipAddress);
  client.connect(ipAddress, 443);
  client.print(xml);
}

Biblioteka WiFiClientSecure występuje w środowisku ESP8266 relatywnie od niedawna. Jeśli macie problemy z kompilacją szkicu właśnie z jej powodu - uaktualnijcie obsługę ESP w Arduino IDE.

Po niewielkich modyfikacjach przypuszczalnie (niestety chwilowo nie mogę tego sprawdzić) uaktualniacz DNS działać będzie również z mikrokontrolerem ESP32. Chyba wystarczy podmienić nazwy dołączanych bibliotek na:

#include <HTTPClient.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>

 

Edytowano przez rziomber
  • Lubię! 1
Link do komentarza
Share on other sites

Podoba Ci się ten projekt? Zostaw pozytywny komentarz i daj znać autorowi, że zbudował coś fajnego!

Masz uwagi? Napisz kulturalnie co warto zmienić. Doceń pracę autora nad konstrukcją oraz opisem.

@rziomber, witam na forum 😉 Widzę, że to Twoje pierwsze kroki na Forbocie, oto najważniejsze informacje na start:

  • Chcesz przywitać się z innymi członkami naszej społeczności? Skorzystaj z tematu powitania użytkowników.
  • Opis najciekawszych funkcji, które ułatwiają korzystanie z forum znajdziesz w temacie instrukcja korzystania z forum - co warto wiedzieć?
  • Poszczególne posty możesz oceniać (pozytywnie i negatywnie) za pomocą reakcji - ikona serca w prawym dolnym rogu każdej wiadomości.

Właśnie zaakceptowałem Twój opis, możesz go teraz zgłosić do akcji rabatowej umieszczając link w temacie zbiorczym. Dziękuję za przedstawienie ciekawego projektu, zachęcam do prezentowania kolejnych DIY oraz aktywności na naszym forum 🙂

Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.