<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://www.holad.de/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.holad.de/" rel="alternate" type="text/html" hreflang="en" /><updated>2026-06-20T11:48:26+02:00</updated><id>https://www.holad.de/feed.xml</id><title type="html">Holger Adams</title><subtitle>Embedded Stuff</subtitle><author><name>Holger Adams</name></author><entry><title type="html">Detecting Lightning with a ScioSense AS3935</title><link href="https://www.holad.de/2026/06/20/detecting-lightning-with-a-sciosense-as3935/" rel="alternate" type="text/html" title="Detecting Lightning with a ScioSense AS3935" /><published>2026-06-20T00:00:00+02:00</published><updated>2026-06-20T00:00:00+02:00</updated><id>https://www.holad.de/2026/06/20/detecting-lightning-with-a-sciosense-as3935</id><content type="html" xml:base="https://www.holad.de/2026/06/20/detecting-lightning-with-a-sciosense-as3935/"><![CDATA[<p>This was a hot summer night test to see how reliable and usable the ScioSense AS3935 lightning detector is.</p>

<p>The PCB from AliExpress wasn’t working at all initially - the 500 kHz detection coil was damaged. Thanks to Coilcraft’s sample delivery service, I was able to replace the broken one (MA5532-AED) within a few days.</p>

<p>On 20.6.2026 a lightning storm passed my hometown, which looked like a good opportunity to test its sensitivity.</p>

<figure>
  <video controls="" width="100%">
    <source src="/pictures/lightning-20260620.webm" type="video/webm" />
    Your browser doesn't support video playback.
  </video>
  <figcaption>Lightning passing Esslingen am Neckar. Source: Blitzortung.org</figcaption>
</figure>

<p>While testing the device I found that a piezo igniter can also trigger it - just bending the piezo is enough, it doesn’t even have to spark.</p>

<p>To keep the disturber rate down it’s critical to disable Wi-Fi on the ESP32. I work around this by collecting data for 15 minutes then briefly enabling Wi-Fi to send it and returning to data collection. To control the sensitivity (registers WDTH and SREJ) I wrote a small algorithm that keeps the “Disturber Events” and “Noise Events” rates at an acceptable level.</p>

<figure>
  <a href="/pictures/lightning-grafana.png" class="glightbox" data-glightbox="description: Grafana visualization of the ScioSense AS3935 during a lightning event">
    <img src="/pictures/lightning-grafana.png" loading="lazy" alt="Grafana visualization of the ScioSense AS3935 during a lightning event" />
  </a>
  <figcaption>Grafana visualization of the ScioSense AS3935 during a lightning event</figcaption>
</figure>

<p>As you can see: nothing. The “Lightning Events” counter stayed zero.</p>

<p>Seems it only picks up strikes that are very close by. According to the datasheet (p.21) the furthest distance estimation bin is 40km.</p>]]></content><author><name>Holger Adams</name></author><summary type="html"><![CDATA[Detecting Lightning with a ScioSense AS3935]]></summary></entry><entry><title type="html">Manual 35mm film checking at Skopje International Airport was rejected</title><link href="https://www.holad.de/2026/05/15/35mm-film-checking-at-skopje-airport/" rel="alternate" type="text/html" title="Manual 35mm film checking at Skopje International Airport was rejected" /><published>2026-05-15T00:00:00+02:00</published><updated>2026-05-15T00:00:00+02:00</updated><id>https://www.holad.de/2026/05/15/35mm-film-checking-at-skopje-airport</id><content type="html" xml:base="https://www.holad.de/2026/05/15/35mm-film-checking-at-skopje-airport/"><![CDATA[<p>Just for the record:</p>

<p>My request for getting my 35mm films hand-checked (without X-Ray) was rejected at Skopje International Airport at 17.5.2026. At the moment they don’t have any of the new CT scanners yet.</p>]]></content><author><name>Holger Adams</name></author><summary type="html"><![CDATA[Manual 35mm film checking at Skopje International Airport was rejected]]></summary></entry><entry><title type="html">Starting AnyDesk within Wayland (Ubuntu/Kubuntu 26.04)</title><link href="https://www.holad.de/2026/04/29/Anydesk-in-Wayland/" rel="alternate" type="text/html" title="Starting AnyDesk within Wayland (Ubuntu/Kubuntu 26.04)" /><published>2026-04-29T00:00:00+02:00</published><updated>2026-04-29T00:00:00+02:00</updated><id>https://www.holad.de/2026/04/29/Anydesk-in-Wayland</id><content type="html" xml:base="https://www.holad.de/2026/04/29/Anydesk-in-Wayland/"><![CDATA[<p>As Anydesk is not a native Wayland application the entire application is unuseable if you don’t start it with the additional GDK_BACKEND prefix.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># GDK_BACKEND=x11 anydesk
</code></pre></div></div>]]></content><author><name>Holger Adams</name></author><summary type="html"><![CDATA[Starting AnyDesk within Wayland (Ubuntu/Kubuntu 26.04)]]></summary></entry><entry><title type="html">Fun in Space and 24 GHz CW Radars</title><link href="https://www.holad.de/2026/04/26/fun-in-space-an-cw-radars/" rel="alternate" type="text/html" title="Fun in Space and 24 GHz CW Radars" /><published>2026-04-26T00:00:00+02:00</published><updated>2026-04-26T00:00:00+02:00</updated><id>https://www.holad.de/2026/04/26/fun-in-space-an-cw-radars</id><content type="html" xml:base="https://www.holad.de/2026/04/26/fun-in-space-an-cw-radars/"><![CDATA[<p>Another month, another CW radar from <a href="http://de.aliexpress.com/item/1005010388578617.html">AliExpress</a> - the streak continues. This time it’s a high-gain presence/speed sensor.</p>

