#include <Arduino.h> #include <WiFi.h> #include <WiFiUdp.h> #include <Adafruit_NeoPixel.h> #include <coap-simple.h> // hirotakaster CoAP simple library // ===== Wi-Fi creds ===== const char* WIFI_SSID = "UPB-Guest"; const char* WIFI_PASS = ""; // ===== UDP + CoAP objects ===== WiFiUDP udp; Coap coap(udp, 256); // ===== On-board NeoPixel (GPIO 3) ===== constexpr uint8_t kNeoPixelPin = 3; constexpr uint8_t kNeoPixelCount = 1; constexpr uint8_t kNeoPixelBrightness = 128; // 50% to limit power draw Adafruit_NeoPixel g_pixel(kNeoPixelCount, kNeoPixelPin, NEO_GRB + NEO_KHZ800); bool g_pixelReady = false; // ===== Simple LED state ===== static bool g_ledOn = false; void applyLedState() { if (!g_pixelReady) { return; } if (g_ledOn) { g_pixel.setPixelColor(0, g_pixel.Color(255, 255, 255)); } else { g_pixel.setPixelColor(0, 0, 0, 0); } g_pixel.show(); } // ----- helper: send text/plain 2.05 Content ----- static void coapSendText(IPAddress ip, int port, const CoapPacket& req, const char* text) { Serial.printf("[CoAP] Replying to %s:%d mid=%u code=%u tokensz=%u\n", ip.toString().c_str(), port, req.messageid, req.code, req.tokenlen); coap.sendResponse( ip, port, req.messageid, text, strlen(text), COAP_CONTENT, // 2.05 Content COAP_TEXT_PLAIN, req.token, req.tokenlen ); } // ----- /sys/uptime (GET) ----- void h_sys_uptime(CoapPacket &packet, IPAddress ip, int port) { unsigned long secs = millis() / 1000UL; char buf[32]; snprintf(buf, sizeof(buf), "%lu", (unsigned long)secs); coapSendText(ip, port, packet, buf); } // ----- /net/rssi (GET) ----- void h_net_rssi(CoapPacket &packet, IPAddress ip, int port) { long rssi = WiFi.RSSI(); char buf[16]; snprintf(buf, sizeof(buf), "%ld", rssi); coapSendText(ip, port, packet, buf); } // ----- /led (GET state, PUT/POST "on" or "off") ----- void h_led(CoapPacket &packet, IPAddress ip, int port) { if (packet.code == COAP_GET) { coapSendText(ip, port, packet, g_ledOn ? "on" : "off"); return; } if (packet.code == COAP_PUT || packet.code == COAP_POST) { String body; body.reserve(packet.payloadlen + 1); for (size_t i = 0; i < packet.payloadlen; ++i) body += (char)packet.payload[i]; body.trim(); if (body.equalsIgnoreCase("on")) g_ledOn = true; if (body.equalsIgnoreCase("off")) g_ledOn = false; applyLedState(); // Acknowledge change (2.04 Changed) and return new state const char* state = g_ledOn ? "on" : "off"; coap.sendResponse( ip, port, packet.messageid, state, strlen(state), COAP_CHANGED, // 2.04 Changed COAP_TEXT_PLAIN, packet.token, packet.tokenlen ); return; } // Method not allowed coap.sendResponse( ip, port, packet.messageid, "Method Not Allowed", 18, COAP_METHOD_NOT_ALLOWD, COAP_TEXT_PLAIN, packet.token, packet.tokenlen ); } // ----- /echo (POST/PUT echoes payload; GET returns hint) ----- void h_echo(CoapPacket &packet, IPAddress ip, int port) { if (packet.payloadlen == 0 || packet.code == COAP_GET) { const char* hint = "POST/PUT a payload and I'll echo it."; coapSendText(ip, port, packet, hint); return; } coap.sendResponse( ip, port, packet.messageid, (const char*)packet.payload, packet.payloadlen, COAP_CONTENT, // 2.05 Content COAP_TEXT_PLAIN, packet.token, packet.tokenlen ); } // ----- /.well-known/core (RFC 6690 CoRE Link Format) ----- void h_wkc(CoapPacket &packet, IPAddress ip, int port) { Serial.printf("[CoAP] Discovery hit from %s:%d type=%u code=%u accept=%s\n", ip.toString().c_str(), port, packet.type, packet.code, packet.optionnum ? "yes" : "no"); // Advertise resources and basic attributes const char* linkfmt = "</sys/uptime>;rt=\"sys.uptime\";if=\"core.a\";ct=0," "</net/rssi>;rt=\"net.rssi\";if=\"core.a\";ct=0," "</led>;rt=\"dev.led\";if=\"core.a\";ct=0," "</echo>;rt=\"util.echo\";if=\"core.p\";ct=0"; coap.sendResponse( ip, port, packet.messageid, linkfmt, strlen(linkfmt), COAP_CONTENT, COAP_APPLICATION_LINK_FORMAT, // ct=40 packet.token, packet.tokenlen ); } void setup() { Serial.begin(115200); delay(200); Serial.println("\n== CoAP RESTful mapping & discovery (server-only) =="); // Wi-Fi WiFi.mode(WIFI_STA); WiFi.begin(WIFI_SSID, WIFI_PASS); Serial.print("Connecting"); while (WiFi.status() != WL_CONNECTED) { delay(300); Serial.print("."); } Serial.println(); Serial.print("Wi-Fi OK. IP: "); Serial.println(WiFi.localIP()); Serial.printf("Listening for CoAP on udp/%d\n", COAP_DEFAULT_PORT); g_pixel.begin(); g_pixel.setBrightness(kNeoPixelBrightness); g_pixel.clear(); g_pixel.show(); g_pixelReady = true; applyLedState(); // Start CoAP server on udp/5683 udp.begin(5683); // Register resources coap.server(h_sys_uptime, "sys/uptime"); coap.server(h_net_rssi, "net/rssi"); coap.server(h_led, "led"); coap.server(h_echo, "echo"); coap.server(h_wkc, ".well-known/core"); // discovery // Start CoAP stack coap.start(); } void loop() { // Process incoming CoAP requests coap.loop(); }