<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nobel Build Repairs</title>
    <description>The latest articles on DEV Community by Nobel Build Repairs (@nobel_buildrepairs_74b47).</description>
    <link>https://dev.to/nobel_buildrepairs_74b47</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4208957%2Ffbab6611-ff70-42ef-98a1-9aea1d7bd945.png</url>
      <title>DEV Community: Nobel Build Repairs</title>
      <link>https://dev.to/nobel_buildrepairs_74b47</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nobel_buildrepairs_74b47"/>
    <language>en</language>
    <item>
      <title>Building a Smart Water Leak Detection System with ESP32 and MQTT</title>
      <dc:creator>Nobel Build Repairs</dc:creator>
      <pubDate>Mon, 26 Oct 2026 14:57:09 +0000</pubDate>
      <link>https://dev.to/nobel_buildrepairs_74b47/building-a-smart-water-leak-detection-system-with-esp32-and-mqtt-3cd</link>
      <guid>https://dev.to/nobel_buildrepairs_74b47/building-a-smart-water-leak-detection-system-with-esp32-and-mqtt-3cd</guid>
      <description>&lt;p&gt;Water leaks are a surprisingly useful problem to explore when learning about the Internet of Things (IoT). They involve real-world sensor input, microcontroller programming, network communication, message processing and alert handling.&lt;/p&gt;

&lt;p&gt;A simple water-contact sensor can detect unexpected moisture, but building a connected monitoring system requires several components working together.&lt;/p&gt;

&lt;p&gt;In this tutorial, we'll create an educational water leak detection prototype using an ESP32, a digital water sensor, Wi-Fi and MQTT.&lt;/p&gt;

&lt;p&gt;We'll also discuss sensor debouncing, network failures, security and potential improvements.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We'll Build
&lt;/h2&gt;

&lt;p&gt;Our prototype will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read a digital water-contact sensor.&lt;/li&gt;
&lt;li&gt;Distinguish between wet and dry readings.&lt;/li&gt;
&lt;li&gt;Connect an ESP32 to a Wi-Fi network.&lt;/li&gt;
&lt;li&gt;Publish sensor states to an MQTT broker.&lt;/li&gt;
&lt;li&gt;Send an updated message when the confirmed state changes.&lt;/li&gt;
&lt;li&gt;Publish periodic status messages.&lt;/li&gt;
&lt;li&gt;Allow another application to subscribe to those messages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The architecture is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Water Contact Sensor
        |
        v
      ESP32
        |
       Wi-Fi
        |
        v
    MQTT Broker
        |
        v
 Monitoring Application
        |
        v
   Dashboard / Alert
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a monitoring prototype, not a certified water protection system.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Hardware Requirements
&lt;/h2&gt;

&lt;p&gt;You'll need the following components:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ESP32 development board&lt;/td&gt;
&lt;td&gt;Reads sensor data and manages communication&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Digital water-contact sensor module&lt;/td&gt;
&lt;td&gt;Detects water contact&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jumper wires&lt;/td&gt;
&lt;td&gt;Connects the components&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Breadboard&lt;/td&gt;
&lt;td&gt;Supports prototyping&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;USB cable&lt;/td&gt;
&lt;td&gt;Powers and programs the ESP32&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Computer&lt;/td&gt;
&lt;td&gt;Runs the development environment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MQTT broker&lt;/td&gt;
&lt;td&gt;Receives published sensor messages&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For this example, use a digital sensor module with an output that is compatible with the ESP32's 3.3 V GPIO input.&lt;/p&gt;

&lt;p&gt;Do not connect a 5 V output directly to an ESP32 GPIO pin.&lt;/p&gt;

&lt;p&gt;We will assume that our particular sensor produces a LOW signal when water is detected. Your sensor may behave differently, so check its documentation before connecting it.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Connecting the Water Sensor
&lt;/h2&gt;

&lt;p&gt;For an appropriately rated digital sensor module, an example connection is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ESP32              Water Sensor

3.3V  ------------ VCC
GND   ------------ GND
GPIO27 ------------ DO
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;DO&lt;/code&gt; represents the sensor module's digital output.&lt;/p&gt;

&lt;p&gt;The ESP32 will read the value using &lt;code&gt;digitalRead()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Keep the electronics and power connections away from water. Only the appropriately designed sensing portion should be exposed during testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Set Up the Development Environment
&lt;/h2&gt;

&lt;p&gt;We'll use the Arduino IDE with the ESP32 board support package.&lt;/p&gt;

&lt;p&gt;Install the appropriate ESP32 board package and select the correct development board.&lt;/p&gt;

