- Web - server на Arduino с авторизацией доступа

Web-server на Arduino MEGA и контроллере сети w5500 с авторизацией доступа для удаленного управления

Практика для студентов. Мясищев А.А.

Более подробное описание можно посмотреть здесь

1.Механизм авторизации и простая программа web-сервера на Arduino, реализующая этот механизм

Фото стенда сервера на Arduino mega

Обозначение выводов модуля на базе w5500

Подключение Arduino mega к модулю w5500 для библиотеки Ethernet2 выполняется по схеме:

Arduino mega Модуль w5500

10 SCS

51 MOSI

50 MISO

52 SCLK

Аппаратный вывод 53 SCS Arduino mega библиотека Ethernet2 не использует.

Подключение датчика температуры DS18B20 возможно двумя способами, как показано ниже:

Нормальный режим питания

Паразитный режим питания

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

Механизм авторизации выглядит следующим образом.

1.Сначала браузер, например Amigo, посылает серверу(Arduino) без запроса авторизации

GET / HTTP/1.1

Host: 192.168.1.18:81

Connection: keep-alive

Cache-Control: max-age=0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8

Upgrade-Insecure-Requests: 1

User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.4.2403.3 Amigo/44.4.2403.3 MRCHROME SOC Safari/537.36

Accept-Encoding: gzip, deflate, sdch

Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4

2.Сервер Arduino отвечает браузеру заголовком на необходимость запроса с авторизацией

HTTP/1.0 401 Unauthorized

WWW-Authenticate: Basic realm="Arduino - HOME"

3 Браузер Amigo посылает серверу запрос но уже с авторизацией

GET / HTTP/1.1

Host: 192.168.1.18:81

Connection: keep-alive

Cache-Control: max-age=0

Authorization: Basic YWxleDoxMzY=

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8

Upgrade-Insecure-Requests: 1

User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.4.2403.3 Amigo/44.4.2403.3 MRCHROME SOC Safari/537.36

Accept-Encoding: gzip, deflate, sdch

Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4

Сервер Arduino посылает ответ и после пустой строки html документ

HTTP/1.0 200 OK

Content-Type: text/html

<Здесь идет передача браузеру html документа>

YWxleDoxMzY= -это закодированный в Base64 набор символов alex:136 (alex - это login, 136 - password, которые вводятся в выскакивающем у браузере окне авторизации).

Интерфейсы ввода логина и пароля и ответа сервера Arduino

Ниже представлена простая программа, реализующая этот механизм

Здесь используется для w5500 библиотека Ethernet2. Входящая в Arduino IDE библиотека Ethernet с модулем w5500 не работает.

#include <SPI.h>

#include <Ethernet2.h> // Used for Ethernet w5500

byte mac[] = { 0x54, 0x34, 0x41, 0x30, 0x30, 0x32 };

IPAddress ip(192, 168, 1, 18);

EthernetServer server(81);

String readString;

void setup() {

Serial.begin(9600);

Ethernet.begin(mac, ip);

server.begin();

Serial.println(Ethernet.localIP());

}

void loop() {

EthernetClient client = server.available();

if (client) {

boolean currentLineIsBlank = true;

while (client.connected()) {

if (client.available()) {

char c = client.read();

readString += c;

Serial.write(c);

if (c == '\n' && currentLineIsBlank) {

if (readString.lastIndexOf("YWxleDoxMzY=")>-1) {

if (readString.lastIndexOf("GET /favicon.ico")>-1) {

client.println("HTTP/1.0 404 Not Found");

}

else html_doc(client);

}

else {

client.println("HTTP/1.0 401 Unauthorized");

client.println("WWW-Authenticate: Basic realm=\"Arduino - HOME\"");

}

break;

}

if (c == '\n') {

currentLineIsBlank = true;

}

else if (c != '\r') {

currentLineIsBlank = false;

}

}

}

delay(10);

readString = "";

client.stop();

}

}

void html_doc(EthernetClient client)

