Arduino mit Netzwerkanschluss erweitern

Wie kann ich einem Microcontroller mit einem Netzwerkanschluss erweitern. Was muss getan werden, um dann dort Werte abzurufen oder besser, wie kann dieser Daten in eine entfernte Datenbank schreiben.
Bei den in dem Video gezeigten Beispielen, wird näher gebracht, wie ein Arduino mit Temperatursensor, einen LAN Anschluss erhält.
Dieser Microcontroller wird im ersten Teil als Mini-Webserver konfiguriert und die Werte sind dann im Browser eines jeden Rechners im Netzwerk abrufbar.
Der zweite Teil wird zeigen, wie aber auch der Arduino eine entfernte Datenbank mit den Temperaturwerten füttern kann, um später damit zum Beispiel eine grafische Auswertung zu erstellen.

Verwendete Hardware:
Arduino Uno
LAN Adapter ENC28J60
Temperatursensor DHT22

Verdrahtung:


Quellcode und Bibliothek:
github.com/njh/EtherCard

Datenblatt:
ENC28J60_Netzwerkmodul_Datenblatt.pdf

Quellcode Teil 1
Werte können auf dem Arduino per Browser abgerufen werden:

// Werte können auf dem Arduino per Browser abgerufen werden

// Quelle: https://github.com/njh/EtherCard (backsoon)
// Modifiziert : https://prilchen.de
// NIC: ENC28J60 mit 10x Pin
// VCC  3.3V  
// GND GND 
// SCK Pin 13  
// MISO  Pin 12  
// MOSI  Pin 11  
// CS  Pin 10  Selectable with the ether.begin() function
//
// DHT22: 
// Daten PIN 5

#include <EtherCard.h>
#include "DHT.h"

static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 }; // ethernet mac address - must be unique on your network

byte Ethernet::buffer[500]; // tcp/ip send and receive buffer

#define DHTTYPE DHT22
#define DHTPIN 5 // Sensor DHT22 an PIN 5 
DHT dht(DHTPIN, DHTTYPE);
String temp, luftf;

void setup(){
  Serial.begin(57600);
  Serial.println("\n[MiniWebserver]");

  if (ether.begin(sizeof Ethernet::buffer, mymac, 10) == 0) // ENC28J60 Pin "CS" an PIN 10
    Serial.println( "Failed to access Ethernet controller");
#if STATIC
  ether.staticSetup(myip, gwip);
#else
  if (!ether.dhcpSetup())
    Serial.println("DHCP failed");
#endif

  ether.printIp("IP:  ", ether.myip);
  ether.printIp("GW:  ", ether.gwip);
  ether.printIp("DNS: ", ether.dnsip);

  dht.begin();
  leseDHT22Sensor();
}

void leseDHT22Sensor() {

  Serial.print("Temperatur: ");
  Serial.print(dht.readTemperature(), 1); //Gibt Temperatur im Seriellen monitor aus
  Serial.println("C");
  Serial.print("Luftfeuchtigkeit: ");
  Serial.print(dht.readHumidity(), 1);  // Ausgabe Luftfeuchtigkeit 
  Serial.println("%");
}

void loop(){
  // wartet auf Startzeichen - erstes eingehendes TCP Packet, ohne dieses auszulesen  
  if (ether.packetLoop(ether.packetReceive())) {
    String page = "";
    page += "HTTP/1.0 200 OK\r\n";
    page += "Content-Type: text/html\r\n";
    page += "\r\n";
    page += "<html>";
    page += "<head><title>DHT22 Sensordaten</title></head><body>";
    page += "<span>Hier im Raum ist die Temperatur: " + String(dht.readTemperature(), 2) + "°C Grad warm</span><br/>";
    page += "<span>und die relative Luftfeuchtigkeit liegt bei: " + String(dht.readHumidity(), 2) + "%</span>";
    page += "</body></html>";
    int lengthOfContent = 231; //Zeichenlänge abgrenzen, damit keine Steuerzeichen auf der Webseite erscheinen
    char pageCopy[lengthOfContent];
    page.toCharArray(pageCopy, lengthOfContent);
    memcpy(ether.tcpOffset(), pageCopy, lengthOfContent);
    ether.httpServerReply(lengthOfContent);
  }
}

Teil 2
Arduino sendet Werte über LAN an WEB-Datenbank:

WEB-Server erstellen:
XAMPP PHP-Entwicklungsumgebung

Arduino – Quellcode:

// Arduino sendet Werte über LAN an WEB-Datenbank

