WebServer на ардуино 2560 и ethernet контроллере W5100

mozgolomys
Offline
Зарегистрирован: 08.01.2016

Здравствуйте, помогите пожалуйста разобраться. Задача сделать удаленное управление периферией, через web интерфейс (эта часть с небольшим трудом сделана). Но управление должно происходить в автоматическом или ручном режиме, в зависимости от первоначального выбора. Т.е. если я выбираю автоматический режим, то периферия управляется по определенному алгоритму. Если выбрал ручной режим - то управляется каждый элемент периферии отдельно.

За основу взял http://zelectro.cc/Ethernet_shield_W5100.

Убрал кнопку отправить, сделал отправление команды после установки галочки в checkbox.

Для красоты запихнул все в табличку и выровнял по левому краю.

Добавил checkbox для выбора автоматического режима. И столкнулся с проблемой того, что состояние выходов парсится и укладывается в массив, из которого потом считывается. Пробовал добавлять такое условие





 char automan = client.read();
if (automan == 'm')  pinState[0] = 1

но результата не дало. 







#include <SPI.h>
#include <Ethernet.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // Мак адрес
byte ip[] = { 192, 168, 1, 198 }; // IP адрес (В броузере вводим 192.168.0.2)
EthernetServer server(80);

int numPins = 4;
int pins[] = { 3, 5, 7, 10 };    // Пины для реле
int pinState[] = {0, 0, 0, 0};  // Состояние пинов
bool mode= 0;

void setup()
{
  // Изначально выключаем все реле
  for (int i = 0; i < numPins; i++)
  {
    pinMode(pins[i], OUTPUT);
    digitalWrite(pins[i], 1);
    
  }
  
  Serial.begin(9600);
  Ethernet.begin(mac, ip);
  server.begin();
}

void loop()
{
  EthernetClient client = server.available();
  if (client)
  {
    // Проверяем подключен ли клиент к серверу
    while (client.connected())
    {
      // Проверяем идет ли запрос к серверу
      int dataCount = client.available();
      if (dataCount > 0)
      {
        // Считываем данные передаваемые серверу с клиента (браузера)
        for (int i = 0; i < dataCount; i++)
        {
          char ch = client.read();
          // Если данные передаются, то они будут переданы POST запросом, который начинается с символа 'P'
          if (i == 0 && ch != 'P')
            break;
          if (ch == '\n' && i < dataCount - 1)
          {
             // Находим строку, в которой содержатся передаваемые данные
             char chNext = client.read();
             // Формат строки r2=on&r3=on&r4=on (Пример если нужно включены 2,3,4 реле)
             if (chNext == 'r')
             {
               // Выключаем все реле
               pinState[0] = 0;
               pinState[1] = 0;
               pinState[2] = 0;
               pinState[3] = 0;
               

              
               // Считываем первый номер реле, который нужно включить
               char relayNum = client.read();
               pinState[relayNum-'0'] = 1;
               Serial.write(relayNum);
               
               // Считываем вспомогательную информацию (=on&)
               relayNum = client.read();
               relayNum = client.read();
               relayNum = client.read();
               relayNum = client.read();
                
               // Пока есть данные об остальных реле, считываем и заносим в массив pinState
               while (relayNum != -1)
               {
                  relayNum = client.read();
                  relayNum = client.read();
                  pinState[relayNum-'0'] = 1;
                  Serial.write(relayNum);
                  relayNum = client.read();
                  relayNum = client.read();
                  relayNum = client.read();
                  relayNum = client.read();
               }
             
             } else
             {
                // Если не было передано данных, то выключаем все реле
                pinState[0] = 0;
                pinState[1] = 0;
                pinState[2] = 0;
                pinState[3] = 0;
             }


             
                       
          }
        }
      }
      
      // В соответствие с переданными данными включаем реле
      for (int i = 0; i < 4; i++)
      {
         digitalWrite(pins[i], pinState[i]);
      }
      
      // Выводим HTML страницу, на которой пользователь может включить или выключить нужные ему реле
      client.println("HTTP/1.1 200 OK");
      client.println("Content-Type: text/html");
      client.println();
      client.println("<html>");
      client.println("<head>");
      //client.println("<meta http-equiv= Refresh content=15; >");
      client.println("<title>Управление аквариумом</title>");
      client.println("<meta http-equiv='Content-Type' content='text/html; charset=utf-8' /> ");
      client.println("</head>");
      client.println("<body>");
      //client.println("<h3>Zelectro. Relay + Ethernet shield.</h3>");
      client.println("<table align='left' border=0 cellpadding=1 cellspacing=1 style='width:190px'>");
      client.println("<tbody>");

      client.println("<tr>");
      client.println("<td>");
      client.println("<form method='post'>");
      client.print("<div> Авто/Ручной режим");
      client.println("</td>");
      client.println("<td>");
      client.println("<input type='checkbox' onClick='this.form.submit()' "); //<input  type="checkbox" onClick="this.form.submit()" name="test" value="test" />
      if (mode == true)
      client.print("checked");       //client.print("onClick='this.form.submit()'");
      client.println(" name='m0'></div>");
      client.println("</td>"); 
      client.println("</tr>");
      
      client.println("<tr>");
      client.println("<td>");
      client.println("<form method='post'>");
      client.print("<div> Свет");
      client.println("</td>");
      client.println("<td>");
      client.println("<input type='checkbox' onClick='this.form.submit()' "); //<input  type="checkbox" onClick="this.form.submit()" name="test" value="test" />
      if (pinState[0] == 1)
      client.print("checked");       //client.print("onClick='this.form.submit()'");
      client.println(" name='r0'></div>");
      client.println("</td>"); 
      client.println("</tr>");
      
      client.println("<tr>");
      client.println("<td>");
      client.print("<div>Фильтр");
      client.println("</td>");
      client.println("<td>");
      client.println(" <input type='checkbox' onClick='this.form.submit()' ");
      if (pinState[1] == 1)     // client.print("onClick='this.form.submit()'");
      client.print("checked");
      client.println(" name='r1'></div>");
      client.println("</td>");

      client.println("<tr>");
      client.println("<td>");
      client.print("<div>Компрессор");
      client.println("</td>");
      client.println("<td>");
      client.println(" <input type='checkbox' onClick='this.form.submit()' ");
      if (pinState[2] == 1)     // client.print("onClick='this.form.submit()'");
      client.print("checked");
      client.println(" name='r2'></div>");
      client.println("</td>");
      
      client.println("<tr>");
      client.println("<td>");
      client.print("<div>Обогрев");
      client.println("</td>");
      client.println("<td>");
      client.println(" <input type='checkbox' onClick='this.form.submit()' ");
      if (pinState[3] == 1)     // client.print("onClick='this.form.submit()'");
      client.print("checked");
      client.println(" name='r3'></div>");
      client.println("</td>"); 

      client.println("</tbody>");
      client.println("</table>");
      
      //client.println("<input type='submit' value='Refresh'>");
      client.println("</form>");
      client.println("</body>");
      client.println("</html>");
      client.stop(); 
    }
  }
}

 

Andrey-S
Offline
Зарегистрирован: 02.01.2015

Создайте еще одну переменную, которая будет переключать режимы и все... Вы должны понимать, что, к примеру, в строках 145, 157, 168, 179 содержатся имена отправляемых релюшек... Тобишь поставив галочку напротив всех реле получите строку вида r1=on&r2=on&r3=on&r4=on... Я сам начинал разбираться с этого примера и могу сказать, что посимвольный парсинг для новичков не самый простой вариант... Проще использовать String и парсить через indexOf(), хоть это и съедает побольше ресурсов..

mozgolomys
Offline
Зарегистрирован: 08.01.2016

Спасибо за ответ, все что вы написали я прекрасно понимаю, вы процитировали 51 строку. Если не сложно, ткните в инфу, где можно по подробнее почитать про post запрос и посимвольный парсинг именно в ардуино. Или если не сложно, объясните пожалуйста на пальцах.

Andrey-S
Offline
Зарегистрирован: 02.01.2015

Фух... ща попытаюсь...Вам нужно понять принцип работы всей этой штуковины... строка 047 подходит как раз к переданным командам POST-запроса...После нее можно создать строку типа String и зафигачить в нее все передаваемые данные... К примеру так в 049:


