-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathXBeeLogger.ino
360 lines (326 loc) · 9.41 KB
/
XBeeLogger.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
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
#include <SoftwareSerial.h>
#include <Phant.h>
#include <Wire.h>
#include <Adafruit_AM2315.h>
// Time in ms, where we stop waiting for serial data to come in
// 2s is usually pretty good. Don't go under 1000ms (entering
// command mode takes about 1s).
#define COMMAND_TIMEOUT 2000 // ms
#define DEBUG
// Phant Stuff
String destIP = "54.86.132.254"; // data.sparkfun.com's IP address
String publicKey = "";
String privateKey = "";
Phant phant("data.sparkfun.com", publicKey, privateKey);
const String tempField = "temp";
const String humidityField = "humidity";
// XBee Stuff
const byte XB_RX = 2; // XBee's RX (Din) pin
const byte XB_TX = 3; // XBee's TX (Dout) pin
const int XBEE_BAUD = 9600; // Your XBee's baud (9600 is default)
SoftwareSerial xB(XB_RX, XB_TX);
// Temp/Humidity Sensor
Adafruit_AM2315 am2315;
float tempVal, humidityVal;
// Phant limits you to 10 seconds between posts. Use this variable
// to limit the update rate (in milliseconds):
const unsigned long UPDATE_RATE = 300000; // 300000ms = 5 minutes
unsigned long lastUpdate = 0; // Keep track of last update time
// LED to show status, fast blinking indicates problem with sensor,
// slow blinking indicates WiFi configuring or problem, on indicates
// WiFi connected.
int led = 13;
bool lastLED = LOW;
bool sendError = false;
void setup()
{
// We have a 5 second delay to give the shield and XBee module some
// time to settle down. Without this things weren't starting up
// properly unless the reset button was hit after power up.
delay(5000);
pinMode(led, OUTPUT);
digitalWrite(led, lastLED);
// Set up serial ports:
Serial.begin(9600);
xB.begin(XBEE_BAUD);
// Set up temp/humidity sensor, blink LED rapidly if sensor problem
if (! am2315.begin()) {
while (1) {
digitalWrite(led, HIGH);
delay(100);
digitalWrite(led, LOW);
delay(100);
}
}
// Set up WiFi network
Serial.println("Testing network");
connectWiFi();
Serial.println("Connected!");
Serial.print("IP Address: "); printIP(); Serial.println();
// setupHTTP() will set up the destination address, port, and
// make sure we're in TCP mode:
setupHTTP(destIP);
}
void loop()
{
// If current time is UPDATE_RATE milliseconds greater than
// the last update rate, send new data.
if (millis() > (lastUpdate + UPDATE_RATE))
{
Serial.print("Sending update...");
if (sendData())
{
sendError = false;
Serial.println("SUCCESS!");
}
else
{
sendError = true;
Serial.println("Failed :(");
}
lastUpdate = millis();
}
// In the meanwhile, we'll print data to the serial monitor,
// just to let the world know our Arduino is still operational:
readSensors();
Serial.print("Hum: "); Serial.println(humidityVal);
Serial.print("Tmp: "); Serial.println(tempVal);
alertSendError();
delay(2000);
}
void alertSendError()
{
if (sendError) {
digitalWrite(led, HIGH);
delay(100);
digitalWrite(led, LOW);
delay(100);
digitalWrite(led, HIGH);
delay(100);
digitalWrite(led, LOW);
delay(100);
digitalWrite(led, HIGH);
delay(100);
digitalWrite(led, LOW);
delay(100);
}
}
// sendData() makes use of the PHANT LIBRARY to send data to the
// data.sparkfun.com server. We'll use phant.add() to add specific
// parameter and their values to the param list. Then use
// phant.post() to send that data up to the server.
int sendData()
{
xB.flush(); // Flush data so we get fresh stuff in
readSensors(); // Get updated values from sensors.
phant.add(tempField, tempVal);
phant.add(humidityField, humidityVal);
// After our PHANT.ADD's we need to PHANT.POST(). The post needs
// to be sent out the XBee. A simple "print" of that post will
// take care of it.
xB.print(phant.post());
// Check the response to make sure we receive a "200 OK". If
// we were good little programmers we'd check the content of
// the OK response. If we were good little programmers...
char response[12];
if (waitForAvailable(12) > 0)
{
for (int i=0; i<12; i++)
{
response[i] = xB.read();
}
if (memcmp(response, "HTTP/1.1 200", 12) == 0)
return 1;
else
{
Serial.println(response);
return 0; // Non-200 response
}
}
else // Otherwise timeout, no response from server
return -1;
}
void readSensors()
{
humidityVal = am2315.readHumidity();
tempVal = am2315.readTemperature() * 1.8 + 32;
}
///////////////////////////
// XBee WiFi Setup Stuff //
///////////////////////////
// setupHTTP() sets three important parameters on the XBee:
// 1. Destination IP -- This is the IP address of the server
// we want to send data to.
// 2. Destination Port -- We'll be sending data over port 80.
// The standard HTTP port a server listens to.
// 3. IP protocol -- We'll be using TCP (instead of default UDP).
void setupHTTP(String address)
{
// Enter command mode, wait till we get there.
while (!commandMode(1))
;
// Set IP (1 - TCP)
command("ATIP1", 2); // RESP: OK
// Set DL (destination IP address)
command("ATDL" + address, 2); // RESP: OK
// Set DE (0x50 - port 80)
command("ATDE50", 2); // RESP: OK
commandMode(0); // Exit command mode when done
}
///////////////
// printIP() //
///////////////
// Simple function that enters command mode, reads the IP and
// prints it to a serial terminal. Then exits command mode.
void printIP()
{
// Wait till we get into command Mode.
while (!commandMode(1))
;
// Get rid of any data that may have already been in the
// serial receive buffer:
xB.flush();
// Send the ATMY command. Should at least respond with
// "0.0.0.0\r" (7 characters):
command("ATMY", 7);
// While there are characters to be read, read them and throw
// them out to the serial monitor.
while (xB.available() > 0)
{
Serial.write(xB.read());
}
// Exit command mode:
commandMode(0);
}
// Assumes you've already configured your XBee module's WiFi settings using X-CTU
// and simply blinks the LED while connecting or if there is a problem. We also
// turn on the LED once connected.
void connectWiFi()
{
const String CMD_SSID = "ATID";
const String CMD_ENC = "ATEE";
const String CMD_PSK = "ATPK";
// Check if we're connected. If so, sweet! We're done.
// Otherwise, time to configure some settings, and print
// some status messages:
int status;
while ((status = checkConnect()) != 0)
{
// Print a status message. If `status` isn't 0 (indicating
// "connected"), then it'll be one of these
// (from XBee WiFI user's manual):
// 0x01 - WiFi transceiver initialization in progress.
// 0x02 - WiFi transceiver initialized, but not yet scanning
// for access point.
// 0x13 - Disconnecting from access point.
// 0x23 – SSID not configured.
// 0x24 - Encryption key invalid (either NULL or invalid
// length for WEP)
// 0x27 – SSID was found, but join failed. 0x40- Waiting for
// WPA or WPA2 Authentication
// 0x41 – Module joined a network and is waiting for IP
// configuration to complete, which usually means it is
// waiting for a DHCP provided address.
// 0x42 – Module is joined, IP is configured, and listening
// sockets are being set up.
// 0xFF– Module is currently scanning for the configured SSID.
//
// We added 0xFE to indicate connected but SSID doesn't match
// the provided id.
Serial.print("Waiting to connect: ");
Serial.println(status, HEX);
digitalWrite(led, (lastLED = ! lastLED));
delay(1000);
}
digitalWrite(led, HIGH);
}
// Check if the XBee is connected to a WiFi network.
// This function will send the ATAI command to the XBee.
// That command will return with either a 0 (meaning connected)
// or various values indicating different levels of no-connect.
byte checkConnect()
{
byte i=0xFF;
char temp[2];
commandMode(0);
while (!commandMode(1))
;
command("ATAI", 2);
temp[0] = hexToInt(xB.read());
temp[1] = hexToInt(xB.read());
xB.flush();
#ifdef DEBUG
Serial.print("temp[0] = ");
Serial.println(temp[0], HEX);
Serial.print("temp[1] = ");
Serial.println(temp[1], HEX);
#endif
if (temp[0] == 0) {
return 0;
}
else {
return (temp[0]<<4) | temp[1];
}
}
/////////////////////////////////////
// Low-level, ugly, XBee Functions //
/////////////////////////////////////
void command(String atcmd, int rsplen)
{
xB.flush();
#ifdef DEBUG
Serial.print("Entering command: ");
#endif
xB.print(atcmd);
#ifdef DEBUG
Serial.println(atcmd);
#endif
xB.print("\r");
waitForAvailable(rsplen);
}
int commandMode(boolean enter)
{
xB.flush();
if (enter)
{
#ifdef DEBUG
Serial.println("Entering Command Mode");
#endif
char c;
xB.print("+++"); // Send CMD mode string
waitForAvailable(1);
if (xB.available() > 0)
{
c = xB.read();
#ifdef DEBUG
Serial.print("Command Mode Response: ");
Serial.println(c);
#endif
if (c == 'O') // That's the letter 'O', assume 'K' is next
return 1; // IF we see "OK" return success
}
return 0; // If no (or incorrect) receive, return fail
}
else
{
#ifdef DEBUG
Serial.println("Exiting Command Mode");
#endif
command("ATCN", 2);
return 1;
}
}
int waitForAvailable(int qty)
{
int timeout = COMMAND_TIMEOUT;
while ((timeout-- > 0) && (xB.available() < qty))
delay(1);
return timeout;
}
byte hexToInt(char c)
{
if (c >= 0x41) // If it's A-F
return c - 0x37;
else
return c - 0x30;
}