// Quelle: https://github.com/njh/EtherCard (backsoon)
// Modifiziert : https://prilchen.de
// NIC: ENC28J60 mit 10x Pin
// VCC  3.3V  
// GND GND 
// SCK Pin 13  
// MISO  Pin 12  
// MOSI  Pin 11  
// CS  Pin 10  Selectable with the ether.begin() function
//
// DHT22: 
// Daten PIN 5

#include <EtherCard.h>
#include "DHT.h"

// ethernet interface mac address, must be unique on the LAN
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };

byte Ethernet::buffer[700];
#define DHTTYPE DHT22
#define DHTPIN 5 // Sensor DHT22 an PIN 5 
DHT dht(DHTPIN, DHTTYPE);
String temp, luftf;
static uint32_t timer;

const char website[] PROGMEM = "xamppserver.fritz.box";// client mit Xampp Server

// called when the client request is complete
static void my_callback (byte status, word off, word len) {
  Serial.println(">>>");
  Ethernet::buffer[off+300] = 0;
  Serial.print((const char*) Ethernet::buffer + off);
  Serial.println("...");
}

void setup () {
  Serial.begin(57600);
  Serial.println(F("\n[arduinosendetdaten]"));

  // Change 'SS' to your Slave Select pin, if you arn't using the default pin
  if (ether.begin(sizeof Ethernet::buffer, mymac, SS) == 0)
    Serial.println(F("Failed to access Ethernet controller"));
  if (!ether.dhcpSetup())
    Serial.println(F("DHCP failed"));

  ether.printIp("IP:  ", ether.myip);
  ether.printIp("GW:  ", ether.gwip);
  ether.printIp("DNS: ", ether.dnsip);

#if 1
  // use DNS to resolve the website's IP address
  if (!ether.dnsLookup(website))
    Serial.println("DNS failed");
#elif 2
  // if website is a string containing an IP address instead of a domain name,
  // then use it directly. Note: the string can not be in PROGMEM.
  char websiteIP[] = "10.10.20.67";
  ether.parseIp(ether.hisip, websiteIP);
#else
  // or provide a numeric IP address instead of a string
  byte hisip[] = { 10,10,20,67 };
  ether.copyIp(ether.hisip, hisip);
#endif

  ether.printIp("SRV: ", ether.hisip);

  dht.begin();
  leseDHT22Sensor();
}

void leseDHT22Sensor() {

  Serial.print("Temperatur: ");
  Serial.print(dht.readTemperature(), 1); //Gibt Temperatur im Seriellen monitor aus
  Serial.println("C");
  Serial.print("Luftfeuchtigkeit: ");
  Serial.print(dht.readHumidity(), 1);  // Ausgabe Luftfeuchtigkeit 
  Serial.println("%");
  temp = dht.readTemperature();
  luftf = dht.readHumidity();
}
void loop () {
  ether.packetLoop(ether.packetReceive());

  String web1 = "value1=";
  String web2 = "&value2=";
  String webg = "";
  
  webg = web1 + temp +web2 + luftf;
  
  char charBuf[100];
  webg.toCharArray(charBuf, 100); 
  
  if (millis() > timer) {
    timer = millis() + 300000; //alle 5Minuten =300000
    Serial.println();
    Serial.print("<<< REQ ");
    ether.browseUrl(PSTR("/annahme.php?"), charBuf, website, my_callback);
  }


}

Code Annahme.php unter XAMPP/htdocs ablegen:

<?php

$servername = "127.0.0.1";
$username = "root";
$password = '';
$dbname = "test";
$dbtable = "tempdaten";

// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection

if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
} 
// Check connection
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
} 


if ($_GET["value1"]){
	echo "<h3>New Data</h3>";
	echo 'Value1: ' .htmlspecialchars($_GET["value1"]).' Value2: '.htmlspecialchars($_GET["value2"]).'</br>';
	$sql = "INSERT INTO `".$dbtable."` (temp, luftf) VALUES ('".$_GET["value1"]."','".$_GET["value2"]."')";
	
	if ($conn->query($sql) === TRUE) {
	    echo "New record created successfully";
	} else {
	    echo "Error: " . $sql . "<br>" . $conn->error;
	}
	
    echo "0 results";
}

SQL Datenbank mit Tabelle

Wer lieber die Datenbank mit Tabelle per Import erzeugen möchte,
diese 4 Schritte unter phpmyadmin ausführen

