Integration Guide

Production-ready code for ESP8266, Arduino, and Raspberry Pi Pico W

Your API Key
Production API URL
https://iot.getyourprojectdone.in/api/insert_data.php
Quick Start
1
Register your devices
Go to Manage Devices and add a device. The device_name you enter must exactly match the name used in your code.
2
Choose your platform
Pick ESP8266, Arduino+ESP8266, or Raspberry Pi Pico W. Download the matching code file below. Your API key is already filled in.
3
Add your sensors
Write one read function per sensor (Step 1 in the code), then add one row to the SENSORS[] table (Step 2). No other changes needed.
4
Set WiFi & server
Fill in WIFI_SSID, WIFI_PASSWORD, and confirm SERVER points to the correct URL. Flash and open Serial Monitor.
Device Code
Your API key is pre-filled in all code blocks below. For sensor snippets (DHT11, HC-SR04, MQ-2, etc.) see the Sensor Library tab.
Board: NodeMCU 1.0 (ESP-12E)  |  Libraries: ESP8266WiFi, ESP8266HTTPClient, ArduinoJson v6.x  |  Baud: 115200
esp8266_monitor.ino
/*
 * ════════════════════════════════════════════════════════════════
 *  ESP8266 — Multi-Sensor Monitor  |  IoT Platform
 *  Production-ready  •  Add unlimited sensors in 2 steps
 * ════════════════════════════════════════════════════════════════
 *
 *  HOW TO ADD A NEW SENSOR:
 *   Step 1 — Write a float function that reads the sensor value
 *   Step 2 — Add one row to the SENSORS[] table below
 *   That's it. No other code needs to change.
 *
 *  BOARD   : NodeMCU 1.0 (ESP-12E Module)
 *  LIBRARIES (Arduino Library Manager):
 *    • ESP8266WiFi        — part of ESP8266 board package
 *    • ESP8266HTTPClient  — part of ESP8266 board package
 *    • ArduinoJson        — by Benoit Blanchon  v6.x
 *
 *  SERIAL MONITOR: 115200 baud
 * ════════════════════════════════════════════════════════════════
 */

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecureBearSSL.h>
#include <ArduinoJson.h>

// ── STEP 0 — Server & credentials ────────────────────────────────
const char* WIFI_SSID     = "Your-SSID";
const char* WIFI_PASSWORD = "Your-Password";
const char* API_KEY       = "";  // from dashboard → API Key pill

// Production server (HTTPS)
const char* SERVER = "https://iot.getyourprojectdone.in";

// Local LAMPP testing — comment out SERVER above, uncomment this:
// const char* SERVER = "http://192.168.x.x/iot_platform";

// Send interval (milliseconds)
const unsigned long SEND_INTERVAL = 10000;  // 10 seconds
// ─────────────────────────────────────────────────────────────────


// ════════════════════════════════════════════════════════════════
//  STEP 1 — Write one float function per sensor
//  Replace the simulated return values with real sensor reads.
//  See sensor_library.h (accessory file) for copy-paste examples
//  for DHT11, HC-SR04, MQ-2, BMP280, DS18B20, LDR, and more.
// ════════════════════════════════════════════════════════════════

float readTemperature() {
  // TODO: e.g. return dht.readTemperature();
  return 28.5;
}

float readHumidity() {
  // TODO: e.g. return dht.readHumidity();
  return 62.0;
}

float readGas() {
  // TODO: e.g. return analogRead(A0) * (5.0/1023.0) * 100;
  return 350.0;
}

float readDistance() {
  // TODO: e.g. return ultrasonicCm(TRIG_PIN, ECHO_PIN);
  return 120.0;
}

// ════════════════════════════════════════════════════════════════
//  STEP 2 — Register sensors in this table
//  Add or remove rows freely — nothing else needs to change.
//
//  Columns:
//    "device_name" — must EXACTLY match name on Devices page
//    "sensor_type" — temperature | humidity | gas | distance |
//                    pressure | light | ph | co2 | motion | custom
//    "unit"        — C | F | % | ppm | cm | hPa | lux | V | etc.
//    readFunction  — the function you wrote in Step 1
// ════════════════════════════════════════════════════════════════

struct Sensor {
  const char* deviceName;
  const char* type;
  const char* unit;
  float (*readFn)();
};

Sensor SENSORS[] = {
// { "device_name",   "sensor_type",  "unit",  readFunction   }
  { "temp_sensor",   "temperature",  "C",     readTemperature },
  { "hum_sensor",    "humidity",     "%",     readHumidity    },
  { "gas_sensor",    "gas",          "ppm",   readGas         },
  { "ultra_sensor",  "distance",     "cm",    readDistance    },

  // Add more rows here — copy the format above
};

// ─────────────────────────────────────────────────────────────────
// Internals — no changes needed below this line
// ─────────────────────────────────────────────────────────────────

const int SENSOR_COUNT = sizeof(SENSORS) / sizeof(SENSORS[0]);

BearSSL::WiFiClientSecure secureClient;
WiFiClient                plainClient;
unsigned long             lastSend  = 0;
int                       cycleNum  = 0;

void setup() {
  Serial.begin(115200);
  delay(300);

  Serial.println(F("\n══════════════════════════════════"));
  Serial.println(F("  ESP8266 Multi-Sensor Monitor"));
  Serial.printf( "  Sensors registered : %d\n", SENSOR_COUNT);
  Serial.printf( "  Send interval      : %lu ms\n", SEND_INTERVAL);
  Serial.println(F("══════════════════════════════════\n"));

  secureClient.setInsecure();  // skip SSL cert verification (fine for IoT)
  connectWiFi();

  lastSend = millis() - SEND_INTERVAL;  // send immediately on first loop
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) {
    Serial.println(F("[WiFi] Disconnected — reconnecting..."));
    connectWiFi();
    return;
  }

  if (millis() - lastSend >= SEND_INTERVAL) {
    lastSend = millis();
    cycleNum++;
    Serial.printf("\n─── Cycle #%d ───────────────────────\n", cycleNum);
    sendAllSensors();
  }
}

// ── Build JSON and POST all sensors in one request ────────────────
void sendAllSensors() {

  // Read all sensor values first
  float values[SENSOR_COUNT];
  for (int i = 0; i < SENSOR_COUNT; i++) {
    values[i] = SENSORS[i].readFn();
    if (isnan(values[i])) {
      Serial.printf("[Sensor] WARNING: %s returned NaN — skipping\n", SENSORS[i].deviceName);
      values[i] = -999;
    }
    Serial.printf("[Sensor] %-16s = %.2f %s\n",
                  SENSORS[i].deviceName, values[i], SENSORS[i].unit);
  }

  // Build JSON: { "api_key":"...", "devices":[{...},{...},...] }
  DynamicJsonDocument doc(512 + SENSOR_COUNT * 120);
  doc["api_key"] = API_KEY;

  JsonArray devices = doc.createNestedArray("devices");
  for (int i = 0; i < SENSOR_COUNT; i++) {
    if (values[i] == -999) continue;  // skip failed reads

    JsonObject device  = devices.createNestedObject();
    device["device_name"] = SENSORS[i].deviceName;

    JsonArray  sensors = device.createNestedArray("sensors");
    JsonObject sensor  = sensors.createNestedObject();
    sensor["type"]  = SENSORS[i].type;
    sensor["value"] = String(values[i], 2);  // 2 decimal places
    sensor["unit"]  = SENSORS[i].unit;
  }

  String payload;
  serializeJson(doc, payload);

  // POST request
  String url = String(SERVER) + "/api/insert_data.php";
  String resp = httpPost(url, payload);

  if (resp.isEmpty()) {
    Serial.println(F("[HTTP] No response — check SERVER and network"));
    return;
  }

  // Parse response
  StaticJsonDocument<256> rdoc;
  if (deserializeJson(rdoc, resp) == DeserializationError::Ok) {
    const char* status = rdoc["status"] | "error";
    const char* msg    = rdoc["message"] | "";
    if (strcmp(status, "success") == 0) {
      Serial.printf("[Server] OK — %s\n", msg);
    } else {
      Serial.printf("[Server] ERROR — %s\n", msg);
      if (rdoc.containsKey("errors")) {
        for (const char* e : rdoc["errors"].as<JsonArray>())
          Serial.printf("         • %s\n", e);
      }
    }
  } else {
    Serial.printf("[Server] Raw: %s\n", resp.c_str());
  }
}

// ── HTTP POST helper ──────────────────────────────────────────────
String httpPost(const String& url, const String& body) {
  bool isHttps = url.startsWith("https");
  HTTPClient http;

  if (isHttps) {
    http.begin(secureClient, url);
  } else {
    http.begin(plainClient, url);
  }

  http.addHeader(F("Content-Type"), F("application/json"));
  http.setTimeout(10000);

  int code = http.POST(body);
  String response = "";

  if (code > 0) {
    response = http.getString();
    if (code != 200)
      Serial.printf("[HTTP] Code: %d\n", code);
  } else {
    Serial.printf("[HTTP] Failed: %s\n", http.errorToString(code).c_str());
  }

  http.end();
  return response;
}

// ── WiFi ──────────────────────────────────────────────────────────
void connectWiFi() {
  Serial.printf("[WiFi] Connecting to %s", WIFI_SSID);
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);

  int t = 0;
  while (WiFi.status() != WL_CONNECTED && t < 40) {
    delay(500); Serial.print('.'); t++;
  }

  if (WiFi.status() == WL_CONNECTED) {
    Serial.println(F(" connected!"));
    Serial.printf("[WiFi] IP: %s  Signal: %d dBm\n",
                  WiFi.localIP().toString().c_str(), WiFi.RSSI());
  } else {
    Serial.println(F(" FAILED — check SSID/password"));
  }
}
esp8266_control.ino
/*
 * ════════════════════════════════════════════════════════════════
 *  ESP8266 — Multi-Device Control  |  IoT Platform
 *  Production-ready  •  Add unlimited control devices in 2 steps
 * ════════════════════════════════════════════════════════════════
 *
 *  HOW IT WORKS:
 *   1. Every POLL_INTERVAL ms → asks server for pending commands
 *   2. Executes each command on the correct GPIO / pin
 *   3. Acknowledges each command back to the server
 *
 *  HOW TO ADD A NEW CONTROL DEVICE:
 *   Step 1 — Write a handler void function for the device
 *   Step 2 — Add one row to DEVICES[] table below
 *
 *  BOARD   : NodeMCU 1.0 (ESP-12E Module)
 *  LIBRARIES: ESP8266WiFi, ESP8266HTTPClient, ArduinoJson v6.x
 *  SERIAL MONITOR: 115200 baud
 * ════════════════════════════════════════════════════════════════
 */

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecureBearSSL.h>
#include <ArduinoJson.h>

// ── STEP 0 — Credentials & server ────────────────────────────────
const char* WIFI_SSID     = "Your-SSID";
const char* WIFI_PASSWORD = "Your-Password";
const char* API_KEY       = "";

// Production server (HTTPS)
const char* SERVER = "https://iot.getyourprojectdone.in";

// Local LAMPP testing:
// const char* SERVER = "http://192.168.x.x/iot_platform";

const unsigned long POLL_INTERVAL = 5000;  // poll commands every 5 s
// ─────────────────────────────────────────────────────────────────


// ════════════════════════════════════════════════════════════════
//  STEP 1 — Define pins and write one handler per control device
//
//  Command types sent by the dashboard:
//    "ON"        → switch ON  (relay, LED, fan, buzzer …)
//    "OFF"       → switch OFF
//    "SET_VALUE" → set to a value (dimmer %, servo angle, PWM …)
//                  cmdValue = the numeric string e.g. "75"
//
//  Handler signature:  void myHandler(const char* type, const char* value)
// ════════════════════════════════════════════════════════════════

// ── Built-in LED (D4 / GPIO2, active LOW) ────────────────────────
#define PIN_LED   LED_BUILTIN  // D4
void handleLED(const char* type, const char* val) {
  if (strcmp(type, "ON")  == 0) { digitalWrite(PIN_LED, LOW);  Serial.println(F("[LED] ON"));  }
  if (strcmp(type, "OFF") == 0) { digitalWrite(PIN_LED, HIGH); Serial.println(F("[LED] OFF")); }
}

// ── Relay (active HIGH — connect relay IN pin here) ───────────────
#define PIN_RELAY D1  // GPIO5
void handleRelay(const char* type, const char* val) {
  if (strcmp(type, "ON")  == 0) { digitalWrite(PIN_RELAY, HIGH); Serial.println(F("[Relay] ON"));  }
  if (strcmp(type, "OFF") == 0) { digitalWrite(PIN_RELAY, LOW);  Serial.println(F("[Relay] OFF")); }
}

// ── Fan / Motor (PWM speed control via SET_VALUE 0-100) ──────────
#define PIN_FAN D2  // GPIO4 — must be PWM-capable
void handleFan(const char* type, const char* val) {
  if (strcmp(type, "ON")  == 0) { analogWrite(PIN_FAN, 255); Serial.println(F("[Fan] FULL ON"));  }
  if (strcmp(type, "OFF") == 0) { analogWrite(PIN_FAN, 0);   Serial.println(F("[Fan] OFF"));       }
  if (strcmp(type, "SET_VALUE") == 0) {
    int pct = constrain(atoi(val), 0, 100);
    int pwm = map(pct, 0, 100, 0, 255);
    analogWrite(PIN_FAN, pwm);
    Serial.printf("[Fan] Speed = %d%%\n", pct);
  }
}

// ── Servo (SET_VALUE = angle 0-180) ──────────────────────────────
// #include <Servo.h>
// Servo myServo;
// #define PIN_SERVO D5
// void handleServo(const char* type, const char* val) {
//   if (strcmp(type, "SET_VALUE") == 0) {
//     int angle = constrain(atoi(val), 0, 180);
//     myServo.write(angle);
//     Serial.printf("[Servo] Angle = %d\n", angle);
//   }
//   if (strcmp(type, "ON")  == 0) { myServo.write(180); }
//   if (strcmp(type, "OFF") == 0) { myServo.write(0);   }
// }

// ── Buzzer (ON/OFF or SET_VALUE = frequency Hz) ───────────────────
// #define PIN_BUZZER D6
// void handleBuzzer(const char* type, const char* val) {
//   if (strcmp(type, "ON")  == 0) { tone(PIN_BUZZER, 1000); }
//   if (strcmp(type, "OFF") == 0) { noTone(PIN_BUZZER);     }
//   if (strcmp(type, "SET_VALUE") == 0) { tone(PIN_BUZZER, atoi(val)); }
// }


// ════════════════════════════════════════════════════════════════
//  STEP 2 — Register control devices in this table
//  "device_name" must EXACTLY match the name on your Devices page
//  (Device Type must be a control type: relay, led, fan, servo …)
// ════════════════════════════════════════════════════════════════

struct ControlDevice {
  const char* deviceName;
  void (*handler)(const char* cmdType, const char* cmdValue);
};

ControlDevice DEVICES[] = {
// { "device_name",  handlerFunction }
  { "led",          handleLED   },
  { "relay",        handleRelay },
  { "fan",          handleFan   },

  // Uncomment to add:
  // { "servo",     handleServo  },
  // { "buzzer",    handleBuzzer },
};

// ─────────────────────────────────────────────────────────────────
// Internals — no changes needed below this line
// ─────────────────────────────────────────────────────────────────

const int DEVICE_COUNT = sizeof(DEVICES) / sizeof(DEVICES[0]);

BearSSL::WiFiClientSecure secureClient;
WiFiClient                plainClient;
unsigned long             lastPoll = 0;

void setup() {
  Serial.begin(115200);
  delay(300);

  Serial.println(F("\n══════════════════════════════════"));
  Serial.println(F("  ESP8266 Multi-Device Control"));
  Serial.printf( "  Devices registered : %d\n", DEVICE_COUNT);
  Serial.printf( "  Poll interval      : %lu ms\n", POLL_INTERVAL);
  Serial.println(F("══════════════════════════════════\n"));

  // Init all control pins
  pinMode(PIN_LED,   OUTPUT); digitalWrite(PIN_LED,   HIGH); // LED off
  pinMode(PIN_RELAY, OUTPUT); digitalWrite(PIN_RELAY, LOW);  // Relay off
  pinMode(PIN_FAN,   OUTPUT); analogWrite(PIN_FAN,    0);    // Fan off

  secureClient.setInsecure();
  connectWiFi();

  lastPoll = millis() - POLL_INTERVAL;
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) {
    Serial.println(F("[WiFi] Disconnected — reconnecting..."));
    connectWiFi();
    return;
  }

  if (millis() - lastPoll >= POLL_INTERVAL) {
    lastPoll = millis();
    pollAllDevices();
  }
}

