Ethernet W5100 + DHCP server
- Войдите на сайт для отправки комментариев
Пт, 19/07/2013 - 09:35
Собственно, есть Ethernet shield на W5100 и arduino uno.
Пытаюсь "поковырять" примеры работы с данным шилдом.
Всё это дело подключено к серверу, имеющему свой DHCP (isc-dhcp-server). Все работает, адреса выдает и т.д.
С ардуиной же получается, что конструкция вида
Ethernet.begin(mac);
работает чудесно. Сервак назначает IP, происходит соединение ну и далее запрос.
А вот конструкция вида:
Ethernet.begin(mac, ip);
Уже не работает и соединения нет.
IP пытался указывать как:
byte ip[] = {192,168,1,200};и как
IPAddress ip(192,168,1,200);
Не работает ни одна конструкция.
Кто сталкивался, может есть какие-то грабли?
а вы как определяете что нет соединения?
и можно на код целиком посмотреть?... а то из вашего описания следует только рекомендация обрызгать все святой водой и прочитать молитву... а то духи злобные в коде поселились :)
Код целиком вот такой в данный момент:
#include <SPI.h> #include <Ethernet.h> byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; byte ip[] = {192,168,1,200}; char server[] = "srv.dyndns.org"; // URL сервера EthernetClient client; void setup() { Serial.begin(9600); Ethernet.begin(mac);//, ip); Serial.print("My address:"); Serial.println(Ethernet.localIP()); delay(1000); Serial.println("connecting..."); if (client.connect(server, 80)) { Serial.println("connected"); client.println("GET /log.php?dev=1&t1=123.45&t2=0.3&t3=0.25&h=85.4 HTTP/1.0"); client.println("Host: srv.dyndns.org"); client.println(); } else Serial.println("connection failed"); } void loop() { if (client.available()) { char c = client.read(); Serial.print(c); } if (!client.connected()) { Serial.println(); Serial.println("disconnecting."); client.stop(); } }Полагаю, что в моём случае неробходимо использовать конструкцию вида
Поправьте, если не прав.
То есть в моем случае (сервак имеет адрес 192.168.1.100) код должен выглядеть так, наверное:
#include <SPI.h> #include <Ethernet.h> byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; byte ip[] = { 192, 168, 1, 200 }; byte dns[] = { 8, 8, 8, 8 }; byte gateway[] = { 192, 168, 1, 100 }; char server[] = "srv.dyndns.org"; // URL сервера EthernetClient client; void setup() { Serial.begin(9600); Ethernet.begin(mac, ip, dns, gateway); //Ethernet.begin(mac);//, ip); Serial.print("My address:"); Serial.println(Ethernet.localIP()); delay(1000); Serial.println("connecting..."); if (client.connect(server, 80)) { Serial.println("connected"); client.println("GET /log.php?dev=1&t1=123.45&t2=0.3&t3=0.25&h=85.4 HTTP/1.0"); client.println("Host: srv.dyndns.org"); client.println(); } else Serial.println("connection failed"); } void loop() { if (client.available()) { char c = client.read(); Serial.print(c); } if (!client.connected()) { Serial.println(); Serial.println("disconnecting."); client.stop(); } }Пока нет возможности проверить. Приду домой - проверю.
Насколько я понимаю Вы пытаетесь обратиться из своей подсети (и на ней же висит сервер) через dyndns к самому себе - вот тут собака и порылась
Ну вероятнее всего так. Но вот задача как раз в том и состоит, чтобы явно задать IP в своей сети, а обратиться (послать GET запрос) уже к хосту в интернете.
Поскажите, как сие сделать?
Заведите сервер на бесплатном хостинге, у него будет постоянный айпишник. Самый простой вариант.
У моего тоже выделенный IP, однако хочется обращаться по имени, поэтому и через dyndns.org
И как тогда будет выглядеть код для внешнего IP? Что-то я запутался...
Причем тут "обращаться по имени" и dyndns? Если у сервера выделенный айпи НЕ из зарезервированных подсетей для личного пользования (192.168.*/12, 10.*/8, 172.16.*/12)то и прописывайте его айпи, но в этом случае надо (если он идин из виртуальных серверов) чтобы он был прописан по дефолту в апачи
В случае данного сервера, не представляется возможным в папку дефолтного виртуального положить скрипты. Но это легко решается строкой:
client.println("Host: srv.dyndns.org");после GET запроса.
ТО есть, если я правильно понимаю, я меняю строку
на примерно такую?
Однако, ИМХО, это две одинаковых строчки. В чем смысл?
del. Дубль.
Вы неправильно понимаете. DNS превращает имя хоста в айпи, никакой другой смысловой нагрузки DNS не несет. Вашей заменой Вы просто разгружаете DNS, но Вашему серверу непонятно какой сайт отображать и поэтому он возьмет дефолтный. Что у вас в dyndns прописано?
Не совсем так. DNS перенаправляет запрос на определенный IP. А уже сервак, стоящий на данном IP перенаправляет запрос (по адресу сайта) в определенную папку соответствующего виртуального сервера (на конкретном сервере). Так вот, виртуальных на данном серваке много. Дефолтный тоже есть (кстати, если именно по IP обратиться к серваку, он именно на дефолтный и направит), но будем считать (в силу определенных обстоятельств), что на дефолтный нет доступа. Если я к серверу по имени обращусь, я попаду в папку одноименного виртуального сервера (что мне и нужно), если по IP - непосредственно в папку default.
P.S. В настройках dyndns прописан урл (пусть будет srv.dyndns.org) и соответственно, IP (пусть будет 173.194.35.168) с галкой "Host with IP address", в принципе, как и везде на любом dns.
DNS перенаправляет запрос? Очень интересно :) DNS это не что иное как текстовый файл в формате ключ-значение (разбивку по зонам мы опустим для простоты как и прочие настройки типа срока хранения). Я так понимаю что у вас страшно засекреченные данные на сервере хранятся, иначе к чему бы такая секретность? :) Ну а если Вы на самом деле прописали в dyndns что искомый домен находится на нем же, то конечно он ничего не найдет (Но я и не исключаю вариант что Вам выделили субдомен на dyndns, что не исключает предложенный вначале вариант завести бесплатный сервер чтобы исключить мое первое предположение) :)
и в догонку - Вы проверяли подсеть правильная? IP не занят кемто еще?
Извиниите, про DNS неверно выразился. Хотел передать общий смысл. Но вы меня корректно исправили. Спасибо. ))
В общем, мы ушли от темы. Как раз эта часть работает нормально. Читайте выше, не работает не отправка или обработка сервером запроса, а именно жесткая привязка IP адреса _ в локальной сети_. При получении адреса сервером DHCP, все запросы доходят туда, куда им нужно.
И в догонку, IP никем не занят еще 200%
что пишет
Serial.println(Ethernet.localIP());? при автоматическом присвоении ipbyte dns[] = { 192, 168, 1, 100}; byte gateway[] = { 192, 168, 1, 100 };что пишет
Serial.println(Ethernet.localIP());? при автоматическом присвоении ipПрисвоенный IP. 192,168,1,22
в скрипте dns поменяйте (см. выше)
Спассибо. Попробую дома. Я как-то не подумал об этом.
По результатам напишу - может ещё кто сталкиваться будет.
P.S. Отвлеченная тема от DHCP, но касающаяся самого ethernet шилда.
Хорошо греется основной чип W5100. Где-то в районе 60-70 градусов (не замерял, но палец не удержишь).
Данный "бутерброд" питается пока по USB. Проблема в питании? То есть, хотелось бы узнать опыт других, кто "ковырял" данную железку.
Как и обещал, отписываюсь.
Да - все работает изумительно. Читаю (как и многие другие) DHT22 и пишу в БД. Работает как с локальным сервером, так и с URL-ом.
Кому нужно, код ниже:
#include <SPI.h> #include <Ethernet.h> #include <DHT.h> byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // MAC-адрес сетевого интерфейса шилда byte ip[] = { 192, 168, 1, 200 }; byte mydns[] = { 192, 168, 1, 100 }; // Адрес DNS-сервера (domain name server) byte gateway[] = { 192, 168, 1, 100 }; // Шлюз сети //char server[] = "srv.dyndns.org"; // URL сервера (для интернета) byte server[] = { 192, 168, 1, 100 }; // URL сервера (для локалки) const unsigned long requestInterval = 600000; // Задержка между запросами (60000 - 1 минута) EthernetClient client; unsigned long lastAttemptTime = 0; // Время последнего соединения с сервером (милисекунды) //Контакты к которым подключены датчик температуры и влажности #define DHTPIN 3 // Выбираем сенсор который используется - DHT22 #define DHTTYPE DHT22 // DHT 22 (AM2302)(в данном случае нам нужен именно он) // Инициализация датчика... DHT dht(DHTPIN, DHTTYPE); void setup() { Serial.begin(9600); // Инициализация первого Serial'a // Старт соединения... Ethernet.begin(mac, ip, mydns, gateway); /* // Пытаемся соединиться с DHCP-сервером // и получить IP-адрес Serial.println("Attempting to get an IP address using DHCP:"); if (!Ethernet.begin(mac)) { // Если IP-адрес не получен... Serial.println("failed to get an IP address using DHCP, trying manually"); // Устанавливаем вручную. Ethernet.begin(mac, ip); } */ // Пишем адрес в serial-порт Serial.print("My address:"); Serial.println(Ethernet.localIP()); // Делаем задержку в секудну для инициализации delay(1000); } void loop() { // Если текущее время запуска - последнее время коннекта > интервала запроса... if (((millis() - lastAttemptTime > 0) ? (millis() - lastAttemptTime): (lastAttemptTime - millis())) > requestInterval) { Serial.println("connecting..."); if (client.connect(server,80)) // Соединяемся с сервером для передачи показаний { Serial.println("connected"); Serial.println("Read data from sensors..."); // Чтение показаний с датчика занимает около 2 секунд - это очень медленный датчик. float h = dht.readHumidity(); float t1 = dht.readTemperature(); if (isnan(t1) || isnan(h)) Serial.println("Failed to read from DHT"); // Если не удалось считать данные с датчиков... else //Удачное чтение показаний с датчиков { Serial.println("Data are read!"); Serial.print("Humidity: "); Serial.print(h); Serial.print(" %\t"); Serial.print("Temperature: "); Serial.print(t1); Serial.println(" *C"); char buf[10]; dtostrf(t1, 5, 3, buf); String msg = "GET /get.php?dev=1&t1="; msg += buf; dtostrf(h, 5, 3, buf); msg += "&h="; msg += buf; msg += " HTTP/1.1"; client.println(msg); //Отправляем данные запросом Serial.println(msg); client.println("Host: srv.dyndns.org"); client.println(); delay(50); // Задержка для того, чтоб сервер успел ответить while (client.available()) // Если пришли данные от сервера, читаем и отображаем их в Serial-порту { char c = client.read(); Serial.print(c); } lastAttemptTime = millis(); // Пишем время последнего соединения client.stop(); // Разрываем соединение. } } else Serial.println("connection failed"); } }Вот это
if (isnan(t1) || isnan(h)) Serial.println("Failed to read from DHT");не есть гут. лучше их по одиночке проверяйте - лучше записать одно значение (если есть) чем ни одного
Вот это
if (isnan(t1) || isnan(h)) Serial.println("Failed to read from DHT");не есть гут. лучше их по одиночке проверяйте - лучше записать одно значение (если есть) чем ни одного
Ну с такой позиции уж лучше так:
if (isnan(t1) & isnan(h)) Serial.println("Failed to read from DHT");Неа :) Так NULL по одному из значений может в БД попасть
Согласен. Не подумал. Хотя, ИМХО если NULL по одному из значений, скорее всего будет нулл и по второму ;)
Подниму старую тему дабы не плодить новую.
Появился еще один вопрос по ethrenet - шилду.
В коде для установления связи шилда с сервером используется строка вида:
Ну и после отправки показаний на сервер закрывается соединение:
Все бы ничего, но прикручиваю к данной связке nRF24L01, которая на той же SPI (периодически дергаю "ногами" chip select для выбора активного slave) и появляется проблема - если закрывать каждый раз соединение, то как я полагаю (может и неправильно) пока нет соединения, буфер приема будет недоступен (в буфер ничего "сыпаться" не будет). А буфер нужен, чтоб не пропустить команду с сервера.
Вопрос в следущем - можно ли (кто-нибудь работал так) не закрывать соединение (client.stop();) - то есть открыть его один раз, допустим, при инициализации шилда и не закрывать и чем это чревато?
Может есть другой выход?
Ага... Разобрался почти. Для инициализации входящих подклчений есть EthernetServer
Однако, пока много чего не понятно.
Допустим, инициализирую я его как клиента EthernetClient client; в сетапе делаю Ethernet.begin(mac, ip, mydns, gateway); и в основном цикле client.connect(server,80) для передачи данных удаленному серверу.
Могу ли я параллельно в том же коде сделать EthernetServer myserver(80); в сетапе (опять же - в сетапе по идее должны быть другие данные - айпи уже этого как я понимаю сервера-ардуино) написать server.begin(); и в основном коде EthernetClient clientsrv = server.available();?
Походу нет. Поправьте, если не прав, но полагаю что сервер и клиент на одном и том же шилде не запустить.
Мысли вслух: Опять-таки, после запроса сервак обязательно ответ пришлет... Кто ловить этот ответ будет на ардуине? Сервер? Клиент?
Или каждый раз когда хочется отправить чего-то переинициализировать (как в сетапе) этот эзернет? Ethernet.begin(mac, ip, mydns, gateway);
P.S. Эх, блин... Все совсем не так... Поправлю этот пост, когда полностью разберусь и напишу рабочий скетч.
Мысли вслух: Опять-таки, после запроса сервак обязательно ответ пришлет... Кто ловить этот ответ будет на ардуине? Сервер? Клиент?
Какая разница? Кто поймал - тот и клиент. :)
На самом деле - хорошо бы хоть азы tcpip знать: ответ приходит на тот порт, с которого уходил запрос. А кто там слушает (или уже никого нет) - это дело десятое.
Мысли вслух: Опять-таки, после запроса сервак обязательно ответ пришлет... Кто ловить этот ответ будет на ардуине? Сервер? Клиент?
Какая разница? Кто поймал - тот и клиент. :)
На самом деле - хорошо бы хоть азы tcpip знать: ответ приходит на тот порт, с которого уходил запрос. А кто там слушает (или уже никого нет) - это дело десятое.
Понимание данных процессов есть. Я прекрасно понимаю, что "Кто поймал - тот и клиент". Очень не хотелось ковырять библиотеку - совсем нет на это времени. Спрашивал потому как думал, может кто-то уже интересовался данным вопросом, пототму как неизвестно как поведет себя данная библа в этом случае.
Ну а уж что ответ придет по тому же порту на котором установлено соединение (мало того, на данном, прикладном уровне он привязывается именно к порту) - и сомнений нет. Вопрос заключался именно в том, кто ж слушать-то будет в данный момент.
Но вы невнимательно читали прошлый пост (как бы я написал, что разобрался, просто не реализовал).
Однако, спасибо за отзыв и помощь.
Кстати, по этой теме понравилась очень данная статья - подробно и очень просто изложено про библиотеку Ethernet - кто не сталкивался настоятельно рекомендую к прочтению для понимая.
Ну а уж что ответ придет по тому же порту на котором установлено соединение (мало того, на данном, прикладном уровне он привязывается именно к порту) - и сомнений нет. Вопрос заключался именно в том, кто ж слушать-то будет в данный момент.
Я исходил из двух простых вещей: по-умолчанию, web-сервер "слушает" 80-й порт, в то же время принято, что приложения, для исходящих пакетов, не используют порты ниже 1024 (а лучше не ниже 6000), т.е., в нормальных условиях, web-сервер никак не может получить пакет, отправленный клиентом.
Другое дело, озадачиться вопросом: как в ардуине tcp-сессия сохраняется между циклами loop, или просто стоим на месте и ждем ответа...
В принципе, не беда. Набросал код - приду домой - проверю :)