Stránka 1 z 1
web server s Basic Authentication
Napsal: 07 zář 2023, 16:34
od BigSandy
Zdravím a prosím o pomoc.
Před par lety jsem skladal arduino uno a Ethernet Shield W5100.
Našel jsem ještě nějake poznamky a přiklady a u tohoto jsem měl napsane odzkoušene a funkční.
Kód: Vybrat vše
#include <SPI.h>
#include <Ethernet.h>
boolean zacatekCteni = false;
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 1, 15);
EthernetServer mujSvr = EthernetServer(80);
String header;
void setup() {
Serial.begin(9600);
Ethernet.begin(mac, ip);
mujSvr.begin();
Serial.println(Ethernet.localIP());
}
void loop() {
String poslane = "";
EthernetClient client = mujSvr.available();
if (client) {
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
header += c;
if(zacatekCteni && c == ' '){zacatekCteni = false;} //ukončí čtení
if(c == '?'){zacatekCteni = true;} //začatek čtení
if(zacatekCteni){poslane = poslane + char(c);}
if (c == '\n' && currentLineIsBlank) {
if(header.indexOf("YWRtaW46YWRtaW4=") >= 0) {
// při úspěšném přihlášení
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println();
client.println("hello world!");
Serial.print(poslane);
}
else {
// špatně zadane user/pass
client.println("HTTP/1.0 401 Authorization Required");
client.println("HTTP/1.1 401 Unauthorized");
client.println("WWW-Authenticate: Basic realm=\"Secure\"");
client.println("Content-Type: text/html");
client.println();
client.println("<html>Text to send if user hits Cancel button</html>"); // really need this for the popup!
}
header = "";
break;
}
if (c == '\n') {currentLineIsBlank = true;}
else
if (c != '\r') {currentLineIsBlank = false;}
}
}
// give the web browser time to receive the data
delay(1);
client.stop();
}
}
Zkouším totež s arduinem nano a Ethernet Shield ENC28J60.
Uplně to same, jenom misto knihovny Ethernet.h jsem použil UIPEthernet.h
Kód: Vybrat vše
#include <UIPEthernet.h>
#include <SPI.h>
boolean zacatekCteni = false;
String header;
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0x78, 0xEE };
IPAddress ip(192, 168, 1, 115);
EthernetServer server(80);
void setup() {
Serial.begin(9600);
Ethernet.begin(mac, ip);
server.begin();
Serial.print("IP Address: ");
Serial.println(Ethernet.localIP());
}
void loop() {
String poslane = "";
EthernetClient client = server.available();
if (client) {
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
header += c;
if(zacatekCteni && c == ' '){zacatekCteni = false;} //ukončí čtení
if(c == '?'){zacatekCteni = true;} //začatek čtení
if(zacatekCteni){poslane = poslane + char(c);}
if (c == '\n' && currentLineIsBlank) {
if(header.indexOf("YWRtaW46YWRtaW4=") >= 0) {
// při úspěšném přihlášení
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println();
client.println("hello world!");
Serial.print(poslane);
}
else {
// špatně zadane user/pass
Serial.print("nespravne heslo");
client.println("HTTP/1.0 401 Authorization Required");
client.println("HTTP/1.1 401 Unauthorized");
client.println("WWW-Authenticate: Basic realm=\"Secure\"");
client.println("Content-Type: text/html");
client.println();
client.println("<html>Text to send if user hits Cancel button</html>"); // really need this for the popup!
}
header = "";
break;
}
if (c == '\n') {currentLineIsBlank = true;}
else
if (c != '\r') {currentLineIsBlank = false;}
}
}
delay(1);
client.stop();
}
}
Heslo to nesežere.
Proč? Mam tam někde kopnec?
Jmeno a heslo by se mělo zašifrovat do base64 ve tvaru admin:admin
https://www.base64encode.org/
YWRtaW46YWRtaW4=
Děkují.
Napsal: 07 zář 2023, 18:15
od BigSandy
Tak jsem se na netu dočet, že to musí podporovat knihovna.
Přes knihovnu Ethernet.h ten Ethernet Shield ENC28J60 nejede a UIPEthernet.h to prý nepodporuje