{

client.println("HTTP/1.0 200 OK");

client.println("Content-Type: text/html\r\n");

client.println("<html><head><meta charset=UTF-8><title>Arduino</title>");

client.println("<font size=5 color=blue> Web-server на Arduino MEGA 1280 <br>и контроллере w5500<br>с аутентификацией</font></head><body>");

client.println("<hr>");

client.println("<font size=4 color=red>Arduino on </font><a href=\"https://arduino.cc\"><font size=4>ARDUINO</font></a>");

client.println("</body></html>");

}

Однако безопасность здесь сомнительная. Пакеты по Интернет передаются в открытом виде, поэтому закодированный логин и пароль (YWxleDoxMzY=) можно легко выловить с помощью программ снифферов и раскодировать с помощью Base64 decode.

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

Ниже представлена модернизированная программа

#include <SPI.h>

#include <Ethernet2.h> // Used for Ethernet

byte mac[] = { 0x54, 0x34, 0x41, 0x30, 0x30, 0x32 };

IPAddress ip(192, 168, 1, 18);

EthernetServer server(81);

String readString; // Буфер для данных от пользователя Web сервера

int passwd=1;

void setup() {

Serial.begin(9600);

Ethernet.begin(mac, ip);

server.begin();

Serial.println(Ethernet.localIP());

}

void loop() {

EthernetClient client = server.available();

if (client) {

boolean currentLineIsBlank = true;

while (client.connected()) {

if (client.available()) {

char c = client.read();

readString += c;

Serial.write(c);

if (c == '\n' && currentLineIsBlank) {

// 1-й пароль

if (readString.lastIndexOf("YWxleDoxMzY=")>-1 && passwd==1) {

passwd=2;

if (readString.lastIndexOf("GET /favicon.ico")>-1) {

client.println("HTTP/1.0 404 Not Found");

}

else html_doc(client);

}

// 2-й пароль

else if (readString.lastIndexOf("YWxleDoxMzg=")>-1 && passwd==2) {

passwd=3;

if (readString.lastIndexOf("GET /favicon.ico")>-1) {

client.println("HTTP/1.0 404 Not Found");

}

else html_doc(client);

}

// 3-й пароль

else if (readString.lastIndexOf("YWxleDoxNDA=")>-1 && passwd==3) {

passwd=1;

if (readString.lastIndexOf("GET /favicon.ico")>-1) {

client.println("HTTP/1.0 404 Not Found");

}

else html_doc(client);

}

else {

client.println("HTTP/1.0 401 Unauthorized");

client.println("WWW-Authenticate: Basic realm=\"Arduino - HOME\"");

}

break;

}

if (c == '\n') {

currentLineIsBlank = true;

}

else if (c != '\r') {

currentLineIsBlank = false;

}

}

}

delay(10);

readString = "";

client.stop();

}

}

void html_doc(EthernetClient client)

{

client.println("HTTP/1.0 200 OK");

client.println("Content-Type: text/html\r\n");

client.println("<html><head><meta charset=UTF-8><title>Arduino</title>");

client.println("<font size=5 color=blue> Web-server на Arduino MEGA 1280 <br>и контроллере w5500 <br>с аутентификацией</font></head><body>");

client.println("<hr>");

client.println("<font size=4 color=red>Arduino on </font><a href=\"https://arduino.cc\"><font size=4>ARDUINO</font></a>");

client.println("<hr>");

client.print("Index:");

client.println(passwd);

client.println("</body></html>");

}

Эта простая демонстрационная программа сервера использует 3 пары логин:пароль

1. alex:136

2. alex:138

3. alex:140

При каждом новом обращении к серверу пароль циклически меняется на следующий в списке. Для того, чтобы знать следующий номер пароля в браузере выводится параметр index. Его пользователь сервера должен запомнить. Однако в последнем практическом примере показано, как при обращении по адресу http://192.168.1.18:81/index можно узнать номер следующего пароля без захода на страничку управления сервером. Таким образом, чем больше паролей в списке, тем более защищенным должен выглядеть сервер.

Интерфейс модернизированной программы

В представленном интерфейсе Index:3 обозначает то, что при следующем входе на сервер необходимо для авторизации использовать пару alex:140

Замечание: В интерфейсе указан контроллер enc28j60, который может также использоваться, если в программе вместо #include <Ethernet2.h> поставить #include <UIPEthernet.h> и установить в среде Arduino IDE библиотеку UIPEthernet.

