Hallo,
ich bin wie der Titel schon sagt auf der Suche nach einer einfachen möglichkeit mehrere Werte ( genauer gesagt 5-6 bytes) über eine einfache webseite auf den Arduino zu bekommen.
Hintergrund ist der , dass ich damit eine 5 Kanal LED-Lampe steuer will.
Ich habe dazu einen Arduino Uno+Ethernet shield auf dem eine Webseite gehostet wird.
Bis jetzt habe ich es so gehandhabt, dass auf dem Arduino eine einfache webseite läuft auf der ich verschieden Links auswählen kann um vorbestimmte "fabprofile" auszuwählen. (Soweit klappt das auch ganz gut)
Allerdings würde ich das ganze gerne insofern erweitern, dass ich beliebe Farben auswählen kann, also mit "RangeSlidern" o.ä.
Ich habe im Internet schon das ein oder andere Beispiel mit drei Kanälen und (wie ich finde) recht aufwendigen Java-Scripts gefunden.
Meine frage ist also: Wie baue ich mir ein einfaches Javascript o.ä ohne großen schnickschnack, das mit 5 Werte von 0-255 aus einer Webseite auf den Arduino bringt?
Erstmal danke für die Antwort!
Aber warum stößt der arduino dabei an seine Leistungsgrenze?
Ich dachte Javascript wird auf dem Zielgerät ausgeführt und nicht auf dem client?
Wäre für mich auch nicht das schlimmste wenn ich auf einen Mega ausweichen muss ;D
das bekommst Du relativ einfach mit einer Ajax-Abfrage hin.
In der json.txt (muss in json.html umbenannt werden) siehst Du ein Beispiel dazu.
Die Datei musst Du auf die SD-Karte vom Arduino schieben.
Mit der Funktion send_Ajax(data), wird eine Anfrage abgesetzt, in diesem Fall rtc.
Dein Arduino müsste dann folgendes erhalten:
GET /?rtc HTTP/1.1
....
....
....
Das müsstest Du dir dann nur noch auseinander friemeln. Kann unter Umständen umständlich werden.
Du kannst auch mehrer Sachen damit abfragen, standart wäre dafür z.B. rtc&ip.
Zum Setzen von Werten nimmt man z.B. rtc="15:23:48"
Die Antwort von Deinem Arduino muss dann ein String im JSON-Format sein.
Wie das aussieht, findest Du reichlich im Internet. Aber hier mal die Antwort aus dem Beispiel rtc:
HTTP/1.1 200 OK
Server: arduino due
Content-Type: text/xml
Cache-Control: no-cache
Connection: close
{"rtc":"06:48:39"}
Vorteil von Ajax ist, das nicht die ganze Seite neu geladen wird, sondern nur einige
Bestandteile. Genau das Richtige für einen Arduino-Webserver.
Mein Webserver habe ich auch so aufgebaut und klappt super.
Dazu genügt ein einfaches HTML-Formular, was per GET abgesendet ("submitted") wird. Bei "Get" werden die zu übertragenden Daten gut lesbar an die URL gehängt. Die musst du bei Ankunft am Arduino nur heraus-parsen und dann entsprechend darauf reagieren. Bei Web-Programming nicht mit schwachbrüstigen Mikrocontrollern verwendet man eher die POST-Methode, dabei ist es aber deutlich komplizierter, an die übermittelten Daten zu kommen ...
Richtig ist, dass es der Arduino Uno mit ca. 1kB freiem Speicher (bei Verwendung des Ethernet-Shields wird ein Teil der 2KB von diesem für VAriablen und Puffer benötigt) nicht so hat, mit der String-Verarbeitung. Aber ganz unmöglich ist es nicht, muss man halt ein wenig "zirkeln" und tricksen ...
Ein einfaches beispiel habe ich mir schon zusammengebastelt
hier ist, falls es jemanden interessiert mein Code:
//known issues: wahl der Links ist nicht sonderlich elegant
//design muss überarbeitet werden
//Bei zu vielen Links keine Steuerung möglich?
#include <SPI.h>
#include <Ethernet.h>
#include "Wire.h"
const byte MASTER_ADDRESS = 43;
const byte Moritz_Adress = 42;
const byte Kim_Adress = 44;
byte SLAVE_ADDRESS = 42;
byte color[6] = {0, 0, 0, 0, 0, 10};
float fakt = 1.0;
int val = 100;
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 192, 168, 178, 177 }; // ip in lan
byte gateway[] = { 192, 168, 1, 1 }; // internet access via router
byte subnet[] = { 255, 255, 255, 0 }; //subnet mask
EthernetServer server(80); //server port
String readString;
//////////////////////
void setup() {
pinMode(5, OUTPUT); //pin selected to control
//start Ethernet
Ethernet.begin(mac, ip, gateway, subnet);
server.begin();
Wire.begin();
//enable serial data print
#ifdef debug
Serial.begin(9600);
Serial.println("server LED test 1.0 Debug: ON"); // so I can keep track of what is loaded
#endif
}
void loop() {
// Create a client connection
EthernetClient client = server.available();
if (client) {
while (client.connected()) {
if (client.available()) {
char c = client.read();
//read char by char HTTP request
if (readString.length() < 100) {
//store characters to string
readString += c;
#ifdef debug
Serial.print(c);
#endif
}
//if HTTP request has ended
if (c == '\n') {
///////////////
Serial.println(readString); //print to serial monitor for debuging
client.println("HTTP/1.1 200 OK"); //send new page
client.println("Content-Type: text/html");
client.println("Connection: close");
//client.println("Refresh: 2"); // refresh the page automatically every 5 sec
client.println();
client.println("<HTML>");
client.println("<HEAD><meta name='viewport' content=width=device-width, initial-scale=1.0, user-scalable=no'>");
client.println("<TITLE>Lichtpanel </TITLE>");
client.println("</HEAD>");
client.println("<BODY> <body text='#848484' link='#848484' vlink='#848484' alink='#000000'style='background-color:#2A1B0A'>");
client.println("<center>");
client.println("<h2>Lichtpanel ");
if (SLAVE_ADDRESS == Kim_Adress) {
client.println("Kim </h2>");
}
else {
client.println("Moritz </h2>");
}
// DIY buttons
client.println("<table><tr>");
client.println("<th>"); client.println("<a href=\"/?1\"\">Weiss</a>"); client.println("</th>");
client.println("<th>"); client.println("\t<a href=\"/?2\"\">Warmweiß</a>"); client.println("</th>");
client.println("<th>"); client.println("\t<a href=\"/?3\"\">Kaltweiß</a>
"); client.println("</th>");
client.println("</tr>");
client.println("<tr>");
client.println("<th>"); client.println("<a href=\"/?4\"\">Mondlicht</a>"); client.println("</th>");
client.println("<th>"); client.println("\t<a href=\"/?5\"\">Rotweiß</a>"); client.println("</th>");
client.println("<th>"); client.println("\t<a href=\"/?6\"\">Violett</a>
"); client.println("</th>");
client.println("</tr>");
client.println("<tr>");
client.println("<th>"); client.println("<a href=\"/?7\"\">Blauweiss</a>"); client.println("</th>");
client.println("<th>"); client.println("\t<a href=\"/?8\"\">Gruenweiss</a>"); client.println("</th>");
client.println("<th>"); client.println("\t<a href=\"/?9\"\">Orange</a>
"); client.println("</th>");
client.println("</tr></table>");
//----------------
client.print("
<form method=get>Helligkeit:<input type=range min='0' max='99' size=4 name=L value=");
client.println(val);
client.print("> <input name=H type=submit value=submit></form>");
//--------
client.println("
<a href=\"/?k\"\">Seite wechseln</a>
");
client.println("</BODY>");
client.println("</HTML>");
delay(1);
//stopping client
client.stop();
if (readString.indexOf("L") == 6)
{
char faktBuff[4];
readString.substring(8, 11).toCharArray(faktBuff, 3); //transfer substring to buffer
Serial.println("faktbuff:");
Serial.println(faktBuff);
Serial.println("readString.substring(readString.indexOf('L')+2,readString.indexOf('H')-1) )");
Serial.println(readString.substring(readString.indexOf("L") + 2, readString.indexOf("H") - 1) );
val = atoi(faktBuff);
fakt = (float)val / 100.0;
#ifdef debug
Serial.print("val: "); Serial.println(val);
Serial.print("fakt: "); Serial.println(fakt);
#endif
set_colors(color[0], color[1], color[2], color[3], color[4], color[5]);
}
if (readString.indexOf("1") == 6) //Weiss
{
set_colors(255, 80, 70, 200, 150, 10);
}
if (readString.indexOf("2") == 6) //warmweiß
{
set_colors(255, 60, 5, 255, 0, 10);
}
if (readString.indexOf("3") == 6) //Kaltweiß
{
set_colors(255, 150, 130, 0, 255, 10);
}
if (readString.indexOf("4") == 6) //Mondlicht
{
set_colors(0, 0, 0, 0, 10, 20);
}
if (readString.indexOf("5") == 6) //Pink
{
set_colors(255, 20, 0, 150, 0, 10);
}
if (readString.indexOf("6") == 6) //Violett
{
set_colors(255, 5, 80, 20, 0, 10);
}
if (readString.indexOf("7") == 6)
{
set_colors(100, 100, 220, 5, 150, 10);
} if (readString.indexOf("8") == 6)
{
set_colors(180, 255, 30, 120, 120, 10);
}
if (readString.indexOf("9") == 6) //Orange
{
set_colors(255, 50, 0, 0, 0, 20);
}
if (readString.indexOf("k") > 0) {
if (SLAVE_ADDRESS == Kim_Adress) {
SLAVE_ADDRESS = Moritz_Adress;
#ifdef debug
Serial.print("Adresse: "); Serial.println(SLAVE_ADDRESS );
#endif
}
else {
SLAVE_ADDRESS = Kim_Adress;
}
#ifdef debug
Serial.print("Adresse: "); Serial.println(SLAVE_ADDRESS );
#endif
}
//clearing string for next read
readString = "";
}
}
}
}
}
int set_colors(byte r, byte g, byte b, byte kw, byte ww, byte t)
{
Wire.beginTransmission(SLAVE_ADDRESS);
color[0] = r;
color[1] = g;
color[2] = b;
color[3] = kw;
color[4] = ww;
color[5] = t;
r = r * fakt;
g = g * fakt;
b = b * fakt;
kw = kw * fakt;
ww = ww * fakt;
Wire.write(r);
Wire.write(g);
Wire.write(b);
Wire.write(ww);
Wire.write(kw);
Wire.write(t);
if (Wire.endTransmission() == 0) //succsess
{
#ifdef debug
Serial.println("Wire.write success");//
#endif
return 1;
}
else { //no success
#ifdef debug
Serial.println("Wire.write was not sccessfull!");
#endif
set_colors(r, g, b, kw, ww, t); //nicht sehr elegant funktioniert aber :D
return 0;
}
}
So sieht die Website dann aus:
Und nochmal etwas Detailierter zum System: Die LED's hängen an zwei Arduino mit 5 MOSFETS, welche mit PWM angestuert werden. Diese Arduinos bekommen per i2c schnittstelle 5 byte gesendet :[rot,grün,blau,warmweiß,kaltweiß,fadezeit]. Diese 5 bytes werden von dem Arduino Uno gesendet auf dem sich ein Ethernet-Shield befindet. Um diesen geht es (der andere Teil funktioniert einwandfrei )
Ein und ausschalten habe ich schon selbst ganz gut hinbekommen mir geht es eigentlich darum, dass ich auf der Website noch gerne für jeden Kanal einen "schieberegler" hätte, so wie ich es schon für die Helligkeit habe.
Aber ich will nicht für jeden Kanal "Submit" klicken. Und ich hätte es gerne einfach und verstädnlich. (Ich habe wenig ahnung von HTML /Javascript und)
@Christian81: ich muss zugeben, dass ich AJAX nicht kenne gibt es da irgendwo was einführendes mit dem Arduino zu?
Habe meinen Code etwas überarbeitet, indem ich mit dem F() makro die ganzen Strings nicht in den arbeitsspeicher lade.
Habe allerdings leider immernoch keinen Plan wie ich mehrere range slider implementiere oder diese "live" auslese
//known issues: wahl der Links ist nicht sonderlich elegant
//design muss überarbeitet werden
#include <SPI.h>
#include <Ethernet.h>
#include "Wire.h"
const byte MASTER_ADDRESS = 43;
const byte Moritz_Adress = 42;
const byte Kim_Adress = 44;
byte SLAVE_ADDRESS = 42;
byte color[6] = {0, 0, 0, 0, 0, 10};
float fakt = 1.0;
int val = 100;
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 192, 168, 178, 177 }; // ip in lan
byte gateway[] = { 192, 168, 1, 1 }; // internet access via router
byte subnet[] = { 255, 255, 255, 0 }; //subnet mask
EthernetServer server(80); //server port
#define debug 1
String readString;
//////////////////////
void setup() {
pinMode(5, OUTPUT); //pin selected to control
//start Ethernet
Ethernet.begin(mac, ip, gateway, subnet);
server.begin();
Wire.begin();
//enable serial data print
#ifdef debug
Serial.begin(9600);
Serial.println(F("server LED test 1.0 Debug: ON")); // so I can keep track of what is loaded
#endif
}
void loop() {
// Create a client connection
EthernetClient client = server.available();
if (client) {
while (client.connected()) {
if (client.available()) {
char c = client.read();
//read char by char HTTP request
if (readString.length() < 100) {
//store characters to string
readString += c;
#ifdef debug
Serial.print(c);
#endif
}
//if HTTP request has ended
if (c == '\n') {
///////////////
Serial.println(readString); //print to serial monitor for debuging
client.println(F("HTTP/1.1 200 OK")); //send new page
client.println(F("Content-Type: text/html"));
client.println(F("Connection: close"));
//client.println(F("Refresh: 2")); // refresh the page automatically every 5 sec
client.println();
client.println(F("<HTML>"));
client.println(F("<HEAD><meta name='viewport' content=width=device-width'>"));
client.println(F("<TITLE>Lichtpanel </TITLE>"));
client.println(F("</HEAD>"));
client.println(F("<BODY style='font-family:Arial'> <body text='#848484' link='#848484' vlink='#848484' alink='#000000'>"));
client.println(F("<center>"));
client.println(F("<h2>
Lichtpanel "));
if (SLAVE_ADDRESS == Kim_Adress) {
client.println(F("Kim </h2>"));
}
else {
client.println(F("Moritz </h2>"));
}
// DIY buttons
client.println(F("<table><tr>"));
client.println(F("<th>")); client.println(F("<a href=\"/?1\"\">Weiß</a>")); client.println(F("</th>"));
client.println(F("<th>")); client.println(F("\t<a href=\"/?2\"\">Warmweiß</a>")); client.println(F("</th>"));
client.println(F("<th>")); client.println(F("\t<a href=\"/?3\"\">Kaltweiß</a>
")); client.println(F("</th>"));
client.println(F("</tr>"));
client.println(F("<tr>"));
client.println(F("<th>")); client.println(F("<a href=\"/?4\"\">Mondlicht</a>")); client.println(F("</th>"));
client.println(F("<th>")); client.println(F("\t<a href=\"/?5\"\">Rotweiß</a>")); client.println(F("</th>"));
client.println(F("<th>")); client.println(F("\t<a href=\"/?6\"\">Violett</a>
")); client.println(F("</th>"));
client.println(F("</tr>"));
client.println(F("<tr>"));
client.println(F("<th>")); client.println(F("<a href=\"/?7\"\">Blauweiß</a>")); client.println(F("</th>"));
client.println(F("<th>")); client.println(F("\t<a href=\"/?8\"\">Gruenweiß</a>")); client.println(F("</th>"));
client.println(F("<th>")); client.println(F("\t<a href=\"/?9\"\">Orange</a>
")); client.println(F("</th>"));
client.println("</tr></table>");
//----------------
client.print(F("
<form method=get>Helligkeit:<input type=range min='0' max='99' size=4 name=L value="));
client.println(val);
client.print(F("> <input name=H type=submit value=submit></form>"));
//--------
client.println(F("
<a href=\"/?k\"\">Seite wechseln</a>
"));
client.println(F("</BODY>"));
client.println(F("</HTML>"));
delay(1);
//stopping client
client.stop();
if (readString.indexOf("L") == 6)
{
char faktBuff[4];
readString.substring(8, 11).toCharArray(faktBuff, 3); //transfer substring to buffer
Serial.println(F("faktbuff:"));
Serial.println(faktBuff);
Serial.println(F("readString.substring(readString.indexOf('L')+2,readString.indexOf('H')-1) )"));
Serial.println(readString.substring(readString.indexOf("L") + 2, readString.indexOf("H") - 1) );
val = atoi(faktBuff);
fakt = (float)val / 100.0;
#ifdef debug
Serial.print(F("val: ")); Serial.println(val);
Serial.print(F("fakt: ")); Serial.println(fakt);
#endif
set_colors(color[0], color[1], color[2], color[3], color[4], color[5]);
}
if (readString.indexOf("1") == 6) //Weiss
{
set_colors(255, 80, 70, 200, 150, 10);
}
if (readString.indexOf("2") == 6) //warmweiß
{
set_colors(255, 60, 5, 255, 0, 10);
}
if (readString.indexOf("3") == 6) //Kaltweiß
{
set_colors(255, 150, 130, 0, 255, 10);
}
if (readString.indexOf("4") == 6) //Mondlicht
{
set_colors(0, 0, 0, 0, 10, 20);
}
if (readString.indexOf("5") == 6) //Pink
{
set_colors(255, 20, 0, 150, 0, 10);
}
if (readString.indexOf("6") == 6) //Violett
{
set_colors(255, 5, 80, 20, 0, 10);
}
if (readString.indexOf("7") == 6)
{
set_colors(100, 100, 220, 5, 150, 10);
} if (readString.indexOf("8") == 6)
{
set_colors(180, 255, 30, 120, 120, 10);
}
if (readString.indexOf("9") == 6) //Orange
{
set_colors(255, 50, 0, 0, 0, 20);
}
if (readString.indexOf("k") > 0) {
if (SLAVE_ADDRESS == Kim_Adress) {
SLAVE_ADDRESS = Moritz_Adress;
#ifdef debug
Serial.print(F("Adresse: ")); Serial.println(SLAVE_ADDRESS );
#endif
}
else {
SLAVE_ADDRESS = Kim_Adress;
}
#ifdef debug
Serial.print(F("Adresse: ")); Serial.println(SLAVE_ADDRESS );
#endif
}
//clearing string for next read
readString = "";
}
}
}
}
}
int set_colors(byte r, byte g, byte b, byte kw, byte ww, byte t)
{
Wire.beginTransmission(SLAVE_ADDRESS);
color[0] = r;
color[1] = g;
color[2] = b;
color[3] = kw;
color[4] = ww;
color[5] = t;
r = r * fakt;
g = g * fakt;
b = b * fakt;
kw = kw * fakt;
ww = ww * fakt;
Wire.write(r);
Wire.write(g);
Wire.write(b);
Wire.write(ww);
Wire.write(kw);
Wire.write(t);
if (Wire.endTransmission() == 0) //succsess
{
#ifdef debug
Serial.println(F("Wire.write success"));//
#endif
return 1;
}
else { //no success
#ifdef debug
Serial.println(F("Wire.write was not sccessfull!"));
#endif
set_colors(r, g, b, kw, ww, t); //nicht sehr elegant funktioniert aber :D
return 0;
}
}
Fingolin:
Aber ich will nicht für jeden Kanal "Submit" klicken. Und ich hätte es gerne einfach und verstädnlich.
(Ich habe wenig ahnung von HTML /Javascript und)
Was Du Dir bastelst sind Eingabeformulare, die mit dem HTML-Tag "" deklariert werden.
Alls zwischen und ist für sich genommen "ein Formular", dessen Daten allesamt auf einmal gesendet werden.
Innerhalb des Formulars kannst Du verschiedene Eingabeelemente definieren "".
Das Eingabelement vom Typ "" ist dabei Dein Slider.
Das ist ein spezielles HTML5 Element, das nur von HTML5-fähigen Webbrowsern verstanden wird.
Eine einzelne HTML-Seite kann keins, eins oder auch mehrere "FORM" Formulare enthalten.
Aber eins ist immer gleich: Wenn Du mehrere Eingabeelemente in einem einzigen Formular haben möchtest, mußt Du auch mehrere Eingabeelemente zwischen und stehen haben.
In diesem Formular definierst Du zwei Elemente, und zwar:
Deinen "Slider" vom "type=range", mit dem Du die Werte einstellst, und
den "Submit-Button" vom "type=submit", mit dem Du das Formular an den Webserver absenden kannst:
Wenn Du mehrere Slider im selben Formular haben möchtest, müßtest Du auch mehrere Slider im Formular definieren. Damit Du die Slider dann auseinander halten kannst, müssen sie verschiedene Namen haben. Und natürlich auch verschiedene Werte, sonst ist es witzlos.
Das würde auf einer HTML-Seite einem Formular mit mehreren Eingabeelementen vom Typ "range" entsprechen.
Damit Du ein funktionierendes Programm bekommst, muß der Server einerseits HTML-Seiten erzeugen, auf denen die Formulare mit den diversen Eingabeelementen vorhanden sind, und andererseits muss der Server bei Erhalt eines Requests die gesendeten Daten auch verarbeiten.
Fingolin:
gibt es noch die möglichtkeit das Formular ohne "submit" abzusenden?
Grundsätzlich arbeiten HTTP-Webserver strikt nach dem Client-Server-Prinzip:
Ein "Client" stellt eine Verbindung zum Server her
Sobald die Verbindung steht, sendet der Client einen Request an den "Server"
der Server beantwortet den Request und schließt die Verbindung auf der Serverseite
der Client liest die Serverantwort und schließt die Verbindung auf der Clientseite
Rein per HTML kannst Du einen Request nur starten, indem Du entweder einen Link im Browser anklickst oder ein Formular submittest.
Wenn Du "aktive" Inhalte in die HTML-Seite eingebaut hast, z.B. "Javascript" oder anderes, dann können auch die aktiven Inhalte auf der Seite neue Requests an den Server auslösen. Wurde auch oben bereits von Christian81 angerissen: Die Kombination von Javascript (JSON) mit der AJAX-Technik ist eine Möglichkeit, um in Deinem Webbrowser Javascript arbeiten zu lassen, um im Hintergrund sowohl HTTP-Anfragen abzusetzen als auch die Rückgabe des Servers auszuwerten, um daraufhin den Seiteninhalt aktiv nur zu "ändern" statt die Seite "komplett neu zu laden".
Allerdings reichen zur Anwendung nur gute Kenntnisse von HTML nicht aus. Du würdest darüber hinaus auch gute Kenntnisse von Javascript und der Ajax-Technik benötigen, um es sinnvoll auf einem Arduino einsetzen zu können.
das hat nichts mit dem arduino zu tun, die slider stehen ja im HTML- bzw JS-teil des sketches. gibt's auch fertig in der jQuery-bibliothek. die mußt Du also im "webseiten-teil" des sketches einbauen und dann genauso wie bei den buttons die werte an den arduino-webserver zurückschicken.
okay danke, habe im Moment nicht so viel Zeit dafür aber ich werde mich nächste Woche mal ein bisschen in Javascript usw einlesen
Vielen Dank für die Hilfe!
Bei meinem Wetterserver Projekt hatte ich erstmal manuell eine Html Seite auf dem PC erstellt
Und dort würde ich mal ein Slider control einbauen. (gibt genug Beispiele)
Auf dem PC kannst du einfacher testen und verstehen was das Control bzw, die Java Funktion macht.
Wenn das ganze mal theoretisch läuft und verstanden ist, auf den Arduino übertragen.
Man wächst mit der Aufgabe, hatte sehr wenig Ahnung von Html und noch weniger von Java Script.
Und wenn der "Aha" Effekt mal da ist, läuft es fast von selbst.
Hatte mich damals auch in Ajax versucht, hier kam leider kein "Aha" Effekt.
Durch das Posting vom Christian81 bin ich wieder neugierig geworden, evtl. kann ich mein altes Projekt verbessern.