INFO: Dieses Forum nutzt Cookies...
Cookies sind für den Betrieb des Forums unverzichtbar. Mit der Nutzung des Forums erklärst Du dich damit einverstanden, dass wir Cookies verwenden.

Es wird in jedem Fall ein Cookie gesetzt um diesen Hinweis nicht mehr zu erhalten. Desweiteren setzen wir Google Adsense und Google Analytics ein.

Antwort schreiben 
 
Themabewertung:
  • 1 Bewertungen - 5 im Durchschnitt
  • 1
  • 2
  • 3
  • 4
  • 5
Temperaturüberwachung + LCD + Webserver + eMail
21.11.2013, 20:58 (Dieser Beitrag wurde zuletzt bearbeitet: 21.11.2013 21:21 von rkuehle.)
Beitrag #1
Temperaturüberwachung + LCD + Webserver + eMail
Hier mal ein kürzlich realisiertes Projekt welches vom Grundsatz wie folgt aufgebaut ist:
Zweck:
Messung von 4 Temperatursensoren
Für 2 Sensoren ist eine Alarmfunktion per eMail integriert
Die Daten der 4 Sensoren werden in eine MySql - DB geschrieben und grafisch auf einer Website dargestellt
Bauteile:
1 Arduino Uno
1 LCD 4 x 20
4 Sensoren DS18S20
Bussysteme: I2C, OneWire
Libraries:
Wire.h // I2C Funktionen
LiquidCrystal_I2C.h // LCD Funktionen
Ethernet.h // Ethernetstack
SPI.h // SPI für Ethernetboard
OneWire.h // 1Wire Funktionen
DallasTemperature.h // Temperaturfühler

Da die bekannten Provider keine eMails von DHCP / DSL - Adressen zulassen, sollte man sich einen eigenen SMTP-Server hinstellen.
Als Software für den Server hat sich bei mir seit Jahren XAMPP bewährt. Finden kann man es hier: http://www.apachefriends.org/de/index.html.

Der Code für den Arduino:

Code:
// Includes
#include <Wire.h> // I2C Funktionen
#include <LiquidCrystal_I2C.h> // LCD Funktionen
#include <Ethernet.h> // Ethernetstack
#include <SPI.h> // SPI für Ethernetboard
#include <OneWire.h> // 1Wire Funktionen
#include <DallasTemperature.h> // Temperaturfühler
// Variablen
/* Ethernet
MAC Adresse steht auf Ethernetshield */
static byte mac[] = {
  0x90, 0xA2, 0xDA, 0x00, 0x9B, 0xC1 };
/* Daten-PIN für OneWire auf 5
Bei mehr als einem Sensor ist nur  e i n  PullUp Widerstand erforderlich */
#define ONE_WIRE_BUS 5
/* Dallas Sensoren
Adressen - müssen angepasst werden. Koennen über  http://www.hacktronics.com/Tutorials/arduino-1-wire-address-finder.html ausgelesen werden.   Alle Sensoren müssen vom Typ DS18S20 sein */
DeviceAddress s_aussenl = {
  0x10, 0x82, 0x9C, 0x77, 0x02, 0x08, 0x00, 0xFE};
DeviceAddress s_innenl = {
  0x10, 0xEA, 0xA2, 0x77, 0x02, 0x08, 0x00, 0xBA};
DeviceAddress s_wasser = {
  0x10, 0x5B, 0xC4, 0x54, 0x02, 0x08, 0x00, 0xFF};
DeviceAddress s_turbine = {
  0x28, 0x36, 0x57, 0xCC, 0x02, 0x00, 0x00, 0xE1};

float aussenl;
float innenl;
float wasser;
float turbine;