2. Web-server на Arduino MEGA и контроллере сети w5500 с авторизацией доступа для удаленного управления и доступа к датчикам температуры и влажности

Интерфейс управления сервером на Arduino mega

На сервере установлены 3 светодиода, которые имитируют включение-выключение 3-х силовых источников питания(например электро-розеток), датчик температуры DS18B20(температура улицы) и датчик влажности и температуры DHT 11 (делает измерения в помещении).

Передача данных выполняется с помощью POST запроса. Данные запроса размещаются после пустой строки заголовка, который посылает браузер web-серверу Arduino:

POST / HTTP/1.1

Accept: text/html, application/xhtml+xml, image/jxr, */*

Referer: http://192.168.1.18:81/

Accept-Language: ru,en-US;q=0.8,en;q=0.5,uk;q=0.3

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393

Content-Type: application/x-www-form-urlencoded

Accept-Encoding: gzip, deflate

Host: 192.168.1.18:81

Content-Length: 23

Connection: Keep-Alive

Cache-Control: no-cache

Authorization: Basic YWxleDoxMzY=

r=0&g=1&b=0&av=2018year

Последняя строка - это передача данных методом POST. Эти данные должны быть обработаны сервером для управления светодиодами. Arduino сервер обрабатывает ее операторами

while(client.available()) { //Обработка запроса POST

post = client.read();

if(buffer.length() <= bufferMax) buffer +=post;

}

Включение и выключение светодиодов определяется параметрами r, g и b. Если r=1 - красный светодиод включен, если r=0 - выключен. Аналогично для зеленого(g) и синего(b). Это выполняется операторами:

if(buffer.indexOf("r=1") >= 0) {digitalWrite(3, HIGH);}

if(buffer.indexOf("r=0") >= 0) {digitalWrite(3, LOW);}

if(buffer.indexOf("g=1") >= 0) {digitalWrite(5, HIGH);}

if(buffer.indexOf("g=0") >= 0) {digitalWrite(5, LOW);}

if(buffer.indexOf("b=1") >= 0) {digitalWrite(7, HIGH);}

if(buffer.indexOf("b=0") >= 0) {digitalWrite(7, LOW);}

После авторизированного входа на страничку управления работу с сервером удобно организовать так, чтобы после каждого изменения параметров светодиодов вход был не авторизированным. Для этого форма должна посылать серверу какой-то дополнительный код(набор символов), получив который сервер бы не запрашивал авторизацию. В этой программе посылается код 2018year с помощью оператора

client.println("<input type='hidden' name='av' value='2018year'>");

Так как поле имеет тип hidden, браузер его не отобразит, но методом PUT будет передано значение 2018year с параметром av (r=0&g=1&b=0&av=2018year). С помощью операторов

else if (buffer.lastIndexOf("2018year")>-1 ) {

if (readString.lastIndexOf("GET /favicon.ico")>-1) {

client.println("HTTP/1.0 404 Not Found");

}

else { onoff(); html_doc(client); }

}

будет выполняться беспарольный вход на страничку управления. Однако для обеспечения лучшей защиты сервера Arduino из программы указанные выше операторы лучше убрать.

Как было указано выше для лучшей защиты сервера программа использует список паролей. Очередной пароль задается номером index. С помощью операторов

else if (readString.lastIndexOf("GET /index")>-1 ) {

if (readString.lastIndexOf("GET /favicon.ico")>-1) {

client.println("HTTP/1.0 404 Not Found");

}

else html_doc_index(client);

}

и функции void html_doc_index(EthernetClient client) реализована возможность определения следующего по списку пароля путем набора в браузере адресной строки:

http://192.168.1.18:81/index

Браузер распечатывает:

Ваш index: 2

Программа web-сервера в среде разработки Arduino IDE ver. 1.8.6

//#include <SPI.h> // Used for Ethernet w5100,w5500

//#include <Ethernet.h> // Used for Ethernet w5100

//#include <Ethernet2.h> // Used for Ethernet w5500

#include <UIPEthernet.h> // Used for Ethernet enc28j60

#include <OneWire.h>

#include <DallasTemperature.h>

#include "DHT.h"

#define ONE_WIRE_BUS 2

#define bufferMax 64

#define readMax 256 // Для Microsoft Edge необходимо установить 512, так как код авторизации он устанавливает в конце заголовка

#define DHTPIN 6 // 2 Pin DHT11 подключен к 6-му выводу Arduino

#define DHTTYPE DHT11 // Выбран датчик DHT 11

DHT dht(DHTPIN, DHTTYPE);

OneWire oneWire(ONE_WIRE_BUS);

DallasTemperature sensors(&oneWire);

byte mac[] = { 0x54, 0x34, 0x41, 0x30, 0x30, 0x32 };

IPAddress ip(192, 168, 1, 18);

EthernetServer server(81);

int passwd=1;

char post;

void setup() {

pinMode(3, OUTPUT); // 3-й вывод определен как выход для светодиода

pinMode(5, OUTPUT); // 5-й вывод определен как выход

pinMode(7, OUTPUT); // 7-й вывод определен как выход

Serial.begin(9600);

Ethernet.begin(mac, ip);

server.begin();

sensors.begin();

dht.begin(); // Запуск библиотеки DHT

Serial.println(Ethernet.localIP());

}

void loop() {

EthernetClient client = server.available();

if (client) {

String readString = "";

String buffer = "";

boolean currentLineIsBlank = true;

while (client.connected()) {

if (client.available()) {

char c = client.read();

// readString += c; // Запись всего заголовка в память. Много мусора, SRAM память не экономиться

if(readString.length() <= readMax) readString +=c; // Для экономии памяти записывает не весь заголовок, а то что нужно

// Serial.write(c); // Посимвольная распечатка всего заголовка Распечатка всего заголовка

if (c == '\n' && currentLineIsBlank) {

while(client.available()) { //Обработка запроса POST

post = client.read();

if(buffer.length() <= bufferMax) buffer +=post;

// Serial.print(post); // Посимвольная распечатка всего POST запроса

}

if (readString.indexOf("GET /index")>=0 ) {

if (readString.lastIndexOf("GET /favicon.ico")>-1) {

client.println("HTTP/1.0 404 Not Found");

}

else html_doc_index(client);

}

// 1-й пароль

else if (readString.lastIndexOf("YWxleDoxMzY=")>-1 && passwd==1) {

passwd=2;

if (readString.lastIndexOf("GET /favicon.ico")>-1) {

client.println("HTTP/1.0 404 Not Found");

}

else { onoff(buffer); html_doc(client);}

}

// 2-й пароль

else if (readString.lastIndexOf("YWxleDoxMzg=")>-1 && passwd==2) {

passwd=3;

if (readString.lastIndexOf("GET /favicon.ico")>-1) {

client.println("HTTP/1.0 404 Not Found");

}

else {onoff(buffer); html_doc(client);}

}

// 3-й пароль

else if (readString.lastIndexOf("YWxleDoxNDA=")>-1 && passwd==3) {

passwd=1;

if (readString.lastIndexOf("GET /favicon.ico")>-1) {

client.println("HTTP/1.0 404 Not Found");

}

else { onoff(buffer); html_doc(client); }

}

/*

else if (buffer.lastIndexOf("2018year")>-1 ) {

if (readString.lastIndexOf("GET /favicon.ico")>-1) {

client.println("HTTP/1.0 404 Not Found");

}

else { onoff(buffer); html_doc(client); }

}

*/

