<?xml version="1.0" encoding="utf-8" standalone="yes"?><?xml-stylesheet href="/rss-style.xsl" type="text/xsl"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Daniel López Blog</title><link>https://web.dlopez.eu.org</link><description>Professional updates, technical articles, and project chronicles by Daniel López Pérez</description><language>en</language><managingEditor>Daniel López Pérez</managingEditor><webMaster>Daniel López Pérez</webMaster><image><title>Daniel López Blog</title><url>https://web.dlopez.eu.org/logo.png</url><link>https://web.dlopez.eu.org</link></image><lastBuildDate>Sat, 02 May 2026 00:00:00 +0000</lastBuildDate><ttl>60</ttl><atom:link href="https://web.dlopez.eu.org/blog/index.xml" rel="self" type="application/rss+xml"/><item><title>Old Internet Tools That Still Work</title><link>https://web.dlopez.eu.org/blog/old-internet-tools/</link><pubDate>Sat, 02 May 2026 00:00:00 +0000</pubDate><author>Daniel López Pérez</author><guid isPermaLink="true">https://web.dlopez.eu.org/blog/old-internet-tools/</guid><description>I was born into a version of the internet that already felt fully formed.
By the time I started using it seriously, the dominant platforms were already established: algorithmic feeds, centralized social networks, and applications designed around constant updates and …</description><content:encoded><![CDATA[<p>I was born into a version of the internet that already felt fully formed.</p>
<p>By the time I started using it seriously, the dominant platforms were already established: algorithmic feeds, centralized social networks, and applications designed around constant updates and notifications. That was simply the baseline.</p>
<p>Because of that, I never <em>lived</em> the earlier internet. I didn’t experience RSS when it was mainstream, I didn’t use mailing lists as my primary communication layer, and I didn’t grow up with tools like Emacs as part of a standard workflow. I encountered them later, as historical artifacts that were still quietly functional.</p>
<p>And that timing changes everything.</p>
<h2>Discovering systems that were never “new” to me</h2>
<p>When I first encountered RSS, it didn’t feel nostalgic. It felt unfamiliar. Almost counterintuitive.</p>
<p>I started using a self-hosted instance of FreshRSS, not because it reminded me of a past version of the web, but because it solved a present problem: information overload without structure.</p>
<p>What surprised me was not that it was simple, but that it felt complete. There was no sense that something was missing. No recommendation engine, no ranking system trying to optimize my attention. Just a direct relationship between sources and reader.</p>
<p>That simplicity didn’t feel like minimalism. It felt like removal of unnecessary assumptions.</p>
<h2>Learning tools without the cultural context</h2>
<p>The same happened with Emacs.</p>
<p>I didn’t grow up with it. I didn’t see it evolve. I encountered it in its modern form, already shaped by decades of development, plugins, and community conventions.</p>
<p>And yet, what stood out immediately was not its age, but its consistency.</p>
<p>Emacs doesn’t behave like a typical application. It behaves like an environment that you gradually shape. With distributions like Doom Emacs, that environment becomes more structured, but the core idea remains: the tool does not define your workflow—you do.</p>
<p>That is a very different assumption from most modern software.</p>
<h2>Reading as an intentional act again</h2>
<p>Using Elfeed reinforced that shift.</p>
<p>Reading RSS inside Emacs is not about consumption efficiency. It is about removing everything that competes with attention.</p>
<p>There is no feed designed to keep me scrolling. No interface trying to predict what I want next. Just a list of entries that I explicitly chose to follow.</p>
<p>Because I did not grow up with RSS, I don’t associate it with “going back” to anything. Instead, it feels like discovering a different set of design choices that were never part of my default experience.</p>
<h2>Communication systems that don’t try to be platforms</h2>
<p>The same pattern appears again with email and mailing lists.</p>
<p>I didn’t experience mailing lists as a primary communication medium. My default expectation was always platform-based messaging: centralized systems, profiles, and interfaces designed around immediacy.</p>
<p>But mailing lists operate differently. There is no feed optimized for engagement. No hidden ordering of messages. Everything is delivered as plain, structured conversation.</p>
<p>This is also where systems like SourceHut become interesting. They don’t try to abstract communication into a platform layer. Instead, they lean directly on existing primitives like email and patches, treating them as first-class workflows.</p>
<p>The result is slower communication, but also more transparent communication. Nothing is hidden behind an interface designed to shape behavior.</p>
<h2>Reclaiming ownership with static sites</h2>
<p>This entire blog is another example. It is built with Hugo, a static site generator.</p>
<p>For a long time, the easiest way to publish something online was to put it on a platform owned by someone else. You got an audience and an editor, but you gave up control over the presentation, the longevity, and the underlying data.</p>
<p>A static site is the exact opposite. It is just HTML, CSS, and Markdown. It doesn&rsquo;t rely on a database that might become corrupted, or a platform that might change its business model tomorrow.</p>
<p>There is a quiet but growing movement around &ldquo;Digital Gardens&rdquo; and personal websites—spaces that are curated and owned by the author, rather than optimized for algorithmic discovery. Writing in plain text and compiling to static files feels less like creating content and more like building an archive.</p>
<h2>The self-hosting mindset</h2>
<p>Underlying many of these tools is the philosophy of self-hosting.</p>
<p>Using FreshRSS wasn’t just about the RSS protocol; it was about the realization that I could run the software myself. Instead of paying with my data or attention for a &ldquo;free&rdquo; Software as a Service (SaaS), I could rent a small server and deploy the tools I needed.</p>
<p>This changes the relationship you have with your software. When you host it, you are responsible for it, but you also have absolute sovereignty over it. It doesn’t try to upsell you, it doesn&rsquo;t pivot to a new feature set you didn&rsquo;t ask for, and it doesn&rsquo;t shut down when a startup runs out of funding.</p>
<p>It is a heavier burden, but it is also a declaration of independence from the constant churn of the modern internet.</p>
<h2>A different relationship with “old” technology</h2>
<p>What makes all of this interesting is that I don’t experience it as nostalgia.</p>
<p>I don’t remember a time when these tools were the norm. I only encounter them as systems that still function, still evolve, and still serve specific purposes better than many modern alternatives.</p>
<p>That distance changes how I see them. They are not “old tools I used to use.” They are simply tools that exist, with different design assumptions.</p>
<p>And because I didn’t grow up with them, I am not comparing them emotionally to what came before. I am comparing them structurally to what I use now.</p>
<h2>What these systems have in common</h2>
<p>Over time, a pattern becomes visible across all of them.</p>
<p>They tend to assume:</p>
<ul>
<li>that communication does not need to be instantaneous</li>
<li>that information should remain readable without mediation</li>
<li>that users can control their own information flow</li>
<li>that systems should be inspectable rather than opaque</li>
<li>that simplicity is a long-term advantage, not a limitation</li>
</ul>
<p>None of these ideas are inherently “old.” But they were implemented more consistently in earlier internet systems than in many modern ones.</p>
<h2>Closing thoughts</h2>
<p>The interesting part is not that these tools are old.</p>
<p>It is that they still work without needing to adapt to the assumptions of modern platform design.</p>
<p>Discovering them later in time creates a different perspective. There is no nostalgia involved, no sense of returning to something. Instead, there is a kind of structural clarity: realizing that the internet was not always built around attention, and does not have to be.</p>
<p>RSS, Emacs, mailing lists, SourceHut and static sites are not alternatives to modern tools because they are outdated. They are alternatives because they follow different principles.</p>
<p>And those principles are still valid</p>
<hr/><p><em>Thanks for reading. You can view the original article at <a href='https://web.dlopez.eu.org/blog/old-internet-tools/'>Daniel López Blog</a>, contact me directly, or send a comment to my <a href='https://lists.sr.ht/~daniellop/public-inbox'>mailing list</a>.</em></p>]]></content:encoded></item><item><title>Mi experiencia en The Wave y la Hackathon: Innovando para la Academia de Inventores</title><link>https://web.dlopez.eu.org/blog/the-wave-hackathon/</link><pubDate>Thu, 16 Apr 2026 00:00:00 +0000</pubDate><author>Daniel López Pérez</author><guid isPermaLink="true">https://web.dlopez.eu.org/blog/the-wave-hackathon/</guid><description>Recientemente tuve la oportunidad de participar en The Wave en Zaragoza, un evento que se ha consolidado como un referente de innovación y tecnología en Aragón. Pero más allá de las ponencias y el networking, el verdadero reto fue la Hackathon, donde junto a mi equipo nos …</description><content:encoded><![CDATA[<p>Recientemente tuve la oportunidad de participar en <strong>The Wave</strong> en Zaragoza, un evento que se ha consolidado como un referente de innovación y tecnología en Aragón. Pero más allá de las ponencias y el networking, el verdadero reto fue la <strong>Hackathon</strong>, donde junto a mi equipo nos enfrentamos al desafío propuesto por la <strong>Academia de Inventores</strong> (del grupo Edelvives).</p>
<h2>El Reto: Programación sin barreras para los más pequeños</h2>
<p>La Academia de Inventores nos planteó una misión clara: crear una plataforma de programación por bloques que fuera funcional, intuitiva para niños de entre 5 y 9 años, y que permitiera la interacción directa con hardware real (placas Arduino). Además, debía integrar Inteligencia Artificial para asistir a los pequeños inventores en su proceso de aprendizaje.</p>
<p>Así nació <strong>Hello Blocks! Kids</strong><sup><a href="#fn-0">◊</a></sup>.</p>
<h2>El ambiente en The Wave</h2>
<p>El congreso no fue solo código y circuitos; fue un punto de encuentro increíble para la comunidad tech. Desde la entrada en el Palacio de Congresos hasta las salas llenas de energía, la atmósfera de innovación se respiraba en cada rincón.</p>






    
        <img src="https://web.dlopez.eu.org/img/blog/wave/wave_3.jpeg" alt="Entrada principal del Palacio de Congresos de Zaragoza durante The Wave."
