Siddhant Kumar
Project 067 · Industrial

Worker Safety Wearable.

A wearable that watches for the two things that kill plant workers — toxic gas and a man-down fall — and raises a located, acknowledged alarm to a control room in seconds.

Advanced 14–22 hours 32 min read GasWearableSafety
Jump to source Bill of materials
Worker Safety Wearable — reference build illustration MCU VCC · GND · SIG · NC
Difficulty
Advanced
Build time
14–22 hours
Indicative cost
₹3,500 – ₹6,000 per wearable
Platform
ESP32 DevKit V1 (ESP-WROOM-32)
Category
Industrial
Last updated
28 July 2026
Contents — 26 sections

Project Overview

A wearable that watches for the two things that kill plant workers — toxic gas and a man-down fall — and raises a located, acknowledged alarm to a control room in seconds.

Two hazards account for a grim share of industrial fatalities, and both are ones a person often cannot save themselves from. Toxic or oxygen-deficient atmospheres — hydrogen sulphide in a sewer, carbon monoxide in a boiler room, oxygen displaced in a tank — can incapacitate a worker in seconds, before they even realise, and a rescuer who rushes in unprotected becomes the next casualty. A man-down event — a fall, a collapse, an incapacitation — leaves a worker unable to call for help, and if they are alone or unseen, minutes of delay can be fatal. This wearable watches for both continuously and, when it detects danger, raises a located, acknowledged alarm to a control room fast enough to matter.

It carries a gas sensor (or several) for the specific hazards of the workplace — H₂S, CO, combustible gas, low oxygen — alarming the moment concentration crosses a danger threshold, both to the worker (loud/vibrating) and to the control room. It carries an accelerometer that recognises the signatures of a man-down event: the impact and sudden stillness of a fall, or prolonged no-motion suggesting incapacitation, with a pre-alarm the worker can cancel if they are fine (to reduce false alarms). And it carries a manual panic button for any other emergency. Every alarm goes out located (who, and where) and is acknowledged by the control room so the worker knows help is coming and the system knows a human is responding.

Being a life-safety device for the two hazards above, its design is dominated by reliability and honest limits. It runs a full shift on battery with battery supervision, uses a communication path with coverage across the plant (LoRa/mesh, sometimes cellular), and — this must be stated plainly — a DIY wearable is not a certified gas detector or a substitute for the intrinsically-safe, calibrated, professionally-certified safety equipment that hazardous industrial work legally requires. Real gas detection in explosive/toxic atmospheres demands certified instruments; this project is an educational build and, at most, a supplementary awareness layer. Within that honest frame, though, it embodies the right architecture: sense the killers, alarm the worker and a control room instantly, locate and acknowledge, and never pretend a hobby device replaces the certified gear that lives are actually trusted to.

Automated machinery on a factory production line
A wearable watching for toxic gas and man-down events — the two hazards a worker often cannot survive alone. Photograph sourced from Wikimedia Commons — Factory automation.jpg. Reused under the licence stated on that page; please check it before republishing.

What this project does

  • Monitors for toxic/combustible gas and low oxygen (workplace-specific)
  • Detects man-down events (fall impact + stillness, or prolonged no-motion)
  • Provides a manual panic button for any emergency
  • Alarms the worker (loud/vibrate) and a control room instantly
  • Sends located, acknowledged alerts (who + where)
  • Runs a full shift on supervised battery with plant-wide comms
  • Is explicit that it is not a certified safety device

Real-World Applications

SettingHow it is used
Confined-space / lone workers (educational)Awareness of gas and man-down events for workers who may be alone or unseen — alongside certified equipment.
Plant / process areasSupplementary gas and fall alerting routed to a control room with location.
Utilities / sewers / tanksDemonstrating the sensing and alarm architecture for toxic-atmosphere and fall hazards.
Safety-tech educationTeaching man-down detection, gas alarming and located, acknowledged alerting.

Deployment contexts where a build of this kind earns its keep.

Features & Capabilities

  • Gas + man-down + panic — the core worker-safety triggers
  • Fall/incapacitation detection with a cancellable pre-alarm
  • Located, acknowledged control-room alarms
  • Worker + control-room dual alerting
  • Shift battery life with supervision
  • Plant-wide resilient comms
  • Honest: supplementary/educational, NOT certified safety equipment

Difficulty, Time & Required Skills

AttributeValue
Difficulty levelAdvanced
Estimated completion time14–22 hours
Indicative build cost₹3,500 – ₹6,000 per wearable
Primary disciplineIndustrial
Reference platformESP32 DevKit V1 (ESP-WROOM-32)

Skills you should have (or will pick up)

  • Gas sensing and danger-threshold alarming
  • Man-down/fall detection from accelerometer signatures
  • Located, acknowledged alerting and pre-alarm cancellation
  • Wearable battery life and supervision
  • Resilient plant-wide comms

Bill of Materials

Every part below is commonly available from Indian and international hobby-electronics suppliers. Prices are indicative 2026 retail figures in Indian rupees and will drift — treat them as a budgeting guide, not a quotation.