/* Puffer für Umsetzung der IP-Adresse aus Byte-Array von Ethernet.localIP()
Aufbau: "IP:  "+IP-Adresse+Abschlußzeichen "\0" + Auffüllung mit Leerezeichen
um vorher auf LCD angezeigtes Datum zu überschreiben */
char ipbuf[21];
// letztes now() für Messung, Webserver und DHCP
unsigned long lastnow;
unsigned long wlastnow;
unsigned long dlastnow;
// DHCP Lease - 2 Stunden - 1 Sekunde anpassen
const int dhcplease = 7199999;
/* Umwandlung eines 32Bit Integer in 8 Bit Integer
wird für Ethernet.localIP() genutzt, die über
Ethernet.maintain() gesetzt wird */
union IPAddressConverter {
  uint32_t ipInteger;
  uint8_t ipArray[4];
};
// OneWire - Instanz erstellen
OneWire oneWire(ONE_WIRE_BUS);
// Ankopplung von Dallas Temperatursensoren an OneWire
DallasTemperature sensors(&oneWire);
/* LCD I2C - Instanz für 4x20 LCD mit yWRobot (0x27)
SDA auf analog 4, SCL auf analog 5
Ãœberschreiben der PIN-Belegung für I2C-Chip da keine Standardbelegung lt. Library
I2C_ADDR    0x27
BACK_PIN  3
En_pin  2
Rw_pin  1
Rs_pin  0
D4_pin  4
D5_pin  5
D6_pin  6
D7_pin  7 */
LiquidCrystal_I2C  lcd(0x27,2,1,0,4,5,6,7);
// EthernetClient - Instanz erstellen
EthernetClient client;
void setup()
{
  // Zeiten für Messung Daten, Webserver und DHCP
  lastnow=millis();
  wlastnow=lastnow;
  dlastnow=lastnow;
  //Dallas Sensoren starten
  sensors.begin();
  // LCD starten
  lcd.setBacklightPin(3,POSITIVE);
  lcd.setBacklight(0);
  lcd.begin(20,4);
  lcd.setCursor(0,0);
  // Ethernet starten, 1 Sekunde warten und erstmalig DHCP-Adresse aktualisieren
  Ethernet.begin(mac);
  delay(1000);
  dhcprenew();
  aussenl = getTemperature(s_aussenl);
  innenl = getTemperature(s_innenl);
  wasser = getTemperature(s_wasser);
  turbine = getTemperature(s_turbine);
  zimmer1 = getTemperature(s_zimmer1);
  // Erstausgabe Temperaturen Dallas und IP auf LCD
  digitalIpDisplay();
  AusgabeTemp();
  // Alarm Turbine bei gleich/über 60 Grad Celsius?
  if (turbine >= 60.00) {
    sendEmail(1);
    digitalAlarmDisplay(1);
  }
  // Alarm Wasser bei gleich/unter 4 Grad Celsius?
  if (wasser <= 4.00) {
    sendEmail(2);
    digitalAlarmDisplay(2);
  }
}
/**************************************
** Ab hier eigentliche Programmlogik **
**************************************/
void loop()
{  
  Mess();
  /* Aktualisierung der DHCP-Adresse alle 2 Stunden
   Adresse wird dann in Speicherpuffer ipbuf geschrieben */
  if (millis()-dlastnow > dhcplease) dhcprenew();
}
/***************************************
** Bis hier eigentliche Programmlogik **
** Ab hier nur Subroutinen            **
***************************************/
// Anzeige IP-Adresse auf LCD
void digitalIpDisplay(){
  // aus IP-Buffer einen String machen
  String message=ipbuf;
  /* Länge des Strings variiert je nach DHCP - lokale IP
   aus der Länge des Strings werden unten die fehlenden
   Leerzeichen zum Ãœberschreiben des Datums errechnet */
  int lipbuf=message.length();
  lcd.setCursor(1,0);
  lcd.print(message);
}
// Anzeige Alarm
void digitalAlarmDisplay(int j){
  lcd.setCursor(0,3);
  if (j==1) lcd.print(">>>Alarm  Turbine<<<");
  if (j==2) lcd.print(">>>Alarm   Wasser<<<");
}
// Anzeige Temperaturen Dallas auf LCD
void AusgabeTemp()
{
  lcd.setCursor(0,1);
  lcd.print("AL: ");
  lcd.print(aussenl);
  lcd.setCursor(11,1);
  lcd.print("WA: ");
  lcd.print(wasser);
  lcd.setCursor(0,2);
  lcd.print("IL: ");
  lcd.print(innenl);
  lcd.setCursor(11,2);
  lcd.print("TU: ");
  lcd.print(turbine);
}
void Mess()
{
  /* Messung der Dallas Sensoren einmal pro 10 Sekunden und Ausgabe auf LCD
   Kleineres Intervall hätte Auswirkungen auf Laufzeitverhalten
   Senden der Daten an Webserver alle 5 Minuten */
  if (millis()-lastnow > 10000)
  {
    aussenl = getTemperature(s_aussenl);
    innenl = getTemperature(s_innenl);
    wasser = getTemperature(s_wasser);
    turbine = getTemperature(s_turbine);
    AusgabeTemp();
    lastnow=millis();
    // Alarm Turbine bei gleich/über 60 Grad Celsius?
    if (turbine >= 60.00) {
      sendEmail(1);
      digitalAlarmDisplay(1);
    }
        // Alarm Wasser bei gleich/unter 4 Grad Celsius?
    if (wasser <= 4.00) {
      sendEmail(2);
      digitalAlarmDisplay(2);
    }
  }
  if (millis() - wlastnow > 299999)
  {
    Daten_senden();
    wlastnow=millis();
  }
}
// Daten an Webserver: aussenl,innenl,wasser,turbine, key
void Daten_senden()
{
  // Name Webserver,-domäne,Pfad zu PHP-Datei auf Server, Key anpassen
  static char webdomain[] = "www.meine-webdomain.de";
  static char url[]  = "/verzeichnis/getdata.php";
  static char key[] = "keywert";
  /* Anpassen - muss hier direkt reingeschrieben werden
   da sonst der connect nicht funktioniert */
  if (client.connect("www.meine-webdomain.de",80))
  {
    client.print("GET ");
    client.print(url);
    // Temperatur aussen
    client.print("?AUSSENL=");
    client.print(aussenl);
    // Temperatur innen
    client.print("&INNENL=");
    client.print(innenl);
    // Temperatur wasser
    client.print("&WASSER=");
    client.print(wasser);
    // Temperatur turbine
    client.print("&TURBINE=");
    client.print(turbine);
    // Kennwort
    client.print("&key=");
    client.print(key);
    // Abschluss des Requests
    client.println(" HTTP/1.1");
    client.print("Host: ");
    client.print(webdomain);
    client.println("User-Agent: Arduino");
    client.println("Accept: text/html");
    client.println();
    client.stop();
    client.flush();
  }
}
void sendEmail(int i)
{
  //  Domäne, Adressen, Texte für SUBJECT und Inhalt anpassen
  static char mailserver[] = "smtp.mailserver.de";
  static char member[] = "Nutzername";
  static char subject[]="Temperatur Alarm!";
  static char inhalt1[]="Turbine bei / über 60 Grad Celsius!";
  static char inhalt2[]="Wasser bei / unter 4 Grad Celsius!";
  delay(1000);
  client.connect(mailserver,25);
  delay(500);
  // Text HELO
  client.print("HELO ");
  client.println(mailserver);
  delay(10);
  // Text Mail From
  client.print("MAIL FROM: @");  
  client.println(mailserver);
  delay(10);
  // Text RCPT TO
  client.print("RCPT TO:");
  client.print(member);
  client.print("@");
  client.println(mailserver);
  delay(10);
  // Text DATA
  client.println("DATA");
  delay(10);
  // Text TO
  client.print("TO:");
  client.print(member);
  client.print("@");
  client.println(mailserver);
  delay(10);
  // Titel des Mails
  client.print("SUBJECT: ");
  client.println(subject);
  delay(10);
  client.println();
  delay(10);
  // Inhaltstext des Mails
  if (i==1) client.println(inhalt1);
  if (i==2) client.println(inhalt2);
  delay(10);
  // Kennzeichnung Ende des Mails
  client.println(".");
  delay(10);
  // Abmelden
  client.println("QUIT");
  delay(10);
  client.stop();
  client.flush();
}
void dhcprenew()
{
  /* Abruf neue DHCP-Adresse
   Umwandeln der DHCP-Adresse in lesbare Zeichen und diese in Speicherbereich ipbuf
   Aufbau des ipbuf entsprechend Hinweis bei Deklaration */
  Ethernet.maintain();
  IPAddressConverter ipAddress;
  ipAddress.ipInteger = Ethernet.localIP();
  sprintf(ipbuf, "IP: %d.%d.%d.%d", ipAddress.ipArray[0], ipAddress.ipArray[1], ipAddress.ipArray[2], ipAddress.ipArray[3]);
  // Zeit für letztes DHCP renew
  dlastnow=millis();
  digitalIpDisplay();
}
// Temperatur auslesen
float getTemperature(byte* address)
{
  int tr;
  byte data[12];
  writeTimeToScratchpad(address);
  readTimeFromScratchpad(address,data);
  tr = data[0];
  if (data[1] > 0x80)
  {
    tr = !tr + 1;
    tr = tr * -1;
  }
  int cpc = data[7];
  int cr = data[6];
  tr = tr >> 1;
  return tr - (float)0.25 + (cpc - cr)/(float)cpc;
}
// Temperatur ins Scratchpad der Sensoren schreiben
void writeTimeToScratchpad(byte* address)
{
   oneWire.reset();
   oneWire.select(address);
   oneWire.write(0x44,1);
   delay(1000);
}
// Temperatur vom Scratchpad der Sensoren lesen
void readTimeFromScratchpad(byte* address, byte* data)
{
  oneWire.reset();
  oneWire.select(address);
  oneWire.write(0xBE);
  for (byte i=0;i<9;i++){
    data[i] = oneWire.read();
  }
}