>
    
    
    
        Entrada principal del Palacio de Congresos de Zaragoza durante The Wave.
    
    







    
        <img src="https://web.dlopez.eu.org/img/blog/wave/wave_2.jpeg" alt="Escenario principal, Planet Zero"
>
    
    
    
        Escenario principal, Planet Zero
    
    







    
        <img src="https://web.dlopez.eu.org/img/blog/wave/wave_1.jpeg" alt="Acreditación para las conferencias y Hackathon"
>
    
    
    
        Acreditación para las conferencias y Hackathon
    
    

<h2>Hello Blocks! Kids: Un entorno pensado para ellos</h2>
<p>Nuestro enfoque fue priorizar la UX para un público infantil. Eliminamos la complejidad innecesaria y creamos un sistema visualmente atractivo y motivador.</p>






    
        <img src="https://web.dlopez.eu.org/img/blog/wave/1.png" alt="Pantalla de selección de perfil: cada niño puede tener su propia progresión guardada de forma local."
>
    
    
    
        Pantalla de selección de perfil: cada niño puede tener su propia progresión guardada de forma local.
    
    

<h3>1. Un mapa de aprendizaje lúdico</h3>
<p>Diseñamos un sistema de niveles no lineal que transporta a los niños por diferentes retos, desde encender su primer LED en un faro hasta controlar motores más complejos.</p>






    
        <img src="https://web.dlopez.eu.org/img/blog/wave/2.png" alt="El mapa de niveles guía a los inventores a través de una narrativa de exploración."