// ── Poll commands for every registered device ─────────────────────
void pollAllDevices() {
  for (int i = 0; i < DEVICE_COUNT; i++) {
    pollDevice(DEVICES[i].deviceName, DEVICES[i].handler);
  }
}

void pollDevice(const char* deviceName, void(*handler)(const char*, const char*)) {
  // Build poll request
  StaticJsonDocument<128> req;
  req["api_key"]     = API_KEY;
  req["device_name"] = deviceName;
  String payload;
  serializeJson(req, payload);

  String url  = String(SERVER) + "/api/device_poll.php";
  String resp = httpPost(url, payload);

  if (resp.isEmpty()) return;

  StaticJsonDocument<1024> doc;
  if (deserializeJson(doc, resp) != DeserializationError::Ok) return;

  if (strcmp(doc["status"] | "error", "success") != 0) {
    Serial.printf("[Poll] %s — %s\n", deviceName, doc["message"] | "error");
    return;
  }

  JsonArray cmds = doc["commands"].as<JsonArray>();
  if (cmds.size() == 0) return;

  Serial.printf("[Poll] %s — %d command(s)\n", deviceName, (int)cmds.size());

  for (JsonObject cmd : cmds) {
    int         id   = cmd["id"]            | 0;
    const char* type = cmd["command_type"]  | "";
    const char* val  = cmd["command_value"] | "";

    Serial.printf("[CMD]  #%d  %s → type=%s  value=%s\n", id, deviceName, type, val);

    handler(type, val);
    ackCommand(id, "executed");
    delay(50);
  }
}

// ── Acknowledge a command ─────────────────────────────────────────
void ackCommand(int cmdId, const char* status) {
  StaticJsonDocument<128> doc;
  doc["api_key"]    = API_KEY;
  doc["command_id"] = cmdId;
  doc["status"]     = status;

  String payload;
  serializeJson(doc, payload);

  String url  = String(SERVER) + "/api/device_ack.php";
  String resp = httpPost(url, payload);

  if (!resp.isEmpty()) {
    StaticJsonDocument<128> rdoc;
    deserializeJson(rdoc, resp);
    Serial.printf("[Ack]  #%d → %s\n", cmdId, rdoc["message"] | resp.c_str());
  }
}

// ── HTTP POST helper ──────────────────────────────────────────────
String httpPost(const String& url, const String& body) {
  bool isHttps = url.startsWith("https");
  HTTPClient http;

  if (isHttps) http.begin(secureClient, url);
  else         http.begin(plainClient,  url);

  http.addHeader(F("Content-Type"), F("application/json"));
  http.setTimeout(8000);

  int code = http.POST(body);
  String response = "";

  if (code > 0) {
    response = http.getString();
  } else {
    Serial.printf("[HTTP] Error: %s\n", http.errorToString(code).c_str());
  }
  http.end();
  return response;
}

// ── WiFi ──────────────────────────────────────────────────────────
void connectWiFi() {
  Serial.printf("[WiFi] Connecting to %s", WIFI_SSID);
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);

  int t = 0;
  while (WiFi.status() != WL_CONNECTED && t < 40) {
    delay(500); Serial.print('.'); t++;
  }
  if (WiFi.status() == WL_CONNECTED) {
    Serial.println(F(" connected!"));
    Serial.printf("[WiFi] IP: %s\n", WiFi.localIP().toString().c_str());
  } else {
    Serial.println(F(" FAILED"));
  }
}
Board: Arduino Uno / Mega with ESP8266 via SoftwareSerial (D2/D3)  |  Library: WiFiEsp by bportaluri  |  Baud: 9600
ardiuno_monitor.ino
/*
 * ════════════════════════════════════════════════════════════════
 *  Arduino Uno/Mega + ESP8266 Module — Multi-Sensor Monitor
 *  Production-ready  •  Add unlimited sensors in 2 steps
 * ════════════════════════════════════════════════════════════════
 *
 *  WIRING (ESP8266 as serial WiFi via AT commands):
 *   Arduino D2  → ESP8266 TX
 *   Arduino D3  → ESP8266 RX  (use 3.3 V level-shifter)
 *   ESP8266 VCC → 3.3 V (NOT 5 V — will damage module)
 *   ESP8266 GND → GND
 *   ESP8266 CH_EN → 3.3 V
 *
 *  HOW TO ADD A NEW SENSOR:
 *   Step 1 — Write a float function that reads the sensor value
 *   Step 2 — Add one row to the SENSORS[] table below
 *
 *  LIBRARY: WiFiEsp by bportaluri (Arduino Library Manager)
 *  SERIAL MONITOR: 9600 baud
 * ════════════════════════════════════════════════════════════════
 */

#include <WiFiEsp.h>
#include <SoftwareSerial.h>

// ── STEP 0 — Credentials & server ────────────────────────────────
const char* WIFI_SSID     = "Your-SSID";
const char* WIFI_PASSWORD = "Your-Password";
const char* API_KEY       = "";

// Production server
const char* SERVER_HOST = "iot.getyourprojectdone.in";
const int   SERVER_PORT = 443;          // 443 = HTTPS/SSL
// Local LAMPP: SERVER_HOST = "192.168.x.x";  SERVER_PORT = 80;

// API path on the server
const char* API_PATH = "/api/insert_data.php";
// Local LAMPP:  const char* API_PATH = "/iot_platform/api/insert_data.php";

const unsigned long SEND_INTERVAL = 15000;  // 15 seconds (AT commands are slower)
// ─────────────────────────────────────────────────────────────────


// ════════════════════════════════════════════════════════════════
//  STEP 1 — Write one float function per sensor
// ════════════════════════════════════════════════════════════════

float readTemperature() {
  // TODO: e.g. return dht.readTemperature();
  return 27.5;
}

float readHumidity() {
  // TODO: e.g. return dht.readHumidity();
  return 58.0;
}

float readGas() {
  // TODO: e.g. return analogRead(A0) * (5.0 / 1023.0) * 100;
  return 380.0;
}

float readDistance() {
  // TODO: e.g. ultrasonic pulseIn measurement
  return 100.0;
}


// ════════════════════════════════════════════════════════════════
//  STEP 2 — Register sensors in this table
//  "device_name" must EXACTLY match name on your Devices page
// ════════════════════════════════════════════════════════════════

struct Sensor {
  const char* deviceName;
  const char* type;
  const char* unit;
  float (*readFn)();
};

Sensor SENSORS[] = {
// { "device_name",   "sensor_type",  "unit",  readFunction   }
  { "temp_sensor",   "temperature",  "C",     readTemperature },
  { "hum_sensor",    "humidity",     "%",     readHumidity    },
  { "gas_sensor",    "gas",          "ppm",   readGas         },
  { "ultra_sensor",  "distance",     "cm",    readDistance    },
};

// ─────────────────────────────────────────────────────────────────
// Internals
// ─────────────────────────────────────────────────────────────────

const int SENSOR_COUNT = sizeof(SENSORS) / sizeof(SENSORS[0]);

SoftwareSerial espSerial(2, 3);   // RX=D2, TX=D3
WiFiEspClient  client;

unsigned long lastSend = 0;
int cycleNum = 0;

void setup() {
  Serial.begin(9600);
  espSerial.begin(9600);
  delay(2000);

  Serial.println(F("\n══════════════════════════════════"));
  Serial.println(F("  Arduino Multi-Sensor Monitor"));
  Serial.print(F("  Sensors: ")); Serial.println(SENSOR_COUNT);
  Serial.println(F("══════════════════════════════════\n"));

  WiFiEsp.init(&espSerial);

  if (WiFiEsp.status() == WL_NO_SHIELD) {
    Serial.println(F("[ERROR] ESP8266 not detected — check wiring"));
    while (true);
  }

  connectWiFi();
  lastSend = millis() - SEND_INTERVAL;
}

void loop() {
  if (WiFiEsp.status() != WL_CONNECTED) {
    Serial.println(F("[WiFi] Reconnecting..."));
    connectWiFi();
    return;
  }

  if (millis() - lastSend >= SEND_INTERVAL) {
    lastSend = millis();
    cycleNum++;
    Serial.print(F("\n─── Cycle #")); Serial.print(cycleNum); Serial.println(F(" ───"));
    sendAllSensors();
  }
}

