Core loop: telemetry A sec, command poll B sec; car-power OFF -> no-power POST + sleep C; WiFi home connect placeholder; GNSS placeholders
This commit is contained in:
@ -2,51 +2,100 @@
|
|||||||
#include "src/core/HttpClient.hpp"
|
#include "src/core/HttpClient.hpp"
|
||||||
#include "src/core/SmsMgr.hpp"
|
#include "src/core/SmsMgr.hpp"
|
||||||
#include "src/core/CommandMgr.hpp"
|
#include "src/core/CommandMgr.hpp"
|
||||||
|
#include "src/core/Telemetry.hpp"
|
||||||
|
#include "src/app/AppConfig.hpp"
|
||||||
|
#include "src/hw/PowerMgr.hpp"
|
||||||
|
#include "src/hw/WiFiMgr.hpp"
|
||||||
|
|
||||||
static String DEVICE_IMEI = "";
|
static AppConfig CFG;
|
||||||
|
|
||||||
static const char* APN = "hologram";
|
|
||||||
static const char* BASE_URL = "http://laravel-server.lab.audasmedia.com.au";
|
|
||||||
static const char* PATH = "/api/gps";
|
|
||||||
|
|
||||||
static String queryImei() {
|
static String queryImei() {
|
||||||
String r = NetMgr::sendAT("AT+CGSN", 3000);
|
String r = NetMgr::sendAT("AT+CGSN", 3000);
|
||||||
// Response often includes the IMEI line + OK; take the first 15-digit line
|
int s = -1;
|
||||||
int s = 0;
|
for (int i = 0; i < (int)r.length() - 14; ++i) { if (isDigit(r[i])) { s = i; break; } }
|
||||||
for (int i=0;i<(int)r.length();++i) {
|
if (s >= 0) { String imei = r.substring(s, s + 15); imei.trim(); return imei; }
|
||||||
if (isDigit(r[i])) { s = i; break; }
|
return "";
|
||||||
}
|
|
||||||
String imei = r.substring(s, s+15);
|
|
||||||
imei.trim();
|
|
||||||
return imei;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
Serial2.begin(9600, SERIAL_8N1, 16, 17); // RX=16, TX=17
|
Serial2.begin(9600, SERIAL_8N1, 16, 17);
|
||||||
|
|
||||||
NetMgr::powerOnSIM7080(4); // PWRKEY pin 4
|
// 1) Radio attach
|
||||||
NetMgr::attachAndPdp(APN); // LTE reg + CNACT + DNS
|
NetMgr::powerOnSIM7080(4);
|
||||||
SmsMgr::setup(); // enable text mode + URCs
|
NetMgr::attachAndPdp(CFG.apn.c_str());
|
||||||
|
SmsMgr::setup();
|
||||||
|
|
||||||
DEVICE_IMEI = queryImei();
|
// 2) Identity
|
||||||
if (DEVICE_IMEI.length()==0) DEVICE_IMEI = "860016049744324"; // fallback if needed
|
CFG.imei = queryImei();
|
||||||
|
if (CFG.imei.isEmpty()) CFG.imei = "860016049744324";
|
||||||
|
|
||||||
CommandMgr::configure(BASE_URL, DEVICE_IMEI);
|
// 3) Init power sim
|
||||||
|
PowerMgr::init(true); // car power ON initially (simulate)
|
||||||
|
|
||||||
double lat,lng,alt,spd,hdg;
|
// 4) Command manager config
|
||||||
Telemetry::readGNSS(lat,lng,alt,spd,hdg);
|
CommandMgr::configure(CFG.baseUrl, CFG.imei);
|
||||||
String json = Telemetry::buildJson(DEVICE_IMEI, lat,lng,alt,spd,hdg);
|
|
||||||
|
|
||||||
//String json =
|
// GNSS power on (if applicable later)
|
||||||
// "{\"device_id\":\"sim7080g-01\",\"lat\":-33.865143,"
|
NetMgr::sendAT("AT+CGNSPWR=1", 2000);
|
||||||
// "\"lng\":151.2099,\"speed\":12.5,\"altitude\":30.2}";
|
|
||||||
HttpClient::postJson(BASE_URL, PATH, json);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
SmsMgr::pollUrc(); // non‑blocking URC scan; handles +CMTI
|
static uint32_t lastTelemetryMs = 0;
|
||||||
CommandMgr::poll(30000); // every 30s
|
static uint32_t lastPollMs = 0;
|
||||||
SmsMgr::pollUnread(); // optional safety poll
|
static bool noPowerSent = false;
|
||||||
delay(250);
|
|
||||||
|
SmsMgr::pollUrc(); // SMS commands
|
||||||
|
|
||||||
|
bool carOn = PowerMgr::isCarPowerOn();
|
||||||
|
|
||||||
|
// When car power is ON
|
||||||
|
if (carOn) {
|
||||||
|
noPowerSent = false; // reset for next OFF cycle
|
||||||
|
|
||||||
|
// Telemetry every A seconds
|
||||||
|
if (millis() - lastTelemetryMs >= CFG.telemetryPeriodSec * 1000UL) {
|
||||||
|
double lat, lng, alt, spd, hdg;
|
||||||
|
Telemetry::read(lat, lng, alt, spd, hdg);
|
||||||
|
String json = Telemetry::buildJson(CFG.imei, lat, lng, alt, spd, hdg, carOn);
|
||||||
|
HttpClient::postJson(CFG.baseUrl, CFG.telemetryPath, json);
|
||||||
|
lastTelemetryMs = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Poll commands every B seconds
|
||||||
|
if (millis() - lastPollMs >= CFG.commandPollSec * 1000UL) {
|
||||||
|
CommandMgr::poll(CFG.commandPollSec * 1000UL); // uses its own timer, but call to force
|
||||||
|
lastPollMs = millis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// When car power is OFF
|
||||||
|
else {
|
||||||
|
if (!noPowerSent) {
|
||||||
|
String np = Telemetry::buildNoPowerJson(CFG.imei);
|
||||||
|
HttpClient::postJson(CFG.baseUrl, CFG.telemetryPath, np);
|
||||||
|
noPowerSent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// One last command poll to check instructions (e.g., connect Wi‑Fi, sleep C seconds)
|
||||||
|
CommandMgr::poll(0);
|
||||||
|
|
||||||
|
// Placeholder: if server requested home Wi‑Fi, connect
|
||||||
|
if (CFG.atHomeRequested) {
|
||||||
|
bool ok = WiFiMgr::connectHome("Aussie Broadband 8729", "Ffdfmunfca", 15000);
|
||||||
|
Serial.println(ok ? "Home WiFi connected" : "Home WiFi failed");
|
||||||
|
if (ok) {
|
||||||
|
// You can add local/LAN interactions here; then disconnect:
|
||||||
|
WiFiMgr::disconnect();
|
||||||
|
}
|
||||||
|
CFG.atHomeRequested = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go to deep sleep (placeholder – currently just delay)
|
||||||
|
PowerMgr::deepSleep(CFG.sleepSec);
|
||||||
|
delay(CFG.sleepSec * 1000UL);
|
||||||
|
// On real deep sleep, code resumes at setup() on wake
|
||||||
|
// If simulating, continue loop
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(100);
|
||||||
}
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
struct AppConfig {
|
||||||
|
// periods (seconds)
|
||||||
|
uint32_t telemetryPeriodSec = 30; // A
|
||||||
|
uint32_t commandPollSec = 30; // B
|
||||||
|
uint32_t sleepSec = 300; // C
|
||||||
|
|
||||||
|
// device state
|
||||||
|
bool carPowerOn = true; // simulate for now
|
||||||
|
bool atHomeRequested = false; // server may request WiFi connect
|
||||||
|
|
||||||
|
// networking
|
||||||
|
String apn = "hologram";
|
||||||
|
String baseUrl = "http://laravel-server.lab.audasmedia.com.au";
|
||||||
|
String telemetryPath = "/api/gps";
|
||||||
|
|
||||||
|
// identity
|
||||||
|
String imei; // set at runtime
|
||||||
|
};
|
||||||
@ -1,6 +1,9 @@
|
|||||||
|
// Telemetry.hpp
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
namespace Telemetry {
|
namespace Telemetry {
|
||||||
bool readGNSS(double& lat, double& lng, double& alt, double& speed, double& heading);
|
bool read(double& lat, double& lng, double& alt, double& speed, double& heading);
|
||||||
String buildJson(const String& imei, double lat, double lng, double alt, double speed, double heading);
|
String buildJson(const String& imei, double lat, double lng, double alt, double speed, double heading, bool carPower);
|
||||||
|
String buildNoPowerJson(const String& imei);
|
||||||
}
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
// PowerMgr.cpp
|
||||||
|
#include "PowerMgr.hpp"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
bool carOn = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace PowerMgr {
|
||||||
|
void init(bool carPowerInitial){ carOn = carPowerInitial; }
|
||||||
|
bool isCarPowerOn(){ return carOn; }
|
||||||
|
void setCarPower(bool on){ carOn = on; }
|
||||||
|
void deepSleep(uint32_t /*sec*/) {
|
||||||
|
// placeholder: implement esp_deep_sleep() later
|
||||||
|
// For now, just delay to simulate
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
// PowerMgr.hpp
|
||||||
|
#pragma once
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
namespace PowerMgr {
|
||||||
|
void init(bool carPowerInitial);
|
||||||
|
bool isCarPowerOn();
|
||||||
|
void setCarPower(bool on); // simulate change
|
||||||
|
// called before deep sleep; placeholder
|
||||||
|
void deepSleep(uint32_t sec);
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
// WiFiMgr.cpp
|
||||||
|
#include "WiFiMgr.hpp"
|
||||||
|
#include <WiFi.h> // ESP32 WiFi
|
||||||
|
|
||||||
|
namespace WiFiMgr {
|
||||||
|
bool connectHome(const char* ssid, const char* psk, uint32_t timeoutMs) {
|
||||||
|
WiFi.mode(WIFI_STA);
|
||||||
|
WiFi.begin(ssid, psk);
|
||||||
|
uint32_t t0 = millis();
|
||||||
|
while (WiFi.status() != WL_CONNECTED && millis() - t0 < timeoutMs) {
|
||||||
|
delay(200);
|
||||||
|
}
|
||||||
|
return WiFi.status() == WL_CONNECTED;
|
||||||
|
}
|
||||||
|
void disconnect() {
|
||||||
|
WiFi.disconnect(true, true);
|
||||||
|
WiFi.mode(WIFI_OFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
// WiFiMgr.hpp
|
||||||
|
#pragma once
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
namespace WiFiMgr {
|
||||||
|
bool connectHome(const char* ssid, const char* psk, uint32_t timeoutMs = 15000);
|
||||||
|
void disconnect();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user