String X=""; //создаем пустую строку
while (chNext!=-1){  //пока строка не наткнулась на пустой символ -  он же конец передаваемых данных
chNext=client.read();//cчитываем байт
X+=chNext; // зафигачиваем в строку все что пришло...
}

int index_r1=X.indexOf("r1="); 

if (index_r1!=-1) {   //если такая совокупность символов найдена в строке Х

//делаем любое нам нужное действие... Почитайте тут про indexOf();

}

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

mozgolomys пишет:
// Выводим HTML страницу, на которой пользователь может включить или выключить нужные ему реле

Ужасная реализация генератора html кода. Я бы сделал так:

const char PROGMEM buf[]={"\
<html>\
<head>\
<title>Управление аквариумом</title>\
</head>\
<body>\
<input type='checkbox' %a> //%a сюда нужно подставить значение переменной
</body>\
</html>\
"};

//в коде
for (i=0; i<buflen; i++)
{
  char c = buf[i];
  if (c=='%')
  {
    if ((c=buf[++i])=='a')  client.print("checked"); 
    i++;
  }
  client.print(c);
}

 

mozgolomys
Offline
Зарегистрирован: 08.01.2016

Спасибо за ответы, попробую переварить и покажу на ваш суд, что получилось.

mozgolomys
Offline
Зарегистрирован: 08.01.2016

Andrey-S пишет:

X+=chNext; // зафигачиваем в строку все что пришло...


Сделал как вы говорили, но проблема в том, что X - string, а chNext - char. И одно в пихнуть другое напрямую нельзя.
Нужен какой-то костыль.
Попробовал сделать так:

String data = client.read();
              String indexmode="";
              while (data!=-1);{
               data= client.read();
               indexmode+=data;
              }
              mode = indexmode.indexOf("m");
             if (mode != -1){
              pinState[0] = 1;
             statemode=true; 
              
             }else{
              pinState[0] = 0;
              statemode=false;
             }

Та же проблема в string нельзя запихнуть int

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

mozgolomys пишет:
проблема в том, что X - string, а chNext - char. И одно в пихнуть другое напрямую нельзя.
Нужен какой-то костыль.
Есть пара функций для доступа к String как к char массиву charAt(), setCharAt().

int однозначно нужно превращать в строку itoa, print и т.п. функции в помощь.

mozgolomys
Offline
Зарегистрирован: 08.01.2016

нашел вот такой вариант с переводом char в String, но все ровно считать не получилось ничего. Судя по монитору порта, я подозреваю, что вхожу в цикл while и из него уже не выхожу, т.к. после установки галочки, страница уходит в долгую перезагрузку и в ответ "m" не приходит.



 String indexmode="";
              while (chNext!=-1);{
               chNext= client.read();
               indexmode+=String (chNext);
              }
              mode = indexmode.indexOf("m");
             if (mode != -1){
              pinState[0] = 1;
             statemode=true; 
              
             }else{
              pinState[0] = 0;
              statemode=false;
             }

 

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Цикл while(chNext != -1); обречен быть бесконечным из-за ; после while. По логике вещей цикл должен выглядеть так:

String indexmode;
char chNext; 
while (client.available()))
{
  chNext = client.read();
  if (chNext != -1) indexmode += chNext;
  ...
}

 

mozgolomys
Offline
Зарегистрирован: 08.01.2016

Или я что-то не понимаю или одно из двух. Этот вариант то же не работает.

/*ВНИМАНИЕ! Выводы 10, 11, 12 и 13 зарезервированы для сопряжения с модулем Ethernet и не могут использоваться никак иначе. 
 Таким образом, число доступных выводов уменьшается до 9, 4 из которых могут использоваться как выходы ШИМ. */

#include <SPI.h>
#include <Ethernet.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // Мак адрес
byte ip[] = { 192, 168, 1, 198 }; // IP адрес (В броузере вводим 192.168.0.2)
EthernetServer server(80);

int numPins = 4;
int pins[] = { 3, 5, 7, 9 };    // Пины для реле
int pinState[] = {0, 0, 0, 0};  // Состояние пинов
int mode;
bool statemode=false;

void setup()
{
  // Изначально выключаем все реле
  for (int i = 0; i < numPins; i++)
  {
    pinMode(pins[i], OUTPUT);
    digitalWrite(pins[i], 1);
    
  }
  
  Serial.begin(9600);
  Ethernet.begin(mac, ip);
  server.begin();
}

void loop()
{
  EthernetClient client = server.available();
  if (client)
  {
    // Проверяем подключен ли клиент к серверу
    while (client.connected())
    {
      // Проверяем идет ли запрос к серверу
      int dataCount = client.available();
      if (dataCount > 0)
      {
        // Считываем данные передаваемые серверу с клиента (браузера)
        for (int i = 0; i < dataCount; i++)
        {
          char ch = client.read();
          // Если данные передаются, то они будут переданы POST запросом, который начинается с символа 'P'
          if (i == 0 && ch != 'P')
            break;
          if (ch == '\n' && i < dataCount - 1)
          {
             // Находим строку, в которой содержатся передаваемые данные
             char chNext = client.read();
             // Формат строки r2=on&r3=on&r4=on (Пример если нужно включены 2,3,4 реле)
             if (chNext == 'r')
             {
               // Выключаем все реле
               pinState[0] = 0;
               pinState[1] = 0;
               pinState[2] = 0;
               pinState[3] = 0;
               

              
               // Считываем первый номер реле, который нужно включить
               char relayNum = client.read();
               pinState[relayNum-'0'] = 1;
               Serial.write(relayNum);
               
               // Считываем вспомогательную информацию (=on&)
               relayNum = client.read();
               relayNum = client.read();
               relayNum = client.read();
               relayNum = client.read();
                
               // Пока есть данные об остальных реле, считываем и заносим в массив pinState
               while (relayNum != -1)
               {
                  relayNum = client.read();
                  relayNum = client.read();
                  pinState[relayNum-'0'] = 1;
                  Serial.write(relayNum);
                  relayNum = client.read();
                  relayNum = client.read();
                  relayNum = client.read();
                  relayNum = client.read();
               }
             
             } else
             {
                // Если не было передано данных, то выключаем все реле
                pinState[0] = 0;
                pinState[1] = 0;
                pinState[2] = 0;
                pinState[3] = 0;
             }

             
              String indexmode;
             // char chNext;
              while (client.available()){
               chNext= client.read();
               if (chNext != -1) indexmode+=String (chNext);
              
              mode = indexmode.indexOf("m");
             if (mode != -1){
              pinState[0] = 1;
             statemode=true; 
              
             }else{
              pinState[0] = 0;
              statemode=false;
             }
                }

             
                       
          }
        }
      }
      
      // В соответствие с переданными данными включаем реле
      for (int i = 0; i < 4; i++)
      {
         digitalWrite(pins[i], pinState[i]);
      }
      
      // Выводим HTML страницу, на которой пользователь может включить или выключить нужные ему реле
      client.println("HTTP/1.1 200 OK");
      client.println("Content-Type: text/html");
      client.println();
      client.println("<html>");
      client.println("<head>");
      //client.println("<meta http-equiv= Refresh content=15; >");
      client.println("<title>Управление аквариумом</title>");
      client.println("<meta http-equiv='Content-Type' content='text/html; charset=utf-8' /> ");
      client.println("</head>");
      client.println("<body>");
      //client.println("<h3>Zelectro. Relay + Ethernet shield.</h3>");
      client.println("<table align='left' border=0 cellpadding=1 cellspacing=1 style='width:190px'>");
      client.println("<tbody>");

      client.println("<tr>");
      client.println("<td>");
      client.println("<form method='post'>");
      client.print("<div> Авто/Ручной режим");
      client.println("</td>");
      client.println("<td>");
      client.println("<input type='checkbox' onClick='this.form.submit()' "); //<input  type="checkbox" onClick="this.form.submit()" name="test" value="test" />
      if (statemode=true)
      client.print("checked");       //client.print("onClick='this.form.submit()'");
      client.println(" name='m'></div>");
      client.println("</td>"); 
      client.println("</tr>");
      
      client.println("<tr>");
      client.println("<td>");
      client.println("<form method='post'>");
      client.print("<div> Свет");
      client.println("</td>");
      client.println("<td>");
      client.println("<input type='checkbox' onClick='this.form.submit()' "); //<input  type="checkbox" onClick="this.form.submit()" name="test" value="test" />
      if (pinState[0] == 1)
      client.print("checked");       //client.print("onClick='this.form.submit()'");
      client.println(" name='r0'></div>");
      client.println("</td>"); 
      client.println("</tr>");
      
      client.println("<tr>");
      client.println("<td>");
      client.print("<div>Фильтр");
      client.println("</td>");
      client.println("<td>");
      client.println(" <input type='checkbox' onClick='this.form.submit()' ");
      if (pinState[1] == 1)     // client.print("onClick='this.form.submit()'");
      client.print("checked");
      client.println(" name='r1'></div>");
      client.println("</td>");

      client.println("<tr>");
      client.println("<td>");
      client.print("<div>Компрессор");
      client.println("</td>");
      client.println("<td>");
      client.println(" <input type='checkbox' onClick='this.form.submit()' ");
      if (pinState[2] == 1)     // client.print("onClick='this.form.submit()'");
      client.print("checked");
      client.println(" name='r2'></div>");
      client.println("</td>");
      
      client.println("<tr>");
      client.println("<td>");
      client.print("<div>Обогрев");
      client.println("</td>");
      client.println("<td>");
      client.println(" <input type='checkbox' onClick='this.form.submit()' ");
      if (pinState[3] == 1)     // client.print("onClick='this.form.submit()'");
      client.print("checked");
      client.println(" name='r3'></div>");
      client.println("</td>"); 

      client.println("</tbody>");
      client.println("</table>");
      
      //client.println("<input type='submit' value='Refresh'>");
      client.println("</form>");
      client.println("</body>");
      client.println("</html>");
      client.stop(); 
    }
  }
}

 

