diff options
-rw-r--r-- | data/www/0.html | 8 | ||||
-rw-r--r-- | data/www/1.html | 137 | ||||
-rw-r--r-- | data/www/2.html | 40 | ||||
-rw-r--r-- | data/www/3.html | 9 | ||||
-rw-r--r-- | data/www/4.html | 9 | ||||
-rw-r--r-- | data/www/css/main.css | 25 | ||||
-rw-r--r-- | data/www/index.html | 32 | ||||
-rw-r--r-- | data/www/kazalo.html | 15 | ||||
-rw-r--r-- | data/www/redirect.html | 10 | ||||
-rw-r--r-- | f000_sijaneciot.ino | 39 | ||||
-rw-r--r-- | f010_raznefunkcije.ino | 164 | ||||
-rw-r--r-- | f015_apihandler.ino | 234 | ||||
-rw-r--r-- | f020_setup.ino | 71 | ||||
-rw-r--r-- | f030_httpserver.ino | 1 | ||||
-rw-r--r-- | f050_loop.ino | 4 |
15 files changed, 798 insertions, 0 deletions
diff --git a/data/www/0.html b/data/www/0.html new file mode 100644 index 0000000..9fa9527 --- /dev/null +++ b/data/www/0.html @@ -0,0 +1,8 @@ +<head> +<meta charset=UTF-8> +<link rel="stylesheet" type="text/css" href="css/main.css"> +</head> +<b><text style=font-size:25px>Glavna stran</text> <!--<img align=right src=img.png alt=SLIKA width=300 height=170 />--> +<br><i>Anton Luka Šijanec, 14. november 2019</i><br></b> +<p>Tole je predloga, spisana za IoT čipe (prilagojena za ESP8266). Izdelal sem jo za potrebe projektne naloge pri fiziki v prvem letniku.</p><hr> +Preberi še: <a href=1.html>Nastavitve omrežja</a> diff --git a/data/www/1.html b/data/www/1.html new file mode 100644 index 0000000..c75f0b3 --- /dev/null +++ b/data/www/1.html @@ -0,0 +1,137 @@ +<head> +<meta charset=UTF-8> +<link rel="stylesheet" type="text/css" href="css/main.css"> +<style> +table, tr, td { border: 1px solid red; } +</style> +</head> +<b><text style=font-size:25px>Nadzorna plošča</text> <!--<img align=right src=img.png alt=SLIKA width=300 height=170 />--> +<br><i>Anton Luka Šijanec, 13. december 2019</i><br></b> +<br> +<table height=89% width=100%> +<tr> +<td width=33%> +zadnja zahteva na strežnik: +<iframe name=zadnjaiframe></iframe> +</td><td width=33%> +<form action="/api/pin" method="GET" target="zadnjaiframe"> + <select name=p> + <option value="D0">D0</option> + <option value="D1">D1</option> + <option value="D2">D2</option> + <option value="D3">D3</option> + <option value="D4">D4</option> + <option value="D5">D5</option> + <option value="D6">D6</option> + <option value="D7">D7</option> + <option value="D8">D8</option> + <option value="A0">A0</option> + </select> + <br>vrednost: <input type=number value=0 min=0 max=1023 name=v> + <br><input type="submit" value="ročna nastavitev pina" /> +</form> +</td><td width=33%> +<form action="/api/pin" method="GET" target="zadnjaiframe"> + <select name=p> + <option value="D0">D0</option> + <option value="D1">D1</option> + <option value="D2">D2</option> + <option value="D3">D3</option> + <option value="D4">D4</option> + <option value="D5">D5</option> + <option value="D6">D6</option> + <option value="D7">D7</option> + <option value="D8">D8</option> + <option value="A0">A0</option> + </select> + <br><input type="submit" value="pridobitev trenutnega stanja pina (branje pina)" /> +</form> +</td> +</tr> +<tr> +<td> +<form action="/api/res" method="GET" target="zadnjaiframe"> +<input type=hidden name=k value=availheap> +<input type="submit" value="pridobi bajte prostega rama" /> +</form> +<form action="/api/rst" method="GET" target="zadnjaiframe"> +<input type="submit" value="ponovno zaženi napravo" /> +</form> +<form action="/api/now" method="GET" target="zadnjaiframe"> +<input type="submit" value="pridobi trenutni čas (UNIX časovni žig)" /> +</form> +</td><td> +<form action="/api/sap" method="GET" target="zadnjaiframe"> +<input required type=text name=s placeholder="SSID"> +<input type=text name=p placeholder="geslo (neobvezno)"> +kanal: <input type=number value=1 min=1 max=13 name=c value=1> +skrij dostopno točko? <input type=radio name=h value=0 checked=checked>ne <input type=radio name=h value=1>da +spoofan mac naslov čipa (neobvezno): <input type=text maxlength=12 name=m placeholder="format: EEFABC286787"> +<input type="submit" value="nastavitev dostopne točke" /> +</form> +</td><td> +<form action="/api/sta" method="GET" target="zadnjaiframe"> +<input required type=text name=s placeholder="SSID"> +<input type=text name=p placeholder="geslo (neobvezno)"> +<input type=text name=h value=sijaneciot placeholder="ime gostitelja čipa (neobvezno)"> +spoofan mac naslov ESP-čipa (neobvezno): <input type=text maxlength=12 name=m placeholder="format: EEFABC286787"> +<input type="submit" value="povezava na omrežje WiFi" /> +</form> +</td> +</tr> +<tr> +<td>7<br><br> +<form action="/api/pin" method="GET" target="zadnjaiframe"> + <select name=k> + <option value="s">MAC kot klient neke druge dost.točke</option> + <option value="a">MAC kot dostopna točka</option> + <option value="i">IP naslov kot klient</option> + <option value="c">ID čipa</option> + <option value="h">ime gostitelja</option> + </select> + <br><input type="submit" value="pridobitev informacij in ID-jev" /> +</form> +</td><td> +<form action="/api/pwm" method="GET" target="zadnjaiframe"> + <input type=number min=1 name=v> Hz + <input type="submit" value="nastavitev frekvence pulzoširinske modulacije" /> +</form> +</td><td> +<form action="/api/slp" method="GET" target="zadnjaiframe"> + za <input type=number min=1 name=v> mikrosekund + <input type="submit" value="pojdi v stanje globokega spanja" /> +</form> +(potrebuje pin D0/GPIO16 priklopljen na RST pin) +</td> +</tr> +<tr> +<td> +<form action="/api/pwd" method="GET" target="zadnjaiframe"> + <input type=text disabled value=sijaneciot placeholder="uporabniško ime"> + <input type=text required placeholder="novo geslo" name=g> + <input type="submit" value="nastavi novo geslo za HTTP in FTP" /> +</form> +</td><td> +<form action="/api/tms" method="GET" target="zadnjaiframe"> + <br><input type=number min=0 max=23 name=h placeholder=ura> + <input type=number min=0 max=23 name=m placeholder=minuta> + <input type=number min=0 max=23 name=s required placeholder=sekunda> + <input type=number min=0 max=23 name=d placeholder=dan> + <input type=number min=0 max=23 name=o placeholder=mesec> + <input type=number min=0 max=23 name=y placeholder=leto> + <input type="submit" value="nastavi nov čas" /> + <br>Če izpolnite samo sekunde bodo upoštevane kot UNIX timestamp. +</form> +</td><td> +<form action="/api/mov" method="GET" target="zadnjaiframe"> + <input type=text maxlength=31 required name=i placeholder="trenutna pot datoteke"> + <input type=text maxlength=31 required name=v placeholder="nova destinacija datoteke"> + <input type="submit" value="premakni datoteko" /> + <br>SPIFFS, ki se uporablja za shranjevanje datotek ne pozna map, poševnice bodo samo del imena datoteke, torej premik cele mape ni možen. + <br>To je uporabno, ker FTP klienti ne podpirajo poševnic v imenih datotek, torej boste lahko datoteke postavljali le v korenu shrambe, s tem APIjem jih lahko premaknete v druge mape. +</form> +</td> +</tr> +</table> +<hr> +Preberi še: <a href=0.html>Glavna stran</a> diff --git a/data/www/2.html b/data/www/2.html new file mode 100644 index 0000000..04eb96a --- /dev/null +++ b/data/www/2.html @@ -0,0 +1,40 @@ +<head> +<meta charset=UTF-8> +<link rel="stylesheet" type="text/css" href="css/main.css"> +</head> +<b><text style=font-size:25px>Dokumentacija API klicev prek HTTP strežnika</text><!-- <img align=right src=img.png alt=SLIKA width=300 height=170 />--> +<br><i>Anton Luka Šijanec, 13. december 2019</i><br></b> +<p> +Klici se delajo z GET ali POST zahtevami na virtualno podmapo strežnika /api/<br> +Kot argumente uporabimo argumente z vrednostmi po RFC specifikaciji, bodi si v URI-ju ali v POST telesu.<br> +Priporočam uporabo GET zahtev, saj zafrkavanje z Content-Length headerji ni potrebno. +</p><p> +Vse zahteve so avtenticirane z uporabo WWW-Authentication standarda z geslom, ki ga nastavite po meri. Uporabniško ime je sijaneciot (oziroma program_ime, če to spremenljivko spremenite), geslo pa lahko spreminjate in je privzeto prav tako nastavljeno na program_ime.<br> +Priporočam, da geslo pred priklopom v večjo mrežo ali internet spremenite.<br> +Sprememba gesla: prek FTP strežnika, datoteka /403/webgeslo.txt ali z API ukazom /api/pwd?g=novogeslo<br> +</p><p> +Kode napak so standardne, če niste avtenticirani, dobite 401, če je dostop prepovedan je 403, napaka na strani strežnika je 5xx, uporabniška napaka/napaka klienta je 4xx, preusmeritve so 3xx, status OK pa je 2xx.<br> +</p><p> +NUJNO! pri API ukazu ne napišite zadnje poševnice, /api/pwd ni isto kot /api/pwd/, slednja bo vrnila <i>404: Napačen ukaz ali napačno ime datoteke.</i> +</p><p> +Spodaj so našteti podprti ukazi, za argumente posameznega ukaza pa zahtevajte ukaz brez argumentov. Če argumentov ne navedete in so za izvedbo ukaza potrebni, tako ali tako dobite napako <i>400: Napačna zahteva</i> in izpiše se vam seznam potrebnih in opcijskih argumentov, razen če ni drugače navedeno; na primer ukaz /api/rst ne potrebuje argumentov in takoj ponovno zažene sistem. +</p><p> +<pre> + <a href=/api/pin>/api/pin - ročna nastavitev pinov (branje in pisanje)</a> + <a href=/api/res>/api/res - prikaz resursov sistema</a> + <a href=/api/sap>/api/sap - nastavitev dostopne točke</a> + <a href=/api/sta>/api/sta - priklop na drugo dostopno točko</a> + <a href=/api/gid>/api/gid - pridobi informacije o napravi in o omrežju</a> + <a href=/api/pwm>/api/pwm - nastavi frekvenco pulzoširinske modulacije (brez argumentov pove trenutno vrednost)</a> + <a href=/api/rst>/api/rst - znova zažene sistem in programje (brez argumentov)</a> + <a href=/api/slp>/api/slp - globoko spanje za n mikrosekund</a> + <a href=/api/now>/api/now - vrne podatek o trenutnem času v obliki UNIX časovnega žiga (brez argumentov)</a> + <a href=/api/pwd>/api/pwd - sprememba gesla</a> + <a href=/api/tms>/api/tms - nastavitev časa (ob povezavi v splet se čas sicer vsakih 300 sekund posodobi iz 0.pool.ntp.org)</a> + <a href=/api/ren>/api/ren - preimenovanje datotek, pod "haubo" isto kot /api/mov</a> + <a href=/api/mov>/api/mov - premikanje datotek, pod "haubo" isto kot /api/ren</a> + + <a href=/test>/test - vedno vrne 200: OK, za namen testiranje povezave, npr. če je kontrolna plošča še vedno povezana na napravo.</a> +</pre> +</p><hr> +Preberi še: <a href=2.html>Dokumentacija API klicev prek HTTP strežnika</a> diff --git a/data/www/3.html b/data/www/3.html new file mode 100644 index 0000000..0d3d7b9 --- /dev/null +++ b/data/www/3.html @@ -0,0 +1,9 @@ +<head> +<meta charset=UTF-8> +<link rel="stylesheet" type="text/css" href="css/main.css"> +</head> +<b><text style=font-size:25px>3333333333333</text> <img align=right src=img.png alt=SLIKA width=300 height=170 /> +<br><i>Anton Šijanec, 13. februar 2018</i><br></b> +<p>Sem Anton Luka Šijanec, star sem 13 let in to, ker ravnokar gledate je moj prvi HTML/CSS template. Čisto sam sem ga ročno natipkal, brez kopiraj-prilepi. Če česa nisem vedel, sem si v LibreOffice naredil to, kar sem hotel na strani, potem pa sem shranil kot HTML, vendar sem si v LibreOffice dokumentu pogledal samo kako značko ali atribut, nisem kopiral direktno. Za tabelni stil me je navdihnila stran <a href=http://komarov.vesolje.net>ARK Komarov</a>(klik, če imaš Internet), ampak sploh nisem pogledal Izvirne kode, samo začel sem delati. Da bi naredil stran, sem se spomnil, ko je učiteljica za informatiko razlagala HTML značko table. Doma sem brez Interneta naredil stran v geditu na Ubuntuju. +</p><p>Ugotovil sem, da Chromixium boljše prikaže stran kot Firefox, ker ima več prostora in naslovna vrstica ni tako debela, vendar sem težavo odpravil tako, da za velikost kakšnih elementov v strani uporabim procente starševskega elementa, za kakšne pa velikost v pikslih, tako, da je stran primerna za velik nabor namiznih brskalnikov (ni testirano na mobilnih napravah).</p><p>UPORABA STILA: Stil lahko uporabiš kot svojo stran, le navesti me moraš kot avtorja. Prosim razmisli o donaciji (crypto/gotovina)</p><p>OPOMBA: Če želiš prikazati dodatno razpredelnico (tabelo) za reklamo (ali karkoli drugega) pod prostorom za članek, sledi navodilom v komentarju nekje med to HTML td značko za članek in med HTML tr značko za nogo. ;-)</p><hr> +Preberi še: <a href=index.html>ČLANEK</a> diff --git a/data/www/4.html b/data/www/4.html new file mode 100644 index 0000000..55285dc --- /dev/null +++ b/data/www/4.html @@ -0,0 +1,9 @@ +<head> +<meta charset=UTF-8> +<link rel="stylesheet" type="text/css" href="css/main.css"> +</head> +<b><text style=font-size:25px>4444444444444</text> <img align=right src=img.png alt=SLIKA width=300 height=170 /> +<br><i>Anton Šijanec, 13. februar 2018</i><br></b> +<p>Sem Anton Luka Šijanec, star sem 13 let in to, ker ravnokar gledate je moj prvi HTML/CSS template. Čisto sam sem ga ročno natipkal, brez kopiraj-prilepi. Če česa nisem vedel, sem si v LibreOffice naredil to, kar sem hotel na strani, potem pa sem shranil kot HTML, vendar sem si v LibreOffice dokumentu pogledal samo kako značko ali atribut, nisem kopiral direktno. Za tabelni stil me je navdihnila stran <a href=http://komarov.vesolje.net>ARK Komarov</a>(klik, če imaš Internet), ampak sploh nisem pogledal Izvirne kode, samo začel sem delati. Da bi naredil stran, sem se spomnil, ko je učiteljica za informatiko razlagala HTML značko table. Doma sem brez Interneta naredil stran v geditu na Ubuntuju. +</p><p>Ugotovil sem, da Chromixium boljše prikaže stran kot Firefox, ker ima več prostora in naslovna vrstica ni tako debela, vendar sem težavo odpravil tako, da za velikost kakšnih elementov v strani uporabim procente starševskega elementa, za kakšne pa velikost v pikslih, tako, da je stran primerna za velik nabor namiznih brskalnikov (ni testirano na mobilnih napravah).</p><p>UPORABA STILA: Stil lahko uporabiš kot svojo stran, le navesti me moraš kot avtorja. Prosim razmisli o donaciji (crypto/gotovina)</p><p>OPOMBA: Če želiš prikazati dodatno razpredelnico (tabelo) za reklamo (ali karkoli drugega) pod prostorom za članek, sledi navodilom v komentarju nekje med to HTML td značko za članek in med HTML tr značko za nogo. ;-)</p><hr> +Preberi še: <a href=index.html>ČLANEK</a> diff --git a/data/www/css/main.css b/data/www/css/main.css new file mode 100644 index 0000000..6834014 --- /dev/null +++ b/data/www/css/main.css @@ -0,0 +1,25 @@ + +table, tr, td {border: 1px solid cyan +} + +iframe { + border: 0px +} +body {background: black; + color: white; + font-family: monospace +} +a { + color: yellow +} +a:visited { + color: yellow +} +a:hover { + color: orange +} +input { + background:black; + color:white; + font-family:monospace +}
\ No newline at end of file diff --git a/data/www/index.html b/data/www/index.html new file mode 100644 index 0000000..e985b47 --- /dev/null +++ b/data/www/index.html @@ -0,0 +1,32 @@ +<html> +<head> +<meta charset=UTF-8> +<meta http-equiv="content-type" content="text/html; charset=utf-8"> +<title>Začetno ogrodje za ESP8266</title> +<link rel="stylesheet" type="text/css" href="css/main.css"> +</head> +<body> +<table width=100% height=100%> +<!--<tr height=28px> +<td colspan=2 style="background: #333"><text style=font-size:28px><b>sijanecIoT</b> - </text><text style=font-size:25px><b><i>Ogrodje za grajenje +IoT aplikacij z UI-jem.</i></b></text></td> +</tr>--> +<tr valign=top> +<td width=200px style="background: #222"><text style=font-size:30px><b>sijanecIoT:</b></text> +<iframe src=kazalo.html style="width:100%; height:95%;" name=kazaloiframe></iframe> +</td> +<td style="background: #111"> +<iframe src=0.html style="width:100%; height:100%;" name=clanekiframe></iframe> +</td> +</tr> +<!--REKLAMA. Odkomentiraj ta komentar in dodaj rowspan=2 atribut k znački td, v kateri je kazalo. +<tr height=100px> +<td><img src=img.png alt="REKLAMA. Za izbris reklamnega prostora daj v komentar celotno tr značko okoli reklame in izbriši atribut rowspan=2 pri znački td, ki vsebuje kazalo" height=100 width=1000 /></td> +</tr> +--> +<tr height=25px> +<td colspan=2 style="background: #444"><p align=center><i>Ogrodje za grajenje IoT aplikacij z uporabniškim vmesnikom -- Spisal Anton Luka Šijanec, (C) 2019-- Prilagojeno za ESP8266</i></p></td> +</tr> +</table> +</body> +</html> diff --git a/data/www/kazalo.html b/data/www/kazalo.html new file mode 100644 index 0000000..9d94830 --- /dev/null +++ b/data/www/kazalo.html @@ -0,0 +1,15 @@ +<html> +<head> +<meta charset=UTF-8> +<link rel="stylesheet" type="text/css" href="css/main.css"> +<base target="clanekiframe"> +</head> +<body> +<br><a href=0.html target=clanekiframe><font face=Monospace><b>. </b></font><text style=font-size:16px>Glavna stran</text></a> +<br><!--<a href=1.html target=clanekiframe>--><font face=Monospace><b>. </b></font><text style=font-size:16px>Navodila:</text><!--</a>--> +<br><a href=2.html target=clanekiframe><font face=Monospace><b>.. </b></font><text style=font-size:16px>API dokumentacija</text></a> +<br><a href=1.html target=clanekiframe><font face=Monospace><b>. </b></font><text style=font-size:16px>Nadzorna plošča</text></a> +<!--<br><a href=3.html target=clanekiframe><font face=Monospace><b>.</b></font><text style=font-size:20px>POVEZAVA3</text></a> +<br><a href=4.html target=clanekiframe><font face=Monospace><b>.</b></font><text style=font-size:20px>POVEZAVA4</text></a>--> +</body> +</html> diff --git a/data/www/redirect.html b/data/www/redirect.html new file mode 100644 index 0000000..ee0a2a1 --- /dev/null +++ b/data/www/redirect.html @@ -0,0 +1,10 @@ +<html> +<head> +<meta charset=UTF-8> +<meta http-equiv="refresh" content="0;url=/index.html" /> +<title>Stran je na /index.html</title> +</head> +<body> +Stran je na <a href="/index.html">/index.html</a>, preusmerjam ... +</body> +</html>
\ No newline at end of file diff --git a/f000_sijaneciot.ino b/f000_sijaneciot.ino new file mode 100644 index 0000000..0e6e5ee --- /dev/null +++ b/f000_sijaneciot.ino @@ -0,0 +1,39 @@ +#include <ESP8266WiFi.h> +#include <ESP8266mDNS.h> +#include <ESP8266WebServer.h> +#include <WiFiClient.h> +#include "FS.h" +#include <TimeLib.h> +#include <WiFiUdp.h> +#include <ESP8266FtpServer.h> +#include <ESP8266httpUpdate.h> +extern "C" { +#include <user_interface.h> +} +const int verzija[3] = {0, 0, 0}; +const char* program_ime = "sijaneciot"; +String dostopnatocka[2]; +String oddaljenadostopnatocka[2]; +bool razhroscevanje = true; +ESP8266WebServer server(80); +FtpServer ftpSrv; +File fsUploadFile; // a File object to temporarily store the received file +static const char ntpServerName[] = "0.pool.ntp.org"; +//static const char ntpServerName[] = "time.nist.gov"; +//static const char ntpServerName[] = "time-a.timefreq.bldrdoc.gov"; +//static const char ntpServerName[] = "time-b.timefreq.bldrdoc.gov"; +//static const char ntpServerName[] = "time-c.timefreq.bldrdoc.gov"; + +const int timeZone = 1; // Central European Time +//const int timeZone = -5; // Eastern Standard Time (USA) +//const int timeZone = -4; // Eastern Daylight Time (USA) +//const int timeZone = -8; // Pacific Standard Time (USA) +//const int timeZone = -7; // Pacific Daylight Time (USA) + +WiFiUDP Udp; +unsigned int localPort = 8888; // local port to listen for UDP packets + +time_t getNtpTime(); +void digitalClockDisplay(); +void printDigits(int digits); +void sendNTPpacket(IPAddress &address); diff --git a/f010_raznefunkcije.ino b/f010_raznefunkcije.ino new file mode 100644 index 0000000..9613049 --- /dev/null +++ b/f010_raznefunkcije.ino @@ -0,0 +1,164 @@ +int x2i(char *s) +{ + int x = 0; + for(;;) { + char c = *s; + if (c >= '0' && c <= '9') { + x *= 16; + x += c - '0'; + } + else if (c >= 'A' && c <= 'F') { + x *= 16; + x += (c - 'A') + 10; + } + else if (c >= 'a' && c <= 'f') { + x *= 16; + x += (c - 'a') + 10; + } + else break; + s++; + } + return x; +} + +void explode(String s, String delimiter, String arr[], int ARR_LEN) { + // by timemage on #arduino/freenode + unsigned part_begin = 0; + for (size_t i = 0; i < ARR_LEN; ++i) { + const auto delim_index = s.indexOf(delimiter, part_begin); + const auto part_end = (delim_index >= 0) ? delim_index : s.length(); + + arr[i] = s.substring(part_begin, part_end); + + if (delim_index >= 0) { + part_begin = delim_index + delimiter.length(); + } + } +} + + +int pin2gpio(String in) { + in.toUpperCase(); + if (in == "A0") return int(A0); + if (in == "D0") return int(D0); + if (in == "D1") return int(D1); + if (in == "D2") return int(D2); + if (in == "D3") return int(D3); + if (in == "D4") return int(D4); + if (in == "D5") return int(D5); + if (in == "D6") return int(D6); + if (in == "D7") return int(D7); + if (in == "D8") return int(D8); + return in.toInt();// fallback to gpio +} + +String getContentType(String filename) { // convert the file extension to the MIME type + if (filename.endsWith(".html")) return "text/html"; + else if (filename.endsWith(".css")) return "text/css"; + else if (filename.endsWith(".js")) return "application/javascript"; + else if (filename.endsWith(".ico")) return "image/x-icon"; + else if (filename.endsWith(".jpg")) return "image/jpeg"; + else if (filename.endsWith(".jpeg")) return "image/jpeg"; + else if (filename.endsWith(".txt")) return "text/plain"; + else if (filename.endsWith(".pdf")) return "application/pdf"; + else if (filename.endsWith(".png")) return "image/png"; + else if (filename.endsWith(".zip")) return "application/zip"; + else if (filename.endsWith(".ttf")) return "font/ttf"; + else if (filename.endsWith(".gif")) return "image/gif"; + else if (filename.endsWith(".mp3")) return "application/ogg"; + else if (filename.endsWith(".ogg")) return "application/ogg"; + else if (filename.endsWith(".mp4")) return "application/ogg"; + else if (filename.endsWith(".gz")) return "application/x-gzip"; + else if (filename.endsWith(".xml")) return "text/xml"; + else if (filename.endsWith(".svg")) return "text/svg+xml"; + return "application/octet-stream"; +} + +bool writefile(String filepath, String contents) { + File file = SPIFFS.open(filepath, "w"); + if (!file) { + return false; + } + int bytesWritten = file.print(String(contents)); + if (bytesWritten == 0) { + return false; + } + file.close(); + return true; +} +String readfile(String filepath) { + File file = SPIFFS.open(filepath, "r"); + if (!file) { + return ""; + } + String filecontents; + while (file.available()) { + filecontents += char(file.read()); + } + file.close(); + return filecontents; +} + +String fihr(int code, String text) { // format inline html response + return "<body style=background:#000;color:#FFF;font-family:monospace><h1>"+String(code)+": "+text+" <a href=/>na koren spletišča (/)<a/>" + +"<button onclick=window.history.back();>nazaj</button></h1><hr><h2><i>"+program_ime+"/"+String(verzija[0])+"."+String(verzija[1])+"."+String(verzija[2]) + +"</i></h2></body>"; +} + + +const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message +byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets + +time_t getNtpTime() +{ + IPAddress ntpServerIP; // NTP server's ip address + + while (Udp.parsePacket() > 0) ; // discard any previously received packets + Serial.println("Transmit NTP Request"); + // get a random server from the pool + WiFi.hostByName(ntpServerName, ntpServerIP); + Serial.print(ntpServerName); + Serial.print(": "); + Serial.println(ntpServerIP); + sendNTPpacket(ntpServerIP); + uint32_t beginWait = millis(); + while (millis() - beginWait < 1500) { + int size = Udp.parsePacket(); + if (size >= NTP_PACKET_SIZE) { + Serial.println("Receive NTP Response"); + Udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer + unsigned long secsSince1900; + // convert four bytes starting at location 40 to a long integer + secsSince1900 = (unsigned long)packetBuffer[40] << 24; + secsSince1900 |= (unsigned long)packetBuffer[41] << 16; + secsSince1900 |= (unsigned long)packetBuffer[42] << 8; + secsSince1900 |= (unsigned long)packetBuffer[43]; + return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR; + } + } + Serial.println("No NTP Response :-("); + return 0; // return 0 if unable to get the time +} + +// send an NTP request to the time server at the given address +void sendNTPpacket(IPAddress &address) +{ + // set all bytes in the buffer to 0 + memset(packetBuffer, 0, NTP_PACKET_SIZE); + // Initialize values needed to form NTP request + // (see URL above for details on the packets) + packetBuffer[0] = 0b11100011; // LI, Version, Mode + packetBuffer[1] = 0; // Stratum, or type of clock + packetBuffer[2] = 6; // Polling Interval + packetBuffer[3] = 0xEC; // Peer Clock Precision + // 8 bytes of zero for Root Delay & Root Dispersion + packetBuffer[12] = 49; + packetBuffer[13] = 0x4E; + packetBuffer[14] = 49; + packetBuffer[15] = 52; + // all NTP fields have been given values, now + // you can send a packet requesting a timestamp: + Udp.beginPacket(address, 123); //NTP requests are to port 123 + Udp.write(packetBuffer, NTP_PACKET_SIZE); + Udp.endPacket(); +} diff --git a/f015_apihandler.ino b/f015_apihandler.ino new file mode 100644 index 0000000..12c9044 --- /dev/null +++ b/f015_apihandler.ino @@ -0,0 +1,234 @@ +void handleTest() { + server.send(200, "text/plain", "200: OK"); +} + +bool preveriprijavo() { + if(!server.authenticate(program_ime, readfile("/403/webgeslo.txt").c_str())){ + server.requestAuthentication(); + return false; + } else { + return true; + } +} +void handleRoot() { + if (!preveriprijavo()) return; + server.sendHeader("Location", "/www/index.html"); + server.send(303); +} +void handleRename() { + if (!preveriprijavo()) return; + if (!server.hasArg("i") || server.arg("i") == NULL || !server.hasArg("v") || server.arg("v") == NULL) { + server.send(400, "text/html", fihr(400, "obvezni argument: i(z) in v (pot datoteke, npr. /www/index.html)")); + return; + } + if(SPIFFS.rename(server.arg("i"), server.arg("v"))) { + server.send(200, "text/html", fihr(200, "uspešno premaknjeno!")); + } else { + server.send(500, "text/html", fihr(500, "premikanje ni uspelo!")); + } +} +void handleTms() { // timeset + if (!preveriprijavo()) return; + if (!server.hasArg("s") || server.arg("s") == NULL) { + server.send(400, "text/html", fihr(400, "obvezni argument: s(ec) ter neobvezni: h(r), m(in), s(ec), d(ay), (m)o(nth), y(ear) (ce je prisoten le argument s, nastavimo kot unix timestamp, drugace kot mhsdmy)")); + return; + } + if (!server.hasArg("m") || server.arg("m") == NULL) { + setTime(String(server.arg("s")).toInt()); + server.send(200, "text/html", fihr(200, "ura nastavljena!")); + } else { + if(server.hasArg("h") && server.arg("h") != NULL && server.hasArg("m") && server.arg("m") != NULL && server.hasArg("s") && server.arg("s") != NULL && + server.hasArg("d") && server.arg("d") != NULL && server.hasArg("o") && server.arg("o") != NULL && server.hasArg("y") && server.arg("y") != NULL) { + setTime(String(server.arg("h")).toInt(), String(server.arg("m")).toInt(), String(server.arg("s")).toInt(), String(server.arg("d")).toInt(), + String(server.arg("o")).toInt(), String(server.arg("y")).toInt()); + server.send(200, "text/html", fihr(200, "ura zamenjana!")); + } else { + server.send(400, "text/html", fihr(400, "ce ze delas ura, minuta, sekunda, dan, mesec, leto; morajo biti prisotni vsi argumenti (hmsdoy)")); + } + } +} +void handlePin() { + if (!preveriprijavo()) return; + if (!server.hasArg("p") || server.arg("p") == NULL) { + server.send(400, "text/html", fihr(400, "obvezni argument: p(in) ter neobvezni: v(rednost) (0-1 za digital, 0-1023 za a) (glede na to ce je prisoten spremeni pinMode)")); + return; + } + if (!server.hasArg("v") && server.arg("v") != NULL) { + pinMode(pin2gpio(server.arg("p")), OUTPUT); + if(server.arg("p").substring(0, 1) == "a" || server.arg("p").substring(0, 1) == "A" || server.arg("v").toInt() > 1) { + analogWrite(pin2gpio(server.arg("p")), server.arg("v").toInt()); + } else { + digitalWrite(pin2gpio(server.arg("p")), server.arg("v").toInt()); + } + } else { + pinMode(pin2gpio(server.arg("p")), OUTPUT); + delay(1); // idk + if(server.arg("p").substring(0, 1) == "a") { + analogRead(pin2gpio(server.arg("p"))); + } else { + digitalRead(pin2gpio(server.arg("p"))); + } + } +} +void handleRes() { + if (!preveriprijavo()) return; + if (!server.hasArg("k") || server.arg("k") == NULL) { + server.send(400, "text/html", fihr(400, "obvezni argument: k(aj), vrednost je lahko: availheap")); + return; + } + server.send(200, "text/plain", String(ESP.getFreeHeap())); +} +void handleSetAP() { + if (!preveriprijavo()) return; + if (!server.hasArg("s") || server.arg("s") == NULL) { + server.send(400, "text/html", fihr(400, "obvezni argument: s(sid) ter neobvezni: p(ass), c(hannel), h(idden-bool) in m(AC address npr. EEFABC286787 APja)")); + return; + } + WiFi.softAPdisconnect(true); + if(server.hasArg("m") && server.arg("m") != NULL) { + long unsigned int mac; uint8_t macar[6]; + mac = strtoul(server.arg("m").c_str(), NULL, 16); + memcpy(macar, (char*)&mac, 6); + wifi_set_macaddr(STATION_IF, macar); + } + if (server.hasArg("h") && server.arg("h") != NULL) { + writefile("/403/hostname.txt", String(server.arg("h"))); + } + writefile("/403/wifi-ap.txt", String(server.arg("s"))+","+String(server.arg("p"))+","+String(server.arg("c"))+","+String(readfile("/403/hostname.txt"))); + WiFi.softAP(server.arg("s").c_str(), server.arg("p").c_str(), server.arg("c").toInt(), readfile("/403/hostname.txt").toInt()); + server.send(200, "text/html", fihr(200, "AP nastavljena")); +} +void handleSetSTA() { + if (!preveriprijavo()) return; + if (!server.hasArg("s") || server.arg("s") == NULL) { + server.send(400, "text/html", fihr(400, "obvezni argument: s(sid) ter neobvezni: p(ass), h(ostname) in m(AC address npr. EEFABC286787 STAja)")); + return; + } + WiFi.disconnect(true); + if(server.hasArg("m") && server.arg("m") != NULL) { + long unsigned int mac; uint8_t macar[6]; + mac = strtoul(server.arg("m").c_str(), NULL, 16); + memcpy(macar, (char*)&mac, 6); + wifi_set_macaddr(SOFTAP_IF, macar); + } + if (server.hasArg("h") && server.arg("h") != NULL) writefile("/403/hostname.txt", String(server.arg("h"))); + WiFi.hostname(readfile("/403/hostname.txt").c_str()); + WiFi.begin(server.arg("s").c_str(), server.arg("p").c_str()); + server.send(200, "text/html", fihr(200, "STA nastavljena")); +} +void handleGetID() { + if (!preveriprijavo()) return; + if (!server.hasArg("k") || server.arg("k") == NULL) { + server.send(400, "text/html", fihr(400, "obvezni argument: k(aj s(ta MAC)/a(p MAC)/i(p)/c(hipId)/h(ostname)). prebere ID, za pisanje MACa glejte /api/sta in /api/ap")); + return; + } + if(server.arg("k").startsWith("s")) { + server.send(200, "text/plain", String(WiFi.macAddress())); + } else if (server.arg("k").startsWith("a")) { + server.send(200, "text/plain", String(WiFi.softAPmacAddress())); + } else if (server.arg("k").startsWith("i")) { + server.send(200, "text/plain", WiFi.localIP().toString()); + } else if (server.arg("k").startsWith("c")) { + server.send(200, "text/plain", String(ESP.getChipId())); + } else { + server.send(200, "text/plain", String(readfile("/403/hostname.txt"))); + } +} +void handlePWM() { + if (!preveriprijavo()) return; + if (server.hasArg("v") && server.arg("v") != NULL) { + writefile("/403/pwmfreq.txt", String(server.arg("v"))); + analogWriteFreq(String(server.arg("v")).toInt()); + server.send(200, "text/html", fihr(200, "PWM nastavljena")); + } else { + server.send(400, "text/html", fihr(400, "obvezni argument: v(rednost v Hz)")); + } +} +void handleRestart() { + if (!preveriprijavo()) return; + ESP.restart(); +} +void handleDeepSleep() { + if (!preveriprijavo()) return; + if (!server.hasArg("m") || server.arg("m") == NULL) { + server.send(400, "text/html", fihr(400, "obvezni argument: m(ikrosekund)")); + return; + } + ESP.deepSleep(String(server.arg("m")).toInt()); +} +void handleUpdate() { + if (!preveriprijavo()) return; + int vraat; + if (!server.hasArg("g") || server.arg("g") == NULL || !server.hasArg("p") || server.arg("p") == NULL) { + server.send(400, "text/html", fihr(400, "obvezna argumenta: g(ostiteljev IP) in p(ot /do/datoteke.bin), neobvezen: v(rata HTTP (privzeta 80))")); + return; + } + if(String(server.arg("v")).toInt() > 0 && String(server.arg("v")).toInt() < 65536) { + vraat = String(server.arg("v")).toInt(); + } else { + vraat = 80; + } + t_httpUpdate_return ret = ESPhttpUpdate.update(server.arg("g"), vraat, server.arg("p"), String(verzija[0])+"."+String(verzija[1])+"."+String(verzija[2])); + switch(ret) { + case HTTP_UPDATE_FAILED: + server.send(500, "text/html", fihr(500, "Sistemska napaka: programska posodobitev: ni uspela")); + break; + case HTTP_UPDATE_NO_UPDATES: + server.send(304, "text/html", fihr(304, "Nespremenjeno: programska posodobitev: ni potrebna, verjetno ni nove verzije")); + break; + case HTTP_UPDATE_OK: + server.send(200, "text/html", fihr(200, "OK: programska posodobitev: uspela, po ponovnem zagonu se bo uporabila")); + break; + } +} +void handleUnixTimestamp() { + if (!preveriprijavo()) return; + server.send(200, "text/plain", String(now())); +} +void handleNewPassword() { + if (!preveriprijavo()) return; + if (!server.hasArg("g") || server.arg("g") == NULL) { + server.send(400, "text/html", fihr(400, "obvezen argument: g(eslo-novo)")); + return; + } + writefile("/403/webgeslo.txt", String(server.arg("g"))); +} +void handleFileUpload() { + if (!preveriprijavo()) return; + HTTPUpload& upload = server.upload(); + if(upload.status == UPLOAD_FILE_START){ + String filename = upload.filename; + if(!filename.startsWith("/")) filename = "/"+filename; + if (razhroscevanje) Serial.print("(razhroscevanje) -> handleFileUpload Name: "); Serial.println(filename); + fsUploadFile = SPIFFS.open(filename, "w"); // Open the file for writing in SPIFFS (create if it doesn't exist) + filename = String(); + } else if(upload.status == UPLOAD_FILE_WRITE){ + if(fsUploadFile) + fsUploadFile.write(upload.buf, upload.currentSize); // Write the received bytes to the file + } else if(upload.status == UPLOAD_FILE_END){ + if(fsUploadFile) { // If the file was successfully created + fsUploadFile.close(); // Close the file again + Serial.print("handleFileUpload Size: "); Serial.println(upload.totalSize); + server.send(200, "text/html", fihr(200, "prenos uspel")); + } else { + server.send(500, "text/html", fihr(500, "izdelava datoteke ni uspela")); + } + } +} +bool handleFileRead(String path) { // send the right file to the client (if it exists) + if (!preveriprijavo()) return false; + // Serial.println("handleFileRead: " + path); // 2hc + if (path.endsWith("/")) path += "index.html"; // If a folder is requested, send the index file + if(path.indexOf("/403/") >= 0) { + server.send(403, "text/html", fihr(403, "prepovedano")); + return true; + } + String contentType = getContentType(path); // Get the MIME type + if (SPIFFS.exists(path)) { // If the file exists + File file = SPIFFS.open(path, "r"); // Open it + size_t sent = server.streamFile(file, contentType); // And send it to the client + file.close(); // Then close the file again + return true; + } + return false; // If the file doesn't exist, return false +} diff --git a/f020_setup.ino b/f020_setup.ino new file mode 100644 index 0000000..28de3b5 --- /dev/null +++ b/f020_setup.ino @@ -0,0 +1,71 @@ +void setup() { + SPIFFS.begin(); + if (SPIFFS.exists("/403/pwmfreq.txt")) { + if (readfile("/403/pwmfreq.txt").toInt() > 0) { + analogWriteFreq(readfile("/403/pwmfreq.txt").toInt()); + } else { + writefile("/403/pwmfreq.txt", "20000"); + analogWriteFreq(20000); + } + } + if (!SPIFFS.exists("/403/webgeslo.txt")) { + writefile("/403/webgeslo.txt", "sijaneciot"); + } + if (!SPIFFS.exists("/403/hostname.txt")) { + writefile("/403/hostname.txt", String(program_ime) + "" + String(ESP.getChipId())); + } + if (razhroscevanje) Serial.setDebugOutput(true); + Serial.begin(9600); + Serial.println(); + String dostopnatocka[4]; + if (SPIFFS.exists("/403/wifi-ap.txt")) { + explode(readfile("/403/wifi-ap.txt"), ",", dostopnatocka, 4); + } else { + if (razhroscevanje) Serial.println("(razhroscevanje): /403/wifi-ap.txt ne obstaja, privzeta wifi konfiguracija"); + dostopnatocka[0] = String(program_ime) + "-" + String(ESP.getChipId()); + dostopnatocka[1] = ""; + dostopnatocka[2] = "1"; // kanal + dostopnatocka[3] = "0"; // skrito omrežje? + } + Serial.print("nastavljam dostopno tocko. SSID: " + String(dostopnatocka[0]) + " geslo: " + String(dostopnatocka[1]) + " ... "); + WiFi.mode(WIFI_AP); + WiFi.softAP(dostopnatocka[0].c_str(), dostopnatocka[1].c_str(), dostopnatocka[2].toInt(), dostopnatocka[3].toInt()); + if (razhroscevanje) Serial.println("(razhroscevanje): wifi.softap --> IPv4 " + String(WiFi.softAPIP().toString())); + if (MDNS.begin(readfile("/403/hostname.txt"))) { // Start the mDNS responder for esp8266.local + if (razhroscevanje) Serial.println("(razhroscevanje): mDNS dela, " + readfile("/403/hostname.txt")); + } else { + if (razhroscevanje) Serial.println("(razhroscevanje): mDNS fejl"); + } + ftpSrv.begin(program_ime, readfile("/403/webgeslo.txt")); + + setSyncProvider(getNtpTime); + setSyncInterval(300); + + + + server.on("/", handleRoot); + server.onNotFound([]() { // If the client requests any URI + if (!handleFileRead(server.uri())) // send it if it exists + server.send(404, "text/html", fihr(404, "Napačen ukaz ali napačno ime datoteke.")); // otherwise, respond with a 404 (Not Found) error + }); + server.on("/api/upload", HTTP_POST, // if the client posts to the upload page + [](){ server.send(200); }, // Send status 200 (OK) to tell the client we are ready to receive + handleFileUpload // Receive and save the file + ); + server.on("/api/pin", handlePin); + server.on("/api/res", handleRes); + server.on("/api/sap", handleSetAP); + server.on("/api/sta", handleSetSTA); + server.on("/api/gid", handleGetID); + server.on("/api/pwm", handlePWM); + server.on("/api/rst", handleRestart); + server.on("/api/slp", handleDeepSleep); + server.on("/api/now", handleUnixTimestamp); + server.on("/api/pwd", handleNewPassword); + server.on("/api/tms", handleTms); + server.on("/api/ren", handleRename); // \ prvi primer + server.on("/api/mov", handleRename); // / uporabe aliasa + server.on("/test", handleTest); + server.begin(); + if (razhroscevanje) Serial.println("(razhroscevanje): HTTP dela, vrata 80"); +} diff --git a/f030_httpserver.ino b/f030_httpserver.ino new file mode 100644 index 0000000..162eea7 --- /dev/null +++ b/f030_httpserver.ino @@ -0,0 +1 @@ +// ti samo pritisni restart, jejhe! diff --git a/f050_loop.ino b/f050_loop.ino new file mode 100644 index 0000000..8baca32 --- /dev/null +++ b/f050_loop.ino @@ -0,0 +1,4 @@ +void loop() { + server.handleClient(); + ftpSrv.handleFTP(); +} |