Step 8 is about admitting the network will fail.
Data must survive longer than connectivity.

After Step 7, the system is:

  • reliable
  • observable
  • power-aware

Step 8 improves robustness under long outages and efficiency under good networks by decoupling data production from data delivery.

This step answers:

“What happens to data when the network is unavailable for a long time?”


1. Purpose of Step 8

Without buffering:

  • data is lost during outages
  • sampling must wait for network
  • retry pressure increases

With buffering:

  • sensing continues independently
  • network can recover later
  • sending becomes more efficient

Step 8 is about temporal decoupling.


2. Design Philosophy

Senior rule:

“Never let a slow subsystem stall a fast one.”

Here:

  • Sensor sampling is fast and predictable
  • Network delivery is slow and unreliable

They should not block each other.


3. What Kind of Buffering (Be Conservative)

For embedded devices, start with:

  • Fixed-size ring buffer
  • In-RAM only (no flash yet)
  • Drop-oldest or drop-newest policy

Avoid at this step:

  • flash wear management
  • databases
  • complex queues

Simplicity first.


4. Data Model

Define a single data record:

struct sample_record {
    int32_t temp_mdeg;
    int64_t timestamp_ms;
};

This is the unit of truth.


5. Buffer Context (Ownership)

#define SAMPLE_BUFFER_SIZE 32

struct sample_buffer {
    struct sample_record buf[SAMPLE_BUFFER_SIZE];
    uint8_t head;
    uint8_t tail;
    uint8_t count;
};

Ownership rules:

  • Buffer is owned by the application
  • Only app_run() mutates it
  • No concurrent access

6. Application Context Update

struct app_ctx {
    enum app_state state;
    enum app_state recovery_state;

    uint32_t retry_count;
    k_timeout_t retry_delay;
    int last_error;

    struct sample_buffer samples;

    struct mcp9808_ctx sensor;
    struct net_ctx net;
    struct http_ctx http;
};

Temperature is no longer sent immediately.


7. SAMPLE State Update (Producer)

case APP_STATE_SAMPLE:
    ret = mcp9808_sample(&ctx->sensor, &temp);
    if (ret < 0) {
        ctx->last_error = ret;
        ctx->recovery_state = APP_STATE_SENSOR_INIT;
        ctx->state = APP_STATE_ERROR;
        break;
    }

    buffer_push(&ctx->samples, temp, now_ms());
    ctx->state = APP_STATE_SEND;
    break;

Sampling:

  • always happens
  • never waits for network

8. SEND State Update (Consumer)

case APP_STATE_SEND:
    if (buffer_empty(&ctx->samples)) {
        ctx->state = APP_STATE_WAIT;
        break;
    }

    rec = buffer_peek(&ctx->samples);
    ret = http_send_record(&ctx->http, rec);
    if (ret < 0) {
        ctx->last_error = ret;
        ctx->recovery_state = APP_STATE_NET_INIT;
        ctx->state = APP_STATE_ERROR;
        break;
    }

    buffer_pop(&ctx->samples);
    ctx->retry_count = 0;
    ctx->state = APP_STATE_SEND; /* try next */
    break;

SEND now:

  • drains the buffer
  • sends multiple records per wake
  • stops on failure

9. Batching Policy

Implicit batching occurs because:

  • multiple records are sent in one SEND phase
  • one connection may deliver many samples

No extra batching logic required.


10. Buffer Overflow Policy (Explicit!)

Choose one:

  • Drop oldest (recommended)
  • Drop newest

Example:

if (buffer_full()) {
    buffer_drop_oldest();
    LOG_WRN("Sample buffer full, dropping oldest");
}

Loss is explicit and logged, never silent.


11. Interaction with Power Management

Buffering allows:

  • long sleeps during outages
  • burst sending when awake

This improves battery life significantly.


12. What Step 8 Deliberately Avoids

  • Flash persistence
  • Reordering guarantees
  • QoS logic

Those are later, product-specific steps.


13. Success Criteria for Step 8

Step 8 is complete when:

  • Sampling continues during outages
  • Buffered data is sent after recovery
  • Buffer behavior is predictable
  • Data loss (if any) is explicit

14. Architectural Status After Step 8

After Step 8, the device:

  • tolerates long network outages
  • uses network efficiently
  • separates sensing from delivery

This is common in commercial IoT devices.


15. Next Steps

Optional next steps:

  • Step 9: OTA (MCUboot integration)
  • Step 10: Watchdog integration
  • Step 11: Flash-backed buffering

Core architecture remains unchanged.