&lt;p&gt;Next, install the &lt;strong&gt;PubSubClient&lt;/strong&gt; MQTT library through the Arduino Library Manager.&lt;/p&gt;

&lt;p&gt;We'll use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;WiFi.h&lt;/code&gt; for Wi-Fi connectivity&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PubSubClient.h&lt;/code&gt; for MQTT messaging&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You'll also need an MQTT broker.&lt;/p&gt;

&lt;p&gt;For local experimentation, you can run Mosquitto on another computer connected to the same trusted network.&lt;/p&gt;

&lt;p&gt;Configure the broker to accept connections from the ESP32, using appropriate test credentials and network restrictions.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Understanding MQTT
&lt;/h2&gt;

&lt;p&gt;MQTT is a publish/subscribe messaging protocol.&lt;/p&gt;

&lt;p&gt;Instead of sending sensor readings directly to every application, a device publishes messages to a broker.&lt;/p&gt;

&lt;p&gt;Other applications subscribe to topics and receive those messages.&lt;/p&gt;

&lt;p&gt;For example, our ESP32 can publish to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;home/water-sensor-01/status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A sample payload might be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"device_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"water-sensor-01"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"water_detected"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This separation makes it easier to connect different monitoring applications without changing the sensor hardware.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. ESP32 Water Leak Monitoring Code
&lt;/h2&gt;

&lt;p&gt;The following Arduino example reads a digital sensor and publishes its confirmed state using MQTT.&lt;/p&gt;

&lt;p&gt;Replace the placeholder connection settings before uploading.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;WiFi.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;PubSubClient.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="c1"&gt;// Network configuration&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;WIFI_SSID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"YOUR_WIFI_NAME"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;WIFI_PASSWORD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"YOUR_WIFI_PASSWORD"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Local MQTT broker&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;MQTT_HOST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"192.168.1.100"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;MQTT_PORT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1883&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;MQTT_USER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"YOUR_MQTT_USER"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;MQTT_PASSWORD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"YOUR_MQTT_PASSWORD"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// MQTT topic&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;STATUS_TOPIC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="s"&gt;"home/water-sensor-01/status"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Hardware&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;SENSOR_PIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Change this if your sensor is active HIGH.&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;WET_LEVEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LOW&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;WiFiClient&lt;/span&gt; &lt;span class="n"&gt;wifiClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;PubSubClient&lt;/span&gt; &lt;span class="nf"&gt;mqttClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wifiClient&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Simple sensor stability filtering&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;REQUIRED_READINGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;confirmedWet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;lastRawWet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;hasConfirmedState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;matchingReadings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;lastSample&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;lastPublish&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;SAMPLE_INTERVAL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;PUBLISH_INTERVAL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;connectWiFi&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WiFi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;WL_CONNECTED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;WiFi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WIFI_SSID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;WIFI_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;connectMQTT&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WiFi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;WL_CONNECTED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mqttClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connected&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;mqttClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"esp32-water-sensor-01"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;MQTT_USER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;MQTT_PASSWORD&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;publishStatus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;mqttClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connected&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
      &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;hasConfirmedState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"{"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;device_id&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;water-sensor-01&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;,"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;water_detected&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;:"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;confirmedWet&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;"}"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;published&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mqttClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;STATUS_TOPIC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nb"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;published&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lastPublish&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;readSensor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;rawWet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;digitalRead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SENSOR_PIN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;WET_LEVEL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rawWet&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;lastRawWet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;matchingReadings&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;REQUIRED_READINGS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;matchingReadings&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lastRawWet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rawWet&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;matchingReadings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;matchingReadings&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;REQUIRED_READINGS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;hasConfirmedState&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
        &lt;span class="n"&gt;rawWet&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;confirmedWet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;confirmedWet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rawWet&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;hasConfirmedState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;confirmedWet&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;
        &lt;span class="s"&gt;"Water detected!"&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="s"&gt;"Sensor is dry."&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="n"&gt;publishStatus&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;115200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;pinMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SENSOR_PIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;INPUT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;WiFi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WIFI_STA&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;mqttClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;MQTT_HOST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;MQTT_PORT&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;connectWiFi&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;lastConnectAttempt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lastConnectAttempt&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lastConnectAttempt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;connectWiFi&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;connectMQTT&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mqttClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connected&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mqttClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lastSample&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;SAMPLE_INTERVAL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lastSample&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;readSensor&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hasConfirmedState&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
      &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lastPublish&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;PUBLISH_INTERVAL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;publishStatus&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How the Code Works
&lt;/h3&gt;

&lt;p&gt;First, the ESP32 connects to the configured Wi-Fi network.&lt;/p&gt;

&lt;p&gt;After connecting, it attempts to establish an MQTT connection using the configured broker address.&lt;/p&gt;

