diff --git a/CAR_GPS_TRACKER.ino b/CAR_GPS_TRACKER.ino index 1026a87..7ed4cfe 100644 --- a/CAR_GPS_TRACKER.ino +++ b/CAR_GPS_TRACKER.ino @@ -1,260 +1,9 @@ -#include +#include "src/app/App.hpp" -// Pins -#define LTE_RX_PIN 16 // ESP32 RX <- SIM7080 TX -#define LTE_TX_PIN 17 // ESP32 TX -> SIM7080 RX -#define PWRKEY_PIN 4 // SIM7080 PWRKEY - -// Network and endpoint -const char* APN = "hologram"; -const char* BASE_URL = "http://laravel-server.lab.audasmedia.com.au"; -const char* PATH = "/api/gps"; - -// -------- Utilities -------- -String sendAT(const String& cmd, uint32_t timeoutMs) { - Serial.print(">> "); Serial.println(cmd); - while (Serial2.available()) (void)Serial2.read(); - Serial2.println(cmd); - - String resp; - uint32_t t0 = millis(); - while (millis() - t0 < timeoutMs) { - while (Serial2.available()) { - char c = (char)Serial2.read(); - resp += c; - Serial.print(c); - t0 = millis(); // extend timeout on input - } - } - resp.trim(); - Serial.println("\n[Resp]\n" + resp); - return resp; -} - -void powerOnSIM7080() { - pinMode(PWRKEY_PIN, OUTPUT); - digitalWrite(PWRKEY_PIN, LOW); - delay(2000); - digitalWrite(PWRKEY_PIN, HIGH); - delay(1000); - digitalWrite(PWRKEY_PIN, LOW); - delay(30000); // full boot -} - -bool waitLTE(uint32_t ms = 120000) { - uint32_t t0 = millis(); - while (millis() - t0 < ms) { - String r = sendAT("AT+CEREG?", 4000); - if (r.indexOf("+CEREG: 0,1") != -1 || r.indexOf("+CEREG: 0,5") != -1) return true; - delay(3000); - } - return false; -} - -// Simple reusable HTTP POST via SH client -bool httpPostSH(const String& baseUrl, const String& path, const String& jsonBody) { - // Configure HTTP client - sendAT("AT+SHCONF=\"URL\",\"" + baseUrl + "\"", 5000); - sendAT("AT+SHCONF=\"BODYLEN\",1024", 2000); - sendAT("AT+SHCONF=\"HEADERLEN\",350", 2000); - - // Connect (no micromanagement; rely on OK) - String r = sendAT("AT+SHCONN", 15000); - if (r.indexOf("OK") == -1) { - Serial.println("SHCONN failed"); - return false; - } - - // Clear and set headers - sendAT("AT+SHCHEAD", 2000); - sendAT("AT+SHAHEAD=\"Content-Type\",\"application/json\"", 2000); - - // Send body - String cmd = "AT+SHBOD=" + String(jsonBody.length()) + ",10000"; - sendAT(cmd, 2000); - Serial2.print(jsonBody); - delay(200); - - // POST (3 = POST) - r = sendAT("AT+SHREQ=\"" + path + "\",3", 20000); - // Expect URC like: +SHREQ: "POST",, - // Print status line if present - int p = r.indexOf("+SHREQ:"); - if (p != -1) { - Serial.println("Status/URC: " + r.substring(p)); - } - - // If there is a body, try to read (non-fatal if none) - sendAT("AT+SHREAD=0,2048", 4000); - - // Disconnect - sendAT("AT+SHDISC", 3000); - return true; -} - -// -------- Arduino setup/loop -------- void setup() { - Serial.begin(115200); - Serial2.begin(9600, SERIAL_8N1, LTE_RX_PIN, LTE_TX_PIN); - Serial.println("--- SIM7080: Simple Connect + HTTP POST ---"); - - powerOnSIM7080(); - - // Basic checks - sendAT("AT", 2000); - sendAT("AT+CMEE=1", 2000); - sendAT("AT+CPIN?", 2000); - sendAT("AT+CSQ", 2000); - - // Force Cat‑M1 + APN attach - sendAT("AT+CNMP=38", 5000); - sendAT("AT+CMNB=1", 5000); - sendAT("AT+CGDCONT=1,\"IP\",\"" + String(APN) + "\"", 5000); - sendAT("AT+CGATT=1", 10000); - - // Wait for LTE registration - if (!waitLTE()) { - Serial.println("No LTE registration; stopping."); - while (true) delay(1000); - } - - // Activate SIM7080 APP PDP (required for HTTP) - sendAT("AT+CNCFG=0,1,\"" + String(APN) + "\"", 5000); - sendAT("AT+CNACT=0,1", 45000); - sendAT("AT+CNACT?", 3000); - - smsSetup(); - - // Optional DNS - sendAT("AT+CDNSCFG=\"8.8.8.8\",\"1.1.1.1\"", 3000); - - // Build your JSON (adjust as needed) - String json = "{\"device_id\":\"sim7080g-01\",\"lat\":-33.865143," - "\"lng\":151.2099,\"speed\":12.5,\"altitude\":30.2}"; - - // Do the POST - bool ok = httpPostSH(BASE_URL, PATH, json); - Serial.println(ok ? "HTTP POST sent (see status above)" : "HTTP POST failed"); - - Serial.println("--- Done ---"); + App::instance().setup(); } void loop() { - // Non-blocking read to capture unsolicited lines like +CMTI - static String urc; - while (Serial2.available()) { - char c = (char)Serial2.read(); - urc += c; - if (c == '\n') { - urc.trim(); - if (urc.startsWith("+CMTI:")) { - // +CMTI: "SM", - int comma = urc.lastIndexOf(','); - if (comma != -1) { - int idx = urc.substring(comma + 1).toInt(); - String body = smsReadAndDelete(idx); - Serial.println("SMS (URC): " + body); - handleSmsCommand(body); - } - } - urc = ""; - } - } - - // Optional periodic poll in case URC was missed - static uint32_t lastPoll = 0; - if (millis() - lastPoll > 60000) { // every 60 s - smsPollUnread(); - lastPoll = millis(); - } - - // Your normal work here... -} - -// Call once after PDP is active (or right after registration) -void smsSetup() { - sendAT("AT+CMGF=1", 2000); // text mode - sendAT("AT+CPMS=\"SM\",\"SM\",\"SM\"", 2000); // SIM storage - sendAT("AT+CNMI=2,1,0,0,0", 2000); // new SMS URC: +CMTI: "SM", - // Optional: show extended text params - // sendAT("AT+CSDH=1", 2000); -} - -// Read & delete one SMS by index; returns the body -String smsReadAndDelete(int idx) { - String r = sendAT("AT+CMGR=" + String(idx), 4000); - // Extract last non-empty line before OK - int okPos = r.lastIndexOf("\nOK"); - String s = (okPos>0) ? r.substring(0, okPos) : r; - int lastLf = s.lastIndexOf('\n'); - if (lastLf != -1) s = s.substring(lastLf + 1); - s.trim(); - - sendAT("AT+CMGD=" + String(idx), 2000); - return s; -} - -// Optional: poll unread SMS (if you want to scan periodically) -void smsPollUnread() { - String list = sendAT("AT+CMGL=\"REC UNREAD\"", 5000); - // list may contain many entries like: - // +CMGL: ,"REC UNREAD",... - int pos = 0; - while (true) { - int p = list.indexOf("+CMGL:", pos); - if (p == -1) break; - int comma = list.indexOf(',', p); - if (comma == -1) break; - // Extract index after "+CMGL: " - int idxStart = list.indexOf(' ', p); - if (idxStart == -1 || idxStart > comma) break; - int idx = list.substring(idxStart + 1, comma).toInt(); - String body = smsReadAndDelete(idx); - Serial.println("SMS (polled): " + body); - handleSmsCommand(body); - pos = comma + 1; - } -} - -void handleSmsCommand(String msg) { - Serial.println("Command received via SMS: " + msg); - - msg.trim(); - if (msg.isEmpty()) { - Serial.println("Empty body"); - return; - } - - // Very simple JSON extraction: look for device_id and speed keys - auto extract = [&](const String& key)->String { - String pat = String("\"") + key + "\":"; - int k = msg.indexOf(pat); - if (k < 0) return ""; - k += pat.length(); - - // Skip quotes/spaces - while (k < (int)msg.length() && (msg[k]==' ' || msg[k]=='\"')) k++; - - // If quoted value - if (k < (int)msg.length() && msg[k-1] == '\"') { - int end = msg.indexOf('\"', k); - if (end > k) return msg.substring(k, end); - } - - // Numeric value - int end = k; - while (end < (int)msg.length() && (isDigit(msg[end]) || msg[end]=='.' || msg[end]=='-' )) end++; - return msg.substring(k, end); - }; - - String deviceId = extract("device_id"); - String speed = extract("speed"); - - Serial.println("Parsed device_id=" + deviceId + " speed=" + speed); - - // Example action: if speed present - if (speed.length()) { - Serial.println("Action: set speed to " + speed); - // TODO: apply speed to your app logic - } + App::instance().loop(); } \ No newline at end of file diff --git a/src/app/App.cpp b/src/app/App.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/app/App.hpp b/src/app/App.hpp new file mode 100644 index 0000000..e69de29 diff --git a/src/app/AppConfig.cpp b/src/app/AppConfig.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/app/AppConfig.hpp b/src/app/AppConfig.hpp new file mode 100644 index 0000000..e69de29 diff --git a/src/core/CommandMgr.cpp b/src/core/CommandMgr.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/core/CommandMgr.hpp b/src/core/CommandMgr.hpp new file mode 100644 index 0000000..e69de29 diff --git a/src/core/HttpClient.cpp b/src/core/HttpClient.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/core/HttpClient.hpp b/src/core/HttpClient.hpp new file mode 100644 index 0000000..e69de29 diff --git a/src/core/Modem.cpp b/src/core/Modem.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/core/Modem.hpp b/src/core/Modem.hpp new file mode 100644 index 0000000..e69de29 diff --git a/src/core/NetMgr.cpp b/src/core/NetMgr.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/core/NetMgr.hpp b/src/core/NetMgr.hpp new file mode 100644 index 0000000..e69de29 diff --git a/src/core/OTAMgr.cpp b/src/core/OTAMgr.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/core/OTAMgr.hpp b/src/core/OTAMgr.hpp new file mode 100644 index 0000000..e69de29 diff --git a/src/core/SmsMgr.cpp b/src/core/SmsMgr.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/core/SmsMgr.hpp b/src/core/SmsMgr.hpp new file mode 100644 index 0000000..e69de29 diff --git a/src/core/Telemetry.cpp b/src/core/Telemetry.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/core/Telemetry.hpp b/src/core/Telemetry.hpp new file mode 100644 index 0000000..e69de29 diff --git a/src/domain/Geofence.cpp b/src/domain/Geofence.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/domain/Geofence.hpp b/src/domain/Geofence.hpp new file mode 100644 index 0000000..e69de29 diff --git a/src/domain/Presence.cpp b/src/domain/Presence.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/domain/Presence.hpp b/src/domain/Presence.hpp new file mode 100644 index 0000000..e69de29 diff --git a/src/hw/EspNowMgr.cpp b/src/hw/EspNowMgr.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/hw/EspNowMgr.hpp b/src/hw/EspNowMgr.hpp new file mode 100644 index 0000000..e69de29 diff --git a/src/hw/GNSS.cpp b/src/hw/GNSS.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/hw/GNSS.hpp b/src/hw/GNSS.hpp new file mode 100644 index 0000000..e69de29 diff --git a/src/hw/GpioCtrl.cpp b/src/hw/GpioCtrl.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/hw/GpioCtrl.hpp b/src/hw/GpioCtrl.hpp new file mode 100644 index 0000000..e69de29 diff --git a/src/hw/PowerMgr.cpp b/src/hw/PowerMgr.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/hw/PowerMgr.hpp b/src/hw/PowerMgr.hpp new file mode 100644 index 0000000..e69de29 diff --git a/src/hw/WiFiMgr.cpp b/src/hw/WiFiMgr.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/hw/WiFiMgr.hpp b/src/hw/WiFiMgr.hpp new file mode 100644 index 0000000..e69de29