// ── Build JSON and POST ───────────────────────────────────────────
void sendAllSensors() {

  float values[SENSOR_COUNT];
  for (int i = 0; i < SENSOR_COUNT; i++) {
    values[i] = SENSORS[i].readFn();
    Serial.print(F("[Sensor] ")); Serial.print(SENSORS[i].deviceName);
    Serial.print(F(" = ")); Serial.print(values[i]); Serial.println(SENSORS[i].unit);
  }

  // Build JSON manually (no ArduinoJson on Uno — saves RAM)
  String json = F("{\"api_key\":\"");
  json += API_KEY;
  json += F("\",\"devices\":[");

  for (int i = 0; i < SENSOR_COUNT; i++) {
    if (i > 0) json += ',';
    json += F("{\"device_name\":\"");
    json += SENSORS[i].deviceName;
    json += F("\",\"sensors\":[{\"type\":\"");
    json += SENSORS[i].type;
    json += F("\",\"value\":\"");
    json += String(values[i], 2);
    json += F("\",\"unit\":\"");
    json += SENSORS[i].unit;
    json += F("\"}]}");
  }
  json += F("]}");

  Serial.print(F("[HTTP] Payload length: ")); Serial.println(json.length());
  sendPost(json);
}

// ── AT-command HTTP/HTTPS POST ────────────────────────────────────
void sendPost(const String& json) {
  bool useSSL = (SERVER_PORT == 443);

  // Build HTTP request string
  String request  = F("POST ");
  request += API_PATH;
  request += F(" HTTP/1.1\r\nHost: ");
  request += SERVER_HOST;
  request += F("\r\nContent-Type: application/json\r\nContent-Length: ");
  request += json.length();
  request += F("\r\nConnection: close\r\n\r\n");
  request += json;

  // Connect via SSL or TCP
  int ok;
  if (useSSL) {
    ok = client.connectSSL(SERVER_HOST, SERVER_PORT);
  } else {
    ok = client.connect(SERVER_HOST, SERVER_PORT);
  }

  if (!ok) {
    Serial.println(F("[HTTP] Connection failed"));
    return;
  }

  client.print(request);
  Serial.println(F("[HTTP] Request sent — reading response..."));

  // Read response (skip headers, grab body)
  String body = "";
  bool   inBody = false;
  unsigned long t = millis();

  while ((client.connected() || client.available()) && millis() - t < 8000) {
    while (client.available()) {
      String line = client.readStringUntil('\n');
      if (!inBody && line == "\r") { inBody = true; continue; }
      if (inBody) { body += line; }
    }
  }
  client.stop();

  body.trim();
  Serial.print(F("[Server] ")); Serial.println(body.isEmpty() ? F("(no body)") : body.c_str());
}

// ── WiFi ──────────────────────────────────────────────────────────
void connectWiFi() {
  Serial.print(F("[WiFi] Connecting to "));
  Serial.print(WIFI_SSID);

  int status = WL_IDLE_STATUS;
  int tries  = 0;
  while (status != WL_CONNECTED && tries < 10) {
    status = WiFiEsp.begin(WIFI_SSID, WIFI_PASSWORD);
    Serial.print('.');
    tries++;
  }

  if (WiFiEsp.status() == WL_CONNECTED) {
    Serial.println(F(" connected!"));
    Serial.print(F("[WiFi] IP: "));
    Serial.println(WiFiEsp.localIP());
  } else {
    Serial.println(F(" FAILED — check SSID/password or ESP8266 baud rate"));
  }
}
ardiuno_control.ino
/*
 * ════════════════════════════════════════════════════════════════
 *  Arduino Uno/Mega + ESP8266 Module — Multi-Device Control
 *  Production-ready  •  Add unlimited control devices in 2 steps
 * ════════════════════════════════════════════════════════════════
 *
 *  WIRING:
 *   Arduino D2 → ESP8266 TX   |   Arduino D3 → ESP8266 RX
 *   ESP8266 VCC → 3.3 V       |   ESP8266 GND → GND
 *   ESP8266 CH_EN → 3.3 V
 *
 *  HOW TO ADD A NEW CONTROL DEVICE:
 *   Step 1 — Write a void handler function for the device
 *   Step 2 — Add one row to DEVICES[] table below
 *
 *  LIBRARY: WiFiEsp by bportaluri (Library Manager)
 *  SERIAL MONITOR: 9600 baud
 * ════════════════════════════════════════════════════════════════
 */

#include <WiFiEsp.h>
#include <SoftwareSerial.h>

// ── STEP 0 — Credentials & server ────────────────────────────────
const char* WIFI_SSID     = "Your-SSID";
const char* WIFI_PASSWORD = "Your-Password";
const char* API_KEY       = "";

const char* SERVER_HOST   = "iot.getyourprojectdone.in";
const int   SERVER_PORT   = 443;
// Local LAMPP: SERVER_HOST = "192.168.x.x";  SERVER_PORT = 80;

const char* POLL_PATH = "/api/device_poll.php";
const char* ACK_PATH  = "/api/device_ack.php";
// Local LAMPP:
// const char* POLL_PATH = "/iot_platform/api/device_poll.php";
// const char* ACK_PATH  = "/iot_platform/api/device_ack.php";

const unsigned long POLL_INTERVAL = 8000;  // poll every 8 s
// ─────────────────────────────────────────────────────────────────


// ════════════════════════════════════════════════════════════════
//  STEP 1 — Define pins and write one handler per device
//
//  Handler receives: cmdType ("ON" | "OFF" | "SET_VALUE")
//                    cmdValue (numeric string, e.g. "75")
// ════════════════════════════════════════════════════════════════

// ── Built-in LED (pin 13, active HIGH on most Arduino boards) ────
#define PIN_LED 13
void handleLED(const char* type, const char* val) {
  if (strcmp(type, "ON")  == 0) { digitalWrite(PIN_LED, HIGH); Serial.println(F("[LED] ON"));  }
  if (strcmp(type, "OFF") == 0) { digitalWrite(PIN_LED, LOW);  Serial.println(F("[LED] OFF")); }
}

// ── Relay (active HIGH) ───────────────────────────────────────────
#define PIN_RELAY 7
void handleRelay(const char* type, const char* val) {
  if (strcmp(type, "ON")  == 0) { digitalWrite(PIN_RELAY, HIGH); Serial.println(F("[Relay] ON"));  }
  if (strcmp(type, "OFF") == 0) { digitalWrite(PIN_RELAY, LOW);  Serial.println(F("[Relay] OFF")); }
}

// ── Fan via PWM (SET_VALUE = 0-100 percent) ───────────────────────
// Arduino Uno PWM pins: 3,5,6,9,10,11
#define PIN_FAN 9
void handleFan(const char* type, const char* val) {
  if (strcmp(type, "ON")  == 0) { analogWrite(PIN_FAN, 255); Serial.println(F("[Fan] FULL ON")); }
  if (strcmp(type, "OFF") == 0) { analogWrite(PIN_FAN, 0);   Serial.println(F("[Fan] OFF"));     }
  if (strcmp(type, "SET_VALUE") == 0) {
    int pct = constrain(atoi(val), 0, 100);
    analogWrite(PIN_FAN, map(pct, 0, 100, 0, 255));
    Serial.print(F("[Fan] Speed = ")); Serial.print(pct); Serial.println('%');
  }
}

// ── Buzzer (ON/OFF or SET_VALUE = duration ms) ────────────────────
// #define PIN_BUZZER 6
// void handleBuzzer(const char* type, const char* val) {
//   if (strcmp(type, "ON")  == 0) { digitalWrite(PIN_BUZZER, HIGH); }
//   if (strcmp(type, "OFF") == 0) { digitalWrite(PIN_BUZZER, LOW);  }
//   if (strcmp(type, "SET_VALUE") == 0) {
//     digitalWrite(PIN_BUZZER, HIGH);
//     delay(atoi(val));
//     digitalWrite(PIN_BUZZER, LOW);
//   }
// }


// ════════════════════════════════════════════════════════════════
//  STEP 2 — Register devices in this table
// ════════════════════════════════════════════════════════════════

struct ControlDevice {
  const char* deviceName;
  void (*handler)(const char* cmdType, const char* cmdValue);
};

ControlDevice DEVICES[] = {
// { "device_name",  handlerFunction }
  { "led",          handleLED   },
  { "relay",        handleRelay },
  { "fan",          handleFan   },

  // Uncomment to add:
  // { "buzzer",    handleBuzzer },
};

