/
GPS_tracker_car.ino
491 lines (452 loc) · 14.6 KB
/
GPS_tracker_car.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
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
/*
Written by W. Hoogervorst
January 2019 (version 13)
Arduino Pro mini 5V 328
*/
#include <TimeLib.h>
#include <TinyGPS++.h>
#include <AltSoftSerial.h>
#include <Timezone.h>
#define A6Serial Serial // A6 module is connected to hardware serial
//#define //DebugSerial Serial
//define serial connection for GPS
AltSoftSerial GPS_serial; // RX = 8 (to TX op GPS) , TX = 9 (to RX of GPS) PWM 10 is not available
//define GPS variable
TinyGPSPlus gps;
// time variables
const int uploadinterval = 300; //upload GPS data every # seconds
time_t local, utc, lastupload;
// Change these two rules corresponding to your timezone, see https://github.com/JChristensen/Timezone
//Central European Time (Frankfurt, Paris) 120 = +2 hours in daylight saving time (summer).
TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120};
//Central European Time (Frankfurt, Paris) 60 = +1 hour in normal time (winter)
TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 60};
Timezone CE(CEST, CET);
#define SPEEDLIMIT 2
#define OKLED 11
#define NOTOKLED 10
#define A6ACTIONLED 12
// variables for the receiving phone numbers
char phone_number[12] = "###########"; //no +, landcode & phone number
char received[13];
int uploadcounter = 0;
char end_c[2];
int8_t answer = 0, answer1 = 0;
uint32_t calltime = 0, maxtime = 5000;
boolean incoming;
boolean speedflag = true;
//temperature and thermistor values and variables
#define THERMISTORPIN A0
#define THERMISTORNOMINAL 10000 // resistance at 25 degrees C
#define TEMPERATURENOMINAL 25 // temp. for nominal resistance (almost always 25 C)
#define NUMSAMPLES 5
#define BCOEFFICIENT 3950 // The beta coefficient of the thermistor (usually 3000-4000)
#define SERIESRESISTOR 10000 // the value of the 'other' resistor
uint16_t samples[NUMSAMPLES];
int8_t temperature; // must be signed, otherwise negative temperatures are not shown correctly
boolean tempsmsflag1 = true; // no ALARM sms is sent yet
boolean tempsmsflag2 = true; // no ALARM sms is sent yet
const int tempcheckinterval = 300; //check temp every # seconds
time_t lasttemp;
#define ALARM 1
#define NO_ALARM 0
#define TEMPERATURELIMIT1 40
#define TEMPERATURELIMIT2 55
#define THERMISTOR_POWER 13
void setup() {
A6Serial.begin(115200);
// ctrlZ String definition
end_c[0] = 0x1a;
end_c[1] = '\0';
pinMode(OKLED, OUTPUT);
pinMode(NOTOKLED, OUTPUT);
pinMode(A6ACTIONLED, OUTPUT);
pinMode(THERMISTOR_POWER, OUTPUT);
digitalWrite(OKLED, LOW);
digitalWrite(NOTOKLED, LOW);
digitalWrite(A6ACTIONLED, LOW);
digitalWrite(THERMISTOR_POWER, LOW);
blinkLEDS(); //leds blinking
GPS_serial.begin(9600); //This opens up communications to the GPS
smartDelay(1000);
A6start();
digitalWrite(NOTOKLED, HIGH);
while (gps.satellites.value() == 0) // wait for a GPS fix to know the UTC time
{
smartDelay(500);
digitalWrite(OKLED, !digitalRead(OKLED));
digitalWrite(NOTOKLED, !digitalRead(NOTOKLED));
}
digitalWrite(OKLED, HIGH);
setthetime();
lastupload = now();
Serial.println("end of init");
measuretemp();
smartDelay(5000);
ThingspeakGSM();
smartDelay(1000);
}
void loop()
{
if (gps.speed.kmph() > SPEEDLIMIT) // upload the GPS data only if the vehicle has moved inbetween uploads
speedflag = true;
if (gps.satellites.value() != 0)
{
digitalWrite(OKLED, HIGH);
digitalWrite(NOTOKLED, LOW);
}
else
{
digitalWrite(OKLED, LOW);
digitalWrite(NOTOKLED, HIGH);
}
if (now() - lastupload > uploadinterval && gps.satellites.value() != 0 && speedflag ) // set the microcontroller time every interval, only if the vehicle has moved
{
setthetime();
ThingspeakGSM();
lastupload = now();
speedflag = false;
smartDelay(1000);
}
if (now() - lasttemp > tempcheckinterval)
{
measuretemp();
lasttemp = now();
smartDelay(1000);
if (temperature > TEMPERATURELIMIT1 && tempsmsflag1)
{
SendTextMessage(ALARM);
tempsmsflag1 = false;
}
if (temperature > TEMPERATURELIMIT2 && tempsmsflag2)
{
SendTextMessage(ALARM);
tempsmsflag2 = false;
}
}
//detect whether the module is phoned
if (sendATcommand("", "+CLIP", 1000) == 1) // when to is phoned, "+CLIP" is in the serial output of the A6
{
incoming = true;
}
//answer is 1 if sendATcommand detects +CLIP
while (incoming)
{
uint32_t starttime = millis();
for (int i = 0; i < 15; i++) {
//read the incoming byte of the phone number:
while (A6Serial.available() == 0)
{
delay (50);
}
//stores phone number
received[i] = A6Serial.read();
}
A6Serial.flush();
byte j = 0;
//phone number comes after quotes (") so discard all bytes until find'em
while (received[j] != '"')
j++;
j++;
for (byte i = 0; i < 11; i++) {
phone_number[i] = received[i + j];
}
int8_t answer2 = sendATcommand("", "ERROR", 1000); //checks whether the caller hang up (gives an "ERROR" message in the serial output of the A6 module)
calltime = 0;
while (answer2 == 0 && calltime < maxtime)
{
calltime = millis() - starttime;
answer2 = sendATcommand("", "ERROR", 1000);
}
SendTextMessage(NO_ALARM);
incoming = false;
}
}
void A6start()
{
digitalWrite(A6ACTIONLED, HIGH);
smartDelay(2000);
answer = 0;
// checks if the module is started
answer = sendATcommand("AT", "OK", 2000);
if (answer == 0)
{
// waits for an answer from the module
while (answer == 0)
{ // send AT every two seconds and wait for the answer
answer = sendATcommand("AT", "OK", 2000);
}
}
answer = 0;
answer1 = 0;
smartDelay(1000);
//answer = sendATcommand("AT+CREG?", ",1", 2000);
answer = sendATcommand("AT+CREG?", "+CREG: 1,1", 2000); // registrered to home network
answer1 = sendATcommand("AT+CREG?", ",5", 2000); // registrered to network and roaming
if (answer == 0 || answer1 == 0)
{
// waits for an answer from the module
while (answer == 0 && answer1 == 0)
{ // checks whether module is connected to network
answer = sendATcommand("AT+CREG?", "+CREG: 1,1", 2000); // registrered to home network
answer1 = sendATcommand("AT+CREG?", ",5", 2000); // registrered to network and roaming
}
}
answer = 0;
smartDelay(1000);
// enable caller ID displaying
answer = sendATcommand("AT+CLIP=1", "OK", 1000);
if (answer == 0)
{
// waits for an answer from the module
while (answer == 0)
{
answer = sendATcommand("AT+CLIP=1", "OK", 2000);
}
}
answer = 0;
smartDelay(1000);
//delete SMS messages from the module
answer = sendATcommand("AT+CMGD=1,4", "OK", 1000);
if (answer == 0)
{
// waits for an answer from the module
while (answer == 0)
{
sendATcommand("AT+CMGD=1,4", "OK", 5000);
}
}
answer = 0;
smartDelay(1000);
answer = sendATcommand("ATE0", "OK", 1000);
if (answer == 0)
{
// waits for an answer from the module
while (answer == 0)
{
answer = sendATcommand("ATE0", "OK", 1000);
}
}
digitalWrite(A6ACTIONLED, LOW);
}
int8_t sendATcommand(char* ATcommand, char* expected_answer, unsigned int timeout)
{
uint8_t x = 0, answer = 0;
char response[100];
unsigned long previous;
memset(response, '\0', 100); // Initialice the string
delay(100);
while (A6Serial.available() > 0) A6Serial.read(); // Clean the input buffer
A6Serial.println(ATcommand); // Send the AT command
x = 0;
previous = millis();
// this loop waits for the answer
do {
// if there are data in the UART input buffer, reads it and checks for the asnwer
if (A6Serial.available() != 0) {
response[x] = A6Serial.read();
x++;
// check if the desired answer is in the response of the module
if (strstr(response, expected_answer) != NULL)
{
answer = 1;
}
}
while (GPS_serial.available())
gps.encode(GPS_serial.read());
// Waits for the answer with time out and reads the GPS data
} while ((answer == 0) && ((millis() - previous) < timeout));
//DebugSerial.println(response);
return answer;
}
static void smartDelay(unsigned long ms)
{
unsigned long start = millis();
do
{
// If data has come in from the GPS module
while (GPS_serial.available())
gps.encode(GPS_serial.read()); // Send it to the encode function
// tinyGPS.encode(char) continues to "load" the tinGPS object with new
// data coming in from the GPS module. As full NMEA strings begin to come in
// the tinyGPS library will be able to start parsing them for pertinent info
} while (millis() - start < ms);
}
void setthetime(void)
{
int Year = gps.date.year();
byte Month = gps.date.month();
byte Day = gps.date.day();
byte Hour = gps.time.hour();
byte Minute = gps.time.minute();
byte Second = gps.time.second();
// Set Time from GPS data string
setTime(Hour, Minute, Second, Day, Month, Year); // set the time of the microcontroller to the UTC time from the GPS
}
///SendTextMessage()
///this function is to send a sms message
void SendTextMessage(int alarm)
{
digitalWrite(A6ACTIONLED, HIGH);
//DebugSerial.println("\nstart SMS subroutine");
sendATcommand("AT+CMGF = 1\r", "OK", 2000); //Because we want to send the SMS in text mode
//smartDelay(1000);
//DebugSerial.println("AT+CMGS =+etcetera");
A6Serial.print("AT+CMGS = +"); // include "+" in number
for (int i = 0; i < 11; i++)
{
// Print phone number:
A6Serial.print(phone_number[i]);
}
A6Serial.println("");
sendATcommand("", " > ", 10000);
if (alarm)
{
A6Serial.print("Attention! Temperature of GPS tracker = ");
A6Serial.print(temperature, 1);
A6Serial.print(" C");
}
else
{
A6Serial.print("Current location : http : //www.google.com/maps?q=");
A6Serial.print(gps.location.lat(), 6);
A6Serial.print(",");
A6Serial.print(gps.location.lng(), 6);
A6Serial.print(". speed: ");
A6Serial.print(gps.speed.kmph());
A6Serial.print(". course: ");
A6Serial.print(gps.course.deg());
A6Serial.print(". module temperature: ");
A6Serial.print(temperature);
}
A6Serial.print(". This SMS was sent to: +");
for (int i = 0; i < 11; i++)
{
// Print phone number:
A6Serial.print(phone_number[i]);
}
// include current time in SMS
utc = now(); // read the time in the correct format to change via the TimeChangeRules
local = CE.toLocal(utc); // change UTC to current time in timezone
A6Serial.print(". at ");
if (hour(local) < 10) // add a zero if minute is under 10
A6Serial.print("0");
A6Serial.print(hour(local));
A6Serial.print(":");
if (minute(local) < 10) // add a zero if minute is under 10
A6Serial.print("0");
A6Serial.print(minute(local));
// SMS end commands
A6Serial.println(end_c);//the ASCII code of the ctrl+z is 26
A6Serial.println();
sendATcommand("", "OK", 10000);
sendATcommand("AT", "OK", 1000);
smartDelay(1000);
digitalWrite(A6ACTIONLED, LOW);
}
void ThingspeakGSM(void)
{
digitalWrite(A6ACTIONLED, HIGH);
String host = "api.thingspeak.com";
String write_api_key = "################"; // place your Thingspeak API key here
//sendATcommand("AT+CIPSTATUS", "OK", 10000);
//sendATcommand("AT+CGATT?", "OK", 20000);
sendATcommand("AT+CGATT=1", "OK", 20000);
//sendATcommand("AT+CIPSTATUS", "OK", 10000);
sendATcommand("AT+CGDCONT=1,\"IP\",\"internet\"", "OK", 20000); //bring up wireless connection
//sendATcommand("AT+CIPSTATUS", "", 10000);
sendATcommand("AT+CGACT=1,1", "OK", 20000);
sendATcommand("AT+CGDCONT?", "CGDCONT", 20000);
//sendATcommand("AT+CIPSTATUS", "", 10000);
//delay(1000);
//sendATcommand("AT+CIPSTATUS", "OK", 10000);
sendATcommand("AT+CIFSR", "OK", 20000); //get local IP adress
//sendATcommand("AT+CIPSTATUS", "OK", 10000);
sendATcommand("AT+CIPSTART=\"TCP\",\"api.thingspeak.com\",80", "CONNECT OK", 25000); //start up the connection
//sendATcommand("AT+CIPSTART=\"TCP\",\""+host+"\",80", "CONNECT OK", 25000); //start up the connection
//sendATcommand("AT+CIPSTATUS", "OK", 10000);
sendATcommand("AT+CIPSEND", ">", 10000); //begin send data to remote server
smartDelay(500);
A6Serial.print("GET /update?api_key=");
A6Serial.print(write_api_key);
A6Serial.print("&field1=");
A6Serial.print(gps.location.lat(), 6);
A6Serial.print("&field2=");
A6Serial.print(gps.location.lng(), 6);
A6Serial.print("&field3=");
A6Serial.print(gps.speed.kmph());
A6Serial.print("&field4=");
A6Serial.print(gps.course.deg());
A6Serial.print("&field5=");
A6Serial.print(uploadcounter + 1);
A6Serial.print("&field6=");
A6Serial.println(temperature, 1);
A6Serial.print("\r\n");
A6Serial.println("");
//DebugSerial.print("GET /update?api_key=");
//DebugSerial.print(write_api_key);
//DebugSerial.print("&field1=");
//DebugSerial.print(gps.location.lat(), 6);
//DebugSerial.print("&field2=");
//DebugSerial.print(gps.location.lng(), 6);
//DebugSerial.print("&field3=");
//DebugSerial.print(gps.speed.kmph());
//DebugSerial.print("&field4=");
//DebugSerial.print(gps.course.deg());
//DebugSerial.print("&field5=");
//DebugSerial.println(uploadcounter+1);
//DebugSerial.print("\r\n");
Serial.println("");
sendATcommand(end_c, "CIPRCV", 30000); //begin send data to remote server and wait
smartDelay(2000);
Serial.println("-------------------------End------------------------------");
//DebugSerial.println("wait for incoming call");
digitalWrite(A6ACTIONLED, LOW);
uploadcounter++;
}
void blinkLEDS(void)
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 3; j++)
{
digitalWrite(10 + j, HIGH);
delay(500);
}
for (int k = 0; k < 3; k++)
{
digitalWrite(10 + k, LOW);
delay(500);
}
}
}
void measuretemp(void)
{
//from: https://learn.adafruit.com/thermistor/using-a-thermistor
uint8_t i;
float average;
digitalWrite(THERMISTOR_POWER, HIGH); // only measure when the pin is high
// take N samples in a row, with a slight delay
for (i = 0; i < NUMSAMPLES; i++) {
samples[i] = analogRead(THERMISTORPIN);
delay(10);
}
// average all the samples out
average = 0;
for (i = 0; i < NUMSAMPLES; i++) {
average += samples[i];
}
average /= NUMSAMPLES;
// convert the value to resistance
average = 1023 / average - 1;
average = SERIESRESISTOR / average;
float steinhart;
steinhart = average / THERMISTORNOMINAL; // (R/Ro)
steinhart = log(steinhart); // ln(R/Ro)
steinhart /= BCOEFFICIENT; // 1/B * ln(R/Ro)
steinhart += 1.0 / (TEMPERATURENOMINAL + 273.15); // + (1/To)
steinhart = 1.0 / steinhart; // Invert
steinhart -= 273.15; // convert to C
temperature = steinhart;
digitalWrite(THERMISTOR_POWER, LOW);
}