#include <WiFi.h>
#include <HTTPClient.h>
// ==========================================
// 1. SETTINGS - DISTRIBUTED UPGRADE
// ==========================================
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* RUST_SERVER_URL = "http://refried-broadly-landslide.ngrok-free.dev/telemetry";
// 2. FLEET SETTINGS
struct VirtualBattery {
String id;
float v_offset;
float t_offset;
};
VirtualBattery fleet[] = {
{"BAT_001", 0.0f, 0.0f},
{"BAT_002", -0.3f, 5.0f},
{"BAT_003", -0.6f, 15.0f},
{"BAT_004", 0.0f, 20.0f},
{"BAT_005", 0.2f, -5.0f}
};
int fleetSize = 5;
int currentDeviceIndex = 0;
// 3. ML SETTINGS
#define INPUTS 9
// FIX 1: Added [INPUTS] — these are arrays, not scalar floats
float SCALER_MEAN[INPUTS] = {3.5024, 0.2399, 2.3877, 3.9813, -2.0050, 0.0016, 31.9615, 3.6719, 39.4484};
float SCALER_SCALE[INPUTS] = {0.0560, 0.0164, 0.2197, 0.0242, 0.0094, 0.0004, 0.8638, 0.3667, 1.4285};
static float sigmoid(float x) {
if (x >= 0) return 1.0f / (1.0f + expf(-x));
else return expf(x) / (1.0f + expf(x));
}
static float predict(float *x) {
// FIX 2: Added [9] — w is an array, not a scalar float
const float w[9] = {-1.2f, 0.2f, -0.6f, 0.7f, -1.8f, 0.3f, 1.1f, 0.2f, 0.5f};
float b = -0.15f;
float s = b;
for (int i = 0; i < INPUTS; i++) s += w[i] * x[i];
return sigmoid(s);
}
void setup() {
Serial.begin(115200);
Serial.println("SYSTEM READY: Distributed DB Mode");
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" CONNECTED!");
}
void loop() {
if (WiFi.status() == WL_CONNECTED) {
// A. GENERATE DATA
VirtualBattery currentBat = fleet[currentDeviceIndex];
float base_voltage = random(300, 420) / 100.0;
float base_temp = random(2000, 6000) / 100.0;
float sim_current = random(-210, -190) / 100.0;
float sim_voltage = base_voltage + currentBat.v_offset;
float sim_temp = base_temp + currentBat.t_offset;
// FIX 3: features is now a proper array with [INPUTS]
// FIX 4: Each element assigned with correct index [0]..[8]
float features[INPUTS];
features[0] = sim_voltage;
features[1] = 0.2399f;
features[2] = sim_voltage - 0.5f;
features[3] = sim_voltage + 0.5f;
features[4] = sim_current;
features[5] = 0.0016f;
features[6] = sim_temp;
features[7] = 3.67f;
features[8] = sim_temp + 5.0f;
// Normalize
for (int i = 0; i < INPUTS; i++) {
features[i] = (features[i] - SCALER_MEAN[i]) / SCALER_SCALE[i];
}
// FIX 5: features array decays to float* automatically — no cast needed
float prediction_score = predict(features);
String batteryStatus = (prediction_score > 0.5f) ? "ABNORMAL" : "HEALTHY";
// B. SEND DATA VIA JSON POST
WiFiClient client;
HTTPClient http;
http.begin(client, RUST_SERVER_URL);
http.addHeader("Content-Type", "application/json");
http.addHeader("ngrok-skip-browser-warning", "69420");
String jsonPayload = "{";
jsonPayload += "\"id\":\"" + currentBat.id + "\",";
jsonPayload += "\"voltage\":" + String(sim_voltage, 2) + ",";
jsonPayload += "\"current\":" + String(sim_current, 2) + ",";
jsonPayload += "\"temp\":" + String(sim_temp, 2) + ",";
jsonPayload += "\"score\":" + String(prediction_score, 4) + ",";
jsonPayload += "\"status\":\"" + batteryStatus + "\"";
jsonPayload += "}";
Serial.print("Sending (" + currentBat.id + ") to Rust... ");
int httpResponseCode = http.POST(jsonPayload);
if (httpResponseCode > 0) {
Serial.print("HTTP Success: ");
Serial.println(httpResponseCode);
} else {
Serial.print("HTTP Error: ");
Serial.println(http.errorToString(httpResponseCode).c_str());
}
http.end();
currentDeviceIndex = (currentDeviceIndex + 1) % fleetSize;
} else {
Serial.println("WiFi Lost. Reconnecting...");
WiFi.begin(ssid, password);
}
delay(6000);
}