// ─────────────────────────────────────────────────────────────────
// Internals
// ─────────────────────────────────────────────────────────────────

const int DEVICE_COUNT = sizeof(DEVICES) / sizeof(DEVICES[0]);

SoftwareSerial espSerial(2, 3);
WiFiEspClient  client;
unsigned long  lastPoll = 0;

void setup() {
  Serial.begin(9600);
  espSerial.begin(9600);
  delay(2000);

  Serial.println(F("\n══════════════════════════════════"));
  Serial.println(F("  Arduino Multi-Device Control"));
  Serial.print(F("  Devices : ")); Serial.println(DEVICE_COUNT);
  Serial.println(F("══════════════════════════════════\n"));

  pinMode(PIN_LED,   OUTPUT); digitalWrite(PIN_LED,   LOW);
  pinMode(PIN_RELAY, OUTPUT); digitalWrite(PIN_RELAY, LOW);
  pinMode(PIN_FAN,   OUTPUT); analogWrite(PIN_FAN,    0);

  WiFiEsp.init(&espSerial);
  if (WiFiEsp.status() == WL_NO_SHIELD) {
    Serial.println(F("[ERROR] ESP8266 not detected"));
    while (true);
  }

  connectWiFi();
  lastPoll = millis() - POLL_INTERVAL;
}

void loop() {
  if (WiFiEsp.status() != WL_CONNECTED) {
    connectWiFi(); return;
  }

  if (millis() - lastPoll >= POLL_INTERVAL) {
    lastPoll = millis();
    for (int i = 0; i < DEVICE_COUNT; i++) {
      pollDevice(DEVICES[i].deviceName, DEVICES[i].handler);
    }
  }
}

// ── Poll one device ───────────────────────────────────────────────
void pollDevice(const char* devName, void(*handler)(const char*, const char*)) {
  // Build request JSON
  String json = F("{\"api_key\":\"");
  json += API_KEY;
  json += F("\",\"device_name\":\"");
  json += devName;
  json += F("\"}");

  String resp = doPost(POLL_PATH, json);
  if (resp.isEmpty()) return;

  // Find "commands" array manually (avoids ArduinoJson RAM on Uno)
  // If response contains "command_type" there are commands
  if (resp.indexOf(F("command_type")) == -1) return;

  Serial.print(F("[Poll] ")); Serial.print(devName);
  Serial.println(F(" — commands found"));

  // Parse up to 5 commands
  int searchFrom = 0;
  for (int c = 0; c < 5; c++) {
    int idIdx   = resp.indexOf(F("\"id\":"),  searchFrom);
    if (idIdx == -1) break;

    // Extract id
    int idStart = idIdx + 5;
    int idEnd   = resp.indexOf(',', idStart);
    int cmdId   = resp.substring(idStart, idEnd).toInt();

    // Extract command_type
    int typeIdx = resp.indexOf(F("\"command_type\":\""), searchFrom);
    if (typeIdx == -1) break;
    int tStart  = typeIdx + 16;
    int tEnd    = resp.indexOf('"', tStart);
    String cmdType = resp.substring(tStart, tEnd);

    // Extract command_value
    int valIdx  = resp.indexOf(F("\"command_value\":\""), searchFrom);
    int vStart  = valIdx + 17;
    int vEnd    = resp.indexOf('"', vStart);
    String cmdVal = (valIdx != -1) ? resp.substring(vStart, vEnd) : "";

    Serial.print(F("[CMD]  #")); Serial.print(cmdId);
    Serial.print(F("  type=")); Serial.print(cmdType);
    Serial.print(F("  value=")); Serial.println(cmdVal);

    handler(cmdType.c_str(), cmdVal.c_str());
    ackCommand(cmdId, "executed");

    // Move search cursor past this command
    searchFrom = tEnd + 1;
    delay(100);
  }
}

// ── Acknowledge command ───────────────────────────────────────────
void ackCommand(int cmdId, const char* status) {
  String json = F("{\"api_key\":\"");
  json += API_KEY;
  json += F("\",\"command_id\":");
  json += cmdId;
  json += F(",\"status\":\"");
  json += status;
  json += F("\"}");

  String resp = doPost(ACK_PATH, json);
  Serial.print(F("[Ack]  #")); Serial.print(cmdId);
  Serial.print(F(" → "));
  Serial.println(resp.isEmpty() ? F("no response") : resp.c_str());
}

// ── AT-command POST (SSL or plain HTTP) ──────────────────────────
String doPost(const char* path, const String& json) {
  bool useSSL = (SERVER_PORT == 443);

  String request  = F("POST ");
  request += path;
  request += F(" HTTP/1.1\r\nHost: ");
  request += SERVER_HOST;
  request += F("\r\nContent-Type: application/json\r\nContent-Length: ");
  request += json.length();
  request += F("\r\nConnection: close\r\n\r\n");
  request += json;

  int ok = useSSL ? client.connectSSL(SERVER_HOST, SERVER_PORT)
                  : client.connect(SERVER_HOST, SERVER_PORT);
  if (!ok) { Serial.println(F("[HTTP] Connect failed")); return ""; }

  client.print(request);

  String body = "";
  bool   inBody = false;
  unsigned long t = millis();

  while ((client.connected() || client.available()) && millis() - t < 8000) {
    while (client.available()) {
      String line = client.readStringUntil('\n');
      if (!inBody && line == "\r") { inBody = true; continue; }
      if (inBody) body += line;
    }
  }
  client.stop();
  body.trim();
  return body;
}

// ── WiFi ──────────────────────────────────────────────────────────
void connectWiFi() {
  Serial.print(F("[WiFi] Connecting"));
  int status = WL_IDLE_STATUS, tries = 0;
  while (status != WL_CONNECTED && tries < 10) {
    status = WiFiEsp.begin(WIFI_SSID, WIFI_PASSWORD);
    Serial.print('.'); tries++;
  }
  if (WiFiEsp.status() == WL_CONNECTED) {
    Serial.println(F(" connected!"));
    Serial.print(F("[WiFi] IP: ")); Serial.println(WiFiEsp.localIP());
  } else {
    Serial.println(F(" FAILED"));
  }
}
Board: Raspberry Pi Pico W  |  Runtime: MicroPython (flash firmware first)  |  Tool: Thonny IDE or rshell
raspberry_monitor.py
"""
════════════════════════════════════════════════════════════════
 Raspberry Pi Pico W — Multi-Sensor Monitor  (MicroPython)
 Production-ready  •  Add unlimited sensors in 2 steps
════════════════════════════════════════════════════════════════

 HOW TO ADD A NEW SENSOR:
  Step 1 — Write a function that returns a float value
  Step 2 — Add one dict to the SENSORS list below

 FIRMWARE: MicroPython for Pico W
   https://micropython.org/download/rp2-pico-w/

 NOTE: For a full Raspberry Pi (Linux/Raspbian), see the note
 at the bottom of this file — uses the standard `requests` lib.
════════════════════════════════════════════════════════════════
"""

import network
import urequests
import ujson
import utime

# ── STEP 0 — Credentials & server ────────────────────────────────
WIFI_SSID     = "Your-SSID"
WIFI_PASSWORD = "Your-Password"
API_KEY       = ""   # from dashboard → API Key pill

# Production server (HTTPS)
SERVER = "https://iot.getyourprojectdone.in"

# Local LAMPP testing — comment out SERVER above, use this:
# SERVER = "http://192.168.x.x/iot_platform"

SEND_INTERVAL = 10   # seconds between sends
# ─────────────────────────────────────────────────────────────────


# ════════════════════════════════════════════════════════════════
#  STEP 1 — Write one function per sensor.
#  Each function must return a float.
#  Replace the simulated values with real sensor reads.
#  See the SENSOR SNIPPETS section at the bottom for DHT11,
#  DS18B20, BMP280, HC-SR04, MQ-2, LDR, and more.
# ════════════════════════════════════════════════════════════════

def read_temperature():
    # TODO: e.g. from machine import ADC (onboard sensor)
    # or use DHT11/DHT22 library
    return 27.5   # simulated

def read_humidity():
    # TODO: e.g. dht_sensor.humidity()
    return 62.0   # simulated

def read_gas():
    # TODO: e.g. ADC(26).read_u16() / 65535 * 100
    return 350.0  # simulated

def read_distance():
    # TODO: HC-SR04 pulse measurement
    return 115.0  # simulated