<figure>
  <a href="/pictures/cw_radar_iq.jpg" class="glightbox" data-glightbox="description: 24 GHz Radar from AliExpress - Back">
    <img src="/pictures/cw_radar_iq.jpg" loading="lazy" alt="24 GHz Radar from AliExpress - Back" />
  </a>
  <figcaption>24 GHz Radar from AliExpress - Back</figcaption>
</figure>

<figure>
  <a href="/pictures/cw_radar_iq_front.jpg" class="glightbox" data-glightbox="description: 24 GHz Radar from AliExpress - Front">
    <img src="/pictures/cw_radar_iq_front.jpg" loading="lazy" alt="24 GHz Radar from AliExpress - Front" />
  </a>
  <figcaption>24 GHz Radar from AliExpress - Front</figcaption>
</figure>

<p>The hardware of the PCB feels rather familiar:</p>

<ul>
  <li>The usual 3.3V LDOs for digital and analog power rails</li>
  <li>SGR SGR1101A: a 100% Infineon BGT24LTR11-compatible radar IC for (FM)CW radars</li>
  <li>Artery AT32F413CCUU7: 200 MHz, 256 KB Flash, 64 KB RAM, dual 12-bit ADC with simultaneous sampling</li>
</ul>

<p>The device gives me full access to its I/Q outputs with identical amplification and no amplitude manipulation.</p>

<p>Read-out protection is enabled on the microcontroller - so I’m not digging into the original firmware.</p>

<p>Getting the raw radar IQ samples out of the device follows the same scheme as in my previous projects: reading both channels synchronously utilizing ADC via DMA, A/B double buffering  and transmitting the data over 6 MBaud UART using DMA. This time I added COBS byte stuffing as a new feature, which makes it much easier to calculate channel saturation due to its fixed-size behavior. Everything is protected by a 32-bit CRC.</p>

<p>Now this beast is spitting a sampling rate of 120kHz with 12-Bit resolution at me. Of each channel. CRC error rate around 0%.</p>

<figure>
  <a href="/pictures/cw_radar_iq_setup.jpg" class="glightbox" data-glightbox="description: Setup on my small balcony. The PCB on the bottom is a FTDI FT2232HL.">
    <img src="/pictures/cw_radar_iq_setup.jpg" loading="lazy" alt="Setup on my small balcony. The PCB on the bottom is a FTDI FT2232HL." />
  </a>
  <figcaption>Setup on my small balcony. The PCB on the bottom is a FTDI FT2232HL.</figcaption>
</figure>

<p>A small frontend was hacked together to receive all the data and visualize it in Python and PyQt.</p>

<figure>
  <a href="/pictures/cw_radar_iq_fronted.jpg" class="glightbox" data-glightbox="description: 24GHz Python UI utilizing PyQt">
    <img src="/pictures/cw_radar_iq_fronted.jpg" loading="lazy" alt="24GHz Python UI utilizing PyQt" />
  </a>
  <figcaption>24GHz Python UI utilizing PyQt</figcaption>
</figure>

<p>Now I can finally start working on the algorithms!</p>

<p>My first “scientific” questions with this Radar: will insects fly away if a tree and its leaves are bending during a wind breeze?</p>

<figure>
  <a href="/pictures/cw_radar_iq_wind_tree.png" class="glightbox" data-glightbox="description: 24 GHz CW Radar pointed against a tree: wind breeze hitting tree leaves - insects flying away">
    <img src="/pictures/cw_radar_iq_wind_tree.png" loading="lazy" alt="24 GHz CW Radar pointed against a tree: wind breeze hitting tree leaves - insects flying away" />
  </a>
  <figcaption>24 GHz CW Radar pointed against a tree: wind breeze hitting tree leaves - insects flying away</figcaption>
</figure>

<p>So they do! But not many of them.</p>

<p>A few more recordings.</p>

<figure>
  <a href="/pictures/cw_radar_iq_bench.png" class="glightbox" data-glightbox="description: 24 GHz CW Radar pointed against a bench with young people">
    <img src="/pictures/cw_radar_iq_bench.png" loading="lazy" alt="24 GHz CW Radar pointed against a bench with young people" />
  </a>
  <figcaption>24 GHz CW Radar pointed against a bench with young people</figcaption>
</figure>

<figure>
  <a href="/pictures/cw_radar_iq_wind_bike.png" class="glightbox" data-glightbox="description: 24 GHz CW Radar pointed against a car and cyclist">
    <img src="/pictures/cw_radar_iq_wind_bike.png" loading="lazy" alt="24 GHz CW Radar pointed against a car and cyclist" />
  </a>
  <figcaption>24 GHz CW Radar pointed against a car and cyclist</figcaption>
</figure>

