// CoapLamp - control LEDs across the mesh with CoAP.
//
// Every board runs a tiny CoAP server exposing its built-in LED:
//
//   GET  coap://[node]/led   ->  "on" / "off"
//   POST coap://[node]/led   <-  "on" / "off" / "toggle"
//
// And every 5 seconds each board multicasts POST /led "toggle" to the whole
// mesh (ff03::1) - so all the LEDs blink together, each one toggled by its
// peers over real CoAP/IPv6. Watch the serial monitor to see who toggles
// whom.
//
// This is the same protocol Thread border routers, Matter devices and
// `coap-client` on Linux speak - point any CoAP tool at a node's mesh-local
// address (the NetworkInfo example prints it) and flip its LED.

#include <NiusThread.h>

static const uint8_t kNetworkKey[16] = {
    0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
    0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
};

// --- our LED "resource" ----------------------------------------------------

static bool ledOn = false;

static void applyLed() {
  digitalWrite(LED_BUILTIN, ledOn ? HIGH : LOW);
}

static const char *handleLedGet() {
  return ledOn ? "on" : "off";
}

static void handleLedPost(const char *payload) {
  if (strcmp(payload, "on") == 0) {
    ledOn = true;
  } else if (strcmp(payload, "off") == 0) {
    ledOn = false;
  } else {                       // anything else toggles
    ledOn = !ledOn;
  }
  applyLed();
  Serial.print("POST /led \"");
  Serial.print(payload);
  Serial.print("\" -> LED ");
  Serial.println(ledOn ? "on" : "off");
}

// ----------------------------------------------------------------------------

void setup() {
  Serial.begin(115200);
  while (!Serial && millis() < 3000) {}
  pinMode(LED_BUILTIN, OUTPUT);
  applyLed();

  Thread.begin();
  Thread.setNetwork("ArduinoNRF", 11, 0xBEEF, kNetworkKey);
  Thread.start();

  Thread.coapStart();                       // CoAP server on port 5683
  Thread.onCoapGet("led", handleLedGet);    // GET  /led
  Thread.onCoapPost("led", handleLedPost);  // POST /led

  Serial.println("CoapLamp: attaching...");
}

void loop() {
  static ThreadClass::Role lastRole = ThreadClass::ROLE_DISABLED;
  static uint32_t lastToggle = 0;

  Thread.process();

  if (Thread.role() != lastRole) {
    lastRole = Thread.role();
    Serial.print("role -> ");
    Serial.println(Thread.roleString());
  }

  // Every 5 s, toggle everyone's LED (multicast to all mesh nodes).
  if (Thread.isAttached() && millis() - lastToggle >= 5000) {
    lastToggle = millis();
    Thread.coapPost("ff03::1", "led", "toggle");
    Serial.println("TX  POST ff03::1 /led \"toggle\"");
  }
}