# ════════════════════════════════════════════════════════════════
#  STEP 2 — Register sensors in this list.
#  Add or remove dicts freely — nothing else needs to change.
#
#  Keys:
#    "device"  — must EXACTLY match name on your Devices page
#    "type"    — temperature | humidity | gas | distance |
#                pressure | light | ph | co2 | motion | custom
#    "unit"    — C | F | % | ppm | cm | hPa | lux | V | etc.
#    "fn"      — the function you wrote in Step 1
# ════════════════════════════════════════════════════════════════

SENSORS = [
    # { "device": "device_name", "type": "sensor_type", "unit": "unit", "fn": read_function },
    { "device": "temp_sensor",  "type": "temperature", "unit": "C",   "fn": read_temperature },
    { "device": "hum_sensor",   "type": "humidity",    "unit": "%",   "fn": read_humidity    },
    { "device": "gas_sensor",   "type": "gas",         "unit": "ppm", "fn": read_gas         },
    { "device": "ultra_sensor", "type": "distance",    "unit": "cm",  "fn": read_distance    },

    # Add more dicts here:
    # { "device": "pressure_sensor", "type": "pressure", "unit": "hPa", "fn": read_pressure },
]

# ─────────────────────────────────────────────────────────────────
# Internals — no changes needed below this line
# ─────────────────────────────────────────────────────────────────

def connect_wifi():
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    if wlan.isconnected():
        return wlan

    print(f"[WiFi] Connecting to {WIFI_SSID}", end="")
    wlan.connect(WIFI_SSID, WIFI_PASSWORD)

    for _ in range(30):
        if wlan.isconnected():
            break
        utime.sleep(1)
        print(".", end="")

    if wlan.isconnected():
        print(f" connected!\n[WiFi] IP: {wlan.ifconfig()[0]}")
    else:
        print("\n[WiFi] FAILED — check SSID/password")

    return wlan


def send_all_sensors():
    # Read all values
    readings = []
    for s in SENSORS:
        try:
            val = s["fn"]()
            readings.append((s, round(float(val), 2)))
            print(f"[Sensor] {s['device']:<18} = {val} {s['unit']}")
        except Exception as e:
            print(f"[Sensor] {s['device']} ERROR: {e}")

    if not readings:
        print("[Send] No valid readings — skipping")
        return

    # Build payload
    payload = {
        "api_key": API_KEY,
        "devices": [
            {
                "device_name": s["device"],
                "sensors": [
                    {
                        "type":  s["type"],
                        "value": str(val),
                        "unit":  s["unit"]
                    }
                ]
            }
            for s, val in readings
        ]
    }

    url  = SERVER + "/api/insert_data.php"
    body = ujson.dumps(payload)

    print(f"[HTTP] POST → {url}")

    try:
        resp = urequests.post(
            url,
            data=body,
            headers={"Content-Type": "application/json"}
        )
        result = resp.text
        resp.close()
        print(f"[Server] {result}")

    except OSError as e:
        print(f"[HTTP] ERROR: {e}")
        print("       Check SERVER and network connection")


def main():
    print("\n══════════════════════════════════")
    print("  Pico W Multi-Sensor Monitor")
    print(f"  Sensors  : {len(SENSORS)}")
    print(f"  Interval : {SEND_INTERVAL}s")
    print("══════════════════════════════════\n")

    wlan = connect_wifi()
    cycle = 0

    while True:
        if not wlan.isconnected():
            print("[WiFi] Connection lost — reconnecting...")
            wlan = connect_wifi()

        cycle += 1
        print(f"\n─── Cycle #{cycle} ───────────────────────")
        send_all_sensors()
        utime.sleep(SEND_INTERVAL)


main()


# ════════════════════════════════════════════════════════════════
#  SENSOR SNIPPETS — copy what you need into Step 1
# ════════════════════════════════════════════════════════════════
#
#  ── Onboard temperature (Pico W only) ──────────────────────────
#  from machine import ADC
#  _adc = ADC(4)
#  def read_temperature():
#      v = _adc.read_u16() * 3.3 / 65535
#      return round(27 - (v - 0.706) / 0.001721, 1)
#
#  ── DHT11 / DHT22 ───────────────────────────────────────────────
#  import dht
#  from machine import Pin
#  _dht = dht.DHT11(Pin(15))   # or DHT22
#  def read_temperature():
#      _dht.measure(); return _dht.temperature()
#  def read_humidity():
#      _dht.measure(); return _dht.humidity()
#
#  ── HC-SR04 Ultrasonic ──────────────────────────────────────────
#  from machine import Pin, time_pulse_us
#  _trig = Pin(14, Pin.OUT)
#  _echo = Pin(15, Pin.IN)
#  def read_distance():
#      _trig.low(); utime.sleep_us(2)
#      _trig.high(); utime.sleep_us(10); _trig.low()
#      dur = time_pulse_us(_echo, 1, 30000)
#      return round(dur / 58.0, 1) if dur > 0 else 0
#
#  ── MQ-2 Gas sensor (ADC) ───────────────────────────────────────
#  from machine import ADC
#  _adc = ADC(26)              # GP26 = ADC0
#  def read_gas():
#      return round(_adc.read_u16() / 65535 * 100, 1)
#
#  ── LDR Light sensor ────────────────────────────────────────────
#  from machine import ADC
#  _ldr = ADC(27)              # GP27 = ADC1
#  def read_light():
#      return round(_ldr.read_u16() / 65535 * 100, 1)
#
# ════════════════════════════════════════════════════════════════
#  FOR FULL RASPBERRY PI (Raspbian / Linux)
#  Replace the entire file with this simpler version:
#
#  pip3 install requests
#
#  import requests, time
#
#  SERVER = "https://iot.getyourprojectdone.in"
#  API_KEY = ""
#
#  SENSORS = [
#      { "device": "temp_sensor",  "type": "temperature", "unit": "C",  "fn": lambda: 28.5 },
#      { "device": "hum_sensor",   "type": "humidity",    "unit": "%",  "fn": lambda: 60.0 },
#  ]
#
#  while True:
#      payload = {
#          "api_key": API_KEY,
#          "devices": [
#              {"device_name": s["device"],
#               "sensors": [{"type": s["type"], "value": str(s["fn"]()), "unit": s["unit"]}]}
#              for s in SENSORS
#          ]
#      }
#      r = requests.post(SERVER + "/api/insert_data.php", json=payload)
#      print(r.json())
#      time.sleep(10)
# ════════════════════════════════════════════════════════════════
raspberry_control.py
"""
════════════════════════════════════════════════════════════════
 Raspberry Pi Pico W — Multi-Device Control  (MicroPython)
 Production-ready  •  Add unlimited control devices in 2 steps
════════════════════════════════════════════════════════════════

 HOW IT WORKS:
  Every POLL_INTERVAL seconds → fetches pending commands
  Calls the matching handler function for each command
  Acknowledges each command back to the server

 HOW TO ADD A NEW CONTROL DEVICE:
  Step 1 — Write a handler function for the device
  Step 2 — Add one dict to DEVICES list below

 Command types from dashboard:
   "ON"        → switch on  (relay, LED, buzzer …)
   "OFF"       → switch off
   "SET_VALUE" → set to a level (fan speed %, servo angle …)
════════════════════════════════════════════════════════════════
"""

import network
import urequests
import ujson
import utime
from machine import Pin, PWM

# ── STEP 0 — Credentials & server ────────────────────────────────
WIFI_SSID     = "Your-SSID"
WIFI_PASSWORD = "Your-Password"
API_KEY       = ""

SERVER = "https://iot.getyourprojectdone.in"
# Local LAMPP: SERVER = "http://192.168.x.x/iot_platform"

POLL_INTERVAL = 5   # seconds
# ─────────────────────────────────────────────────────────────────


# ════════════════════════════════════════════════════════════════
#  STEP 1 — Define pins and write one handler per device
#
#  Handler signature:  def handle_xxx(cmd_type, cmd_value):
#    cmd_type  : "ON" | "OFF" | "SET_VALUE"
#    cmd_value : string, e.g. "75" for SET_VALUE
# ════════════════════════════════════════════════════════════════

# ── Onboard LED (GP25 on Pico W) ─────────────────────────────────
_led = Pin("LED", Pin.OUT)   # built-in LED on Pico W
def handle_led(cmd_type, cmd_value):
    if cmd_type == "ON":
        _led.on()
        print("[LED] ON")
    elif cmd_type == "OFF":
        _led.off()
        print("[LED] OFF")