else { //Запрос браузеру на авторизацию

client.println("HTTP/1.0 401 Unauthorized");

client.println("WWW-Authenticate: Basic realm=\"Arduino-manager\"");

}

Serial.println(readString); // Распечатка части заголовка

Serial.println(buffer); //Распечатка POST запрсоса

Serial.println("");

break;

}

if (c == '\n') {

currentLineIsBlank = true;

}

else if (c != '\r') {

currentLineIsBlank = false;

}

}

}

delay(1);

client.stop();

}

}

void html_doc(EthernetClient client){

char buf[30];

// send a standard http response header

client.println("HTTP/1.1 200 OK");

client.println("Content-Type: text/html; charset=UTF8");

client.print("Connection: close\r\n\r\n"); // the connection will be closed after completion of the response

client.println("<!DOCTYPE HTML>");

client.println("<html lang=\"ru\">");

client.println("<head>");

client.println("<title>Arduino mega</title>");

client.println("</head>");

client.println("<body>");

client.println("<font size=5 color=blue> Web-server на Arduino MEGA 1280 <br>и контроллере w5500 <br>с авторизацией доступа</font>");

client.println("<br>");

client.println("<hr>");

client.println("<FORM action=\"\" method=\"POST\">");

client.println("<FONT size=4 color=red>Красный светодиод:</FONT><BR>");

client.println("<INPUT type=\"radio\" name=\"r\" value=\"1\">ON<br>");

client.println("<INPUT type=\"radio\" name=\"r\" value=\"0\"CHECKED>OFF<br><br>");

client.println("<FONT size=4 color=green>Зеленый светодиод:</FONT><BR>");

client.println("<INPUT type=\"radio\" name=\"g\" value=\"1\">ON<br>");

client.println("<INPUT type=\"radio\" name=\"g\" value=\"0\"CHECKED>OFF<br><br>");

client.println("<FONT size=4 color=blue>Синий светодиод:</FONT><BR>");

client.println("<INPUT type=\"radio\" name=\"b\" value=\"1\">ON<br>");

client.println("<INPUT type=\"radio\" name=\"b\" value=\"0\"CHECKED>OFF<br>");

client.println("<input type='hidden' name='av' value='2018year'>");

client.println("<INPUT type=\"submit\" value=\"Ввести\">");

client.println("</FORM>");

client.println("<br>");

sensors.requestTemperatures();

dtostrf(sensors.getTempCByIndex(0),7,1,buf);

client.print("<font size=4 color=broun>Температура вне помещения ");

client.print(buf);

client.println(" градусов C</font><br>");

float tin = dht.readTemperature();

dtostrf(tin,7,0,buf);

client.print("<font size=4 color=blue>Температура в помещении ");

client.print(buf);

client.println(" градусов C</font><br>");

float hu = dht.readHumidity();

dtostrf(hu,7,0,buf);

client.print("<font size=4 color=broun>Влажность в помещении ");

client.print(buf);

client.println(" %</font><br><br>");

if (digitalRead(3)){ client.println("<font size=4 color=red>Красный светодиод ВКЛЮЧЕН</font><br>"); }

else{ client.println("<font size=4 color=red>Красный светодиод ВЫКЛЮЧЕН</font><br>"); }

if (digitalRead(5)){ client.println("<font size=4 color=green>Зеленый светодиод ВКЛЮЧЕН</font><br>");}

else{ client.println("<font size=4 color=green>Зеленый светодиод ВЫКЛЮЧЕН</font><br>"); }

if (digitalRead(7)){client.println("<font size=4 color=blue>Синий светодиод ВКЛЮЧЕН</font><br>"); }

else{ client.println("<font size=4 color=blue>Синий светодиод ВЫКЛЮЧЕН</font><br>"); }

client.println("<hr>");

client.print("Свободно памяти: ");

client.println(freeRam());

client.print("<br>Index: ");

client.println(passwd);

client.println("</body>");

client.println("</html>");

}

