Chapter 221: Fire Safety and Alarm Systems
Chapter Objectives
By the end of this chapter, you will be able to:
- Understand the fundamental principles of common smoke and gas detectors.
- Interface an analog smoke/gas sensor with an ESP32 microcontroller.
- Read and process sensor data using the ESP-IDF ADC (Analog-to-Digital Converter) one-shot driver.
- Implement a state-based alarm logic system using FreeRTOS tasks.
- Trigger local audible and visual alarms using a buzzer and an LED.
- Transmit alarm notifications to a remote system over Wi-Fi using the MQTT protocol.
- Recognize and account for differences between ESP32 variants in your design.
- Troubleshoot common issues in sensor-based alarm projects.
Introduction
In the realm of building automation, few systems are as critical as fire safety and alarm systems. A traditional smoke detector provides a localized warning, but in our connected world, we can do much more. A “smart” alarm system can not only alert occupants but also notify property owners remotely, contact emergency services, or trigger other automated actions like shutting down ventilation systems or unlocking emergency exits.
The ESP32, with its powerful dual-core processor, integrated Wi-Fi and Bluetooth, and a suite of peripherals, is an ideal platform for developing sophisticated, cost-effective smart alarm systems. In this chapter, we will build upon our knowledge of peripherals and networking to create a functional smoke detector and emergency notification system. We will learn how to read the physical world through a sensor, process that data in real-time, and act upon it both locally and remotely.
Theory
1. Smoke Detection Technologies
Commercial fire alarms typically use one of two main technologies:
- Photoelectric Detectors: These contain a light source and a light sensor positioned at an angle to each other. In normal conditions, the light beam does not hit the sensor. When smoke enters the chamber, its particles scatter the light, causing some of it to hit the sensor and trigger the alarm. They are generally more responsive to smoldering fires.
- Ionization Detectors: These use a tiny amount of a radioactive material to ionize the air between two electrodes, creating a small, constant electric current. When smoke particles enter the chamber, they disrupt this flow of ions, reducing the current and triggering the alarm. They typically respond best to fast, flaming fires.
For our practical exercise, we will use a common and readily available MQ-series gas sensor, such as the MQ-2. While not a certified fire safety device, it is an excellent educational tool. The MQ-2 is sensitive to combustible gases like LPG, propane, and methane, as well as smoke and hydrogen. It contains a small heating element and a chemoresistive sensor whose electrical resistance changes in the presence of target gases.
The MQ-2 sensor module typically provides two outputs:
- DO (Digital Out): A simple high/low signal that goes HIGH when the gas concentration exceeds a threshold set by an onboard potentiometer.
- AO (Analog Out): An analog voltage (typically 0-5V or 0-3.3V) that is proportional to the concentration of detected gases.
We will use the Analog Output (AO) as it provides a richer, more nuanced stream of data, allowing us to define multiple alarm levels (e.g., “Warning” and “Critical”) rather than a simple on/off state.
2. Analog-to-Digital Conversion (ADC)
Microcontrollers like the ESP32 operate in the digital domain, understanding only ones and zeros. To interpret the analog voltage from the MQ-2 sensor, we must convert it into a digital number. This is the job of the Analog-to-Digital Converter (ADC).
As covered in Chapter 126, the ADC reads an input voltage and maps it to a digital value within a specific range, determined by its resolution (e.g., 12-bit resolution provides values from 0 to 4095).