# ── External Relay (active HIGH — wire to any GP pin) ─────────────
_relay = Pin(15, Pin.OUT, value=0)   # GP15
def handle_relay(cmd_type, cmd_value):
    if cmd_type == "ON":
        _relay.on()
        print("[Relay] ON")
    elif cmd_type == "OFF":
        _relay.off()
        print("[Relay] OFF")

# ── Fan via PWM (SET_VALUE = 0-100 percent) ───────────────────────
_fan_pwm = PWM(Pin(14))              # GP14
_fan_pwm.freq(1000)
def handle_fan(cmd_type, cmd_value):
    if cmd_type == "ON":
        _fan_pwm.duty_u16(65535)
        print("[Fan] FULL ON")
    elif cmd_type == "OFF":
        _fan_pwm.duty_u16(0)
        print("[Fan] OFF")
    elif cmd_type == "SET_VALUE":
        pct = max(0, min(100, int(cmd_value)))
        duty = int(pct / 100 * 65535)
        _fan_pwm.duty_u16(duty)
        print(f"[Fan] Speed = {pct}%")

# ── Servo (SET_VALUE = angle 0-180) ──────────────────────────────
# _servo_pwm = PWM(Pin(13))    # GP13
# _servo_pwm.freq(50)          # 50 Hz for servo
# def _angle_to_duty(deg):
#     # 0.5ms=0° → 2.5ms=180° at 50Hz (period=20ms)
#     us = 500 + int(deg / 180 * 2000)
#     return int(us / 20000 * 65535)
# def handle_servo(cmd_type, cmd_value):
#     if cmd_type == "SET_VALUE":
#         angle = max(0, min(180, int(cmd_value)))
#         _servo_pwm.duty_u16(_angle_to_duty(angle))
#         print(f"[Servo] Angle = {angle}°")
#     elif cmd_type == "ON":  _servo_pwm.duty_u16(_angle_to_duty(180))
#     elif cmd_type == "OFF": _servo_pwm.duty_u16(_angle_to_duty(0))

# ── Buzzer ────────────────────────────────────────────────────────
# _buzzer = Pin(12, Pin.OUT, value=0)
# def handle_buzzer(cmd_type, cmd_value):
#     if cmd_type == "ON":        _buzzer.on()
#     elif cmd_type == "OFF":     _buzzer.off()
#     elif cmd_type == "SET_VALUE":
#         _buzzer.on(); utime.sleep_ms(int(cmd_value)); _buzzer.off()


# ════════════════════════════════════════════════════════════════
#  STEP 2 — Register devices in this list
#  "device" must EXACTLY match name on your Devices page
#  (Device Type must be a control type: relay, led, fan, servo…)
# ════════════════════════════════════════════════════════════════

DEVICES = [
    # { "device": "device_name", "handler": handle_function },
    { "device": "led",   "handler": handle_led   },
    { "device": "relay", "handler": handle_relay },
    { "device": "fan",   "handler": handle_fan   },

    # Uncomment to add:
    # { "device": "servo",   "handler": handle_servo  },
    # { "device": "buzzer",  "handler": handle_buzzer },
]

# ─────────────────────────────────────────────────────────────────
# Internals — no changes needed below this line
# ─────────────────────────────────────────────────────────────────

def connect_wifi():
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    if wlan.isconnected():
        return wlan

    print(f"[WiFi] Connecting to {WIFI_SSID}", end="")
    wlan.connect(WIFI_SSID, WIFI_PASSWORD)
    for _ in range(30):
        if wlan.isconnected():
            break
        utime.sleep(1); print(".", end="")

    if wlan.isconnected():
        print(f" connected!\n[WiFi] IP: {wlan.ifconfig()[0]}")
    else:
        print("\n[WiFi] FAILED")
    return wlan


def http_post(url, body):
    try:
        resp = urequests.post(
            url,
            data=body,
            headers={"Content-Type": "application/json"}
        )
        text = resp.text
        resp.close()
        return text
    except OSError as e:
        print(f"[HTTP] Error: {e}")
        return ""


def poll_device(device_name, handler):
    payload = ujson.dumps({"api_key": API_KEY, "device_name": device_name})
    url  = SERVER + "/api/device_poll.php"
    resp = http_post(url, payload)

    if not resp:
        return

    try:
        data = ujson.loads(resp)
    except Exception:
        print(f"[Poll] Parse error: {resp}")
        return

    if data.get("status") != "success":
        print(f"[Poll] {device_name} — {data.get('message', 'error')}")
        return

    commands = data.get("commands", [])
    if not commands:
        return

    print(f"[Poll] {device_name} — {len(commands)} command(s)")

    for cmd in commands:
        cmd_id  = cmd.get("id", 0)
        c_type  = cmd.get("command_type", "")
        c_value = cmd.get("command_value", "")

        print(f"[CMD]  #{cmd_id}  {device_name} → type={c_type}  value={c_value}")

        try:
            handler(c_type, c_value)
            ack_status = "executed"
        except Exception as e:
            print(f"[CMD]  Handler error: {e}")
            ack_status = "failed"

        ack_command(cmd_id, ack_status)
        utime.sleep_ms(100)


def ack_command(cmd_id, status):
    payload = ujson.dumps({
        "api_key":    API_KEY,
        "command_id": cmd_id,
        "status":     status
    })
    resp = http_post(SERVER + "/api/device_ack.php", payload)
    print(f"[Ack]  #{cmd_id} → {resp if resp else 'no response'}")


def main():
    print("\n══════════════════════════════════")
    print("  Pico W Multi-Device Control")
    print(f"  Devices  : {len(DEVICES)}")
    print(f"  Interval : {POLL_INTERVAL}s")
    print("══════════════════════════════════\n")

    wlan = connect_wifi()
    cycle = 0

    while True:
        if not wlan.isconnected():
            print("[WiFi] Reconnecting...")
            wlan = connect_wifi()

        cycle += 1
        print(f"\n─── Poll cycle #{cycle} ───")

        for dev in DEVICES:
            poll_device(dev["device"], dev["handler"])

        utime.sleep(POLL_INTERVAL)


main()
Copy any section into your .ino monitor file as Step 1. Each section includes the library #include, pin define, and the read function — ready to drop into SENSORS[].
sensor_library.h — accessory snippets
/*
 * ════════════════════════════════════════════════════════════════
 *  sensor_library.h — Sensor Accessory Code
 *  Copy-paste any section you need into esp8266_monitor.ino
 *  or ardiuno_monitor.ino as your Step 1 read functions.
 * ════════════════════════════════════════════════════════════════
 *
 *  USAGE:
 *   1. Install the required library for your sensor
 *   2. Copy the ENTIRE section (includes + pin define + function)
 *      into your .ino file above the SENSORS[] table
 *   3. Use the read function in the SENSORS[] table
 *
 *  AVAILABLE SENSORS:
 *   • DHT11 / DHT22    — Temperature + Humidity
 *   • BMP280           — Temperature + Pressure
 *   • DS18B20          — Temperature (waterproof)
 *   • HC-SR04          — Ultrasonic Distance
 *   • MQ-2 / MQ-135   — Gas / Air Quality (analog)
 *   • LDR              — Light level (analog)
 *   • Soil Moisture    — Analog moisture sensor
 *   • ACS712           — Current sensor (analog)
 *   • PIR              — Motion detection (digital)
 *   • Water Level      — Analog water level
 * ════════════════════════════════════════════════════════════════
 */

#pragma once

// ════════════════════════════════════════════════════════════════
//  DHT11 / DHT22 — Temperature & Humidity
//  Library: "DHT sensor library" by Adafruit  (Library Manager)
//  Also install: "Adafruit Unified Sensor"
// ════════════════════════════════════════════════════════════════
/*
#include <DHT.h>

#define DHT_PIN   D5        // change to your data pin
#define DHT_TYPE  DHT11     // DHT11 or DHT22

DHT dht(DHT_PIN, DHT_TYPE);

void initDHT() { dht.begin(); }

float readDHT_Temp() {
  float t = dht.readTemperature();
  return isnan(t) ? -1 : t;
}

float readDHT_Humidity() {
  float h = dht.readHumidity();
  return isnan(h) ? -1 : h;
}

// Add to SENSORS[]:
// { "temp_sensor",     "temperature", "C",  readDHT_Temp     },
// { "humidity_sensor", "humidity",    "%",  readDHT_Humidity },

// Add to setup():
//   initDHT();
*/