>
    
    
    
        El mapa de niveles guía a los inventores a través de una narrativa de exploración.
    
    

<h3>2. CodePilot: La IA como mentora</h3>
<p>Uno de los puntos clave del reto era la integración de IA. Desarrollamos a <strong>CodePilot</strong>, un pequeño robot asistente que no solo da instrucciones, sino que analiza el estado del código del niño y ofrece pistas contextualmente relevantes.</p>






    
        <img src="https://web.dlopez.eu.org/img/blog/wave/3.png" alt="CodePilot en acción, explicando el concepto de bucles de forma sencilla."
>
    
    
    
        CodePilot en acción, explicando el concepto de bucles de forma sencilla.
    
    

<h3>3. Programación y Hardware Real</h3>
<p>Utilizando la <strong>Web Serial API</strong>, logramos que los bloques se tradujeran a código C++ de Arduino y se cargaran directamente a la placa desde el navegador, sin necesidad de instalar nada. El entorno incluye un simulador para que puedan probar sus algoritmos antes de volcarlos al hardware.</p>






    
        <img src="https://web.dlopez.eu.org/img/blog/wave/4.png" alt="Entorno de programación: bloques semánticos y simulador en tiempo real para un feedback inmediato."
>
    
    
    
        Entorno de programación: bloques semánticos y simulador en tiempo real para un feedback inmediato.
    
    