In ESP-IDF v5.x, we use the adc_oneshot
driver, which is designed for straightforward, single readings from an ADC channel. The process involves:
- Initializing an ADC Unit: Configuring the ADC peripheral (e.g.,
ADC_UNIT_1
). - Configuring an ADC Channel: Setting up a specific pin (e.g.,
ADC_CHANNEL_6
) with parameters like attenuation. Attenuation is crucial as it determines the maximum input voltage the ADC can handle. For a 0-3.3V sensor signal, we typically use the 11dB attenuation, which maps this voltage range to the full digital output range. - Reading the Value: Calling a function to perform a conversion and retrieve the digital value.
3. System Architecture and Notification Flow
Our smart alarm system will follow a clear architectural pattern:
- Sense: A dedicated FreeRTOS task will periodically read the analog value from the smoke sensor.
- Process: The same task will compare the reading against predefined thresholds to determine the system state:
NORMAL
,WARNING
, orALARM
. - Act (Local): A separate task will manage local alerts. If the state is
ALARM
, it will activate a flashing LED and a buzzer. Separating this from the sensor task ensures that the alarm actions (which may involve delays) do not block new sensor readings. - Act (Remote): When an alarm is triggered, the system will connect to Wi-Fi and publish a notification message to an MQTT topic. This allows any subscribed client (a mobile app, a central dashboard) to receive the alert instantly.
graph TD subgraph "Hardware Layer" A[MQ-2 Sensor] -- "Analog Voltage" --> B(ESP32); end subgraph "ESP32 Processing" B -- "1- Read Signal" --> C{ADC One-Shot Read}; C -- "Digital Value" --> D[Process Task]; D -- "Compare Value" --> E{Value > Threshold?}; end subgraph "Local Actions" E -- No --> F[State: NORMAL]; E -- Yes --> G[State: ALARM]; G -- "Trigger" --> H((Buzzer)); G -- "Trigger" --> I(Flashing LED); end subgraph "Remote Actions" G -- "Publish" --> J[Wi-Fi]; J -- "MQTT Message" --> K[(MQTT Broker)]; K -- "Notification" --> L[User Client / Dashboard]; end %% Styling classDef hardware fill:#DBEAFE,stroke:#2563EB,stroke-width:1px,color:#1E40AF classDef process fill:#EDE9FE,stroke:#5B21B6,stroke-width:2px,color:#5B21B6 classDef decision fill:#FEF3C7,stroke:#D97706,stroke-width:2px,color:#92400E classDef local_alarm fill:#FEE2E2,stroke:#DC2626,stroke-width:2px,color:#991B1B classDef remote fill:#D1FAE5,stroke:#059669,stroke-width:1px,color:#065F46 class A hardware; class B,C,D process; class E decision; class H,I local_alarm; class J,K,L remote;
Practical Example: ESP32 Smart Smoke Alarm
Let’s build the system.
Hardware Required
- An ESP32 development board (e.g., ESP32-DevKitC).
- MQ-2 Gas/Smoke Sensor module.
- 5mm LED.
- Active Buzzer.
- 220Ω resistor (for the LED).
- Breadboard and jumper wires.
Wiring
Warning: Always check the pinout for your specific ESP32 board. Some pins have special functions or are not suitable for general-purpose I/O.
GPIO34
is an input-only pin, making it perfect for an ADC.
- Connect the MQ-2 Sensor:
VCC
->3V3
on ESP32.GND
->GND
on ESP32.AO
->GPIO34
on ESP32 (This is ADC1_CHANNEL_6, a good choice as it’s on ADC1).
- Connect the LED:
- LED Anode (longer leg) -> 220Ω resistor ->
GPIO26
on ESP32. - LED Cathode (shorter leg) ->
GND
.
- LED Anode (longer leg) -> 220Ω resistor ->
- Connect the Buzzer:
- Buzzer
+
->GPIO27
on ESP32. - Buzzer
-
->GND
.
- Buzzer
Project Configuration
- Create a new ESP-IDF project in VS Code.
- Open the
main/CMakeLists.txt
file and add the required components for MQTT and ADC:# Inside idf_component_register(...)
REQUIRES
idf::nvs_flash
idf::esp_wifi
idf::esp_event
idf::esp_netif
idf::esp_log
idf::mqtt
idf::esp_adc
- Run
idf.py menuconfig
(or use the VS Code extension’s GUI). - Go to
Component config
->ESP System Settings
and ensureFreeRTOS
->Kernel
->Enable SMP support
is checked if you are on a dual-core chip. - Go to
Example Connection Configuration
to set your Wi-Fi SSID and Password. For the MQTT broker, you can use a public test broker likemqtt.eclipseprojects.io
.
Code Implementation
We will structure our code into logical parts: ADC setup, GPIO setup, a sensor reading task, an alarm task, and a Wi-Fi/MQTT setup function.
/* main/main.c */
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "esp_wifi.h"
#include "nvs_flash.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "mqtt_client.h"
#include "driver/gpio.h"
#include "esp_adc/adc_oneshot.h"
static const char *TAG = "SMOKE_ALARM";
// Hardware Configuration
#define SMOKE_SENSOR_ADC_CHANNEL ADC_CHANNEL_6 // GPIO34 on most ESP32 DevKits
#define LED_ALARM_GPIO GPIO_NUM_26
#define BUZZER_ALARM_GPIO GPIO_NUM_27
// Alarm Logic Configuration
#define ALARM_THRESHOLD 2000 // Raw ADC value to trigger alarm. Calibrate this!
#define NORMAL_READ_INTERVAL_MS 5000
#define ALARM_READ_INTERVAL_MS 1000
// MQTT Configuration
#define MQTT_BROKER_URL "mqtt://mqtt.eclipseprojects.io" // Using public broker
#define MQTT_TOPIC "building/floor1/smoke_alarm/status"
// System State
typedef enum {
STATE_NORMAL,
STATE_ALARM
} alarm_state_t;
volatile alarm_state_t system_state = STATE_NORMAL;
SemaphoreHandle_t state_mutex;
esp_mqtt_client_handle_t mqtt_client;
adc_oneshot_unit_handle_t adc1_handle;
// --- Function Prototypes ---
static void wifi_init(void);
static void mqtt_app_start(void);
static void configure_peripherals(void);
void sensor_reader_task(void *pvParameters);
void alarm_handler_task(void *pvParameters);
// --- MQTT Event Handler ---
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) {
esp_mqtt_event_handle_t event = event_data;
switch ((esp_mqtt_event_id_t)event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGW(TAG, "MQTT_EVENT_DISCONNECTED");
break;
default:
// This is a minimal handler. A real app might handle other events.
break;
}
}
void app_main(void) {
// Initialize NVS
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
state_mutex = xSemaphoreCreateMutex();
if (state_mutex == NULL) {
ESP_LOGE(TAG, "Failed to create state mutex");
return;
}
configure_peripherals();
wifi_init();
// MQTT client start is handled in the WiFi event handler
}
// --- Task Implementations ---
void sensor_reader_task(void *pvParameters) {
int adc_raw;
int read_interval = NORMAL_READ_INTERVAL_MS;
bool is_mqtt_connected = false;
while (1) {
// Only attempt to publish if MQTT is connected
if (mqtt_client != NULL) {
// A more robust check might involve a dedicated connection status flag
is_mqtt_connected = true;
}
// Read from ADC
ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, SMOKE_SENSOR_ADC_CHANNEL, &adc_raw));
ESP_LOGI(TAG, "Raw ADC value: %d", adc_raw);
xSemaphoreTake(state_mutex, portMAX_DELAY);
if (adc_raw > ALARM_THRESHOLD) {
if (system_state == STATE_NORMAL) {
ESP_LOGW(TAG, "ALARM TRIGGERED! ADC value: %d", adc_raw);
system_state = STATE_ALARM;
if (is_mqtt_connected) {
char payload[50];
snprintf(payload, sizeof(payload), "{\"status\":\"ALARM\", \"value\":%d}", adc_raw);
esp_mqtt_client_publish(mqtt_client, MQTT_TOPIC, payload, 0, 1, 1); // QoS 1, Retain
}
read_interval = ALARM_READ_INTERVAL_MS;
}
} else {
if (system_state == STATE_ALARM) {
ESP_LOGI(TAG, "System back to normal. ADC value: %d", adc_raw);
system_state = STATE_NORMAL;
if (is_mqtt_connected) {
char payload[50];
snprintf(payload, sizeof(payload), "{\"status\":\"NORMAL\", \"value\":%d}", adc_raw);
esp_mqtt_client_publish(mqtt_client, MQTT_TOPIC, payload, 0, 1, 1); // QoS 1, Retain
}
read_interval = NORMAL_READ_INTERVAL_MS;
}
}
xSemaphoreGive(state_mutex);
vTaskDelay(pdMS_TO_TICKS(read_interval));
}
}
void alarm_handler_task(void *pvParameters) {
bool local_alarm_active = false;
while (1) {
xSemaphoreTake(state_mutex, portMAX_DELAY);
alarm_state_t current_state = system_state;
xSemaphoreGive(state_mutex);
if (current_state == STATE_ALARM) {
local_alarm_active = true;
// Blink LED and sound buzzer
gpio_set_level(LED_ALARM_GPIO, 1);
gpio_set_level(BUZZER_ALARM_GPIO, 1);
vTaskDelay(pdMS_TO_TICKS(500));
gpio_set_level(LED_ALARM_GPIO, 0);
gpio_set_level(BUZZER_ALARM_GPIO, 0);
vTaskDelay(pdMS_TO_TICKS(500));
} else {
if (local_alarm_active) {
// Ensure alarms are off when returning to normal
gpio_set_level(LED_ALARM_GPIO, 0);
gpio_set_level(BUZZER_ALARM_GPIO, 0);
local_alarm_active = false;
}
// If normal, sleep longer to yield CPU time
vTaskDelay(pdMS_TO_TICKS(100));
}
}
}
// --- Initialization Functions ---
static void configure_peripherals(void) {
// --- Configure GPIO for Alarms ---
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << LED_ALARM_GPIO) | (1ULL << BUZZER_ALARM_GPIO),
.mode = GPIO_MODE_OUTPUT,
.intr_type = GPIO_INTR_DISABLE,
.pull_down_en = 0,
.pull_up_en = 0
};
gpio_config(&io_conf);
gpio_set_level(LED_ALARM_GPIO, 0);
gpio_set_level(BUZZER_ALARM_GPIO, 0);
ESP_LOGI(TAG, "Alarm GPIOs configured.");
// --- Configure ADC ---
adc_oneshot_unit_init_cfg_t init_config1 = {
.unit_id = ADC_UNIT_1,
};
ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config1, &adc1_handle));
adc_oneshot_chan_cfg_t config = {
.bitwidth = ADC_BITWIDTH_DEFAULT, // Corresponds to 12 bits
.atten = ADC_ATTEN_DB_11 // For input voltage range up to ~3.3V
};
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, SMOKE_SENSOR_ADC_CHANNEL, &config));
ESP_LOGI(TAG, "ADC configured on ADC1 Channel %d.", SMOKE_SENSOR_ADC_CHANNEL);
}
static void wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
ESP_LOGI(TAG, "Retrying WiFi connection...");
esp_wifi_connect();
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
ESP_LOGI(TAG, "Got IP address:" IPSTR, IP2STR(&event->ip_info.ip));
mqtt_app_start(); // Start MQTT client after getting an IP
}
}
static void wifi_init(void) {
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
// Register event handlers
esp_event_handler_instance_t instance_any_id;
esp_event_handler_instance_t instance_got_ip;
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, &instance_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL, &instance_got_ip));
wifi_config_t wifi_config = {
.sta = {
.ssid = CONFIG_ESP_WIFI_SSID,
.password = CONFIG_ESP_WIFI_PASSWORD,
.threshold.authmode = WIFI_AUTH_WPA2_PSK, // Set auth mode explicitly
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "WiFi initialization finished.");
// Start the main application tasks
xTaskCreate(sensor_reader_task, "sensor_reader_task", 4096, NULL, 5, NULL);
xTaskCreate(alarm_handler_task, "alarm_handler_task", 2048, NULL, 5, NULL);
}
static void mqtt_app_start(void) {
esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.uri = MQTT_BROKER_URL,
};
mqtt_client = esp_mqtt_client_init(&mqtt_cfg);
esp_mqtt_client_register_event(mqtt_client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
esp_mqtt_client_start(mqtt_client);
}
Build and Flash
- Connect your ESP32 board to your computer.
- In VS Code, use the ESP-IDF extension to select the correct COM port.
- Click the “Build, Flash, and Monitor” button (the flame icon with a plug).
Observe the Output
Once running, you will see log messages in the terminal:
- The system will connect to your Wi-Fi network.
- It will connect to the MQTT broker.
- You will see periodic ADC readings:
Raw ADC value: XXXX
. - Use an MQTT client (like MQTT Explorer) to subscribe to the topic
building/floor1/smoke_alarm/status
.
Now, test it! Bring a source of smoke (like a blown-out match) or combustible gas (from an unlit lighter) near the MQ-2 sensor.
- You should see the ADC value rise sharply.
- Once it crosses the
ALARM_THRESHOLD
, the log will show “ALARM TRIGGERED!”. - The LED will start flashing, and the buzzer will sound.
- An MQTT message with
{"status":"ALARM", ...}
will be published. - When the smoke dissipates, the ADC value will drop, the local alarms will cease, and a “NORMAL” status will be published.
Tip: The initial
ALARM_THRESHOLD
of2000
is a guess. You must calibrate this value for your specific sensor and environment. Run the device in a clean air environment to find the baseline reading, then expose it to a small amount of smoke to find a suitable trigger point.
Variant Notes
- ADC and Wi-Fi: On the original ESP32, ADC2 is shared with the Wi-Fi driver. You cannot reliably use ADC2 channels while Wi-Fi is active. The code example correctly uses ADC1 to avoid this conflict. The ESP32-S2, S3, C3, and C6 have improved this, and their ADC2 peripherals can be used alongside Wi-Fi without issue. However, sticking to ADC1 when possible is a good practice for cross-variant compatibility.
Feature / Consideration | Original ESP32 | ESP32-S3 | ESP32-C3 / C6 | ESP32-H2 |
---|---|---|---|---|
ADC & Wi-Fi Coexistence | ADC2 conflicts with Wi-Fi. Must use ADC1 as shown in the example. |
No conflict. ADC1 and ADC2 can be used with Wi-Fi. |
No conflict. ADC1 and ADC2 can be used with Wi-Fi. |
N/A (No Wi-Fi). |
Available ADC Pins | High (up to 18 channels) | High (up to 20 channels) | Lower (5-7 channels) | High (up to 12 channels) |
Connectivity | Wi-Fi + Classic BT/BLE | Wi-Fi + BLE 5 | Wi-Fi 4/6 + BLE 5 (+ 802.15.4 for C6) | BLE 5 + IEEE 802.15.4 (Zigbee/Thread) |
Project Adaptation | None. Works as-is. | None. Works as-is. | None, but verify pin numbers as GPIO count is lower. | Major. Replace Wi-Fi/MQTT with Zigbee or BLE notifications. |
- Available Pins: The number of available GPIOs and ADC channels differs. For example, the ESP32-C3 has fewer GPIOs than the ESP32-S3. Always consult the datasheet for your specific module to select valid pins for ADC, GPIO, etc.
- Wireless Protocols: This example uses Wi-Fi. All variants listed (ESP32, S2, S3, C3, C6) have Wi-Fi. The ESP32-H2 is an exception; it supports IEEE 802.15.4 (the foundation for Zigbee and Thread) and Bluetooth 5 (LE), but not Wi-Fi. To adapt this project for an ESP32-H2, you would replace the MQTT-over-Wi-Fi notification with a Zigbee message to a gateway or a BLE notification to a nearby device.
Common Mistakes & Troubleshooting Tips
Mistake / Issue | Symptom(s) | Troubleshooting / Solution |
---|---|---|
Alarm triggers randomly in clean air. | The buzzer and LED activate without any smoke present. MQTT messages show “ALARM” state unexpectedly. |
Calibrate Threshold: The ALARM_THRESHOLD is too low.
|
ADC readings are always 0 or 4095. | Sensor values do not change, or they are “railed” at the minimum or maximum value. |
Check Wiring and Attenuation: 1. Wiring: A reading of 0 could mean the AO pin is shorted to GND. A reading of 4095 could mean it’s shorted to 3V3. Check for loose wires or incorrect connections. 2. ADC Attenuation: Ensure .atten is set to ADC_ATTEN_DB_11 . If set incorrectly, the ADC’s voltage range will not match the sensor’s output.
|
Wi-Fi connects, but MQTT fails. | Logs show “Got IP address” but then “MQTT_EVENT_DISCONNECTED” or connection timeouts. |
Check MQTT Broker/Topic: 1. Broker URL: Verify the MQTT_BROKER_URL is correct and accessible from your network. A public broker like mqtt.eclipseprojects.io is good for testing.2. Firewall: Corporate or school networks may block the MQTT port (1883). Test on a different network (e.g., mobile hotspot) to confirm. |
Device reboots continuously in alarm state. | When the alarm triggers, the device runs for a moment and then resets (Guru Meditation Error). |
Task Stack Overflow: The alarm_handler_task may be using more stack than allocated.
|
Exercises
- Alarm Calibration and Multi-Stage Alerts:
- Modify the
sensor_reader_task
to only print the ADC value every second. - Expose your sensor to varying levels of smoke to determine three distinct thresholds:
NORMAL
(baseline),WARNING
(low smoke), andCRITICAL
(high smoke). - Update the
alarm_state_t
enum and the system logic to handle these three states. TheWARNING
state could trigger a slow-blinking LED, whileCRITICAL
triggers the fast-blinking LED and buzzer. Publish the appropriate state via MQTT.
- Modify the
- Local Alarm Silence Button:
- Add a push button to an available GPIO pin, configured as an input with an internal pull-up resistor.
- Implement a GPIO interrupt service routine (ISR) or a polling mechanism in a task.
- When the alarm is active and the button is pressed, the local alarms (buzzer/LED) should be silenced, but the
system_state
should remainSTATE_ALARM
. A “SILENCED” message should be published via MQTT. The alarm should only fully reset when the sensor readings return to normal.
- Heartbeat and Connectivity Status:
- Improve the system’s reliability by implementing a “heartbeat.”
- Modify the
sensor_reader_task
to publish an MQTT message with{ "status": "OK", "value": ... }
every 5 minutes while in theNORMAL
state. - This assures a remote monitoring system that the device is online and functioning correctly. Also, use the MQTT Last Will and Testament (LWT) feature (see Chapter 107) to publish an “OFFLINE” message if the device disconnects unexpectedly.
stateDiagram-v2 direction LR [*] --> NORMAL: System Start NORMAL --> WARNING: ADC > WARNING_THRESHOLD note right of NORMAL <b>Actions:</b> - LED Off - Buzzer Off - Publish "NORMAL" - Poll every 5s end note WARNING --> CRITICAL: ADC > CRITICAL_THRESHOLD WARNING --> NORMAL: ADC < WARNING_THRESHOLD note right of WARNING <b>Actions:</b> - LED Slow Blink - Buzzer Off - Publish "WARNING" - Poll every 2s end note CRITICAL --> WARNING: ADC < CRITICAL_THRESHOLD note right of CRITICAL <b>Actions:</b> - LED Fast Blink - Buzzer ON - Publish "CRITICAL" - Poll every 1s end note
Summary
- Smart fire alarm systems leverage IoT connectivity to provide remote notifications in addition to local alerts.
- MQ-series gas sensors offer a practical way to detect smoke and other combustibles, providing an analog voltage proportional to concentration.
- The ESP-IDF
adc_oneshot
driver is the modern API for performing simple, single ADC readings. Proper channel selection and attenuation are key configuration steps. - A robust embedded application often uses multiple FreeRTOS tasks to handle different concerns (e.g., sensing, acting, communicating) to prevent blocking and improve responsiveness.
- MQTT is an excellent protocol for relaying critical, low-latency alarm messages from an embedded device to a central server or application.
- Awareness of hardware differences, especially regarding ADC and Wi-Fi coexistence on older ESP32 variants, is crucial for writing portable and reliable code.
Further Reading
- ESP-IDF ADC Documentation: ESP-IDF ADC API Reference
- ESP-IDF MQTT Client Library: ESP-IDF MQTT Client Documentation
- MQ-2 Sensor Datasheet: A quick search for “MQ-2 Gas Sensor Datasheet” will yield numerous resources explaining its operating principles and characteristics curves.