Pages: 1 2 3 [4]   Go Down
Author Topic: Ausgang per Web schalten mit PHP  (Read 12817 times)
0 Members and 1 Guest are viewing this topic.
Germany
Offline Offline
Sr. Member
****
Karma: 1
Posts: 309
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo,
ja ist richtig, ich habe hier eine Synologie DS111 wo der Apache drauf läuft.
@Mario, nochmal Danke, hätte man auch selber drauf kommen müssen  smiley-roll-blue
Ich habe am falschen Ende probiert, ich dachte es müste noch ein byte mehr übertragen werden, damit beide Zahlen angezeigt werden.  smiley-red
Aber so ist das mit "halbwissen".... lol

Aber jetzt gehts, Timer werden übergeben und die Restzeit für jedes Ventil (Ausgang) angezeigt.

Damit ist dieses Projekt hier erstmal zu Ende. Ich werde den Code so schnell wie möglich nach schieben, aber mit dem Kommentieren hapert es noch  smiley-slim

Also vielen vielen Dank für die tolle und sehr Hilfreiche unterstützung an mkl0815 !!!
Ich kann sagen ich habe vieles gelernt und einiges werde ich wohl nie lernen...  smiley-wink
DANKE !!!
« Last Edit: May 21, 2012, 10:20:52 am by Cetax » Logged

*greatz*

 CeTax

www dot blinkmann dot de


Germany
Offline Offline
Sr. Member
****
Karma: 1
Posts: 309
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo allerseits,
hier mal der Sketch und das PHP-Script welches die Arduino Ausgänge per Zeitvorgabe
über ein Webinterface Steuert. Das PHP-Script ist einfach gehalten, so kann es jeder
nach seinen Vorstellungen verändern, bei mir sieht es komplexer aus.  smiley-wink

Ich hoffe das ist gut genug beschrieben, habe das mal auf die schnelle zusammen gestellt.

Sketch:
Code:
/*
  Arduino Ausgang per PHP-Webinterface schalten
  written by mkl0815 and Cetax
  Date 21.05.2012
  Cetax at bk-s dot de
*/
#include <SPI.h>
#include <Ethernet.h>

// MAC und IP Konfiguration
byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0xEE, 0xF3 };
IPAddress ip(192,168,178,216);
IPAddress gateway(192,168,178,1);
IPAddress subnet(255, 255, 255, 0);

// warten auf port 23
EthernetServer server(23);

unsigned long previousMillis = 0;       

#define NUMTIMER 6               // 6 Timer können kommen
int TI;                          // Variable für Timer
int timerpin[NUMTIMER];          // Variable für Ausgangs-Pin
int timerlength[NUMTIMER];       // Variable für übergebene Zeit

void setup() {
  //Ethernet initialisieren
  Ethernet.begin(mac, ip, gateway, subnet);
  // Server starten
  server.begin();
  // serielle konsole öffnen (debug)
  Serial.begin(9600);
}