void html_doc_index(EthernetClient client) {

client.println("HTTP/1.1 200 OK");

client.println("Content-Type: text/html; charset=UTF8");

client.print("Connection: close\r\n\r\n");

client.println("<!DOCTYPE HTML>");

client.println("<html lang=\"ru\">");

client.println("<head>");

client.println("<title>Arduino mega</title>");

client.println("</head>");

client.println("<body>");

client.print("Ваш index: ");

client.println(passwd);

client.println("</body>");

client.println("</html>");

}

void onoff(String buffer) {

if(buffer.indexOf("r=1") >= 0) {digitalWrite(3, HIGH);}

if(buffer.indexOf("r=0") >= 0) {digitalWrite(3, LOW);}

if(buffer.indexOf("g=1") >= 0) {digitalWrite(5, HIGH);}

if(buffer.indexOf("g=0") >= 0) {digitalWrite(5, LOW);}

if(buffer.indexOf("b=1") >= 0) {digitalWrite(7, HIGH);}

if(buffer.indexOf("b=0") >= 0) {digitalWrite(7, LOW);}

}

int freeRam () {

extern int __heap_start, *__brkval; int v;

return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); }

Та же программа, только вместо датчика влажности DHT-11 установлен датчик давления и температуры bmp280, работающий по шине I2C (Arduino IDE ver. 1.8.6). Метео данные выводятся и на индикатор LCD