&lt;p&gt;The program reads the sensor approximately every 500 milliseconds.&lt;/p&gt;

&lt;p&gt;Instead of accepting every reading immediately, it requires three consistent observations before confirming the wet or dry state.&lt;/p&gt;

&lt;p&gt;When the confirmed state changes, the device attempts to publish an MQTT message.&lt;/p&gt;

&lt;p&gt;It also attempts periodic status updates.&lt;/p&gt;

&lt;p&gt;The message uses the retained-message flag, allowing a new MQTT subscriber to receive the broker's most recently retained status.&lt;/p&gt;

&lt;p&gt;However, this simple example has limitations.&lt;/p&gt;

&lt;p&gt;It does not guarantee message delivery during a network outage, and a retained message may become stale if the device disconnects.&lt;/p&gt;

&lt;p&gt;For production systems, a separate device availability topic, persistent event identifiers and more robust reconnection logic would be useful.&lt;/p&gt;

&lt;p&gt;The basic &lt;code&gt;WiFiClient&lt;/code&gt; connection in this example is also unencrypted. It is intended only for a trusted local development network. A deployed system should use TLS-capable communication, properly managed credentials and appropriate broker access controls.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Subscribe to Sensor Messages
&lt;/h2&gt;

&lt;p&gt;Once the ESP32 starts publishing, another MQTT client can subscribe to its status topic.&lt;/p&gt;

&lt;p&gt;For example, using Mosquitto's command-line client:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mosquitto_sub &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-h&lt;/span&gt; 192.168.1.100 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 1883 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="s2"&gt;"YOUR_MQTT_USER"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-P&lt;/span&gt; &lt;span class="s2"&gt;"YOUR_MQTT_PASSWORD"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="s2"&gt;"home/water-sensor-01/status"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace the broker address and credentials with your test environment's values.&lt;/p&gt;

&lt;p&gt;When the sensor detects water, a message similar to the following should appear:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"device_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"water-sensor-01"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"water_detected"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the sensor returns to its dry state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"device_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"water-sensor-01"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"water_detected"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A separate monitoring application could use these messages to update a dashboard or trigger notifications.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Why Debouncing Matters
&lt;/h2&gt;

&lt;p&gt;Physical sensors are not always perfectly stable.&lt;/p&gt;

&lt;p&gt;A sensor exposed to intermittent moisture might alternate between wet and dry readings over a short period.&lt;/p&gt;

&lt;p&gt;If every individual reading triggers an alert, the monitoring application could generate unnecessary notifications.&lt;/p&gt;

&lt;p&gt;Our simple example requires three consecutive matching readings before confirming a state.&lt;/p&gt;

&lt;p&gt;This provides basic filtering, but it is not a complete solution.&lt;/p&gt;

&lt;p&gt;More advanced designs might use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Time-based validation&lt;/li&gt;
&lt;li&gt;Moving averages for analogue sensors&lt;/li&gt;
&lt;li&gt;Separate wet and dry thresholds&lt;/li&gt;
&lt;li&gt;Sensor health checks&lt;/li&gt;
&lt;li&gt;Configurable recovery periods&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The correct filtering strategy depends on the actual sensor and its intended operating conditions.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Handling Network Failures
&lt;/h2&gt;

&lt;p&gt;One of the challenges in connected-device development is deciding what happens when communication stops.&lt;/p&gt;

&lt;p&gt;A water sensor may detect moisture while Wi-Fi is unavailable.&lt;/p&gt;

&lt;p&gt;In that situation, an internet-based alert may never reach the user.&lt;/p&gt;

&lt;p&gt;A more robust implementation could include a local buzzer that activates independently of Wi-Fi.&lt;/p&gt;

&lt;p&gt;Other improvements include offline event buffering, connection-health reporting and a monitoring service that recognises when a device has stopped transmitting.&lt;/p&gt;

&lt;p&gt;These features become especially important when the monitoring system is expected to operate without someone regularly checking it.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Security Considerations
&lt;/h2&gt;

&lt;p&gt;IoT devices are often installed in environments where they may operate for long periods.&lt;/p&gt;

&lt;p&gt;Security therefore needs attention beyond the initial prototype.&lt;/p&gt;

&lt;p&gt;Important considerations include:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Encrypted communication:&lt;/strong&gt; Protect sensor messages with suitable transport encryption when communicating outside a restricted test environment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Credential management:&lt;/strong&gt; Avoid publishing working passwords or embedding shared credentials in public repositories.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Topic permissions:&lt;/strong&gt; Restrict which MQTT topics a device can access.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Firmware updates:&lt;/strong&gt; Establish a maintenance process for security fixes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Network segmentation:&lt;/strong&gt; Isolate IoT devices where appropriate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data minimisation:&lt;/strong&gt; Avoid collecting unnecessary information about property occupants.&lt;/p&gt;

