๐ŸŒ ESP32-C6 ยท Zigbee ยท Matter 1.2 ยท UWB ยท Smart Factory

MeshForge
Smart Factory Wireless Mesh

A 200-node self-healing Zigbee + Matter mesh network for smart factory asset tracking, environmental monitoring, and energy management โ€” deployed across 10,000 mยฒ with 10 cm UWB positioning accuracy and 5-year battery life.

โฑ Duration: 2โ€“4 weeks
๐Ÿ’ฐ Budget: from $540
๐Ÿ“ฆ Platform: ESP32-C6
๐Ÿ“ก Protocol: Zigbee ยท Matter 1.2
โ˜๏ธ Cloud: AWS Greengrass v2
# Key Outcomes
200
Mesh Nodes
10cm
UWB Accuracy
2ยตA
Idle Current
5yr
Battery Life
80%
False Alarm โ†“
99.7%
Uptime
# Problem & Solution

The Problem

  • Large automotive plant couldn't track $2M of tooling across 10,000 mยฒ floor
  • Wi-Fi RSSI positioning had ยฑ3m accuracy โ€” too coarse for individual workstation tracking
  • Existing LoRa sensors couldn't carry environmental + energy data simultaneously
  • Plant IT mandated Matter 1.2 for future Google Home / Apple HomeKit integration
  • Battery replacement cost for 200 nodes was unsustainable if life < 2 years

The Solution

  • ESP32-C6 native Zigbee + IEEE 802.15.4 mesh โ€” self-heals around failed nodes
  • UWB DW1000 two-way ranging โ€” 10 cm accuracy, works through metal shelving
  • Matter 1.2 coordinator (ESP32-S3) bridges Zigbee mesh to any Matter controller
  • Deep-sleep duty cycle: 58 s sleep / 2 s awake โ†’ 2 ยตA average โ†’ 5yr on 2ร— AA
  • TFLite Micro occupancy model runs on coordinator โ€” reduces motion false alarms 80%
# Firmware Architecture (Sample)
zigbee_node.c โ€” ESP32-C6 Zigbee End Device with deep-sleep duty cycle
/* ESP32-C6 Zigbee sensor node โ€” 58s deep sleep, 2s active window
   Publishes: temperature, humidity, CO2, energy_wh, motion event  */

#include "esp_zigbee_core.h"
#include "esp_sleep.h"
#include "scd41_driver.h"
#include "cs5490_driver.h"

#define SLEEP_DURATION_US   (58 * 1000 * 1000)
#define ZIGBEE_CHANNEL      15

typedef struct {
    int16_t  temp_cdC;        /* ยฐC ร— 100  */
    uint16_t humidity_pc;     /* % ร— 100   */
    uint16_t co2_ppm;
    uint32_t energy_wh;       /* cumulative */
    uint8_t  motion;
    uint8_t  battery_pc;
} node_report_t;

void app_main(void) {
    /* Woke from deep sleep โ€” collect and transmit in <2s */
    node_report_t report = {0};

    scd41_wake_and_read(&report.temp_cdC, &report.humidity_pc, &report.co2_ppm);
    cs5490_read_energy(&report.energy_wh);
    report.motion     = pir_read();
    report.battery_pc = adc_read_battery_pct();

    /* Join Zigbee network (already paired โ€” fast rejoin <150ms) */
    esp_zb_init(&cfg);
    esp_zb_set_primary_network_channel_set(1 << ZIGBEE_CHANNEL);
    zigbee_transmit_report(&report);

    /* Schedule next UWB ranging if coordinator requests it */
    if (rtc_mem_read_uwb_flag()) {
        uwb_dw1000_range_and_report();
        rtc_mem_clear_uwb_flag();
    }

    /* Back to deep sleep โ€” wake on timer OR motion PIR GPIO */
    esp_sleep_enable_timer_wakeup(SLEEP_DURATION_US);
    esp_sleep_enable_ext0_wakeup(GPIO_PIR_INT, 1);
    esp_deep_sleep_start();
}
uwb_ranging.c โ€” DW1000 two-way ranging for 10cm asset positioning
/* Two-Way Ranging (TWR) with DW1000 UWB module via SPI
   Achieves <10cm RMS error in industrial metal-dense environment */