void loop() {
      //prüfen ob eine Sekunde vergangen ist
  if(millis()-previousMillis >= 1000) {
    //aktuelle Zeit merken
    previousMillis = millis();

    //alle timer auswerten
    for(int t=0; t<NUMTIMER;t++) {

      //nur timer beachten, die auch verwendet werden sollen (positive PIN nummer)
      if(timerpin[t] > 0 ){

        //bei aktuellem timer eine sekunde abziehen, wenn "0", dann abgelaufen
        if( --timerlength[t] == 0) {
          //Ausgang umschalten ( HIGH -> LOW oder LOW -> HIGH)
          digitalWrite(timerpin[t],!digitalRead(timerpin[t])); 

          //timer deaktivieren ( timer mit pin "-1" sind inaktiv)
          timerpin[t] = -1;

          //debug
          Serial.print("T Kommando empfangen, Timer ");
          Serial.print(t);
          Serial.println(" abeglaufen.");
        }
      } 
    }
  }

  // auf eine eingehende Verbindung warten
  EthernetClient client = server.available();
 
  if (client) {
   
    char command =client.read();
    byte pinnumber =client.read();
    byte pinvalue =client.read();
    byte returnvalue = 0;
   
    //Kommando auswerten
    switch(command) {

    case 'S':
      Serial.print("S Kommando empfangen, setze Pin ");
      Serial.print(pinnumber);
      Serial.print(" auf ");
      Serial.println(pinvalue);
      pinMode(pinnumber,OUTPUT);
      digitalWrite(pinnumber,pinvalue);
     //gesetzten wert auch zurückliefern
      returnvalue=pinvalue;
      break;

    case 'R':
      returnvalue = digitalRead(pinnumber);
      Serial.print("R Kommando empfangen, lese Pin ");
      Serial.print(pinnumber);
      Serial.print(". Wert = ");
      Serial.println(returnvalue);
      break;
     
   case 'U':
      TI = client.read();                     // Timer Nr.
      Serial.print("U Kommando empfangen, lese Timer ");
      Serial.print(TI);
      Serial.print(" Wert = ");
      Serial.println(timerlength[TI] /60);
      client.print(timerlength[TI] /60);
      break;

   case 'T':
     TI = client.read();                     // Timer Nr.
     timerlength[TI] = client.read();        // zeit für ventil öffnung
     timerpin[TI] = pinnumber;               // zu schaltender Pin
     timerlength[TI] = timerlength[TI] *60;  // die empfangenen sec*60 = min
     Serial.print("T Kommando empfangen, ");
     Serial.print("Timer ");
     Serial.print(TI);
     Serial.println(" gestartet");
      Serial.print("T Kommando empfangen, setze Pin ");     
      Serial.print(timerpin[TI]);
      Serial.print(" auf ");
      Serial.println(pinvalue);
      pinMode(timerpin[TI],OUTPUT);
      digitalWrite(timerpin[TI],pinvalue);
      Serial.print("T Kommando empfangen, setze Time auf ");
      Serial.print(timerlength[TI]);
      Serial.print(" sec");
      Serial.println(" ");
      returnvalue=pinvalue;                 //gesetzten wert auch zurückliefern
      break;

    default:
      Serial.println("Fehler, unbekanntes Kommando");   
      break;

    } 
   
    // rückantwort senden (1 byte) die "+48" sorgen dafür das der Wert 0 oder 1
    // als Zeichen "0" oder "1" übertragen werden.
    //das vereinfacht die verarbeitung in php.
    client.write(returnvalue+48);
   
    //übertragung erzwingen
    client.flush();
   
    //10ms delay damit daten sicher gesendet werden.
    delay(10);
   
    //wichtg! client verbindung beenden
    client.stop();
  }
}
PHP-Code:
Code:
<!--
  Arduino Ausgang per PHP-Webinterface schalten
  written by mkl0815 and Cetax
  Date 21.05.2012
  Cetax at bk-s dot de
-->
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Bew&auml;sserung</title>
<?php

$arduino_ip 
"192.168.178.216";
$arduino_port "23";

function 
arduino_send($ip,$port,$command) {
    
$res fsockopen($ip,$port);
    if(
$res) {
        
fwrite($res,$command);
        
$ret =fread($res,10);
        
//echo "Ventil = $ret <br>\n";
        //echo "1 = Zu | 0 = Auf <br>\n";
        
return $ret;
    } else {
        echo 
"Fehler, kein kontakt.<br>Kommando konnte nicht abgesetzt werden";
    }
}
// Ventil 1 start

// hier werden 5 byte gesendet ( T  ; chr(4) ; chr(0)  ; chr(0) ; chr($V1) )
//  Case ; PinNr  ; Zustand ; Timer1 ; Ventil1
if(isset($_GET['V1'])) {
    
$V1 $_GET['V1'];                      //PinNR.   AUF    Timer1  Ventil1
    
arduino_send($arduino_ip,$arduino_port,"T".chr(4).chr(0).chr(0).chr($V1));
}

if(isset(
$_GET['V1stop'])) {
    
$V1stop $_GET['V1stop'];
    
arduino_send($arduino_ip,$arduino_port,"S".chr(4).chr(1));
}
 else {
    
$V1stop arduino_send($arduino_ip,$arduino_port,"R".chr(4).chr(1));
 }
// Ventil 1 ende
?>

</head>
<body>
<h1><div align="center">Bew&auml;sserung</div></h1>
<div align="center">
<table border="0" bgcolor="#808080">
<tr>
<td><div align="center"><b>Ventil 1</b></div></td>
</tr>
<tr>
<td>
<form action="">
<p><div align="center"><select name="V1">
<option value="">&nbsp;&nbsp;Zeit</option>
<option value="15">15 min</option>
<option value="30">30 min</option>
<option value="45">45 min</option>
<option value="60">60 min</option>
</select></div></p>
<p><input type="checkbox" name="V1stop" value="1"><font size=
"-1">Schlie&szlig;en</font></p>
<p></p>
<div align="center"><input type="submit" name="submit" value=
"Senden"></div>
<p></form>
<?php if($V1stop==1){
  echo 
"<div align='center'>&nbsp;Geschlossen&nbsp;</div>\n";
} else {
  echo 
"<div align='center'>&nbsp;Offen&nbsp;</div>\n";}
?>