Der Code in den Dateien der Website:

db.php - stellt die Verbindung zur Datenbank her:

Code:
<?php
define('DB_SERVER',"localhost");
define('DB_NAME',"Datenbankname");
define('DB_USER',"SqlUser");
define('DB_PASSWORD',"Kennwort SqlUser");
$conn = mysql_connect(DB_SERVER, DB_USER, DB_PASSWORD);
if(is_resource($conn))
{
mysql_select_db(DB_NAME, $conn);
mysql_query("SET NAMES 'utf8'", $conn);
mysql_query("SET CHARACTER SET 'utf8'", $conn);
}
?>

getdata.php - wird vom Arduino aufgerufen:

Code:
<?php
define("KEY","Key"); // anpassen an Key im Artduinoscript
include("db.php");
if(isset($_GET['key']))
{
if($_GET['key'] == KEY)
{
if(isset($_GET['AUSSENL']) && isset($_GET['INNENL']) && isset($_GET['WASSER']) && isset($_GET['TURBINE']))
{
$AUSSENL1 = mysql_real_escape_string($_GET['AUSSENL']);
$INNENL1 = mysql_real_escape_string($_GET['INNENL']);
$WASSER1 = mysql_real_escape_string($_GET['WASSER']);
$TURBINE1 = mysql_real_escape_string($_GET['TURBINE']);
$result = mysql_query("INSERT INTO muehle (date, aussenl, innenl,wasser,turbine)
VALUES(now(), '".$AUSSENL1."', '".$INNENL1."', '".$WASSER1."' , '".$TURBINE1."') ") or die(mysql_error());
if(mysql_affected_rows() == 1)
{
$result = "Temperaturwerte gespeichert";
} else $result = "Fehler beim speichern der Daten in der MySQL-Datenbank";
} else $result = "Keine Temperaturwerte übergeben";
} else $result = "Falscher Key";
} else $result = "Kein Key übergeben";
print_r($result);
?>

show_data_tag.php - grafische Anzeige der Tagesdaten (anpassen von Farben etc.):

Code:
<?php
// JPGraph Library einbinden
include ("jpgraph/jpgraph.php");
include ("jpgraph/jpgraph_line.php");
include ("jpgraph/jpgraph_date.php");
include ("jpgraph/jpgraph_plotline.php");

// Datenbank-Zugriff, -Abfrage und Array füllen
mysql_connect("localhost","MySqlUser","Kennwort MySqlUser") or die ("Keine Verbindung moeglich"); //anpassen
mysql_select_db("Datenbankname") or die ("Die Datenbank existiert nicht."); //anpassen

$sql = "SELECT DATE, aussenl,innenl,wasser,turbine FROM muehle WHERE DATE(Date) = CURDATE() ORDER BY DATE;";
$result = mysql_query($sql) OR die(mysql_error());

$i=0;
while ($array=mysql_fetch_array($result)) {
        $datum[$i]= strtotime($array[0]);
        $aussenl[$i]=$array[1];
    $innenl[$i]=$array[2];
    $wasser[$i]=$array[3];
    $turbine[$i]=$array[4];

$i++;
};

// Grafik generieren
$graph = new Graph(800,500,"auto");
$graph->SetScale("datint",20,$aYMax=32);     // y-Achse von 24-28

// Grafik formatieren
$graph->SetMargin(40,40,20,80);                 // Rahmen

$graph->SetShadow();                            // Schatten-Effekt einschalten

// For background to be gradient, setfill is needed first.
$graph->ygrid->SetFill(true,'#FFFFFF@0.5','#FFFFFF@0.5');
$graph->SetBackgroundGradient('#FF3F00', '#007FFF', GRAD_HOR, BGRAD_PLOT);

$graph->title->Set("Temperatur-Überwachung - aktueller Tag");    // Titel der Grafik
$graph->title->SetFont(FF_FONT2,FS_BOLD);

// Untertitel
$graph->subtitle->Set("Temperaturüberwachung mit Arduino");
$graph->subtitle->SetFont(FF_FONT1 ,FS_NORMAL,8);
$graph->subtitle->SetColor("darkred");

// Achsen Formatierung
$graph->xaxis->SetLabelAngle(90);
$graph -> xaxis -> SetLabelFormatString('H:i', true); // d,M / d,m,y / d,m,Y / H:i:s

$graph->yaxis->title->Set("Temperatur in °C");
$graph->yaxis->title->SetFont(FF_FONT1,FS_BOLD);

// Grid Lines
$graph -> xgrid -> Show(true, true);

// Graphen generieren
$lineplot = new LinePlot($aussenl, $datum);
$lineplot2 = new LinePlot($innenl, $datum);
$lineplot3 = new LinePlot($wasser, $datum);
$lineplot4 = new LinePlot($turbine, $datum);
// Graphen in Grafik einbinden
$graph->Add($lineplot);
$graph->Add($lineplot2);
$graph->Add($lineplot3);
$graph->Add($lineplot4);

// 1. Graph
$lineplot->SetColor("red");
$lineplot->SetWeight(1);
// 2. Graph
$lineplot2->SetColor("darkgreen");
$lineplot2->SetWeight(1);
// 3. Graph
$lineplot3->SetColor("darkblue");
$lineplot3->SetWeight(1);
// 4. Graph
$lineplot4->SetColor("coral4");
$lineplot4->SetWeight(1);

// Legende generieren
$lineplot->SetLegend('Temperatur AL');
$lineplot2->SetLegend('Temperatur IL');
$lineplot3->SetLegend('Temperatur WA');
$lineplot4->SetLegend('Temperatur TU');

$graph -> legend -> SetFont(FF_FONT1 ,FS_BOLD);
$graph->legend->Pos(0.5,0.97,"center","center");

// Grafik anzeigen
$graph->Stroke();
?>

Für die Wochen- und Monatsansicht müssen nur die Beschriftungen und das SELECT-Statement angepasst werden

Woche - Show_data_week.php :

Code:
$sql = "SELECT DATE, aussenl,innenl,wasser,turbine FROM muehle WHERE Week(DATE(Date),3)=WEEK(NOW(),3) ORDER BY DATE;";

Monat - Show_data_month.php :

Code:
$sql = "SELECT DATE, aussenl,innenl,wasser,turbine FROM muehle WHERE month(DATE(Date)) = month(NOW()) ORDER BY DATE;";

Index.html - Anzeige der Grafiken:

Code:
<img src="show_data_tag.php" alt="Diagramm wird geladen..." align="middle" width="800" height="600">
<img src="show_data_woche.php" alt="Diagramm wird geladen..." align="middle" width="800" height="600">
<img src="show_data_monat.php" alt="Diagramm wird geladen..." align="middle" width="800" height="600">

Hier noch das SQL-Statement zum anlegen der Datentabelle:

Code:
CREATE TABLE IF NOT EXISTS `tabellenname` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT,
  `date` datetime NOT NULL,
  `aussenl` float(5,2) NOT NULL,
  `innenl` float(5,2) NOT NULL,
  `wasser` float(5,2) NOT NULL,
  `turbine` float(5,2) NOT NULL,
  `zimmer1` float(5,2) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_german2_ci AUTO_INCREMENT=1 ;

Alle Dateien der Webseite liegen im Verzeichnis das in der URL-Variable im Arduino-Script angegeben ist.
Jpgraph kann man hier runterladen: http://jpgraph.net/ und legt man unverändert im Unterverzeichnis "jpgraph" in dem URL-Verzeichnis ab.

Hoffe dass es was nutzbringendes für die Allgemeinheit ist und der/die eine oder andere was davon gebrauchen kann.

Grüße Ricardo
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
Antwort schreiben 


Möglicherweise verwandte Themen...
Thema: Verfasser Antworten: Ansichten: Letzter Beitrag
  Arduino UNO + EthernetShield (Webserver mit E-Mail) m0nn3 0 991 21.12.2015 18:35
Letzter Beitrag: m0nn3
Sad Temperatur u. feuchtigkeit Webserver+speichern der Temp. u. Feuchti. auf sd Porblem!! TbO92 0 1.882 27.10.2014 10:14
Letzter Beitrag: TbO92
  Arduino Webserver mit Sensoren Mi Kat 10 8.521 20.08.2014 14:14
Letzter Beitrag: RMR
  WebServer mit Ethernet Shield--->Fehler im Programm Wampo 0 2.018 22.08.2013 13:13
Letzter Beitrag: Wampo

Gehe zu:


Benutzer, die gerade dieses Thema anschauen: 1 Gast/Gäste