SQL Import Datei:

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
START TRANSACTION;
SET time_zone = "+00:00";

CREATE TABLE `tempdaten` (
  `id` int(11) NOT NULL,
  `temp` float NOT NULL,
  `luftf` float NOT NULL,
  `Zeitstempel` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


ALTER TABLE `tempdaten`
  ADD PRIMARY KEY (`id`);

ALTER TABLE `tempdaten`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=443;
COMMIT;

Weitere Möglichkeit (Nicht im Video zu sehen)
Arduino mit ENC28J60 empfängt Anweisung per Browser

Wir erweitern die Schaltung um ein Gerät was ein oder ausgeschaltet werden soll.
Zum Beispiel eine weiße LED Anode an Pin 9 und Kathode an GND
(bei den anderen Farben an den Vorwiderstand denken –> Liste)

Übertrage diesen Code (für Netzwerk das per DHCP IP-Adressen vergibt) auf den Microcontroller:

// Arduino empfängt Anweisung per Browser
// für Netzwerk das per DHCP IP-Adressen vergibt

// NIC: ENC28J60 mit 10x Pin
// VCC  3.3V  
// GND GND 
// SCK Pin 13  
// MISO  Pin 12  
// MOSI  Pin 11  
// CS  Pin 10  Selectable with the ether.begin() function
//
// LED, Schalter, Motor an PIN 9

#include <EtherCard.h>
#define STATIC 0 
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
int ledpin = 9;
byte Ethernet::buffer[700];
 
char const page[] PROGMEM =
"HTTP/1.0 200 Service OK\r\n"
"Content-Type: text/html\r\n"
"Retry-After: 600\r\n"
"\r\n"
"<html>"
"<head><title>"
"Arduino wartet auf Kommando"
"</title></head>"
"<body>"
"<h3>Schau lieber zu deinem Arduino</h3>"
"<p><em>"
"Diese zwei Befehle werden die LED an den Arduino ein oder aus schalten<br /><br />"
"Anschalten: http://deineIP-Adresse/?LED=AN<br />"
"Ausschalten: http://deineIP-Adresse/?LED=AUS"
"</em></p>"
"</body>"
"</html>"
;
 
void setup () {
pinMode(ledpin, OUTPUT);
 
Serial.begin(9600);
Serial.println("Versuch eine IP-Adresse zu erhalten");
 
Serial.print("MAC: ");
for (byte i = 0; i < 6; ++i) {
Serial.print(mymac[i], HEX);
if (i < 5)
Serial.print(":");
}
Serial.println();
 
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
{
Serial.println( "Zugriff auf Ethernet-Controller fehlgeschlagen");
}
else
{
Serial.println("Ethernet-Controller Zugriff: OK");
}
;

Serial.println("Werte von DHCP");
if (!ether.dhcpSetup()){
Serial.println( "DHCP Problem");
blinkLed(); // blinkt wenn DHCP Problem
}
 
ether.printIp("Meine IP: ", ether.myip);
ether.printIp("Subnetmaske: ", ether.netmask);
ether.printIp("Gateway IP: ", ether.gwip);
ether.printIp("DNS IP: ", ether.dnsip);
}
 
void loop () {
word len = ether.packetReceive();
word pos = ether.packetLoop(len);
 
if(strstr((char *)Ethernet::buffer + pos, "GET /?LED=AN") != 0) {
Serial.println("Kommando für AN wurde gesendet");
digitalWrite(ledpin, HIGH);
}
 
if(strstr((char *)Ethernet::buffer + pos, "GET /?LED=AUS") != 0) {
Serial.println("Kommando für AUS wurde gesendet");
digitalWrite(ledpin, LOW);
}
 
// show some data to the user
memcpy_P(ether.tcpOffset(), page, sizeof page);
ether.httpServerReply(sizeof page -1);
}
 
void blinkLed(){
while (true){
digitalWrite(ledpin, HIGH);
delay(500);
digitalWrite(ledpin, LOW);
delay(500);
}
}

Nach dem Hochladen, sollte im Seriellen Monitor folgendes zu sehen sein:

Serieller Monitor

Jetzt kann von einem entfernten Smartphone, Tablett oder PC im lokalen Netzwerk per Browser diese zu sehende IP-Adresse aufgerufen werden.
Erweitert man nun hinter dieser IP-Adresse, die vorgegebene Kommandozeile,
http://IP-Adresse/?LED=AN
dann schaltet der Arduino den Verbraucher an oder auch wieder aus.
It´s Magic 🙂

,