</td>
</tr>
<tr>
<td>
<?php
  $V1 
arduino_send($arduino_ip,$arduino_port,"U".chr(4).chr($V1).chr(0));
  
$restzeit $V1;
if(
$restzeit!=0){
   echo 
'<div align="center">Restzeit<br /> <b>' .gmdate("i:s"$V1). '&nbsp;min</b></div>';
   } else {
   echo 
"&nbsp;"; }
  
?>

</td>
</tr>
</table></div>
</body>
</html>

Geht bestimmt schöner und aufgeräumter...
« Last Edit: May 21, 2012, 02:36:28 pm by Cetax » Logged

*greatz*

 CeTax

www dot blinkmann dot de


Offline Offline
Full Member
***
Karma: 0
Posts: 238
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi, vielen Dank für dein Thread und eure geleistete Arbeit. Magst du mir die Geschichte mit dem Prot einmal erklären. Ich möchte das ganze einfach lokal mit einem WLAN Shield testen. Dazu verwende ich XAMPP, muss ich den Port als Weiterleitung als UDP/TCP im Router einstellen oder (weil ich lokal im selben Netz arbeite) kann ichd as weglassen?
mfg
Balli
Logged

Germany
Offline Offline
Full Member
***
Karma: 1
Posts: 130
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

...Dazu verwende ich XAMPP, muss ich den Port als Weiterleitung als UDP/TCP im Router einstellen oder (weil ich lokal im selben Netz arbeite) kann ichd as weglassen?...

Hallo Ballibum,

lokal kannst du den Port weglassen. Da leitet der Router alles weiter! Man muss nur die Ports manuell konfigurieren, die von Außen kommen.
Dazu ist aber eh eine Domain-Weiterleitung nötig, da sich die IP alle 24Std ändert. Dyndns.org zum Beispiel bietet sowas kostenfrei an. Aber ich denke das führt zu weit, wenn du das erstmal nur intern testen möchtest  smiley

Gruß,
Thomas
Logged

Offline Offline
Edison Member
*
Karma: 21
Posts: 1419
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

lokal kannst du den Port weglassen. Da leitet der Router alles weiter! Man muss nur die Ports manuell konfigurieren, die von Außen kommen.
Dazu ist aber eh eine Domain-Weiterleitung nötig, da sich die IP alle 24Std ändert. Dyndns.org zum Beispiel bietet sowas kostenfrei an. Aber ich denke das führt zu weit, wenn du das erstmal nur intern testen möchtest  smiley
Wenn es das gleiche Subnetz ist, hat der Router damit nichst zu tun. Der Router kommt nur ins Spiel, wenn Pakete das eigene Netz verlassen, dann wird nämlich gerouted, was auch den Namen des Gerätes erklärt. Ein lokales Netz läuft auch ohne einen Router nur mit einem Switch, oder bei einer direkten Verbindung zwischen zwei Geräten sogar ohne diesen.

Domain-Weiterleitung stimmt auch nicht ganz, denn das wäre sowas wie ein HTTP-Redirect (HTTP 301 oder HTTP 302). Was Du meinst ist die Namensauflösung, also DNS (Domain Name Service). Am Ende wird eine registrierte Dyndns.org Domain regelmäßig mit der akutellen IP des Routers versorgt und damit die Domain immer auf diese aufgelöst. Dafür wird dann auch das Portforwarding benötigt, da in der Regel der Router das interne, private Netz auf die öffentliche IP die er vom Provider bekommt umsetzt. (Stichwort NAT)

@Balibum: Unterscheiden musst Du im Prinzip 2 Verbindungen. Einmal die Netzwerkverbindung zwischen dem Webserver und dem Arduino, die ist vermutlich lokal. Hier kann also das Script auf dem Webserver direkt die IP des Arduino und den entsprechenden Port verwenden. Die andere Verbindung ist die vom Browser zum Webserver. Diese kann auch lokal sein, wenn Du von innerhalb Deines lokalen Netztes auf den Webserver zugreifst. Willst Du auch von extern über einen Browser auf die Anwendung zugreifen, dann kommen die oben genannten Port-Weiterleitungen auf dem Router ins Spiel, damit Du über die externe IP Deines Routers (oder die passenden dyndns.org domain) darauf zugreifen kannst.