Napsal: 07 zář 2023, 19:01
od Valdano
Zde je odkaz na knihovnu
EtherCard, která umí pracovat s čipem
ENC28J60 a poskytuje rutiny, které umožňují různé přenosy dat včetně zpracování HTTP.
Zde je ukázka použití knihovny
EtherCard pro jednoduchý webserver. S tím by se tedy něco dělat dalo.
Zde je pro změnu ukázka webserveru s použitím knihovny
NanodeUIP, která umí také pracovat s čipem
ENC28J60.
Je však třeba mít na paměti to, že práce s ENC28J60 je náročnější na paměť než s W5100 a navíc webserver to je obecně celkem žrout paměti a Arduino NANO má jen 2KB RAMky. Tak, aby vám při tvorbě webserveru paměť brzo nedošla. Šetřete proto pamětí
viz popis k tomu. Zejména různé textové literály tj. staticky definované textové řetězce umísťujte pomocí makra
F() do FLASH paměti namísto do RAM.
Takže například namísto tohoto plýtvání RAM pamětí.
Kód: Vybrat vše
client.println("HTTP/1.0 401 Authorization Required");
client.println("HTTP/1.1 401 Unauthorized");
client.println("WWW-Authenticate: Basic realm=\"Secure\"");
client.println("Content-Type: text/html");
client.println("<html>Text to send if user hits Cancel button</html>");
Používejte toto z hlediska RAM paměti úspornější řešení.
Kód: Vybrat vše
client.println(F("HTTP/1.0 401 Authorization Required"));
client.println(F("HTTP/1.1 401 Unauthorized"));
client.println(F("WWW-Authenticate: Basic realm=\"Secure\""));
client.println(F("Content-Type: text/html"));
client.println(F("<html>Text to send if user hits Cancel button</html>"));
Ke zvážení je zda nepoužít trochu vyšší level a mít do budoucna nadlouho vystaráno viz třeba vývojovou desku
ESP32-WROOM-32, která má 520KB SRAM a 32-bitový dvoujádrový procesor
s nastavitelnou frekvencí od 80MHz po 240MHz a na desce má i integrovanou podporu Bluetooth a Wifi, kterou nemusíte využít a cena je při tom menší než u Arduina NANO. Nebo při požadavku na programování přes vestavěný USB port třeba desku
ESP32-DevKitC (
podpora pro Arduino IDE). Stačilo by akorát desku vhodně propojit s tím ethernetovým modulem s ENC28J60 a měl byste webserver jak pro ethernet tak případně i pro Wifi, které je integrováno na zmíněné desce. Desky jsou kompatibilní s Arduino IDE, takže je můžete programovat podobně jako byste programoval Arduino NANO akorát si do Arduino IDE doplníte podporu pro ESP32 viz už uvedený odkaz a pak už jen zvolíte příslušnou desku.
Napsal: 08 zář 2023, 08:05
od BigSandy
Asi se na to vysmolim a koupim na aliku W5500 Ethernet Shield.
https://aliexpress.com/item/1005003946385295.html
Jsem kdysi tu ENC28J60 od někoho dostal a valela se v šupliku, tak jsem myslel, že se jí zbavim.
Libilo se mi, že do ní jen zasunu nano a hotovo.
To co tu navruješ, použit ESP32-WROOM-32 je jak dělo na vrabce a bez rj45.
Mame na firmě par kamer, a občas se nějaka sekne a musím tam jezdit. Vždy stači jen vypnout a zapnout zdroj.
Takže chci něco, co bude dělat ping na kameru a pokud se kamera neozve, tak ji restartovat.
Určitě by stačilo toto.
https://aliexpress.com/item/1005005683843344.html
Ale neni tam wifi a aní wifi nechci. Radějí něco s RJ45
Napsal: 08 zář 2023, 13:44
od Valdano
Ten ethernetový modul co je určen přímo pro NANO s ním musí fungovat tj. je to jen otázka najít v čem máte chybu.
Teď bohužel nemám dost času, abych se tomu věnoval blíže. Až budu mít víc času tj. pravděpodobně o víkendu tak se na to zkusím mrknout. Mám doma Arduino NANO, ale ten ethernetový modul mám trochu jiný
viz tento odkaz, ale také je s čipem
ENC28J60 takže to s ním pak vyzkouším.
Zkuste zatím použít příklad, který je k tomu ethernetovému modulu pro NANO uveden na webu u Dratka
viz tento odkaz. V tom příkladu se namísto
Ethernet.h používá
EthernetENC.h tj.
tato knihovna EthernetENC což je modernizovaná verze staré knihovny
UIPEthernet.
S knihovnou
EthernetENC by to mělo fungovat. Tak to s ní zkuste a nezapomeňte na to dříve popsané používání makra
F() v textových literálech ať zbytečně neplýtváte pamětí.
Napsal: 08 zář 2023, 20:34
od BigSandy
Ta knihovna EthernetENC.h je ok a funguje i ten zdrojak co jsem dal v prvním postu. I to přihlašovaní je ok.
Ale ta knihovna ICMPPing.h neprojde.
Jsem jen lama, ale podle mně je psana pro w5100.
d:\ARDUINO\+Arduino projekty\libraries\Arduino-Ping-master/ICMPPing.h:12:10: fatal error: utility/w5100.h: No such file or directory
#include <utility/w5100.h>
Napsal: 08 zář 2023, 23:16
od Valdano
Ano ICMPPing.h je pro w5100. Takže nepoužívejte ping, ale zkuste klientské připojení k té webové kameře na její webové rozhraní tj. předpokládám na TCP portu 80. Žádná data z kamery nemusíte číst. Stačí jen navázat to spojení a otestovat zda se to povedlo. Pokud bude kamera v pořádku tak by se spojení mělo navázat a pokud bude tzv. "zamrzlá" tak se spojení na ni nepodaří. Pokud se spojení opakovaně nepodaří tak se provede vypnutí a zapnutí napájení kamery. Příklad viz níže.
Kód: Vybrat vše
#include <SPI.h>
#include <EthernetENC.h>
// digitální pin číslo 3 tj. D3 na Arduinu
#define PIN_PRO_RELE 3
byte citac = 0;
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; // MAC adresa ethernet shieldu
// IP adresa ethernet shieldu
byte ip[] = {192,168,1,99};
// IP adresa webové kamery
IPAddress webCamAddr(192,168,1,98);
EthernetClient client;
void setup()
{
pinMode(PIN_PRO_RELE, OUTPUT);
digitalWrite(PIN_PRO_RELE, LOW);
Ethernet.begin(mac, ip);
}
void loop()
{
// pokus o spojení na web kameru na TCP portu 80
client.connect(webCamAddr, 80);
delay(1000);
if (client.connected()) {
// spojeno, vynulovat čítač
// je-li odpoveď OK, vynulovat čítač
citac = 0;
} else {
// nespojeno
if (citac < 5) {
// zvyšovat čítač
citac++;
} else {
// šestý po sobě neúspěšný pokus
// vynulovat čítač
citac = 0;
// sepnout relé
// přes rozpínací kontakt se rozpojí napájení webové kamery
digitalWrite(PIN_PRO_RELE, HIGH);
// počkat třeba vteřinu
delay(1000);
// relé zase vypnout
// čímž se spojí rozpínací kontakt a napájení kamery se obnoví
digitalWrite(PIN_PRO_RELE, LOW);
};
};
// ukončit klienta bez ohledu na to zda bylo či nebylo spojeno
// pokud bylo spojeno tak se při provádění client.stop()
// spojení automaticky uzavře
client.stop();
// počkat 10 vteřin
delay(10000);
}
Napsal: 09 zář 2023, 09:26
od BigSandy
Děkují moooooc, zkusim.
Jsem se v praci nudil a tak jsem trochu googlil.
Pokud jsem to pochopil spravně, tak ping by měla zvladnou knihovna EtherCard.
https://www.aelius.com/njh/ethercard/pi ... ample.html
Jsem i zkoušel nahrat do nana toto.
https://codebender.cc/sketch:108337#ENC ... server.ino
Sketch uses 8166 bytes (26%) of program storage space. Maximum is 30720 bytes.
Ostatní knihovny zabirali přes 60%
Napsal: 09 zář 2023, 12:01
od Valdano
To je spotřeba FLASH paměti a té má NANO celkem dost, ale kritičtější je spíš spotřeba RAMky, které má jen 2kB.
Napsal: 08 říj 2023, 08:56
od BigSandy
Zdar. Nenapada někoho, kde mám kopanec?
Přes millis volám každou minutu proceduru zkontroluj.
Pokud tu proceduru volám, nemohu se na server přihlásit přes heslo.
Furt zadávám heslo, ale stránka se jen protočí.
Pokud to volaní zakoncertují // zkontroluj();, normálně se přihlásím
Jinak ta procedura normalně funguje. 5 pokusu a restart.
https://pastebin.com/arWYN0Rj
Kód: Vybrat vše
#include <SPI.h>
#include <EthernetENC.h>
//#include <avr\wdt.h> // watchdog knihovna
boolean zacatekCteni = false;
unsigned long cas = millis();
unsigned long reset = millis();
byte citac = 0;
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 1, 11);
EthernetServer mujSvr = EthernetServer(4501);
EthernetClient clientzkontroluj;
IPAddress webCamAddr(192,168,1,34); // IP adresa webové kamery
String header;
void setup() {
Serial.begin(9600);
Ethernet.begin(mac, ip);
mujSvr.begin();
Serial.println(Ethernet.localIP());
digitalWrite(8, HIGH); // pin 8 na 1
pinMode(8,OUTPUT); // nastavení pinu 8 na výstup
}
///////////////////////////////////////////////////////////
void loop() {
String poslane = "";
EthernetClient client = mujSvr.available();
if (client) {
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
header += c;
if(zacatekCteni && c == ' '){zacatekCteni = false;} //ukončí čtení
if(c == '?'){zacatekCteni = true;} //začatek čtení
if(zacatekCteni){poslane = poslane + char(c);}
if (c == '\n' && currentLineIsBlank) {
// // heslo je admin admin
if(header.indexOf("YWRtaW46YWRtaW4=") >= 0) {
// při úspěšném přihlášení
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println();
//-------------------------------------
if (poslane == "?reboot")
{
citac = 0;
digitalWrite(8, LOW);
reset = millis();
client.println("restartuji zasuvku");
Serial.print(poslane);
}
//-------------------------------------
}
else {
// špatně zadane user/pass
client.println("HTTP/1.0 401 Authorization Required");
client.println("HTTP/1.1 401 Unauthorized");
client.println("WWW-Authenticate: Basic realm=\"Secure\"");
client.println("Content-Type: text/html");
client.println();
client.println("<html>Text to send if user hits Cancel button</html>"); // really need this for the popup!
}
header = "";
break;
}
if (c == '\n') {currentLineIsBlank = true;}
else
if (c != '\r') {currentLineIsBlank = false;}
}
}
delay(1);
client.stop();
}
// ---------------------------------------------------------------------
if (millis() - reset > 5000)
{
digitalWrite(8, HIGH);
}
// ---------------------------------------------------------------------
// Každou minutu zavola proceduru zkontroluj
if (millis() - cas > 60000)
{
Serial.print("kontrolují kameru ");
Serial.print(webCamAddr);
zkontroluj();
cas = millis();
}
// ---------------------------------------------------------------------
}
/////////////////////////////////////////////////////////////////////////////////////////////
void zkontroluj()
{
clientzkontroluj.connect(webCamAddr, 8034); // kamera na adrese 192,168,1,34 port 8034
delay(1000); // počka vteřinu
if (clientzkontroluj.connected())
{
citac = 0; // je-li odpoveď OK, vynulovat čítač
Serial.println(" - je tam");
}
else
{
// není odpověd
citac++; // zvyšovat čítač
Serial.println(" - není tam");
};
clientzkontroluj.stop(); // spojení clientzkontroluj automaticky uzavře
if (citac == 5)
{
Serial.println("restartuji zasuvku");
digitalWrite(8, LOW);
reset = millis();
citac = 0;
}
}
Napsal: 08 říj 2023, 11:36
od BigSandy
Tady je to zjednodušené.
Přes millis volám proceduru co 10 minut.
Pokud vše co je v proceduře smažu, tak se na web přes heslo dostanu a relé resetují.
Pokud to tam nechám, tak to co 10 minut kontroluje a po 5 neúspěšných pokusech se relé na 5 vteřin rozepne. Ale login na web nefunguje.
Divné je, že se ta procedura poprvé zavolá až 10 minut po spuštění arduina.
Ale ani těch 10 minut nefunguje ten login .
Kde to muže být dokokocene?
Děkují.
https://pastebin.com/8YV94JMm
Napsal: 08 říj 2023, 13:18
od Valdano
Nepoužíváte makro F() pro řetězce a plýtváte tak zbytečně pamětí (u této malé aplikace dělá úspora při použití F() cca 300 bajtů což není zrovna málo). Navíc používáte String bez definice rezervace což je u Arduina NANO, které má dost málo paměti hazard. String alokuje paměť dynamicky až za běhu programu a spotřebu paměti tak neuvidíte při překladu. Při použití objektů String může docházet k fragmentaci paměťové haldy. Zbytečně používáte dva samostatné objekty EthernetClient což je opět plýtvání pamětí. Navíc máte objekty a některé další proměnné deklarované uvnitř loop() takže neustálé vznikají a zanikají s každým voláním loop() až za běhu programu, ale při překladu se jejich spotřeba paměti neprojeví. Zkuste níže uvedenou úpravu. Mimochodem to, že se funkce zkontroluj() volala až 10 minut po zapnutí Arduina je naprosto logické, protože jste to tak měl naprogramováno. V níže upraveném zdrojáku se funkce zkontroluj() zavolá hned po startu a další volání bude až za 10 minut.
Kód: Vybrat vše
#include <SPI.h>
#include <EthernetENC.h>
boolean zacatekCteni = false;
boolean currentLineIsBlank = false;
unsigned long cas = 0;
unsigned long reset = 0;
byte citac = 0;
char c = 0;
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 1, 11);
EthernetServer mujSvr = EthernetServer(4501);
EthernetClient client;
IPAddress webCamAddr(192,168,1,34); // IP adresa webove kamery
String header;
String poslane;
void setup()
{
Serial.begin(9600);
Ethernet.begin(mac, ip);
mujSvr.begin();
pinMode(8,OUTPUT); // nastaveni pinu 8 na vystup
digitalWrite(8, HIGH); // pin 8 na 1
Serial.println(Ethernet.localIP());
header.reserve(100); // ochrana proti fragmentaci pameti, reservace 100 znaku
poslane.reserve(100); // ochrana proti fragmentaci pameti, reservace 100 znaku
header = "";
poslane = "";
Serial.print(F("kontroluji kameru "));
Serial.print(webCamAddr);
Serial.println();
zkontroluj();
cas = millis();
reset = 0;
}
///////////////////////////////////////////////////////////
void loop()
{
client = mujSvr.available();
if (client) {
currentLineIsBlank = true;
header = "";
poslane = "";
while (client.connected()) {
if (client.available()) {
c = client.read();
header += c;
if (zacatekCteni && c == ' ') {zacatekCteni = false;}; //ukonci cteni
if (c == '?') {zacatekCteni = true;}; //zacatek cteni
if (zacatekCteni) {poslane = poslane + char(c);};
if (c == '\n' && currentLineIsBlank) {
// heslo je admin admin
if (header.indexOf(F("YWRtaW46YWRtaW4=")) >= 0) {
// pri uspesnem prihlaseni
client.println(F("HTTP/1.1 200 OK"));
client.println(F("Content-Type: text/html"));
client.println(F("Connection: close"));
client.println();
//-------------------------------------
if (poslane == F("?reboot")) {
citac = 0;
digitalWrite(8, LOW);
reset = millis();
if (!reset) reset = 1;
client.println(F("restartuji zasuvku"));
Serial.print(poslane);
};
//-------------------------------------
} else {
// Spatne zadane user/pass
client.println(F("HTTP/1.0 401 Authorization Required"));
client.println(F("HTTP/1.1 401 Unauthorized"));
client.println(F("WWW-Authenticate: Basic realm=\"Secure\""));
client.println(F("Content-Type: text/html"));
client.println();
client.println(F("<html>Text to send if user hits Cancel button</html>"));
};
break;
};
if (c == '\n') {
currentLineIsBlank = true;
} else {
if (c != '\r') {
currentLineIsBlank = false;
};
};
};
};
delay(1);
header = "";
poslane = "";
client.stop();
};
// ---------------------------------------------------------------------
if (reset > 0 && (millis() - reset) > 5000) {
reset = 0;
digitalWrite(8, HIGH);
}
// ---------------------------------------------------------------------
// Kazdych 10 minut zavola proceduru zkontroluj
if (millis() - cas > 600000) {
Serial.print(F("kontroluji kameru "));
Serial.print(webCamAddr);
zkontroluj();
cas = millis();
};
// ---------------------------------------------------------------------
}
void zkontroluj()
{
client.connect(webCamAddr, 8034); // kamera na adrese 192,168,1,34 port 8034
delay(1000); // pocka vterinu
if (client.connected()) {
citac = 0; // je-li odpoved OK, vynulovat citac
Serial.println(F(" - je tam"));
} else {
// neni odpoved
citac++; // zvysovat citac
Serial.println(F(" - neni tam"));
};
client.stop(); // spojeni clientzkontroluj automaticky uzavre
if (citac == 5) {
Serial.println(F("restartuji zasuvku"));
digitalWrite(8, LOW);
reset = millis();
if (!reset) reset = 1;
citac = 0;
};
}
Napsal: 08 říj 2023, 14:47
od BigSandy
Zdravím Tě a hned děkují. Funguje.
To že se procedura volala až po těch 10 minutach bylo schvalně, jen jako test jestli ten login bude fungovat než se zavola. Normalně mám 1 mimutu a je fuk zda až po minutě.
Asi byl problem v tom, že jsem použival ty dva samostatné objekty EthernetClient, že jsem se nemoh přihlasit.
Ještě jednou
