<?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: Kevin Lee</title>
    <description>The latest articles on DEV Community by Kevin Lee (@kevin-thingboot).</description>
    <link>https://dev.to/kevin-thingboot</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%2F4229578%2F4843fe2c-da2d-43d9-b342-e2f601b71fd6.png</url>
      <title>DEV Community: Kevin Lee</title>
      <link>https://dev.to/kevin-thingboot</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kevin-thingboot"/>
    <language>en</language>
    <item>
      <title>ESP32 Self-Hosted IoT Platform: Your First MQTT Message in 15 Minutes</title>
      <dc:creator>Kevin Lee</dc:creator>
      <pubDate>Fri, 06 Nov 2026 04:42:53 +0000</pubDate>
      <link>https://dev.to/kevin-thingboot/esp32-self-hosted-iot-platform-your-first-mqtt-message-in-15-minutes-4i6p</link>
      <guid>https://dev.to/kevin-thingboot/esp32-self-hosted-iot-platform-your-first-mqtt-message-in-15-minutes-4i6p</guid>
      <description>&lt;p&gt;&lt;em&gt;This article is cross-posted from the &lt;a href="https://github.com/Kevin-ThingBoot/thingboot-guides" rel="noopener noreferrer"&gt;ThingBoot Guides&lt;/a&gt; repository on GitHub, where you'll also find the &lt;a href="https://github.com/Kevin-ThingBoot/thingboot-guides/blob/main/guides/01-esp32-mqtt-platform.zh-CN.md" rel="noopener noreferrer"&gt;Chinese version&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Most ESP32 tutorials stop at "blink an LED". Real products need the next step:&lt;br&gt;
get your device talking to a platform you &lt;strong&gt;own&lt;/strong&gt; — not someone else's cloud.&lt;/p&gt;

&lt;p&gt;This guide walks you from a stock ESP32 to publishing telemetry and receiving&lt;br&gt;
commands over MQTT against a self-hosted broker. It takes about 15 minutes.&lt;/p&gt;
&lt;h2&gt;
  
  
  What you need
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;An ESP32 dev board (ESP32 / ESP32-S3 / ESP32-C3 all work)&lt;/li&gt;
&lt;li&gt;USB cable + Arduino IDE (or PlatformIO)&lt;/li&gt;
&lt;li&gt;A machine that can run an MQTT broker (Docker is fine)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ESP32] --WiFi--&amp;gt; [MQTT Broker (self-hosted)] ---&amp;gt; [Your apps / dashboards / AI agents]
         &amp;lt;-------- (commands, OTA triggers) ------
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Self-hosting the broker means: your data stays on your network, you control&lt;br&gt;
auth, and AI agents can talk to devices through the same topics later.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1 — Run a broker
&lt;/h2&gt;

&lt;p&gt;The fastest way to get a local broker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 1883:1883 &lt;span class="nt"&gt;--name&lt;/span&gt; mosquitto eclipse-mosquitto
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create a minimal &lt;code&gt;mosquitto.conf&lt;/code&gt; allowing local testing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;listener 1883
allow_anonymous true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;For production: always enable auth + TLS. See the &lt;a href="https://github.com/Kevin-ThingBoot/thingboot-guides/blob/main/guides/02-esp32-ota-production.md" rel="noopener noreferrer"&gt;OTA &amp;amp; safe-mode guide&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 2 — Flash the ESP32
&lt;/h2&gt;

&lt;p&gt;Install the &lt;a href="https://github.com/ThingBoot/thingboot-device-esp-arduino-sdk" rel="noopener noreferrer"&gt;ThingBoot ESP Arduino SDK&lt;/a&gt;,&lt;br&gt;
which wraps WiFi provisioning, MQTT reconnect, and OTA into a setup()/loop()&lt;br&gt;
model. Or use plain Arduino with PubSubClient — the flow is the same:&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="n"&gt;WiFiClient&lt;/span&gt; &lt;span class="n"&gt;net&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;mqtt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;net&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;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="s"&gt;"YOUR_SSID"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"YOUR_PASSWORD"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;while&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="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;mqtt&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="s"&gt;"192.168.1.100"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1883&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// your broker's LAN IP&lt;/span&gt;
  &lt;span class="n"&gt;mqtt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setCallback&lt;/span&gt;&lt;span class="p"&gt;([](&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;topic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;payload&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;int&lt;/span&gt; &lt;span class="n"&gt;len&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;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"command received on %s: %.*s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&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="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;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;mqtt&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="n"&gt;mqtt&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-demo"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;mqtt&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="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;last&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;last&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;last&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="n"&gt;mqtt&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="s"&gt;"things/esp32-demo/telemetry"&lt;/span&gt;&lt;span class="p"&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;temp&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;:25.5,&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;rssi&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;:-60}"&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;h2&gt;
  
  
  Step 3 — Verify
&lt;/h2&gt;

&lt;p&gt;Subscribe from your computer and watch data arrive:&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="nt"&gt;-h&lt;/span&gt; 192.168.1.100 &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="s2"&gt;"things/#"&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then send a command back to the device:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mosquitto_pub &lt;span class="nt"&gt;-h&lt;/span&gt; 192.168.1.100 &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="s2"&gt;"things/esp32-demo/cmd"&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s1"&gt;'{"relay":"on"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see telemetry flowing and the device reacting to commands — congratulations,&lt;br&gt;
that's the entire foundation of an IoT fleet: &lt;strong&gt;device → platform → device&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to go next
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Goal&lt;/th&gt;
&lt;th&gt;Guide&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OTA updates for production fleets (A/B partitions, rollback, safe mode)&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/Kevin-ThingBoot/thingboot-guides/blob/main/guides/02-esp32-ota-production.md" rel="noopener noreferrer"&gt;Part 2&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Letting an AI agent control devices via MCP&lt;/td&gt;
&lt;td&gt;Part 3 (planned)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full SDK with provisioning + rollback&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/ThingBoot" rel="noopener noreferrer"&gt;ThingBoot SDKs&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;&lt;em&gt;ThingBoot provides free device SDKs and a self-hosted IoT platform.&lt;br&gt;
Questions? Open an &lt;a href="https://github.com/Kevin-ThingBoot/thingboot-guides/issues" rel="noopener noreferrer"&gt;issue&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>esp32</category>
      <category>iot</category>
      <category>mqtt</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