// ════════════════════════════════════════════════════════════════
//  BMP280 — Temperature & Barometric Pressure
//  Library: "Adafruit BMP280 Library"  (Library Manager)
//  Wiring: SDA → D2 (GPIO4), SCL → D1 (GPIO5)  [I2C]
// ════════════════════════════════════════════════════════════════
/*
#include <Wire.h>
#include <Adafruit_BMP280.h>

Adafruit_BMP280 bmp;

void initBMP() {
  if (!bmp.begin(0x76)) {  // try 0x77 if 0x76 fails
    Serial.println("[BMP280] Not found — check wiring");
  }
}

float readBMP_Temp()     { return bmp.readTemperature(); }   // °C
float readBMP_Pressure() { return bmp.readPressure() / 100.0; }  // hPa

// Add to SENSORS[]:
// { "temp_sensor",     "temperature", "C",   readBMP_Temp     },
// { "pressure_sensor", "pressure",    "hPa", readBMP_Pressure },

// Add to setup():
//   Wire.begin(); initBMP();
*/


// ════════════════════════════════════════════════════════════════
//  DS18B20 — Waterproof Temperature Sensor (1-Wire)
//  Library: "DallasTemperature" + "OneWire"  (Library Manager)
//  Wiring: Data → any digital pin, 4.7 kΩ pullup to 3.3 V
// ════════════════════════════════════════════════════════════════
/*
#include <OneWire.h>
#include <DallasTemperature.h>

#define DS18B20_PIN  D4

OneWire           oneWire(DS18B20_PIN);
DallasTemperature ds18b20(&oneWire);

void initDS18B20() { ds18b20.begin(); }

float readDS18B20() {
  ds18b20.requestTemperatures();
  float t = ds18b20.getTempCByIndex(0);
  return (t == DEVICE_DISCONNECTED_C) ? -1 : t;
}

// Add to SENSORS[]:
// { "temp_sensor", "temperature", "C", readDS18B20 },

// Add to setup():
//   initDS18B20();
*/


// ════════════════════════════════════════════════════════════════
//  HC-SR04 — Ultrasonic Distance Sensor
//  No library needed — uses pulseIn()
//  Wiring: VCC → 5V, TRIG → D6, ECHO → D7 (use voltage divider!)
// ════════════════════════════════════════════════════════════════
/*
#define ULTRASONIC_TRIG  D6   // GPIO12
#define ULTRASONIC_ECHO  D7   // GPIO13

void initUltrasonic() {
  pinMode(ULTRASONIC_TRIG, OUTPUT);
  pinMode(ULTRASONIC_ECHO, INPUT);
}

float readUltrasonic() {
  // Send pulse
  digitalWrite(ULTRASONIC_TRIG, LOW);
  delayMicroseconds(2);
  digitalWrite(ULTRASONIC_TRIG, HIGH);
  delayMicroseconds(10);
  digitalWrite(ULTRASONIC_TRIG, LOW);

  // Measure echo (timeout = 30 ms → max ~500 cm)
  long duration = pulseIn(ULTRASONIC_ECHO, HIGH, 30000);
  if (duration == 0) return -1;  // out of range
  return duration / 58.0;        // convert to cm
}

// Add to SENSORS[]:
// { "distance_sensor", "distance", "cm", readUltrasonic },

// Add to setup():
//   initUltrasonic();
*/


// ════════════════════════════════════════════════════════════════
//  MQ-2 / MQ-135 — Gas / Air Quality Sensor (Analog)
//  No library needed — uses analogRead()
//  Wiring: AO → A0 (ESP8266 only has one ADC pin)
//  Note: ESP8266 ADC is 0-1V (use voltage divider if needed)
// ════════════════════════════════════════════════════════════════
/*
#define GAS_PIN  A0

float readGas() {
  int raw = analogRead(GAS_PIN);          // 0–1023
  return raw * (100.0 / 1023.0);          // 0–100% scale
  // For actual ppm, use sensor datasheet calibration curve
}

// Add to SENSORS[]:
// { "gas_sensor", "gas", "%", readGas },
*/


// ════════════════════════════════════════════════════════════════
//  LDR — Light Dependent Resistor (Analog)
//  Wiring: LDR + 10 kΩ resistor voltage divider → A0
// ════════════════════════════════════════════════════════════════
/*
#define LDR_PIN  A0

float readLDR() {
  int raw = analogRead(LDR_PIN);          // 0 = dark, 1023 = bright
  return raw * (100.0 / 1023.0);          // 0–100 lux scale (approximate)
}

// Add to SENSORS[]:
// { "light_sensor", "light", "lux", readLDR },
*/


// ════════════════════════════════════════════════════════════════
//  Soil Moisture Sensor (Analog)
//  Wiring: AO → A0
//  Output: 0% = dry, 100% = wet (inverted — raw 1023=dry, 0=wet)
// ════════════════════════════════════════════════════════════════
/*
#define SOIL_PIN  A0

float readSoilMoisture() {
  int raw = analogRead(SOIL_PIN);
  return (1023 - raw) * (100.0 / 1023.0);  // invert so 100% = wet
}

// Add to SENSORS[]:
// { "soil_sensor", "moisture", "%", readSoilMoisture },
*/


// ════════════════════════════════════════════════════════════════
//  ACS712 — Current Sensor (5A / 20A / 30A variants) (Analog)
//  Wiring: OUT → A0
// ════════════════════════════════════════════════════════════════
/*
#define ACS712_PIN       A0
#define ACS712_SENSITIVITY  0.185   // V/A for 5A module (use 0.100 for 20A, 0.066 for 30A)
#define ACS712_VREF         2.5     // V  (midpoint at VCC/2)

float readCurrent() {
  int   raw     = analogRead(ACS712_PIN);
  float voltage = raw * (3.3 / 1023.0);          // ADC voltage
  float current = (voltage - ACS712_VREF) / ACS712_SENSITIVITY;
  return abs(current);
}

// Add to SENSORS[]:
// { "current_sensor", "current", "A", readCurrent },
*/


// ════════════════════════════════════════════════════════════════
//  PIR — Motion Detection Sensor (Digital)
//  Wiring: OUT → D5 (any digital pin)
//  Returns 1.0 = motion detected, 0.0 = no motion
// ════════════════════════════════════════════════════════════════
/*
#define PIR_PIN  D5

void initPIR() { pinMode(PIR_PIN, INPUT); }

float readPIR() {
  return digitalRead(PIR_PIN) ? 1.0 : 0.0;
}

// Add to SENSORS[]:
// { "pir_sensor", "motion", "", readPIR },

// Add to setup():
//   initPIR();
*/


// ════════════════════════════════════════════════════════════════
//  Water Level Sensor (Analog)
//  Wiring: S (signal) → A0
// ════════════════════════════════════════════════════════════════
/*
#define WATER_PIN  A0

float readWaterLevel() {
  int raw = analogRead(WATER_PIN);
  return raw * (100.0 / 1023.0);   // 0–100%
}

// Add to SENSORS[]:
// { "water_sensor", "water_level", "%", readWaterLevel },
*/
API Reference
Endpoint Method Purpose Required JSON Fields Response
/api/insert_data.php POST Send sensor readings from device to platform api_key, devices[]device_name, sensors[]type, value, unit {"status":"success"}
/api/device_poll.php POST Fetch pending commands for a control device api_key, device_name {"status":"success","commands":[{id, command_type, command_value}]}
/api/device_ack.php POST Acknowledge a command was executed api_key, command_id, status ("executed"|"failed") {"status":"success","message":"Command #N marked as executed"}
/api/fetch_data.php POST Read stored sensor data (used by charts) api_key + optional ?limit=N JSON array of sensor readings
Supported Sensor Types

Use these exact strings as the type field in your sensor definition. The chart will color-code automatically.

temperaturehumiditygasdistancepressurelightphco2motioncurrentvoltagemoisturewater_levelspeedweightflowsoundvibrationstatuscustom
Control Device Types
Device TypeDashboard WidgetCommands Sent
relay / switch / ledToggle switchON / OFF
fan / dimmerSlider (0–100)SET_VALUE with 0–100
servoSlider (0–180)SET_VALUE with 0–180
motorSlider (0–100)SET_VALUE with 0–100
rgbColor pickerSET_VALUE with hex color
buzzerToggle switchON / OFF
lock / valveToggle switchON / OFF