Created
November 5, 2017 15:50
-
-
Save adlerweb/8047c1b018aa31b98dd1ce219e82d453 to your computer and use it in GitHub Desktop.
GPS Tracker (ublox neo 6/7 + ESP8266), https://www.youtube.com/watch?v=wlQ7ku758T4
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <ESP8266WiFi.h> | |
#include <ESP8266HTTPClient.h> | |
#include <NMEAGPS.h> | |
#include <SoftwareSerial.h> | |
/** | |
* Required libs (see manager): | |
* - SoftwareSerial | |
* - NeoGPS | |
*/ | |
#define RTCMEMORYSTART 65 | |
extern "C" { | |
#include "user_interface.h" | |
} | |
//WiFi | |
const char* ssid = "freifunk-myk.de"; | |
const char* pass = ""; | |
//URL of ownTracks Recorder | |
const char* owntracksURL = "http://adlerweb-vm-owntracks.ffmyk:8083/pub"; | |
//User and Device for ownTracks | |
const char* owntracksUser = "esp8266-1"; | |
const char* owntracksDevice = "esp8266-1"; | |
//Sleep between GNSS checks in minutes | |
//const unsigned int sleep_off = 5; | |
const unsigned int sleep_off = 1; | |
//Time for GNSS warm-up in seconds | |
//const unsigned int sleep_GNSS = 30; | |
const unsigned int sleep_GNSS = 10; | |
//Time to wait for 3D-Fix before reverting to 2D in seconds | |
const unsigned int sleep_3d = 30; | |
//Time to wait for 2D-Fix before reverting to RF in seconds | |
const unsigned int sleep_2d = 60; | |
//RF Geolocation Todo https://github.com/m0xpd/ESP8266-GeoLocation/blob/master/ESP8266_GeoLocate_2.ino | |
//Geo-deviation in deg-fract(?) | |
const unsigned int fence = 5000; | |
//Force update after x minutes | |
const unsigned int rf_force = 720; | |
//Time to wait for RF-Connect before giving up in seconds | |
const unsigned int rf_timeout = 60; | |
//GNSS Power Switch | |
#define GNSS_PWR_PIN D4 | |
#define GNSS_PWR_ON LOW | |
//Software UART for GNSS (RX, TX) | |
SoftwareSerial GNSSPort(D7, D8); | |
#define GNSS_BAUD 115200 | |
//Hardware UART for Debug | |
#define DEBUG_PORT Serial | |
#define DEBUG_BAUD 115200 | |
//Write all data when received | |
#define DEBUG_DUMP 0 | |
NMEAGPS GNSS; | |
gps_fix fix; | |
int32_t lon=0, lat=0; | |
float vel=0,alt=0,cog=0; | |
bool delayGNSS(uint32_t dly) { | |
return delayGNSS(dly, false); | |
} | |
bool delayGNSS(int32_t dly, bool direct) { | |
unsigned long mstop = millis()+dly; | |
bool ret = false; | |
if(DEBUG_DUMP > 1) DEBUG_PORT.print(F("\nS:")); | |
if(DEBUG_DUMP > 1) DEBUG_PORT.print(dly); | |
do { | |
if (GNSS.available( GNSSPort )) { | |
fix = GNSS.read(); | |
ret = true; | |
if(DEBUG_DUMP > 1) DEBUG_PORT.print('!'); | |
} | |
}while(!ret && mstop > millis()); | |
if (fix.valid.heading) cog = fix.heading(); | |
if (fix.valid.speed) vel = fix.speed_kph(); | |
if (fix.valid.altitude) alt = fix.altitude(); | |
if (fix.valid.location) { | |
lon = fix.longitudeL(); | |
lat = fix.latitudeL(); | |
} | |
if(!ret) return false; | |
if(!direct) { | |
if(DEBUG_DUMP > 1) DEBUG_PORT.print('+'); | |
if(DEBUG_DUMP > 1) DEBUG_PORT.print(mstop-millis()); | |
delay((mstop-millis())); | |
} | |
return true; | |
} | |
bool getGNSS(void) { | |
bool ret; | |
if(delayGNSS(100, true)) { | |
if(DEBUG_DUMP > 0) debugDump(); | |
return true; | |
} | |
return false; | |
} | |
bool wait_3d(void) { | |
DEBUG_PORT.print(F("Waiting 3D Fix...")); | |
for (unsigned int sec = 0; sec < sleep_3d; sec++) { | |
if(getGNSS() && lon != 0 && lat != 0 && alt != 0) { | |
DEBUG_PORT.println(F("OK")); | |
return true; | |
} | |
Serial.print('.'); | |
yield(); | |
delayGNSS(1000); | |
} | |
DEBUG_PORT.println(F("NOPE")); | |
return false; | |
} | |
bool wait_2d(void) { | |
DEBUG_PORT.print(F("Waiting 2D Fix...")); | |
for (unsigned int sec = 0; sec < sleep_2d; sec++) { | |
if(getGNSS() && lon != 0 && lat != 0) { | |
DEBUG_PORT.println(F("OK")); | |
return true; | |
} | |
Serial.print('.'); | |
yield(); | |
delayGNSS(1000); | |
} | |
DEBUG_PORT.println(F("NOPE")); | |
return false; | |
} | |
byte getBattery(void) { | |
//@TODO not yet implemented | |
return 100; | |
} | |
String getGeoDecimal(int32_t location) { | |
unsigned long tmp1, tmp2; | |
String out = ""; | |
if (location < 0) { | |
out += '-'; | |
location = 0 - location; | |
} | |
tmp1 = location / 10000000; | |
tmp2 = location - (tmp1 * 10000000); | |
out += tmp1; | |
out += "."; | |
out += tmp2; | |
return out; | |
} | |
bool getFence(void) { | |
int32_t check = 0; | |
DEBUG_PORT.print(F("FENCE - ")); | |
//Lat | |
DEBUG_PORT.print(F("LAT:")); | |
system_rtc_mem_read(RTCMEMORYSTART + 1, (int32_t *)check, 4); | |
DEBUG_PORT.print(check); | |
DEBUG_PORT.print('/'); | |
DEBUG_PORT.print(lat); | |
if (check + fence > lat || check - fence < lat) { | |
DEBUG_PORT.println('!'); | |
return true; | |
} | |
//Lon | |
DEBUG_PORT.print(F(" - LON:")); | |
system_rtc_mem_read(RTCMEMORYSTART + 2, (int32_t *)check, 4); | |
DEBUG_PORT.print(check); | |
DEBUG_PORT.print('/'); | |
DEBUG_PORT.print(lon); | |
if (check + fence > lon || check - fence < lon) { | |
DEBUG_PORT.println('!'); | |
return true; | |
} | |
DEBUG_PORT.println('_'); | |
return false; | |
} | |
NeoGPS::clock_t getTimestamp(void) { | |
if (!fix.valid.date || !fix.valid.time) return 0; | |
//This contains the seconds starting from the start of this century | |
NeoGPS::clock_t seconds = fix.dateTime; | |
//Guessing we're still 20xx this is the unix timestamp for 01.01.2000 00:00:00 | |
seconds += 946684800; | |
return seconds; | |
} | |
bool rfConnect(void) { | |
unsigned int rftimer; | |
if(WiFi.status() == WL_CONNECTED) return true; | |
DEBUG_PORT.print(F("connecting to ")); | |
DEBUG_PORT.println(ssid); | |
if(pass == "") { | |
WiFi.begin(ssid); | |
}else{ | |
WiFi.begin(ssid, pass); | |
} | |
while (WiFi.status() != WL_CONNECTED && rftimer < rf_timeout) { | |
delay(1000); | |
DEBUG_PORT.print("."); | |
rftimer++; | |
yield(); | |
} | |
if (WiFi.status() != WL_CONNECTED) { | |
DEBUG_PORT.println(F("failed")); | |
return false; | |
} | |
DEBUG_PORT.println(F("connected")); | |
DEBUG_PORT.print(F("IP address: ")); | |
DEBUG_PORT.println(WiFi.localIP()); | |
return true; | |
} | |
void rfDisconnect(void) { | |
/*WiFi.disconnect(); | |
WiFi.mode(WIFI_OFF); | |
WiFi.forceSleepBegin();*/ | |
} | |
bool rfSend(void) { | |
String data; | |
HTTPClient http; | |
if (!rfConnect()) return false; | |
if (lat == 0 || lon == 0) return false; | |
http.begin(owntracksURL); | |
http.addHeader(F("X-Limit-U"), owntracksUser); | |
http.addHeader(F("X-Limit-D"), owntracksDevice); | |
http.addHeader(F("User-Agent"), F("Adlerweb-ESP-Tracker")); | |
http.addHeader(F("Content-Type"), F("application/json")); | |
data = "{\"_type\":\"location\",\"tid\":\"01\",\"conn\":\"m\",\"_cp\":true,\"batt\":"; | |
data += getBattery(); | |
data += ",\"lat\":"; | |
data += getGeoDecimal(lat); | |
data += ",\"lon\":"; | |
data += getGeoDecimal(lon); | |
if (cog != 0) { | |
data += ",\"cog\":"; | |
data += cog; | |
} | |
if (vel != 0) { | |
data += ",\"vel\":"; | |
data += vel; | |
} | |
if (alt != 0) { | |
data += ",\"alt\":"; | |
data += alt; | |
} | |
data += ",\"tst\":"; | |
data += getTimestamp(); | |
data += "}"; | |
DEBUG_PORT.println(F("---")); | |
DEBUG_PORT.println(data); | |
DEBUG_PORT.println(F("---")); | |
DEBUG_PORT.println(F("Send")); | |
DEBUG_PORT.flush(); | |
http.POST(data); | |
DEBUG_PORT.println("."); | |
DEBUG_PORT.flush(); | |
http.writeToStream(&Serial); | |
DEBUG_PORT.println("."); | |
DEBUG_PORT.flush(); | |
http.end(); | |
DEBUG_PORT.println(F("OK")); | |
DEBUG_PORT.flush(); | |
rfDisconnect(); | |
return true; | |
} | |
void debugDump() { | |
DEBUG_PORT.print(F("Status: ")); | |
switch (fix.status) { | |
case 1: | |
DEBUG_PORT.println(F("Nährungswert")); | |
break; | |
case 2: | |
DEBUG_PORT.println(F("Nur Zeit")); | |
break; | |
case 3: | |
DEBUG_PORT.println(F("GNSS-Fix")); | |
break; | |
case 4: | |
DEBUG_PORT.println(F("DGNSS-Fix")); | |
break; | |
default: | |
DEBUG_PORT.println(F("Keiner")); | |
} | |
DEBUG_PORT.print(F("UTC: ")); | |
DEBUG_PORT.print(fix.dateTime.year); | |
DEBUG_PORT.print("-"); | |
DEBUG_PORT.print(fix.dateTime.month); | |
DEBUG_PORT.print("-"); | |
DEBUG_PORT.print(fix.dateTime.date); | |
DEBUG_PORT.print(" "); | |
DEBUG_PORT.print(fix.dateTime.hours); | |
DEBUG_PORT.print(":"); | |
DEBUG_PORT.print(fix.dateTime.minutes); | |
DEBUG_PORT.print(":"); | |
DEBUG_PORT.print(fix.dateTime.seconds); | |
DEBUG_PORT.print(" - "); | |
DEBUG_PORT.print(getTimestamp()); | |
DEBUG_PORT.print("/"); | |
//DEBUG_PORT.println(lasttime); | |
DEBUG_PORT.print(F("Satellites: ")); | |
DEBUG_PORT.println(fix.satellites); | |
DEBUG_PORT.print(F("Speed: ")); | |
DEBUG_PORT.println(vel); | |
DEBUG_PORT.print(F("Heading: ")); | |
DEBUG_PORT.println(cog); | |
DEBUG_PORT.print(F("Altitude: ")); | |
DEBUG_PORT.println(alt); | |
DEBUG_PORT.print(F("Postition: ")); | |
DEBUG_PORT.print(lat); | |
DEBUG_PORT.print(","); | |
DEBUG_PORT.println(lon); | |
DEBUG_PORT.print(getGeoDecimal(lat)); | |
DEBUG_PORT.print(","); | |
DEBUG_PORT.println(getGeoDecimal(lon)); | |
} | |
byte getBootMode(void) { | |
byte bootMode = 0; | |
system_rtc_mem_read(RTCMEMORYSTART, &bootMode, 1); | |
DEBUG_PORT.print("BootMode: "); | |
DEBUG_PORT.println(bootMode); | |
return bootMode; | |
} | |
///////////// | |
void setup() { | |
int32_t dummy = 0; | |
pinMode(GNSS_PWR_PIN, OUTPUT); | |
DEBUG_PORT.begin(DEBUG_BAUD); | |
GNSSPort.begin(GNSS_BAUD); | |
delay(2000); | |
DEBUG_PORT.println( F("Adlerweb GNSS Tracker v0.1.1") ); | |
DEBUG_PORT.flush(); | |
byte bootMode = getBootMode(); | |
if(bootMode == 0 || bootMode > 5) { //Unknown or first boot | |
DEBUG_PORT.println(F("Enabling GNSS Power")); | |
digitalWrite(GNSS_PWR_PIN, GNSS_PWR_ON); | |
bootMode=1; | |
system_rtc_mem_write(RTCMEMORYSTART, &bootMode, 1); | |
DEBUG_PORT.print(F("Sleeping for ")); | |
DEBUG_PORT.print(sleep_GNSS); | |
DEBUG_PORT.println(F(" Seconds")); | |
DEBUG_PORT.flush(); | |
ESP.deepSleep(sleep_GNSS * 1e6); | |
} | |
if(bootMode == 1) { //Waiting for GNSS 3D Fix | |
if (wait_3d()) { | |
bootMode = 4; | |
} else { | |
bootMode++; | |
} | |
} | |
if(bootMode == 2) {//Waiting for GNSS 2D Fix | |
if (wait_2d()) { | |
bootMode = 4; | |
} else { | |
bootMode++; | |
} | |
} | |
if(bootMode == 3) { //Waiting for RF Fix | |
//@TODO Not implemented | |
bootMode = 5; | |
} | |
if(bootMode == 4) { //Fix Aquired - sending | |
system_rtc_mem_read(RTCMEMORYSTART + 3, &dummy, 4); | |
if (getFence() || dummy + (rf_force * 60) <= getTimestamp()) { | |
bootMode = 5; | |
if (rfSend()) { | |
system_rtc_mem_write(RTCMEMORYSTART + 1, &lat, 4); | |
system_rtc_mem_write(RTCMEMORYSTART + 2, &lon, 4); | |
dummy = getTimestamp(); | |
system_rtc_mem_write(RTCMEMORYSTART + 3, &dummy, 4); | |
bootMode = 0; | |
} else { | |
DEBUG_PORT.println(F("Transfer failed")); | |
bootMode = 0; | |
} | |
}else{ | |
Serial.println(F("Position unchanged, no transfer")); | |
bootMode = 0; | |
} | |
} | |
if(bootMode == 5) { //No fix | |
debugDump(); | |
bootMode = 0; | |
} | |
system_rtc_mem_write(RTCMEMORYSTART, &bootMode, 1); | |
} | |
void loop() { | |
DEBUG_PORT.println(F("Disabling GNSS Power")); | |
digitalWrite(GNSS_PWR_PIN, !GNSS_PWR_ON); | |
DEBUG_PORT.print(F("Sleeping for ")); | |
DEBUG_PORT.print(sleep_off); | |
DEBUG_PORT.println(F(" Minutes")); | |
DEBUG_PORT.flush(); | |
ESP.deepSleep(sleep_off * 60e6); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Wieder prima gemacht!