Reporter node Updates

This commit is contained in:
programmingPug
2025-01-14 14:58:09 -05:00
parent 0f190a3f26
commit 2de48f1fc9
2 changed files with 284 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
"version": "0.2.0",
"configurations": []
}

View File

@@ -0,0 +1,278 @@
#include <WiFiManager.h> // ESP32 WiFiManager library for captive portal configuration
#include <WiFi.h>
#include <HTTPClient.h>
#include <BLEDevice.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
#include <vector>
using std::vector;
// --- Debug Logging: Uncomment to enable debugging ---
#define DEBUG 1
#ifdef DEBUG
#define DEBUG_PRINT(x) Serial.print(x)
#define DEBUG_PRINTLN(x) Serial.println(x)
#else
#define DEBUG_PRINT(x)
#define DEBUG_PRINTLN(x)
#endif
// Global configuration parameters
String apiServer = "http://192.168.1.193:8000/api/soilmoisture"; // Default API server URL
int scanningDelaySec = 30; // Default scanning delay in seconds
// WiFiManager parameters for additional configuration
WiFiManagerParameter customServer("server", "API Server URL", apiServer.c_str(), 100);
WiFiManagerParameter customScanDelay("scandelay", "Scan Delay (sec)", String(scanningDelaySec).c_str(), 10);
// Create a WiFiManager instance
WiFiManager wifiManager;
// Global variable for the API key (modify as needed)
//const char* apiKey = "YOUR_UNIQUE_API_KEY_HERE";
// BLE configuration
#define SCAN_TIME 5 // Scan duration in seconds for each scan cycle
static BLEUUID serviceUUID("12345678-1234-1234-1234-123456789abc");
static BLEUUID charUUID("abcd1234-5678-1234-5678-abcdef123456");
// Global vector to store discovered sensor BLE addresses
vector<BLEAddress> foundSensors;
// State machine for controlling the reporter node
enum ReporterState {
STATE_SCANNING,
STATE_CONNECTING,
STATE_WAITING
};
ReporterState currentState = STATE_SCANNING;
unsigned long waitStartTime = 0;
// Forward declarations of functions
bool connectToSensor(const BLEAddress &addr);
bool sendDataToAPI(const String &sensorAddress, float moistureValue);
// --- BLE Advertised Device Callback: Collect sensor addresses ---
class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
public:
void onResult(BLEAdvertisedDevice advertisedDevice) override {
if (advertisedDevice.haveServiceUUID() &&
advertisedDevice.isAdvertisingService(serviceUUID)) {
BLEAddress addr = advertisedDevice.getAddress();
// Avoid duplicates
bool alreadyAdded = false;
for (auto &existing : foundSensors) {
if (existing.equals(addr)) {
alreadyAdded = true;
break;
}
}
if (!alreadyAdded) {
DEBUG_PRINT("Found sensor: ");
DEBUG_PRINTLN(addr.toString().c_str());
foundSensors.push_back(addr);
}
}
}
};
// --- Minimal BLE Client Callbacks ---
class MyClientCallbacks : public BLEClientCallbacks {
public:
void onConnect(BLEClient* pClient) override {
DEBUG_PRINTLN("BLE Client connected.");
}
void onDisconnect(BLEClient* pClient) override {
DEBUG_PRINTLN("BLE Client disconnected.");
}
};
void setup() {
Serial.begin(115200);
Serial.println(F("Starting Reporter Node with Captive Portal Configuration..."));
// --- WiFiManager Captive Portal Configuration ---
// Add custom parameters so the user can configure the API server URL and scan delay.
wifiManager.addParameter(&customServer);
wifiManager.addParameter(&customScanDelay);
// Optionally force configuration mode (for example, via a hardware button or by calling resetSettings())
// Uncomment the next line to force configuration mode for testing:
//wifiManager.resetSettings();
// Attempt autoConnect; if theres no saved config, the captive portal AP "ConfigAP" (with password "configpassword") is created.
if (!wifiManager.autoConnect("PlantPalConfig", "plantpal")) {
DEBUG_PRINTLN("Failed to connect and hit timeout. Restarting...");
delay(4000);
ESP.restart();
}
Serial.println(F("WiFi connected via captive portal."));
// Retrieve updated configuration parameters from WiFiManager:
apiServer = String(customServer.getValue());
scanningDelaySec = (customScanDelay.getValue() != nullptr) ? atoi(customScanDelay.getValue()) : scanningDelaySec;
DEBUG_PRINT("Configured API Server: ");
DEBUG_PRINTLN(apiServer);
DEBUG_PRINT("Configured Scan Delay (sec): ");
DEBUG_PRINTLN(scanningDelaySec);
// --- Initialize BLE ---
BLEDevice::init("");
BLEScan* pBLEScan = BLEDevice::getScan();
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setActiveScan(true);
pBLEScan->setInterval(1349);
pBLEScan->setWindow(449);
pBLEScan->start(SCAN_TIME, false);
currentState = STATE_SCANNING;
}
void loop() {
// Optionally, if you're using a hardware watchdog, call esp_task_wdt_reset() here.
// esp_task_wdt_reset();
switch(currentState) {
case STATE_SCANNING: {
// Start a new scan cycle
BLEScan* pBLEScan = BLEDevice::getScan();
pBLEScan->start(SCAN_TIME, false);
pBLEScan->clearResults();
if (!foundSensors.empty()) {
currentState = STATE_CONNECTING;
DEBUG_PRINTLN("Transitioning to STATE_CONNECTING");
}
break;
}
case STATE_CONNECTING: {
if (!foundSensors.empty()) {
BLEAddress addr = foundSensors.front();
foundSensors.erase(foundSensors.begin());
DEBUG_PRINT("Processing sensor: ");
DEBUG_PRINTLN(addr.toString().c_str());
if (connectToSensor(addr)) {
DEBUG_PRINTLN("Sensor processed successfully.");
} else {
DEBUG_PRINTLN("Failed to process sensor.");
}
}
// If no more sensors remain, switch to waiting state.
if (foundSensors.empty()) {
currentState = STATE_WAITING;
waitStartTime = millis();
DEBUG_PRINTLN("All sensors processed. Transitioning to STATE_WAITING.");
}
break;
}
case STATE_WAITING: {
if (millis() - waitStartTime >= (unsigned long)scanningDelaySec * 1000) {
currentState = STATE_SCANNING;
DEBUG_PRINTLN("Transitioning to STATE_SCANNING");
foundSensors.clear();
}
break;
}
default:
break;
}
delay(10); // Small delay to yield time to other tasks
}
bool connectToSensor(const BLEAddress &addr) {
BLEAddress sensorAddr = addr; // Make a local copy for printing
DEBUG_PRINT("Connecting to sensor: ");
DEBUG_PRINTLN(sensorAddr.toString().c_str());
BLEClient* pClient = BLEDevice::createClient();
pClient->setClientCallbacks(new MyClientCallbacks());
if (!pClient->connect(sensorAddr)) {
DEBUG_PRINTLN("Failed to connect.");
pClient->disconnect();
return false;
}
DEBUG_PRINTLN("Connected to sensor.");
pClient->setMTU(517); // Optionally set a larger MTU
BLERemoteService* pService = pClient->getService(serviceUUID);
if (pService == nullptr) {
DEBUG_PRINT("Failed to find service UUID: ");
DEBUG_PRINTLN(serviceUUID.toString().c_str());
pClient->disconnect();
return false;
}
DEBUG_PRINTLN("Service found.");
BLERemoteCharacteristic* pCharacteristic = pService->getCharacteristic(charUUID);
if (pCharacteristic == nullptr) {
DEBUG_PRINT("Failed to find characteristic UUID: ");
DEBUG_PRINTLN(charUUID.toString().c_str());
pClient->disconnect();
return false;
}
DEBUG_PRINTLN("Characteristic found.");
if (pCharacteristic->canRead()) {
String value = pCharacteristic->readValue();
DEBUG_PRINT("Sensor Value: ");
DEBUG_PRINTLN(value);
float moistureValue = value.toFloat();
if (sendDataToAPI(sensorAddr.toString(), moistureValue)) {
DEBUG_PRINTLN("Data sent to API successfully.");
} else {
DEBUG_PRINTLN("Failed to send data to API.");
}
} else {
DEBUG_PRINTLN("Characteristic not readable.");
}
pClient->disconnect();
return true;
}
bool sendDataToAPI(const String &sensorAddress, float moistureValue) {
if (WiFi.status() != WL_CONNECTED) {
DEBUG_PRINTLN("Wi-Fi not connected.");
return false;
}
HTTPClient http;
http.begin(apiServer);
http.addHeader("Content-Type", "application/json");
//http.addHeader("X-API-KEY", apiKey);
// Construct the JSON payload based on the model:
// {
// "deviceId": "sensorAddress",
// "moistureLevel": moistureValue,
// "device": {
// "deviceId": "sensorAddress",
// "nickname": "SoilSensor",
// "soilMoistures": []
// }
// }
String payload = String("{\"deviceId\":\"")
+ sensorAddress
+ String("\",\"moistureLevel\":")
+ String(moistureValue)
+ String("}");
DEBUG_PRINT("Sending payload: ");
DEBUG_PRINTLN(payload);
int httpResponseCode = http.POST(payload);
DEBUG_PRINT("HTTP Response code: ");
DEBUG_PRINTLN(httpResponseCode);
String response = http.getString();
DEBUG_PRINT("Response: ");
DEBUG_PRINTLN(response);
http.end();
return (httpResponseCode > 0);
}