<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>ESP32 on Nalar</title>
    <link>https://nalar.dev/tags/esp32/</link>
    <description>Recent content in ESP32 on Nalar</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <lastBuildDate>Sat, 19 Sep 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://nalar.dev/tags/esp32/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>ESP-IDF LCD APIs Depend on the Selected SoC Target</title>
      <link>https://nalar.dev/esp-idf-lcd-apis-depend-on-the-selected-soc-target/</link>
      <pubDate>Sat, 19 Sep 2026 00:00:00 +0000</pubDate>
      <guid>https://nalar.dev/esp-idf-lcd-apis-depend-on-the-selected-soc-target/</guid>
      <description>&lt;p&gt;An ESP-IDF project can include &lt;code&gt;esp_lcd_panel_io.h&lt;/code&gt; successfully and still fail on &lt;code&gt;esp_lcd_i80_bus_config_t&lt;/code&gt; or &lt;code&gt;esp_lcd_new_i80_bus()&lt;/code&gt;. That combination looks contradictory until the build target is taken into account.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;esp_lcd&lt;/code&gt; is a framework, not a promise that every ESP chip exposes every LCD transport. The selected SoC determines which low-level interfaces are compiled into the project. Panel-controller support, such as ILI9341, is another layer again.&lt;/p&gt;&#xA;&lt;p&gt;That distinction matters when moving code between ESP32 variants.&lt;/p&gt;</description>
    </item>
    <item>
      <title>ESP32 MQTT over TLS: Transport Encryption and Broker Authentication Are Separate</title>
      <link>https://nalar.dev/esp32-mqtt-tls-transport-encryption-broker-authentication/</link>
      <pubDate>Sat, 19 Sep 2026 00:00:00 +0000</pubDate>
      <guid>https://nalar.dev/esp32-mqtt-tls-transport-encryption-broker-authentication/</guid>
      <description>&lt;p&gt;An ESP32 that moves an MQTT connection from port 1883 to 8883 crosses more than a port boundary. The TCP stream is now expected to carry MQTT inside TLS. Data in transit is protected only when the TLS client also validates the broker certificate. MQTT username/password authentication is separate: credentials identify the client to the broker, while certificate validation identifies the broker to the ESP32.&lt;/p&gt;&#xA;&lt;p&gt;Calling this &amp;ldquo;MQTT with HTTPS&amp;rdquo; mixes two application protocols. MQTT does not become HTTP when TLS is added. MQTT can run over plain TCP or over a TLS-protected TCP connection.&lt;/p&gt;</description>
    </item>
    <item>
      <title>ESP32 MQTT Sensor State: Publishing DHT22 Temperature and Humidity as One JSON Message</title>
      <link>https://nalar.dev/esp32-mqtt-sensor-state-json-dht22/</link>
      <pubDate>Sat, 19 Sep 2026 00:00:00 +0000</pubDate>
      <guid>https://nalar.dev/esp32-mqtt-sensor-state-json-dht22/</guid>
      <description>&lt;p&gt;A DHT22 read produces temperature and relative humidity from the same sampling event. Publishing them on separate MQTT topics works, but it also creates two independent message boundaries. A subscriber can receive the new temperature before the matching humidity value arrives.&lt;/p&gt;&#xA;&lt;p&gt;Putting both measurements in one payload preserves the relationship explicitly:&lt;/p&gt;&#xA;&lt;div&#xA;  x-data=&#34;{ code: $el.querySelector(&#39;code&#39;).innerText, copied: false }&#34;&#xA;  class=&#34;code-block group relative my-6 overflow-hidden rounded-xl border border-line bg-surface-muted dark:border-night-line dark:bg-night-surface&#34;&gt;&#xA;  &lt;button&#xA;    type=&#34;button&#34;&#xA;    @click=&#34;navigator.clipboard.writeText(code); copied = true; setTimeout(() =&gt; copied = false, 1600)&#34;&#xA;    class=&#34;absolute right-3 top-3 z-10 rounded-lg border border-line-strong bg-surface px-2 py-1 font-mono text-[0.8rem] text-muted opacity-0 transition group-hover:opacity-100 hover:bg-ink hover:text-white dark:border-night-line dark:bg-night dark:text-night-muted dark:hover:bg-white dark:hover:text-ink&#34;&gt;&#xA;    &lt;span x-text=&#34;copied ? &#39;Copied&#39; : &#39;Copy&#39;&#34;&gt;&lt;/span&gt;&#xA;  &lt;/button&gt;&#xA;  &#xA;  &lt;div class=&#34;overflow-x-auto p-4 text-sm leading-6 [&amp;_pre]:!m-0 [&amp;_pre]:!bg-transparent [&amp;_pre]:!p-0 [&amp;_code]:font-mono&#34;&gt;&#xA;    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;#34;temperature&amp;#34;&lt;/span&gt;:25.34,&lt;span style=&#34;font-weight:bold&#34;&gt;&amp;#34;humidity&amp;#34;&lt;/span&gt;:60.21}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#xA;  &lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;MQTT does not require JSON. The useful property here is that both measurements travel in one publication and can be treated as one sensor-state snapshot.&lt;/p&gt;</description>
    </item>
    <item>
      <title>GPS Distance and IMU Balance on ESP32 Measure Different Things</title>
      <link>https://nalar.dev/gps-distance-imu-balance-esp32/</link>
      <pubDate>Sat, 19 Sep 2026 00:00:00 +0000</pubDate>
      <guid>https://nalar.dev/gps-distance-imu-balance-esp32/</guid>
      <description>&lt;p&gt;A GPS module and an IMU can both feed an ESP32 with numbers that describe motion, but they observe different physical quantities. Treating them as interchangeable sensors creates bad measurements quickly.&lt;/p&gt;&#xA;&lt;p&gt;A GPS receiver estimates geographic position from satellite signals. Two position fixes can be converted into an approximate distance across Earth&amp;rsquo;s surface. An IMU such as the MPU-6050 measures acceleration and angular rate along its axes. Those measurements can be used to estimate tilt, rotation, and short-term motion.&lt;/p&gt;</description>
    </item>
    <item>
      <title>How Linux Maps an ESP32 USB-UART Bridge to /dev/ttyUSB0 on Fedora</title>
      <link>https://nalar.dev/esp32-usb-serial-ports-on-fedora/</link>
      <pubDate>Sat, 19 Sep 2026 00:00:00 +0000</pubDate>
      <guid>https://nalar.dev/esp32-usb-serial-ports-on-fedora/</guid>
      <description>&lt;p&gt;An ESP32 development board connected through a CH341 USB-to-UART bridge does not appear on Fedora as a Windows-style COM port. Linux binds the USB interface to a serial driver and exposes a character device such as &lt;code&gt;/dev/ttyUSB0&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;A working connection can produce this kernel message:&lt;/p&gt;&#xA;&lt;div&#xA;  x-data=&#34;{ code: $el.querySelector(&#39;code&#39;).innerText, copied: false }&#34;&#xA;  class=&#34;code-block group relative my-6 overflow-hidden rounded-xl border border-line bg-surface-muted dark:border-night-line dark:bg-night-surface&#34;&gt;&#xA;  &lt;button&#xA;    type=&#34;button&#34;&#xA;    @click=&#34;navigator.clipboard.writeText(code); copied = true; setTimeout(() =&gt; copied = false, 1600)&#34;&#xA;    class=&#34;absolute right-3 top-3 z-10 rounded-lg border border-line-strong bg-surface px-2 py-1 font-mono text-[0.8rem] text-muted opacity-0 transition group-hover:opacity-100 hover:bg-ink hover:text-white dark:border-night-line dark:bg-night dark:text-night-muted dark:hover:bg-white dark:hover:text-ink&#34;&gt;&#xA;    &lt;span x-text=&#34;copied ? &#39;Copied&#39; : &#39;Copy&#39;&#34;&gt;&lt;/span&gt;&#xA;  &lt;/button&gt;&#xA;  &#xA;  &lt;div class=&#34;overflow-x-auto p-4 text-sm leading-6 [&amp;_pre]:!m-0 [&amp;_pre]:!bg-transparent [&amp;_pre]:!p-0 [&amp;_code]:font-mono&#34;&gt;&#xA;    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;usb 5-1: ch341-uart converter now attached to ttyUSB0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#xA;  &lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;That line confirms USB enumeration, binding to the &lt;code&gt;ch341&lt;/code&gt; serial driver, and creation of &lt;code&gt;ttyUSB0&lt;/code&gt;. The path used by a flasher or serial monitor is therefore &lt;code&gt;/dev/ttyUSB0&lt;/code&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Raw IR Capture and Replay on ESP32 Depends on Timing, Frame Boundaries, and Carrier Frequency</title>
      <link>https://nalar.dev/raw-ir-capture-and-replay-on-esp32-timing-frame-boundaries-carrier-frequency/</link>
      <pubDate>Sat, 19 Sep 2026 00:00:00 +0000</pubDate>
      <guid>https://nalar.dev/raw-ir-capture-and-replay-on-esp32-timing-frame-boundaries-carrier-frequency/</guid>
      <description>&lt;p&gt;An infrared receiver does not hand an ESP32 a universal &amp;ldquo;button code.&amp;rdquo; At the electrical boundary, it produces a sequence of detected carrier bursts and gaps. A raw capture represents those intervals as alternating mark and space durations, usually in microseconds.&lt;/p&gt;&#xA;&lt;p&gt;A capture such as:&lt;/p&gt;&#xA;&lt;div&#xA;  x-data=&#34;{ code: $el.querySelector(&#39;code&#39;).innerText, copied: false }&#34;&#xA;  class=&#34;code-block group relative my-6 overflow-hidden rounded-xl border border-line bg-surface-muted dark:border-night-line dark:bg-night-surface&#34;&gt;&#xA;  &lt;button&#xA;    type=&#34;button&#34;&#xA;    @click=&#34;navigator.clipboard.writeText(code); copied = true; setTimeout(() =&gt; copied = false, 1600)&#34;&#xA;    class=&#34;absolute right-3 top-3 z-10 rounded-lg border border-line-strong bg-surface px-2 py-1 font-mono text-[0.8rem] text-muted opacity-0 transition group-hover:opacity-100 hover:bg-ink hover:text-white dark:border-night-line dark:bg-night dark:text-night-muted dark:hover:bg-white dark:hover:text-ink&#34;&gt;&#xA;    &lt;span x-text=&#34;copied ? &#39;Copied&#39; : &#39;Copy&#39;&#34;&gt;&lt;/span&gt;&#xA;  &lt;/button&gt;&#xA;  &#xA;  &lt;div class=&#34;overflow-x-auto p-4 text-sm leading-6 [&amp;_pre]:!m-0 [&amp;_pre]:!bg-transparent [&amp;_pre]:!p-0 [&amp;_code]:font-mono&#34;&gt;&#xA;    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;uint16_t&lt;/span&gt; rawData[] = {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  3570, 1620,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  554, 342,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  498, 1244,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  496, 378,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;font-style:italic&#34;&gt;// ...&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-style:italic&#34;&gt;&lt;/span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#xA;  &lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;is therefore a waveform description. Replaying it successfully depends on preserving four things together: the timing sequence, the correct frame boundary, the modulation carrier used for marks, and enough optical output from the IR LED.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Reading ESP32 I2S Pin Definitions: MCLK, BCLK, WS, DIN, and DOUT</title>
      <link>https://nalar.dev/esp32-i2s-pin-definitions-mclk-bclk-ws-din-dout/</link>
      <pubDate>Sat, 19 Sep 2026 00:00:00 +0000</pubDate>
      <guid>https://nalar.dev/esp32-i2s-pin-definitions-mclk-bclk-ws-din-dout/</guid>
      <description>&lt;p&gt;An ESP32 audio configuration can look deceptively similar to ordinary GPIO setup:&lt;/p&gt;&#xA;&lt;div&#xA;  x-data=&#34;{ code: $el.querySelector(&#39;code&#39;).innerText, copied: false }&#34;&#xA;  class=&#34;code-block group relative my-6 overflow-hidden rounded-xl border border-line bg-surface-muted dark:border-night-line dark:bg-night-surface&#34;&gt;&#xA;  &lt;button&#xA;    type=&#34;button&#34;&#xA;    @click=&#34;navigator.clipboard.writeText(code); copied = true; setTimeout(() =&gt; copied = false, 1600)&#34;&#xA;    class=&#34;absolute right-3 top-3 z-10 rounded-lg border border-line-strong bg-surface px-2 py-1 font-mono text-[0.8rem] text-muted opacity-0 transition group-hover:opacity-100 hover:bg-ink hover:text-white dark:border-night-line dark:bg-night dark:text-night-muted dark:hover:bg-white dark:hover:text-ink&#34;&gt;&#xA;    &lt;span x-text=&#34;copied ? &#39;Copied&#39; : &#39;Copy&#39;&#34;&gt;&lt;/span&gt;&#xA;  &lt;/button&gt;&#xA;  &#xA;  &lt;div class=&#34;overflow-x-auto p-4 text-sm leading-6 [&amp;_pre]:!m-0 [&amp;_pre]:!bg-transparent [&amp;_pre]:!p-0 [&amp;_code]:font-mono&#34;&gt;&#xA;    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;&#34;&gt;uint8_t&lt;/span&gt; I2S_MCLK = 0;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;&#34;&gt;uint8_t&lt;/span&gt; I2S_SCK = 5;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;&#34;&gt;uint8_t&lt;/span&gt; I2S_WS = 25;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;&#34;&gt;uint8_t&lt;/span&gt; I2S_SDOUT = 26;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;&#34;&gt;uint8_t&lt;/span&gt; I2S_SDIN = 35;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#xA;  &lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;These constants do not define five interchangeable audio wires. Each represents a different part of the I2S timing and data path. A speaker amplifier can remain completely silent even when every GPIO is electrically connected if BCLK and WS are missing, the data direction is reversed, or the frame format does not match the receiving device.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Reliable ESP32 IR Air-Conditioner Control Needs Hysteresis and State Synchronization</title>
      <link>https://nalar.dev/reliable-esp32-ir-air-conditioner-control-needs-hysteresis-and-state-synchronization/</link>
      <pubDate>Sat, 19 Sep 2026 00:00:00 +0000</pubDate>
      <guid>https://nalar.dev/reliable-esp32-ir-air-conditioner-control-needs-hysteresis-and-state-synchronization/</guid>
      <description>&lt;p&gt;An ESP32 can turn a conventional infrared air conditioner into a temperature-driven controller without modifying the AC itself. The basic signal path is simple: a room-temperature sensor feeds the ESP32, the firmware decides whether cooling is required, and an IR LED transmits the same kind of frame the handheld remote would send.&lt;/p&gt;&#xA;&lt;p&gt;The difficult part is not producing infrared light. It is keeping the control loop stable while working with an appliance whose IR protocol may encode the remote&amp;rsquo;s complete state in every transmission.&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