Макет сервера с LCD

В программе текстовые данные размещены в памяти EEPROM (например client.println(F("HTTP/1.1 200 OK"));)

//#include <SPI.h> // Used for Ethernet w5100,w5500

//#include <Ethernet.h> // Used for Ethernet w5100

//#include <Ethernet2.h> // Used for Ethernet w5500

#include <UIPEthernet.h> // Used for Ethernet enc28j60. Вывод CS (enc28j60) подключить к аппаратному 53 выводу arduino mega

#include <Adafruit_Sensor.h>

#include <Adafruit_BMP280.h>

#include <LiquidCrystal.h>

#include <Wire.h>

#include <OneWire.h>

#include <DallasTemperature.h>

#define ONE_WIRE_BUS 2

#define bufferMax 64

#define readMax 512 // Для Microsoft Edge необходимо установить 512, так как код авторизации он устанавливает в конце заголовка

const int rs = 13, en = 12, d4 = 11, d5 = 9, d6 = 8, d7 = 6;

LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

Adafruit_BMP280 bmp;

OneWire oneWire(ONE_WIRE_BUS);

DallasTemperature sensors(&oneWire);

byte mac[] = { 0x54, 0x34, 0x41, 0x30, 0x30, 0x32 };

IPAddress ip(192, 168, 1, 18);

EthernetServer server(81);

int passwd=1;

char post;

int sec=0, ends=1;

void setup() {

pinMode(3, OUTPUT); // 3-й вывод определен как выход для светодиода

pinMode(5, OUTPUT); // 5-й вывод определен как выход

pinMode(7, OUTPUT); // 7-й вывод определен как выход

lcd.begin(16, 2);

Serial.begin(9600);

Ethernet.begin(mac, ip);

server.begin();

sensors.begin();

bmp.begin();

Serial.println(Ethernet.localIP());

meter();

CLKPR=0x80;CLKPR=0x00;

TCCR5A=0x00 ;TCCR5B=0x0C;//Делитель тактовой частоты счетчика (256)

TCNT5L=0x00; TCNT5H=0x00; ICR5L=0x00; ICR5H=0x00;

OCR5AH=0xF1; OCR5AL=0xE5; // Число тактов для достижения 1 секунды

OCR5BH=0x00; OCR5BL=0x00; OCR5CH=0x00; OCR5CL=0x00;

TIMSK5=0x02; // Прерывание при совпадении с A

}

ISR (TIMER5_COMPA_vect)

{

sec++;

if(sec==14) ends=0;

if(sec==15) sec=0;

}