ComponentKey specificationQtyApprox. cost
ESP32 DevKit V1 (ESP-WROOM-32)
Wi-Fi transmit bursts peak near 500 mA — size the regulator accordingly.
Dual-core Xtensa LX6 @ 240 MHz, 520 KB SRAM, 4 MB flash, Wi-Fi 802.11 b/g/n + BLE 4.2, 34 GPIO, 18× 12-bit ADC, 2× 8-bit DAC1₹450
MQ-2 combustible gas / smoke sensor
Needs 24–48 h burn-in and a stable 5 V; the heater alone draws ~150 mA.
300–10000 ppm LPG, propane, methane, hydrogen, smoke; analogue + digital output1₹150
MQ-135 air-quality sensor
Not a true CO₂ sensor — calibrate against clean air (R0) before trusting ppm.
NH₃, NOx, benzene, smoke, CO₂ proxy, 10–1000 ppm, analogue output1₹180
MQ-7 carbon monoxide sensor
Requires an alternating 60 s / 90 s heater cycle to read correctly — a constant 5 V gives wrong numbers.
20–2000 ppm CO, dual-heater cycle (1.4 V / 5 V), analogue output1₹260
MPU-6050 6-axis IMU
Gyro bias drifts with temperature — re-zero at boot while the device is still.
3-axis gyro ±250–2000 °/s, 3-axis accel ±2–16 g, 16-bit ADC, on-chip DMP1₹190
Active piezo buzzer 5 V
Active buzzers make tone on DC; passive ones need a PWM carrier.
85 dB at 10 cm, 2.3 kHz resonance, 12 mm diameter1₹25
SX1278 LoRa 433 MHz module (Ra-02)
Never power the radio without an antenna — the PA will destroy itself.
−148 dBm sensitivity, +20 dBm output, up to 10 km line of sight, SF7–SF121₹480
18650 Li-ion cell 3400 mAh + holder
Never charge below 0 °C; always use a protected cell or a BMS.
3.7 V nominal, 4.2 V full, 3400 mAh, ~12.6 Wh, 2 C discharge1₹450
Gas sensor(s) for the hazard
Real safety needs certified, calibrated, IS-rated detectors
H₂S/CO/combustible/O₂ sensors appropriate to the workplace (educational-grade)1₹900
Vibration motor + loud buzzerHaptic + audible worker alarm1₹200
Wearable enclosure + batteryComfortable, rugged, shift-life battery with supervision1₹500
Control-room gateway/consoleLoRa/mesh gateway + console for located, acknowledged alarms1₹2,500

Estimated total: ₹6,285, excluding tools, shipping and consumables.

Tools and consumables

  • Soldering iron (temperature controlled, 350 °C) with 0.8 mm 60/40 or lead-free solder
  • Digital multimeter — continuity, DC volts and current ranges
  • Wire strippers, flush cutters and a small set of precision screwdrivers
  • Heat-shrink tubing and a heat gun (or a lighter, carefully)
  • A laptop with a USB port and the toolchain listed above

Hardware Specifications

PartSpecificationSupplyInterfaceReference
ESP32 DevKit V1 (ESP-WROOM-32)Dual-core Xtensa LX6 @ 240 MHz, 520 KB SRAM, 4 MB flash, Wi-Fi 802.11 b/g/n + BLE 4.2, 34 GPIO, 18× 12-bit ADC, 2× 8-bit DAC3.3 V logic / 5 V USBUART, SPI, I²C, I²S, CAN, PWMDatasheet
MQ-2 combustible gas / smoke sensor300–10000 ppm LPG, propane, methane, hydrogen, smoke; analogue + digital output5 V (heater)Analogue + comparator digitalDatasheet
MQ-135 air-quality sensorNH₃, NOx, benzene, smoke, CO₂ proxy, 10–1000 ppm, analogue output5 V (heater)AnalogueDatasheet
MQ-7 carbon monoxide sensor20–2000 ppm CO, dual-heater cycle (1.4 V / 5 V), analogue output5 VAnalogue (PWM heater)Datasheet
MPU-6050 6-axis IMU3-axis gyro ±250–2000 °/s, 3-axis accel ±2–16 g, 16-bit ADC, on-chip DMP2.375–3.46 V (module 5 V tolerant)I²C (0x68/0x69)Datasheet
Active piezo buzzer 5 V85 dB at 10 cm, 2.3 kHz resonance, 12 mm diameter3–5 VDigital / PWMDatasheet
SX1278 LoRa 433 MHz module (Ra-02)−148 dBm sensitivity, +20 dBm output, up to 10 km line of sight, SF7–SF123.3 VSPIDatasheet
18650 Li-ion cell 3400 mAh + holder3.7 V nominal, 4.2 V full, 3400 mAh, ~12.6 Wh, 2 C discharge3.0–4.2 VHolder / spot-welded tabsDatasheet

Consolidated electrical and interface specifications for every active part in the build.

Power Budget & Supply Sizing

Add up the typical active current of every part, then size the supply with at least 50 % headroom so transmit bursts and motor inrush never brown out the controller.

LoadSupply railTypical current (mA)Notes
ESP32 DevKit V1 (ESP-WROOM-32)3.3 V logic / 5 V USB160Wi-Fi transmit bursts peak near 500 mA — size the regulator accordingly.
MQ-2 combustible gas / smoke sensor5 V (heater)150Needs 24–48 h burn-in and a stable 5 V; the heater alone draws ~150 mA.
MQ-135 air-quality sensor5 V (heater)150Not a true CO₂ sensor — calibrate against clean air (R0) before trusting ppm.
MQ-7 carbon monoxide sensor5 V150Requires an alternating 60 s / 90 s heater cycle to read correctly — a constant 5 V gives wrong numbers.
MPU-6050 6-axis IMU2.375–3.46 V (module 5 V tolerant)3.9Gyro bias drifts with temperature — re-zero at boot while the device is still.
Active piezo buzzer 5 V3–5 V30Active buzzers make tone on DC; passive ones need a PWM carrier.
SX1278 LoRa 433 MHz module (Ra-02)3.3 V120Never power the radio without an antenna — the PA will destroy itself.

