-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathWeatherStation-Wunderground-Ethernet.ino
250 lines (220 loc) · 6.6 KB
/
WeatherStation-Wunderground-Ethernet.ino
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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
/*
This Arduino sketch controls a personal weather station and use an ethernet shield to upload data to wunderground.com.
Details about the weather station can be found at http://www.avanux.de/space/Arduino/Wetterstation.
*/
//////////////
// Libraries
//////////////
#include <avr/wdt.h>
//////////////
// Variables
//////////////
//#define INFO_WS 1
//#define DEBUG_WS 1
//#define DEBUG_UPLOAD 1
#define UPLOAD 1
#define ENABLE_TEMPERATURE 1
#define ENABLE_PRESSURE 1
#define ENABLE_WIND_SPEED 1
#define ENABLE_WIND_DIRECTION 1
#define ENABLE_RAIN 1
//#define ENABLE_SOLAR_RADIATION 1
#define ENABLE_HUMIDITY 1
#define WDT_COUNTER_MAX 50 // 50=400s : Number of times of ISR(WDT_vect) to autoreset the board. I will autoreset the board after 8 secondes x counterMax
volatile int wdtCounter;
unsigned const long MAX_LONG = 4294967295;
unsigned const int ANALOG_READINGS = 100;
unsigned int hourOfDay = -1;
// results
unsigned int humidity;
float temperature;
float dewpoint;
unsigned long pressure;
float windSpeed;
float windSpeedAvg;
float windSpeedGust;
unsigned int windDirection;
unsigned int windDirectionAvg;
unsigned int windGustDirection;
float rainLastHour;
float rainToday;
unsigned int solarRadiation;
//////////////
// Pins set up
//////////////
// analog input
unsigned const int unusedAnalogPin = A0;
unsigned int pressurePin = A1;
unsigned int windDirectionPin = A2;
unsigned int solarRadiationPin = A3;
unsigned int humidityPin = A4;
// digital
unsigned int windSpeedInterrupt= 0; // D2(Uno), D3(Leonardo)
unsigned int rainInterrupt = 1; // D3(Uno), D2(Leonardo)
unsigned int temperaturePin = 5;
unsigned int ledPin = 6;
//////////////
// Watchdog
// http://www.seeedstudio.com/recipe/279-long-time-auto-reset-feature-for-your-arduino.html
//////////////
ISR (WDT_vect)
{
wdtCounter += 1;
if (wdtCounter < WDT_COUNTER_MAX - 1) {
wdt_reset(); // Reset timer, still in interrupt mode
// Next time watchdogtimer complete the cicle, it will generate antoher ISR interrupt
} else {
MCUSR = 0;
WDTCSR |= 0b00011000; //WDCE y WDE = 1 --> config mode
WDTCSR = 0b00001000 | 0b100001; //clear WDIE (interrupt mode disabled), set WDE (reset mode enabled) and set interval to 8 seconds
//Next time watchdog timer complete the cicly will reset the IC
}
}
void wdt_long_enable()
{
wdtCounter = 0;
cli(); //disabled ints
MCUSR = 0; //clear reset status
WDTCSR |= 0b00011000; //WDCE y WDE = 1 --> config mode
WDTCSR = 0b01000000 | 0b100001; //set WDIE (interrupt mode enabled), clear WDE (reset mode disabled) and set interval to 8 seconds
sei(); //enable ints
}
void wdt_long_disable()
{
wdt_disable();
}
//////////////
// Set up
//////////////
void setup() {
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
wdt_disable();
pinMode(ledPin, OUTPUT);
unsigned long now = currentMillis();
#ifdef ENABLE_TEMPERATURE
setupTemperature();
#endif
#ifdef ENABLE_WIND_SPEED
setupWindSpeed(now);
#endif
#ifdef ENABLE_WIND_DIRECTION
setupWindDirection();
#endif
#ifdef ENABLE_PRESSURE
setupPressure();
#endif
#ifdef ENABLE_RAIN
setupRain(now);
#endif
#ifdef ENABLE_SOLAR_RADIATION
setupSolarRadiation();
#endif
#ifdef ENABLE_HUMIDITY
setupHumidity();
#endif
#ifdef UPLOAD
setupUpload(now);
#endif
}
//////////////
// Loop
//////////////
void loop() {
// enable watchdog; it will be disabled after upload connection was successful
wdt_long_enable();
unsigned long now = currentMillis();
#ifdef INFO_WS
Serial.print(F("\nnow="));Serial.print(now);Serial.print(F("\tfree="));Serial.println(freeRam());
#endif
#ifdef ENABLE_TEMPERATURE
loopTemperature();
#endif
#ifdef ENABLE_WIND_SPEED
loopWindSpeed(now);
#endif
#ifdef ENABLE_WIND_DIRECTION
loopWindDirection(now);
#endif
#ifdef ENABLE_PRESSURE
loopPressure();
#endif
#ifdef ENABLE_RAIN
loopRain(now);
#endif
#ifdef ENABLE_SOLAR_RADIATION
loopSolarRadiation();
#endif
#ifdef ENABLE_HUMIDITY
loopHumidity();
#endif
#ifdef UPLOAD
loopUpload(now);
#endif
digitalWrite(ledPin, HIGH);
delay(500);
digitalWrite(ledPin, LOW);
delay(500);
}
//////////////
// Functions
//////////////
/*
* The sensors are connected to the Arduino with long wires that act as antennas and pick up noise. This caused the analog readings to fluctuate.
* A first step towards repressing this noise could be to do 100 A/D conversions and taking the average. While this is a very straight forward approach,
* there are better options.
* A median filter is much better in reducing the impact of noise than an averaging filter. It works like this: you take 100 measurements,
* sort them from small to large and take the middle one. A median filter is much less influenced by outliers, since they end up at the beginning or the end.
* A mode filter is a combination of a median filter and an averaging filter: you sort the values and take the average of the ones in the middle.
* In my case I take the average of the 10 center values.
*
* Source: http://www.elcojacobs.com/eleminating-noise-from-sensor-readings-on-arduino-with-digital-filtering/
*
* Note: this method takes 18 ms for 100 readings additional to the initial delay after reading the unusedAnalogPin
*/
int analogReadSmoothed(int pin){
analogRead(unusedAnalogPin); // dummy read to discharge ADC
delay(20); // wait a little
// read multiple values and sort them to take the mode
int sortedValues[ANALOG_READINGS];
for(int i=0;i<ANALOG_READINGS;i++){
int value = analogRead(pin);
int j;
if(value<sortedValues[0] || i==0){
j=0; //insert at first position
}
else {
for(j=1;j<i;j++) {
if(sortedValues[j-1]<=value && sortedValues[j]>=value){
// j is insert position
break;
}
}
}
for(int k=i;k>j;k--){
// move all values higher than current reading up one position
sortedValues[k]=sortedValues[k-1];
}
sortedValues[j]=value; //insert current reading
}
//return scaled mode of 10 values
float returnval = 0;
for(int i=ANALOG_READINGS/2-5;i<(ANALOG_READINGS/2+5);i++){
returnval +=sortedValues[i];
}
return returnval/10;
}
long currentMillis() {
#ifdef DEBUG_WS
return MAX_LONG - 10000 + millis();
#endif
return millis();
}
int freeRam ()
{
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}