Skip to content

Instantly share code, notes, and snippets.

@adlerweb
Created November 5, 2017 15:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save adlerweb/8047c1b018aa31b98dd1ce219e82d453 to your computer and use it in GitHub Desktop.
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
#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);
}
@Bluebirdonline
Copy link

Wieder prima gemacht!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment