2012-09-12 20:02:09 +00:00
|
|
|
/*
|
|
|
|
Copyright (C) 2012 Nathanaël Restori
|
|
|
|
|
2012-09-17 17:43:24 +00:00
|
|
|
Permission is hereby granted, free of charge, to any person
|
|
|
|
obtaining a copy of this software and associated documentation
|
|
|
|
files (the "Software"), to deal in the Software without
|
|
|
|
restriction, including without limitation the rights to use, copy,
|
|
|
|
modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
|
|
of the Software, and to permit persons to whom the Software is
|
|
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be
|
|
|
|
included in all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
|
|
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
|
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
SOFTWARE.
|
2012-09-12 20:02:09 +00:00
|
|
|
|
|
|
|
*/
|
|
|
|
|
2012-09-05 18:01:37 +00:00
|
|
|
#include <Wire.h>
|
|
|
|
#include <SPI.h>
|
|
|
|
#include <Ethernet.h>
|
|
|
|
#include "BMP085.h"
|
2012-09-12 19:29:43 +00:00
|
|
|
#include "Chronodot.h"
|
2012-09-05 18:01:37 +00:00
|
|
|
#include "DHT.h"
|
|
|
|
#include "TSL2561.h"
|
2012-09-12 19:29:43 +00:00
|
|
|
#include "WebServer.h"
|
2012-09-05 18:01:37 +00:00
|
|
|
|
2012-09-12 19:29:43 +00:00
|
|
|
#define TIMEZONE 7200 // 2 hours
|
|
|
|
#define DHTPIN 2
|
|
|
|
#define DHTTYPE DHT22
|
|
|
|
#define PREFIX ""
|
2012-09-05 18:01:37 +00:00
|
|
|
#define NTP_PACKET_SIZE 48
|
|
|
|
|
|
|
|
static uint8_t mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
|
|
|
|
static IPAddress ip = IPAddress(192, 168, 1, 210);
|
|
|
|
static IPAddress timeserver = IPAddress(192, 43, 244, 18);
|
|
|
|
|
2012-09-17 17:43:24 +00:00
|
|
|
P(indexHtml) = "<!DOCTYPE html><html><head><meta charset='utf-8'/\
|
|
|
|
><title>Station Météo</title><style>html, body{ba\
|
|
|
|
ckground: #000;color: #fff;}body{font-family: 'De\
|
|
|
|
jaVu Sans', Verdana, Arial, sans-serif;font-size:\
|
|
|
|
100%;margin: 0;padding: 0;}#home{background: #00\
|
|
|
|
0;color: #fff;margin: 1em;padding: 0;}#home h1{co\
|
|
|
|
lor: #f7c000;font-size: 2em;margin: 1em;text-alig\
|
|
|
|
n: center;}#home p{background: #111;border: 1px s\
|
|
|
|
olid #444;font-size: 1.5em;list-style-type: none;\
|
|
|
|
padding: 0;width: 100%;text-align: center;}#home \
|
|
|
|
table{background: #111;border: 1px solid #444;fon\
|
|
|
|
t-size: 1.5em;list-style-type: none;padding: 0;wi\
|
|
|
|
dth: 100%;text-align: center;}#footer{background:\
|
|
|
|
#000;color: #888;font-size: 0.8em;margin: 1em;te\
|
|
|
|
xt-align: center;padding: 0;}</style></head><body\
|
|
|
|
><div id='home'><h1>Station Météo</h1><table><tr>\
|
|
|
|
<th>Temps</th><th>T [°C]</th><th>P [Pa]</th><th>A\
|
|
|
|
lt [m]</th><th>Hr [%]</th><th>Lx [lux]</th></tr><\
|
|
|
|
tr><td>0</td><td>0</td><td>0</td><td>0</td><td>0<\
|
|
|
|
/td><td>0</td></tr></table><p><label>Intervale de\
|
|
|
|
mise à jour (en secondes) : </label><input id='i\
|
|
|
|
nterval' type='number' value=2/></p></div><div id\
|
|
|
|
='footer'> par Nathanaël Restori </div><script>fu\
|
|
|
|
nction updateInfo(){var xhr=new XMLHttpRequest();\
|
|
|
|
xhr.open('GET', '/sensors.json');xhr.onreadystate\
|
|
|
|
change=function(){if (xhr.readyState==4 && xhr.st\
|
|
|
|
atus==200){var response=JSON.parse(xhr.responseTe\
|
|
|
|
xt);var rows=document.getElementsByTagName('tr');\
|
|
|
|
var cell=rows[1].firstChild;var index=0;while (ce\
|
|
|
|
ll){cell.firstChild.nodeValue=response.sensors[in\
|
|
|
|
dex].data;cell=cell.nextSibling;index++;}}};xhr.s\
|
|
|
|
end(null);}updateInfo();var updateID=setInterval(\
|
|
|
|
updateInfo, 2000);var interval=document.getElemen\
|
|
|
|
tById('interval');interval.addEventListener('chan\
|
|
|
|
ge', function(e){clearInterval(updateID);updateID\
|
|
|
|
=setInterval(updateInfo, e.target.value*1000);}, \
|
|
|
|
true);</script></body></html>";
|
2012-09-05 18:01:37 +00:00
|
|
|
|
|
|
|
// no-cost stream operator as described at
|
|
|
|
// http://sundial.org/arduino/?page_id=119
|
|
|
|
template<class T>
|
|
|
|
inline Print &operator <<(Print &obj, T arg)
|
|
|
|
{ obj.print(arg); return obj; }
|
|
|
|
|
|
|
|
BMP085 bmp;
|
2012-09-12 19:29:43 +00:00
|
|
|
Chronodot chronodot;
|
2012-09-05 18:01:37 +00:00
|
|
|
DHT dht(DHTPIN, DHTTYPE);
|
|
|
|
TSL2561 tsl(TSL2561_ADDR_FLOAT);
|
|
|
|
WebServer webserver(PREFIX, 80);
|
|
|
|
|
|
|
|
byte packetBuffer[ NTP_PACKET_SIZE];
|
|
|
|
EthernetUDP Udp;
|
|
|
|
|
2012-09-17 17:43:24 +00:00
|
|
|
void defaultCmd(WebServer &server, WebServer::ConnectionType type,
|
|
|
|
char *url_tail, bool tail_complete) {
|
2012-09-05 18:01:37 +00:00
|
|
|
server.httpSuccess();
|
|
|
|
server.printP(indexHtml);
|
|
|
|
}
|
|
|
|
|
2012-09-17 17:43:24 +00:00
|
|
|
void sensorsJsonCmd(WebServer &server, WebServer::ConnectionType type,
|
|
|
|
char *url_tail, bool tail_complete) {
|
2012-09-05 18:01:37 +00:00
|
|
|
float temperature = bmp.readTemperature();
|
|
|
|
int32_t pressure = bmp.readPressure();
|
|
|
|
float altitude = bmp.readAltitude();
|
|
|
|
|
2012-09-15 10:25:54 +00:00
|
|
|
float humidity = dht.readHumidity();
|
|
|
|
|
2012-09-05 18:01:37 +00:00
|
|
|
uint32_t lum = tsl.getFullLuminosity();
|
|
|
|
uint16_t lightIr = lum >> 16;
|
|
|
|
uint16_t lightFull = lum & 0xFFFF;
|
|
|
|
|
|
|
|
DateTime time = chronodot.now();
|
|
|
|
|
|
|
|
server.httpSuccess("application/json");
|
|
|
|
|
|
|
|
server << "{ \"sensors\": ["
|
2012-09-17 17:43:24 +00:00
|
|
|
<< "{\"data\":\"" << time.hour() << ":" << time.minute()
|
|
|
|
<< ":" << time.second() << " " << time.day() << "/"
|
|
|
|
<< time.month() << "/" << time.year() << "\"},"
|
|
|
|
|
2012-09-05 18:01:37 +00:00
|
|
|
<< "{\"data\":" << temperature << "},"
|
|
|
|
<< "{\"data\":" << pressure << "},"
|
|
|
|
<< "{\"data\":" << altitude << "},"
|
|
|
|
<< "{\"data\":" << humidity << "},"
|
|
|
|
<< "{\"data\":" << tsl.calculateLux(lightFull, lightIr) << "}"
|
|
|
|
<< "] }";
|
|
|
|
}
|
|
|
|
|
2012-09-12 19:29:43 +00:00
|
|
|
// Taken from http://arduino.cc/en/Tutorial/UdpNtpClient .
|
2012-09-08 20:00:20 +00:00
|
|
|
void sendNTPpacket() {
|
2012-09-12 19:29:43 +00:00
|
|
|
// set all bytes in the buffer to 0
|
|
|
|
memset(packetBuffer, 0, NTP_PACKET_SIZE);
|
|
|
|
// Initialize values needed to form NTP request
|
|
|
|
// (see URL above for details on the packets)
|
|
|
|
packetBuffer[0] = 0b11100011; // LI, Version, Mode
|
|
|
|
packetBuffer[1] = 0; // Stratum, or type of clock
|
|
|
|
packetBuffer[2] = 6; // Polling Interval
|
|
|
|
packetBuffer[3] = 0xEC; // Peer Clock Precision
|
|
|
|
// 8 bytes of zero for Root Delay & Root Dispersion
|
|
|
|
packetBuffer[12] = 49;
|
|
|
|
packetBuffer[13] = 0x4E;
|
|
|
|
packetBuffer[14] = 49;
|
|
|
|
packetBuffer[15] = 52;
|
|
|
|
|
|
|
|
// all NTP fields have been given values, now
|
|
|
|
// you can send a packet requesting a timestamp:
|
|
|
|
Udp.beginPacket(timeserver, 123); //NTP requests are to port 123
|
|
|
|
Udp.write(packetBuffer,NTP_PACKET_SIZE);
|
|
|
|
Udp.endPacket();
|
|
|
|
Serial.println("Sending ntp packet");
|
|
|
|
|
|
|
|
delay(1000);
|
|
|
|
if ( Udp.parsePacket() ) {
|
|
|
|
// We've received a packet, read the data from it
|
2012-09-17 17:43:24 +00:00
|
|
|
Udp.read(packetBuffer,NTP_PACKET_SIZE); // read the packet
|
|
|
|
// into the buffer
|
2012-09-12 19:29:43 +00:00
|
|
|
|
2012-09-17 17:43:24 +00:00
|
|
|
// the timestamp starts at byte 40 of the received packet and is
|
|
|
|
// four bytes, or two words, long. First, esxtract the two
|
|
|
|
// words:
|
2012-09-12 19:29:43 +00:00
|
|
|
|
2012-09-17 17:43:24 +00:00
|
|
|
unsigned long highWord = word(packetBuffer[40],
|
|
|
|
packetBuffer[41]);
|
|
|
|
unsigned long lowWord = word(packetBuffer[42],
|
|
|
|
packetBuffer[43]);
|
2012-09-12 19:29:43 +00:00
|
|
|
// combine the four bytes (two words) into a long integer
|
|
|
|
// this is NTP time (seconds since Jan 1 1900):
|
|
|
|
unsigned long secsSince1900 = highWord << 16 | lowWord;
|
2012-09-17 17:43:24 +00:00
|
|
|
// Unix time starts on Jan 1 1970. In seconds, that's
|
|
|
|
// 2208988800:
|
2012-09-12 19:29:43 +00:00
|
|
|
const unsigned long seventyYears = 2208988800UL;
|
|
|
|
// subtract seventy years:
|
|
|
|
unsigned long epoch = secsSince1900 - seventyYears + TIMEZONE;
|
|
|
|
|
|
|
|
Serial.println("Adjusting time");
|
|
|
|
chronodot.adjust(DateTime(epoch));
|
|
|
|
}
|
2012-09-05 18:01:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void setup() {
|
|
|
|
Serial.begin(9600);
|
|
|
|
|
|
|
|
//----- Ethernet/WebServer
|
|
|
|
Serial.println("INIT Ethernet");
|
|
|
|
|
|
|
|
Ethernet.begin(mac, ip);
|
|
|
|
webserver.begin();
|
|
|
|
|
|
|
|
webserver.setDefaultCommand(&defaultCmd);
|
|
|
|
webserver.addCommand("sensors.json", &sensorsJsonCmd);
|
|
|
|
|
|
|
|
//----- Sensors
|
|
|
|
Serial.println("INIT Sensors");
|
|
|
|
|
|
|
|
bmp.begin();
|
|
|
|
dht.begin();
|
|
|
|
tsl.begin();
|
|
|
|
chronodot.begin();
|
|
|
|
|
2012-09-17 17:43:24 +00:00
|
|
|
//tsl.setGain(TSL2561_GAIN_0X); // bright situtations
|
|
|
|
tsl.setGain(TSL2561_GAIN_16X); // dim situations
|
2012-09-05 18:01:37 +00:00
|
|
|
|
2012-09-17 17:43:24 +00:00
|
|
|
tsl.setTiming(TSL2561_INTEGRATIONTIME_13MS); // bright light
|
|
|
|
//tsl.setTiming(TSL2561_INTEGRATIONTIME_101MS); // medium light
|
|
|
|
//tsl.setTiming(TSL2561_INTEGRATIONTIME_402MS); // dim light
|
2012-09-10 15:07:09 +00:00
|
|
|
|
2012-09-05 18:01:37 +00:00
|
|
|
Udp.begin(8888);
|
2012-09-08 20:00:20 +00:00
|
|
|
sendNTPpacket();
|
2012-09-05 18:01:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void loop() {
|
|
|
|
webserver.processConnection();
|
|
|
|
|
|
|
|
delay(500);
|
|
|
|
}
|