<h2>Arquitectura Técnica</h2>
<p>Para lograr un sistema robusto y escalable en solo 24 horas, apostamos por un stack moderno y eficiente:</p>
<ul>
<li><strong>Frontend</strong>: Desarrollado con <strong>React</strong> y <strong>Vite</strong>, utilizando <strong>Blockly</strong> para el motor de bloques y <strong>Framer Motion</strong> para las animaciones y micro-interacciones que dan vida a la interfaz.</li>
<li><strong>Backend</strong>: Una API en <strong>Node.js</strong> con <strong>Express</strong> que gestiona la persistencia de perfiles y la lógica de validación.</li>
<li><strong>Integración de IA</strong>: Implementamos un modelo de <strong>Mistral</strong>, consumido mediante un proxy desde Vite para mantener la seguridad de las claves y optimizar las peticiones del asistente CodePilot.</li>
<li><strong>Integración con Hardware</strong>: El backend incluye un flujo específico de <strong>compilación y carga para Arduino</strong>, permitiendo que el código generado por los niños se transforme en binarios ejecutables de forma transparente.</li>
</ul>
<h2>Conclusión</h2>
<p>La Hackathon de The Wave fue una experiencia intensa pero increíblemente gratificante. Logramos desarrollar un producto mínimo viable (MVP) completamente funcional en menos de 24 horas, demostrando que la tecnología y la educación pueden ir de la mano para inspirar a la próxima generación de inventores.</p>
<p>¿Quieres verlo en acción? Puedes explorar la demo en <a href="https://hbk.demo.dlopez.eu.org">hbk.demo.dlopez.eu.org</a>.</p>
<p>¡Gracias a la Academia de Inventores y a la organización de The Wave por esta oportunidad!</p>
<hr/><p><em>Thanks for reading. You can view the original article at <a href='https://web.dlopez.eu.org/blog/the-wave-hackathon/'>Daniel López Blog</a>, contact me directly, or send a comment to my <a href='https://lists.sr.ht/~daniellop/public-inbox'>mailing list</a>.</em></p>]]></content:encoded></item><item><title>Git Cheat Sheet: Master the Workflow</title><link>https://web.dlopez.eu.org/blog/git-cheat-sheet/</link><pubDate>Tue, 03 Mar 2026 00:00:00 +0000</pubDate><author>Daniel López Pérez</author><guid isPermaLink="true">https://web.dlopez.eu.org/blog/git-cheat-sheet/</guid><description>Git can be complex, but with the right reference, it becomes a powerful ally. This cheat sheet is designed to be clear, visual, and comprehensive.
🛠️ Configuration &amp;amp; Setup First things first: identify yourself to Git.
You can use --global to apply settings to all repositories …</description><content:encoded><![CDATA[<p>Git can be complex, but with the right reference, it becomes a powerful ally. This cheat sheet is designed to be clear, visual, and comprehensive.</p>
<h2>🛠️ Configuration &amp; Setup</h2>
<p>First things first: identify yourself to Git.</p>
<p>You can use <code>--global</code> to apply settings to all repositories on your system, or omit it for project-specific settings.</p>
<p>
    <pre><code>git config --global user.name &#34;Your Name&#34;</code></pre>
    <button title="Copy to clipboard">
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
            <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
        </svg>
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <polyline points="20 6 9 17 4 12"></polyline>
        </svg>
    </button>


    <pre><code>git config --global user.email &#34;email@example.com&#34;</code></pre>
    <button title="Copy to clipboard">
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
            <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
        </svg>
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <polyline points="20 6 9 17 4 12"></polyline>
        </svg>
    </button>
</p>
<h2>🚀 Repository Initialization</h2>
<p>Start a new project or grab an existing one from the cloud.</p>
<p>
    <pre><code>git init</code></pre>
    <button title="Copy to clipboard">
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
            <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
        </svg>
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <polyline points="20 6 9 17 4 12"></polyline>
        </svg>
    </button>


    <pre><code>git clone &lt;url&gt;</code></pre>
    <button title="Copy to clipboard">
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
            <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
        </svg>
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <polyline points="20 6 9 17 4 12"></polyline>
        </svg>
    </button>
</p>
<h2>🔄 Daily Workflow (Staging &amp; Committing)</h2>
<p>This is where the magic happens. Move your changes from the working directory to the repository.</p>

    <p>Status Check</p>
    
        Always run <code>git status</code> before committing to see exactly what is being included.
    


<p>
    <pre><code>git status</code></pre>
    <button title="Copy to clipboard">
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
            <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
        </svg>
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <polyline points="20 6 9 17 4 12"></polyline>
        </svg>
    </button>


    <pre><code>git add &lt;file&gt;</code></pre>
    <button title="Copy to clipboard">
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
            <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
        </svg>
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <polyline points="20 6 9 17 4 12"></polyline>
        </svg>
    </button>


    <pre><code>git commit -m &#34;Descriptive message&#34;</code></pre>
    <button title="Copy to clipboard">
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
            <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
        </svg>
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <polyline points="20 6 9 17 4 12"></polyline>
        </svg>
    </button>
</p>
<h2>🌿 Branching &amp; Merging</h2>
<p>Branches are essential for working in parallel without affecting the main codebase (<code>main</code>).</p>

    <p>Branching Concept</p>
    
        Think of a branch as a separate timeline. You can experiment, break things, and then, when you&rsquo;re ready, integrate those changes back.
    


<table>
  <thead>
      <tr>
          <th>Command</th>
          <th>Action</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>git branch</code></td>
          <td>List all local branches</td>
      </tr>
      <tr>
          <td><code>git checkout -b &lt;name&gt;</code></td>
          <td>Create and switch to a new branch</td>
      </tr>
      <tr>
          <td><code>git merge &lt;name&gt;</code></td>
          <td>Merge branch <code>&lt;name&gt;</code> into current branch</td>
      </tr>
      <tr>
          <td><code>git branch -d &lt;name&gt;</code></td>
          <td>Safely delete a merged branch</td>
      </tr>
  </tbody>
</table>
<h2>🏗️ Pull Requests (PRs)</h2>
<p>A <strong>Pull Request</strong> is the way you propose changes to a repository and ask others to review them before they are integrated.</p>
<h3>PR Merge Types:</h3>
<ul>
<li><strong>Standard Merge</strong>: Creates a &ldquo;merge commit&rdquo;, keeping the entire commit history of the branch.</li>
<li><strong>Squash and Merge</strong>: Combines all commits from the branch into a single one. Great for keeping a clean history.</li>
<li><strong>Rebase and Merge</strong>: Applies the branch&rsquo;s commits one by one on top of the current base. Does not create a merge commit.</li>
</ul>
<p>Use <strong>Draft Pull Requests</strong> if you want to showcase your work-in-progress but aren&rsquo;t ready for official review yet.</p>
<h2>🛠️ Workflow</h2>
<p>The most common workflow on platforms like GitHub or SourceHut is:</p>
<ol>
<li><strong>Fork</strong>: Create a copy of the repository in your own account.</li>
<li><strong>Clone</strong>: Download your copy locally: <code>git clone &lt;url&gt;</code>.</li>
<li><strong>Branch</strong>: Create a branch for your change: <code>git checkout -b my-improvement</code>.</li>
<li><strong>Commit</strong>: Make your changes and save them: <code>git commit -am &quot;Add X&quot;</code>.</li>
<li><strong>Push</strong>: Upload the branch to your remote: <code>git push origin my-improvement</code>.</li>
<li><strong>PR</strong>: Open a Pull Request from the platform&rsquo;s web interface.</li>
</ol>
<h2>🌐 Remote Operations</h2>
<p>Sync your local work with a remote server (like GitHub or SourceHut).</p>
<p>
    <pre><code>git remote -v</code></pre>
    <button title="Copy to clipboard">
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
            <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
        </svg>
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <polyline points="20 6 9 17 4 12"></polyline>
        </svg>
    </button>


    <pre><code>git push origin &lt;branch&gt;</code></pre>
    <button title="Copy to clipboard">
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
            <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
        </svg>
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <polyline points="20 6 9 17 4 12"></polyline>
        </svg>
    </button>


    <pre><code>git pull origin &lt;branch&gt;</code></pre>
    <button title="Copy to clipboard">
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
            <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
        </svg>
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <polyline points="20 6 9 17 4 12"></polyline>
        </svg>
    </button>
</p>
<h2>⏪ Undoing Changes</h2>
<p>Mistakes happen. Here is how to fix them.</p>

    <p>Caution</p>
    
        Be careful with <code>--hard</code> resets, as they permanently discard uncommitted changes.
    


<ul>
<li><strong>Unstage a file</strong>: <code>git reset &lt;file&gt;</code></li>
<li><strong>Discard local changes</strong>: <code>git checkout -- &lt;file&gt;</code></li>
<li><strong>Undo last commit (keep changes)</strong>: <code>git reset --soft HEAD~1</code></li>
<li><strong>Revert a commit (safe)</strong>: <code>git revert &lt;hash&gt;</code></li>
</ul>
<h2>📦 Stashing</h2>
<p>Need to switch branches but not ready to commit? Stash it!</p>
<p>
    <pre><code>git stash</code></pre>
    <button title="Copy to clipboard">
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
            <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
        </svg>
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <polyline points="20 6 9 17 4 12"></polyline>
        </svg>
    </button>


    <pre><code>git stash pop</code></pre>
    <button title="Copy to clipboard">
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
            <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
        </svg>
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <polyline points="20 6 9 17 4 12"></polyline>
        </svg>
    </button>
</p>
<h2>🔍 Inspection &amp; Logs</h2>
<p>Understand the history of your project.</p>
<p>
    <pre><code>git log --oneline --graph --all</code></pre>
    <button title="Copy to clipboard">
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
            <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
        </svg>
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <polyline points="20 6 9 17 4 12"></polyline>
        </svg>
    </button>


    <pre><code>git diff --staged</code></pre>
    <button title="Copy to clipboard">
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
            <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
        </svg>
        <svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none"
            stroke-linecap="round" stroke-linejoin="round">
            <polyline points="20 6 9 17 4 12"></polyline>
        </svg>
    </button>
</p>
<h2>🎓 Advanced Mastery</h2>
<p>If you ever &ldquo;lose&rdquo; a commit after a bad reset, <code>git reflog</code> is your best friend. It tracks every move of the HEAD.</p>
<ul>
<li><strong>Cherry-pick</strong>: <code>git cherry-pick &lt;hash&gt;</code> (Apply a specific commit from elsewhere)</li>
<li><strong>Reflog</strong>: <code>git reflog</code></li>
<li><strong>Interactive Rebase</strong>: <code>git rebase -i HEAD~n</code></li>
</ul>
<hr/><p><em>Thanks for reading. You can view the original article at <a href='https://web.dlopez.eu.org/blog/git-cheat-sheet/'>Daniel López Blog</a>, contact me directly, or send a comment to my <a href='https://lists.sr.ht/~daniellop/public-inbox'>mailing list</a>.</em></p>]]></content:encoded></item><item><title>Smart Thermostat with ESP32-S3: An Information Theory Project</title><link>https://web.dlopez.eu.org/blog/smart-thermostat-esp32/</link><pubDate>Sun, 01 Mar 2026 00:00:00 +0000</pubDate><author>Daniel López Pérez</author><guid isPermaLink="true">https://web.dlopez.eu.org/blog/smart-thermostat-esp32/</guid><description>Last year, as part of my Information Theory and Coding course, I developed a smart thermostat using the ESP32-S3 microcontroller. This project was more than just a simple temperature controller; it was an exercise in integrating various communication protocols and a robust …</description><content:encoded><![CDATA[<p>Last year, as part of my <strong>Information Theory and Coding</strong> course, I developed a <strong>smart thermostat</strong> using the <strong>ESP32-S3</strong> microcontroller. This project was more than just a simple temperature controller; it was an exercise in integrating various communication protocols and a robust control logic into a single IoT device.</p>
<h2>The Hardware Architecture</h2>
<p>The system&rsquo;s hardware is designed to simulate a real climate control environment:</p>
<ul>
<li><strong>Core</strong>: The <strong>ESP32-S3</strong> provides the necessary processing power and dual-radio capabilities (WiFi and BLE).</li>
<li><strong>Input</strong>: A <strong>10k Potentiometer</strong> acts as an analog temperature sensor.</li>
<li><strong>Visual Feedback</strong>: <strong>Status LEDs</strong> (Green, Red, Blue) and a <strong>7-segment Display</strong> for local readout.</li>
</ul>
<p>The temperature reading is performed by mapping the internal ADC values:</p>
<pre tabindex="0"><code>// Mapping analogRead (0-4095) to a range of -10 to 60 degrees
tempActual = ((((analogRead(pot)) * 70) / 4095) - 10);
</code></pre><h2>System Logic: The State Machine</h2>
<p>The behavior of the thermostat is governed by a finite state machine that incorporates <strong>hysteresis</strong> ($H$). This is a critical concept in control theory to prevent rapidly switching the relay on and off when the temperature is exactly at the set point.</p>

    
stateDiagram-v2
    S0_IDLE --> S1_COLD: t < tObj - H
    S1_COLD --> S0_IDLE: t>= tObj
    S0_IDLE --> S2_HOT: t> tObj + H
    S2_HOT --> S0_IDLE: t <= tObj

    state S0_IDLE {
        Green_LED
    }
    state S1_COLD {
        Red_LED
        Heating_Active
    }
    state S2_HOT {
        Blue_LED
        Cooling_Active
    }