<figure>
  <a href="/pictures/cw_radar_iq_wind_car.png" class="glightbox" data-glightbox="description: 24 GHz CW Radar pointed against a car - Also very weak cyclist signal visible on the left">
    <img src="/pictures/cw_radar_iq_wind_car.png" loading="lazy" alt="24 GHz CW Radar pointed against a car - Also very weak cyclist signal visible on the left" />
  </a>
  <figcaption>24 GHz CW Radar pointed against a car - Also very weak cyclist signal visible on the left</figcaption>
</figure>

<p>GitHub: <a href="https://github.com/h0lad/AT32F413CCU7_CW_Radar_Sampler">https://github.com/h0lad/AT32F413CCU7_CW_Radar_Sampler</a></p>]]></content><author><name>Holger Adams</name></author><summary type="html"><![CDATA[Fully rewriting the firmware of a off-the-shelf CW speed radar for fun and profit]]></summary></entry><entry><title type="html">Ghost CMS hanging for 5 seconds with ‘Probe unresponsive’ error message</title><link href="https://www.holad.de/2026/04/19/Ghost-CMS-website-hangs-wth-probe-unresponsive/" rel="alternate" type="text/html" title="Ghost CMS hanging for 5 seconds with ‘Probe unresponsive’ error message" /><published>2026-04-19T00:00:00+02:00</published><updated>2026-04-19T00:00:00+02:00</updated><id>https://www.holad.de/2026/04/19/Ghost-CMS-website-hangs-wth-probe-unresponsive</id><content type="html" xml:base="https://www.holad.de/2026/04/19/Ghost-CMS-website-hangs-wth-probe-unresponsive/"><![CDATA[<p>Bah! Just spent 4 hours of my life debugging a stupid issue on my new photo blog.</p>

<p>Problem: Everytime I loaded the website the main page was hanging for several seconds.</p>

<p>In the console the Ghost CMS was spitting</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Apr 19 15:39:11 xxx.de app[8646]: [2026-04-19 15:39:11] ERROR Probe unresponsive.
Apr 19 15:39:11 xxx.de app[8646]: 
Apr 19 15:39:11 xxx.de app[8646]: Probe unresponsive.
Apr 19 15:39:11 xxx.de app[8646]: Error ID:
Apr 19 15:39:11 xxx.de app[8646]:     262548c0-3bf5-11f1-bc23-6768b80af7bd
Apr 19 15:39:11 xxx.de app[8646]: Error Code: 
Apr 19 15:39:11 xxx.de app[8646]:     IMAGE_SIZE_URL
Apr 19 15:39:11 xxx.de app[8646]: ----------------------------------------
Apr 19 15:39:11 xxx.de app[8646]: InternalServerError: Probe unresponsive.
Apr 19 15:39:11 xxx.de app[8646]:     at Timeout._onTimeout (/x/versions/6.30.0/core/server/lib/image/image-size.js:91:25)
Apr 19 15:39:11 xxx.de app[8646]:     at listOnTimeout (node:internal/timers:585:17)
Apr 19 15:39:11 xxx.de app[8646]:     at process.processTimers (node:internal/timers:521:7)
</code></pre></div></div>

<p>After adding some wild debug code it turned out that this was the culprit:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Apr 19 15:39:06 xxx.de app[8646]: PROBE_URL: https://static.ghost.org/v5.0.0/images/publication-cover.jpg
Apr 19 15:39:06 xxx.de app[8646]: PROBE_URL: https://static.ghost.org/v5.0.0/images/publication-cover.jpg
Apr 19 15:39:06 xxx.de app[8646]: PROBE_URL: https://static.ghost.org/v5.0.0/images/publication-cover.jpg
</code></pre></div></div>

<p>The “Publication Cover” was still set to default and pointing to a host from the Ghost project.</p>

<p>And <code class="language-plaintext highlighter-rouge">static.ghost.org</code> has some kind of rate throttling causing it to hang until the function call timed out.</p>]]></content><author><name>Holger Adams</name></author><summary type="html"><![CDATA[Ghost CMS hanging for 5 seconds with 'Probe unresponsive' error message]]></summary></entry><entry><title type="html">Backing up your external SD-Cards using a Android device with scp/rsync</title><link href="https://www.holad.de/2026/02/21/backup-files-android/" rel="alternate" type="text/html" title="Backing up your external SD-Cards using a Android device with scp/rsync" /><published>2026-02-21T00:00:00+01:00</published><updated>2026-02-21T00:00:00+01:00</updated><id>https://www.holad.de/2026/02/21/backup-files-android</id><content type="html" xml:base="https://www.holad.de/2026/02/21/backup-files-android/"><![CDATA[<p>One of my oldest problems was solved today: how to back up the SD card of my camera while traveling with my tablet or smartphone.</p>

<p>I tried this with Nextcloud and several other tools - but they crashed after a two‑digit amount of gigabytes.</p>

<p>But finally I can use <code class="language-plaintext highlighter-rouge">scp</code> or <code class="language-plaintext highlighter-rouge">rsync</code> to my own servers.</p>

<p>How to</p>

