Pagina 1 van 1

Arduino Ethernet – Data van de Arduino ophalen (Pull)

Arduino Ethernet – Data van de Arduino ophalen (Pull)
   2

De Arduino is beslist leuk spul om mee te prullen, zeker als je zaken zoals de Arduino ENC28J60 Ethernet shield/module toevoegt.

Nu is het “Hello World!” voorbeeld best leuk, maar nou niet echt zinvol, vooral als je weet dat er voor de Arduino allerlei sensoren bestaan (zoals de DS18B20 temperatuur sensor) en we de data toegankelijk willen maken over het netwerk. Daarbij natuurlijk de vraag … hoe krijgen we de data over het netwerk gestuurd? Op basis van het “Hello World!” voorbeeld kunnen we de data natuurlijk in een browser bekijken, of een applicatie bouwen die regelmatig de data ophaalt van de Arduino.

In dit artikel gaan we kijken naar een eenvoudig voorbeeld voor het ophalen van data, of te wel “Data Pull”. De applicatie die deze data ophaalt kan jouw web-browser zijn, of een programma dat je zelf schrijft.




Arduino en een ENC28J60 Ethernet Shield

In dit artikel gebruiken we een Arduino ENC28J60 Ethernet shield, zoals besproken in het “Hoe web-enable je een Arduino“, welke we zullen combineren met èèn of meer DS18B20 digitale temperatuur sensoren (je kunt natuurlijk ook andere sensoren gebruiken). Het doel: Data LEZEN van de Arduino over het netwerk.

  We gebruiken hier precies dezelfde opstelling als in ons Data Push artikel!

Hiervoor gebruiken we de “UIPEthernet” Library die je van Github kun downloaden of van Tweaking4All. Zoals gebruikelijk het advies om de Github versie te gebruiken aangezien deze meer recent kan zijn dan de versie op Tweaking4All.

DOWNLOAD - Arduino Uip 

Bestand: arduino_uip.zip
Versie: 1.01
Omvang: 99.6 KiB
Datum: 23 mrt 2014
 Download Nu 

 

Omdat we in ons voorbeeld de DS18B20 sensoren gaan gebruiken, hebben we ook de “OneWire” library nodig, welke te vinden is op de OneWire Project Website (aanbevolen) of natuurlijk van Tweaking4All.

DOWNLOAD - OneWire 

Bestand: OneWire.zip
Versie: 2.2
Omvang: 14.7 KiB
Datum: 19 mrt 2014
 Download Nu 

Gebruik maken van de standard Arduino Ethernet Shield

Omdat “UIPEthernet” volledig compatible met de standaard “Ethernet” library is die bij de Arduino IDE zit, zou je de voorbeelden op deze pagina ook voor de Standaard Arduino Ethernet Shield (W5100 gebaseerd) kunnen gebruiken. Om dit te doen, vervang de include regel (#include <UIPEthernet.h> ) met deze twee regels:


1
2
#include <SPI.h>
#include <Ethernet.h>
Aansluiten van het Ethernet Shield

Aansluiten van het Ethernet shield is eenvoudig, voor meer details zie ook het “Hoe web-enable je een Arduino” artikel.

Een Ethernet module gebruikt altijd GND (aarde) en +3.3V of +5V, omdat we stroom nodig hebben.

 Voor mijn eBay module moest ik +5V gebruiken (het heeft een voltage regulator aan boord).

Hieronder een tabel voor Arduino Uno, Arduino Nano en de module die ik op eBay had gekocht, met de pin aansluitingen die we nodig hebben.

ENC28J60 Pins
Pin naam UIPEthernet Mijn eBay Module
 SS  10  10
 MOSI (SI)  11  11
 MISO (SO)  12  12
 SCK  13  13
Mijn ENC28J60 test opstelling

Mijn ENC28J60 test opstelling

Aansluiten van de Temperatuur sensor

De temperatuur sensor is ook eenvoudig aan te sluiten, en we gebruiken pin 2 als de data pin voor onze sensor(en). In mijn opstelling heb ik er 2 gebruikt, maar dit werkt ongewijzigd ook voor slechts èèn of meerdere sensoren.

Lees het artikel “Hoe temperaturen meten met een Arduino en een DS18B20” voor meer details.

Arduino, ENC28J60 en 2x DS18B20 test opstelling

Arduino, ENC28J60 en 2x DS18B20 test opstelling

Alle aansluitingen gecombineerd

Afhankelijk van het Arduino board en ENC28J60 Ethernet shield model dat je gebruikt, zouden de aansluitingen er als volgt uit kunnen zien. Bedenk dat ik hierbij een “Deek Robot – Nano Ethernet Shield” (van eBay) en een Arduino Uno heb gebruikt. De meegeleverde Arduino Nano is hierbij niet gebruikt en voor de pinnen D10 … D13 op de ethernet shield kun je bovenstaande tabel volgen.

Arduino, ENC28J60 en DS18B20 diagram

Arduino, ENC28J60 en DS18B20 diagram

Hoe gaan we de Data ophalen?

In dit voorbeeld gebruiken we dus de temperatuur sensor van het DS18B20 artikel en willen we de temperatuur waarneming van de sensor(en) in onze computer inlezen via het computer netwerk. Als ik zeg “computer” denk dan ook aan b.v. een  smartphone of tablet, zolang ze maar in hetzelfde netwerk zitten.

Data Pull of Push

We hebben bij het uitwisselen van data twee opties, en de beste optie hangt af van jouw toepassing:
– Pull: Een applicatie op onze computer (of server) bepaalt wanneer data van de Arduino opgehaald gaat worden.
– Push: De Arduino bepaalt wanneer data naar onze computer (of server) gestuurd wordt.

  In dit artikel kijken we naar DATA PULL van de Arduino, door onze computer.

Dit is de eerste aanpak die ik probeerde vanwege zijn eenvoud. We hebben aan de computer kan alleen maar een web-browser nodig (die je later door jouw eigen programma kunt vervangen). In principe wordt de data opgehaald van de Arduino alsof het een “web pagina” is. De computer bepaalt dus wanneer we data gaan ophalen.

In dit voorbeeld heb ik gekozen voor het XML formaat voor de data, maar is absoluut niets mis met andere formaten zoals CSV (Comma Separated Values), HTML, of jouw eiegn formaat. Uiteindelijk is het jouw programma die straks de data gaat ophalen en dus aan jouw om te bepalen welke formaat het meest geschikt is.

Als je naar het “Hello World!” voorbeeld kijkt die we voor “UIPEthernet” hadden gebruikt (zie “Hoe web-enable je een Arduino“), dan zie je in de loop dat we eigenlijk steeds wachten op een verbinding (regel 23). Als een verbinding wordt gevonden en blijft bestaan (regel 23 en regel 30), dan sturen we data (regel 41) naar de computer die de verbinding maakt en vervolgens sluiten we de verbinding (regel 61).

Makkelijk, niet dan? We gaan nu dit voorbeeld gebruiken en regel 41 vervangen met onze data.

Lezen van de DS18B20 Temperatuur Sensor(en)

In dit deel had ik UIPEthernet echt nodig omdat het de print functie volledig ondersteund en op dezelfde manier werkt als de Serial.print  of Serial.println functie.

Mijn voorbeeld code mag dan wel niet de meest efficiente of beste code zijn die je zou kunnen schrijven: werken doet het wel! Ik heb het getest met 1 en 2 temperatuur sensoren (ik had er maar 2).

De functie “TemperaturesToXML“, in onderstaan de Sketch, bevat in principe alles wat we gebruikt hebben in de Sketch van het DS18B20 Temperatuur Sensor artikel waarbij we pin 2 voor de data van de temperatuur sensoren gebruiken. Voor wie dat artikel werkelijk gelezen heeft: nu weet je wat ik bedoel met “andere plannen voor pin 10”.

De rest van de code is een aangepaste versie van het Ethernet “Hello World!” voorbeeld.

Je kunt de Sketch kopiëren en plakken of je kunt het .ino bestand downloaden.

DOWNLOAD - T4A TemperatureDrone 

Bestand: T4A_TemperatureDrone.ino
Versie: 1.0
Omvang: 6.2 KiB
Datum: 23 mrt 2014
 Download Nu 

Nog een paar opmerkingen voor het gebruik van de client.print  en client.println functies (dito voor Serial.print  varianten):

  • Vermijd combineren van verschillende data typen – het kan onverwachte resultaten leveren.
  • Je kunt “\n” in een string gebruiken om een nieuwe regel te starten.
  • Lees de Arduino Referentie voor “Serial.print” voor meer trucs en tips.

 

Output Voorbeelden

In mijn test opstelling heb ik twee sensoren gebruikt en de output in mijn web-browser bekeken. Je kunt de output in jouw web-browser bekijken door het adres als volgt in te voeren in het adres van van jouw browser: http://192.168.1.179 (natuurlijk wel het IP adres gebruiken dat je in de Sketch hebt gebruikt).

Voorbeeld output in een web-browser:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version='1.0'?>
<sensordata>
<sensor>
  <serial>28 88 84 82 05 00 00 6a </serial>
  <status>OK</status>
  <chip>DS18B20</chip>
  <celsius>20.44</celsius>
  <fahrenheit>68.79</fahrenheit>
</sensor>
<sensor>
  <serial>28 da ca 27 05 00 00 49 </serial>
  <status>OK</status>
  <chip>DS18B20</chip>
  <celsius>20.31</celsius>
  <fahrenheit>68.56</fahrenheit>
</sensor>
</sensordata>

 

Ik heb in de Sketch ook output naar de “Serial Monitor” gestuurd van de Arduino IDE en dat ziet er ongeveer zo uit:


Tweaking4All.com - Temperature Drone - v1.0
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

IP Address: 192.168.1.179

-> New Connection

   Collecting Sensor Data:

   Sensor     : 28 88 84 82 05 00 00 6a
   Temperature: 20.44 C  (68.79 F)

   Sensor     : 28 da ca 27 05 00 00 49
   Temperature: 20.31 C  (68.56 F)

   Done Collecting Sensor Data
   Disconnected

 

Even door de code lopen …

Basis voor we starten:

Regel 1 en 2 zijn de twee Library includes die we nodig hebben voor de Arduino ENC28J60 Ethernet module, en de DS18B20 1-wire temperatuur sensor(en).
In regel lines 5 – 11 stellen we IP en MAC adres in en definiëren we define poort 80 voor data requests (HTTP).
Regel 13 maakt een globale variabele aan die onze Ethernet Client verbinding vast houdt, zodat we met de client kunnen praten.
Voor de sensoren definiëren we pin 2 als de data pin, in regel 19.

Setup()

In de “setup()” functie openen we de seriële poort voor debug data die we met de “Serial Monitor” van de Arduino IDE kunnen bekijken (menu “Tools”  Serial Monitor” en vergeet net te controleren dat de snelheid op “9600 baud” staat). Het lijkt erop dat Arduino Leonardo gebruikers een stukje code moeten toevoegen na regel 25 om te wachten op de seriële poort – maar ik heb geen Leonardo dus ik kan dat niet bevestigen (zoiets als while (!Serial) { } ). In regel 28 starten we dan de Ethernet shield met gegeven IP en MAC adres en een eerste teken van leven wordt door de seriële poort gestuurd.

  Alle regels met “Serial.begin”, “Serial.print” en “Serial.println” mogen verwijderd worden als je geen seriële output nodig hebt.

Loop()

De “loop()” functie is waar we op een verbinding gaan wachten. Als een verbinding opgezet is, gaan we vervolgens de sensoren uitlezen, de data naar de client sturen en uiteindelijk verbreken we de verbinding. Zoals Arduino gebruikelijk blijft deze loop oneindig rond gaan zolang de Arduino stroom heeft.

TemperatureToXML()

Zoals eerder gezegd, de functie “TemperaturesToXML()” is in principe de code die we voor onze DS18B20 temperatuur sensor demo hebben gebruikt. Ik heb het wat opgeruimd en aangepast zodat het niet alleen seriële data uitstuurt maar ook data over de netwerkverbinding stuurt. Voor meer details zie ook het DS18B20 artikel.

Demo Sketch

Hieronder vindt je de besproken demo code (download link zie eerder vermelde link) – zodra de Arduino draait, open een web-browser op jouw computer en voer het volgende in (IP adres aanpassen indien nodig): http://192.168.1.79

Na een seconde of zo zie je de output in jouw browser verschijnen.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
#include <UIPEthernet.h> // Gebruikt voor Ethernet
#include <OneWire.h>     // Gebruikt voor de temperatuur sensor(en)

// **** ETHERNET SETTING ****
// Ethernet MAC adres - moet uniek zijn in jouw netwerk
byte mac[] = { 0x54, 0x34, 0x41, 0x30, 0x30, 0x31 };                                      
// ethernet interface IP adres (moet ook uniek zijn in jouw netwerk)
IPAddress ip(192, 168, 1, 179);                        
// ethernet interface IP poort (80 = http)
EthernetServer server(80);

EthernetClient client;

// **** TEMPERATUUR INSTELLINGEN ****
// Sensor(en) data pin worden met Arduino pin 2 verbonden in non-parasite mode!
OneWire  ds(2);

void setup() {
  // Open serieel poort:
  Serial.begin(9600);

  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();

  Serial.println("Tweaking4All.com - Temperature Drone - v1.0");
  Serial.println("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
  Serial.print("IP Adres: ");
  Serial.println(Ethernet.localIP());
  Serial.println();
}

void loop() {
  // listen for incoming clients
  client = server.available();

  if (client)
  {  
    Serial.println("-> Nieuwe verbinding\n");

    // http requests starten met een lege regel
    boolean currentLineIsBlank = true;

    while (client.connected())
    {
      if (client.available()) {
        char c = client.read();

        // einde regel bereikt en de regel was leeg?
        // dan is de http request klaar,
        // stuur nu de data
        if (c == '\n' && currentLineIsBlank)
        {
          client.println("<?xml version='1.0'?>\n<sensordata>");
          Serial.println("   Ophalen Sensor Data:");
          TemperaturesToXML();
          client.println("</sensordata>");
          Serial.println("\n   Klaar met ophalen Sensor Data");
          break;
        }

        if (c == '\n') {
          // we beginnen weer met een lege regel
          currentLineIsBlank = true;
        }
        else if (c != '\r') {
          // je hebt een character ontvangen, dus niet een lege regel
          currentLineIsBlank = false;
        }
      }
    }

    // geef web browser tijd om de data te ontvangen
    delay(10);

    // sluit de verbinding:
    client.stop();
    Serial.println("   Einde verbinding\n");
  }
}

void TemperaturesToXML(void) {
  byte counter;
  byte present = 0;
  byte sensor_type;
  byte data[12];
  byte addr[8];
  float celsius, fahrenheit;

  ds.reset_search();

  while ( ds.search(addr)) {
    client.println("<sensor>");

    // Ophalen Serial nummer
    client.print("  <serial>");
    Serial.print("\n   Sensor     : ");

    for( counter = 0; counter < 8; counter++)
    {
      if (addr[counter]<0x10) client.print("0");
      client.print(String(addr[counter], HEX));
      client.print(" ");

      if (addr[counter]<0x10) Serial.print("0");
      Serial.print(String(addr[counter], HEX));
      Serial.print(" ");
    }
    Serial.println();

    client.println("</serial>");

    // Check CRC
    if (OneWire::crc8(addr, 7) != addr[7])
    {
        client.println("  <status>Invalid CRC</status>\n</sensor>");
        Serial.println("   ERROR\n");
        return;
    }

    client.println("  <status>OK</status>");

    // Ophalen Chip type (de eerste ROM byte geven chip model aan)
    client.print("  <chip>");

    switch (addr[0])
    {
      case 0x10:
        client.println("DS18S20</chip>");
        sensor_type = 1;
        break;
      case 0x28:
        client.println("DS18B20</chip>");
        sensor_type = 0;
        break;
      case 0x22:
        client.println("DS1822</chip>");
        sensor_type = 0;
        break;
      default:
        client.println("onbekend</chip>");
        return;
    }

    ds.reset();
    ds.select(addr);
    ds.write(0x44);  // start conversie, met normale (non-parasite!) voeding

    delay(1000);     // misschien is 750ms, misschien ook niet

    present = ds.reset();
    ds.select(addr);    
    ds.write(0xBE);  // Read Scratchpad

    // Get Raw Temp Data, we need 9 bytes
    for ( counter = 0; counter < 9; counter++)
    {          
      data[counter] = ds.read();
    }

    // Converteer data naar temperatuur
    // Dit is een 16 bit signed integer, dus opslaan
    // in een "int16_t" type
    int16_t raw = (data[1] << 8) | data[0];

    if (sensor_type)
    {
      raw = raw << 3; // 9 bit resolution default
      if (data[7] == 0x10) {
        // "count remain" gives full 12 bit resolution
        raw = (raw & 0xFFF0) + 12 - data[6];
      }
    }
    else
    {
      // at lower res, the low bits are undefined, so let's zero them
      byte cfg = (data[4] & 0x60);

      //// default is 12 bit resolution, 750 ms conversion time
      if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
      else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
      else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
    }

    celsius = (float)raw / 16.0;
    fahrenheit = celsius * 1.8 + 32.0;

    client.print("  <celsius>");
    client.print(celsius);
    client.print("</celsius>\n  <fahrenheit>");
    client.print(fahrenheit);
    client.println("</fahrenheit>");

    Serial.print("   Temperature: ");
    Serial.print(celsius);
    Serial.print(" C  (");
    Serial.print(fahrenheit);
    Serial.println(" F)");

    client.println("</sensor>");
  }

  return;
}

Donatie Opties


Donaties worden zeer gewaardeerd, maar zijn zeker niet vereist. Donaties worden gebruikt voor het dekken van kosten voor web-hosting en project materialen, en eventueel voor een drankje of een snack. Voor wie al gedoneerd heeft: Hartelijk dank! Het is werkelijk geweldig om te zien dat men onze artikelen en applicaties waardeert.

Reacties


Er zijn 2 reacties welke je hieronder kunt lezen.
Je kunt jouw eigen opmerkingen plaatsen m.b.v. dit formulier, of een reactie op een opmerking plaatsen door op de "Reageer" knop te klikken.

  • 4 jul 2014 - 18:32 Reactie Link
    PingBack: www.tweaking4all.nl

    […] een voorgaand artikel beschreef ik hoe je m.b.v. “Data Pull” Arduino sensor data kon lezen via een […]

  • 27 mrt 2016 - 13:18 - hans - Auteur: Reactie Link

    UPDATE:

    Bug in de code (bij het toevoegen van een “0” by ieder adres nummer gebruikte ik <10, maar dit moet <0x10 zijn) en XML output een beetje opgeruimd (</chip> staat nu op dezelfde regel als <chip>).

    Beantwoorden

    hans



Jouw Reactie ...

Vriendelijk verzoek om hier geen lange teksten te plaatsen (zoals source codes, log files of config files). Gebruik daarvoor het Forum.

Deel met anderen:
*
*
Houd me op de hoogte van nieuwe reacties (email).
       Gebruik jouw RSS reader om reacties te volgen.


Tweaking4All gebruikt de gratis Gravatar dienst voor Avatars.
Tweaking4All zal nooit jouw email adres met anderen delen.