<script type="module">
    import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
    mermaid.initialize({ startOnLoad: true });
</script>
<p>In the code, this is implemented within the <code>loop()</code> function using a <code>switch</code> statement that manages the transitions between <code>NEUTRAL</code>, <code>CALENTANDO</code> (Heating), and <code>ENFRIANDO</code> (Cooling).</p>
<h2>Communication Protocols</h2>
<p>The ESP32-S3 handles two concurrent interfaces:</p>
<h3>1. Bluetooth Low Energy (BLE)</h3>
<p>I implemented a custom BLE server with a specific callback class to handle remote commands. This allows for low-power configuration via a mobile app or terminal.</p>
<pre tabindex="0"><code>class MyCallbacks: public BLECharacteristicCallbacks {
  void onWrite(BLECharacteristic* pCharacteristic) {
      String value = pCharacteristic-&gt;getValue().c_str();
      if (value.length() &gt; 0) {
          int comando = value[0] - &#39;0&#39;; // Command ID
          switch (comando) {
              case ESTABLECER_TEMP_OBJETIVO:
                  tempTermo = value.substring(1).toFloat();
                  guardarEEPROM(&#34;tempTermo&#34;, tempTermo);
                  break;
              // ... other commands
          }
      }
  }
};
</code></pre><h3>2. Integrated Web Dashboard</h3>
<p>The device also acts as a WiFi Access Point hosting a responsive web server. This interface provides a more user-friendly way to monitor and control the system.</p>
<p><img src="https://web.dlopez.eu.org/blog/t_ui.png" alt="Thermostat Web UI"></p>
<p>The UI is designed to be clean and intuitive, following a modern &ldquo;Glassmorphism&rdquo; aesthetic:</p>
<ul>
<li><strong>Real-time Monitoring</strong>: The current temperature is displayed prominently, fetching data from the <code>/data</code> JSON endpoint every 2 seconds.</li>
<li><strong>Dynamic Controls</strong>: Users can adjust the target temperature and hysteresis with a 0.5°C precision using interactive buttons.</li>
<li><strong>State Indicators</strong>: A color-coded status badge (&ldquo;Heating&rdquo;, &ldquo;Cooling&rdquo;, or &ldquo;Optimal&rdquo;) provides immediate context.</li>
</ul>
<h2>Non-Volatile Storage (Preferences)</h2>
<p>To ensure the settings persist after a power cycle, I used the <code>Preferences.h</code> library, which interacts with the ESP32&rsquo;s NVS flash partition.</p>
<pre tabindex="0"><code>void guardarEEPROM(const char* clave, float valor) {
    preferences.begin(&#34;TEMPERATURAS&#34;, false);
    preferences.putFloat(clave, valor);
    preferences.end();
}
</code></pre><h2>Conclusion</h2>
<p>This project successfully applied theoretical concepts of signal coding and data transmission in a practical IoT application. The combination of hardware control, wireless communication, and persistent storage makes this a robust prototype for smart home automation</p>
<hr/><p><em>Thanks for reading. You can view the original article at <a href='https://web.dlopez.eu.org/blog/smart-thermostat-esp32/'>Daniel López Blog</a>, contact me directly, or send a comment to my <a href='https://lists.sr.ht/~daniellop/public-inbox'>mailing list</a>.</em></p>]]></content:encoded></item></channel></rss>