<ol>
  <li>
    <p>Install “Termux” from the Google Play Store</p>
  </li>
  <li>
    <p>Enter <code class="language-plaintext highlighter-rouge"># termux-setup-storage</code> and give Termux all file access privileges</p>
  </li>
  <li>
    <p>Install <code class="language-plaintext highlighter-rouge">scp</code> and <code class="language-plaintext highlighter-rouge">rsync</code>: <code class="language-plaintext highlighter-rouge"># pkg install openssh rsync</code></p>
  </li>
  <li>
    <p>Restart the app (by killing it) to propagate all new privileges. Otherwise you’ll get a permission denied.</p>
  </li>
  <li>
    <p>Get your mount point using <code class="language-plaintext highlighter-rouge">df</code>. It’s usually <code class="language-plaintext highlighter-rouge">/mnt/media_rw/&lt;something&gt;</code>. You can enter that absolut path directly using <code class="language-plaintext highlighter-rouge">cd</code> like (<code class="language-plaintext highlighter-rouge"># cd /media/media_rw/A4DC-1112</code>)</p>
  </li>
  <li>
    <p>Have fun <code class="language-plaintext highlighter-rouge">scp</code>‑ing or <code class="language-plaintext highlighter-rouge">rsync</code>‑ing your files :-)</p>
  </li>
</ol>]]></content><author><name>Holger Adams</name></author><summary type="html"><![CDATA[Using Termux on Android to back up camera SD cards via scp and rsync to your own server while traveling.]]></summary></entry><entry><title type="html">Pushing Sensor Data to VictoriaMetrics Using Prometheus 1‑Line Format in ESP‑IDF</title><link href="https://www.holad.de/2026/02/12/pushing-sensor-data-to-victoriametrics-using-prometheus/" rel="alternate" type="text/html" title="Pushing Sensor Data to VictoriaMetrics Using Prometheus 1‑Line Format in ESP‑IDF" /><published>2026-02-12T00:00:00+01:00</published><updated>2026-02-12T00:00:00+01:00</updated><id>https://www.holad.de/2026/02/12/pushing-sensor-data-to-victoriametrics-using-prometheus</id><content type="html" xml:base="https://www.holad.de/2026/02/12/pushing-sensor-data-to-victoriametrics-using-prometheus/"><![CDATA[<p>I recently picked up a Sensirion SEN66 sensor and wanted to push all its measurements into my VictoriaMetrics database.</p>

<p>With ESP-IDF, the whole setup turned out to be surprisingly straightforward.</p>

<p>A few highlights from this project:</p>

<ul>
  <li>
    <p>All data points use an SNTP‑synchronized timestamp. This is not part of this blog post.</p>
  </li>
  <li>
    <p>The device’s Wi‑Fi MAC address serves as a unique identifier</p>
  </li>
</ul>