mozgolomys
Offline
Зарегистрирован: 08.01.2016

По поводу ; после цикла - мой промах. Но что-то не пойму. Сначала мы определили типы данных для indexmode и chNext, проверили что соединение есть и все в порядке, записали в chNext символ, проверили что строка не кончилась и переписали тип данных char в String?

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Слушай, ты замутил цикл for от 0 до количества символов в буфере, а пытаешься прочитать больше чем есть.

    relayNum = client.read();
    relayNum = client.read();
    relayNum = client.read();
    relayNum = client.read();

Этот код приведет к тому, что в буфере не останется принятых символов и очередная функция client.read() будет ждать пока не поступит сообщение в приемник. Функцию cient.read() надо вызывать столько раз сколько там реально есть символов.

А вообще я тебе изначально предлагал уйти от этой пурги:

...
      client.println("<tr>");
      client.println("<td>");
      client.println("<form method='post'>");
      client.print("<div> Авто/Ручной режим");
      client.println("</td>");
      client.println("<td>");
      client.println("<input type='checkbox' onClick='this.form.submit()' "); //<input  type="checkbox" onClick="this.form.submit()" name="test" value="test" />
      if (statemode=true)
      client.print("checked");       //client.print("onClick='this.form.submit()'");
      client.println(" name='m'></div>");
      client.println("</td>");
      client.println("</tr>");
      client.println("<tr>");
      client.println("<td>");
      client.println("<form method='post'>");
      client.print("<div> Свет");
      client.println("</td>");
      client.println("<td>");
      client.println("<input type='checkbox' onClick='this.form.submit()' "); //<input  type="checkbox" onClick="this.form.submit()" name="test" value="test" />
      if (pinState[0] == 1)
      client.print("checked");       //client.print("onClick='this.form.submit()'");
      client.println(" name='r0'></div>");
      client.println("</td>");
      client.println("</tr>");
...

Но ты меня на разбор POST запросов подписал :)

mozgolomys
Offline
Зарегистрирован: 08.01.2016

Andy пишет:
Но ты меня на разбор POST запросов подписал :)
Приношу извинения. Я еще очень плохо дружу с ардуино, да и если честно с программированием. По этому пытаюсь допилить уже готовый скетч.

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

POST запрос выглядит таким образом:

POST /login.php HTTP/1.1
User-Agent: Opera/9.80 (Windows NT 6.1; WOW64; U; ru) Presto/2.10.229 Version/11.62
Host: yourhost.ru
Accept: */*
Accept-Language: ru-RU,en
Connection: Close
Content-Length: 25
Content-Type: application/x-www-form-urlencoded
     
название_поля1=значение&название_поля2=значение&...

Размер заголовка может меняться, твоя задача убедиться что это POST запрос, найти в запросе пустую строку \r\n\r\n и после неё уже разбирать твой запрос. название_поля1=значение&название_поля2=значение&

Цикл может выглядеть так

String str, s="";
while (client.available()) s+=client.read();
//в строке s весь запрос полностью
if (s.indexOf("POST")==0)
{
  int i = s.indexOf("\r\n\r\n");
  if (i != -1) 
  {
    str = s.substring(i);
    //в str твой запрос, ищи в нем
    i=str.indexOf("название_поля1=");
    ....
  }
}

 

mozgolomys
Offline
Зарегистрирован: 08.01.2016

Если вы мне поможете, то попробую все переделать:



/*ВНИМАНИЕ! Выводы 10, 11, 12 и 13 зарезервированы для сопряжения с модулем Ethernet и не могут использоваться никак иначе.
 Таким образом, число доступных выводов уменьшается до 9, 4 из которых могут использоваться как выходы ШИМ. */

#include <SPI.h>
#include <Ethernet.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // Мак адрес
byte ip[] = { 192, 168, 1, 198 }; // IP адрес (В броузере вводим 192.168.0.2)
EthernetServer server(80);

int pins (3);    // Пины для реле

int mode;
bool statemode = false;
String str;
String s;
int i;


void setup()
{
  // Изначально выключаем все реле
  for (int i = 0; i < 1; i++)
  {
    pinMode(3, OUTPUT);
    digitalWrite(3, LOW);

  }

  Serial.begin(9600);
  Ethernet.begin(mac, ip);
  server.begin();
}

void loop()
{
  EthernetClient client = server.available();
  if (client)
  {
    // Проверяем подключен ли клиент к серверу
    while (client.connected())
    {
      if (client.available()) s += client.read();
      if (s.indexOf("POST") == 0)
      {
        i = s.indexOf("\r\n\r\n");
        if (i != -1)
        {
          str = s.substring(i);
          //в str твой запрос, ищи в нем
          i = str.indexOf("m");
          statemode = true;
        }
      }
 const char PROGMEM buf[]={"
 client.println("<html>");
 client.println("<head>");
 client.println("<title>");
  client.println("Управление аквариумом");
   client.println("</title>");
 client.println("</head>");
 client.println("<body>");
 client.println("<input type='checkbox' %a>"); //%a сюда нужно подставить значение переменной
 client.println("</body>");
 client.println("</html>");
 "};

//в коде
for (i=0; i<buflen; i++)
{
  char c = buf[i];
  if (c=='%')
  {
    if ((c=buf[++i])=='a')  client.print("checked"); 
    i++;
  }
  client.print(c);
}   


    client.stop();
  }
  }
}
Примерно должно так получиться?




 

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Не вопрос, только давай так, идеи за мной, отладка за тобой. Насколько я понимаю за основу взят библиотечный пример WebServer. Теперь к нему надо прикрутить парсер запросов и нормальный генератор html кода. Моя идея хранить в буфере html страничку целиком, и выводить её целиком в цикле 

for(i=0; i<len; i++) client.print(buf[i]);

, а не кусочками, как в примере при помощи тыщи команд 

client.print("<html>"); 
client.print("<head>");
client.print("<title>");
...

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

Есть одна засада, компиляторы не умеют инициализировать буфер из файла, поэтому предлагаю такой выход из ситуации: весь html код вынести в файл html.h, а в проект вставить при помощи директивы

#include "html.h"

В файле html.h мы просто объявим буфер и проинициализируем чистым html кодом твоей странички. Давай сначала эту фишку реализуем. С тебя нужен чистый html код твоей странички.

#include <SPI.h>
#include <Ethernet.h>
#include "html.h"

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 1, 177);

// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);

void setup()
{
  Serial.begin(9600);
   Ethernet.begin(mac, ip);
  server.begin();
}
const char PROGMEM header[]={"\
HTTP/1.1 200 OK\n\
Content-Type: text/html\n\
Connection: close\n\
\n\
"};

void loop() 
{
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) 
  {
    boolean currentLineIsBlank = true;
    while (client.connected()) 
    {
      if (client.available()) 
      {
        char c = client.read();
        Serial.write(c);
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) 
        {
          client.print(header); // send a standard http response header
          client.println(html); //здесь посылаем твою страничку, пока без изменений
          break;
        }
        if (c == '\n') 
        {
          // you're starting a new line
          currentLineIsBlank = true;
        }
        else if (c != '\r') 
        {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    delay(1); // give the web browser time to receive the data
    client.stop(); // close the connection:
  }
}

 

alexvs
Offline
Зарегистрирован: 22.07.2014

mozgolomys пишет:

Или я что-то не понимаю или одно из двух. Этот вариант то же не работает.

Изучите этот материал http://startingelectronics.org/tutorials/arduino/ethernet-shield-web-server-tutorial/

Тут все подробно изложено, причем от простого к сложному. 

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

alexvs пишет:

Изучите этот материал http://startingelectronics.org/tutorials/arduino/ethernet-shield-web-server-tutorial/

Тут все подробно изложено, причем от простого к сложному.

Говнопример, от него и пытаемся избавиться.

alexvs
Offline
Зарегистрирован: 22.07.2014

Тогда, по вашему, проект известный как Arduino Mega Server http://majordomo.smartliving.ru/forum/viewtopic.php?f=4&t=2347&sid=941635f1d7a7edbd3938e3e51bab724e , за основу которого взят тот самый цикл статей  - это говносервер? Тогда покажите миру что-то свое, гораздо более эффективное. Или расскажите, почему это говнопример?

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

alexvs, не указывай, что мне делать, и я не стану указывать, куда тебе идти.

alexvs
Offline
Зарегистрирован: 22.07.2014

Я не указываю, а прошу объяснить, почему цикл статей, на который я дал ссылку - это говнопример.

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Этот генератор html кода хороший пример "как не надо делать".

                    // send a standard http response header
                    client.println("HTTP/1.1 200 OK");
                    client.println("Content-Type: text/html");
                    client.println("Connection: close");
                    client.println();
                    // send web page
                    client.println("<!DOCTYPE html>");
                    client.println("<html>");
                    client.println("<head>");
                    client.println("<title>Arduino Web Page</title>");
                    client.println("</head>");
                    client.println("<body>");
                    client.println("<h1>Hello from Arduino!</h1>");
                    client.println("<p>A web page from the Arduino server</p>");
                    client.println("</body>");
                    client.println("</html>");

А это не парсер запросов, а кусок овна

                if (c == '\n' && currentLineIsBlank) {
                ...
                // every line of text received from the client ends with \r\n
                if (c == '\n') {
                    // last character on line of received text
                    // starting new line with next character read
                    currentLineIsBlank = true;
                } 
                else if (c != '\r') {
                    // a text character was received from client

Взамен этого я и предлагаю написать нормальный генератор html кода (без SD карты) и по человечески разобрать пару запросов.

alexvs
Offline
Зарегистрирован: 22.07.2014

Про первое - согласен, не очень правильно,  но на этапе изучения возможностей - вполне сойдет, только надо в каждой строке добавить F,  client.println(F("HTTP/1.1 200 OK"));, что бы зря не забивать оперативку.  Далее, в статьях, предлагается исходный код HTML вообще хранить в файлах на  SD Card и загружать странички прямо из файлов - что вообще самое правильное, на мой взгляд.

Ну и если не трудно, можно пример адекватного парсера?

GraninDm
Offline
Зарегистрирован: 01.08.2013

http://arduino.ru/forum/proekty/web-server-na-arduino-s-kontrollerom-temperatury

Посмотрите там мой 40 пост. Может это то что нужно?

Работает и в ручном режиме и в автоматическом.

Можно свои датчики подключить.

Вся web морда на sd карте

mozgolomys
Offline
Зарегистрирован: 08.01.2016

GraninDm спасибо за ссылку. Но хотелось бы поочередно разобарться как что формируется, особенно запросы и как это парсится.

Andy вот html странички, для начала. Приношу извинения за долгий ответ, но работа прежде всего.



<!DOCTYPE html>
<html>
    <head>
 <style>
#manauto {display: none;}
[for="manauto"] {
  position: relative;
  display: block;
  width: 95px;
  height: 10px;
  padding: 15px;
  border-radius: 50px;
  line-height: 10px;
  color: #00FF22;
  text-shadow: 1px 1px 0px rgba(255,255,255,.15);
  background: rgb(71, 71, 71);
  box-shadow:
       0 1px 0 rgba(255,255,255,.2),
       inset 0 0 0 5px rgb(60, 60, 60),
       inset 0 6px 6px rgba(0,0,0,.5),
       inset 0 -6px 1px rgba(255,255,255,.2);
  cursor: pointer;
}
[for="manauto"]:before {
  content: "MAN";
  position: absolute;
  right: 15px;
  color: #FF0000;
}
[for="manauto"]:after {
  content: "";
  position: absolute;
  left: 5px; top: 5px;
  display: block;
  width: 55px;
  height: 30px;
  border-radius: 50px;
  background: #ccc linear-gradient(#fcfff4 0%, #dfe5d7 40%, #b3bead 100%);
  transition: .5s;
}
#manauto:checked ~ [for="manauto"]:after {
  left: 65px;
}

#light {display: none;}
[for="light"] {
  position: relative;
  display: block;
  width: 95px;
  height: 10px;
  padding: 15px;
  border-radius: 50px;
  line-height: 10px;
  color: #00FF22;
  text-shadow: 1px 1px 0px rgba(255,255,255,.15);
  background: rgb(71, 71, 71);
  box-shadow:
       0 1px 0 rgba(255,255,255,.2),
       inset 0 0 0 5px rgb(60, 60, 60),
       inset 0 6px 6px rgba(0,0,0,.5),
       inset 0 -6px 1px rgba(255,255,255,.2);
  cursor: pointer;
}
[for="light"]:before {
  content: "OFF";
  position: absolute;
  right: 15px;
  color: #FF0000;
}
[for="light"]:after {
  content: "";
  position: absolute;
  left: 5px; top: 5px;
  display: block;
  width: 55px;
  height: 30px;
  border-radius: 50px;
  background: #ccc linear-gradient(#fcfff4 0%, #dfe5d7 40%, #b3bead 100%);
  transition: .5s;
}
#light:checked ~ [for="light"]:after {
  left: 65px;
}

#filter {display: none;}
[for="filter"] {
  position: relative;
  display: block;
  width: 95px;
  height: 10px;
  padding: 15px;
  border-radius: 50px;
  line-height: 10px;
  color: #00FF22;
  text-shadow: 1px 1px 0px rgba(255,255,255,.15);
  background: rgb(71, 71, 71);
  box-shadow:
       0 1px 0 rgba(255,255,255,.2),
       inset 0 0 0 5px rgb(60, 60, 60),
       inset 0 6px 6px rgba(0,0,0,.5),
       inset 0 -6px 1px rgba(255,255,255,.2);
  cursor: pointer;
}
[for="filter"]:before {
  content: "OFF";
  position: absolute;
  right: 15px;
  color: #FF0000;
}
[for="filter"]:after {
  content: "";
  position: absolute;
  left: 5px; top: 5px;
  display: block;
  width: 55px;
  height: 30px;
  border-radius: 50px;
  background: #ccc linear-gradient(#fcfff4 0%, #dfe5d7 40%, #b3bead 100%);
  transition: .5s;
}
#filter:checked ~ [for="filter"]:after {
  left: 65px;
}

#air {display: none;}
[for="air"] {
  position: relative;
  display: block;
  width: 95px;
  height: 10px;
  padding: 15px;
  border-radius: 50px;
  line-height: 10px;
  color: #00FF22;
  text-shadow: 1px 1px 0px rgba(255,255,255,.15);
  background: rgb(71, 71, 71);
  box-shadow:
       0 1px 0 rgba(255,255,255,.2),
       inset 0 0 0 5px rgb(60, 60, 60),
       inset 0 6px 6px rgba(0,0,0,.5),
       inset 0 -6px 1px rgba(255,255,255,.2);
  cursor: pointer;
}
[for="air"]:before {
  content: "OFF";
  position: absolute;
  right: 15px;
  color: #FF0000;
}
[for="air"]:after {
  content: "";
  position: absolute;
  left: 5px; top: 5px;
  display: block;
  width: 55px;
  height: 30px;
  border-radius: 50px;
  background: #ccc linear-gradient(#fcfff4 0%, #dfe5d7 40%, #b3bead 100%);
  transition: .5s;
}
#air:checked ~ [for="air"]:after {
  left: 65px;
}

#hiter {display: none;}
[for="hiter"] {
  position: relative;
  display: block;
  width: 95px;
  height: 10px;
  padding: 15px;
  border-radius: 50px;
  line-height: 10px;
  color: #00FF22;
  text-shadow: 1px 1px 0px rgba(255,255,255,.15);
  background: rgb(71, 71, 71);
  box-shadow:
       0 1px 0 rgba(255,255,255,.2),
       inset 0 0 0 5px rgb(60, 60, 60),
       inset 0 6px 6px rgba(0,0,0,.5),
       inset 0 -6px 1px rgba(255,255,255,.2);
  cursor: pointer;
}
[for="hiter"]:before {
  content: "OFF";
  position: absolute;
  right: 15px;
  color: #FF0000;
}
[for="hiter"]:after {
  content: "";
  position: absolute;
  left: 5px; top: 5px;
  display: block;
  width: 55px;
  height: 30px;
  border-radius: 50px;
  background: #ccc linear-gradient(#fcfff4 0%, #dfe5d7 40%, #b3bead 100%);
  transition: .5s;
}
#hiter:checked ~ [for="hiter"]:after {
  left: 65px;
}

</style>
</head>

<body>
<table align=left border=0 cellpadding=5 cellspacing=1 width="auto">
<tbody>
<tr>
<td>Режим работы</td>
<td><input type="checkbox" id="manauto" /><label for="manauto">AUTO</label></td>
<td>Feedback</td>
</tr>
<tr>
<td>Свет</td>
<td><input type="checkbox" id="light"/><label for="light">ON</label></td>
<td>Feedback</td>
</tr>
<tr>
<td>Фильтр</td>
<td><input type="checkbox" id="filter"/><label for="filter">ON</label></td>
<td>Feedback</td>
</tr>
<tr>
<td>Компрессор</td>
<td><input type="checkbox" id="air"/><label for="air">ON</label></td>
<td>Feedback</td>
</tr>
<tr>
<td>Нагреватель</td>
<td><input type="checkbox" id="hiter"/><label for="hiter">ON</label></td>
<td>Feedback</td>
</tr>
</tbody>
</table>
</body>
</html>

 

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Получилось вот так:

#include <SPI.h>
#include <Ethernet.h>
#include "HTML.h"
#include "request.h"

Crequest request;
const char PROGMEM ok[]={\
"HTTP/1.1 200 OK\r\n"\
"Content-Type: text/html\r\n"\
"\r\n"\
};
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 1, 177);

EthernetServer server(80);

void setup() 
{
  //Serial.begin(9600);
  Ethernet.begin(mac, ip);
  server.begin();
  request.init();
}

void loop() 
{
  EthernetClient client = server.available();// listen for incoming clients
  if (client) 
  {
    while (client.connected())
    {
      if (client.available() && request.received(client.read()))
      {
        switch (request.type())
        {
          case GET:  client.print(ok); client.print(html); break;
          case POST: client.print(ok); break;
          default: break;
        }
        break;
      }
    }
    client.stop();
    request.init();
  }
}

Это HTML.h

const char PROGMEM html[]={\
"<!DOCTYPE html>"\
"<html>"\
"<head>"\
"<style>"\
"#manauto {display: none;}"\
"[for='manauto'] {"\
"  position: relative;"\
"  display: block;"\
"  width: 95px;"\
"  height: 10px;"\
"  padding: 15px;"\
"  border-radius: 50px;"\
"  line-height: 10px;"\
"  color: #00FF22;"\
"  text-shadow: 1px 1px 0px rgba(255,255,255,.15);"\
"  background: rgb(71, 71, 71);"\
"  box-shadow:"\
"       0 1px 0 rgba(255,255,255,.2),"\
"       inset 0 0 0 5px rgb(60, 60, 60),"\
"       inset 0 6px 6px rgba(0,0,0,.5),"\
"       inset 0 -6px 1px rgba(255,255,255,.2);"\
"  cursor: pointer;"\
"}"\
"[for='manauto']:before {"\
"  content: 'MAN';"\
"  position: absolute;"\
"  right: 15px;"\
"  color: #FF0000;"\
"}"\
"[for='manauto']:after {"\
"  content: '';"\
"  position: absolute;"\
"  left: 5px; top: 5px;"\
"  display: block;"\
"  width: 55px;"\
"  height: 30px;"\
"  border-radius: 50px;"\
"  background: #ccc linear-gradient(#fcfff4 0%, #dfe5d7 40%, #b3bead 100%);"\
"  transition: .5s;"\
"}"\
"#manauto:checked ~ [for='manauto']:after {"\
"  left: 65px;"\
"}"\
"#light {display: none;}"\
"[for='light'] {"\
"  position: relative;"\
"  display: block;"\
"  width: 95px;"\
"  height: 10px;"\
"  padding: 15px;"\
"  border-radius: 50px;"\
"  line-height: 10px;"\
"  color: #00FF22;"\
"  text-shadow: 1px 1px 0px rgba(255,255,255,.15);"\
"  background: rgb(71, 71, 71);"\
"  box-shadow:"\
"       0 1px 0 rgba(255,255,255,.2),"\
"       inset 0 0 0 5px rgb(60, 60, 60),"\
"       inset 0 6px 6px rgba(0,0,0,.5),"\
"       inset 0 -6px 1px rgba(255,255,255,.2);"\
"  cursor: pointer;"\
"}"\
"[for='light']:before {"\
"  content: 'OFF';"\
"  position: absolute;"\
"  right: 15px;"\
"  color: #FF0000;"\
"}"\
"[for='light']:after {"\
"  content: '';"\
"  position: absolute;"\
"  left: 5px; top: 5px;"\
"  display: block;"\
"  width: 55px;"\
"  height: 30px;"\
"  border-radius: 50px;"\
"  background: #ccc linear-gradient(#fcfff4 0%, #dfe5d7 40%, #b3bead 100%);"\
"  transition: .5s;"\
"}"\
"#light:checked ~ [for='light']:after {"\
"  left: 65px;"\
"}"\
"#filter {display: none;}"\
"[for='filter'] {"\
"  position: relative;"\
"  display: block;"\
"  width: 95px;"\
"  height: 10px;"\
"  padding: 15px;"\
"  border-radius: 50px;"\
"  line-height: 10px;"\
"  color: #00FF22;"\
"  text-shadow: 1px 1px 0px rgba(255,255,255,.15);"\
"  background: rgb(71, 71, 71);"\
"  box-shadow:"\
"       0 1px 0 rgba(255,255,255,.2),"\
"       inset 0 0 0 5px rgb(60, 60, 60),"\
"       inset 0 6px 6px rgba(0,0,0,.5),"\
"       inset 0 -6px 1px rgba(255,255,255,.2);"\
"  cursor: pointer;"\
"}"\
"[for='filter']:before {"\
"  content: 'OFF';"\
"  position: absolute;"\
"  right: 15px;"\
"  color: #FF0000;"\
"}"\
"[for='filter']:after {"\
"  content: '';"\
"  position: absolute;"\
"  left: 5px; top: 5px;"\
"  display: block;"\
"  width: 55px;"\
"  height: 30px;"\
"  border-radius: 50px;"\
"  background: #ccc linear-gradient(#fcfff4 0%, #dfe5d7 40%, #b3bead 100%);"\
"  transition: .5s;"\
"}"\
"#filter:checked ~ [for='filter']:after {"\
"  left: 65px;"\
"}"\
"#air {display: none;}"\
"[for='air'] {"\
"  position: relative;"\
"  display: block;"\
"  width: 95px;"\
"  height: 10px;"\
"  padding: 15px;"\
"  border-radius: 50px;"\
"  line-height: 10px;"\
"  color: #00FF22;"\
"  text-shadow: 1px 1px 0px rgba(255,255,255,.15);"\
"  background: rgb(71, 71, 71);"\
"  box-shadow:"\
"       0 1px 0 rgba(255,255,255,.2),"\
"       inset 0 0 0 5px rgb(60, 60, 60),"\
"       inset 0 6px 6px rgba(0,0,0,.5),"\
"       inset 0 -6px 1px rgba(255,255,255,.2);"\
"  cursor: pointer;"\
"}"\
"[for='air']:before {"\
"  content: 'OFF';"\
"  position: absolute;"\
"  right: 15px;"\
"  color: #FF0000;"\
"}"\
"[for='air']:after {"\
"  content: '';"\
"  position: absolute;"\
"  left: 5px; top: 5px;"\
"  display: block;"\
"  width: 55px;"\
"  height: 30px;"\
"  border-radius: 50px;"\
"  background: #ccc linear-gradient(#fcfff4 0%, #dfe5d7 40%, #b3bead 100%);"\
"  transition: .5s;"\
"}"\
"#air:checked ~ [for='air']:after {"\
"  left: 65px;"\
"}"\
"#hiter {display: none;}"\
"[for='hiter'] {"\
"  position: relative;"\
"  display: block;"\
"  width: 95px;"\
"  height: 10px;"\
"  padding: 15px;"\
"  border-radius: 50px;"\
"  line-height: 10px;"\
"  color: #00FF22;"\
"  text-shadow: 1px 1px 0px rgba(255,255,255,.15);"\
"  background: rgb(71, 71, 71);"\
"  box-shadow:"\
"       0 1px 0 rgba(255,255,255,.2),"\
"       inset 0 0 0 5px rgb(60, 60, 60),"\
"       inset 0 6px 6px rgba(0,0,0,.5),"\
"       inset 0 -6px 1px rgba(255,255,255,.2);"\
"  cursor: pointer;"\
"}"\
"[for='hiter']:before {"\
"  content: 'OFF';"\
"  position: absolute;"\
"  right: 15px;"\
"  color: #FF0000;"\
"}"\
"[for='hiter']:after {"\
"  content: '';"\
"  position: absolute;"\
"  left: 5px; top: 5px;"\
"  display: block;"\
"  width: 55px;"\
"  height: 30px;"\
"  border-radius: 50px;"\
"  background: #ccc linear-gradient(#fcfff4 0%, #dfe5d7 40%, #b3bead 100%);"\
"  transition: .5s;"\
"}"\
"#hiter:checked ~ [for='hiter']:after {"\
"  left: 65px;"\
"}"\
"</style>"\
"</head>"\
"<body>"\
"<table align=left border=0 cellpadding=5 cellspacing=1 width='auto'>"\
"<tbody>"\
"<tr>"\
"<td>Режим работы</td>"\
"<td><input type='checkbox' id='manauto' /><label for='manauto'>AUTO</label></td>"\
"<td>Feedback</td>"\
"</tr>"\
"<tr>"\
"<td>Свет</td>"\
"<td><input type='checkbox' id='light'/><label for='light'>ON</label></td>"\
"<td>Feedback</td>"\
"</tr>"\
"<tr>"\
"<td>Фильтр</td>"\
"<td><input type='checkbox' id='filter'/><label for='filter'>ON</label></td>"\
"<td>Feedback</td>"\
"</tr>"\
"<tr>"\
"<td>Компрессор</td>"\
"<td><input type='checkbox' id='air'/><label for='air'>ON</label></td>"\
"<td>Feedback</td>"\
"</tr>"\
"<tr>"\
"<td>Нагреватель</td>"\
"<td><input type='checkbox' id='hiter'/><label for='hiter'>ON</label></td>"\
"<td>Feedback</td>"\
"</tr>"\
"</tbody>"\
"</table>"\
"</body>"\
"</html>"\
};

Это request.h

#define GET 0
#define POST 1
class Crequest
{
protected:
  String s;
  byte st;
  int i, dataLen;
  boolean bGet, bPost;
public:
  void init() {s=""; st=0; bGet=false; bPost=false; dataLen=0;}
  byte type(){if (bGet) return GET; if (bPost) return POST; return -1;}
  void LookForKeyWord()
  {
    if (s.indexOf("GET / ")!=-1) bGet=true;
    else if (s.indexOf("POST /")!=-1) bPost=true;
    else if (s.indexOf("Content-Length: ")!=-1) dataLen = s.substring(15).toInt();
    s="";
  }
  bool received(char c)
  {
    s+=c; //Собираю символы в строку
    switch(st)
    {
      case 0: if(c=='\r') st=1; break;
      case 1: if(c=='\n') {st=2; LookForKeyWord();} break;//получена строка запроса
      case 2: if(c=='\r') st=3; else st=0; break;
      case 3: if(c=='\n') {if (bGet) return true; st=4; s=""; i=0;} break;//получен заголовок запроса
      case 4: if (++i>=dataLen) return true; break;//Получены данные POST запроса
    }
  }
};

/*
Так выглядит GET запрос. Пустая строка это конец запроса
------------------------------------------------------------------------------------------
GET / HTTP/1.1\r\n
Host: 10.0.0.20\r\n
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:19.0) Gecko/20100101 Firefox/19.0\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*;q=0.8\r\n
Accept-Language: en-ZA,en-GB;q=0.8,en-US;q=0.5,en;q=0.3\r\n
Accept-Encoding: gzip, deflate\r\n
Connection: keep-alive\r\n
\r\n
------------------------------------------------------------------------------------------


Так выглядит POST запрос. Между заголовком и данными пустая строка. Content-Length: это длина данных.
------------------------------------------------------------------------------------------
POST /login.php HTTP/1.1\r\n
User-Agent: Opera/9.80 (Windows NT 6.1; WOW64; U; ru) Presto/2.10.229 Version/11.62\r\n
Host: yourhost.ru\r\n
Accept: *\r\n
Accept-Language: ru-RU,en\r\n
Connection: Close\r\n
Content-Length: 25\r\n
Content-Type: application/x-www-form-urlencoded\r\n
\r\n
name=value&name=value&...
------------------------------------------------------------------------------------------


На любой запрос отвечаем Ok. Ответ тоже заканчивается пустой строкой
------------------------------------------------------------------------------------------
HTTP/1.1 200 OK\r\n
Content-Type: text/html\r\n
\r\n
------------------------------------------------------------------------------------------

*/

Давай отладим это. Модификацию html и разбор данных POST запроса добавим позже.

mozgolomys
Offline
Зарегистрирован: 08.01.2016

Ошибок нет, но страничка не грузится. "Во время загрузки страницы соединение с сервером было сброшено."

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Нашел одну ошибку, в request.h между строками 30 и 31 нужно вставить return false;

mozgolomys
Offline
Зарегистрирован: 08.01.2016

исправил - ничего не изменилось

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

подключай Serial.print();

Для PROGMEM рекомендуют #include <avr/pgmspace.h>, попробуй добавить.

Попробуй вместо client.print(ok); client.print(html); вызвать функцию:

void func()
{
// send a standard http response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println();
// send web page
client.println("<!DOCTYPE html>");
client.println("<html>");
client.println("<head>");
client.println("<title>Arduino Web Page</title>");
client.println("</head>");
client.println("<body>");
client.println("<h1>Hello from Arduino!</h1>");
client.println("<p>A web page from the Arduino server</p>");
client.println("</body>");
client.println("</html>");
}

В общем надо отлаживать код. Если в коде что-то непонятно спрашивай.

mozgolomys
Offline
Зарегистрирован: 08.01.2016

client.print(html) - не выводит. Подозреваю, что нужно каким-то другим методом выводить содержимое html.

mozgolomys
Offline
Зарегистрирован: 08.01.2016

Судя по этой статье http://easyelectronics.ru/avr-uchebnyj-kurs-programmirovanie-na-si-rabota-s-pamyatyu-adresa-i-ukazateli.html мы не так выводим из памяти html. Наверное нужно что-то типа pgm_read_word, а потом уже запихивать это в printline.

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

mozgolomys пишет:
Наверное нужно что-то типа pgm_read_word, а потом уже запихивать это в printline.

Давай попробуем так. Добавь к массивам Ок и html символ \0 в самом конце.

const char PROGMEM ok[]={\
"HTTP/1.1 200 OK\r\n"\
"Content-Type: text/html\r\n"\
"\r\n\0"\
};

В html:

...
"</html>\0"\
};

Замени вызовы: client.print(Ok); на send(Ok); а clien.print(html); на send(html);

добавь функцию send

void send(char *ptr)
{
  char c;
  while(c=pgm_read_byte(ptr++)) client.print(c);
}

Эта функция нам потом все равно понадобится, при выводе htm кода будем налету подменять значения.

alexvs
Offline
Зарегистрирован: 22.07.2014

Andy пишет:

подключай Serial.print();

Для PROGMEM рекомендуют #include <avr/pgmspace.h>, попробуй добавить.

Попробуй вместо client.print(ok); client.print(html); вызвать функцию:

void func()
{
// send a standard http response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println();
// send web page
client.println("<!DOCTYPE html>");
client.println("<html>");
client.println("<head>");
client.println("<title>Arduino Web Page</title>");
client.println("</head>");
client.println("<body>");
client.println("<h1>Hello from Arduino!</h1>");
client.println("<p>A web page from the Arduino server</p>");
client.println("</body>");
client.println("</html>");
}

В общем надо отлаживать код. Если в коде что-то непонятно спрашивай.

А на несколько постов ранее......

Andy пишет:

Этот генератор html кода хороший пример "как не надо делать".

                    // send a standard http response header
                    client.println("HTTP/1.1 200 OK");
                    client.println("Content-Type: text/html");
                    client.println("Connection: close");
                    client.println();
                    // send web page
                    client.println("<!DOCTYPE html>");
                    client.println("<html>");
                    client.println("<head>");
                    client.println("<title>Arduino Web Page</title>");
                    client.println("</head>");
                    client.println("<body>");
                    client.println("<h1>Hello from Arduino!</h1>");
                    client.println("<p>A web page from the Arduino server</p>");
                    client.println("</body>");
                    client.println("</html>");

 

mozgolomys
Offline
Зарегистрирован: 08.01.2016

Для alexvs. Функция func() предлагалась мне временно, для вычисления места до которого у меня работает код. Это пока для меня единственный меттод для определения места возникновения проблемы. Правда сегодня пол ночи потратил, что бы нормально прикрутить к atmes studia 6.2 Visual Micro, но уйти от ошибки при компиляции об отсутствии cor.a так и не смог.

mozgolomys
Offline
Зарегистрирован: 08.01.2016

Andy пишет:

Давай попробуем так. Добавь к массивам Ок и html символ \0 в самом конце.

const char PROGMEM ok[]={\
"HTTP/1.1 200 OK\r\n"\
"Content-Type: text/html\r\n"\
"\r\n\0"\
};

В html:

...
"</html>\0"\
};

Ничего не изменилось.

mozgolomys
Offline
Зарегистрирован: 08.01.2016

Ругается на 32 строчку exit status 1'client' was not declared in this scope

#include <SPI.h>
#include <Ethernet.h>
#include <HTML.h>
#include <request.h>
#include <avr/pgmspace.h>

Crequest request;
const char PROGMEM ok[]={\
"HTTP/1.1 200 OK\r\n"\
"Content-Type: text/html\r\n"\
"\r\n\0"\
};

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 1, 198);

EthernetServer server(80);

void setup() 
{
  //Serial.begin(9600);
  Ethernet.begin(mac, ip);
  server.begin();
  request.init();
}

void send(char *ptr)
{
  char c;
  while(c=pgm_read_byte(ptr++)) client.print(c);
}

void loop() 
{
  EthernetClient client = server.available();// listen for incoming clients
  if (client) 
  {
    while (client.connected())
    {
      if (client.available() && request.received(client.read()))
      {

       switch (request.type())
        {
          case GET:  send(Ok); send(html); break;
          case POST: send(Ok); break;
          default: break;
        }
        break;
      }
    }
    client.stop();
    request.init();
  }
}

Ставил  void send(char *ptr) после void loop(), ругался на 47 строчку exit status 1'Ok' was not declared in this scope

alexvs
Offline
Зарегистрирован: 22.07.2014

Зачем ты полез в такие дебри если ты путаешься с областью видимости переменных?

Где у тебя объявлена переменная client? Правильно, в loop(), так с какого перепугу ты ее пытаешься заюзать в send()? Или объявляй ее как глобальную, или передавай в send().

Я тебе дал ссылку на прекрасный материал, котрый проведет тебя от простого к сложному в области создания веб-сервера на Ардуино, но ты упорно бьешься над своими ошибками, не понимя, что делаешь. 

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Вот так без ошибок

#include <SPI.h>
#include <Ethernet.h>
#include "HTML.h"
#include "request.h"
#include <avr/pgmspace.h>

Crequest request;
const char PROGMEM Ok[]={\
"HTTP/1.1 200 OK\r\n"\
"Content-Type: text/html\r\n"\
"\r\n\0"\
};

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 1, 198);

EthernetServer server(80);
EthernetClient client;
void setup() 
{
  //Serial.begin(9600);
  Ethernet.begin(mac, ip);
  server.begin();
  request.init();
}

void send(const char *ptr)
{
  char c;
  while(c=pgm_read_byte(ptr++)) client.print(c);
}

void loop() 
{
  client = server.available();// listen for incoming clients
  if (client) 
  {
    while (client.connected())
    {
      if (client.available() && request.received(client.read()))
      {

       switch (request.type())
        {
          case GET:  send(Ok); send(html); break;
          case POST: send(Ok); break;
          default: break;
        }
        break;
      }
    }
    client.stop();
    request.init();
  }
}

 

mozgolomys
Offline
Зарегистрирован: 08.01.2016

Все заработало!

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Отлично! Теперь нам надо, что бы html страничка отображала значения переменных. Есть несколько вариантов:

1. Менять html код налету, во время вывода. В браузере требуется обновление всей странички, решается при помощи refresh. Можно обойтись без скриптов. В html коде размещаем ключевые символы, которые при выводе подменяем значениями переменных. С точки зрения повторения проекта другими - это не очень наглядный способ.

2. Использовать скрипты: <script type=" text/javascript" src="URL"></script> где URL будет указывать на наш скрипт с переменными. Скрипт достаточно простой, можно создавать во время вывода. В браузере требуется обновление всей странички, решается при помощи refresh или скриптов. В коде html размещаем идентификаторы id='sensor1'. В скрипте создаем запись типа document.getElementById('sensor1').value = 123; Потребуется разбор GET запроса. С точки зрения повторения проекта другими - это более наглядный способ.

3. Использовать iframe. В браузере обновлять можно только iframe при помощи скриптов. Потребуется разбор GET запросов. С точки зрения повторения проекта другими - достаточно наглядный способ.

Какой вариант тебе больше нравится?

mozgolomys
Offline
Зарегистрирован: 08.01.2016

2 вариант

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Вот как это будет выглядеть

Это твой html с небольшими изменениями:

<!DOCTYPE html>
<html>
    <head>
 <style>
#manauto {display: none;}
[for="manauto"] {
  position: relative;
  display: block;
  width: 95px;
  height: 10px;
  padding: 15px;
  border-radius: 50px;
  line-height: 10px;
  color: #00FF22;
  text-shadow: 1px 1px 0px rgba(255,255,255,.15);
  background: rgb(71, 71, 71);
  box-shadow:
       0 1px 0 rgba(255,255,255,.2),
       inset 0 0 0 5px rgb(60, 60, 60),
       inset 0 6px 6px rgba(0,0,0,.5),
       inset 0 -6px 1px rgba(255,255,255,.2);
  cursor: pointer;
}
[for="manauto"]:before {
  content: "MAN";
  position: absolute;
  right: 15px;
  color: #FF0000;
}
[for="manauto"]:after {
  content: "";
  position: absolute;
  left: 5px; top: 5px;
  display: block;
  width: 55px;
  height: 30px;
  border-radius: 50px;
  background: #ccc linear-gradient(#fcfff4 0%, #dfe5d7 40%, #b3bead 100%);
  transition: .5s;
}
#manauto:checked ~ [for="manauto"]:after {
  left: 65px;
}

#light {display: none;}
[for="light"] {
  position: relative;
  display: block;
  width: 95px;
  height: 10px;
  padding: 15px;
  border-radius: 50px;
  line-height: 10px;
  color: #00FF22;
  text-shadow: 1px 1px 0px rgba(255,255,255,.15);
  background: rgb(71, 71, 71);
  box-shadow:
       0 1px 0 rgba(255,255,255,.2),
       inset 0 0 0 5px rgb(60, 60, 60),
       inset 0 6px 6px rgba(0,0,0,.5),
       inset 0 -6px 1px rgba(255,255,255,.2);
  cursor: pointer;
}
[for="light"]:before {
  content: "OFF";
  position: absolute;
  right: 15px;
  color: #FF0000;
}
[for="light"]:after {
  content: "";
  position: absolute;
  left: 5px; top: 5px;
  display: block;
  width: 55px;
  height: 30px;
  border-radius: 50px;
  background: #ccc linear-gradient(#fcfff4 0%, #dfe5d7 40%, #b3bead 100%);
  transition: .5s;
}
#light:checked ~ [for="light"]:after {
  left: 65px;
}

#filter {display: none;}
[for="filter"] {
  position: relative;
  display: block;
  width: 95px;
  height: 10px;
  padding: 15px;
  border-radius: 50px;
  line-height: 10px;
  color: #00FF22;
  text-shadow: 1px 1px 0px rgba(255,255,255,.15);
  background: rgb(71, 71, 71);
  box-shadow:
       0 1px 0 rgba(255,255,255,.2),
       inset 0 0 0 5px rgb(60, 60, 60),
       inset 0 6px 6px rgba(0,0,0,.5),
       inset 0 -6px 1px rgba(255,255,255,.2);
  cursor: pointer;
}
[for="filter"]:before {
  content: "OFF";
  position: absolute;
  right: 15px;
  color: #FF0000;
}
[for="filter"]:after {
  content: "";
  position: absolute;
  left: 5px; top: 5px;
  display: block;
  width: 55px;
  height: 30px;
  border-radius: 50px;
  background: #ccc linear-gradient(#fcfff4 0%, #dfe5d7 40%, #b3bead 100%);
  transition: .5s;
}
#filter:checked ~ [for="filter"]:after {
  left: 65px;
}

#air {display: none;}
[for="air"] {
  position: relative;
  display: block;
  width: 95px;
  height: 10px;
  padding: 15px;
  border-radius: 50px;
  line-height: 10px;
  color: #00FF22;
  text-shadow: 1px 1px 0px rgba(255,255,255,.15);
  background: rgb(71, 71, 71);
  box-shadow:
       0 1px 0 rgba(255,255,255,.2),
       inset 0 0 0 5px rgb(60, 60, 60),
       inset 0 6px 6px rgba(0,0,0,.5),
       inset 0 -6px 1px rgba(255,255,255,.2);
  cursor: pointer;
}
[for="air"]:before {
  content: "OFF";
  position: absolute;
  right: 15px;
  color: #FF0000;
}
[for="air"]:after {
  content: "";
  position: absolute;
  left: 5px; top: 5px;
  display: block;
  width: 55px;
  height: 30px;
  border-radius: 50px;
  background: #ccc linear-gradient(#fcfff4 0%, #dfe5d7 40%, #b3bead 100%);
  transition: .5s;
}
#air:checked ~ [for="air"]:after {
  left: 65px;
}

#hiter {display: none;}
[for="hiter"] {
  position: relative;
  display: block;
  width: 95px;
  height: 10px;
  padding: 15px;
  border-radius: 50px;
  line-height: 10px;
  color: #00FF22;
  text-shadow: 1px 1px 0px rgba(255,255,255,.15);
  background: rgb(71, 71, 71);
  box-shadow:
       0 1px 0 rgba(255,255,255,.2),
       inset 0 0 0 5px rgb(60, 60, 60),
       inset 0 6px 6px rgba(0,0,0,.5),
       inset 0 -6px 1px rgba(255,255,255,.2);
  cursor: pointer;
}
[for="hiter"]:before {
  content: "OFF";
  position: absolute;
  right: 15px;
  color: #FF0000;
}
[for="hiter"]:after {
  content: "";
  position: absolute;
  left: 5px; top: 5px;
  display: block;
  width: 55px;
  height: 30px;
  border-radius: 50px;
  background: #ccc linear-gradient(#fcfff4 0%, #dfe5d7 40%, #b3bead 100%);
  transition: .5s;
}
#hiter:checked ~ [for="hiter"]:after {
  left: 65px;
}

</style>
<script type="text/javascript" src="script.js"></script>
</head>

<body onload="setVars();">
<table align=left border=0 cellpadding=5 cellspacing=1 width="auto">
<tbody>
<tr>
<td>Режим работы</td>
<td><input type="checkbox" id="manauto" /><label for="manauto">AUTO</label></td>
<td>Feedback</td>
</tr>
<tr>
<td>Свет</td>
<td><input type="checkbox" id="light"/><label for="light">ON</label></td>
<td>Feedback</td>
</tr>
<tr>
<td>Фильтр</td>
<td><input type="checkbox" id="filter"/><label for="filter">ON</label></td>
<td>Feedback</td>
</tr>
<tr>
<td>Компрессор</td>
<td><input type="checkbox" id="air"/><label for="air">ON</label></td>
<td>Feedback</td>
</tr>
<tr>
<td>Нагреватель</td>
<td><input type="checkbox" id="hiter"/><label for="hiter">ON</label></td>
<td>Feedback</td>
</tr>
</tbody>
</table>
</body>
</html>

Это скрипт, который мы будем создавать во время вывода:

function setVars()
{
 document.getElementById('manauto').checked='true';
 document.getElementById('light').checked='true';
 document.getElementById('filter').checked='true';
 document.getElementById('air').checked='true';
 document.getElementById('hiter').checked='true';
}

 

mozgolomys
Offline
Зарегистрирован: 08.01.2016

чего-то я ничего не понял.
1. Мы уже не используем PROGMEM html[]?
2. script.js - это function set()?
3. onload="setVars() - у нас вроде нигде не используется setVars?

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

mozgolomys пишет:
чего-то я ничего не понял. 1. Мы уже не используем PROGMEM html[]? 2. script.js - это function set()? 3. onload="setVars() - у нас вроде нигде не используется setVars?

1.Используем, это я выложил чистый код html, его можно в браузере открыть. Код для ардуины я выложу чуть позже.

2.Опечаточка произошла: script.js - это function setVars(). Она же вызывается по onload в body.

Вопрос такой: у тебя 5 переменных. В html коде нет ни одной формы. Будем делать 5 форм (по одной на каждую переменную) или одну форму на все?

inspiritus
Offline
Зарегистрирован: 17.12.2012

Хмм.. А про Ajax почитать ?

http://www.ibm.com/developerworks/ru/views/xml/libraryview.jsp?search_by=Ajax+master

и куча ссылок по запросу "arduino ajax" с работающими примерами

alexvs
Offline
Зарегистрирован: 22.07.2014

inspiritus пишет:

Хмм.. А про Ajax почитать ?

http://www.ibm.com/developerworks/ru/views/xml/libraryview.jsp?search_by=Ajax+master

и куча ссылок по запросу "arduino ajax" с работающими примерами

Да я предлогал ТС данный материал для изучения, но Andy отговорил его, сказав, что это говнопример.

mozgolomys
Offline
Зарегистрирован: 08.01.2016

Andy пишет:
Вопрос такой: у тебя 5 переменных. В html коде нет ни одной формы. Будем делать 5 форм (по одной на каждую переменную) или одну форму на все?

У меня все в табличку впихнуто. По логике, если будет всю страничку обновлять, то смысл тогда делать отдельные формы. Но я в дальнейшем планирую еще температуру выводить, обратную связь от реле.

mozgolomys
Offline
Зарегистрирован: 08.01.2016

alexvs пишет:

inspiritus пишет:

Хмм.. А про Ajax почитать ?

http://www.ibm.com/developerworks/ru/views/xml/libraryview.jsp?search_by=Ajax+master

и куча ссылок по запросу "arduino ajax" с работающими примерами

Да я предлогал ТС данный материал для изучения, но Andy отговорил его, сказав, что это говнопример.

Я по мере наличия времени изучаю любезно скинутые вами ссылки и возможно в дальнейшем где-нибудь применю.

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

mozgolomys пишет:
По логике, если будет всю страничку обновлять, то смысл тогда делать отдельные формы.
На стороне сервера разбирать по одной переменной или сразу 5... В случае добавления новой переменной изменений в коде будет меньше, если в запросе только одна переменная.