&lt;p&gt;Even relatively simple devices should follow basic security practices.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Testing the Monitoring System
&lt;/h2&gt;

&lt;p&gt;Before relying on the prototype, test its behaviour under different conditions.&lt;/p&gt;

&lt;p&gt;A useful test plan includes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Confirming correct readings when the sensor is dry.&lt;/li&gt;
&lt;li&gt;Safely testing water contact according to the sensor manufacturer's instructions.&lt;/li&gt;
&lt;li&gt;Checking that MQTT messages contain the expected state.&lt;/li&gt;
&lt;li&gt;Repeating the wet/dry transition to examine debouncing.&lt;/li&gt;
&lt;li&gt;Disconnecting Wi-Fi and observing reconnection behaviour.&lt;/li&gt;
&lt;li&gt;Restarting the MQTT broker.&lt;/li&gt;
&lt;li&gt;Testing the system after a power interruption.&lt;/li&gt;
&lt;li&gt;Checking what happens when the sensor cable is disconnected.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The final test is particularly important.&lt;/p&gt;

&lt;p&gt;A basic digital input may not distinguish a disconnected sensor from a valid dry reading.&lt;/p&gt;

&lt;p&gt;Production equipment should use appropriate fault-detection techniques rather than assuming that no alarm means no problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  11. Real-World Applications
&lt;/h2&gt;

&lt;p&gt;A connected water-monitoring system could be useful in several environments.&lt;/p&gt;

&lt;p&gt;For example, sensors may be positioned near washing machines, beneath kitchen sinks or around accessible pipework.&lt;/p&gt;

&lt;p&gt;Property management applications could combine multiple sensor readings into a monitoring dashboard.&lt;/p&gt;

&lt;p&gt;A monitoring application could also maintain an event history to help maintenance teams understand recurring problems.&lt;/p&gt;

&lt;p&gt;However, identifying water contact is only one part of dealing with a plumbing issue.&lt;/p&gt;

&lt;p&gt;The actual fault may involve damaged pipework, a leaking fitting or another component requiring physical inspection.&lt;/p&gt;

&lt;p&gt;Businesses involved in property maintenance, such as &lt;a href="https://nobelbuildrepairs.co.uk/" rel="noopener noreferrer"&gt;Nobel Build &amp;amp; Repairs Ltd&lt;/a&gt;, operate in an area where reliable leak information and timely repair coordination can be valuable.&lt;/p&gt;

&lt;p&gt;This illustrates how software monitoring can complement practical building maintenance without replacing professional diagnosis.&lt;/p&gt;

&lt;h2&gt;
  
  
  12. Future Improvements
&lt;/h2&gt;

&lt;p&gt;This prototype can be extended in several directions.&lt;/p&gt;

&lt;p&gt;Potential improvements include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple ESP32 sensor nodes&lt;/li&gt;
&lt;li&gt;A web-based monitoring dashboard&lt;/li&gt;
&lt;li&gt;Mobile push notifications&lt;/li&gt;
&lt;li&gt;Battery status reporting&lt;/li&gt;
&lt;li&gt;Sensor calibration interfaces&lt;/li&gt;
&lt;li&gt;TLS-secured MQTT connections&lt;/li&gt;
&lt;li&gt;Offline message buffering&lt;/li&gt;
&lt;li&gt;Device health and availability reporting&lt;/li&gt;
&lt;li&gt;Home Assistant integration&lt;/li&gt;
&lt;li&gt;Historical event visualisation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a more advanced system, developers could investigate suitable flow sensors or professionally installed automatic shut-off equipment.&lt;/p&gt;

&lt;p&gt;However, automated control of water supplies introduces additional safety and reliability considerations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;An ESP32-based water leak monitoring prototype is a useful project for learning about real-world IoT development.&lt;/p&gt;

&lt;p&gt;It combines sensor interfacing, Arduino programming, network connectivity, MQTT messaging and basic event processing.&lt;/p&gt;

&lt;p&gt;It also highlights broader engineering challenges such as sensor reliability, cybersecurity, network failures and monitoring architecture.&lt;/p&gt;

&lt;p&gt;Although the prototype is straightforward, developing it into a dependable system requires careful testing and more advanced failure handling.&lt;/p&gt;

&lt;p&gt;The most useful IoT projects are those that solve clearly defined problems while accounting for the limitations of both hardware and software.&lt;/p&gt;

</description>
      <category>hardware</category>
      <category>iot</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