Summed typical draw is 763.9 mA. With a 1.5× design margin the supply should deliver at least 1200 mA continuously at the stated rail voltage.

Software Requirements & Development Environment

Reference toolchain: Arduino IDE 2.3.x with the ESP32 board package 3.x (or PlatformIO on VS Code). Anything newer normally works; anything older may lack the board definitions used here.

  • Install the Arduino IDE 2.3.x (or PlatformIO if you prefer a real editor and dependency locking).
  • Add https://espressif.github.io/arduino-esp32/package_esp32_index.json under File → Preferences → Additional Board Manager URLs, then install esp32 from the Boards Manager.
  • Set the correct port under Tools → Port. On Linux add yourself to the dialout group: sudo usermod -aG dialout $USER and log out and back in.
  • Open the Serial Monitor at 115200 baud — every sketch here logs its state there.
  • Keep File → Preferences → Show verbose output during: compilation switched on while you are debugging build errors.

Required libraries

LibraryWhy it is neededInstall
WiFi (ESP32 core) bundledStation/AP connection management for the ESP32.Bundled with the ESP32 Arduino core
MPU6050_light / Adafruit MPU6050 1.3.xIMU register access, calibration and complementary-filter angles.Library Manager → "MPU6050_light" by rfetick
LoRa (sandeepmistry) 0.8.0SX127x radio configuration, packet TX/RX and callbacks.Library Manager → "LoRa" by Sandeep Mistry
ArduinoJson 7.xZero-allocation JSON serialisation and parsing.Library Manager → "ArduinoJson" by Benoit Blanchon
Preferences (NVS) bundledWear-levelled key/value storage in ESP32 flash for settings.Bundled with the ESP32 core
NTPClient / configTime bundledWall-clock time from an NTP server for timestamping.Bundled (`configTime()` on ESP32)

Block Diagram

The block diagram shows the functional decomposition of the system — what senses, what decides, what acts, and where the data ends up.

Worker Safety Wearable — system block diagramFunctional block diagram of the Worker Safety Wearable system. Sense dangerGastoxic/O₂Man-downfall/stillnessPanicmanual SOSDecideESP32thresholds + pre-alarmAlarmWorkerloud + vibrateControl roomlocated + ackAssureSupervisionbattery/linkrightrightnone
Worker Safety Wearable — system block diagram

Circuit Diagram & Wiring

Every signal line in the build is shown below, followed by a pin-by-pin connection table you can work through with a multimeter in hand.

Worker Safety Wearable — wiring schematicConnection schematic showing which controller pin drives each peripheral. Sensors / InputsControllerActuators / OutputsESP32 DevKit V1(ESP-WROOM-32)3.3 V logic / 5 V USBGas sensor(s)GPIO 34/35Toxic/combustible/O₂MPU-6050GPIO 21/22/27Man-down(fall/stillness)Panic buttonGPIO 26Manual SOSBuzzer + vibratorGPIO 13/14Worker alarmLoRa/meshGPIO 18/19/23/5Located alert tocontrol roomBattery senseGPIO 32SupervisionCharger3V3 regShift power
Worker Safety Wearable — wiring schematic
PeripheralPeripheral pinController pinSignal
Gas sensor(s)AOUTGPIO 34/35Toxic/combustible/O₂
MPU-6050SDA/SCL/INTGPIO 21/22/27Man-down (fall/stillness)
Panic buttonNOGPIO 26Manual SOS
Buzzer + vibratorINGPIO 13/14Worker alarm
LoRa/meshSPIGPIO 18/19/23/5Located alert to control room
Battery senseADCGPIO 32Supervision
ChargerOUT3V3 regShift power

Wire one row at a time and tick it off — most "it does not work" reports trace back to a single swapped pair.

Wiring explanation

  • Use gas sensors appropriate to the workplace hazard; understand these are educational-grade, not certified detectors.
  • Mount the accelerometer firmly on the body so fall/stillness signatures are faithful.
  • Provide both loud audible and haptic (vibration) worker alarms so it is felt in noise/PPE.
  • Power for a full shift with battery supervision, and use a comms path with plant-wide coverage (LoRa/mesh; cellular where needed).
  • Keep the panic button easy to press but guarded against accidental activation.
An ESP32 development board with the ESP-WROOM-32 module and USB connector
ESP32 module sensing gas and fall/stillness and sending located, acknowledged alarms. Photograph sourced from Wikimedia Commons — ESP32 Espressif ESP-WROOM-32 Dev Board.jpg. Reused under the licence stated on that page; please check it before republishing.

System Architecture

Read the stack from the bottom up: physical hardware, the firmware that drives it, the transport that moves data off the device, and the software a human actually looks at.