<p>Very clean an minimal.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* Wifi MAC as char array */</span>
<span class="k">static</span> <span class="kt">char</span> <span class="n">device_id</span><span class="p">[</span><span class="mi">32</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">};</span>

<span class="k">static</span> <span class="n">esp_err_t</span> <span class="nf">http_event_handler</span><span class="p">(</span><span class="n">esp_http_client_event_t</span> <span class="o">*</span><span class="n">evt</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">ESP_OK</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">static</span> <span class="n">esp_err_t</span> <span class="nf">send_to_victoriametrics</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">payload</span><span class="p">)</span>
<span class="p">{</span>
    <span class="cm">/* 
     * My setup uses valid certificates from LetsEncrypt and is 
     * also fronted by a Nginx which handles authentification
     */</span>

    <span class="n">esp_http_client_config_t</span> <span class="n">config</span> <span class="o">=</span> <span class="p">{</span>
        <span class="p">.</span><span class="n">url</span> <span class="o">=</span> <span class="s">"https://my.vicmetrics.instance/api/v1/import/prometheus"</span><span class="p">,</span>
        <span class="p">.</span><span class="n">event_handler</span> <span class="o">=</span> <span class="n">http_event_handler</span><span class="p">,</span>
        <span class="p">.</span><span class="n">timeout_ms</span> <span class="o">=</span> <span class="mi">5000</span><span class="p">,</span>
        <span class="p">.</span><span class="n">auth_type</span> <span class="o">=</span> <span class="n">HTTP_AUTH_TYPE_BASIC</span><span class="p">,</span>
        <span class="p">.</span><span class="n">username</span> <span class="o">=</span> <span class="s">"super"</span><span class="p">,</span>
        <span class="p">.</span><span class="n">password</span> <span class="o">=</span> <span class="s">"secret"</span><span class="p">,</span>
        <span class="p">.</span><span class="n">crt_bundle_attach</span> <span class="o">=</span> <span class="n">esp_crt_bundle_attach</span><span class="p">,</span>
    <span class="p">};</span>

    <span class="n">esp_http_client_handle_t</span> <span class="n">client</span> <span class="o">=</span> <span class="n">esp_http_client_init</span><span class="p">(</span><span class="o">&amp;</span><span class="n">config</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">client</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">ESP_LOGE</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span> <span class="s">"HTTP client init failed"</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">ESP_FAIL</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="n">esp_http_client_set_method</span><span class="p">(</span><span class="n">client</span><span class="p">,</span> <span class="n">HTTP_METHOD_POST</span><span class="p">);</span>
    <span class="n">esp_http_client_set_header</span><span class="p">(</span><span class="n">client</span><span class="p">,</span> <span class="s">"Content-Type"</span><span class="p">,</span> <span class="s">"text/plain"</span><span class="p">);</span>

    <span class="n">esp_err_t</span> <span class="n">err</span> <span class="o">=</span> <span class="n">esp_http_client_set_post_field</span><span class="p">(</span><span class="n">client</span><span class="p">,</span> <span class="n">payload</span><span class="p">,</span> <span class="n">strlen</span><span class="p">(</span><span class="n">payload</span><span class="p">));</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">err</span> <span class="o">!=</span> <span class="n">ESP_OK</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">ESP_LOGE</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span> <span class="s">"Failed to set POST body: %s"</span><span class="p">,</span> <span class="n">esp_err_to_name</span><span class="p">(</span><span class="n">err</span><span class="p">));</span>
        <span class="n">esp_http_client_cleanup</span><span class="p">(</span><span class="n">client</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">err</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="n">err</span> <span class="o">=</span> <span class="n">esp_http_client_perform</span><span class="p">(</span><span class="n">client</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">err</span> <span class="o">!=</span> <span class="n">ESP_OK</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">ESP_LOGE</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span> <span class="s">"HTTP POST failed: %s"</span><span class="p">,</span> <span class="n">esp_err_to_name</span><span class="p">(</span><span class="n">err</span><span class="p">));</span>
        <span class="n">esp_http_client_cleanup</span><span class="p">(</span><span class="n">client</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">err</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="kt">int</span> <span class="n">status</span> <span class="o">=</span> <span class="n">esp_http_client_get_status_code</span><span class="p">(</span><span class="n">client</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">status</span> <span class="o">&lt;</span> <span class="mi">200</span> <span class="o">||</span> <span class="n">status</span> <span class="o">&gt;=</span> <span class="mi">300</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">ESP_LOGE</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span> <span class="s">"VictoriaMetrics returned HTTP %d"</span><span class="p">,</span> <span class="n">status</span><span class="p">);</span>
        <span class="n">esp_http_client_cleanup</span><span class="p">(</span><span class="n">client</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">ESP_FAIL</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="n">esp_http_client_cleanup</span><span class="p">(</span><span class="n">client</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">ESP_OK</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">static</span> <span class="kt">void</span> <span class="nf">send_metrics_to_vm</span><span class="p">(</span>
    <span class="kt">uint16_t</span> <span class="n">pm1</span><span class="p">,</span> <span class="kt">uint16_t</span> <span class="n">pm25</span><span class="p">,</span> <span class="kt">uint16_t</span> <span class="n">pm4</span><span class="p">,</span> <span class="kt">uint16_t</span> <span class="n">pm10</span><span class="p">,</span>
    <span class="kt">int16_t</span> <span class="n">hum</span><span class="p">,</span> <span class="kt">int16_t</span> <span class="n">temp</span><span class="p">,</span> <span class="kt">int16_t</span> <span class="n">voc</span><span class="p">,</span> <span class="kt">int16_t</span> <span class="n">nox</span><span class="p">,</span> <span class="kt">uint16_t</span> <span class="n">co2</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">char</span> <span class="n">payload</span><span class="p">[</span><span class="mi">2048</span><span class="p">];</span>
    <span class="kt">int64_t</span> <span class="n">ts_s</span> <span class="o">=</span> <span class="n">time</span><span class="p">(</span><span class="nb">NULL</span><span class="p">);</span>

     <span class="n">snprintf</span><span class="p">(</span><span class="n">payload</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">payload</span><span class="p">),</span>
        <span class="s">"sens66_pm1{device=</span><span class="se">\"</span><span class="s">%s</span><span class="se">\"</span><span class="s">} %u %"</span> <span class="n">PRId64</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span>
        <span class="s">"sens66_pm25{device=</span><span class="se">\"</span><span class="s">%s</span><span class="se">\"</span><span class="s">} %u %"</span> <span class="n">PRId64</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span>
        <span class="s">"sens66_pm4{device=</span><span class="se">\"</span><span class="s">%s</span><span class="se">\"</span><span class="s">} %u %"</span> <span class="n">PRId64</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span>
        <span class="s">"sens66_pm10{device=</span><span class="se">\"</span><span class="s">%s</span><span class="se">\"</span><span class="s">} %u %"</span> <span class="n">PRId64</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span>
        <span class="s">"sens66_humidity{device=</span><span class="se">\"</span><span class="s">%s</span><span class="se">\"</span><span class="s">} %d %"</span> <span class="n">PRId64</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span>
        <span class="s">"sens66_temperature{device=</span><span class="se">\"</span><span class="s">%s</span><span class="se">\"</span><span class="s">} %d %"</span> <span class="n">PRId64</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span>
        <span class="s">"sens66_voc{device=</span><span class="se">\"</span><span class="s">%s</span><span class="se">\"</span><span class="s">} %d %"</span> <span class="n">PRId64</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span>
        <span class="s">"sens66_nox{device=</span><span class="se">\"</span><span class="s">%s</span><span class="se">\"</span><span class="s">} %d %"</span> <span class="n">PRId64</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span>
        <span class="s">"sens66_co2{device=</span><span class="se">\"</span><span class="s">%s</span><span class="se">\"</span><span class="s">} %u %"</span> <span class="n">PRId64</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span>
        <span class="n">device_id</span><span class="p">,</span> <span class="n">pm1</span><span class="p">,</span> <span class="n">ts_s</span><span class="p">,</span>
        <span class="n">device_id</span><span class="p">,</span> <span class="n">pm25</span><span class="p">,</span> <span class="n">ts_s</span><span class="p">,</span>
        <span class="n">device_id</span><span class="p">,</span> <span class="n">pm4</span><span class="p">,</span> <span class="n">ts_s</span><span class="p">,</span>
        <span class="n">device_id</span><span class="p">,</span> <span class="n">pm10</span><span class="p">,</span> <span class="n">ts_s</span><span class="p">,</span>
        <span class="n">device_id</span><span class="p">,</span> <span class="n">hum</span><span class="p">,</span> <span class="n">ts_s</span><span class="p">,</span>
        <span class="n">device_id</span><span class="p">,</span> <span class="n">temp</span><span class="p">,</span> <span class="n">ts_s</span><span class="p">,</span>
        <span class="n">device_id</span><span class="p">,</span> <span class="n">voc</span><span class="p">,</span> <span class="n">ts_s</span><span class="p">,</span>
        <span class="n">device_id</span><span class="p">,</span> <span class="n">nox</span><span class="p">,</span> <span class="n">ts_s</span><span class="p">,</span>
        <span class="n">device_id</span><span class="p">,</span> <span class="n">co2</span><span class="p">,</span> <span class="n">ts_s</span>
    <span class="p">);</span>

    <span class="n">ESP_LOGI</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span> <span class="s">"Sending metrics:</span><span class="se">\n</span><span class="s">%s"</span><span class="p">,</span> <span class="n">payload</span><span class="p">);</span>

    <span class="n">esp_err_t</span> <span class="n">err</span> <span class="o">=</span> <span class="n">send_to_victoriametrics</span><span class="p">(</span><span class="n">payload</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">err</span> <span class="o">!=</span> <span class="n">ESP_OK</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">ESP_LOGE</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span> <span class="s">"Failed to send metrics to VictoriaMetrics"</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">static</span> <span class="kt">void</span> <span class="nf">task_example</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">pvParameters</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">uint8_t</span> <span class="n">mac</span><span class="p">[</span><span class="mi">6</span><span class="p">];</span>
    <span class="cm">/* MAC will never change. So only read once. */</span>
    <span class="n">esp_efuse_mac_get_default</span><span class="p">(</span><span class="n">mac</span><span class="p">);</span>
    <span class="n">snprintf</span><span class="p">(</span><span class="n">device_id</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">device_id</span><span class="p">),</span>
             <span class="s">"%02X:%02X:%02X:%02X:%02X:%02X"</span><span class="p">,</span>
             <span class="n">mac</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">mac</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">mac</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">mac</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="n">mac</span><span class="p">[</span><span class="mi">4</span><span class="p">],</span> <span class="n">mac</span><span class="p">[</span><span class="mi">5</span><span class="p">]);</span>

    <span class="p">(...)</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This is the console output of the programm.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>I (52244) esp-x509-crt-bundle: Certificate validated
I (62957) SEN66_APP: Sending metrics:
sens66_pm1{device="D8:3B:DA:xx:xx:xx"} 257 1770918016
sens66_pm25{device="D8:3B:DA:xx:xx:xx"} 310 1770918016
sens66_pm4{device="D8:3B:DA:xx:xx:xx"} 345 1770918016
sens66_pm10{device="D8:3B:DA:xx:xx:xx"} 362 1770918016
sens66_humidity{device="D8:3B:DA:xx:xx:xx"} 3898 1770918016
sens66_temperature{device="D8:3B:DA:xx:xx:xx"} 4429 1770918016
sens66_voc{device="D8:3B:DA:xx:xx:xx"} 360 1770918016
sens66_nox{device="D8:3B:DA:xx:xx:xx"} 10 1770918016
sens66_co2{device="D8:3B:DA:xx:xx:xx"} 615 1770918016
</code></pre></div></div>

<p>Putting everything together results in these beautiful graphs.</p>

<figure>
  <a href="/pictures/vicmetrics_sen66.jpg" class="glightbox" data-glightbox="description: Sensirion SEN66 visualized using Grafana">
    <img src="/pictures/vicmetrics_sen66.jpg" loading="lazy" alt="Sensirion SEN66 visualized using Grafana" />
  </a>
  <figcaption>Sensirion SEN66 visualized using Grafana</figcaption>
</figure>]]></content><author><name>Holger Adams</name></author><summary type="html"><![CDATA[Sending Sensirion SEN66 data from an ESP32 to VictoriaMetrics using the Prometheus text format over HTTPS.]]></summary></entry><entry><title type="html">Testing Meshcore with the new ESP32 Power Saving Implementation</title><link href="https://www.holad.de/2026/01/15/testing-meshcore-with-esp32-power-saving/" rel="alternate" type="text/html" title="Testing Meshcore with the new ESP32 Power Saving Implementation" /><published>2026-01-15T00:00:00+01:00</published><updated>2026-01-15T00:00:00+01:00</updated><id>https://www.holad.de/2026/01/15/testing-meshcore-with-esp32-power-saving</id><content type="html" xml:base="https://www.holad.de/2026/01/15/testing-meshcore-with-esp32-power-saving/"><![CDATA[<p>Lately there has been a very interesting pull request in the Meshcore GitHub: <a href="https://github.com/meshcore-dev/MeshCore/pull/1353">To support PowerSaving for all ESP32-based repeaters and NRF52-based repeaters</a>. The developer IOTThinks implemented power-saving functionality for all repeaters that utilize ESP32 or NRF52 microcontrollers! The merge request also looks to be in its final stages - so a merge is expected soon.</p>

<p>Let’s compare the differences.</p>

<p><strong>Setup</strong></p>

<p>3.7V from a  using Nordic Profiler II -&gt; TI BQ25185 charge controller -&gt; 3.0V LDO -&gt; Heltec HT-CT62</p>

<p><strong>Without Powersaving</strong></p>

<figure>
  <a href="/pictures/meshcore_wo_powersaving.png" class="glightbox" data-glightbox="description: Meshcore without power saving">
    <img src="/pictures/meshcore_wo_powersaving.png" loading="lazy" alt="Meshcore without power saving" />
  </a>
  <figcaption>Meshcore without power saving</figcaption>
</figure>

<p>Idle Consumption: ~25-27mA</p>

<p>Peak consumption: ~190mA</p>

<p><strong>With Powersaving</strong></p>

<figure>
  <a href="/pictures/meshcore_w_powersaving.png" class="glightbox" data-glightbox="description: Meshcore with power saving">
    <img src="/pictures/meshcore_w_powersaving.png" loading="lazy" alt="Meshcore with power saving" />
  </a>
  <figcaption>Meshcore with power saving</figcaption>
</figure>

<p>Sleep Consumption: ~7-8mA</p>

<p>Idle Consumption: ~25-27mA</p>

<p>Peak consumption: ~190mA</p>

<p>So, when the device is sleeping  (most of the time) it reduces the current consumption by a factor of 3. Not tested: according to the pull request the power consumption of the NRF drops to 6mA during sleep.</p>

<p>That dramatically improves the useability for ESP32  and NRF52 when it comes to very compact solar driven stations!</p>]]></content><author><name>Holger Adams</name></author><summary type="html"><![CDATA[Measuring MeshCore power saving on ESP32: idle current drops from 25mA to 7mA during sleep, a 3x improvement.]]></summary></entry><entry><title type="html">Logic Analyzer Sipheed SLogic16U - First Impression</title><link href="https://www.holad.de/2026/01/02/Sipheed-SLogic16U-First-Impression/" rel="alternate" type="text/html" title="Logic Analyzer Sipheed SLogic16U - First Impression" /><published>2026-01-02T00:00:00+01:00</published><updated>2026-01-02T00:00:00+01:00</updated><id>https://www.holad.de/2026/01/02/Sipheed-SLogic16U-First-Impression</id><content type="html" xml:base="https://www.holad.de/2026/01/02/Sipheed-SLogic16U-First-Impression/"><![CDATA[<p>I gifted myself a Sipheed SLogic16 logic analyzer for Christmas, as my Cypress FX2 had reached its sampling limits in recent projects.</p>

<figure>
  <a href="/pictures/sipeed_slogic16u_a.jpg" class="glightbox" data-glightbox="description: Sipheed SLogic16 - Back">
    <img src="/pictures/sipeed_slogic16u_a.jpg" loading="lazy" alt="Sipheed SLogic16 - Back" />
  </a>
  <figcaption>Sipheed SLogic16 - Back</figcaption>
</figure>

<figure>
  <a href="/pictures/sipeed_slogic16u_b.jpg" class="glightbox" data-glightbox="description: Sipheed SLogic16 - Back">
    <img src="/pictures/sipeed_slogic16u_b.jpg" loading="lazy" alt="Sipheed SLogic16 - Back" />
  </a>
  <figcaption>Sipheed SLogic16 - Back</figcaption>
</figure>

<p>First impression? Guess!</p>

<p>In short:</p>
<ul>
  <li>I ordered the variant with coax cables</li>
  <li>The cables are not numbered, so you have no idea which cable belongs to which channel</li>
  <li>You can’t inspect the solder joints because they covered everything with heat-shrink tubing</li>
</ul>

<p>I contacted Sipheed support and asked whether they could send me they non-shielded colored cables.</p>

<p>Solveable with a small male&lt;-&gt;male 2.54mm pin-header board.. but Ugh.. I just wanted a working tool.</p>]]></content><author><name>Holger Adams</name></author><summary type="html"><![CDATA[First impressions of the Sipeed SLogic16U logic analyzer: unnumbered coax cables and a disappointing unboxing.]]></summary></entry><entry><title type="html">Hi-Link HLK-LD303 - This FMCW Radar is looking good for experiments</title><link href="https://www.holad.de/2025/12/31/hlk-ld303-this-fmcw-radar-is-looking-good/" rel="alternate" type="text/html" title="Hi-Link HLK-LD303 - This FMCW Radar is looking good for experiments" /><published>2025-12-31T00:00:00+01:00</published><updated>2025-12-31T00:00:00+01:00</updated><id>https://www.holad.de/2025/12/31/hlk-ld303-this-fmcw-radar-is-looking-good</id><content type="html" xml:base="https://www.holad.de/2025/12/31/hlk-ld303-this-fmcw-radar-is-looking-good/"><![CDATA[<p>Looks my journy for searching a modifyable FMCW Radar board  finally came to an end thanks to the Hi-Link HLK-LD303.</p>

<figure>
  <a href="/pictures/ld303_pcbf.jpg" class="glightbox" data-glightbox="description: LD303 - Front PCB">
    <img src="/pictures/ld303_pcbf.jpg" loading="lazy" alt="LD303 - Front PCB" />
  </a>
  <figcaption>LD303 - Front PCB</figcaption>
</figure>

<p>Why?</p>

<p>The small PCB has all I ever wanted</p>

<ul>
  <li>24GHz FMCW Radar IC</li>
  <li>Full access to I/Q output of the Radar module</li>
  <li>DAC access to the Radar for the frequency modulation</li>
  <li>A not too weak microcontroller with option for USB</li>
</ul>

<p>Price wise it’s also very attractive (17-20€).</p>

<h2 id="analysis">Analysis</h2>

<h3 id="hardware">Hardware</h3>

<h4 id="key-components">Key Components</h4>

<ul>
  <li>
    <p>Microcontroller: Atery AT32F403ACGT7 (240MHz, 1024KBytes Flash, 128+96KBytes SRAM, 2x DAC, 3x 12-bit 2MSPS ADCs)</p>
  </li>
  <li>
    <p>OpAmp: SGMicro SGM724 (Quad OpAmp)</p>
  </li>
  <li>
    <p>Radar Module: “TR11” -&gt; Infineon BGT24MTR11</p>
  </li>
</ul>

<h3 id="signals">Signals</h3>

<h4 id="iq-signals">IQ-Signals</h4>

<figure>
  <a href="/pictures/ld303_iq.png" class="glightbox" data-glightbox="description: Measurement on the I and Q test points">
    <img src="/pictures/ld303_iq.png" loading="lazy" alt="Measurement on the I and Q test points" />
  </a>
  <figcaption>Measurement on the I and Q test points</figcaption>
</figure>

<p>“I” and “Q” are labeled on the PCB.</p>

<ul>
  <li>A_ref = 5V</li>
  <li>Vmin_I/Q: ~200mV</li>
  <li>Vmax_I/Q: ~5.2V</li>
</ul>

<h4 id="vco-ramp">VCO Ramp</h4>

<figure>
  <a href="/pictures/ld303_sweep.png" class="glightbox" data-glightbox="description: Radar return signal vs. sawtooth wave">
    <img src="/pictures/ld303_sweep.png" loading="lazy" alt="Radar return signal vs. sawtooth wave" />
  </a>
  <figcaption>Radar return signal vs. sawtooth wave</figcaption>
</figure>

<figure>
  <a href="/pictures/ld303_freq.jpg" class="glightbox" data-glightbox="description: Screenshot from the Application Note AN303 showing the frequency&lt;-&gt;voltage relation">
    <img src="/pictures/ld303_freq.jpg" loading="lazy" alt="Screenshot from the Application Note AN303 showing the frequency&lt;-&gt;voltage relation" />
  </a>
  <figcaption>Screenshot from the Application Note AN303 showing the frequency&lt;-&gt;voltage relation</figcaption>
</figure>

<h4 id="vco-ramp-vs-bang-signal">VCO Ramp vs. Bang Signal</h4>

<figure>
  <a href="/pictures/ld303_vco_bang.png" class="glightbox" data-glightbox="description: VCO Ramp vs. Bang Signal">
    <img src="/pictures/ld303_vco_bang.png" loading="lazy" alt="VCO Ramp vs. Bang Signal" />
  </a>
  <figcaption>VCO Ramp vs. Bang Signal</figcaption>
</figure>

<h4 id="swd">SWD</h4>

<p>Pins are labeled on the PCB. No proections are set.</p>

<h4 id="pins">Pins</h4>

<ul>
  <li>Radar I: PA3, ADC123_IN1</li>
  <li>Radar Q: PA2, ADC123_IN2</li>
  <li>Radar VCO: PA5, DAC2_OUT</li>
  <li>UART TX: PA9, USART1_TX</li>
  <li>UART RX: PA10, USART1_RX (assumed)</li>
</ul>

<h3 id="firmware">Firmware</h3>

<p>Pack File: https://arterytek.com/en/product/AT32F403.jsp#Resource</p>

<p>Datasheet: https://crossic.com/wp-content/uploads/2021/12/DS_AT32F403A_EN_V2.00.pdf</p>

<h4 id="analysis-1">Analysis</h4>

<p>No read-out protection being set.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># pyocd commander --pack "ArteryTek.AT32F403A_407_DFP.2.2.3.pack"
Waiting for a debug probe to be connected...
(...)
Connected to CoreSightTarget [Running]: 06x

pyocd&gt; savemem  0x08000000 0xFFFFF flash.bin
Saved 1048575 bytes to flash.bin
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># sha256sum flash.bin 
93c407b791f3ae1ea5e6d2514dbc518c63ce28f6532e2a0cb74c2027fd31b403  flash.bin
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># file flash.bin 
flash.bin: ARM Cortex-M firmware, initial SP at 0x20003d58, reset at 0x08000190, NMI at 0x08000d14, HardFault at 0x08000cd6, SVCall at 0x08001720, PendSV at 0x08000d9c
</code></pre></div></div>

<p>Strings in the firmware blob</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>080064af  adc_samp_%d
080064c7  adc_cha_%d
080064e3  Ffft-out
08007278  Upgrade
0800876c  0123456789abcdef
08008780  0123456789ABCDEF
080097f4  %4dcm
08009800  %8d
</code></pre></div></div>]]></content><author><name>Holger Adams</name></author><summary type="html"><![CDATA[The Hi-Link HLK-LD303 has full I/Q output and DAC access to the VCO, making it a solid platform for FMCW experiments.]]></summary></entry></feed>