Mario.
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 238
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo Mario und Thomas,
danke für die Antworten.
Ich möchte das ganze nur im lokalen Netz laufen haben. Sprich ich habe mein Arduino mit WLAN Shield und mein Laptop mit irgendeiner anderen Netzwerkkarte, weil ich zwei aber nicht Ad Hoc verbinden will sind sie beide über einen Router im selben Netzwerk registriert (so wie das privat eben üblich ist, sofern auf WLAN zurück gegriffen wird). Als Webserver habe ich XAMPP und MS4W (verwenden meines erachtens den Apache-Webserver) zur Verfügung. Den Port kann ich also weglassen, solange ich das ganze nur in diesem Netzwerk laufen lassen möchte. Sollte ich die Funktion auf meinem Webserver bei Strato laufen lassen müsste ich das ganze über portforwarding machen, richtig?Wenn ja, muss ich den Port verwenden der im Router festgelegt wurde richtig?
mfg
Balli
Logged

Offline Offline
Edison Member
*
Karma: 21
Posts: 1419
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Im Prinzip ist es so. Dein Router fungiert in Deinem Fall aber nur als "Switch", bzw. WLAN-Access Point für das WLAN Shield und nicht primär als Router.

Von welchem Port genau redest Du?
1) Der Port auf dem der Arduino auf eine ankommende Verbidung vom Webserver-Script lauscht (im Beispiel-Code wäre das Port 23)?
2) Vom Port auf dem der Webserver auf eine ankommende Verbndung (HTTP-Anfrage) vom Browser wartet?
Das mußt Du ganz klar unterscheiden.

Wenn Du Deine Webanwendung z.B. bei Strato hostest, dann müßtest Du den Port auf dem der Arduino lauscht im Router freigeben und auf die IP-Adresse die der Arduino hat weiterleiten, damit Dein Script bei Strato auf den Arduino zugreifen kann. Davon würde ich aber abraten, denn der Sketch auf dem Arduino hat keinerlei Sicherheitsmassnahmen eingebaut. Ist der Port im Router auf den Arduino weitergeleitet, kann JEDER im Internet darauf zugreifen. Da reichen schon die ganzen Bots, welche die Provider-IPs scannen und dort Verbindungen aufbauen, irgendwelche bytes senden die sicher immer und je nachdem auf was der Sketch reagiert, kann das "lustige" Effekte auslösen.

Der bessere Weg wäre, wenn Du auch den Webserver lokal in Deinem Netz hast und dort entsprechende Sicherheitsfeatures wie z.B. https oder eine Passwort-Abfrage etc. einbaust. Im Router leitest Du dann den Port auf dem der Webserver lauscht (in der Regel Port 80, oder 443 bei HTTPS) auf die interne IP des Webservers um.

In beiden Fällen mußt Du natürlich dafür sorgen, das Arduino oder Webserver intern immer die gleiche IP haben, sonst klappt das nicht.
Mario.
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 238
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Mario,

Quote
Von welchem Port genau redest Du?
1) Der Port auf dem der Arduino auf eine ankommende Verbidung vom Webserver-Script lauscht (im Beispiel-Code wäre das Port 23)?
2) Vom Port auf dem der Webserver auf eine ankommende Verbndung (HTTP-Anfrage) vom Browser wartet?
Das mußt Du ganz klar unterscheiden.
Ich denke ich meine Vorallem Punkt 1, denn Punkt zwei passiert doch automatisch oder etwa nicht???Und im PHP-Script verwende ich eben den Port "23", weil dieser Port der Eingang zum WLan Shield ist!? Ich selber verwende das Socket-Beispiel vom Arduino und wollte mit SocketRead() arbeiten, leider finde ich da keine Möglichkeit einen Port zu definieren. Worauf muss ich da achten, bzw. was genau ist der Unterschied zwischen Socket und normalen Zugriff?

mfg
Balli
Logged

Offline Offline
Edison Member
*
Karma: 21
Posts: 1419
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Kannst Du bitte den Code posten mit dem Du arbeitest (Arduino und PHP), denn so ganz folgen kann ich Dir gerade nicht.
Welches "Socket-Beispiel vom Arduino " meinst Du genau?
Btw. wäre es evtl. gut einen neuen Thread zu starten, da dieser hier ja eigentlich abgeschlossen war.
Mario.
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 238
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Okay, ich starte einen eigenen Thread wenn ich nicht weiter komme, werde erstmal alles fertig machen und ausprobieren. Nur zur Info, ich arbeite aktuell mit den RedFly Wlan Shield Beispielen.
mfg
Balli
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