void loop() {

if(sec==14 && ends==0) { meter(); ends=1; } //Чтобы была только 1 запись в LCD при sec=14

EthernetClient client = server.available();

if (client) {

String readString = "";

String buffer = "";

boolean currentLineIsBlank = true;

while (client.connected()) {

if (client.available()) {

char c = client.read();

// readString += c; // Запись всего заголовка в память. Много мусора, SRAM память не экономиться

if(readString.length() <= readMax) readString +=c; // Для экономии памяти записывает не весь заголовок, а то что нужно

// Serial.write(c); // Посимвольная распечатка всего заголовка Распечатка всего заголовка

if (c == '\n' && currentLineIsBlank) {

while(client.available()) { //Обработка запроса POST

post = client.read();

if(buffer.length() <= bufferMax) buffer +=post;

// Serial.print(post); // Посимвольная распечатка всего POST запроса

}

if (readString.indexOf(F("GET /index"))>=0 ) {

if (readString.lastIndexOf(F("GET /favicon.ico"))>-1) {

client.println(F("HTTP/1.0 404 Not Found"));

}

else html_doc_index(client);

}

// 1-й пароль

else if (readString.lastIndexOf(F("YWxleDoxMzY="))>-1 && passwd==1) {

passwd=2;

if (readString.lastIndexOf(F("GET /favicon.ico"))>-1) {

client.println(F("HTTP/1.0 404 Not Found"));

}

else { onoff(buffer); html_doc(client);}

}

// 2-й пароль

else if (readString.lastIndexOf(F("YWxleDoxMzg="))>-1 && passwd==2) {

passwd=3;

if (readString.lastIndexOf(F("GET /favicon.ico"))>-1) {

client.println(F("HTTP/1.0 404 Not Found"));

}

else {onoff(buffer); html_doc(client);}

}

// 3-й пароль

else if (readString.lastIndexOf(F("YWxleDoxNDA="))>-1 && passwd==3) {

passwd=1;

if (readString.lastIndexOf(F("GET /favicon.ico"))>-1) {

client.println(F("HTTP/1.0 404 Not Found"));

}

else { onoff(buffer); html_doc(client); }

}

/*

else if (buffer.lastIndexOf("2018year")>-1 ) {

if (readString.lastIndexOf("GET /favicon.ico")>-1) {

client.println("HTTP/1.0 404 Not Found");

}

else { onoff(buffer); html_doc(client); }

}

*/

else { //Запрос браузеру на авторизацию

client.println(F("HTTP/1.0 401 Unauthorized"));

client.println(F("WWW-Authenticate: Basic realm=\"Arduino-manager\""));

}

Serial.println(readString); // Распечатка части заголовка

Serial.println(buffer); //Распечатка POST запрсоса

Serial.println("");

break;

}

if (c == '\n') {

currentLineIsBlank = true;

}

else if (c != '\r') {

currentLineIsBlank = false;

}

}

}

delay(1);

client.stop();

}

}

void html_doc(EthernetClient client){

char buf[30];

// send a standard http response header

client.println(F("HTTP/1.1 200 OK"));

client.println(F("Content-Type: text/html; charset=windows-1251"));

client.print(F("Connection: close\r\n\r\n")); // the connection will be closed after completion of the response

client.println(F("<!DOCTYPE HTML>"));

client.println(F("<html lang=\"ru\">"));

client.println(F("<head>"));

client.println(F("<title>Arduino mega</title>"));

client.println(F("</head>"));

client.println(F("<body>"));

client.println(F("<font size=5 color=blue> Web-server на Arduino MEGA 1280 <br>и контроллере w5500(enc28j60) <br>с авторизацией доступа</font>"));

client.println(F("<br>"));

client.println(F("<hr>"));

client.println(F("<FORM action=\"\" method=\"POST\">"));

client.println(F("<FONT size=4 color=red>Красный светодиод:</FONT><BR>"));

client.println(F("<INPUT type=\"radio\" name=\"r\" value=\"1\">ON<br>"));

client.println(F("<INPUT type=\"radio\" name=\"r\" value=\"0\"CHECKED>OFF<br><br>"));

client.println(F("<FONT size=4 color=green>Зеленый светодиод:</FONT><BR>"));

client.println(F("<INPUT type=\"radio\" name=\"g\" value=\"1\">ON<br>"));

client.println(F("<INPUT type=\"radio\" name=\"g\" value=\"0\"CHECKED>OFF<br><br>"));

client.println(F("<FONT size=4 color=blue>Синий светодиод:</FONT><BR>"));

client.println(F("<INPUT type=\"radio\" name=\"b\" value=\"1\">ON<br>"));

client.println(F("<INPUT type=\"radio\" name=\"b\" value=\"0\"CHECKED>OFF<br>"));

client.println(F("<input type='hidden' name='av' value='2018year'>"));

client.println(F("<INPUT type=\"submit\" value=\"Ввести\">"));

client.println(F("</FORM>"));

client.println(F("<br>"));

sensors.requestTemperatures();

dtostrf(sensors.getTempCByIndex(0),7,1,buf);

client.print(F("<font size=4 color=broun>Температура вне помещения <b>"));

client.print(buf);

client.println(F(" </b>градусов C</font><br>"));

float tin = bmp.readTemperature()-1.0; // Датчик bmp280 дает превышение

// температуры примерно на 1 град. С

dtostrf( tin,7,1,buf);

client.print(F("<font size=4 color=blue>Температура в помещении <b>"));

client.print(buf);

client.println(F(" </b>градусов C</font><br>"));

float pr = 0.00750062*bmp.readPressure();

dtostrf(pr,7,1,buf);

client.print(F("<font size=4 color=broun>Атмосферное давление <b>"));

client.print(buf);

client.println(F(" </b>мм.рт.ст</font><br>"));

float alt = bmp.readAltitude(1013.25);

dtostrf(alt,7,1,buf);

client.print(F("<font size=4 color=green>Приблизительная высота<br> над уровнем моря <b>"));

client.print(buf);

client.println(F(" </b>м</font><br><br>"));

if (digitalRead(3)){ client.println(F("<font size=4 color=red>Красный светодиод ВКЛЮЧЕН</font><br>")); }

else{ client.println(F("<font size=4 color=red>Красный светодиод ВЫКЛЮЧЕН</font><br>")); }

if (digitalRead(5)){ client.println(F("<font size=4 color=green>Зеленый светодиод ВКЛЮЧЕН</font><br>"));}

else{ client.println(F("<font size=4 color=green>Зеленый светодиод ВЫКЛЮЧЕН</font><br>")); }

if (digitalRead(7)){client.println(F("<font size=4 color=blue>Синий светодиод ВКЛЮЧЕН</font><br>")); }

else{ client.println(F("<font size=4 color=blue>Синий светодиод ВЫКЛЮЧЕН</font><br>")); }

client.println("<hr>");

client.print(F("Свободно памяти: "));

client.println(freeRam());

client.print(F("<br>Index: "));

client.println(passwd);

client.println(F("</body>"));

client.println(F("</html>"));

}