Worker Safety Wearable — architecture stackLayered architecture from hardware to user interface. Hardware layerESP32 DevKit V1 (ESP-WROOM-32) · MQ-2 combustible gas / smoke sensor ·MQ-135 air-quality sensor · MQ-7 carbon monoxide sensorDriver layerwifi · mpu · lorolib · arduinojsonApplication logicsampling loop · filtering · thresholds · state machineTransport layerLoRa/mesh → control-room console (located, ack) · TLS · retry and backoffPresentation layerdashboard · mobile notifications · historical charts
Worker Safety Wearable — architecture stack

Working Principle

This wearable is a life-safety device targeted at two specific killers, and life-safety design means everything is optimised for the rare, adverse moment of use, with brutal honesty about limits. The two hazards are chosen because they share a lethal property: the victim often cannot save themselves. A toxic or oxygen-deficient atmosphere can incapacitate before the worker even perceives danger — and, notoriously, lures would-be rescuers to their deaths — so it must be detected by an instrument, not by human senses. A man-down event leaves the worker unable to call for help, so the device must call on their behalf. The wearable's whole reason to exist is to sense these, alarm instantly, and get a located, acknowledged call to people who can respond.

Gas detection alarms on concentration crossing a danger threshold for the specific hazard — a toxic gas rising past its exposure limit, oxygen falling below safe, combustible gas approaching its explosive limit. The response is immediate and dual: the worker is alerted loudly and by vibration (because in plant noise and PPE, sound alone may not reach them) so they can evacuate or don protection, and the control room is alerted simultaneously so help and rescue (properly equipped) can be organised. The device must be candid that its educational-grade sensors are not the certified, calibrated, intrinsically-safe detectors that hazardous work legally mandates — so its gas function is, at most, a supplementary awareness layer, never the primary protection lives are trusted to.

Man-down detection reads the accelerometer for the signatures of incapacitation. A fall shows as a characteristic sequence — often a brief free-fall or lurch, a sharp impact, then abnormal stillness — and prolonged no-motion (a worker who has not moved for an unusual period) suggests collapse. The design must balance sensitivity against false alarms, because a wearable that cries wolf gets taken off, so a detected man-down triggers a cancellable pre-alarm: the device warns the worker (buzz/vibrate) and, if they are fine, they cancel it within a few seconds; only if they do not cancel does it escalate to a full located alarm. This "confirm before escalate" pattern keeps false alarms tolerable while still catching a genuinely incapacitated worker who cannot cancel. A manual panic button covers every other emergency the sensors do not.

Because it is trusted (even supplementarily) for safety, the wearable lives or dies on reliability, location, acknowledgement and supervision. Alarms carry the worker's identity and location so responders go straight to them — vital in a large plant. They are acknowledged end-to-end so the worker knows help is coming and the control room confirms it is handling the event. The device runs a full shift on battery with battery supervision, over comms with plant-wide coverage, and heartbeats its health so a dead or low wearable is flagged before an incident — because a silently failed safety device is worse than none. Above all, the design is emphatically honest: a homebrew wearable, however well-architected, is not a certified gas detector or a replacement for the intrinsically-safe, calibrated, professionally-certified safety equipment that industrial hazardous work requires by law. It is an educational realisation of the right ideas — sense the killers, alarm the worker and a control room instantly, locate and acknowledge, supervise relentlessly — and it must never be presented, or relied upon, as the real thing.

The maths behind it

Gas danger alarm

plainGas danger alarm
For each gas, alarm on crossing its danger threshold:

  toxic  : conc > exposure_limit (e.g. ppm)
  O2     : O2 < safe_min (e.g. 19.5%)  OR > safe_max
  LEL    : combustible > %LEL_alarm (with margin)

Alarm worker (loud+vibrate) AND control room, immediately.

Man-down detection

plainMan-down detection
From accelerometer magnitude a and orientation:
  free-fall : a ≈ 0 briefly
  impact    : a spike (high g)
  stillness : low motion sustained after impact
  no-motion : |a − 1g| < ε for > T_still (collapse)

  man_down = (impact THEN stillness) OR prolonged no-motion

Pre-alarm + escalate

plainPre-alarm + escalate
On man_down:
  pre-alarm the worker for T_cancel seconds
  if worker cancels -> resume (false alarm avoided)
  else -> escalate: located, acknowledged control-room alarm

Reduces false alarms while catching real incapacitation.

Program Flowchart

The firmware is a single cooperative loop. Nothing blocks for long, so networking, sensing and the user interface all stay responsive.

Worker Safety Wearable — firmware flowchartControl flow through the main program loop. Monitor gas + motion;superviseGas over danger, fall, orpanic?Worker alarm + located alertHeartbeatMan-down: pre-alarm(cancellable)?Cancelled → resumeEscalate man-downWorker alarm + located alertEscalate man-downControl-room ack → confirm toworkerHeartbeatContinue
Worker Safety Wearable — firmware flowchart

Assembly Instructions

Build on a breadboard first and only commit to solder once the whole system has run for an hour without a fault.

  1. Build a reliable, comfortable wearable

    Assemble the gas sensor(s), a firmly-mounted accelerometer, loud + haptic alarms, and a guarded panic button in a comfortable, rugged enclosure with shift battery life and supervision.

  2. Set up located, acknowledged comms

    Use a comms path with plant-wide coverage (LoRa/mesh; cellular where needed) so alarms reach a control-room console with the worker's location and are acknowledged back.

  3. Configure detection and pre-alarm

    Set gas danger thresholds for the workplace, man-down signatures, and the cancellable pre-alarm and escalation, plus heartbeat supervision.

Step-by-Step Implementation Guide

Work through these in order. Each step ends in something you can observe, so a failure is always localised to the step you just finished.

  1. Detect gas, man-down and panic

    Alarm immediately on gas crossing a danger threshold or a panic press; on man-down, run a cancellable pre-alarm before escalating.

    cppsafety-triggers.ino
    #define T_STILL_MS  20000    // no-motion time suggesting collapse
    #define T_CANCEL_MS  8000    // pre-alarm cancel window
    uint32_t stillSince=0, preAlarmStart=0; bool preAlarm=false;
    
    bool gasDanger(float toxic, float o2, float lel){
      return toxic > TOXIC_LIMIT || o2 < O2_MIN || lel > LEL_ALARM;
    }
    
    // Man-down: impact-then-stillness OR prolonged no-motion.
    bool manDown(float aMag, uint32_t now){
      static bool impacted=false; static uint32_t impactAt=0;
      if (aMag > 3.0f){ impacted=true; impactAt=now; }          // impact spike
      bool still = fabsf(aMag - 1.0f) < 0.08f;                  // ~stationary (g)
      if (still){ if(!stillSince) stillSince=now; }
      else stillSince=0;
      bool afterImpact = impacted && (now-impactAt<30000) && stillSince
                         && (now-stillSince>3000);
      bool collapsed   = stillSince && (now-stillSince>T_STILL_MS);
      return afterImpact || collapsed;
    }
    
    // Cancellable pre-alarm before escalating a man-down.
    bool escalateManDown(bool md, bool cancelled, uint32_t now){
      if (md && !preAlarm){ preAlarm=true; preAlarmStart=now; warnWorker(); }
      if (preAlarm && cancelled){ preAlarm=false; return false; }
      if (preAlarm && now-preAlarmStart>T_CANCEL_MS){ preAlarm=false; return true; }
      return false;
    }
    return toxic > TOXIC_LIMIT || o2 < O2_MIN || lel > LEL_ALARMAny gas crossing its danger threshold — toxic high, oxygen low, combustible high — triggers an immediate alarm.
    bool afterImpact = impacted && ... && (now-stillSince>3000)A fall is recognised as an impact spike followed by abnormal stillness, the classic man-down signature.
    bool collapsed = stillSince && (now-stillSince>T_STILL_MS)Prolonged no-motion catches a collapse without a sharp impact, e.g. a slow incapacitation.
    if (md && !preAlarm){ preAlarm=true; ... warnWorker(); }A detected man-down first warns the worker, giving them a chance to cancel if they are fine — the false-alarm control that keeps the device worn.
    if (preAlarm && now-preAlarmStart>T_CANCEL_MS){ preAlarm=false; return true; }Only if the worker does not cancel within the window does it escalate to a full located alarm — catching someone genuinely unable to respond.
  2. Alarm, locate, acknowledge, supervise

    On any trigger, alarm the worker (loud+vibrate) and send a located alert to the control room, retry until acknowledged, confirm to the worker, and heartbeat health continuously.

Complete Source Code

The listing below is complete and compiles as written — there are no elided sections. Read the annotations under each block before you upload it.

cppworker-safety-wearable.ino
/* ═══════════════════════════════════════════════════════════════
   Worker Safety Wearable — ESP32 (EDUCATIONAL / SUPPLEMENTARY)

   Detects toxic/low-O2 gas and man-down (fall/stillness), plus a panic
   button; alarms the worker (loud+vibrate) and a control room with a
   located, acknowledged alert; supervises battery/link.
   NOT a certified, calibrated, intrinsically-safe safety device.
   ══════════════════════════════════════════════════════════════════ */

#include <Wire.h>
#include <MPU6050.h>
#include <LoRa.h>
#include <SPI.h>
#include <Preferences.h>
#include <math.h>

#define PIN_TOXIC 34
#define PIN_O2    35
#define PIN_PANIC 26
#define PIN_BUZZER 13
#define PIN_VIBE  14
#define PIN_CANCEL 33
#define T_STILL_MS 20000
#define T_CANCEL_MS 8000
#define HEARTBEAT_MS 60000UL

MPU6050 imu; Preferences prefs;
const uint16_t WORKER_ID = 7;
const char *ZONE = "Boiler room";     // updated by location beacons in practice
uint32_t stillSince=0, preAlarmStart=0, lastBeat=0, seq=0;
bool preAlarm=false;

void workerAlarm(bool on){ digitalWrite(PIN_BUZZER,on); digitalWrite(PIN_VIBE,on); }

bool sendAlert(const char *type){
  for (int a=0; a<5; a++){
    LoRa.beginPacket();
    LoRa.printf("{\"t\":\"%s\",\"id\":%u,\"zone\":\"%s\",\"seq\":%lu}",
                type, WORKER_ID, ZONE, (unsigned long)++seq);
    LoRa.endPacket();
    if (waitAck(seq, 1500)){ /* confirm to worker */ return true; }
  }
  return false;
}

bool gasDanger(){
  float toxic = analogRead(PIN_TOXIC)/4095.0f * TOXIC_FS;
  float o2    = analogRead(PIN_O2)/4095.0f * 25.0f;      // %O2 (calibrate)
  return toxic > TOXIC_LIMIT || o2 < 19.5f;
}

bool manDown(float aMag, uint32_t now){
  static bool impacted=false; static uint32_t impactAt=0;
  if (aMag>3.0f){ impacted=true; impactAt=now; }
  bool still = fabsf(aMag-1.0f)<0.08f;
  if (still){ if(!stillSince) stillSince=now; } else stillSince=0;
  bool afterImpact = impacted&&(now-impactAt<30000)&&stillSince&&(now-stillSince>3000);
  bool collapsed = stillSince&&(now-stillSince>T_STILL_MS);
  return afterImpact||collapsed;
}

void setup(){
  Serial.begin(115200);
  pinMode(PIN_PANIC,INPUT_PULLUP); pinMode(PIN_CANCEL,INPUT_PULLUP);
  pinMode(PIN_BUZZER,OUTPUT); pinMode(PIN_VIBE,OUTPUT);
  Wire.begin(21,22); imu.initialize();
  SPI.begin(); LoRa.setPins(5,14,2); LoRa.begin(433E6); LoRa.setSpreadingFactor(10);
}

void loop(){
  uint32_t now=millis();
  int16_t ax,ay,az; imu.getAcceleration(&ax,&ay,&az);
  float g=1.0f/16384.0f;
  float aMag=sqrtf((ax*g)*(ax*g)+(ay*g)*(ay*g)+(az*g)*(az*g));

  // panic + gas = immediate
  if (digitalRead(PIN_PANIC)==LOW){ workerAlarm(true); sendAlert("PANIC"); }
  if (gasDanger()){ workerAlarm(true); sendAlert("GAS"); }

  // man-down with cancellable pre-alarm
  if (manDown(aMag, now) && !preAlarm){ preAlarm=true; preAlarmStart=now; workerAlarm(true); }
  if (preAlarm && digitalRead(PIN_CANCEL)==LOW){ preAlarm=false; workerAlarm(false); }
  if (preAlarm && now-preAlarmStart>T_CANCEL_MS){
    preAlarm=false; sendAlert("MAN_DOWN");            // escalate located alarm
  }

  if (now-lastBeat>HEARTBEAT_MS){                     // supervision
    LoRa.beginPacket();
    LoRa.printf("{\"t\":\"HB\",\"id\":%u,\"vbat\":%.2f}",
                WORKER_ID, readBattery());
    LoRa.endPacket(); lastBeat=now;
  }
  delay(100);
}
NOT a certified, calibrated, intrinsically-safe safety device.The header states the scope in the code itself — this is educational/supplementary and must never be relied on as the certified equipment hazardous work requires.
bool sendAlert(const char *type)Every alert is retried until the control room acknowledges, and carries the worker's id and zone — located, reliable, confirmed delivery.
return toxic > TOXIC_LIMIT || o2 < 19.5fGas alarms fire on toxic concentration or oxygen deficiency, the atmospheric killers a worker cannot sense in time.
if (manDown(aMag, now) && !preAlarm){ preAlarm=true; ... }A man-down first raises a cancellable pre-alarm the worker can dismiss if fine, controlling false alarms so the device stays worn.
if (now-lastBeat>HEARTBEAT_MS){Heartbeats supervise the wearable so a dead or low-battery unit is flagged before an incident — a silent safety device is worse than none.

Configuration & Calibration

Configuration steps

  • Set gas danger thresholds for the workplace hazard (educational-grade sensors, clearly labelled as such).
  • Configure man-down signatures, the pre-alarm cancel window, and escalation.
  • Set the located-alert path (with acknowledgement), heartbeat interval and battery-low threshold.
  • Integrate plant location (beacons/zones) so alerts are located.

Calibration procedure

An uncalibrated sensor produces confident, precise, wrong numbers. Do this once per physical unit and record the constants.

  1. Gas

    Understand these are educational sensors; for any real use, certified, calibrated detectors are required. Set thresholds and test response conservatively.

  2. Man-down

    Tune fall/stillness thresholds so genuine falls/incapacitation are caught while normal movement and brief rest do not false-alarm (with the pre-alarm as backstop).

  3. Comms/battery

    Verify located, acknowledged delivery across the plant and shift battery life with supervision.

Network Architecture & Connectivity

Worker Safety Wearable — network topologyPath taken by telemetry from field node to end user. Edge nodesGatewayCloudClientsWearableESP32Other workersfleetLoRa/meshControl-room GWlocated alarmsMQTT/consoleControl roomgas/man-down/panicConsolelocated + ackRespondersrescue
Worker Safety Wearable — network topology

Communication protocol

Alarms deliver with retry and acknowledgement, located by worker/zone; heartbeats supervise every wearable. Worker alarm and delivery do not depend on a single link.

Topic / endpointDirectionPayload
safety/alarmwearable → consoletype (gas/man-down/panic), worker, zone
safety/ackconsole → wearableacknowledgement → confirm to worker
safety/heartbeatwearable → consolebattery, link (supervision)

Message contract between the device and the broker.

Cloud platform configuration

A control-room console shows located, acknowledged alarms and every wearable's health, and coordinates (properly-equipped) response.

Dashboard setup

A plant map of workers with instant located alarms, an alarm queue with acknowledge, and a wearable-health/supervision view.

Mobile app integration

Located alarms to responders and supervision alerts for low-battery/silent wearables.

Security considerations

  • Authenticate wearables/acknowledgements so alarms cannot be spoofed.
  • Keep worker alarm and delivery independent of a single link; supervise continuously.
  • Never present as certified equipment; certified, calibrated, IS-rated detectors are legally required for hazardous work.

Testing Procedure & Expected Output

Test from the bottom up. Confirm power, then each sensor in isolation, then the integrated loop — the first failing step tells you exactly where to look.

TestWhat you should see
Expose to test gas (safely)Worker + control-room alarm; located, acknowledged
Simulate a fallPre-alarm; if not cancelled, escalates to man-down alarm
Cancel the pre-alarmNo escalation (false alarm avoided)
Remain motionless past the timeoutCollapse detected; man-down escalated
Press panicImmediate located alarm
Let battery run low / go silentSupervision flags low battery / missing heartbeat

Bench-test checklist. If a row fails, stop and fix it before moving on.

Expected output

The control-room console shows located, acknowledged alarms (gas/man-down/panic) with the worker and zone, and a health view of every wearable.

jsonsafety-event.json
{
  "type": "MAN_DOWN",
  "worker": 7,
  "zone": "Boiler room",
  "seq": 22,
  "time": "2026-07-27T14:03:51",
  "acknowledged": true
}

A located man-down alert (worker 7, boiler room) reaches the control room and is acknowledged; a gas or panic event would be handled identically — always with a supplementary, never a certified, guarantee.

A wrist-worn fitness tracker
A control-room console shows located alarms and every wearable's health — supplementary to, never a replacement for, certified safety equipment. Photograph sourced from Wikimedia Commons — Fitness tracker.jpg. Reused under the licence stated on that page; please check it before republishing.

Troubleshooting: Common Errors & Fixes

Too many man-down false alarms

Likely cause. Thresholds too sensitive / no pre-alarm

Fix. Use the cancellable pre-alarm; tune fall/stillness; make the pre-alarm unmissable

Worker doesn't feel the alarm

Likely cause. Audible only in noise/PPE

Fix. Add strong vibration/haptic alongside the buzzer

Alarm not located/acknowledged

Likely cause. No location or ack

Fix. Add plant location and end-to-end acknowledgement with retry

Wearable dies mid-shift unnoticed

Likely cause. No supervision

Fix. Heartbeat battery/health; flag silent/low units

Treated as a certified detector

Likely cause. Misunderstanding of scope

Fix. Be explicit: educational/supplementary; certified equipment is legally required for hazardous work

The sketch will not upload — "Failed to connect" or "avrdude: stk500_recv()"

Likely cause. The bootloader is not being reached: wrong port, wrong board, a serial monitor holding the port open, or a USB cable that only carries power.

Fix. Close every serial monitor, confirm Tools → Board and Port, and swap to a known data-capable USB cable. On an ESP32 hold BOOT while the IDE prints "Connecting…", then release. If a peripheral is wired to the UART pins (GPIO 1/3 on ESP32, D0/D1 on Uno) unplug it — it fights the programmer.

The board resets in a loop, or the serial monitor prints "Brownout detector was triggered"

Likely cause. The supply cannot deliver peak current. Wi-Fi transmit bursts, relay coils and servos all pull far more than their average draw.

Fix. Power peripherals from a separate regulated supply with a common ground rather than from the board 5 V pin. Add a 470–1000 µF electrolytic capacitor across the supply near the load, and use a real power adapter rather than a laptop USB port.

Serial monitor shows garbage characters

Likely cause. Baud rate mismatch between Serial.begin() and the monitor, or a floating/shared UART line.

Fix. Set the monitor to 115200 to match the sketch. If it still garbles, the crystal or the USB bridge is being confused by noise — shorten the cable and keep motor wiring away from the USB lead.

An I²C device is not detected

Likely cause. Wrong address, missing pull-ups, swapped SDA/SCL, or a bus too long for the pull-up value.

Fix. Run an I²C scanner sketch first — it should print the device address. Most breakout boards include 4.7 kΩ pull-ups, but if you have chained four of them the parallel resistance is too low; remove the pull-ups from all but one board. Keep the bus under 30 cm at 100 kHz.

Wi-Fi connects but MQTT never does (state -2)

Likely cause. Wrong broker address or port, a firewall in the way, or the broker requiring credentials the sketch is not sending.

Fix. Test from a laptop on the same network first: mosquitto_sub -h <broker> -t "#" -v. If that works, the problem is on the device — check the IP literal, port 1883 (or 8883 for TLS), and that client.setServer() runs before connect(). PubSubClient state codes are documented in its header.

Readings arrive for a while and then stop

Likely cause. The Wi-Fi or MQTT session dropped and the sketch never reconnects, or the broker dropped the client on keep-alive timeout.

Fix. Never assume the link stays up. Check WiFi.status() and client.connected() at the top of every loop and reconnect with exponential backoff. Add a watchdog so a wedged network stack reboots the device instead of going silent.

Performance Optimisation

  • Prioritise instant, reliable alarming (retry+ack) over everything.
  • Keep man-down detection light so it runs continuously without draining the shift battery.
  • Heartbeat health so a dead/low wearable is known before an incident.
  • Make the worker alarm both loud and haptic for noisy/PPE environments.
  • Replace every delay() with a millis() comparison — blocking delays are the single most common cause of dropped readings.
  • Sample sensors on a fixed cadence and publish on a slower one; you almost never need to transmit at the sampling rate.
  • Move networking into its own FreeRTOS task so a slow DNS lookup cannot stall the control loop.
  • Use uint8_t / uint16_t where the range allows; on an 8-bit AVR a 32-bit add costs four times as much.
  • Batch several samples into one MQTT publish. Radio time, not CPU time, dominates the energy budget.
  • Set the MQTT keep-alive to a value that matches your reporting interval so the broker does not churn reconnections.
  • For battery builds use deep sleep between samples: an ESP32 drops from ~160 mA awake to about 10 µA asleep, which is the difference between days and months of runtime.

Safety Precautions

  • THIS IS EDUCATIONAL/SUPPLEMENTARY — not a certified, calibrated, intrinsically-safe gas detector. Hazardous industrial work legally requires certified safety equipment; never rely on this for life safety.
  • Real toxic/explosive atmospheres demand certified instruments and proper procedures (confined-space entry, rescue plans).
  • Provide located, acknowledged alarms and supervision; a silent or unlocated alarm fails when it matters.
  • Test regularly and never let this replace required PPE, gas detectors or safe systems of work.
  • Lithium cells vent and burn when abused. Only use protected cells or a proper BMS, never charge below 0 °C, and never leave a charging pack unattended on a wooden desk.
  • MQ-series sensors run a hot element. They get genuinely hot, need ventilation, and must never be enclosed in a sealed plastic box.
  • Never power an RF module without its antenna fitted — the reflected power destroys the output stage. Check your local licence-free band and duty-cycle limits before transmitting.
  • Wear eye protection when soldering or cutting, and solder in a ventilated space — rosin flux fumes are a respiratory irritant.
  • Power the circuit through a bench supply with a current limit while you are testing. A 300 mA limit turns a wiring mistake into a beep instead of a dead board.
  • Disconnect power before changing any wiring. Hot-plugging a sensor onto a live bus is the fastest way to lose a controller.

Maintenance

  • Act on every supervision alert; replace/charge batteries; fix silent wearables.
  • Test gas response and man-down detection regularly (with the pre-alarm).
  • Verify located, acknowledged delivery across the plant.
  • Reinforce that it is supplementary — certified equipment remains mandatory.
  • Re-check every screw terminal and header after the first week — thermal cycling loosens connections that felt tight on day one.
  • Log pack voltage. When resting voltage after a full charge drops below about 4.0 V, the cell is near end of life — replace it.
  • Keep the broker and dashboard containers patched, and rotate device credentials at least once a year.
  • Recalibrate at the interval given in the calibration section, and keep the constants in a text file next to the firmware — not only in flash.
  • Keep a short logbook of firmware versions and what changed. Six months later you will not remember why that constant is 1.083.

Future Improvements & Upgrades

A working v1 is a platform, not a finish line. These are the upgrades that add the most capability for the least rework.

  • Add heart-rate/temperature for heat-stress detection.
  • Add precise indoor location (UWB/beacons) for faster rescue.
  • Add two-way voice to the control room.
  • Integrate with certified gas-detection systems as a data/awareness layer.
  • Design a proper PCB. Once the breadboard version has run for a month, moving to a two-layer board removes the intermittent-contact failures that dominate prototype faults.
  • Add over-the-air firmware updates so you never have to physically reach a deployed node again.
  • Add persistent local storage (microSD or the on-chip flash) so a network outage does not create a hole in your data.
  • Move configuration out of the source: a captive-portal setup page or a JSON config file makes the build reusable without a recompile.
  • Add a battery and solar option so the unit survives a power cut and can be sited away from a socket.
  • Write a small test harness that feeds synthetic sensor values through the decision logic, so you can validate thresholds without physically triggering the event.

Frequently Asked Questions

Can I use this instead of a real gas detector?

No — absolutely not. This is an educational/supplementary build. Hazardous work legally requires certified, calibrated, intrinsically-safe gas detectors and proper procedures; never rely on this for life safety.

Why detect man-down and gas specifically?

Because in both, the victim often cannot save themselves — a toxic atmosphere incapacitates before you realise, and a fall/collapse leaves you unable to call for help. The wearable calls for help on the worker's behalf.

How does it avoid constant false man-down alarms?

With a cancellable pre-alarm: on a detected man-down it warns the worker, who cancels if fine; only an uncancelled event escalates to a full alarm. That keeps false alarms tolerable so the device stays worn.

Why do alarms need location and acknowledgement?

Location sends responders straight to the worker in a large plant; acknowledgement tells the worker help is coming and confirms a human is responding. A silent, unlocated alarm fails at the crucial moment.

What makes it reliable enough to trust (even supplementarily)?

Shift battery life with supervision, plant-wide comms, retry-until-acknowledged alarms, and heartbeats that flag a dead or low wearable before an incident — plus the honesty that it does not replace certified equipment.

References & Learning Resources

These are the primary sources worth reading in full. Manufacturer datasheets always outrank forum posts when the two disagree.

  1. Confined spaces and toxic atmospheres (OSHA)OSHA
  2. Gas detection and exposure limitsReference
  3. Man-down / lone worker safetyReference
  4. Fall detection with accelerometersReference
  5. Intrinsic safety (ATEX/IECEx)Reference