WeMOS Web Publicering
| WeMOS WiFi Processor | |
|---|---|
| WeMOS | Server Connection - Simpel Server - Flere SSID - ESP8266 - Watchdog - Interrupt |
| Anvendelse | LED-eksempel - AD-eksempel - Mail - POST metode - Web Publicering |
Den grundlæggende ide i denne kode er at sende en kommando fra den serielle monitor, og via WeMOS WiFi sende en henvendelse til en webserver[1] med et lille PHP-script, der kan sende en mail, med et indhold bestem af det der er indtastet i Serial Monitor
Strukturen i systemet, der beskrives på denne side
Dette beskriver kort hvilke elementer der er i spil i dette eksempel, og hvilken rolle de har
Den overordnede ide er at kunne måle noget elektrisk og præsentere disse ting på nettet, mere eller mindre offentligt, alt efter hvad det er man præsenterer.
WeMOS Enhed
Der skal være en WeMOS enhed, som programmeres op med de funktioner, så den kan måle det er ønskes publiceret. Det kan i princippet være en enkelt kontakts værdi man vil kunne se, og i mere komplicerede tilfælde kan det være logning af et system med mange variable værdier, som et alarmsystem, en vejrstation, overvågning af et drivhus, eller hvad man har fantasi til.
Ud over at mål skal WeMOS enheden forbinde til en WiFi forbindelse.
Når den har forbindelse til WiFi skal den sende sine måledata til en web-server. Dette kræver en del sikkerhedsmæssige overvejelser, så man ikke umiddelbart gør den anvendte webserver sårbar over for spam og mere alvorlig indtrængen.
Ved anvendelser på Holstebro HTX's system kan det være en fordel at kunne tilgå den del af webserveren der ligger internt, men det kan også være problematisk, da man skal ind på skolens netværk for at kunne tilgå den, og det er ikke så enkelt med en WeMOS.
WiFi Netværk
For at WeMOS kan kommunikere skal den tilsluttes et WiFi netværk, som skal kunne give adgang til den server hvor data skal uploades.
Upload side
WeMOS enheden skal henvende sig til en Web-Server ved at den sender nogle værdier til et PHP-script, som PHP-scriptet så lagrer i en MySQL-database.
Database
Databasens, som i dette tilfælde er en MySQL-database, skal indeholde nogle tabeller der kan modtage de værdier man ønsker at offentliggøre.
Site til visning af værdier
Der skal opbygges et web-site, som kan vise de ønskede værdier - det kan være en simpel index.php, som det vises her i eksemplet, eller man kan opbygge et helt site med login og alle mulige andre funktioner, hvor man laver grafisk visning og evt. en tolkning af de målte værdier.
Forbindelse til WiFi
Selve forbindelsen til WiFi er lavet som beskrevet ved WeMOS Server Connection, og skal blot etablere forbindelsen til WiFi netværket.
For at den samlede kode kan fungere, så skal det netværk der forbindes til have forbindelse til internettet, så man kan komme i kontakt med webserveren med PHP-scriptet.
Opsætning til HTTP-request
For at man kan sende en besked til webserveren, så skal man have adgange til HTTP-request biblioteket, og der skal oprettes at HTTP-objekt.
Dette sker i følgende kode:
#include <ESP8266HTTPClient.h>
HTTPClient http;
int httpCode;Webserver henvendelse
For at henvende sig til webserveren på simpel vis anvendes GET-metoden. Hvis man skulle gøre det med større sikkerhed, så skulle man anvende POST-metoden[2], og man burde også sikre webserveren med et login - det er ikke gjort i dette eksempel.
Selve webserveren har en http-adresse, der angives i en variabel som vist her:
const String serverAddress = "http://htx-elev.ucholstebro.dk/HX-class/user/"; // Webserverens URL
String stringToSend = serverAddress; // Serveradressen der skal henvendes tilPå Holstebro HTX har vi webserver på adressen htx-elev.ucholstebro.dk, hvor man kan uploade sine scipts, når holdet er oprettet med de brugere der er på holdet. Serveren har installeret en MySQL database, så man kan lagre noget med scriptet. Webserveren er nærmere beskrevet på Beskrivelse af htx-elev Webserver.
Inde på webserveren ligger PHP-filen, som skal lagre ud fra henvendelsen som vist her:
stringToSend += "setValue.php?"; // FilnavnetDer tilføjes også navnet på parameteren (send).
Endelig tages et input fra den serielle monitor, og der sikres at det kun er selve det indtastede man tager med. Dette tilføjes henvendelsen:
if (digitalRead(3)) {
stringToSend += "value1=" + analogRead(A0); // Send analog indgang til value1
while (digitalRead(3)) { // Vent på at knappen slippes
;
}
}
if (digitalRead(4)) {
stringToSend += "value2=" + analogRead(A0); // Send analog indgang til value2
while (digitalRead(4)) { // Vent på at knappen slippes
;
}
}Herefter foretages selve henvendelsen til webserveren med en HTTP-henvendelse:
http.setTimeout(2000); // Use 2 seconds timeout for HTTP connection
http.begin(stringToSend); // Start HTTP connection and send HTTP headerHTTP henvendelsen fungerer fint i ESP8266 bibliotekerne version 2.x (testet på version 2.7.4).
Fra version 3 (testet på version 3.0.2) kan det ikke længere oversættes. Det skyldes at http.begin skal have en ekstra parameter[3], så der skal laves følgende tilføjelse i koden:
WiFiClient client; // Client to send to
http.setTimeout(2000); // Use 2 seconds timeout for HTTP connection
http.begin(client, stringToSend); // Start HTTP connection and send HTTP headerAt sende IP-adressen med
Det er simpelt at printe IP-adressen, men hvis man ønsker at sende den med som en del af henvendelsen, så er det ikke helt så enkelt.
En måde at gøre det på kan være at starte med at oprette en funktion, der omformer[4][5] det til en streng.
String IpAddress2String(const IPAddress& ipAddress)
{
return String(ipAddress[0]) + String(".") +\
String(ipAddress[1]) + String(".") +\
String(ipAddress[2]) + String(".") +\
String(ipAddress[3]) ;
}Når man så vil anvende den kan det gøres på følgende måde:
stringToSend += "&IP=" + IpAddress2String(WiFi.localIP());Connection response
Henvendelsen til webserveren giver en respons, som man skal tjekke for at se om henvendelsen gik godt.
Dette returnerer en kode:
httpCode = http.GET(); // Get response from HTTP requestHenvendelsen giver også en respons, der her udskrives til seriel monitor
if(httpCode > 0) // httpCode will be negative on error
{
Serial.printf("[HTTP] GET... code: %d\n", httpCode); // Response from server is not an error
if(httpCode == HTTP_CODE_OK) { // Response from server is HTTP CODE 200
String payload = http.getString();
Serial.println(payload);
}
} else {
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
http.end();Efter endt henvendelse lukkes forbindelsen igen.
PHP-kode til indlæsning af data
Inde på webserveren placeres et lille PHP-script, laves ud fra følgende koncept. Scriptet udnytter at der ligger en MySQL database på serveren. Hjælp til kontakt til databasen og funktioner til at lægge noget ind stammer fra w3scholls[6].
For at gøre det enkelt at vedligeholde oprettes en lille simpel fil, som forbinder til databasen. Hvis man bruger HTX-serveren i Holstebro, så kan man finde disse oplysninger inde på ens private område af serveren i en readme-fil. HTX-serveren i Holstebro er nærmere beskrevet på Beskrivelse af htx-elev Webserver.
<?php
$mysqli = new mysqli("localhost","my_user","my_password","my_db");
if ($mysqli -> connect_errno) {
echo "Failed to connect to MySQL: " . $mysqli -> connect_error;
exit();
}
?>Database til værdierne
For kunne lægge værdier ind i databasen skal der oprettes tabeller til det. Disse tabeller oprettes via phpMyAdmin. Til dette eksempel skal der oprettes to tabeller, hvor der i den ene tabel opdateres ind i en post, som også skal oprettes med phpMyAdmin, og den anden tabel skal bare oprettes. Til eksemplet her vil tabellerne skulle oprettes med følgende felter:
| Navn | Type | Egenskab | Værdi |
|---|---|---|---|
| ID | INT | Auto Increment | 1 |
| value1 | INT | ingen | tal |
| tid | INT | ingen | 0 |
| Navn | Type | Egenskab |
|---|---|---|
| ID | INT | Auto Increment |
| value2 | INT | ingen |
| tid | INT | ingen |
For at oprette disse tabeller vil man på Holstebros HTX-server skulle logge ind på phpMyAdmin som beskrevet i dokumentationen for webserveren.
Ved at vælge sin database (hedder det samme som brugernavnet, man har kun adgang til den ene database), så kan man oprette en tabel som vist her:
![]()
Oprettelse af tabel til at indeholde værdier
Tabellens felter navngives, som vist her, hvor der her er brugt eksempel-navne, men hvor det klart vil være en fordel for forståelsen af programmet, hvis man anvender nogle navne som siger noget om hvad felterne indeholder, som der fx er brugt navnet tid, hvilket indikerer et det er tidspunktet for opdateringen af værdien.
![]()
Angivelse af feltnavne og egenskaber til at indeholde værdier
Læg mærke til at der er angivet at feltet ID skal være det primære felt, og at det skal Autoincremente - lige netop for denne tabel er det ikke så relevant, men normalt giver det en vigtig egenskab, nemlig at man får sat en ID på hver post i tabellen, så man senere kan henvende sig til lige netop denne post, ved at referere til ID'et.
For at koden der skal opdatere kan fungere, så er vi nødt til at have en enkelt post lagt ind i denne tabel. Det gør man ved at vælge tabellen, og bruge fanebaldet Indsæt, så man kan sætte et sæt værdier i posten, som senere kan opdateres, som vist her:
![]()
Oprettelse af post i tabellen med angivne værdier
Kode til at lægge data ind i tabellen
Når begge tabeller er oprettet, så skal man have oprettet noget server-kode, som kan modtage de værdier man ønsker at placere i databasen. I starten burde man have noget tjek for om man (i dette tilfælde WeMOS'en) var logget ind på serveren, men for ikke at komplicere dette eksempel yderligere, så er det udeladt.
Nedenstående kode, som i eksemplet er placeret i en fil der hedder setValue.php, starter med at henvende sig til filen med login-oplysninger:
<?php
/*
* Bent Arnoldsen, Holstebro HTX 2020
*
* Aktiveres med domæne/path/setValue.php?valueName=Value
*/
/*
* Her bør der tjekkes for et login-system, hvor man kunne anvende sessions, så man ved at der
* er logget ind, og at brugeren er autoriseret
*/
include ("db-info.php");
$message = "";
// Her opdateres en værdi value1 ind i en eksistrende tabel ValueTabel
if (isset($_GET['value1'])) {
$value1 = $mysqli -> real_escape_string($_GET['value1']); // Sikring mod SQL-injections
$value1 = intval($value1); // Konverter til heltal
$tid = time();
$sql = "UPDATE ValueTabel SET value1=$value1, tid=$tid WHERE ID=1";
if ($mysqli->query($sql) === TRUE) {
$message .= "Opdateret value1 til $value1<br />";
} else {
$message .= "Error updating record: " . $mysqli->error . "<br />";
}
}
// Her lægges en ny værdi value2 ind som en ny post i en eksistrende tabel OpsamlTabel
if (isset($_GET['value2'])) {
$value2 = $mysqli -> real_escape_string($_GET['value2']); // Sikring mod SQL-injections
$value2 = intval($value2); // Konverter til heltal
$tid = time();
$sql = "INSERT INTO OpsamlTabel (value2, tid) VALUES ($value2, $tid)";
if ($mysqli->query($sql) === TRUE) {
$message .= "Opdateret value2 til $value2<br />";
} else {
$message .= "Error updating record: " . $mysqli->error . "<br />";
}
}
$mysqli->close();
?>
<html>
<h2>Database-System</h2>
<p><?php echo $message; ?></p>
</html>Når der er etableret en forbindelse til databasen, så tjekkes der hvilken værdi man vil henvende sig til, og alt efter værdien og indholdet man lægger ind, så laves der en behandling af data - en vigtig ting at tage med real_escape_string, som sikrer at man ikke kan sende ondsindede kommandoer til databasen, så man kan få den til at afsløre sig, og at man kun kan modtage de ting man ønsker.
Test af PHP-scriptet
For at teste om PHP-scriptet virker, og at det faktisk får fat i databasen, så kan man henvende sig til serveren direkte via en browser med følgende URL:
htx-elev.ucholstebro.dk/klasse-mappe/user/setValue.php?value1=123
Hvor man selvfølgelig anvende sin egen placering på HTX-serven i stedet for /klasse-mappe/user/.
Dette vil give følgende resultat, hvis ellers tingene virker som de skal:
![]()
Respons fra serveren, ved opdatering af value1
Når man skal have WeMOS'en til at lægge noget op, så er det selvfølgelig denne URL man anvender, hvor man så kan henvende sig til de felter man har lavet i PHP-koden, i stedet for value1 og med de værdier der er relevante.
Det at man anvender GET-metoden i stedet for POST, gør igen at systemet ikke er så sikkert, men det er til gengæld simplere og lettere at forstå.
PHP-kode til visning af data
Når man har fået det til at fungere med at opdatere og lægge noget ind i de relevante tabeller, så skal man have implementeret den side, som brugeren skal kunne se, nemlig der endelige resultat af anstrengelserne.
Dette eksempel er blot lavet til at få vist værdierne, hvor man i et endeligt produkt vil kunne lave siden, så den giver mere værdi for brugeren.
Nedenstående kode anvender igen db-info.php til at etablere forbindelsen til databasen.
Herefter trækker koden data ud af databasen ved hjælp af MySQL statementen SELECT[7].
Koden er placeret i index.php, så det er den side man får vist ved at henvende sig til roden af mappen på serven. Man kunne også placere det i en underside, hvor man så først skulle vær logget ind, inden man kan få vist siden. Denne del er ikke vist i dette eksempel.
<?php
/*
* Bent Arnoldsen, Holstebro HTX 2020
*
* Aktiveres med domæne/path/index.php
*/
/*
* Her kunne tjekkes for et login-system, hvor man kunne anvende sessions, så man ved at der
* er logget ind, og at brugeren må se det viste
*/
include ("db-info.php");
?>
<html>
<h2>Visnings-side for WeMOS dataopsamling</h2>
<?php
$tid = time();
$sql = "SELECT * FROM ValueTabel";
$result = $mysqli->query($sql);
if ($result->num_rows > 0) {
$row = $result->fetch_assoc();
echo "Værdi: " . $row["value1"]. " - Opdateret: " . date("d-m-Y G:i:s", $row["tid"]) . " for " . ($tid - $row["tid"]) . " sekunder siden<br>";
} else {
echo "Ikke noget indhold";
}
$sql = "SELECT * FROM OpsamlTabel";
$result = $mysqli->query($sql);
if ($result->num_rows > 0) {
echo("<table border='1'><tr><th>ID</th><th>Værdi</th><th>Tid</th></tr>");
// output data of each row
while($row = $result->fetch_assoc()) {
echo "<tr><td>" . $row["ID"]. "</td><td>" . $row["value2"]. "</td><td>" . date("d-m-Y G:i:s", $row["tid"]) . "</td></tr>";
}
echo("</table>");
} else {
echo "Ingen data i OpsamlTabel";
}
$mysqli->close();
?>
</html>Visningen af siden kommer ved at henvende sig til følgende URL:
htx-elev.ucholstebro.dk/klasse-mappe/user/
![]()
Resultatet af den kode, som trækker værdierne ud af databasen
Det over tabellen er en visning af den post, som bare opdateres i databasen, mens det der er placeret i tabellen er fra de poster, hvor man tilføjer nye værdier løbende.
Koden samlet
Koderne i eksemplet her kan hentes i Denne ZIP-fil, men kræver stadig at man skal oprette databasen manuelt, og at man tilretter efter sine ønsker.
Referencer
- ↑ Get HTTP request
- ↑ Webserver POST requests
- ↑ Tutorial til ESP8266
- ↑ Konvertering af IP-adresse til en streng på arduinoes forum
- ↑ Stackoverflow.com med konvertering af IP-adresse til String
- ↑ MySQL funktioner i PHP - vist på undersiderne af denne hovedside
- ↑ PHP objektorienteret måde at trække ud fra en MySQL database