void html_doc_index(EthernetClient client) {

client.println(F("HTTP/1.1 200 OK"));

client.println(F("Content-Type: text/html; charset=windows-1251"));

client.print(F("Connection: close\r\n\r\n"));

client.println(F("<!DOCTYPE HTML>"));

client.println(F("<html lang=\"ru\">"));

client.println(F("<head>"));

client.println(F("<title>Arduino mega</title>"));

client.println(F("</head>"));

client.println(F("<body>"));

client.print(F("Ваш index: "));

client.println(passwd);

client.println(F("</body>"));

client.println(F("</html>"));

}

void onoff(String buffer) {

if(buffer.indexOf("r=1") >= 0) {digitalWrite(3, HIGH);}

if(buffer.indexOf("r=0") >= 0) {digitalWrite(3, LOW);}

if(buffer.indexOf("g=1") >= 0) {digitalWrite(5, HIGH);}

if(buffer.indexOf("g=0") >= 0) {digitalWrite(5, LOW);}

if(buffer.indexOf("b=1") >= 0) {digitalWrite(7, HIGH);}

if(buffer.indexOf("b=0") >= 0) {digitalWrite(7, LOW);}

}

int freeRam () {

extern int __heap_start, *__brkval; int v;

return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); }

void meter()

{

sensors.requestTemperatures();

float cel=sensors.getTempCByIndex(0);

float cel1 = bmp.readTemperature()-1.0;

float pr = 0.00750062*bmp.readPressure();

lcd.setCursor(0, 0);

lcd.print("To=");

lcd.print(cel,1);

lcd.print(" Ti=");

lcd.print(cel1,1);

lcd.print("C ");

lcd.setCursor(0, 1);

lcd.print(" P=");

lcd.print(pr,0);

lcd.print("mm Hg ");

}

Интерфейс управления

Источники

1. Kitsum. Авторизация на Web сервере микроконтроллера. [Electronic resource]. - Mode of access: https://it4it.club/topic/13-авторизация-на-web-сервере-микроконтроллера/, 2015

2. Гранкин С.С. Подключение Arduino к Интернету: настройка режима клиент-сервер, обработка GET и POST запросов. [Electronic resource]. - Mode of access: http://cxem.net/arduino/arduino176.php , 2016

15.01.2018г.