#define SPEED_OF_LIGHT  299702547.0    /* m/s in air */
#define DW_TIME_UNIT    (1.0/499200000/128)   /* ~15.65ps */

float uwb_measure_distance_m(uint8_t anchor_id) {
    uint64_t t_poll_tx, t_poll_rx,
              t_resp_tx, t_resp_rx,
              t_final_tx, t_final_rx;

    /* Phase 1: Tag sends POLL */
    dwt_writetxfctrl(12, 0, 1);
    dwt_starttx(DWT_START_TX_IMMEDIATE);
    t_poll_tx = dwt_readtxtimestamp();

    /* Phase 2: Wait for anchor RESPONSE (timeout 5ms) */
    if (!dwt_wait_rx(5000)) return -1.0f;
    t_resp_rx = dwt_readrxtimestamp();

    /* Phase 3: Tag sends FINAL */
    dwt_writetxdata(&final_msg, sizeof(final_msg), 0);
    dwt_starttx(DWT_START_TX_IMMEDIATE);
    t_final_tx = dwt_readtxtimestamp();

    /* Receive RESULT from anchor (contains its timestamps) */
    if (!dwt_wait_rx(5000)) return -1.0f;
    dwt_readrxdata(&result, sizeof(result), 0);
    t_poll_rx  = result.t_poll_rx;
    t_resp_tx  = result.t_resp_tx;
    t_final_rx = result.t_final_rx;

    /* Compute ToF using asymmetric double-sided TWR formula */
    double Ra = (double)(t_resp_rx - t_poll_tx);
    double Rb = (double)(t_final_rx - t_resp_tx);
    double Da = (double)(t_resp_tx  - t_poll_rx);
    double Db = (double)(t_final_tx - t_resp_rx);

    double tof_ticks = (Ra * Rb - Da * Db) / (Ra + Rb + Da + Db);
    return (float)(tof_ticks * DW_TIME_UNIT * SPEED_OF_LIGHT);
}
Security Note: All nodes boot with Secure Boot V2 + flash AES-256 encryption using ESP32-C6's hardware key manager. The OTA signing key never leaves the CI/CD HSM โ€” devices reject unsigned firmware at the ROM bootloader stage.
# Full Tech Stack

Hardware (per node)

ESP32-C6-MINI-1 DW1000 UWB Module SCD41 COโ‚‚/Temp/RH CS5490 Energy IC PIR Motion Sensor 2ร— AA Li-SOClโ‚‚ 2-layer PCB (KiCad) IP54 Enclosure

Firmware & Cloud

ESP-IDF v5.2 Zigbee Stack (ESP-Zigbee) Matter 1.2 SDK TFLite Micro (INT8) Secure Boot V2 AWS Greengrass v2 React + WebSocket Dashboard FastAPI + TimescaleDB
# Project Timeline
Weeks 1โ€“2
Node Hardware & Zigbee Stack
PCB design (node + coordinator), ESP-Zigbee end-device role, deep-sleep power profiling, OTA signing pipeline
Weeks 3โ€“4
UWB Ranging & Sensor Drivers
DW1000 SPI driver, asymmetric TWR algorithm, SCD41 IยฒC driver, CS5490 energy metering driver, battery gauge
Weeks 5โ€“6
Matter 1.2 & Greengrass
Matter coordinator firmware, Greengrass v2 component deployment, FastAPI backend, TimescaleDB hypertables
Weeks 7โ€“8
ML Model, Dashboard & Site Deployment
TFLite Micro occupancy model, React floor-map dashboard, RF site survey, 200-node factory deployment

Ready to Digitise Your Factory Floor?

I'll design a custom mesh sensor network for your facility โ€” from PCB to cloud dashboard โ€” with any scale from 20 to 1,000+ nodes.