vielen Dank für diesen Thread, ich versuche es mit Pyhton(Django-Framework) und Wifi/LAN Shield. Bin jetzt schon ein gutes Stück weitergekommen ;-)
Logged

Cloppenburg
Offline Offline
Edison Member
*
Karma: 30
Posts: 1263
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Vor 120 tagen das letzte mal gepostet.... hmm
Das Thema ist aber immer noch Aktuell.

Ich sitze schon paar Tage dran und bekomme es nicht hin....
Habe in der index.php diesen code
Code:
<div data-role="content">
        <h2>Light switches</h2>
        <div data-role="fieldcontain">
            <label for="A">A</label>
            <select name="sliderA" id="A" data-role="slider" data-mini="true">
                <option value="off">Off</option>
                <option value="on">On</option>
            </select>
        <div data-role="fieldcontain">
            <label for="B">B</label>
            <select name="sliderB" id="B" data-role="slider" data-mini="true">
                <option value="off"">Off</option>
                <option value="on">On</option>
            </select>
        <div data-role="fieldcontain">
            <label for="C">C</label>
            <select name="sliderC" id="C" data-role="slider" data-mini="true">
                <option value="off"">Off</option>
                <option value="on">On</option>
            </select>
        </div>
        <script>
            $('#A').change(function (event) {
                var mySwitch = event.currentTarget;
                var val = mySwitch.value == "on" ? 1 :0 ;
$.post('updateProperties.php?dev='+mySwitch.id+'&stat='+mySwitch.value+'&pin='+"7"+'&val='+val, function(response){});
                $.post('sendControl.php?device='+mySwitch.id+'&switchDevice='+val, function (response){});

            });
            $('#B').change(function (event) {
                var mySwitch = event.currentTarget;
                var val = mySwitch.value == "on" ? 1 :0 ;
$.post('updateProperties.php?dev='+mySwitch.id+'&stat='+mySwitch.value+'&pin='+"7"+'&val='+val, function(response){});
                $.post('sendControl.php?device='+mySwitch.id+'&switchDevice='+val, function (response){});  
            });
            $('#C').change(function (event) {
               var mySwitch = event.currentTarget;
                var val = mySwitch.value == "on" ? 1 :0 ;
$.post('updateProperties.php?key=switchState_C&val='+mySwitch.value, function(response){});  
                $.post('sendControl.php?device='+mySwitch.id+'&switchDevice='+val, function (response){});
            });

function loadProperties(){

$.getJSON('properties.json?'+ new Date().getTime(), function(data) {
//alert ("I am here!");
$('.slider').val(data+mySwitch.id).slider('refresh');
// $('#B').val(data.B).slider('refresh');
// $('#C').val(data.switchState_C).slider('refresh');
});
}

</script>

Nun möchte ich beim klick auf #A,
die id (A), status (on), pin (7), value (1)
an updateProperties.php senden.

Anschließend in loadProperties() die Werte id (A), status (on) laden und der slider('refreshet')

In der sendControl.php habe ich momentan dieses
Code:
<?php
error_reporting
(E_ALL);
ini_set('display_errors''1');

$dev $_GET['dev'];
$stat $_GET['stat'];
$pin $_GET['pin'];
$val $_GET['val'];

#echo $dev;
#echo $val;

#$json_Data= json_decode(file_get_contents('properties.json'), true);
#$json_data[$dev] = "$stat";"$pin";$val;
$json_data json_decode(file_get_contents('properties.json'), true);
$json_data[$dev] = array($dev => $stat$pin => $val);
#$json_data[$device] = $stat;
#$json_data[$adress] = $key;
#$json_data[$pin] = $val;


#echo json_encode($arr);
#echo $json_data;
file_put_contents('properties.json'json_encode($json_data));
?>

Das ganze soll dann in der properties.json mit diesem Format gespeichert werden
[{"A":"on","7":"1"},{"B":"on","8":"1"}]

Weiß da jemand eine Lösung?
Oder wie man es evtl einfacher gestalten könnte?
« Last Edit: August 20, 2013, 08:34:52 am by skorpi08 » Logged

Nicht Mensch, nicht Tier: Programmierer halt...

Pages: 1 2 3 [4]   Go Up
Jump to: