Files
demeter/esp

Demeter ESP - CoAP Sensor Node with Observe

CoAP (RFC 7252) sensor node firmware for ESP32/ESP8266 running MicroPython, with CoAP Observe (RFC 7641) support for real-time push notifications.

Project Structure

demeter-esp/
├── microcoapy/                  # Extended microCoAPy library
│   ├── __init__.py
│   ├── coap_macros.py           # Constants + COAP_OBSERVE option number
│   ├── coap_option.py           # CoapOption (str-compatible)
│   ├── coap_packet.py           # CoapPacket + setObserve(), getObserveValue(), setMaxAge()
│   ├── coap_reader.py           # Packet parser (unchanged)
│   ├── coap_writer.py           # Packet serializer (unchanged)
│   ├── microcoapy.py            # Main Coap class + Observe server/client methods
│   └── observe_manager.py       # Observer registry with per-resource tracking
├── config.py                    # WiFi, device ID, pin assignments, thresholds
├── sensors.py                   # Hardware abstraction for analog/digital sensors
├── main.py                      # Entry point: CoAP server + sensor loop
└── tests/
    └── test_observe.py          # Observe extension tests (runs on CPython)

CoAP Resources

URI Path Method Observable Description
/sensors/soil_moisture GET Yes (periodic) Soil moisture 0100%
/sensors/temperature GET Yes (periodic) Temperature in °C
/sensors/water_level GET Yes (periodic) Water level 0100%
/events/trigger GET Yes (event-driven) Digital input state change
/device/info GET No Device metadata, uptime
/config/interval GET, PUT No Read/set polling interval

Observe Behavior

  • Periodic sensors (soil, temp, water): NON-confirmable notifications at configurable intervals. Only sent when value changes beyond a configurable threshold.
  • Trigger events: CON-confirmable notifications sent immediately on GPIO state change via hardware interrupt.
  • Max observers: 4 per resource, 8 total (configurable in observe_manager.py).
  • Deregistration: Via Observe option value 1, or automatically on RST response.

Setup

  1. Flash MicroPython to your ESP32/ESP8266
  2. Edit config.py with your WiFi credentials, device ID, and pin assignments
  3. Upload all files to the board (via mpremote, ampy, or Thonny)
  4. The node starts automatically and listens on UDP port 5683

Testing with aiocoap (from Demeter server)

# Simple GET
aiocoap-client coap://ESP_IP/sensors/temperature

# Observe subscription
aiocoap-client coap://ESP_IP/sensors/soil_moisture --observe

# Set polling interval to 10 seconds
echo '{"interval": 10}' | aiocoap-client coap://ESP_IP/config/interval -m PUT

Running Tests

python tests/test_observe.py

Changes from upstream microCoAPy

  • Added COAP_OBSERVE = 6 to option numbers
  • Added setObserve(), getObserveValue(), setMaxAge(), getUriPath() to CoapPacket
  • Added ObserveManager class for server-side observer tracking
  • Added notifyObservers(), observeGet(), observeCancel() to Coap
  • Modified handleIncomingRequest() to detect and handle Observe registrations
  • Added RST handling to deregister observers
  • Made CoapOption accept str input (CPython compatibility)