<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[chester's blog]]></title>
  <link href="https://chester.me/atom.xml" rel="self"/>
  <link href="https://chester.me/"/>
  <updated>2026-03-24T00:09:32+00:00</updated>
  <id>https://chester.me/</id>
  <author>
    <name><![CDATA[Chester (Carlos Duarte do Nascimento)]]></name>
    <email><![CDATA[cd@pobox.com]]></email>
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[A workaround to fix the Firefox emoji keyboard shortcut on macOS Sonoma]]></title>
    <link href="https://chester.me/archives/2024/02/a-workaround-to-fix-the-firefox-emoji-keyboard-shortcut-on-macos-sonoma/"/>
    <updated>2024-02-18T00:00:00+00:00</updated>
    <id>https://chester.me/archives/2024/02/a-workaround-to-fix-the-firefox-emoji-keyboard-shortcut-on-macos-sonoma</id>
    <content type="html"><![CDATA[<p>macOS 14 (Sonoma) <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1855346">broke</a> the “Emoji &amp; Symbols” keyboard shortcuts (<code class="language-plaintext highlighter-rouge">fn/🌐</code>+<code class="language-plaintext highlighter-rouge">e</code> or <code class="language-plaintext highlighter-rouge">control</code>+<code class="language-plaintext highlighter-rouge">cmd</code>+<code class="language-plaintext highlighter-rouge">space</code>) on Firefox: instead of opening, the emoji picker briefly flashes and disappears:</p>

<p><img src="/img/2024/02/emoji-flash.gif" alt="The &quot;Emoji &amp; Symbols&quot; panel briefly flashes and disappears" class="center" /></p>

<p>If you use the “Edit… Emoji &amp; Symbols” menu, the picker works - but it’s annoying to reach out for the mouse whenever you need an emoji or special character! I thought such an inconvenient bug would be fixed quickly on a minor Firefox or macOS update, but months passed and the bug was still there.</p>

<p>Between annoyed and curious, I dug the <a href="https://firefox-source-docs.mozilla.org/contributing/directory_structure.html">source code</a> a bit and wrote a <a href="https://phabricator.services.mozilla.com/D193328">patch</a> that fixes it, and also a <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1833923">secondary problem</a> with the <code class="language-plaintext highlighter-rouge">fn/🌐</code>+<code class="language-plaintext highlighter-rouge">e</code> shortcut (introduced in Monterey as a replacement/alternative for <code class="language-plaintext highlighter-rouge">control</code>+<code class="language-plaintext highlighter-rouge">cmd</code>+<code class="language-plaintext highlighter-rouge">space</code>): it works sometimes, but when it does, it also writes the letter “e” where the cursor is, which is equally irksome.</p>

<p>For reasons that I will explain below, Mozilla did not accept the fix. They are working on another solution, but it will take a while to be released. Since <a href="https://www.reddit.com/r/firefox/search/?q=emoji%20mac&amp;restrict_sr=1&amp;rdt=60658">many people have the problem right now</a>, I decided to share some details about my fix here, alongside with instructions for <a href="/archives/2024/02/a-workaround-to-fix-the-firefox-emoji-keyboard-shortcut-on-macos-sonoma/#applying-the-patch">applying the patch to the official Firefox source code</a> or <a href="/archives/2024/02/a-workaround-to-fix-the-firefox-emoji-keyboard-shortcut-on-macos-sonoma/#downloading-emojifox">downloading my patched version</a> - which I rebranded “EmojiFox” to avoid confusion and respect Mozilla’s trademarks/license.</p>

<p><strong>UPDATE:</strong> In January 7th, 2025, Mozilla released Firefox 134, which contains the aforementioned fix (and they were kind enough to mention the work described here on the <a href="https://www.mozilla.org/en-US/firefox/134.0beta/releasenotes/">beta release notes</a> ❤️). I strongly recoomend that you just update your browser instead of donwnolading the outdated build below, and swittch back to the official release if you are still using mine. I’m keeping the downloadable file here for historical purposes only.</p>

<!--more-->

<h3 id="finding-and-fixing-the-bug">Finding and fixing the bug</h3>

<p>(skip to the <a href="/archives/2024/02/a-workaround-to-fix-the-firefox-emoji-keyboard-shortcut-on-macos-sonoma/#what-are-my-options">next section</a> if you are not interested in the programming details and just want a workaround for the bug)</p>

<p>One thing that caught my attention was that this bug <a href="https://issues.chromium.org/issues/40934002">also happened with Chrome</a> after the macOS Sonoma update. They quickly produced a <a href="https://chromium.googlesource.com/chromium/src/+/cd62b1ad7d6557f6f6df26080d0305fb19622a1b%5E%21/">fix</a> - a surprisingly short one:</p>

<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code>     if (is_a_system_shortcut_event) {
       [[NSApp mainMenu] performKeyEquivalent:theEvent];
<span class="gi">+
+      // Behavior changed in macOS Sonoma - now it's important we early-out
+      // rather than allow the code to reach
+      // _hostHelper-&gt;ForwardKeyboardEventWithCommands(). Go with the existing
+      // behavior for prior versions because we know it works for them.
+      if (base::mac::MacOSVersion() &gt;= 14'00'00) {
+        _currentKeyDownCode.reset();
+        _host-&gt;EndKeyboardEvent();
+        return;
+      }
</span>
     } else {
       [self interpretKeyEvents:@[ theEvent ]];
     }
</code></pre></div></div>

<p>It gives some hints on the root cause: the app is forwarding the system shortcut event, instead of stopping it. It caused no harm before Sonoma, but after it, it results in the shortcut triggering <strong>twice</strong>, and the second trigger closes the picker. You can check it by pressing the shortcut twice in quick succession on any <em>other</em> (non-buggy) app: it cause the exact behavior of the bug!</p>

<p>With that in mind, I downloaded the <a href="https://hg.mozilla.org/mozilla-central">Firefox source code</a> and started poking at it. It’s a quite large (but <a href="https://firefox-source-docs.mozilla.org/">well documented</a>) codebase, but I didn’t need to understand it all - just had to find a suitable place to stop the event processing. Finding one, I produced a <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1855346#c16">proof-of-concept</a>, which crudely detected the key combinations and abruptly stopped processing:</p>

<div class="language-objc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(((</span><span class="n">anEvent</span><span class="p">.</span><span class="n">modifierFlags</span> <span class="o">&amp;</span> <span class="n">NSEventModifierFlagControl</span><span class="p">)</span> <span class="o">&amp;&amp;</span>
     <span class="p">(</span><span class="n">anEvent</span><span class="p">.</span><span class="n">modifierFlags</span> <span class="o">&amp;</span> <span class="n">NSEventModifierFlagCommand</span><span class="p">)</span> <span class="o">&amp;&amp;</span>
     <span class="n">anEvent</span><span class="p">.</span><span class="n">keyCode</span> <span class="o">==</span> <span class="mi">49</span><span class="p">)</span> <span class="o">||</span>
    <span class="p">((</span><span class="n">anEvent</span><span class="p">.</span><span class="n">modifierFlags</span> <span class="o">&amp;</span> <span class="n">NSEventModifierFlagFunction</span><span class="p">)</span> <span class="o">&amp;&amp;</span>
     <span class="n">anEvent</span><span class="p">.</span><span class="n">keyCode</span> <span class="o">==</span> <span class="mi">14</span><span class="p">))</span> <span class="p">{</span>
  <span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">break</span><span class="p">;</span>
</code></pre></div></div>

<p>That worked, but wouldn’t be much useful because users can redefine the emoji keyboard shortcut, so the only way to figure out whether an event is the shortcut I want to prevent is to go through the menus and find one that matches the event keys <em>and</em> triggers the action of opening the emoji picker. Chrome already had <a href="https://source.chromium.org/chromium/chromium/src/+/main:ui/base/cocoa/nsmenuitem_additions.mm;l=128-279;drc=28154a6fbbcaa037ae8692d96bc114286c57f6c7">code</a> for that, so I had to add something equivalent to Firefox:</p>

<div class="language-objc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Determines whether the key event matches the shortcut assigned to the Emoji &amp;</span>
<span class="c1">// Symbols menu item, so we can avoid dispatching it (and closing the picker).</span>
<span class="c1">//</span>
<span class="c1">// It works by looking for a second-level menu item that triggers the picker AND</span>
<span class="c1">// matches the shortcut, skipping any top-level menus that don't contain picker</span>
<span class="c1">// triggers (avoiding potentially long menus such as Bookmarks).</span>
<span class="c1">//</span>
<span class="c1">// It handles fn-E (the standard shortcut), ^⌘Space (which appears in a hidden</span>
<span class="c1">// menu when the standard is not redefined) and custom shortcuts (created via</span>
<span class="c1">// System Settings &gt; Keyboard &gt; Keyboard Shortcuts &gt; App Shortcuts), save for a</span>
<span class="c1">// few complex key combos that send incorrect modifiers.</span>
<span class="k">static</span> <span class="n">bool</span> <span class="nf">IsKeyEventEmojiAndSymbols</span><span class="p">(</span><span class="n">NSEvent</span><span class="o">*</span> <span class="n">event</span><span class="p">,</span> <span class="n">NSMenu</span><span class="o">*</span> <span class="n">menu</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">SEL</span> <span class="n">targetAction</span> <span class="o">=</span> <span class="k">@selector</span><span class="p">(</span><span class="n">orderFrontCharacterPalette</span><span class="o">:</span><span class="p">);</span>
  <span class="k">for</span> <span class="p">(</span><span class="n">NSMenuItem</span><span class="o">*</span> <span class="n">topLevelItem</span> <span class="k">in</span> <span class="n">menu</span><span class="p">.</span><span class="n">itemArray</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">topLevelItem</span><span class="p">.</span><span class="n">hasSubmenu</span> <span class="o">&amp;&amp;</span>
        <span class="p">[</span><span class="n">topLevelItem</span><span class="p">.</span><span class="n">submenu</span> <span class="nf">indexOfItemWithTarget</span><span class="p">:</span><span class="nb">nil</span>
                                          <span class="nl">andAction:</span><span class="n">targetAction</span><span class="p">]</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">for</span> <span class="p">(</span><span class="n">NSMenuItem</span><span class="o">*</span> <span class="n">item</span> <span class="k">in</span> <span class="n">topLevelItem</span><span class="p">.</span><span class="n">submenu</span><span class="p">.</span><span class="n">itemArray</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">item</span><span class="p">.</span><span class="n">action</span> <span class="o">==</span> <span class="n">targetAction</span><span class="p">)</span> <span class="p">{</span>
          <span class="n">NSString</span><span class="o">*</span> <span class="n">itemCharacters</span> <span class="o">=</span> <span class="p">[[</span><span class="n">item</span> <span class="nf">keyEquivalent</span><span class="p">]</span> <span class="nf">lowercaseString</span><span class="p">];</span>
          <span class="n">NSUInteger</span> <span class="n">itemModifiers</span> <span class="o">=</span> <span class="p">[</span><span class="n">item</span> <span class="nf">keyEquivalentModifierMask</span><span class="p">];</span>
          <span class="n">NSString</span><span class="o">*</span> <span class="n">eventCharacters</span> <span class="o">=</span>
              <span class="p">[[</span><span class="n">event</span> <span class="nf">charactersIgnoringModifiers</span><span class="p">]</span> <span class="nf">lowercaseString</span><span class="p">];</span>
          <span class="n">NSUInteger</span> <span class="n">eventModifiers</span> <span class="o">=</span>
              <span class="p">[</span><span class="n">event</span> <span class="nf">modifierFlags</span><span class="p">]</span> <span class="o">&amp;</span>
              <span class="n">NSEventModifierFlagDeviceIndependentFlagsMask</span><span class="p">;</span>

          <span class="k">if</span> <span class="p">([</span><span class="n">itemCharacters</span> <span class="nf">isEqualToString</span><span class="p">:</span><span class="n">eventCharacters</span><span class="p">]</span> <span class="o">&amp;&amp;</span>
              <span class="n">itemModifiers</span> <span class="o">==</span> <span class="n">eventModifiers</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
          <span class="p">}</span>
        <span class="p">}</span>
      <span class="p">}</span>
    <span class="p">}</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>(a nice bonus of doing that was discovering how Apple managed to replace <code class="language-plaintext highlighter-rouge">control</code>+<code class="language-plaintext highlighter-rouge">cmd</code>+<code class="language-plaintext highlighter-rouge">space</code> with <code class="language-plaintext highlighter-rouge">fn/🌐</code>+<code class="language-plaintext highlighter-rouge">e</code> on the menu, yet the old shortcut still worked: they keep <strong>two</strong> menu items for “Emoji &amp; Symbols”, but the one linked to the <code class="language-plaintext highlighter-rouge">control</code>+<code class="language-plaintext highlighter-rouge">cmd</code>+<code class="language-plaintext highlighter-rouge">space</code> shortcut is hidden)</p>

<p>With that in place, the fix is as simple as Chrome’s:</p>

<div class="language-objc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Early exit if Emoji &amp; Symbols shortcut is pressed; fixes bug 1855346</span>
<span class="c1">// (first seen on macOS Sonoma) and bug 1833923 (first seen on Monterey)</span>
<span class="k">if</span> <span class="p">((</span><span class="n">nsCocoaFeatures</span><span class="o">::</span><span class="n">OnMontereyOrLater</span><span class="p">())</span> <span class="o">&amp;&amp;</span>
    <span class="n">IsKeyEventEmojiAndSymbols</span><span class="p">(</span><span class="n">aNativeEvent</span><span class="p">,</span> <span class="p">[</span><span class="n">NSApp</span> <span class="nf">mainMenu</span><span class="p">]))</span> <span class="p">{</span>
  <span class="k">return</span> <span class="n">currentKeyEvent</span><span class="o">-&gt;</span><span class="n">IsDefaultPrevented</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<p>It turns out that doing this on the right place fixes not only the “flashing” bug, but the “e” one as well, because the later is also being processed twice, but <code class="language-plaintext highlighter-rouge">fn/🌐</code> being such a <a href="https://github.com/qmk/qmk_firmware/issues/2179">special</a> key on the Mac, sometimes the second occurrence loses the <code class="language-plaintext highlighter-rouge">fn</code>, acting as the <code class="language-plaintext highlighter-rouge">e</code> key being pressed right after the <code class="language-plaintext highlighter-rouge">fn/🌐</code>+<code class="language-plaintext highlighter-rouge">e</code>. That’s why I only apply the check to Monterey or later (after confirming that the “e” bug was introduced in Monterey, and the “flashing” one in Sonoma).</p>

<p><img src="/img/2024/02/hammer-keyboard.jpeg" alt="&quot;Person with a hammer hitting a keyboard&quot;" class="right" /></p>

<p>Of course it took me quite some time and learning to get there, and the true heroes are the Mozilla developers who kindly gave me feedback and pointed me towards the right direction at every step. At the end, we had a <a href="https://phabricator.services.mozilla.com/D193328">patch</a> that fully fixed both problems, addressing all performance and compatibility concerns with the traversal.</p>

<p>However, those same Mozilla developers reasoned it would be better to prevent the event from trickling down at all instead of catching it on the <code class="language-plaintext highlighter-rouge">TextInputHandler</code> (and catch <em>any</em> system shortcut events, not just the emoji picker one, which would avoid the need to traverse menus altogether), and wrote a <a href="https://phabricator.services.mozilla.com/D195016">different</a> patch in that direction.</p>

<p>I was happy with that: I learned a lot, helped raising awareness and researching towards the cleanest solution, and - most important - the bug would soon be fixed for good. But a couple months passed, Firefox got a few major version updates, yet the keyboard shortcut was still broken!</p>

<p>So I <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1855346#c43">asked</a> around, and it seems the  cleaner patch fixes the “flashing” issue, but <strong>not</strong> the “e” bug. They are actively working on a second patch for that, and will release both together - which is technically the best approach, but will take a while to be available for Firefox + Mac users.</p>

<h3 id="what-are-my-options">What are my options?</h3>

<p>If you are affected by this bug, you can:</p>

<ol>
  <li>
    <p><strong>Wait for the official fix</strong>. This is the simplest and safest option, but considering the <a href="https://whattrainisitnow.com/calendar/">release calendar</a>, my best guess is that a fix won’t come before Firefox 125 (due April 16).</p>
  </li>
  <li>
    <p><strong>Apply my patch to the Firefox source code and build it</strong>. This is also very safe: you don’t need to trust anyone but Mozilla, since you are using their code (which you already trust as a Firefox user) and my patch (which is public and you can review). But it requires familiarity with the command line and <em>a lot</em> of time to compile the browser.</p>
  </li>
  <li>
    <p><strong>Download and install EmojiFox</strong>, that is, Firefox Nightly/Unofficial with my patch applied. The downsides: you have to trust me and it won’t auto-update - you should throw it away as soon as the official fix is released.</p>
  </li>
</ol>

<h3 id="applying-the-patch">Applying the patch</h3>

<p>First step is to download and build Firefox on macOS by following the <a href="https://firefox-source-docs.mozilla.org/setup/macos_build.html">official instructions</a>. Just keep in mind that:</p>

<ul>
  <li>You should <em>not</em> select <a href="https://firefox-source-docs.mozilla.org/contributing/build/artifact_builds.html">artifact builds</a> when asked, as they are based on pre-built binaries and you need to build the binaries yourself.</li>
  <li>Before running <code class="language-plaintext highlighter-rouge">./mach build</code>, you should add <code class="language-plaintext highlighter-rouge">ac_add_options --enable-release</code> to your <code class="language-plaintext highlighter-rouge">.mozconfig</code> file (and comment out any debug-related options, or pretty much anything but this one)</li>
</ul>

<p><code class="language-plaintext highlighter-rouge">./mach build</code> takes a few hours, even on a beefy machine. Once you are running Nightly, confirm the bug is still there, then apply the patch with:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-L</span> https://phabricator.services.mozilla.com/D193328?download<span class="o">=</span><span class="nb">true</span> | patch
</code></pre></div></div>

<p>and <code class="language-plaintext highlighter-rouge">./mach build</code> again (don’t worry, it will be much faster, since it only recompiles the files that changed), then <code class="language-plaintext highlighter-rouge">./mach run</code> again. You should see the bug fixed now:</p>

<p><img src="/img/2024/02/fix.gif" alt="&quot;Emoji &amp; Symbols&quot; shortuct now opens the full or contextual panel" class="center" /></p>

<p>You are not done yet - even though there is a <code class="language-plaintext highlighter-rouge">Nightly.app</code> that you can copy, it will be bound to assets that will disappear once you clean up your building environment. So now run:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./mach package
</code></pre></div></div>

<p>That will generate a <code class="language-plaintext highlighter-rouge">.dmg</code> file in your <code class="language-plaintext highlighter-rouge">obj-x86_64-apple-darwin23.1.0/dist</code> folder (or <code class="language-plaintext highlighter-rouge">obj-arm64/dist</code> if you are using an Apple Silicon Mac). That <code class="language-plaintext highlighter-rouge">.dmg</code> contains a <code class="language-plaintext highlighter-rouge">Nightly.app</code> that you can copy to your Applications folder and use as your main browser.</p>

<h3 id="downloading-emojifox">Downloading EmojiFox</h3>

<p>I have been using Firefox 121 with this path since December, and recently re-applied it to the nightly build of Firefox 124. You can download this patched version (which I rebranded as “EmojiFox”) as long as you keep in mind that:</p>

<ul>
  <li>I (Chester) do not represent Mozilla, and this is <strong>not</strong> a Mozilla/Firefox official release.</li>
  <li>This software will <strong>not</strong> auto-update, and I don’t intend to release new versions (by the time it gets old, we should have the proper fix on official Firefox). It’s a workaround that you should throw away and go back to default Firefox as soon as a fixed version is released. Always keep your browser updated!</li>
  <li>Neither I, nor Mozilla, nor anyone is responsible for any damage caused by the patched version.</li>
  <li>Per <a href="https://www.mozilla.org/en-US/MPL/">Mozilla Public License</a> terms, my source code changes are available <a href="https://phabricator.services.mozilla.com/D193328">here</a> (<a href="https://phabricator.services.mozilla.com/D193328?download=true">raw diff</a>).</li>
  <li><strong>As of Jan 7, 2025, the bug is fixed on the official release</strong>. <strong>Do not use this one</strong>. It is here for historical reasons only.</li>
</ul>

<style>
  #emojifox-download-div {
    display: none;
  }

  #emojifox-agree-with-terms-checkbox:checked + label + #emojifox-download-div {
    display: block;
    border: 2px solid;
    padding-top: 16px;
    padding-right: 16px;
    width: fit-content;
    margin: 10px auto 10px auto;
  }
</style>

<form style="padding-bottom:12px">
  <input type="checkbox" id="emojifox-agree-with-terms-checkbox" />
  <label for="emojifox-agree-with-terms-checkbox"><strong>I <u>read</u> and <u>agree</u> with the terms above</strong> (click to show download links)</label>
  <div id="emojifox-download-div">
    <ul>
      <li><a href="/download/EmojiFox-124.0a1.en-US.mac.x86_64.dmg">Download EmojiFox 124.0a1 for Intel Macs</a></li>
      <li><a href="/download/EmojiFox-124.0a1.en-US.mac.arm64.dmg">Download EmojiFox 124.0a1 for Apple Silicon Macs</a></li>
    </ul>
  </div>
</form>

<p>Open the file and drag EmojiFox to your Applications folder, as usual. But when you run the app, it will say it’s from an unidentified developer (I currently don’t do enough macOS development to justify the yearly USD 99 for an Apple Developer Program membership that would allow me to sign it).</p>

<p><img src="/img/2024/02/cannot-be-opened.png" alt="Dialog saying EmojiFox cannot be opened because the developer cannot be verified, with no option to override" class="center" /></p>

<p>The <a href="https://support.apple.com/en-ca/guide/mac-help/mh40616/mac">trick</a> here is to hold <code class="language-plaintext highlighter-rouge">control</code> while clicking the app icon, then select “Open” from the context menu. It will also show a warning, but now there will be an <code class="language-plaintext highlighter-rouge">Open</code> button that will open the app. You only need to do this once - from now on, it will open normally.</p>

<p><img src="/img/2024/02/cannot-verify.png" alt="Aslo a dialog saying EmojiFox cannot be opened because the developer cannot be verified, with but now it has an Open button" class="center" /></p>

<p>Verify that both the <code class="language-plaintext highlighter-rouge">control</code>+<code class="language-plaintext highlighter-rouge">cmd</code>+<code class="language-plaintext highlighter-rouge">space</code> and <code class="language-plaintext highlighter-rouge">fn/🌐</code>+<code class="language-plaintext highlighter-rouge">e</code> shortcuts work as expected.</p>

<p><img src="/img/2024/02/emojifox.gif" alt="&quot;Emoji &amp; Symbols&quot; shortuct on EmojiFox" class="center" /></p>

<h3 id="use-your-existing-profile">Use your existing profile</h3>

<p>Regardless of whether you built or downloaded your fixed browser, you will want to bring your existing bookmarks, history, extensions, etc. to it, and the easy way to do that is to configure it to use your existing profile (instead of the one it just created).</p>

<p>To do so, ensure the original Firefox is closed, and type <code class="language-plaintext highlighter-rouge">about:profiles</code> at the new browser’s address bar. Click <code class="language-plaintext highlighter-rouge">Set as default profile</code> on your Firefox profile, restart the browser and you should see your bookmarks, history, extensions, etc.</p>

<p>(if you have multiple profiles and don’t know which is the right one, just try <code class="language-plaintext highlighter-rouge">Launch profile in new browser</code> on any candidates)</p>

<h3 id="final-considerations">Final considerations</h3>

<p>The only issue I had with this build so far: unlocking the 1Password extension doesn’t work with Touch ID (I suppose it’s because it isn’t an official release); you can still unlock with your password, and/or use Touch ID on the 1Password application. It’s a minor trade-off for people who, like myself, type emoji <em>much</em> more often than log on to websites.</p>

<p>If you try any of these solutions, please let me know in the comments below whether it worked for you or not. And let’s 🤞 for Mozilla to release the official fix soon (they are working on it) so we don’t need these workarounds anymore!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Migrating blog comments from Disqus to Staticman]]></title>
    <link href="https://chester.me/archives/2024/02/migrating-blog-comments-from-disqus-to-staticman/"/>
    <updated>2024-02-14T00:00:00+00:00</updated>
    <id>https://chester.me/archives/2024/02/migrating-blog-comments-from-disqus-to-staticman</id>
    <content type="html"><![CDATA[<p><img src="/img/2024/02/staticman-logo-with-text.jpeg" alt="Staticman's logo by Erlen Masson (https://www.erlen.co.uk/), reproduced under a premise of fair use - a minimalist/negative space illustration of a Clark-Kent-y head and partial torso, but wearing a Superman-style cape, the cape tied with a bowtie. Below the text &quot;Staticman&quot;, then &quot;Static sites with superpowers&quot;" class="left" /></p>

<p>In this age of <a href="https://www.engadget.com/how-twitter-died-in-2023-and-why-x-may-not-be-far-behind-143033036.html">controversial</a> social media platforms, having a <a href="https://en.wikipedia.org/wiki/Blog">blog</a> is one of the few remaining opportunities to keep ownership over your content. There are several good solutions around to publish and host one, but <a href="https://jekyllrb.com/">Jekyll</a> and <a href="https://pages.github.com/">GitHub Pages</a> are a great (and free) combination for people like myself who are happy hacking a little bit - except for not providing a comment system out of the box.</p>

<p>For years, I filled that gap with <a href="https://disqus.com/">Disqus</a> - a service that hosts your comments in exchange for a bit of advertising space. It was great at first, but over time <a href="https://disqus.com/home/discussion/channel-discusschitchatchannel/disqus_has_too_many_ads/">ads became heavier</a>, users were <a href="https://disqus.com/home/discussion/channel-discussdisqus/does_disqus_allow_anonymous_commenting/">pushed towards creating accounts</a> and <a href="https://techcrunch.com/2021/05/05/disqus-facing-3m-fine-in-norway-for-tracking-users-without-consent/">abusively tracked</a>. Moreover, hosting comments externally affects search engine indexing, and over time this all caused people to comment less and less, so I decided to bring the comments back to my blog.</p>

<p>A comment system isn’t a very complicated app, but it would be another database that I’d have to care for, and a departure from Jekyll’s static generation model that served me so well. The ideal solution would be to store comments in the same place I store posts: a trusty GitHub repository. Jekyll can read data files to show the comments, and all I needed was to host an app somewhere that would create those files when a new comment is written.</p>

<p>I almost coded that app myself, but <a href="https://eduardoboucas.com/about/">Eduardo Bouças</a> wrote and kindly shared <a href="https://staticman.net/">Staticman</a>, which does precisely that. Sure, I still had to host/configure it, adapt the blog to send it the comments (and read them from the repository files), and migrate the old comments from Disqus. These things combined took me a couple days, so I thought I’d share the process here.</p>

<!--more-->

<h3 id="hosting-staticman">Hosting Staticman</h3>

<p>It’s a good idea to first familiarize oneself with <a href="https://staticman.net/docs/">how Staticman works</a>, but the gist is that your blog’s “new comment” form sends the POST to Staticman (instead of sending to the blog itself); Staticman has a GitHub API key that allows it to add the data file containing the post data to your website. That will trigger a rebuild (in the same way that a new blog post would), and Jekyll will show the new comment.</p>

<p><img src="/img/2024/02/staticman-flow.png" alt="A sequence diagram illustrating how the website (browser), the Staticman instance and the git provider (GitHub) interact: the browser POSTs a content submission to the Staticman, which grabs the config from GitHub, creates the pull request on it and sends back an OK response; once a merge happens, GitHub deploys the site with the newly submitted content" class="center" /></p>

<p>If you want to moderate the comments (like I do), it can create a pull request instead of merging the data directly. You review the pull request and merge it to approve, or discard to reject - a very familiar environment for most programmers these days. It supports other git providers such as GitLab, but I’ll focus on GitHub.</p>

<p>You will need to host it somewhere. It’s a lightweight, database-less Node.js app, so there are lots of options and not a lot of configuration involved. My choice is a DigitalOcean droplet (you can check my <a href="/archives/2023/11/budget-friendly-hosting-for-personal-projects">recent blog post on cost-effective hosting</a> for details).</p>

<p>The <a href="https://staticman.net/docs/getting-started">official instructions</a> are clear once you figure the moving parts. Your server will contain two RSA keys: a GitHub API key so the server can act on your behalf), and a private key that (I suppose) is used to store local secrets.</p>

<p>A few gotchas I ran into:</p>

<ul>
  <li>
    <p>There are two configuration files: the API configuration (<code class="language-plaintext highlighter-rouge">config.production.json</code>) and the site configuration (<code class="language-plaintext highlighter-rouge">staticman.xml</code>). The first contains secrets such as API keys and should only reside on your Staticman server; the other goes on your blog’s repository, telling Staticman what to do when it receives a comment, and can be public (<a href="https://github.com/chesterbr/chesterbr.github.io/blob/b268fe58c6d0d1279c4c10031fa964ef2d3d19e3/staticman.yml">here is mine</a>).</p>
  </li>
  <li>
    <p>The docs currently <a href="https://staticman.net/docs/api#githubAppId">state</a> that the GitHub Application ID in <code class="language-plaintext highlighter-rouge">config.production.json</code> is <code class="language-plaintext highlighter-rouge">githubAppId</code>; actually, it’s <code class="language-plaintext highlighter-rouge">gitHubAppID</code>.</p>
  </li>
  <li>
    <p>Both RSA keys were triggering <a href="https://github.com/tngan/samlify/issues/452#issuecomment-1359699318">a <code class="language-plaintext highlighter-rouge">node-rsa</code> error</a>. In order to fix it, I changed the code (<a href="https://github.com/chesterbr/staticman/commit/bb2cc22e07fdf685751ee9d9758813af16f02f76">here</a> and <a href="https://github.com/chesterbr/staticman/commit/6a52984c6273d59a7b9973fa8a11c6ff8faa77bd">here</a>).</p>
  </li>
  <li>
    <p>Thanks to GitHub’s support for <a href="https://letsencrypt.org/">Let’s Encrypt</a>, my blog runs over https (TLS), which means it <a href="https://developer.mozilla.org/en-US/docs/Web/Security/Mixed_content">cannot post data to a regular http server</a>. My go-to solution for those cases is to run the application behind <a href="https://nginx.org/en/">nginx</a>, configuring it to <a href="https://docs.nginx.com/nginx/admin-guide/security-controls/terminating-ssl-tcp/">terminate</a> the secure connection and use certificates that Let’s Encrypt provides for free.</p>
  </li>
</ul>

<p>If you use Ansible (or are comfortable reading Ansible files), <a href="https://github.com/chesterbr/chester-ansible-configs/pull/17/files#diff-5ed24083ba879c12fe8883c7c949333838832ee538935eaa3a3217e3ba5a328f">here</a> is the playbook that installs/configures the Staticman and nginx, with <a href="http://supervisord.org/">Supervisor</a> to keep it running and <a href="https://certbot.eff.org/">Certbot</a> to keep the certificates up to date.</p>

<h3 id="creating-and-showing-comments">Creating and showing comments</h3>

<p>At this point you should have a working Staticman server, so the next step is to add a form to your blog that sends the comment to it. The form should have the same fields that Staticman expects, and you can use JavaScript to send the data to the server and show the comment immediately after it’s created.</p>

<p>I based mine on a few examples I saw online, most notably <a href="https://github.com/avglinux/alu-test-website">this one</a>. It uses <a href="https://jquery.com/">jQuery</a> to send the data to the server and show the comment - not my choice in 2024, but I already have legacy JQuery code on the blog anyway, so I rolled with it.</p>

<p>You will know it is working when a post results in a pull request on your blog’s repository like <a href="https://github.com/chesterbr/chesterbr.github.io/pull/29">this one</a>. Merging it will add the comment to your blog’s <code class="language-plaintext highlighter-rouge">_data</code> directory, and the next step is to show it in the post’s page.</p>

<p>Again I borrowed a lot from Avglinux’s example, fixing a couple issues with the threaded replies and adjusting to my blog’s style. I also replaced the Liquid <a href="https://shopify.github.io/liquid/filters/strip_html/"><code class="language-plaintext highlighter-rouge">strip_html</code> filter</a> with <a href="https://github.com/chesterbr/chesterbr.github.io/blob/main/_plugins/sanitize_html.rb">a custom one</a> that sanitizes it instead, so I can allow some HTML tags alongside the Markdown, while still keep the blog safe from JavaScript injection, <a href="https://owasp.org/www-community/attacks/xss/">cross-site scripting attacks</a> and the like.</p>

<p><a href="https://github.com/chesterbr/chesterbr.github.io/pull/72">This PR</a> contains all the code mentioned above; feel free to peruse and copy any of them; possibly checking the latest versions as this post gets older.</p>

<h3 id="migrating-comments-from-disqus-to-staticman">Migrating comments from Disqus to Staticman</h3>

<p>With this in place, all that was left to do was to migrate the comments from Disqus.</p>

<p>Disqus allows you to <a href="http://disqus.com/admin/discussions/export/">export</a> the comments to an XML file (documented <a href="https://help.disqus.com/en/articles/1717164-comments-export">here</a>), but in order to import them anywhere else, a conversion is needed. I found a few recipes (<a href="https://blog.arkey.fr/2022/10/16/moving-from-disqus-to-giscus/">1</a>, <a href="https://asp.net-hacker.rocks/2018/11/19/github-comments.html">2</a>, <a href="https://gist.github.com/evert/3332e6cc73848aefe36fd9d0a30ac390">3</a>, <a href="https://blog.riemann.cc/2021/12/27/jekyll-import-disqus-comments-for-staticman/">4</a>) online, but none of those worked for me, so I threw together <a href="https://gist.github.com/chesterbr/6368adb7530f6d582046a5d93a4d4a49">some JavaScript code</a> that does the job:</p>

<script src="https://gist.github.com/6368adb7530f6d582046a5d93a4d4a49.js"> </script>

<p>You can just run it, making the needed adjustments for your <code class="language-plaintext highlighter-rouge">staticman.yml</code> configuration (e.g., if you changed the filename structure or added other fields that you want to import or generate) and put the generated <code class="language-plaintext highlighter-rouge">comments</code> directory under your <code class="language-plaintext highlighter-rouge">_data</code> directory in your blog’s repository, like I did <a href="https://github.com/chesterbr/chesterbr.github.io/pull/69/files">here</a>.</p>

<p>The code documents some of the shenanigans I found (odd terminology, invalid characters, etc.). It’s worth noticing that not every bit of information needed by Staticman is available in the XML, so a few choices were made:</p>

<ul>
  <li>
    <p>I kept the comment <code class="language-plaintext highlighter-rouge">_id</code> as its original Disqus ID (instead of generating a UUID, which would change the values at each migration run and require an extra lookup for comment replies). Doing so made the <code class="language-plaintext highlighter-rouge">replying_to_uid</code> field odd, but it will correctly point to the <code class="language-plaintext highlighter-rouge">_id</code> of the comment being replied to, and Staticman is fine with that.</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">createdAt</code> is an <a href="https://en.wikipedia.org/wiki/ISO_8601">ISO 8601</a> date with seconds precision, which is easy to convert to the <code class="language-plaintext highlighter-rouge">date</code> Staticman field (which is, by default, a <a href="https://en.wikipedia.org/wiki/Unix_time">Unix time</a>), but the comment filenames are based on the timestamp in milliseconds. In order to improve uniqueness in the case of same-second comments, I filled the ms using the <code class="language-plaintext highlighter-rouge">_id</code> (once again keeping successive migration runs idempotent).</p>
  </li>
  <li>
    <p>My blog uses <a href="https://gravatar.com/">Gravatar</a> to display user pictures (if they create one on the site; a generated pattern otherwise) based on a hash of their e-mail. Unfortunately, Disqus doesn’t export users’ emails, so instead of leaving it blank (which would give all users the same pattern), I hash the Disqus username, so the same user will always have the same pattern across the site.</p>
  </li>
</ul>

<h3 id="conclusion">Conclusion</h3>

<p>As I said before, it took me a while to figure out all these pieces, but I’m happy with how it turned out: I own the comments (which I can keep hosting if I ever switch away from Jekyll), they are indexed by search engines, and I can moderate them in a familiar environment (pull requests).</p>

<p>There is the burden/cost of hosting the server, but I share it with other apps, so it’s effectively free for me. I did not (yet) set up email notifications for replies on users’ comments or a spam filter, but that can be done with <a href="https://www.mailgun.com">Mailgun</a> and <a href="https://akismet.com/">Akismet</a> - and those services have generous free tiers.</p>

<p>The only caveat is that Staticman doesn’t seem to be actively maintained, despite its numerous forks/users. That is a sign of maturity, but also makes me wary of yet-undiscovered vulnerabilities. But with its minimal code (and thus attack surface) and <a href="https://docs.github.com/en/code-security/getting-started/dependabot-quickstart-guide">Dependabot</a> on my fork warning me about vulnerabilities found in its dependencies, I think it’s worth the risk. Worst come to worse, it can always be replaced by a custom solution, since the comments are not locked in a proprietary system anymore - something I’ll never give up again.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Visiting Cuba]]></title>
    <link href="https://chester.me/archives/2024/01/visiting-cuba/"/>
    <updated>2024-01-05T00:00:00+00:00</updated>
    <id>https://chester.me/archives/2024/01/visiting-cuba</id>
    <content type="html"><![CDATA[<p><img src="/img/2024/01/chester-mala-fidel.jpeg" alt="Me at the airport, with a suitcase. Above a billboard with Fidel Castro and a quote in Spanish (&quot;The grateful go with you&quot;), from a Raul Torres song, with some tourist-y photos" class="right" /></p>

<p>Having a relatively short office closure week for the holidays led my wife and I to look for a sunny break from the Canadian winter, and we noticed a lot of Canadians chose Cuba for that.</p>

<p>Between the proximity (it’s a 3-hour flight from Toronto), the relative affordability and our desire to understand the country beyond the usual left/right political narratives, we decided to give it a try. Here are some highlights of our experience and a few things we wish we knew before going.</p>

<!--more-->

<h3 id="preparation">Preparation</h3>

<p><strong>Accommodations:</strong> Typical (that is, US-based) travel agency and homestay websites don’t list accommodations in Cuba. <a href="https://www.expedia.ca">Expedia</a> is a notable exception, so we booked and prepaid our stays through it. You usually have two options: all-inclusive resorts (usually close to a beach, where people stay through their whole vacation) and homestays (for those wanting to see the country and talk to the locals, like us). In any case, the websites ask an odd question about your reason for visiting Cuba (and none of the answers matches “tourism”) - that’s because they are required to do so by the US government, so just pick one of the options and move on.</p>

<p><strong>Money:</strong> Visa/MasterCard don’t operate there, so you will use cash for everything. Restaurants, stores and experiences will accept US dollars, so bring those. USD 30 should get three basic meals for a person and USD 10 transports you within the same city, so budgeting at least USD 50/person/day (with prepaid stays) is a good idea. Don’t buy pesos (CUP) - you will get the official rate (1 USD = 120 CUP), whereas purchases will go with 200-250 CUP per USD. Change for your USD will usually be CUP anyway - so bring small bills (5/10/20) and use the pesos from change on small purchases, like a coffee or pastry on a street vendor. Don’t count on converting back to USD or spending at the airport, so spend or donate your pesos before leaving.</p>

<p><strong>Food and medication:</strong> Be prepared to focus on local specialities such as the <a href="https://en.wikipedia.org/wiki/Ropa_vieja">Ropa Vieja</a> (shredded beef). You may find other food, but ingredients and spices will be scarce, so don’t expect sophistication. Bring some snack bars and biscuits if you have dietary needs or are a picky eater, and also any medication, seasoning (e.g.: sweeteners) and toiletries you can imagine yourself needing.</p>

<p><strong>Clothing:</strong> Winter was mostly warm (above 21ºC with a single rainy day); summer must be 🔥, so pack accordingly. You may consider donating some of your clothes/shoes once you use them. Speaking of which…</p>

<p><strong>Donations:</strong> Blame the embargo, the corruption, both or anything else; it doesn’t matter: fact is that Cuba is suffering severe shortages, and the locals will appreciate any donations you can bring (details below). Think dollar store daily essentials that would be hard to get in an isolated country (toiletries, clothing, reading glasses, pens and pencils, crosswords/coloring books, etc.) and fill the empty spaces in your luggage with those, if you can and want.</p>

<p><strong>Media and Internet:</strong> Check below for details, but in short: <strong>before you go</strong>, get a VPN (to access sites and services that are blocked for Cuba) and plan for mobile internet access: you can either get a local SIM card at the airport or use roaming from your phone operator (but <a href="https://consumerrescue.org/travel-troubles/roaming-charge-nightmare-giant-cell-phone-bill/">triple check the rates and limits</a> and keep an eye while you are there). Of course, download offline maps on Google Maps and any other apps and media you may want there, and pre-book (and pre-pay) any tours and experiences you can before traveling.</p>

<p><strong>Advance Travel Information (D’VIAJEROS):</strong> Not sure if mandatory, but it’s easy: a day or two before the trip, go to the <a href="https://www.dviajeros.mitrans.gob.cu/inicio">website</a>, select your language and fill the information on what you are (not) bringing. You get a PDF with a QR code that you print or save to your phone, and show that when asked at the airport. Unlike Canada’s ArriveCAN, each passenger needs to fill their own form and get their own QR code.</p>

<p><strong>Visa:</strong> Any visitor needs a visa (often referred to as a “tourist card”) to enter the country, but it’s inexpensive (around USD 20) and airlines often give you one as part of the ticket purchase; check with yours. Air Transat gave us the card inside the plane (hints: bring a pen and avoid mistakes; you can’t cross them and they will charge you for another form). Just fill (twice) your name, passport number and date of birth, show it on your way in, <strong>don’t lose it</strong>, return it on your way out and you are good.</p>

<p><strong>Non-Americans / Non-Canadians:</strong> If you are <em>not</em> Canadian or American, and plan to visit the United States in the future, keep in mind that, as of January 2024, <a href="https://www.timeandleisure.co.uk/promotions/esta-application-if-ive-been-to-cuba/">visiting Cuba prevents you from using the ESTA (“electronic visa”) program</a> and you will need to apply for a regular US visa; so you may want to get your ESTA before visiting Cuba (or plan to get a US visa instead). This was a farewell gift from Trump that hopefully will change in the future, but keep it in mind for now.</p>

<h3 id="here-comes-the-sun">Here comes the sun</h3>

<p>Our arrival and return flights were in Varadero (VAR), which is a very popular destination for Canadians - quite a few get all-inclusive resorts and stay inside them for the entirety of their trips. That wasn’t really our thing - sure, we wanted a break from the Canadian winter, but we also wanted to see the country and talk to the locals, so we split our time between Varadero itself (for the beaches), Havana (the urbanized capital) and Boca de Camarioca (a smaller village closer to the Varadero airport).</p>

<p>The beaches in Varadero are magnificent and the water was warm and clear. We were lucky to have great weather during our stay - in fact, winter brings the sun down to levels that my caucasian skin can withstand. You can rent chairs for the day and/or drink coconut water for a few dollars, get lunch at a nearby restaurant or have it brought to you. If you want to just relax and enjoy the sun, that’s where you should go.</p>

<p><img src="/img/2024/01/praia.jpeg" alt="Beach in Varadero" class="center" /></p>

<h3 id="getting-around">Getting around</h3>

<p>The airport in Varadero was functional, albeit minimalistic - they used inexpensive webcams to take our pictures and we even to lend one of the officers a pen. Customs asks few questions (fewer if you are Canadian), but we were randomly stopped after getting our luggage. We were asked about our itinerary (it helped to have all the dates and addresses) and, after acknowledging how cannabis is legal in Canada and stating it was “not a judgement question”, they asked whether we ever had it; we said no, and that was everything.</p>

<p>Speaking Spanish (or, in our case, <a href="https://en.wikipedia.org/wiki/Portu%C3%B1ol">Portuñol</a>) was quite helpful, but you can get around with English and some effort. We had a great recommendation for a taxi driver, with whom we pre-arranged pickup and drop-off at the airport and the transportation between our destinations according to distances. Going from Varadero to Havana and back typically costs around USD 100 for each trip (the price is for the car, regardless of the number of persons, but always ask). Getting from/to the airport will hover around USD 30.</p>

<p>Cuba is famous for the old-style cars used for tourists (other than those, most of what we saw were really old ones, nearly falling apart and the occasional luxury one, heavily contrasting with everything around it). The old-style cars do tours (a popular one being to visit Havana from Varadero and vice-versa). There are also horse-drawn carriages, pedal-powered taxis and buses, but we had no problems just using the taxis for long distance and walking everywhere else.</p>

<p><img src="/img/2024/01/carros.jpeg" alt="Old cars parked in Varadero" class="center" /></p>

<p>An interesting fact: the first letter in the license plate identifies the car’s assigned usage. <a href="https://en.wikipedia.org/wiki/Vehicle_registration_plates_of_Cuba#New_registration_system">Sources</a> <a href="https://www.cubatramite.com/cambio-de-chapa-de-identificacion-del-vehiculo/#1-_Cual_es_el_diseno_de_las_matriculas_en_Cuba">differ</a> <a href="https://www.tripadvisor.ca/ShowTopic-g147270-i91-k14405329-Cuban_licence_plates-Cuba.html">on</a> the meaning, but a few that seem to be consistent are:</p>

<table>
  <thead>
    <tr>
      <th>First Letter</th>
      <th>Meaning / Usage</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>A/B</td>
      <td>Government-assigned (by Transportation Ministry)</td>
    </tr>
    <tr>
      <td>C/D/E</td>
      <td>Diplomatic (Consular / Diplomatic / Embassy?)</td>
    </tr>
    <tr>
      <td>F</td>
      <td><a href="https://en.wikipedia.org/wiki/Cuban_Revolutionary_Armed_Forces">Revolutionary Army Forces</a></td>
    </tr>
    <tr>
      <td>K</td>
      <td>Temporary residents / foreign companies doing government business (later with “Cuba” written on a blue banner)</td>
    </tr>
    <tr>
      <td>M</td>
      <td><a href="https://en.wikipedia.org/wiki/Ministry_of_the_Interior_(Cuba)">Ministry of the Interior</a></td>
    </tr>
    <tr>
      <td>P</td>
      <td>Private</td>
    </tr>
    <tr>
      <td>S/W/Z</td>
      <td>Religious institutions, cooperatives (Z/S = bikes, W = others)</td>
    </tr>
    <tr>
      <td>T</td>
      <td>Tourism</td>
    </tr>
  </tbody>
</table>

<h3 id="social-perspectives">Social perspectives</h3>

<p>Even during our beach time, we walked around and talked to the locals (as we started giving some of the things we brought as gifts). At first, most people would tell how they were happy with the government and how things were good, but as we got closer to the less tourist-y places, we started to hear (and witness) a different story.</p>

<p>Outside of Cuba, people tend to align their opinions on the country with their left/right political leanings. For example, when Bolsonaro was Brazil’s president, his supporters will often tell you to “go to Cuba” when they run out of arguments (or even unprovoked just if you happen to not idolize him), while left-wing people will often overly praise the country’s performance on safety, education and healthcare, turning a blind eye to the human rights violations, lack of basic freedoms and the biased origins of those performance metrics.</p>

<p>This is a very complex subject, and I don’t expect to cover it in a single blog post from a week-long visit, but I would like to share some of the tidbits we learned from talking to the locals, from the guided tours (led by a <a href="https://www.airbnb.ca/experiences/496009">sociologist</a> and a <a href="https://www.airbnb.ca/experiences/162612">geographer</a>) and from consuming their local media and online content.</p>

<p>We highly recommend the tours above - as much as they have their personal opinions, they brought us lots of perspective on the country’s history (in particular, they helped us understand the extent of US assets that were seized, which explains why private lobby will never allow the US government to relent until those parties are compensated <em>and</em> why the local government has no hopes of negotiating a compensation, as neither the assets, nor wealth created by them are available) and the current situation, including the <a href="https://en.wikipedia.org/wiki/2021_Cuban_protests">2021 protests</a>.</p>

<p>The thing that mostly stands out are the shortages. Food, medicine, toiletries, electronics, you name it: everything is in short supply and rationed. The <em>bodegas</em> - government-sanctioned stores for the locals - will check their <em>libreta</em> (ration book) and only sell the amounts they’re allowed to buy (when they have supplies).</p>

<p><img src="/img/2024/01/libreta-bodega.jpeg" alt="Left: page of a libreta showing what a person bought in a month; right: list of available products on a bodega" class="center" /></p>

<p>We witnessed a semi-scheduled evening blackout of city lights around the public squares; locals are so used to it that our guide didn’t realize at first how scared we were. Sure, it is deemed safe to walk around at night, but it must be hard to go without electricity for hours when it hits residences (and it does).</p>

<p>As much as salaries are nearly the same for everyone, those with access to foreign currency (from working with tourism, for example) or resources (from relatives abroad) have a visibly different standard of living. They can buy things at the markets that are not available to the general population (at much higher prices), but they need to first get the foreign currency through a local bank card.</p>

<p><img src="/img/2024/01/mercado-che.jpeg" alt="A produce market - not a bodega - with paintings of Che Guevara on the walls" class="center" /></p>

<p>We noticed that that all the things we brought as <em>regalitos</em> (“gifts”, but they were actually donations) were gladly accepted, even by people that would obviously not use them - because they could be traded in alternative markets for the things they need and cannot get at the government stores. These trades are organized in the community by word of mouth, but also in WhatsApp groups. Checking that activity was an eye-opening experience.</p>

<p>As for the causes: the embargo (and US in general) definitely plays a role on that. Even those who blame the government admit <a href="https://en.wikipedia.org/wiki/Cuban_thaw">things were better in the Obama years</a> and are very afraid of a second Trump term. But the locals are quick to point out how many of the shortages can’t be explained by the embargo, as there are many things that are produced in Cuba and should be available in sufficient quantities.</p>

<p>Those conversations happened in hush-hush tone, as the government doesn’t take criticism as well as it says it does, and the electoral process is quite convoluted; in the higher instances, anything but sanctioning the central administration decisions is said to be not tolerated. Locals are proud of their country, but aware that they can’t speak freely about it, and that they aren’t compensated by social welfare as some external supporters would like to believe.</p>

<p>We learned is that doctors that work abroad (e.g.: in Brazil, where remote communities had significant social improvements thanks to them, until the right-wing government dismantled the program with offering no replacement) are paid a fraction of what the host country pays for their services, and the rest goes to the government. This sounds absurd in a capitalist logic, but might be be understandable if the government used that money to improve the lives of the locals (and maybe justify Cuba’s reputation for education, safety and health systems).</p>

<p>We wanted to check that <em>in loco</em>, but between the school break and our unwillingness to disturb hospitals in any way, we had to rely on the locals. They recognized and were proud of those achievements, but pointed out (and showed a bit) how the lack of investment in people and supplies degraded service in schools and hospitals in recent years. As for safety, crime is indeed low with nearly no weapons around, but locals are very afraid of the police (even more so with so many people are still incarcerated or disappeared after the 2021 protests).</p>

<p>Of course, these are random impressions I picked up; if you want some hard data with proper methodologies, I invite you to check the <a href="https://derechossocialescuba.com/informes/reports/">reports (in English) from the Observatorio de Derechos Sociales</a> - the Spanish version was highly recommended by academics to whom we spoke. The report is quite critical of the government, but also very transparent about the methodologies and data sources, so you can make your own conclusions.</p>

<h3 id="media-and-the-internet">Media and the internet</h3>

<p><img src="/img/2024/01/novela.jpeg" alt="Brazilian soap opera on a Cuban TV" class="left" /></p>

<p>As Portuguese native speakers, we were able to communicate with locals and and consume the local media. Television included some Latin American channels (seemingly unsupervised, but we were not sure how accessible they were to non-tourists). Government-ran Cubavisión seemed available everywhere, and <a href="https://en.wikipedia.org/wiki/Segundo_Sol">Segundo Sol</a>, a 2018 Brazilian soap opera <a href="https://www.cibercuba.com/noticias/2023-06-19-u1-e208512-s27065-nuevo-sol-television-cubana-estrena-telenovela-brasilena">dubbed in Spanish as “Nuevo Sol”</a>, is popular among locals.</p>

<p>Local shows were, as expected, heavily loaded with unapologetic government propaganda - a youth-oriented show that presented itself as an educational block against media manipulation was basically accusing international media of doing that, while presenting the government’s point of view as the only unbiased truth.</p>

<div style="clear:both" />

<p>The <a href="https://www.granma.cu/">official newspaper</a> is a daily set of around 8 pages that costs 20 CUP and limits to reporting policy changes and occasional cultural articles. There are some libraries and pop-up bookstores (the later mostly for tourists), but the selection is very limited.</p>

<p>Internet access is available, mostly through smartphones. Locals complain about the speed more often than they complain about price (but that was among those that actually had a smartphone). Some websites are indeed blocked by the government, but from our point of view, most of the blockings were done on the US sites/services side, which either block you, or don’t allow you to create accounts or handle payments from Cuba. A VPN works around that (and I recommend getting one <strong>before</strong> you go, for the reasons stated).</p>

<p><img src="/img/2024/01/granma.jpeg" alt="Granma and other offecial newspapers" class="center" /></p>

<p>To get internet as a foreigner, you can either by an ETECSA SIM (or e-SIM) right at the airport, or get roaming from your phone operator. I usually avoid the later option, as it’s quite easy to rack up a huge bill, but my provider (Freedom Mobile) has a CAD$ 30 package that gives you 5GB for 90 days on a large list of countries that includes Cuba. I kept an eye to make sure I’d not go over it and it worked fine, while my wife went with the e-SIM, so we had a failover in case one of them didn’t work.</p>

<p>One unexpected bug/feature: while her e-SIM got under all the restrictions while outside of a VPN, mine didn’t. I got a British Columbia IP address (despite living in Ontario) and was able to access all the sites and services that were blocked for her. Of course I didn’t abuse that, but it was quite helpful as we were able to book a couple of tours that were only available online.</p>

<p>When visiting the library, I found a <a href="https://medium.com/casa-editora-abril/100-respuestas-sobre-internet-en-cuba-12117aff9d3f">book</a> that explains how the internet (and computers in general) work in Cuba, which (as a retrocomputing and computer history nerd lucky enough to read Spanish) I found quite interesting. It’s very deferential to the government mantras (even in contradictory points such as being proud of their pioneirism on mainframe capabilities yet noticing they were kickstarted by nationalized IBM assets), but it’s interesting to see how Cubans managed to get their online infrastructure working in such a challenging environment.</p>

<h3 id="is-it-worth-to-visit-cuba">Is it worth to visit Cuba?</h3>

<p>Definitely yes! It is a great place to get a breather from the Canadian winter, with friendly people and relatively affordable accommodations, but you should be aware of the situation and be prepared to see a lot of poverty and people struggling to get by. If you’re not comfortable with that, you should probably stick to the all-inclusive resorts.</p>

<p><a href="/img/2024/01/cuba-map-illustration-large.png"><img src="/img/2024/01/cuba-map-illustration.png" alt="Stylized, upbeat map of Cuba featuring vibrant colors and cartoonish icons representing landmarks and cultural elements, generated by DALL-E" class="center" /></a></p>

<p>On the other hand, if you want to check for yourself, get an unbiased perspective and/or help the locals, by all means spend some time out of the resorts, and get to know the real Cuba. You will be able to see the beautiful landmarks and the old cars, but also the real people and their struggles.</p>

<p>Most important: free your mind both from the demonizing and the idolizing of the country, the government system and the people running it, and try to understand the situation from the locals’ perspective. You won’t regret it.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Budget-friendly hosting for personal projects]]></title>
    <link href="https://chester.me/archives/2023/11/budget-friendly-hosting-for-personal-projects/"/>
    <updated>2023-11-20T00:00:00+00:00</updated>
    <id>https://chester.me/archives/2023/11/budget-friendly-hosting-for-personal-projects</id>
    <content type="html"><![CDATA[<p><img src="/img/2023/11/build-server.jpg" alt="UI button" class="right" /></p>

<p>People get surprised when I tell them I keep all my personal software projects running on a single server, and that it costs me roughly a cup of (fancy) coffee per month. This post explains how I do it, and how you can do it too!</p>

<h3 id="why-bother">Why bother?</h3>

<p>Every now and then I build a personal project that requires hosting on a server - sometimes it’s a <a href="http://cruzalinhas.com/">website</a>, sometimes a <a href="https://github.com/chesterbr/toronto-transit-time/tree/main/server#readme">back-end API</a> for a <a href="https://github.com/chesterbr/toronto-transit-time#toronto-transit-time">watchface</a>, or even a <a href="https://github.com/chesterbr/minitruco-android/blob/main/README.md">multiplayer game</a> server. In any case, it is tempting to use a free service or self-host, but eventually some of those prove to be useful to other people (or myself) on the long run, requiring a more robust solution.</p>

<p>Sure, one can always embrace the <a href="https://en.wikipedia.org/wiki/DevOps">DevOps</a> culture and build the projects with <a href="https://cloudblogs.microsoft.com/opensource/2019/07/15/how-to-get-started-containers-docker-kubernetes/">tooling</a> that describes their infrastructure needs in code, deploying on a cloud provider. That works, but comes with a price tag that might discourage building new projects, and you don’t learn a lot about how things work behind the scenes.</p>

<p>In contrast, configuring and keeping a server up in a cost-effective, secure and robust way is a fun challenge in itself and a great learning experience. Even if you have a team or a service that does it all for you, getting some hands-on experience with servers makes you build better software, as you’ll be more aware of the constraints and trade-offs involved when it is deployed.</p>

<!--more-->

<h3 id="hosting-strategies">Hosting strategies</h3>

<p>There are many ways to host a project. Some of those are:</p>

<ul>
  <li>
    <p><strong>Self-hosting</strong>: You run the server yourself, on your own hardware. It’s cheap, but requires a good connection and a static IP address (or some shenanigans like <a href="https://www.howtogeek.com/866573/what-is-dynamic-dns-ddns-and-how-do-you-set-it-up/">dynamic DNS</a>) and dealing with the physical aspects of a server. Currently I only use it for home automation stuff (which I run on a Raspberry Pi, which is silent and has modest space and power requirements). Can be fun to do for a while, but may become a chore, and I have enough of those at home.</p>
  </li>
  <li>
    <p><strong>Platform-specific solutions</strong>: There are many services that allow you to host a project written in a specific technology (Java Web Applications and PHP-based sites come to mind); you just configure some things, drop your files there and your app is visible to the world. They are free/cheap for small projects, but can get expensive as things grow. I’ve used some of those in the past, but they don’t fit the things I do nowadays (and are unlikely to fit new projects for anyone, as they are a bit out of fashion).</p>
  </li>
  <li>
    <p><strong>Serverless</strong>: Instead of running a server, people that choose this route use a service that runs code on demand. I am skeptical of those in professional settings (where you can at least justify the gymnastics with the cost flexibility), but for personal projects it’s just too much hassle (and often $) for too little benefit (unless your chosen tooling is already serverless).</p>
  </li>
  <li>
    <p><strong>Dedicated servers</strong>: They are reliable, but buying or renting them is too expensive for personal projects, in particular because they will be underused - unless you intend to build your own personal cloud, but that isn’t my case.</p>
  </li>
  <li>
    <p><strong>Containers</strong>: As mentioned above, you can build your app with the likes of Docker and Kubernetes, and run it on a cloud provider. It is a good option for professional projects (and I particularly love the “<a href="https://devops.stackexchange.com/questions/653/what-is-the-definition-of-cattle-not-pets">cattle, not pets</a>” approach), but it is overkill for personal ones, and it is a bit more expensive than the option below.</p>
  </li>
  <li>
    <p><strong>Virtual private servers</strong>: On those, you rent a virtual machine (VM) from a provider. Like a dedicated server, you manage it yourself, but it is much cheaper (because you are sharing the hardware with other users). It is what I use for most of my projects, and I’ll detail it below.</p>
  </li>
</ul>

<p>There are many VPS providers around, and it is tempting to go with the likes of Amazon Web Services (AWS) or Microsoft Azure, but they are overkill for personal projects. My VPS provider of choice is <a href="https://www.digitalocean.com/">DigitalOcean</a> - besides the reliability and great tooling, they charge a fixed monthly rate for each “droplet” (their VMs) - which is important since any project may have an unexpected surge, and I’m not a startup that converts engagement into VC money.</p>

<p>It supports several Linux distributions and you can even supply your own, I suppose. I personally prefer <a href="https://ubuntu.com/download/server">Ubuntu Server</a>, as it builds upon the robustness, stability and familiarity of Debian but puts practicality above purity (e.g., by including non-free drivers and codecs by default). I use the <a href="https://ubuntu.com/about/release-cycle">long-term support (LTS)</a> versions, so I can stay a few years just adding security patches, and rebuild the server from scratch when support ends or I need something from the newer versions - sounds radical, but is actually easy to do (more on that below).</p>

<h3 id="domain-names-and-https">Domain names and HTTPS</h3>

<p>In theory, you can just access the server’s by typing its IP address on the browser (or client tool), but if you want to show it to others, it is <em>much</em> nicer to have a domain name. Some people like to register a domain for each hobby project (and for a few, registering domain names <em>is</em> the hobby project). A more suitable route IMHO is to register a single domain (that represents you) and <a href="https://hostadvice.com/blog/domains/wildcard-subdomain/">use subdomains</a> for the projects, which is what I do nowadays: I registered <code class="language-plaintext highlighter-rouge">chester.me</code>, and use the likes of <code class="language-plaintext highlighter-rouge">totransit.chester.me</code>, <code class="language-plaintext highlighter-rouge">minitruco.chester.me</code>, etc, for my projects.</p>

<p>A registrar is the company or entity that will register the domain name for you. Which one to choose depends on the domain-suffix, but my general go-to is <a href="https://www.dynadot.com/">Dynadot</a>, which is reasonably priced and has a nice user interface that allows you to easily direct all access to the server, or even fancier setups. For example, I pointed <code class="language-plaintext highlighter-rouge">chester.me</code> DNS entries to GitHub Pages, which hosts the blog you are reading right now, and all the subdomains to go to my DigitalOcean droplet.</p>

<p>Another reason to keep all your things on a single top-level domain is that it makes it easier to set up <a href="https://www.cloudflare.com/en-ca/learning/ssl/what-is-https/">encryption (https)</a>, which requires a <a href="https://www.cloudflare.com/en-ca/learning/ssl/what-is-an-ssl-certificate/">certificate</a> for each domain. Having a single one, you can get a wildcard certificate for it, and use it for all subdomains (instead of registering a new one for each new project). You can and should get a free one from <a href="https://letsencrypt.org/">Let’s Encrypt</a> and use it with <a href="https://certbot.eff.org/">Certbot</a>, which automates the process of getting and renewing the certificates.</p>

<h3 id="joining-to-conquer">Joining to conquer</h3>

<p>Even with a cost-effective VPS, it is tempting to just go creating one server for each project, but that will become expensive pretty quickly, and here comes the main point of my personal project hosting strategy: <strong>I host them all on a single (virtual) server</strong>. Doing so allows me to share system resources, bandwidth and storage between projects (reducing the cost), and I can always split one of them to a new server if it grows too much or misbehaves.</p>

<p>The trick is to just configure them all on the same machine, each on a separate process (tree). Doing so is trivial for services that run on different ports, but even for those that run on the same port, I use <a href="https://nginx.org/en/">nginx</a> as a reverse proxy to route requests to the right app.</p>

<p>For example, I have two apps that run internally on ports 3000 and 3001 (but you can’t reach those ports externally, see the Security part below). Each of them has its own domain name, so it’s easy to set up nginx to listen on the default web port (80) and route requests to the right app. For example, the configuration for one of the apps looks like this:</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># /etc/nginx/sites-available/cruzalinhas.com</span>

<span class="c1"># Define a new upstream server, which is the app running on port 3000</span>
<span class="k">upstream</span> <span class="s">cruzalinhas_rails</span> <span class="p">{</span> <span class="kn">server</span> <span class="nf">127.0.0.1</span><span class="p">:</span><span class="mi">3000</span><span class="p">;</span> <span class="p">}</span>

<span class="c1"># Requests to cruzalinhas.com...</span>
<span class="k">server_name</span> <span class="s">cruzalinhas.com</span><span class="p">;</span>

<span class="k">server</span> <span class="p">{</span>

  <span class="c1"># ...are forwarded to the upstream server defined above</span>
  <span class="kn">location</span> <span class="p">~</span> <span class="sr">.*</span> <span class="p">{</span>
      <span class="kn">proxy_pass</span> <span class="s">http://cruzalinhas_rails</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Other niceties that nginx provides are SSL termination (so you can have your apps “speak” plain HTTP, and it converts the incoming HTTPS requests from port 443 to HTTP requests to the upstream server), and the ability to serve static files (e.g., static HTML, images, video) directly, without having to go through the app. The <a href="https://nginx.org/en/docs/">docs</a> show how to do it, but as you will see below, I use Ansible to automate most of those configs.</p>

<p>In order to keep those services alive, I use <a href="http://supervisord.org/">Supervisor</a>, a very configurable tool that allows you to start and stop your different projects, monitoring their processes and auto-(re)starting any of them as needed.</p>

<h3 id="squeezing-the-most-out-of-a-single-server-swapfile">Squeezing the most out of a single server: swapfile</h3>

<p>The cheapest DigitalOcean droplets provide more than enough disk space and transfer bandwidth for my projects, but the memory is a bit tight. I could just upgrade to a more expensive droplet, but I found a better solution: a <a href="https://www.digitalocean.com/community/tutorials/how-to-add-swap-space-on-ubuntu-20-04">swapfile</a>.</p>

<p>Usually sysadmins cringe at the idea of swap files on servers - I worked at places where they were forbidden, or where swap activity above a certain threshold would page the on-call person! For personal projects like mine, the server sits still most of the time, and the actual <a href="https://en.wikipedia.org/wiki/Working_set">working set</a> of used RAM is much smaller than the allocated RAM, so it’s 100% ok to let the allocated-but-unused pages swap out. On top of that, the “disk” is actually an SSD, so even if some swap activity happens, the performance hit isn’t that bad, if perceptible at all.</p>

<p>You can start with the cheapest droplet, install your things and check <code class="language-plaintext highlighter-rouge">htop</code> to see how much physical memory is being used. If it is close to the limit, upgrade to the next tier (which is a matter of a few clicks on DigitalOcean’s web interface), rinse, repeat. I have all my current projects (two active Rails apps and one Java multiplayer game server back-end) running their second-cheapest droplet, which has 1GB of RAM. It has a 2GB swapfile, rarely used above 10% and no <a href="https://en.wikipedia.org/wiki/Thrashing_(computer_science)">thrashing</a> observed.</p>

<h3 id="automated-provisioning">Automated Provisioning</h3>

<p>Sure, you can manually set up your server (and in fact you should do that every now and then for learning purposes, IMHO), but doing so it is not a good idea for a production environment: you may want to move to a different provider, or the server may crash and you’ll need to set it up again, or you may want to split a project that grew too much into its own server… any of those things will require you to reconfigure from the start, and it’s very likely that you will forget something.</p>

<p>One way of doing so is to have a shell script that contains all the commands you’d typically run to set up a server. That is better than nothing (and I’ve seen some startups doing that), but it has a few drawbacks: you need to handle secrets (e.g., passwords, API keys); if the config need changes, you need to manually reconfigure and keep the script updated (and likely can’t run again on a production server); it gets complicated with different profiles (e.g., development vs production, or different apps); and so on.</p>

<p>A better approach is to use a tool that allows you to describe your server’s configuration in a file, and then run that tool to set up the server. There are many tools for that, but I use <a href="https://www.ansible.com/">Ansible</a>. It is free and open-source, does not require installing anything on the server (it just needs SSH access), and is very flexible.</p>

<p>Ansible’s central idea is that you describe your server’s desired state in a YAML file containing all the configuration steps - this file is called a “playbook”. A playbook can be written to be <em>idempotent</em>, that is, it can be run multiple times on an existing server, and it will only change what needs to be changed.</p>

<p>Most important: those configuration steps are not unlike the commands you’d manually issue (they are only wrapped in so-called “tasks”, which automate all that checking). Even if there isn’t a task for a given command, you can always run a shell command directly (as long as you ensure it is idempotent, as described above).</p>

<p>For example, my server has a <a href="https://github.com/chesterbr/chester-ansible-configs/blob/8cb0146dfffedc6c0136976f58d85bd5d87b6ee9/provisioning.yml"><code class="language-plaintext highlighter-rouge">provisioning.yml</code></a> playbook that <a href="https://github.com/chesterbr/chester-ansible-configs/blob/main/roles/chesterbr.user_setup/tasks/main.yml">sets up the necessary Unix users</a> (both mine for manual ssh-ing, and the ones needed by application servers), <a href="https://github.com/chesterbr/chester-ansible-configs/blob/main/roles/chesterbr.security/tasks/main.yml">tightens the security</a> of the server and does some <a href="https://github.com/chesterbr/chester-ansible-configs/blob/main/roles/chesterbr.swapfile/tasks/main.yml">additional configuration</a>.</p>

<p>It also has one playbook for each specific project (e.g., <a href="https://github.com/chesterbr/chester-ansible-configs/blob/main/cruzalinhas.yml">this one</a> that sets up a Ruby on Rails app, which installs the necessary packages, sets up the database, installs the app, and so on). Sure, right now all my apps run on the same server, but if I ever need to split one of them, I can just provision the new server and run the playbook for the new app.</p>

<p>The best thing is that spinning a new server is easy and non-disruptive. For example, when I want to upgrade Ubuntu to a new version (usually a risky operation in any operating system or distribution), I just create a new droplet on DigitalOcean and run the playbooks on it. Then I edit my local <code class="language-plaintext highlighter-rouge">/etc/hosts</code> file and point all subdomains to the new server’s IP (from the point of view of my computer) and test it. Once I’m sure it’s working fine, I revert that edit, flip the DNS to the new server and destroy the old one.</p>

<h3 id="app-deployment">App deployment</h3>

<p>Each tech stack has its own way of deploying and redeploying apps; quite a few have more than one blessed way. You have to consider things like how much downtime your project can tolerate between deploys; whether you need to preserve any state (data, connections) between deploys, and so on.</p>

<p>For personal projects, I try to make the simplest possible thing that works. For example, most of my Rails-based apps just update the code on the server straight from GitHub (the existing instance won’t be affected by that, as the code is already loaded and production configs don’t auto-reload) and restart it.</p>

<p>For the game server, I needed to do a more complex <a href="https://github.com/chesterbr/minitruco-android/blob/d5fee6c0b5c6c194e670ad3a7ad82cfbc055e764/launcher.sh">script</a> that starts the server software, then monitors its <code class="language-plaintext highlighter-rouge">.jar</code> file for changes. When it happens, the script instructs the running server to stop responding to connections, and immediately start another process with the new version (which accepts all new connections). Meanwhile, the old server drops any player that isn’t currently on a game until no one is left, then finishes itself. In practice, that gives everyone the opportunity to finish their games, while anyone not in a game just connects to the new server, with no downtime or interrupted games.</p>

<h3 id="security">Security</h3>

<p>When you manage your own server, it’s important to keep it secure. There are many things you can do, but here are some of the most important ones:</p>

<ul>
  <li>Disable root login and password authentication for any user (they should always use SSH keys);</li>
  <li>Configure some form of auto-update (Debian/Ubuntu have <code class="language-plaintext highlighter-rouge">unattended-upgrades</code>, but you need to configure it to actually apply the updates; I recommend just focusing on security ones here, and manually update playbooks or rebuild the server on a new OS version for everything else);</li>
  <li>Enable a software firewall (I recommend <code class="language-plaintext highlighter-rouge">ufw</code>, which is a friendly wrapper for Linux’ built-in packet filtering), only allowing inbound traffic on the necessary ports. My provisioning playbook opens ports 22 (SSH), 80 (HTTP) and 443 (HTTPS), and any app that needs a different port will have that configured in its own playbook;</li>
  <li>Add additional security software. I like <code class="language-plaintext highlighter-rouge">fail2ban</code>, which automatically blocks IPs that try to brute-force SSH or HTTP logins by using the same firewall structure managed by <code class="language-plaintext highlighter-rouge">ufw</code>, thus adding no additional load to the server.</li>
</ul>

<p>You can see these configs on the <a href="https://github.com/chesterbr/chester-ansible-configs/blob/8cb0146dfffedc6c0136976f58d85bd5d87b6ee9/roles/chesterbr.security/tasks/main.yml">security part</a> of my provisioning setup.</p>

<p>Keep in mind your apps’ needs (for example, when opening the port used by my multiplayer game server on <code class="language-plaintext highlighter-rouge">ufw</code>, I also had to <a href="https://github.com/chesterbr/chester-ansible-configs/blob/8cb0146dfffedc6c0136976f58d85bd5d87b6ee9/minitruco.yml#L46-L55">increase</a> <code class="language-plaintext highlighter-rouge">fail2ban</code>’s allowance for multiple connections from the same IP, because it is reasonable that friends playing together may be using the same Wi-Fi network and have the same external IP). Always go with closed stuff by default, and opening on a case-by-case basis.</p>

<p>If you tighten it enough, the next vector for security issues will be… your own code! Aside from the usual security best practices (e.g., sanitizing user input), you should also keep your dependencies up to date. Keeping the code on <a href="https://github.com/">GitHub</a> allows <a href="https://docs.github.com/en/code-security/dependabot">Dependabot</a> to check for that in supported languages (and even suggest updates), and the tooling there will also monitor for leaked secrets (e.g., API keys) and alert you if it finds any. As a former GitHub employee I may be biased, but I can’t recommend it enough.</p>

<h3 id="keeping-your-server-alive">Keeping your server alive</h3>

<p>It isn’t a home banking system, yet you want the service to stay alive when you sleep. I already mentioned Supervisor above, but other small things worth considering are:</p>

<ul>
  <li><strong>Log rotation</strong>: You don’t want your server to run out of disk space because of logs. I use <code class="language-plaintext highlighter-rouge">logrotate</code> to avoid that; it has sensible defaults but is easy to <a href="https://github.com/chesterbr/chester-ansible-configs/blob/8cb0146dfffedc6c0136976f58d85bd5d87b6ee9/templates/minitruco_logrotate.conf.j2">customize</a>.</li>
  <li><strong>Monitoring</strong>: This is one I haven’t done as well lately, but it’s a good idea to have. For webservers, a good idea is to add an endpoint that does whatever basic checks you think reasonable (e.g., get something from the database) and responds with, say an “OK”, then have a service call it every few minutes and alert you when it doesn’t respond. <a href="https://uptimerobot.com/">UptimeRobot</a> offers free checks every 5 minutes, which should be enough for a personal project.</li>
</ul>

<h3 id="user-data">User data</h3>

<p>Honestly, having any sort of persistent data in a personal project is a hassle - both from a technical perspective (you have to back it up, you have to take it with you when you rebuild your server, etc.) and from a legal perspective (you have to comply with privacy laws, etc.). It’s ok to have persisted data, as long as you can easily rebuild and start anew.</p>

<p>If you really need a database for important data, consider those operations when choosing. For example, SQLite is easy to back up (it’s just a file) <em>if</em> you can stop the server - or at least writes - during backups (otherwise you risk copying a corrupt backup); MySQL has more backup options, but you need to set them up. An external service like Amazon RDS or DigitalOcean’s Managed Databases may be a good idea, but it will add to the cost.</p>

<p>Whatever you choose, make sure you restore the backups when provisioning a new server, and <strong>test the backups</strong> from time to time, not only when you need them. In fact, if you restore when provisioning, a good (and cheap) test is to just provision a new server and see if the data is there. The only caveat is that once you confirm it is fine, users may have written new data to the soon-to-become old server, so you’ll likely need some downtime to make a new backup/restore cycle… as I said, avoid this at all costs!</p>

<h3 id="secrets-and-non-secrets">Secrets (and non-secrets)</h3>

<p>My server configuration is <a href="https://github.com/chesterbr/chester-ansible-configs">published on GitHub</a>. It may sound reckless, but <a href="https://en.wikipedia.org/wiki/Security_through_obscurity">good security should never be done by obscurity</a>; instead, it gives the good guys a chance to alert me about bad practices, while not showing much that the bad guys couldn’t find out by themselves. Please check it for details on the techniques I describe here.</p>

<p>Things that should actually be kept secret can be stored in <a href="https://docs.ansible.com/ansible/latest/user_guide/vault.html">Ansible Vault</a>, which encrypts them with a password that you supply when running the playbooks, or in some service like <a href="https://docs.github.com/en/actions/reference/encrypted-secrets">GitHub Secrets</a>, that are only visible to the repository owner (but they require some GitHub Actions gymnastics for provisioning into a server, which is why I currently stay with Ansible Vault).</p>

<h3 id="final-thought">Final thought</h3>

<p>This isn’t a universal guide on how to host personal projects - but rather a description of how have been doing it (which I may update as I find or remember other interesting things), and how other people can do it too. The dynamics of hosting change all the time; the main thing is to design and iterate around them, automating just enough so that you don’t need to keep an eye on it. That’s what worked for me so far!</p>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Unlocking a dumb electric lock via Home Assistant (+ ESPHome + ESP8266)]]></title>
    <link href="https://chester.me/archives/2022/12/updating-dumb-electric-lock-home-assistant-esphome-sp8266/"/>
    <updated>2022-12-15T00:00:00+00:00</updated>
    <id>https://chester.me/archives/2022/12/updating-dumb-electric-lock-home-assistant-esphome-sp8266</id>
    <content type="html"><![CDATA[<p>In the <a href="2022-10-29-making-an-old-school-dorbell-ring-on-telegram-home-assistant.md">last post</a> I described how I used an <a href="https://makersportal.com/blog/2019/6/12/wemos-d1-mini-esp8266-arduino-wifi-board">ESP8266 board</a> to detect when my ancient doorbell rings, and trigger a notification on my phone. This time, I’m going to use the same board and a relay to unlock the front door, which, combined with the ring detection, will allow me to get deliveries past the front door, open it for visitors, and even unlock both that door and the internal one (which already has a smart lock) when I arrive home!</p>

<p><img src="/img/2022/12/esp-and-relay-shield.jpg" alt="ESP8266 and relay shield" class="center" /></p>

<!--more-->

<h3 id="relay-circuit-vs-relay-shield">Relay Circuit vs Relay Shield</h3>

<p>My front door is as old school as my doorbell: just an electric lock downstairs, and a button inside my house that opens it. The voltage/current there is certainly out of of what an ESP8266 GPIO pin can handle, so the solution is to connect a relay to it.</p>

<p>I usually prefer discrete circuits over “<a href="https://www.youtube.com/watch?v=KeCN4t79vdM">shields</a>” (boards that go over an Arduino/Raspberry Pi/etc.) because they are simpler, cheaper and more fun/educational to build; but I found an <a href="https://www.amazon.ca/gp/product/B0B3HF1DTN/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&amp;tag=raquelcamar0e-20&amp;th=1">inexpensive and convenient shield</a> containing the relay and all needed electronics.</p>

<p>I measured the current/voltage when the button was pressed, but forgot to write it down for the post. But it was well within what the relay shield can handle.</p>

<p>There isn’t any schematics this time: just soldered the shield pins over the ESP pins. The relay has three pins: the common (C), the normally closed (NC) and the normally open (NO). In order to “press” the wall unlock button with the relay, we have to connect the C and NO pins to its terminals. But before that…</p>

<h3 id="software">Software</h3>

<p>It’s easier to test before you stick things to the wall. Once again I used <a href="https://esphome.io/">ESPHome</a> within <a href="[https://](https://www.home-assistant.io/)">Home Assistant</a>. This time we want to present the relay as a push button, so something like this does the job:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">switch</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="na">platform</span><span class="pi">:</span> <span class="s">gpio</span>
    <span class="na">name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Front</span><span class="nv"> </span><span class="s">door"</span>
    <span class="na">id</span><span class="pi">:</span> <span class="s2">"</span><span class="s">front_door"</span>
    <span class="na">pin</span><span class="pi">:</span> <span class="s">GPIO5</span>
    <span class="na">on_turn_on</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">delay</span><span class="pi">:</span> <span class="s">4s</span>
    <span class="pi">-</span> <span class="na">switch.turn_off</span><span class="pi">:</span> <span class="s">front_door</span>
    <span class="na">icon</span><span class="pi">:</span> <span class="s2">"</span><span class="s">mdi:door"</span>
</code></pre></div></div>

<p>The relay is configured by GPIO5 pin, and the <code class="language-plaintext highlighter-rouge">on_turn_on</code> section is what makes it behave as a push button: it doesn’t matter what turns it on in Home Assistant (user interface, automations, etc), it will turn itself off automatically after the specified interval (4 seconds). During that time, the electric lock buzzes, signaling the visitor that they can enter.</p>

<h3 id="putting-it-on-the-wall">Putting it on the wall</h3>

<p><img src="/img/2022/12/ui.png" alt="UI button" class="right" />
Once you write ESPHome to the board with the configuration above, you can add that switch to any card on the “Overview” page (if your Home Assistant isn’t set up to automatically add new switches). When you click/touch the virtual button to turn it on, you should hear a “click” on the relay, and, after 4s, another “click” as the virtual button returns to the “off” position.</p>

<p>Using the conductivity test on a multimeter, double-check that the “NC” and middle pin only connect when the button is pressed. Those pins are the ones you should connect to the doorbell button, without disconnecting the wires already there (so the manual button continues to work).</p>

<p><img src="/img/2022/12/on-the-wall.jpg" alt="on the wall" class="center" /></p>

<p>There was plenty of space on the wall for the ESP8266 and the relay shield, so I just stuck them there, wrapping all the metal parts with electrical tape to avoid short circuits. Could use a case, but that was good enough.</p>

<p>You’ll need to supply power to the ESP8266. This time I didn’t have an outlet nearby, but there was some leftover coaxial cable from the older cable installation (the landlord even offered to remove that cabling, since the current provider comes from a different place altogether). It isn’t the most appropriate cable for USB power, but it is already there, and it works.</p>

<h3 id="automations">Automations</h3>

<p>Now the sky is the limit. I could, for example, just unlock the door from any automation by adding an action like this (no need to turn the switch off, as the configuration above does that automatically):</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">action</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="na">service</span><span class="pi">:</span> <span class="s">switch.turn_on</span>
    <span class="na">target</span><span class="pi">:</span>
      <span class="na">entity_id</span><span class="pi">:</span> <span class="s">switch.porta_da_casa</span>
</code></pre></div></div>

<p>I actually did a more complex setup: since I also have a smart lock controlled by Home Assistant on the internal door, I created an “I’m home” button on the UI that unlocks both the front and the internal door (which can even be linked to Siri/Google Assistant/etc. so I can just say “Hey Siri, I’m Home” and enter).</p>

<p>I’ve also created an “incoming delivery” switch that I can turn on when I’m expecting a delivery, and it will unlock just the front door when the doorbell rings (but only during daytime):</p>

<p><img src="/img/2022/12/automation.png" alt="automation" class="center" /></p>

<p>I’m considering to hook this <a href="https://github.com/moralmunky/Home-Assistant-Mail-And-Packages">Mail and Packages Integration</a> to automatically turn on that switch in days I’m expecting a delivery, but I first need to ensure it works with the emails sent by Canadian retailers. In any case, this setup is pretty robust and easy to customize, all done for a ridiculously low price. I’m pretty happy with it!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Making an old-school doorbell "ring" on Telegram (via Home Assistant + ESPHome + ESP8266)]]></title>
    <link href="https://chester.me/archives/2022/10/making-an-old-school-dorbell-ring-on-telegram-home-assistant/"/>
    <updated>2022-10-29T00:00:00+00:00</updated>
    <id>https://chester.me/archives/2022/10/making-an-old-school-dorbell-ring-on-telegram-home-assistant</id>
    <content type="html"><![CDATA[<p>After years of living in single-room condos, we decided to try a more spacious, two-store house, which has a very old and low-tech doorbell: a button on the door triggers a “ding-dong” classic doorbell - very easy to miss if you are on the upper floor, causing all sorts of issues with deliveries.</p>

<p>Sure, I could make it ring louder, but it would be annoying for anyone on the lower floor. And I also want to automate other hurdles related to package delivery, so I decided to first get the  doorbell to ring into my <a href="https://www.home-assistant.io/">Home Assistant</a> setup (where I can trigger all sorts of automations).</p>

<!--more-->

<h3 id="acϟdc-">ACϟDC 🤘</h3>

<p>The easiest thing would be to replace the front door pushbutton with a four-contact one (so it would close the doorbell circuit and mine); but this being a rental discourages me from doing outdoors modifications; instead I got my trusty multimeter to pry into the doorbell, and found that when the doorbell rings, a ~12V AC current flows through the exposed contacts.</p>

<p>That kind of signal isn’t good to trigger my home automation stuff, which usually relies on Arduino/Raspberry Pi/etc. GPIO pins (which operate on lower voltages and DC current). But the internet is wonderful - I found a <a href="https://forum.arduino.cc/t/sensing-12v/202885/3">circuit</a> that <em>pulls down</em> (that is, connects to GND) a GPIO pin whenever a 12V AC current is present. Here is a reproduction:</p>

<p><img src="/img/2022/10/ring_circuit.png" alt="circuit" class="center" /></p>

<p>As usual, I’m learning the basics of the electronics involved. This time the big mystery was the AC-&gt;DC conversion. What I understood/learned is that:</p>

<ul>
  <li>The “+” and “-“ refer to the polarity of one of the phases of the alternating current (AC) present when the doorbell is ringing;</li>
  <li>The capacitor charges up during that phase;</li>
  <li>When the current flips, the diode prevents it from flowing, while the capacitor discharges, resulting in a same-polarity, direct current (DC) flow.</li>
</ul>

<p>The other new thing was the opto-coupler - a tiny chip that contains an LED and a photo-sensitive transistor. Feeding the (now) DC current to the LED closes the transistor, which is a smart way to pull down the GPIO pin while keeping the ESP8266 100% isolated from the doorbell. 🏆</p>

<h3 id="try-before-you-buy">Try before you buy</h3>

<p>Before progressing further, I decided to test the circuit above on a breadboard, using an Arduino and a slightly modified version of the <code class="language-plaintext highlighter-rouge">02-Digital/Button</code> example that comes with the Arduino IDE that pulls up the pin and flips the built-in LED when it is pulled down, that is, when the doorbell rings:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">setup</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">pinMode</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="n">INPUT_PULLUP</span><span class="p">);</span>
  <span class="n">pinMode</span><span class="p">(</span><span class="mi">13</span><span class="p">,</span> <span class="n">OUTPUT</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">loop</span><span class="p">()</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="n">sensorVal</span> <span class="o">=</span> <span class="n">digitalRead</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span>
  <span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="n">sensorVal</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">sensorVal</span> <span class="o">==</span> <span class="n">HIGH</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">digitalWrite</span><span class="p">(</span><span class="mi">13</span><span class="p">,</span> <span class="n">HIGH</span><span class="p">);</span>
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="n">digitalWrite</span><span class="p">(</span><span class="mi">13</span><span class="p">,</span> <span class="n">LOW</span><span class="p">);</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="wemos-d1-mini-and-esphome">Wemos D1 Mini and ESPHome</h3>

<p>I could connect that circuit to the Raspberry Pi 3B+ that runs my Home Assistant, but, as I said, it’s a big house, so I got a <a href="https://makersportal.com/blog/2019/6/12/wemos-d1-mini-esp8266-arduino-wifi-board">WeMos D1 Mini</a> - a cheap and tiny ESP8266-based board that, in short, behaves like an Arduino with built-in Wi-Fi.</p>

<p><a href="https://chester.me/archives/2019/07/cheap-433mhz-leak-detectors-home-assistant-arduino-openmqttgateway-telegram-alerts/">In the past</a> I used the <a href="https://github.com/1technophile/OpenMQTTGateway">OpenMQTTGateway</a> software to turn such boards into sensors and triggers. But as much as I love the community around that software, its source-code-based approach and reliance on MQTT makes it quite hard to set up and update.</p>

<p>Enter <a href="https://esphome.io/">ESPHome</a>, which is focused on Home Assistant and thus <em>much</em> easier to work with: you just configure what your sensor needs to do in a tiny YAML file straight from Home Assistant; it builds the firmware and updates it (wirelessly and very securely once you set up the first time via USB).</p>

<h3 id="building-for-real-now">Building for real now</h3>

<p><img src="/img/2022/10/ring_perfboard.png" alt="perfboard" class="right" />
 I know, I know: all the cool kids either make their own PCBs, or design them and use one of the small-volume PCB services that sponsor half of the YouTube electronics videos. Not wanting to deal with the chemicals and iterate quickly, I went to my custom solution of cutting a piece of perfboard and doing the connections with solder and, when needed, jumpers.</p>

<p>After botching a first attempt (in which I just threw the components at Fritzing’s Breadboard view), I realized I could reproduce the circuit on the Schematic view, and get all the components connected on the Breadboard view, where I could just lay them out on a perfboard (“Stripboard” component) and figure the needed solder/jumper points, error-free - not unlike people use the PCB view to design their boards, I suppose.</p>

<p>I used a white 5V USB charger to power the boards, sticking them with mount tape to the side of the charger (which will be facing down and thus invisible when plugged in):</p>

<p><img src="/img/2022/10/all-together.jpg" alt="all together" class="center" /></p>

<p>A pair of white wires connects this to the doorbell. It’s not the most finished setup, but it is discreet enough to be ignored (in particular because there are several other white cables running over those walls) and easy to remove when I return this rental.</p>

<p>Here is the link to download the <a href="/img/2022/10/ring-detection.fzz">Fritzing (.fzz) schematics</a>:</p>

<h3 id="making-it-sing">Making it sing</h3>

<p>Using the code above we can check the doorbell state on the ESP8266 LED, but what we really want is to have it available on Home Assistant via ESPHome. The easiest way is to do it <a href="https://esphome.io/guides/getting_started_hassio.html">directly from Home Assistant</a>, but that requires:</p>

<ul>
  <li>A <a href="https://caniuse.com/web-serial">browser that supports web serial api</a> (e.g. Chrome); and</li>
  <li>Enough RAM on your Raspberry Pi to build the firmware (my 3B+ has 1GB, which should be enough, but was failing to build until I reinstalled Home Assistant and started fresh - something I wanted to do for a while, since I’ve hacked that instance a lot in the last years).</li>
</ul>

<p>The specific config that allowed me to get the doorbell state on Home Assistant is:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">binary_sensor</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="na">platform</span><span class="pi">:</span> <span class="s">gpio</span>
    <span class="na">name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">doorbell"</span>
    <span class="na">pin</span><span class="pi">:</span>
      <span class="na">number</span><span class="pi">:</span> <span class="m">2</span>
      <span class="na">inverted</span><span class="pi">:</span> <span class="no">true</span>
      <span class="na">mode</span><span class="pi">:</span>
        <span class="na">input</span><span class="pi">:</span> <span class="no">true</span>
        <span class="na">pullup</span><span class="pi">:</span> <span class="no">true</span>
</code></pre></div></div>

<p>It’s pretty straightforward: we’re using the GPIO pin 2, which is the one we connected to the opto-coupler output, and we’re telling ESPHome to treat it as a binary sensor (i.e. a switch that can be either on or off). The <code class="language-plaintext highlighter-rouge">inverted: true</code> is needed because the opto-coupler is pulling down the pin when the doorbell rings, and we want the sensor to be on when the doorbell rings.</p>

<p>Once that configuration is built and installed, we can add/see the sensor on Home Assistant’s dashboard:</p>

<p><img src="/img/2022/10/doorbell-ha.jpg" alt="dashboard" class="center" /></p>

<p>I already had the Telegram bot set up (from this other <a href="/archives/2019/07/cheap-433mhz-leak-detectors-home-assistant-arduino-openmqttgateway-telegram-alerts/">post</a>), so I just created an automation whose trigger is the doorbell sensor changing from “off” to “on” and whose action is to send a message to my Telegram bot.</p>

<p>I did it mostly on the web UI, resulting in something like this:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">alias</span><span class="pi">:</span> <span class="s">Send Telegram message when doorbell rings</span>
<span class="na">description</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
<span class="na">trigger</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="na">platform</span><span class="pi">:</span> <span class="s">state</span>
    <span class="na">entity_id</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">binary_sensor.doorbell</span>
    <span class="na">from</span><span class="pi">:</span> <span class="s2">"</span><span class="s">off"</span>
    <span class="na">to</span><span class="pi">:</span> <span class="s2">"</span><span class="s">on"</span>
<span class="na">condition</span><span class="pi">:</span> <span class="pi">[]</span>
<span class="na">action</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="na">service</span><span class="pi">:</span> <span class="s">telegram_bot.send_message</span>
    <span class="na">data</span><span class="pi">:</span>
      <span class="na">message</span><span class="pi">:</span> <span class="s">🔔 Ding dong</span>
      <span class="na">target</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="m">11111111</span>
        <span class="pi">-</span> <span class="m">22222222</span>
        <span class="pi">-</span> <span class="s">....</span>
<span class="na">mode</span><span class="pi">:</span> <span class="s">single</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">target:</code>s should be the ID(s) of the user(s) to which the bot will send messages. To get the numeric ID of a Telegram user, you can <a href="https://t.me/GetIDsBot">start a chat</a> with GetIDsBot (<a href="https://github.com/wjclub/telegram-bot-getids">source</a>).</p>

<p>Now when someone rings my doorbell, I get a message:</p>

<p><img src="/img/2022/10/telegram.png" alt="telegram" class="center" /></p>

<h3 id="next-steps">Next steps</h3>

<p>As seen above, I often get more than one message; which means that either people are a bit nervous, or I need to set up some debouncing; fortunately ESPHome has <a href="https://esphome.io/components/binary_sensor/gpio.html#debouncing-values">options</a> for that.</p>

<p>I also want to figure out a way to check who is on the door (maybe snapping a picture from a security camera and sending it alongside the message), and the icing on the cake would be to open the door (e.g., by interacting with the robot).</p>

<p>Not sure if I’ll do all that (depends on how long I’ll stay on this house), but if I do, it will mean no more packages will be returned or stolen because I wasn’t there to receive them.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Got an NFC/RFID chip implanted in my hand]]></title>
    <link href="https://chester.me/archives/2022/02/got-an-rfid-nfc-chip-implanted/"/>
    <updated>2022-02-26T00:00:00+00:00</updated>
    <id>https://chester.me/archives/2022/02/got-an-rfid-nfc-chip-implanted</id>
    <content type="html"><![CDATA[<h3 id="rfid--nfc--next-implant">RFID + NFC = NExT implant</h3>

<p><a href="https://en.wikipedia.org/wiki/Near-field_communication">NFC</a> (the tech used in mobile phones for contactless payments and contact exchanges) and <a href="https://en.wikipedia.org/wiki/Radio-frequency_identification">RFID</a> (used in product identification/tracking, building access cards and <a href="https://internetofthingsagenda.techtarget.com/definition/RFID-radio-frequency-identification">many other things</a>) are found everywhere these days. I played a little bit with <a href="https://www.amazon.ca/gp/product/B088QW9274/ref=ppx_yo_dt_b_asin_title_o08_s00?ie=UTF8&amp;psc=1">cheap tags</a> that can be used to interact with phones, but implants are getting more practical, so I decided to give one of them a go!</p>

<p><em>(I know, I know: technically, NFC “is” RFID - or, specifically, is a set of protocols built upon a subset of the RFID ones, but I’m going with the commonplace usage of the terms: “RFID” for the unregulated “low frequency” 120-150 kHz tags that use all sorts of proprietary protocols, “NFC” for the “high frequency” 13.56 Mhz devices using specifically NFC)</em></p>

<p>I didn’t want to limit myself to a single technology (or to go with two implants), but <a href="https://dangerousthings.com/">Dangerous Things</a> (yes, that’s the company name 😅) sells the <a href="https://dangerousthings.com/product/next/">NExT</a>: an implant with both an <a href="https://github.com/RfidResearchGroup/proxmark3/blob/master/doc/T5577_Guide.md#t5577-overview">RFID chip</a> (that can simulate - or “clone” - fobs and tags on the wild) and an <a href="https://www.nxp.com/products/rfid-nfc/nfc-hf/ntag-for-tags-labels/ntag-213-215-216-nfc-forum-type-2-tag-compliant-ic-with-144-504-888-bytes-user-memory:NTAG213_215_216">NFC chip</a> (which can store 888 bytes of data, accessible to any NFC reader I touch, including smartphones).</p>

<p><img src="/img/2022/02/needle_and_specs.jpg" alt="The contraption used to inject it (after the fact) and some specs" class="center" /></p>

<p>There are some limitations: its NFC can’t be used for payments (like, for example, the <a href="https://dangerousthings.com/product/walletmor/">Walletmor</a>), and the RFID can’t emulate super advanced security, or hold multiple tags, but the combination is enough for a lot of uses, plus it’s a field-tested set of chips that should be operational for years and years, so I chose it.</p>

<!--more-->

<h3 id="the-implant-process">The implant process</h3>

<p>Now that I knew what implant I wanted, the issue was how to get it implanted. Being quite afraid of something going wrong, I would prefer to get a physician to do it, but I didn’t feel like bothering my family doctor with an elective procedure during a pandemic.</p>

<p>After some digging, I found the <a href="https://dangerousthings.com/partners/">installation partners</a> section on the Dangerous Things website, which led me to <a href="https://www.midwaytattoo.com/">Midway Tattoo and Piercing</a>, a studio in Kensington (where else?), Toronto where Matt Graziano kindly gave me a quote and scheduled a date.</p>

<p>I won’t lie: I was quite afraid, but Matt - a biohacker himself who was quite excited with his (literally) shiny <a href="https://dangerousthings.com/product/xsiid/">xSIID NFC + LED implant</a> - put me at ease. The entire procedure took a couple minutes, and honestly, was nearly painless (just a bit of blood). I even managed to film it with the other hand:</p>

<p style="text-align: center;"><iframe width="465" height="840" src="https://www.youtube-nocookie.com/embed/TVAmycheQnA" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe></p>

<h3 id="im-a-cyborg-here-is-my-card">I’m a cyborg, here is my card</h3>

<p>The beauty of NExT is flexibility: its high-frequency NTAG216 chip allows me to store several different classes of data (not unlike, say, a QR code) and have it accessed by any NFC-enabled phones when I touch them at the right spot, and it’s the easiest thing to do, so I tried it first.</p>

<p>There are several Android and iOS apps that allow writing NFC data to the chip; I already had <a href="https://play.google.com/store/apps/details?id=com.wakdev.nfctools.pro&amp;hl=pt&amp;gl=US">NFC Tools PRO</a>, so I used it to store a <a href="https://linktr.ee/">Linktree</a> address, turning my hand into a virtual business card:</p>

<blockquote class="tiktok-embed" cite="https://www.tiktok.com/@chesterbr/video/7046586326728101126" data-video-id="7046586326728101126" style="max-width: 605px;min-width: 325px;"> <section> <a target="_blank" title="@chesterbr" href="https://www.tiktok.com/@chesterbr">@chesterbr</a> I am now a <a title="cyborg" target="_blank" href="https://www.tiktok.com/tag/cyborg">#cyborg</a> 😁 <a title="bodymodification" target="_blank" href="https://www.tiktok.com/tag/bodymodification">#bodymodification</a>  <a title="nfc" target="_blank" href="https://www.tiktok.com/tag/nfc">#nfc</a> <a title="chipimplant" target="_blank" href="https://www.tiktok.com/tag/chipimplant">#chipimplant</a> <a title="electronics" target="_blank" href="https://www.tiktok.com/tag/electronics">#electronics</a> <a target="_blank" title="♬ original sound - Chester" href="https://www.tiktok.com/music/original-sound-7046586258067344133">♬ original sound - Chester</a> </section> </blockquote>
<script async="" src="https://www.tiktok.com/embed.js"></script>

<h3 id="hacking-actual-buildings">Hacking actual buildings</h3>

<p>The URL sending thing was fun (although NFC support in phones on the wild is hit-and-miss, at least here in Canada), but the other part of the dual chip (the low-frequency T5577) allows some other interesting applications, including the one I <strong>really</strong> wanted: getting rid of building access “fobs”.</p>

<p>Contrary to the NTAG216 (which can be programmed with any smartphone with NFC), specialized hardware is needed to read the fobs and write them on the T5577. My kit came with the <a href="https://www.proxmark.com/proxmark-3-hardware/proxmark-3-easy">Proxmark 3 Easy</a>, a somwewhat outdated member of the <a href="https://en.wikipedia.org/wiki/Proxmark3">Proxmark platform of open-source RFID hacking tools</a>, but very useful nonetheless for reading, writing and cracking several types of RFID devices.</p>

<p><img src="/img/2022/02/proxmark3.jpg" alt="Proxmark3 Easy" class="center" /></p>

<p>Using it requires a client on your computer and a matching firmware on the board. There are several builds of those around - my board came with an old version of <a href="https://github.com/RfidResearchGroup/proxmark3">“Iceman”</a>, one of the most feature-complete builds, but in a really old version. Updating it requires downloading and compiling the client and firmware as a set.</p>

<p><strong>EDIT:</strong> previously this required some file editing; now you just follow the instructions to get the dependencies (e.g., <a href="https://github.com/RfidResearchGroup/proxmark3/blob/master/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md#homebrew-mac-os-x-developer-installation">these</a> for macOS), then <code class="language-plaintext highlighter-rouge">make</code> as usual.</p>

<p>Any errors here can be fixed with web searching (for example, I had to do a <a href="https://stackoverflow.com/a/45196185/64635">small fix to my Homebrew-installed openssl</a>). When that is done, it’s a good idea to start by upgrading the board’s bootloader with <code class="language-plaintext highlighter-rouge">./pm3-flash-bootrom</code>. It requires putting the board into bootloader mode, by pressing its single button while plugging to the computer. My version was so old that I had to keep it pressed through the process, otherwise it was quick and easy.</p>

<p><img src="/img/2022/02/matt.jpg" alt="Me and Matt. Who said chips are the mark of the beast? His shop is decorated in the opposite direction... I think!" class="right" /></p>

<p>Once the bootloader is on a decent version, the same process (plugging the board while pressing the button, but now you can release it) can be used to update the firmware, just now running <code class="language-plaintext highlighter-rouge">./pm3-flash-fullimage</code>.</p>

<p>With the board fully updated, typing <code class="language-plaintext highlighter-rouge">./pm3</code> invokes the client - which will detect the board, connect to it, and that’s where the fun begins!</p>

<p><a href="https://dangerousthings.com/product/proxmark3-easy/">These videos</a> go a long way showing how to navigate the client menus; the most useful commands I learned are <code class="language-plaintext highlighter-rouge">lf search</code> and <code class="language-plaintext highlighter-rouge">hf search</code>, that try to read things on the LF (RFID) and HF (NFC) antennas, respectively. If they identify a tag, they will suggest further commands.</p>

<p><strong>In my case</strong>, the command identified the tag as a <a href="https://kantech.com/Products/rkc_ioprox.aspx">Kantech ioProx</a>, which also uses a chip from the T55xx family and had no particular advanced protection. Yours is likely to be different, so do an <a href="https://duckduckgo.com/?t=ffab&amp;q=ioprox+fob&amp;atb=v199-1&amp;iax=images&amp;ia=images">image search</a> to confirm you identified it correctly.</p>

<p>These tags are identified with a number in the format <code class="language-plaintext highlighter-rouge">XSF(XX)YY:CN</code>, where <code class="language-plaintext highlighter-rouge">XX</code> is the “version”, <code class="language-plaintext highlighter-rouge">YY</code> is the “facility” and <code class="language-plaintext highlighter-rouge">CN</code> is the “card number”. These are important because they are the parameters for the command that will reprogram the implant (or some other T55xx card/tag) to behave just like the tag, effectively “cloning” it.</p>

<p>With the right numbers in hand, you can use <code class="language-plaintext highlighter-rouge">lf io clone --vn xx --fn yy --cn CN</code> (<code class="language-plaintext highlighter-rouge">xx</code> and <code class="language-plaintext highlighter-rouge">yy</code> are the <code class="language-plaintext highlighter-rouge">XX</code> and <code class="language-plaintext highlighter-rouge">YY</code> from above, <strong>converted to decimal</strong>) to write the tag to the implant. Of course, other manufacturers/models of tags will require different commands (this is for the iOProx, hence the <code class="language-plaintext highlighter-rouge">io</code>), but the overall process is the same.</p>

<p><img src="/img/2022/02/measuring.jpg" alt="Measuring it and getting ready" class="left" /></p>

<p>Just be careful and notice the version and facility numbers are hexadecimal - <strong>they need to be converted to decimal</strong> before applying. I topped that with also writing the original fob (they are often writable!) with the wrong info; getting both hand and fob rejected by the building on the first attempt 🤦‍♂️.</p>

<p>Fortunately I keep a long scrollback on my terminal, so I was able to figure out the change and fix the mess. Lesson learned: <strong>save the info returned</strong> by <code class="language-plaintext highlighter-rouge">lf search</code> - in particular, the <code class="language-plaintext highlighter-rouge">[+] IO Prox - XSF(XX)YY:ZZZZZ, Raw: NNNNNNNNNNNNNNNN (ok)</code> line. The last number is a composition of the others, so you can use it to verify the tag.</p>

<p>Anyway, with that sorted out, I was able to record the implant with the correct information, and then access my building just with my bare hand~s~:</p>

<blockquote class="tiktok-embed" cite="https://www.tiktok.com/@chesterbr/video/7069206986822356229" data-video-id="7069206986822356229" style="max-width: 605px;min-width: 325px;"> <section> <a target="_blank" title="@chesterbr" href="https://www.tiktok.com/@chesterbr">@chesterbr</a> Used a Proxmark 3 Easy to copy the building fob to the NExT chip in my hand <a title="biohacking" target="_blank" href="https://www.tiktok.com/tag/biohacking">#biohacking</a> <a title="rfid" target="_blank" href="https://www.tiktok.com/tag/rfid">#RFID</a> <a title="nfc" target="_blank" href="https://www.tiktok.com/tag/nfc">#NFC</a> <a title="dangerousthings" target="_blank" href="https://www.tiktok.com/tag/dangerousthings">#dangerousthings</a> <a target="_blank" title="♬ original sound - Chester" href="https://www.tiktok.com/music/original-sound-7069206970661948166">♬ original sound - Chester</a> </section> </blockquote>
<script async="" src="https://www.tiktok.com/embed.js"></script>

<h3 id="other-applications">Other applications</h3>

<p>That was all cool, yet feels like I just scratched the surface on what can be done with this dual chip implant. My bundle included (among other things) these cool hacking tools:</p>

<ul>
  <li><a href="https://dangerousthings.com/product/xac-v2/">xEM Access Controller</a> is a board that memorizes fobs (including the implant) and can trigger your own hardware to build an an access management system or anything else.</li>
  <li><a href="https://dangerousthings.com/product/kbr1/">KBR1</a> is a module that “types” any RFID tag’s id on a computer, Raspberry Pi or anything that recognizes a USB keyboard; could be used for a more software-based access control system.</li>
  <li><a href="https://dangerousthings.com/product/rdc/">RFID diagnostic card</a> can identify tag readers as low frequency (LF) or high frequency (HF), so you know which chip to use.</li>
</ul>

<p>I am tempted to use some of this stuff to to open my apartment’s door (since I already have an electronic lock securely linked to a <a href="https://www.home-assistant.io/">Home Assistant</a>-controlled Raspberry Pi), but I am not sure how safe that would be (building fobs are ridiculously easy to copy, as seen above). On the other <em>hand</em> 🥁, it’s not like a regular key can’t be trivially copied too. Have to think about it.</p>

<h3 id="should-i-do-it">Should I do it?</h3>

<p>The idea of upgrading one’s body with cybernetic parts is mesmerizing, I must admit. Surely, I’m not lifting cars like <a href="https://www.imdb.com/title/tt0071054/">The Six Million Dollar Man</a>, but mine didn’t cost anywhere near that mark (which, to be fair, <a href="https://www.in2013dollars.com/us/inflation/1974?amount=6000000">would be more like 34 Million these days</a>), and I’m having my share of fun with it.</p>

<p>Anyway, RFID readers and fob cards/stickers/<a href="https://dangerousthings.com/product/magic-ring/">rings</a> can be bought online, and are cheaper and less risky than and implant - but those can always be lost, so it’s your call. Implant or no implant, one thing is ture: there is a lot of fun to be had with NFC and RFID!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Atari 2600 on a breadboard, part VI: fixing the video, adding a joystick and wrapping up]]></title>
    <link href="https://chester.me/archives/2021/09/atari-2600-on-a-breadboard-part-vi-fixing-the-video-adding-a-joystick-and-wrapping-up/"/>
    <updated>2021-09-26T00:00:00+00:00</updated>
    <id>https://chester.me/archives/2021/09/atari-2600-on-a-breadboard-part-vi-fixing-the-video-adding-a-joystick-and-wrapping-up</id>
    <content type="html"><![CDATA[<ul>
  <li><a href="/archives/2017/09/atari-2600-cpu-running-on-a-breadboard/">Part I: CPU (6507)</a></li>
  <li><a href="/archives/2021/02/atari-2600-on-a-breadboard-part-2-reading-a-cart/">Part II: Cartridge</a></li>
  <li><a href="/archives/2021/06/atari-2600-on-a-breadboard-part-3-tidying-up-and-adding-the-TIA-video-chipe/">Part III: TIA (Video chip)</a></li>
  <li><a href="/archives/2021/07/atari-2600-on-a-breadboard-part-iv-clock-composite-video-hello-world/">Part IV: Clock and Composite Video</a></li>
  <li><a href="/archives/2021/07/atari-2600-on-a-breadboard-part-v-riot-and-audio-and-running-actual-games/">Part V: RIOT (RAM, I/O, Timer) and Audio</a></li>
  <li>Part VI: Joystick, switches, fixes and wrapping up</li>
</ul>

<p>It has been a wild ride, and it finally comes to an end. Here are the final tweaks I’ve added to this project, which results in a mostly working Atari 2600. Most importantly, I learned a ton and had a lot of fun. If you came so far, I hope you did too!</p>

<!--more-->

<h3 id="joysticks">Joysticks</h3>

<p>It’s time to play, and for that we need a joystick! I could a couple DB-9 connectors, but  it was more fun to just add a few push buttons and precariously play by pressing them directly on the motherboard.</p>

<p>The Atari joystick connector has a pin for each direction and the button, open by default. When you move or press, the controller closes the connection between that pin and ground. A simple design that requires no electronics on the joystick itself (paddles and auto-fire are another story, of course).</p>

<p>Directions are handled by RIOT pins 12-15 (PA4-PA7), so I just connected them to the push buttons (black wiring). The fire button is handled by TIA pin 36 (I4), but it requires what seems to be debouncing circuit (a high-value resistor pulls it up, and a capcitor/low-value resistor ensures consistent registering of button presses).</p>

<p><img src="/img/2021/09/joystick.jpeg" alt="" class="center" /></p>

<p>I did not connect the buttons for a player 2, but it would be the same thing, using using RIOT pins 8-11 (PA0-PA3)  and TIA pin 35 (I5). I <em>did</em> have to add the pull-up resistor to the TIA pin, otherwise player 2 would fire constantly. Likewise I don’t care about the paddle pins, so I just added capacitors to TIA pins 37-40 to avoid spurious signals.</p>
<h3 id="console-switches">Console Switches</h3>

<p>The Atari 2600 had quite a few switches on the console: two <em>difficulty</em> switches (one for each player), <em>TV Type</em>, <em>Game Select</em> and <em>Game Reset</em> . They are all handled by a subset of RIOT pins PB0-PB7.</p>

<p>For this experiment, I only needed Game Reset to play, so I added a push button between that one (pin 24/PB0) and ground, with a (debouncing?) cap like in the original schematics, and let all the others open. It’s the leftmost black button seen on the picture above.</p>

<p><img src="/img/2021/09/console.jpg" alt="" class="center" /></p>

<p>This was the last “feature”, but I still had a couple things to fix:</p>
<h3 id="consistent-power-on">Consistent power on</h3>
<p>One thing that bothered me was that the breadboard Atari would never power on cleanly - most games would just crash, and I’d have to push the 6502 reset button a couple times to make it start properly.</p>

<p>That happens because the <a href="https://retrocomputing.stackexchange.com/questions/13515/6502-reset-pin-always-needed-on-power-on/13520">65xx family of processors doesn’t have a built-in startup circuit</a> - when powered on, the CPU just works with whatever (usually bad) state the silicon happens to be on.</p>

<p>The original schematics shows a 4.7µf capacitor alongside a pull-up resistor do the job of triggering the reset once the capacitor charges, which not only ensures the proper initialization, but also gives time for the CPU to start its work at optimal power level.</p>

<p>I had the pull-up resistor in my drawer, but not the capacitor at that exact value. Didn’t matter: a higher value just delays power-on by a non-humanly-measurable factor, so I threw in the 100µf I had. Now the Atari turns on consistently whenever I power it. For good measure, I added the equivalent circuit for the RIOT (6532), since it also shows up on the schematics:</p>

<p><img src="/img/2021/09/reset.png" alt="reset" class="center" /></p>
<h3 id="display-vertical-alignment">Display vertical alignment</h3>

<p>In previous posts, I tried several composite circuit variations, but I’d always get a scrolling image, like the TV wasn’t able to figure out when each frame (“screen”) started. After a lot of head-scratching, I <em>finally</em> found the issue: TIA pin 6 (BLK), the “Vertical Blank Output” - that is, the signal that is output at the beginning of every frame of an Atari game, is not connected anywhere.</p>

<p>For some odd reason, it doesn’t appear on the <a href="/img/2021/06/schematics.jpg">Atari schematics</a>. Once I joined that pin with pin 2 (SYNC), a stable image appeared! Horizontal position and weird colors still need adjustment, but that can be solved by fiddling with resistor values on the composite circuit. For my study purposes, it’s good enough™️:</p>

<p><img src="/img/2021/09/pacman-vertical-fix.jpg" alt="Vertical fix" class="center" /></p>

<p>I also got a pair of RCA jacks for breadboards from Omega MCU Systems - they have <a href="http://oms.onebytecpu.com/catalog/breadboard-connectors.php">breadboard connectors for all sorts of things</a>, making connections to the outside world much sturdier.</p>

<p><img src="/img/2021/09/rca-jacks.jpeg" alt="RCA jacks for breadboards" class="center" /></p>
<h3 id="wrapping-it-up">Wrapping it up</h3>

<p>With that setup, all my carts worked pretty well - including the Harmony Cart, that allowed me to test all sorts of games; including modern homebrew!</p>

<p>Below is the final board (and <a href="/img/2021/09/board-large.jpg">here</a> is a larger photo). It required connecting three breadboards together:</p>

<ul>
  <li>Bottom board has the 6507 CPU and the cart connector</li>
  <li>Middle board has the TIA, clock, sound and RIOT (the later in the opposite direction to simplify the data lines coming from the cartridge)</li>
  <li>Top board has the composite video circuit, audio/video connector, joystick/RESET buttons and a power adaptor.</li>
</ul>

<p>Wires are somewhat color-coded: red/blue for power/ground, yellow for data lines, green for address lines, white for logic signals (clock, chip select, read/write, etc.) and black for input/output devices (audio/video/controller).</p>

<p><a href="/img/2021/09/board-large.jpg"><img src="/img/2021/09/board.jpg" alt="" class="center" /></a></p>

<h3 id="final-considerations">Final considerations</h3>

<p>My main motivation for this project was the fact that I wanted to reproduce <a href="https://www.youtube.com/watch?v=QoBcrZJA4TI">Ben Heck’s hand-soldered Atari</a>, but he did not publish any diagrams (like he usually does), just referring people to the original Atari schematics (which were near uncomprehensible for me at the time).</p>

<p>My plan was to create drawings of the breadboard on Fritzing as I progressed, so anyone wanting to rebuild an Atari could do so without resorting to the circuit diagram. And I did it on the fist few parts, but at certain point, it became impossible - the drawing got too complicated and Fritzing started to crash.</p>

<p>Anyway, after tackling the project in small steps (and looking at other diagrams, partial circuits, articles and discussions), I learned enough about electronics and the Atari 2600 to grasp its original diagram - and finally understood why Ben did not find it necessary to publish anything else.</p>

<p><img src="/img/2021/09/diagramas-sm.jpg" alt="" class="center" /></p>

<p>So if you want to (re)build your ow your Atari, be it soldered or on a breadboard, you can either follow the diagram like Ben, or, if it’s too complicated, just go step by step.</p>

<p>In any case, I hope you have as much fun (and learn as much) as I did!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Atari 2600 on a breadboard, part V: RIOT and Audio (and running actual games!)]]></title>
    <link href="https://chester.me/archives/2021/07/atari-2600-on-a-breadboard-part-v-riot-and-audio-and-running-actual-games/"/>
    <updated>2021-07-12T00:00:00+00:00</updated>
    <id>https://chester.me/archives/2021/07/atari-2600-on-a-breadboard-part-v-riot-and-audio-and-running-actual-games</id>
    <content type="html"><![CDATA[<ul>
  <li><a href="/archives/2017/09/atari-2600-cpu-running-on-a-breadboard/">Part I: CPU (6507)</a></li>
  <li><a href="/archives/2021/02/atari-2600-on-a-breadboard-part-2-reading-a-cart/">Part II: Cartridge</a></li>
  <li><a href="/archives/2021/06/atari-2600-on-a-breadboard-part-3-tidying-up-and-adding-the-TIA-video-chipe/">Part III: TIA (Video chip)</a></li>
  <li><a href="/archives/2021/07/atari-2600-on-a-breadboard-part-iv-clock-composite-video-hello-world/">Part IV: Clock and Composite Video</a></li>
  <li>Part V: RIOT (RAM, I/O, Timer) and Audio</li>
  <li><a href="/archives/2021/09/atari-2600-on-a-breadboard-part-vi-fixing-the-video-adding-a-joystick-and-wrapping-up/">Part VI: Joystick, switches, fixes and wrapping up</a></li>
</ul>

<h3 id="after-hello-world">After Hello World</h3>

<p>Now that I <a href="/archives/2021/07/atari-2600-on-a-breadboard-part-iv-clock-composite-video-hello-world/">got Hello, World! running</a>, I feel confident this project may actually succeed! 😅 The next step is to run an actual game, which requires wiring the last chip (and, due to the poor video I have so far, a sound circuit).</p>

<!--more-->

<h3 id="adding-riot">Adding RIOT</h3>
<p>MOS’s catalog included several support chips compatible with its successful 6502 “family” of CPUs (of which our Atari’s <a href="https://en.wikipedia.org/wiki/MOS_Technology_6507">6507</a> is a member). Atari picked the <a href="https://en.wikipedia.org/wiki/MOS_Technology_6532">6532</a> to supply the missing pieces (<strong>R</strong>AM, <strong>I</strong>nput/<strong>O</strong>utput channels and <strong>T</strong>imers) that give this chip the nickname “RIOT”.</p>

<p>Wiring it was no different than wiring the TIA. Pretty much:</p>
<ul>
  <li>Following the address and data lines from the <a href="/img/2021/06/schematics.jpg">schematics</a>;</li>
  <li>Connecting the +5V (1) and ground (20) pins to their power rails;</li>
  <li>Bringing the RESET (34) pin up - the schematics have a 24K resistor <em>and</em> a .1µF capacitor that I considered overkill, but heck, why not;</li>
  <li>Connecting the 6502 Phase 2 clock (𝜃2) clock and R/W pins (28 and 26) to its RIOT counterparts (39 and 35), so the CPU can sync the communication with the chip.</li>
</ul>

<p>The chip also reads directional/fire buttons from joysticks, SELECT, START and both difficulty switches, but I’ll wire those later. All I want is to give games what they need to run!</p>

<p><img src="/img/2021/07/breadboard-with-riot-and-audio.jpeg" alt="" /></p>
<h3 id="some-sound">Some sound</h3>

<p>Sound was actually part of TIA, but I did not bother adding it before because the only software I had that would work without RAM and Timers (the “Hello, World” program) was silent. But now it will work (and be invaluable since my composite output is still 💩), so I added a 1K resistor and a 1µF cap to both pins; resistor goes to 5V and cap goes to center pin of audio jack (outer part is ground). May be improved (e.g., doubling the circuit for “stereo” sound), but good for now.</p>

<h3 id="games">Games!</h3>
<p>Incredibly, this setup worked first time (notwithstanding the video). One can hear (and almost see) Pac-Man going through the circle of life:</p>

<iframe width="560" height="315" src="https://www.youtube.com/embed/Bag9FnKe2q0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
<h3 id="video-blues">Video blues</h3>

<p>Unfortunately, I can’t still get a good composite video image. Tried every composite circuit under the sun, results are still wonky. The best I got so far was with the circuit mentioned on the <a href="/archives/2021/07/atari-2600-on-a-breadboard-part-iv-clock-composite-video-hello-world/">last post</a>, only replacing a resistor that was a bit out-of-range:</p>

<p><img src="/img/2021/07/pacman-so-so.jpg" alt="" /></p>

<p>In fact, only one of my TVs got me any image at all (as previously mentioned, modern TVs are more picky with the signals they get). People often get around that running the signal through a VCR, but I had a much smaller option: this  <a href="https://www.amazon.ca/Caxico-RCACVS-Composite-Converter-Blue-Ray/dp/B011E6GRPU">composite-to-HDMI converter</a>. It’s not as tolerant as the VCR (or a tube TV), but it picks up even this bad signal, and was quite cheap when I bought it.</p>

<p><img src="/img/2021/07/upscaler.jpg" alt="" /></p>

<h3 id="next">Next</h3>
<p>I guess I should now add a joystick and SELECT/START (either a connector, or some push buttons, depending on what I have on my drawer), then fix the video (assuming it’s not a TIA defect). Then I’ll transcribe all the things back to a Fritzing drawing (so anyone - including myself in the future -  can reproduce), and I guess I will be done with this experiment.</p>

<ul>
  <li><a href="/archives/2021/09/atari-2600-on-a-breadboard-part-vi-fixing-the-video-adding-a-joystick-and-wrapping-up/">Part VI: Joystick, switches, fixes and wrapping up</a></li>
</ul>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Atari 2600 on a breadboard, part IV: clock + composite video = Hello, World!]]></title>
    <link href="https://chester.me/archives/2021/07/atari-2600-on-a-breadboard-part-iv-clock-composite-video-hello-world/"/>
    <updated>2021-07-04T00:00:00+00:00</updated>
    <id>https://chester.me/archives/2021/07/atari-2600-on-a-breadboard-part-iv-clock-composite-video-hello-world</id>
    <content type="html"><![CDATA[<ul>
  <li><a href="/archives/2017/09/atari-2600-cpu-running-on-a-breadboard/">Part I: CPU (6507)</a></li>
  <li><a href="/archives/2021/02/atari-2600-on-a-breadboard-part-2-reading-a-cart/">Part II: Cartridge</a></li>
  <li><a href="/archives/2021/06/atari-2600-on-a-breadboard-part-3-tidying-up-and-adding-the-TIA-video-chipe/">Part III: TIA (Video chip)</a></li>
  <li>Part IV: Clock and Composite Video</li>
  <li><a href="/archives/2021/07/atari-2600-on-a-breadboard-part-v-riot-and-audio-and-running-actual-games/">Part V: RIOT (RAM, I/O, Timer) and Audio</a></li>
  <li><a href="/archives/2021/09/atari-2600-on-a-breadboard-part-vi-fixing-the-video-adding-a-joystick-and-wrapping-up/">Part VI: Joystick, switches, fixes and wrapping up</a></li>
</ul>

<h3 id="tv-time">TV Time</h3>

<p>In the <a href="https://chester.me/archives/2021/06/atari-2600-on-a-breadboard-part-3-tidying-up-and-adding-the-TIA-video-chipe/">previous post</a>, I had the CPU, cartridge and TIA wired and tested, but still needed the Arduino to make them tick and check the resuts. All those hex numbers were fun to debug, but let’s get to the real deal: plugging it to the TV.</p>

<!--more-->

<h3 id="clock">Clock</h3>
<p>In order to show the image of a game on a TV set, the video chip (TIA) needs to generate 60 frames (screens) per second, which, in turn, requires its clock to receive 3,579,545 “pulses” per second. What makes that magic work is a  <a href="https://en.wikipedia.org/wiki/Crystal_oscillator">crystal oscilator</a>, and fortunately that particular frequency (3.579545 Mhz) is so common in TV-related applications that one can easily <a href="https://www.walmart.ca/en/ip/3-x-3-579545-MHz-Crystal-Oscillator-HC-49S-Low-Profile/7DRO8USL2ETL">buy such a crystal online</a>.</p>

<p>The crystal won’t do the job on its own. We need a circuit that amplifies and cleans the wave it produces, so the TIA gets a more regular signal. Each Atari 2600 model has a slight variation of that circuit, and after fiddling with a couple, I settled on the one used in the <a href="http://www.atarimuseum.com/videogames/consoles/2600/atari2600jr.html">Atari 2600 Jr.</a>, following this <a href="http://www.kevtris.org/2600/2600schemo.html">diagram by Kevin Horton</a>:</p>

<p><img src="/img/2021/07/2600osc.gif" alt="" class="center" /></p>

<p><img src="/img/2021/07/clock-circuit-rough.jpeg" alt="" /></p>

<p>Testing that circuit was a bit of a pickle: the Arduino could not monitor such a signal. Usually, these tests are done with an oscilloscope. Those appliances were always out of my budget as a hobbyist, but these days there are quite a few “USB oscilloscopes”: they contain the electronics to do the measurement, but output their data to a computer, which makes them much cheaper. Professionals frown a bit on them, but the <a href="https://www.amazon.ca/gp/product/B009H4AYII/">Hantek 6022BE</a> was within my price range, so I decided to give it a shot.</p>

<p><a href="/img/2021/07/oscilloscope-board-and-computer.jpeg"><img src="/img/2021/07/oscilloscope-board-and-computer.jpeg" alt="" /></a></p>

<p>It was a <strong>great</strong> purchase - in particular due to <a href="http://openhantek.org/">OpenHantek</a>, an open-source alternative to the included software that future-proofs the investment. The user guide initiated me to the point that I could measure the clock of a working Atari, then compare it with my circuit (click to zoom).</p>

<p><a href="/img/2021/07/clock.png"><img src="/img/2021/07/clock.png" alt="" /></a></p>

<p>In both cases, I got a steady wave, pulsing once each ~277ns, which the software computes to be a frequency of 3.60 Mhz. The actual values should be 279.365115ns and the 3.579545 Mhz mentioned above, but I had to mark the period manually, and this is as precise as I could get; maybe ther is a way for the software to auto-zoom on a single cycle, have to figure that out.</p>

<p>That was enough for me to organize and shorten the components into a tidier circuit. Notice the long horizontal cable connecting the clock output to TIA pin 11, where the Arduino used to provide a much slower pulse.</p>

<p><img src="/img/2021/07/clock-final-with-tia.jpeg" alt="" /></p>
<h3 id="composite-video">Composite Video</h3>
<p>At that point I had a clock that <em>probably</em> puts the CPU/TIA to work in full speed, so now it’s all about hooking it up to the TV, right? Not so fast: the TIA generates a few separate signals that need to be combined properly into a format that the TV can understand.</p>

<p>The Atari 2600 does so by generating an RF (antenna) signal, which was complicated, prone to interference and most modern TVs have a hard time with it, so a better option for modern TVs is <a href="https://en.wikipedia.org/wiki/Composite_video">composite video</a>. Roughly speaking, it combines a sync wave (that tells the TV when each frame starts) with the black-and-white and color components (aka “chrominance” and “luminance”) of each pixel (<a href="http://rfcafe.com/references/radio-news/color-tv-ntsc-system-radio-television-news-april-1954.htm">in a non-trivial</a> way to ensure backwards compatibility with black-and-white TVs).</p>

<p><a href="/img/2021/07/color-chart.png"><img src="/img/2021/07/color-chart.png" alt="" /></a></p>

<p>Modern-day Atari owners often install a “composite mod” on their consoles: a small circuit that extracts and combines the signals mentioned above from the Atari main board. I tried using <a href="http://www.cheeptech.com/2600mods/2600mods.shtml">a few mods</a>, but they all depend partially on existing components on the Atari board.</p>

<p>I found a <a href="https://atariage.com/forums/topic/215414-composite-av-from-tia-chip/?do=findComment&amp;comment=3065838">circuit</a> on the AtariAge forum (based on <a href="https://www.atariage.com/2600/faq/index.html?SystemID=2600#composite">a chroma/luma one from the Atari FAQ</a>) that includes the Atari parts (the ones on the blue border). It’s slightly more complex than others, but was the only one that generated  <em>anything</em> on my TV.</p>

<p><a href="/img/2021/07/composite-circuit-from-parafin.png"><img src="/img/2021/07/composite-circuit-from-parafin.png" alt="" /></a></p>

<h3 id="sync-issues">Sync issues</h3>
<p>Like I did on the previous post, I used the <a href="https://gist.github.com/chesterbr/5864935">Atari 2600 Hello, World program</a> that I created for an <a href="https://www.slideshare.net/chesterbr/atari-2600programming">Atari 2600 Programming presentation</a>, because we still don’t have RAM, timers or inputs that any regular game would require. Also, it’s kinda fun to start with a “Hello, World”.</p>

<p>My first attempt (which I <a href="https://www.instagram.com/tv/CQoftoNF3zz/?utm_source=ig_web_copy_link">livestreamed in Portuguese</a>) was an epic failure (didn’t check for shorts and smell of burning ensued), but the second one worked… <em>if</em> you ignore the lack of color and the rolling screen 😅</p>

<p><img src="/img/2021/07/scrolling.gif" alt="" class="center" style="width:700px; height:543px" /></p>

<p>This often happens when Atari softare fails to “<a href="https://en.wikipedia.org/wiki/Racing_the_Beam">race the beam</a>”, but that piece of code is, to put it shortly, too minimalistic to fail. After checking the TV menus, I found the issue: the TV was recognizing the signal as PAL, and not NTSC.</p>

<p>Those systems <a href="https://www.spiceware.org/atari_ntsc_pal_secam.html">expect different frame sizes</a>, which explains the scrolling (the software sends the next screen starts before the TV is done with the previous one).</p>

<p>TVs of that time were electrical devices, driving a cathode tube that were tied to (among other things) the electrical frequency on the outlets (60Hz in countries that work with NTSC, 50Hz with PAL - which 100% relates to the 50 x 60 frames per second). If you used the wrong frequency, scrolling would indeed happen (if you want details, click the image for a great Technical Connections video about that):</p>

<p><a href="https://www.youtube.com/watch?v=l4UgZBs7ZGo"><img src="/img/2021/07/scrolling-person.jpg" alt="this is a great video if you want the details" /></a></p>

<p>In that context, my modern(ish) TV is more like an “emulator”, trying to identify and decode the signal into its LCD array of fixed pixels. That is hit-and-miss (of the three TVs that I tested, this was the only one that showed any image at all). I tried adding a CD4050 chip as a buffer (like the <a href="https://www.atariage.com/2600/faq/index.html?SystemID=2600#composite">FAQ circuit</a> does), no improvement.</p>

<h3 id="the-fix--hello-world">The fix =&gt; HELLO, WORLD!</h3>

<p>What actually worked was “cleaning up” the circuit - cutting the components and fitting them properly (like I did with the clock). <em>That</em> convinced the TV to recognize the signal as NTSC. Swapping the crystal also gave it more stability (maybe the livestream incident broke it? glad I bought a pack of 3 😅).</p>

<p><img src="/img/2021/07/composite-final.jpeg" alt="" /></p>

<p>Anyway, I <strong>finally</strong> got to the first milestone I envisioned where I started this journey, years ago: <code class="language-plaintext highlighter-rouge">HELLO WORLD</code>! 🎉</p>

<p><img src="/img/2021/07/hello-world-atari.jpg" alt="" /></p>
<h3 id="next-steps">Next steps</h3>
<p>Even with the fixed circuit, the image is a bit unstable, colors are wrong and there is an odd bar on the right. But instead of debugging these, I’ll add the RIOT (the last chip), which should allow me to run actual games and fine-tune the circuit.</p>

<p>I also want to update the Fritzing sketches with all those circuits once I settle them (so anyone wanting to rebuild a custom Atari can have a more readable starting point), add or build a controller… we’ll see!</p>

<ul>
  <li><a href="/archives/2021/07/atari-2600-on-a-breadboard-part-v-riot-and-audio-and-running-actual-games/">Part V: RIOT (RAM, I/O, Timer) and Audio</a></li>
</ul>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Atari 2600 on a breadboard, part III: tidying up and adding the TIA (video chip)]]></title>
    <link href="https://chester.me/archives/2021/06/atari-2600-on-a-breadboard-part-3-tidying-up-and-adding-the-TIA-video-chipe/"/>
    <updated>2021-06-25T00:00:00+00:00</updated>
    <id>https://chester.me/archives/2021/06/atari-2600-on-a-breadboard-part-3-tidying-up-and-adding-the-TIA-video-chipe</id>
    <content type="html"><![CDATA[<ul>
  <li><a href="/archives/2017/09/atari-2600-cpu-running-on-a-breadboard/">Part I: CPU (6507)</a></li>
  <li><a href="/archives/2021/02/atari-2600-on-a-breadboard-part-2-reading-a-cart/">Part II: Cartridge</a></li>
  <li>Part III: TIA (Video chip)</li>
  <li><a href="/archives/2021/07/atari-2600-on-a-breadboard-part-iv-clock-composite-video-hello-world/">Part IV: Clock and Composite Video</a></li>
  <li><a href="/archives/2021/07/atari-2600-on-a-breadboard-part-v-riot-and-audio-and-running-actual-games/">Part V: RIOT (RAM, I/O, Timer) and Audio</a></li>
  <li><a href="/archives/2021/09/atari-2600-on-a-breadboard-part-vi-fixing-the-video-adding-a-joystick-and-wrapping-up/">Part VI: Joystick, switches, fixes and wrapping up</a></li>
</ul>

<h3 id="tidying-up">Tidying Up</h3>

<p>In the previous posts I made the CPU work on the breadboard, then added a cartridge connector, all using <a href="https://en.wikipedia.org/wiki/Jump_wire">jump wires</a> - which can be easily reconnected, labeled, etc., but have a downside: they disconnect easily. Coupled with the equally flimsy cart connector, all my attempts at moving on with the project would result in failures.</p>

<p>After seeing <a href="https://eater.net/">Ben Eater’s beautiful breadboard computers</a> I decided to rewire the boards I already had. For that, I’d have to rethink my cartridge connector: instead of having the jumper cables going out of it (left), I got some <a href="https://www.creatroninc.com/product/feather-stackable-header-set/">long pin female headers</a> that extended the pins so the connector now fits the board like any other chip (right):</p>

<p><img src="/img/2021/06/before-and-after-cart.jpg" alt="cart, before and after" class="center" /></p>

<!--more-->

<p>Armed with that and <a href="https://www.youtube.com/watch?v=PE-_rJqvDhQ">Ben’s video with tips</a>, I rewired everything I had (minus the “pause” button, as it will be replaced on the next step). Other than the Arduino (which is temporary), everything is now nice, tidy and color-coded (data is yellow, addresses are green, +5V is red and ground is blue):</p>

<p><img src="/img/2021/06/cleaner-board-with-cpu-and-cart.jpg" alt="clean board with cpu and cart connector" class="center" /></p>

<h3 id="wiring-the-tia">Wiring the TIA</h3>

<p>The Television Interface Adapter (TIA) is the only custom chip on the Atari. It was designed to generate the video and audio signals, and to reduce costs, it has nearly no video memory, requiring programmers to sync their code with the TV signal - with microssecond precision. To aid in that task, the TIA controls the 6507 CPU in two ways:</p>

<ul>
  <li>It provides the CPU clock, by “dividing” its input clock by 3, that is: for every three pulses that the TIA receives from the clock crystal (for now, in our case, from the Arduino), it sends one pulse to the CPU.</li>
  <li>When the software writes to the <code class="language-plaintext highlighter-rouge">WSYNC</code> address, the TIA halts the CPU (using the <code class="language-plaintext highlighter-rouge">RDY</code> pin) until the current scanline in the video finishes drawing.</li>
</ul>

<p><img src="/img/2021/06/sync-signal.jpg" alt="illustration adapted from Racing The Beam" class="center" /></p>

<p>For that magic to work, we need to connect the 6507 clock pins (<code class="language-plaintext highlighter-rouge">ø0</code> and <code class="language-plaintext highlighter-rouge">ø2</code>; the later is an output that seems to help keeping things in sync) and the <code class="language-plaintext highlighter-rouge">RDY</code> pin to their matching TIA pins (keeping the pull-up resitor); we’ll also connect the <code class="language-plaintext highlighter-rouge">R/W</code> pin between them (so the TIA can know whether the 6507 wants to read or write to it).</p>

<p>And, of course, connect the data pins (<code class="language-plaintext highlighter-rouge">D0-D7</code>) and the lower address pins (<code class="language-plaintext highlighter-rouge">A0-A5</code>), so the data can flow from/to the proper addresses. Finally, connect two address pins and two fixed voltages to the “chip selector” TIA pins (<code class="language-plaintext highlighter-rouge">CS0-CS3</code>), so TIA knows when the CPU is talking to it (as opposed to the cart or the other upcoming chip).</p>

<p><img src="/img/2021/06/schematics.jpg" alt="Atari 2600 Schematics" class="center" /></p>

<p>I found some TIA pin descriptions online, but they had a few incorrections; so I guided myself mostly on the <a href="/img/2021/06/schematics.jpg">original schematics</a> and built this table for TIA-to-CPU connections:</p>

<table>
  <thead>
    <tr>
      <th>Pin Name</th>
      <th style="text-align: right">TIA #</th>
      <th style="text-align: right">6507 #</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">ø0</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">4</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">27</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">ø2</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">26</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">28</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">RDY</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">3</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">3</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">R/W</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">25</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">36</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">D0</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">14</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">25</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">D1</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">15</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">24</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">D2</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">16</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">23</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">D3</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">17</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">22</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">D4</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">18</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">21</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">D5</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">19</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">20</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">D6</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">33</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">19</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">D7</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">34</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">18</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">A0</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">32</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">5</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">A1</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">31</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">6</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">A2</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">30</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">7</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">A3</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">29</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">8</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">A4</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">28</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">9</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">CS0/A12</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">24</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">17</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">CS3/A7</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">21</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">12</code></td>
    </tr>
  </tbody>
</table>

<p>and one for the direct-to-power connections:</p>

<table>
  <thead>
    <tr>
      <th>Pin Name</th>
      <th style="text-align: right">TIA #</th>
      <th style="text-align: right">+/-</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">CS1</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">23</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">+5V</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">CS2</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">22</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">GND</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">VSS</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">1</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">+5V</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">VCC</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">20</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">GND</code></td>
    </tr>
  </tbody>
</table>

<p>Throwing a 100nF capacitor close to the <code class="language-plaintext highlighter-rouge">VSS</code> pin gives the TIA clean power (like I did to the CPU). I stacked a second breadboard on the first to add the TIA, using the same color conventions of before for power, data and address signals, adding white for non-address/non-data TIA-to-CPU connections.</p>

<p>I aligned the TIA with the breadboard numbers, which proved to be a mistake: several cables needed to go through the left side and had to hang outside of the board. Other than that, it looks pretty nice:</p>

<p><img src="/img/2021/06/final-board.jpg" alt="final board with TIA and CPU" class="center" /></p>

<h3 id="testing">Testing</h3>

<p>Once again, I’ll plug an Arduino for testing, connecting pins 2-9 to the data lines as in the previous post. This time, I’ll connect the Arduino-generated clock pin to the TIA clock input (<code class="language-plaintext highlighter-rouge">OSC</code>, pin 11), and slightly reduce the delays to 10ms, speeding the clock to roughly 50Hz (still around 24 times slower than the real Atari):</p>

<p><img src="/img/2021/06/board-with-arduino.jpg" alt="board with Arduino" class="center" /></p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Turns an Arduino into a 50Hz clock generator (on pin A5)</span>
<span class="c1">// and a monitor for an 8-bit data bus (pins 2-9)</span>

<span class="kt">void</span> <span class="nf">setup</span><span class="p">()</span> <span class="p">{</span>
  <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">pin</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="n">pin</span> <span class="o">&lt;=</span> <span class="mi">9</span><span class="p">;</span> <span class="n">pin</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">pinMode</span><span class="p">(</span><span class="n">pin</span><span class="p">,</span> <span class="n">INPUT</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="n">pinMode</span><span class="p">(</span><span class="n">A5</span><span class="p">,</span> <span class="n">OUTPUT</span><span class="p">);</span>
  <span class="n">Serial</span><span class="p">.</span><span class="n">begin</span><span class="p">(</span><span class="mi">115200</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">loop</span><span class="p">()</span> <span class="p">{</span>
  <span class="c1">// Clock pulse</span>
  <span class="n">digitalWrite</span><span class="p">(</span><span class="n">A5</span><span class="p">,</span> <span class="n">HIGH</span><span class="p">);</span>
  <span class="n">delay</span><span class="p">(</span><span class="mi">10</span><span class="p">);</span>
  <span class="n">digitalWrite</span><span class="p">(</span><span class="n">A5</span><span class="p">,</span> <span class="n">LOW</span><span class="p">);</span>
  <span class="n">delay</span><span class="p">(</span><span class="mi">10</span><span class="p">);</span>

  <span class="c1">// Print current data bus (pins 2-9)</span>
  <span class="kt">int</span> <span class="n">data_value</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">power_of_two</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
  <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">bit</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">bit</span> <span class="o">&lt;=</span> <span class="mi">7</span><span class="p">;</span> <span class="n">bit</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">data_value</span> <span class="o">+=</span> <span class="n">digitalRead</span><span class="p">(</span><span class="n">bit</span> <span class="o">+</span> <span class="mi">2</span><span class="p">)</span> <span class="o">*</span> <span class="n">power_of_two</span><span class="p">;</span>
    <span class="n">power_of_two</span> <span class="o">*=</span> <span class="mi">2</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">data_value</span> <span class="o">&lt;</span> <span class="mh">0x10</span><span class="p">)</span> <span class="p">{</span> <span class="n">Serial</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s">"0"</span><span class="p">);</span> <span class="p">}</span>
  <span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="n">data_value</span><span class="p">,</span> <span class="n">HEX</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Instead of an actual game, this time I loaded my <a href="https://harmony.atariage.com/Site/Harmony.html">Harmony Cart</a> with the <a href="https://gist.github.com/chesterbr/5864935">Atari 2600 Hello, World program</a> that I created once for an <a href="https://www.slideshare.net/chesterbr/atari-2600programming">Atari 2600 Programming presentation</a>, because we don’t have RAM or timers yet, and that software doesn’t use either.</p>

<p>Once again, let’s have the Stella disassembly handy:</p>

<p><img src="/img/2021/06/stella.png" alt="disassembled code on Stella" class="center" /></p>

<p>and check the Arduino output (right after we reset the CPU with the button on the breadboard). This time I’ll remove the timestamps, group the numbers together and put on a Gist, to make it easier to analyze:</p>

<script src="https://gist.github.com/chesterbr/c3437955a94548593073cf92841fea41.js"></script>

<p>First thing to notice: that almost all numbers print three times. That is expected: the TIA sends one clock pulse for each three it receives, and we monitor the data lines every time we send a clock pulse to TIA.</p>

<p>When we account for the triple vision, the output is not unlike the one on the previous post: line 1 shows the 6502 reading the two-byte location of the reset vector on the cart (<code class="language-plaintext highlighter-rouge">F000</code>, read in reverse order). Line 2 matches the instruction at that address (<code class="language-plaintext highlighter-rouge">LDA #$02</code>, that is, <code class="language-plaintext highlighter-rouge">A9 02</code> in machine code), and line 3 is the following instruction (<code class="language-plaintext highlighter-rouge">STA VSYNC</code>, or <code class="language-plaintext highlighter-rouge">85 00</code>). The <code class="language-plaintext highlighter-rouge">STA</code> writes the value <code class="language-plaintext highlighter-rouge">02</code> to memory, which takes an extra cycle (line 4, with the <code class="language-plaintext highlighter-rouge">02</code> forming at the end of the cycle).</p>

<p>Things get odd at lines 7, 10 an 13, where we see <strong>a lot</strong> of repeated numbers. What gives? Well, the lines above them are <code class="language-plaintext highlighter-rouge">STA WSYNC</code>, and as stated above, when we write to that address, TIA uses the <code class="language-plaintext highlighter-rouge">RDY</code> pin to “freeze” the 6502 until an entire scanline is produced; which is why the data bus didn’t change until we total 228 cycles.</p>

<p>If you pay attention, you may notice that we have a little less than that number of bytes on lines 10 and 13, and even less on line 7; that is because we have to discount the cycles “spent” since the current scanline started.</p>

<p>Anyway, this more than proves that our TIA is up and running!</p>

<h3 id="next">Next</h3>

<p>One may wonder why I don’t plug this on the TV, given there is a video chip. We’re missing a couple things that I plan to add on the next post, in which I expect to finally generate some image!</p>

<ul>
  <li><a href="/archives/2021/07/atari-2600-on-a-breadboard-part-iv-clock-composite-video-hello-world/">Part IV: Clock and Composite Video</a></li>
</ul>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Atari 2600 on a breadboard, part II: reading a cart]]></title>
    <link href="https://chester.me/archives/2021/02/atari-2600-on-a-breadboard-part-2-reading-a-cart/"/>
    <updated>2021-02-14T00:00:00+00:00</updated>
    <id>https://chester.me/archives/2021/02/atari-2600-on-a-breadboard-part-2-reading-a-cart</id>
    <content type="html"><![CDATA[<ul>
  <li><a href="/archives/2017/09/atari-2600-cpu-running-on-a-breadboard/">Part I: CPU (6507)</a></li>
  <li>Part II: Cartridge</li>
  <li><a href="/archives/2021/06/atari-2600-on-a-breadboard-part-3-tidying-up-and-adding-the-TIA-video-chipe/">Part III: TIA (Video chip)</a></li>
  <li><a href="/archives/2021/07/atari-2600-on-a-breadboard-part-iv-clock-composite-video-hello-world/">Part IV: Clock and Composite Video</a></li>
  <li><a href="/archives/2021/07/atari-2600-on-a-breadboard-part-v-riot-and-audio-and-running-actual-games/">Part V: RIOT (RAM, I/O, Timer) and Audio</a></li>
  <li><a href="/archives/2021/09/atari-2600-on-a-breadboard-part-vi-fixing-the-video-adding-a-joystick-and-wrapping-up/">Part VI: Joystick, switches, fixes and wrapping up</a></li>
</ul>

<h3 id="previously">Previously…</h3>

<p>A <em>long</em> time ago I grabbed the three chips from a broken Atari 2600 (Jr.), to see if I could build an Atari with them on a <a href="https://www.youtube.com/watch?v=mE33WpRWrXs">solder-less “breadboard”</a>. My first attempt (<a href="/archives/2017/09/atari-2600-cpu-running-on-a-breadboard/">post here</a>) was to drive the CPU with an Arduino, which showed the chip advancing through what it believes to be memory, but is actually just a single “no operation” (<code class="language-plaintext highlighter-rouge">NOP</code>) hard-wired instruction:</p>

<p><img src="/img/2021/02/6507-nop.jpg" alt="cleaner version of the 6507 memory walk on a breadboard" class="center" /></p>

<p>It took some time (between finding the right connector, 3D-printing a part, figuring out the wiring and fixing the Arduino software), but I finally moved on to the next step: <strong>plugging a real Atari cart and seeing some actual code running</strong>!</p>

<!--more-->

<h3 id="how-the-atari-2600-reads-game-carts">How the Atari 2600 reads game carts</h3>

<p>An Atari cartridge contains a ROM (Read-Only Memory) chip, meaning we’ll only read data from it. The 6507 CPU can request any single byte on a given memory position on the cart by setting that memory address, in binary form, on a given set of its pins (the <em>address bus</em>), and the cart responds with the byte on that position on another set of pins (the <em>data bus</em>).</p>

<p>In fact, these buses are used to both read and write bytes to all other parts of the system, but for now we only care about the cart. My first step was to get the cart pinout, which you can find in <a href="https://old.pinouts.ru/Motherboard/AtariCartridge_pinout.shtml">several</a> <a href="https://atariage.com/forums/topic/185932-my-2600-cart-dumper/">places</a>, but people often forget to mention the orientation of the pins, whether we are seeing the cart or the slot, etc., so I went with the <a href="https://atariage.com/2600/archives/schematics/">original Atari schematics</a>, which shows the <strong>connector</strong> as seen by someone looking directly at the console:</p>

<p><img src="/img/2021/02/cart-connector-schematics.png" alt="Atari cart connector" class="center" /></p>

<p>From looking at it, the connector consists pretty much in address (<code class="language-plaintext highlighter-rouge">A0</code>-<code class="language-plaintext highlighter-rouge">A12</code>) and data (<code class="language-plaintext highlighter-rouge">D1</code>-<code class="language-plaintext highlighter-rouge">D8</code>) lines (plus a +5V and two GND pins), so connecting those to the matching CPU and voltage pins in our board should do the job, no extra electronics needed this time.</p>

<h3 id="physical-connection">Physical connection</h3>

<p>In non-Atari lingo, the socket is a <a href="https://www.digikey.ca/en/products/detail/sullins-connector-solutions/EBC12DCWN/927256">24-pin “edge” connector</a> - which is just like a computer peripheral card “slot”, only smaller. It isn’t a trivial size, but with the right name you can find it online (or use the link above).</p>

<p><img src="/img/2021/02/connector.jpg" alt="Physical connector" class="center" /></p>

<p>Unfortunately you can’t just plug a cart into the connector, because carts (or, at least, the Atari-manufactured ones) have a sliding plastic protector that only opens when the cart is inserted in the matching plastic guide - and <em>that</em> one isn’t manufactured anymore.</p>

<p>I was lucky not to be the only one with this problem. In particular, people <a href="http://www.atarimuseum.com/fb2hacks/">hacking Atari Flashback</a> mini-consoles to add a cart slot also required one, so they created a <a href="https://www.thingiverse.com/thing:292341">model</a> that I could download and 3D-print (of course, there are <a href="https://hackaday.io/project/113217-atari2600-cartridge-reader">other options</a> you may consider):</p>

<p><img src="/img/2021/02/cart-guide.jpg" alt="printed cart guide" class="center" /></p>

<p>The fit wasn’t perfect, but with some epoxy and a bit of drilling, I managed to fix the connector in the guide. I connected some <a href="https://www.dx.com/p/diy-male-to-female-dupont-breadboard-jumper-wires-black-multi-color-40-pcs-10cm-2045521.html#.YCilgOBybUI">female-to-male jump wires</a> (hint: use <a href="https://www.dx.com/p/male-to-female-dupont-breadboard-jumper-wires-for-arduino-40-piece-pack-20cm-length-2017096.html#.YCilt-BybUI">longer ones</a>), inserting a toothpick to keep them firm, then labeling according to the schematics:</p>

<p><img src="/img/2021/02/connector-bottom.jpg" alt="connector bottom with toothpick inserted" class="center" />
<img src="/img/2021/02/cart-guide-with-connector-and-wires.jpg" alt="cart guide with connector and wires" class="center" /></p>

<h3 id="wiring">Wiring</h3>

<p><img src="/img/2021/02/6507.gif" alt="6507" class="right" /></p>

<p>Starting with the breadboard from the <a href="/archives/2017/09/atari-2600-cpu-running-on-a-breadboard/">first post</a>, I removed the hard-wired <code class="language-plaintext highlighter-rouge">NOP</code> instruction, and connected the address/data lines to the matching pins on the 6507, and the +5V (socket pin 23) and ground (socket pins 12 &amp; 24) to the power lines.</p>

<p>One thing to notice: the Atari schematics refer to data pins as <code class="language-plaintext highlighter-rouge">D1</code>-<code class="language-plaintext highlighter-rouge">D8</code>, whereas 6507 names them <code class="language-plaintext highlighter-rouge">D0</code>-<code class="language-plaintext highlighter-rouge">D7</code> (starting from 0 like the address pins, and also like bits are usually assigned). But at least they are aligned on the chip, so it wasn’t (much) confusing.</p>

<p>Another thing to pay attention: for some reason, <code class="language-plaintext highlighter-rouge">A10</code> and <code class="language-plaintext highlighter-rouge">A11</code> are flipped on the connector - the sequence, looking left-to-right from outside the console, is <code class="language-plaintext highlighter-rouge">A8</code>, <code class="language-plaintext highlighter-rouge">A9</code>, <code class="language-plaintext highlighter-rouge">A11</code>, <code class="language-plaintext highlighter-rouge">A10</code> and <code class="language-plaintext highlighter-rouge">A12</code>. Remember to flip them as you connect the wires.</p>

<p>Speaking of pins, the previous method of monitoring the address lines worked fine when addresses were just growing sequentially, but monitoring an actual program this way was too difficult, so I switched to wiring the Arduino to the data lines instead. That will show the actual ROM bytes as they were requested by the CPU for execution (as long as we tweak the monitoring program, which I had to do anyway, see below).</p>

<p>Here is the updated drawing, with the Arduino connected to the data lines, and the cart connected to data and address. I included the power connections as well, so everything needed is there. I recommend opening the <a href="/img/2021/02/6507-and-cart.fzz/">.fzz file</a> on <a href="https://fritzing.org/">Fritzing</a>, which has the pin names on the cart connector (it doesn’t resemble the connector a lot, I know; but it’s the first time I customized a part in the software).</p>

<p><img src="/img/2021/02/6507-and-cart_bb.png" alt="Drawing of 6507, cart and Arduino" class="center" /></p>

<h3 id="monitoring">Monitoring</h3>

<p>The test program generates a (slow - 10Hz) clock pulse to keep the processor running. At each pulse, it prints the hex value from the data bus in the Arduino IDE serial monitor (set the speed to 115200). It is <em>much</em> smaller than the original code, and several issues (such as use of serial I/O pins and wonky binary conversion) were fixed.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Turns an Arduino into a 10Hz clock generator (on pin A5)</span>
<span class="c1">// and a monitor for an 8-bit data bus (pins 2-9)</span>

<span class="kt">void</span> <span class="nf">setup</span><span class="p">()</span> <span class="p">{</span>
  <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">pin</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="n">pin</span> <span class="o">&lt;=</span> <span class="mi">9</span><span class="p">;</span> <span class="n">pin</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">pinMode</span><span class="p">(</span><span class="n">pin</span><span class="p">,</span> <span class="n">INPUT</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="n">pinMode</span><span class="p">(</span><span class="n">A5</span><span class="p">,</span> <span class="n">OUTPUT</span><span class="p">);</span>
  <span class="n">Serial</span><span class="p">.</span><span class="n">begin</span><span class="p">(</span><span class="mi">115200</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">loop</span><span class="p">()</span> <span class="p">{</span>
  <span class="c1">// Clock pulse</span>
  <span class="n">digitalWrite</span><span class="p">(</span><span class="n">A5</span><span class="p">,</span> <span class="n">HIGH</span><span class="p">);</span>
  <span class="n">delay</span><span class="p">(</span><span class="mi">50</span><span class="p">);</span>
  <span class="n">digitalWrite</span><span class="p">(</span><span class="n">A5</span><span class="p">,</span> <span class="n">LOW</span><span class="p">);</span>
  <span class="n">delay</span><span class="p">(</span><span class="mi">50</span><span class="p">);</span>

  <span class="c1">// Print current data bus (pins 2-9)</span>
  <span class="kt">int</span> <span class="n">data_value</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">power_of_two</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
  <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">bit</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">bit</span> <span class="o">&lt;=</span> <span class="mi">7</span><span class="p">;</span> <span class="n">bit</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">data_value</span> <span class="o">+=</span> <span class="n">digitalRead</span><span class="p">(</span><span class="n">bit</span> <span class="o">+</span> <span class="mi">2</span><span class="p">)</span> <span class="o">*</span> <span class="n">power_of_two</span><span class="p">;</span>
    <span class="n">power_of_two</span> <span class="o">*=</span> <span class="mi">2</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">data_value</span> <span class="o">&lt;</span> <span class="mh">0x10</span><span class="p">)</span> <span class="p">{</span> <span class="n">Serial</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s">"0"</span><span class="p">);</span> <span class="p">}</span>
  <span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="n">data_value</span><span class="p">,</span> <span class="n">HEX</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="lets-run-some-atari-code">Let’s run some Atari code!</h3>

<p>To test it, I’ve used a cart with <a href="https://github.com/chesterbr/2048-2600">2048 2600</a> since, as the author, I’m familiar with the code. The Stella screenshot below shows the initialization code, and we’ll be looking for the bytes (opcodes) on the right side:</p>

<p><img src="/img/2021/02/stella-output.png" alt="Stella output of 2048 2600's startup code" class="center" /></p>

<p>To be precise: once we press and release the “reset” push button, we expect the 6507 to read the address of that code (<code class="language-plaintext highlighter-rouge">F914</code>) from its <a href="https://www.pagetable.com/?p=410">standard location</a> from the cartridge, then start reading the opcodes above (<code class="language-plaintext highlighter-rouge">78</code>, <code class="language-plaintext highlighter-rouge">D8</code>, <code class="language-plaintext highlighter-rouge">A2</code>, <code class="language-plaintext highlighter-rouge">00</code>, …) in sequence, until the <code class="language-plaintext highlighter-rouge">BNE</code> instruction at <code class="language-plaintext highlighter-rouge">F91D</code> loops back to reading again from a few lines above (<code class="language-plaintext highlighter-rouge">CA</code>, <code class="language-plaintext highlighter-rouge">9A</code>, <code class="language-plaintext highlighter-rouge">48</code>, …), and repeat that a bunch of times.</p>

<p>That will be enough to show us whether this mess of wires is working - and indeed it is! Check this snippet of the serial monitor output (comments and disassembly after <code class="language-plaintext highlighter-rouge">#</code>), comparing to the values above:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...
00                  <span class="c"># Some gibberish here, until 6507 resets</span>
00
14                  <span class="c"># 6507 reads the contents of RESET vector: the lowest byte (14)...</span>
F9                  <span class="c"># ...then the highest (F9) of F914, which is where our code starts</span>
78    <span class="c"># SEI         # read from address F914</span>
D8    <span class="c"># CLD         # read from address F915</span>
D8
A2    <span class="c"># LDX #$      # read from address F916</span>
A2
00    <span class="c">#       00</span>
8A    <span class="c"># TXA         # read from address F918</span>
A8    <span class="c"># TAY         # read from address F919</span>
A8
CA    <span class="c"># DEX         # read from address F91A</span>
CA
9A    <span class="c"># TXS         # read from address F91B</span>
9A
48    <span class="c"># PHA         # read from address F91C</span>
48
D0                  <span class="c"># maybe a premature read of next instruction?</span>
00                  <span class="c"># the value that would be sent to the stack - if we had RAM :-)</span>
D0    <span class="c"># BNE</span>
FB    <span class="c">#      F91A   # address calculated as "5 bytes before"; FB here means -5</span>
A9
CA    <span class="c"># DEX         # again from address F91A</span>
9A    <span class="c"># TXS         # again from address F91B</span>
9A                  <span class="c"># ...</span>
48
48
D0
00
D0
FB
A9
CA
9A
...
</code></pre></div></div>
<p>We print the value on the data bus once per clock cycle - since instructions take a different number of clock cycles to run, we see the uneven repetitions. But overall, we are running the code in the cart - mission accomplished! 🎉</p>

<p><img src="/img/2021/02/6507-cart-breadboard-messy.jpg" alt="breadboard with 6507, cart and Arduino" class="center" /></p>

<h3 id="next-steps">Next steps</h3>

<p>Hope I don’t take as long as I did this time to continue with this experiment. I wonder if I can add the TIA at some capacity without going with a full speed clock (which will be hard to monitor without an oscilloscope, so I’m deferring as much as I can). I’ll see as I tinker. Stay tuned!</p>

<ul>
  <li><a href="/archives/2021/06/atari-2600-on-a-breadboard-part-3-tidying-up-and-adding-the-TIA-video-chipe/">Part III: TIA (Video chip)</a></li>
</ul>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Building a classic XBox to USB adapter (to use a RedOctane Ignition DDR mat to a computer)]]></title>
    <link href="https://chester.me/archives/2020/07/building-a-classic-xbox-to-usb-adapter-to-use-a-redoctane-ignition-ddr-mat-on-a-computer/"/>
    <updated>2020-07-19T00:00:00+00:00</updated>
    <id>https://chester.me/archives/2020/07/building-a-classic-xbox-to-usb-adapter-to-use-a-redoctane-ignition-ddr-mat-on-a-computer</id>
    <content type="html"><![CDATA[<p>As a <a href="https://en.wikipedia.org/wiki/Dance_Dance_Revolution">Dance Dance Revolution (DDR)</a> enthusiast on its heyday, I spent a lot of time <a href="https://chester.me/tapete/">adapting dance pads</a> to improve comfort and durability, until I <a href="https://chester.me/ignition/">got myself an Ignition pad</a>. Its thick rubber interior, superior sensors and <a href="https://en.wikipedia.org/wiki/RedOctane">RedOctane</a> (of Guitar Hero fame) quality resulted in no mis-/over-/continued registering of arrows, less knee strain and happier downstairs neighbours.</p>

<p><img src="/img/ignition/tapete.jpg" alt="My Ignition pad from the 2000s" class="center" /></p>

<p>I sold that one years ago, but having some floor space and time now, I decided to buy a “new” one on eBay. Not having a Playstation these days, I planned to use <a href="https://www.stepmania.com/">Stepmania</a> (the open-source DDR clone), but my mat was missing the USB adaptor. A Playstation-to-USB one gets recognized, but <a href="https://www.reddit.com/r/DanceDanceRevolution/comments/40k6y0/looking_for_a_red_octane_dance_pad_usb_breakaway/cywo6rs/">arrows do not register correctly</a>.</p>

<p>The adaptor I needed would plug in the XBox connector (<a href="https://en.wikipedia.org/wiki/Xbox_controller">classic XBox controllers</a> are quite close to USB in nature, as we’ll see below). They are near-impossible to find, but it seems the breakaway cable that came with the controller can be converted into such an adaptor.</p>

<!--more-->

<iframe width="700" height="393" src="https://www.youtube-nocookie.com/embed/Zt-6FxZqgYQ" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<p>The operation is trivial:</p>

<ul>
  <li>Buy <a href="https://www.ebay.com/itm/192880300626">the XBox controller breakaway cable</a>;</li>
  <li>Get any USB data cable (you likely have a dozen in your drawer);</li>
  <li>Split both cables, getting the round end of the first and the USB-A end of the other (the ones that plug on the mat and on the computer);</li>
  <li>Just connect the wires, matching the colors on each side (it seems the classic XBox controller is a USB device, just with a different plug - even the cable colors follow <a href="https://hubpages.com/technology/USB-wire-color-code-The-four-wires-inside">the standard</a>).</li>
</ul>

<p><img src="/img/2020/07/ends-wired.jpg" alt="color-matched wires between XBox controller and USB connectors" class="center" /></p>

<p>I was going to solder them together and tape (like the video), but it seemed too flimsy for me, so I soldered the wires into a protoboard, then fixed the set on a small box with my trusty <a href="https://www.supermarketbrazil.com/products/brazilian-original-epoxi-durepoxi-solder-henkel-adhesive-paste-100g-loctite">Durepoxy</a>.</p>

<p><img src="/img/2020/07/protoboard-on-box.jpg" alt="Durepoxy is great. And nowhere to be found in Canada. It is likely a health hazard" class="center" /></p>

<p>Ugly, I know, but sturdy. Once the box was closed, had some cleanup and electrical tape finished, it looked much better:</p>

<p><img src="/img/2020/07/box-final.jpg" alt="Noice" class="center" /></p>

<p>As for the software, I used this <a href="https://sourceforge.net/projects/xhd/">macOS XBox Controller Driver</a>. To test it (and Mac controllers in general), I recommend <a href="https://apps.apple.com/ca/app/controllers-lite/id673660806?mt=12">Controllers Lite</a>.</p>

<p><img src="/img/2020/07/controllers-lite.png" alt="Controllers lite - my adaptor works \o/" class="center" /></p>

<p>With that set, I downloaded <a href="https://github.com/stepmania/stepmania/releases">Stepmania</a>, addded some songs from the usual places, and spent a great afternoon playing! 🕺</p>

<p><img src="/img/2020/07/mat-and-stepmania.jpg" alt="&quot;Let's MAX, I mean... who do you verb Stepmania?&quot;" class="center" /></p>

<p>A positive surprise was that no remapping was needed: Controllers Lite shows the arrows registering both as axis and button presses, and StepMania recognizes the arrows as it should, the A/B buttons as OK/back, and even the cancellation shortcuts with select+start.</p>

<p>P.S.: If you can’t find the original XBox breakaway cable, <a href="https://www.instructables.com/id/Clean-and-EASY-convert-original-Xbox-controller-to/">this page</a> says an XBox 360 one (which is already USB on the other end) will do, as long as you sand the connector a bit to make it fit on the mat/controller. I’m curious to try that.</p>

<p>Photos: <a href="http://raquelcamargo.com/pt/">Raquel Camargo</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Detecting TV power state via USB]]></title>
    <link href="https://chester.me/archives/2020/06/detecting-tv-power-state-via-usb/"/>
    <updated>2020-06-03T00:00:00+00:00</updated>
    <id>https://chester.me/archives/2020/06/detecting-tv-power-state-via-usb</id>
    <content type="html"><![CDATA[<p>One convenient feature of Chromecast is that it turns on your TV automatically when you connect to it - as long as your TV has HDMI-CEC. Mine doesn’t, but it is already <a href="https://chester.me/archives/2017/12/voice-control-for-a-non-smart-tv-with-google-home-raspberry-pi-lirc-nginx-lua-ifttt/">remote-controlled via Raspberry Pi</a>, and thanks to <a href="https://www.home-assistant.io/">Home Assistant</a>, I can easily detect when the Chromecast is in use, so in theory I could just blast a command to the IR when it switches away from “off”.</p>

<p>There is just one problem: Home Assistant doesn’t know whether the TV is on or off. If it is already on when I start casting, sending the command will turn it off - the opposite of what I want. Also, I would like to turn the TV off when not using the Chromecast (something it doesn’t seem to do, even with HDMI-CEC).</p>

<!--more-->

<h2 id="detecting-power-via-usb">Detecting power via USB</h2>

<p>I am not the only one: people have already <a href="https://raspberrypi.stackexchange.com/questions/8224/detecting-tv-power-on-off-without-cec">asked</a> around, and one of the ideas was to use the USB port (that a lot of sets have for playing media or firmware upgrades). A quick multimeter test on mine showed that it is only powered when the TV is on, so it’s just a question of monitoring it and forwarding the info to Home Assistant.</p>

<h3 id="attempt-1-raspberry-pi-gpio-spoiler--for-polling--for-home-assistant">Attempt 1: Raspberry Pi GPIO (spoiler: 👍 for polling, 👎 for Home Assistant)</h3>

<p>The simplest idea for monitoring the state would be to connect the power output of the TV to a GPIO pin on the Raspberry Pi. However, those pins expect 3.3V, and USB operates at 5V, so a direct connection would fry the RPi. I knew I’d need what is known as a “voltage divider” - a setup that (in its simplest form) uses two resistors to extract a lower voltage from a higher one.</p>

<p>The good news: <a href="https://raspberrypi.stackexchange.com/a/99197/100572">someone</a> had already done the homework for me, noticing the Rasperry Pi already provides one of the resistors and calculating the value of the other. So it was as simple as:</p>

<ul>
  <li>Connecting the TV USB GND to a Pi GND pin (e.g., pin 9);</li>
  <li>Connecting the TV USB 5V to a 4.7kΩ resistor, and the resistor to a Pi GPIO pin (e.g., GPIO17, which is pin 11 <a href="https://raspberrypi.stackexchange.com/a/12967/100572">on the board</a>);</li>
  <li>Software-enable the pull-down resistor on that pin and read it to know if the TV is on or off.</li>
</ul>

<p>You can reuse any cable with a USB connector - they are usually <a href="https://turbofuture.com/computers/Color-Coded-Wire-inside-the-USB">color-coded</a>, red being the 5v, and the silver, non-isolated wire is GND. Raspberry Pi pinout is <a href="https://turbofuture.com/computers/Color-Coded-Wire-inside-the-USB">here</a>, but here is my wiring for this setup:</p>

<p><img src="/img/2020/06/tv-usb-raspberry.png" alt="Schematics of USB-to-Raspberry connection with the resistor that completes the voltage divider" class="center" /></p>

<p>To test it, we can invoke <code class="language-plaintext highlighter-rouge">python2</code> and type some Python code:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">RPi.GPIO</span> <span class="k">as</span> <span class="n">GPIO</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="n">GPIO</span><span class="p">.</span><span class="n">setmode</span><span class="p">(</span><span class="n">GPIO</span><span class="p">.</span><span class="n">BOARD</span><span class="p">)</span>
<span class="n">GPIO</span><span class="p">.</span><span class="n">setup</span><span class="p">(</span><span class="mi">11</span><span class="p">,</span> <span class="n">GPIO</span><span class="p">.</span><span class="n">IN</span><span class="p">,</span> <span class="n">pull_up_down</span><span class="o">=</span><span class="n">GPIO</span><span class="p">.</span><span class="n">PUD_DOWN</span><span class="p">)</span>
<span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
  <span class="k">print</span> <span class="n">GPIO</span><span class="p">.</span><span class="nb">input</span><span class="p">(</span><span class="mi">11</span><span class="p">)</span>
  <span class="n">time</span><span class="p">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</code></pre></div></div>

<p>This prints <code class="language-plaintext highlighter-rouge">1</code> when the TV is off and <code class="language-plaintext highlighter-rouge">0</code> when it is off. Here is a test I did plugging and unplugging the USB to a power adaptor:</p>

<p><img src="/img/2020/06/power-detection.gif" alt="" class="center" /></p>

<p>On the actual TV, it takes some time to pick up the “off” state because the TV slowly reduces the output instead of cutting it straight (I checked with a multimeter, it takes quite a few seconds to go from ~5V to ~0).</p>

<p>Anyway, it shows that the hardware works, so we can move on to exposing it in Home Assistant. It will appear on the panel as a <a href="https://www.home-assistant.io/integrations/rpi_gpio/"><code class="language-plaintext highlighter-rouge">binary_sensor</code></a> just by adding these lines to the <code class="language-plaintext highlighter-rouge">binary_sensor</code> section of <code class="language-plaintext highlighter-rouge">configuration.yaml</code> (creating one if you don’t have it):</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">binary_sensor</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="na">platform</span><span class="pi">:</span> <span class="s">rpi_gpio</span>
    <span class="na">ports</span><span class="pi">:</span>
      <span class="na">17</span><span class="pi">:</span> <span class="s">PIR TV</span> <span class="c1"># rpi_gpio uses BCM notation =&gt; physical pin 11 = GPIO17</span>
    <span class="na">pull_mode</span><span class="pi">:</span> <span class="s">DOWN</span>
</code></pre></div></div>

<p>And it <em>almost</em> works 🥺. Even though the sensor shows up on the interface (alongside the Chromecast, on the screenshot), and switches to <code class="language-plaintext highlighter-rouge">on</code> when I turn the TV on, it does not switch to <code class="language-plaintext highlighter-rouge">off</code> when I turn the TV off. Never.</p>

<p><img src="/img/2020/06/home-assistant-direct-pi-connection.png" alt="" class="center" /></p>

<p>It happens that (unsurprisingly), Home Assistant <a href="https://github.com/home-assistant/core/blob/dev/homeassistant/components/rpi_gpio/__init__.py#L51">code</a> is more efficient than mine, using threaded callbacks instead of checking the state every second (<a href="https://sourceforge.net/p/raspberry-gpio-python/wiki/Inputs/">details</a>).</p>

<p>So I changed my test code to match Home Assistant’s:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">RPi.GPIO</span> <span class="k">as</span> <span class="n">GPIO</span>
<span class="n">GPIO</span><span class="p">.</span><span class="n">setmode</span><span class="p">(</span><span class="n">GPIO</span><span class="p">.</span><span class="n">BOARD</span><span class="p">)</span>
<span class="n">GPIO</span><span class="p">.</span><span class="n">setup</span><span class="p">(</span><span class="mi">11</span><span class="p">,</span> <span class="n">GPIO</span><span class="p">.</span><span class="n">IN</span><span class="p">,</span> <span class="n">pull_up_down</span><span class="o">=</span><span class="n">GPIO</span><span class="p">.</span><span class="n">PUD_DOWN</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">cb</span><span class="p">(</span><span class="n">port</span><span class="p">):</span>
  <span class="k">print</span> <span class="n">GPIO</span><span class="p">.</span><span class="nb">input</span><span class="p">(</span><span class="n">port</span><span class="p">)</span>
<span class="n">GPIO</span><span class="p">.</span><span class="n">add_event_detect</span><span class="p">(</span><span class="mi">11</span><span class="p">,</span> <span class="n">GPIO</span><span class="p">.</span><span class="n">BOTH</span><span class="p">,</span> <span class="n">callback</span><span class="o">=</span><span class="n">cb</span><span class="p">,</span> <span class="n">bouncetime</span><span class="o">=</span><span class="mi">1000</span><span class="p">)</span>
</code></pre></div></div>

<p>Instead of continuously printing, it will just output the current state when it changes, and works as expected fine when plugging/unplugging from the power adaptor.</p>

<p>When connected to the TV, turning it of produces a “1”, but turning it off <em>also</em> produces a “1”. It isn’t a bounce issue (I tried changing <code class="language-plaintext highlighter-rouge">bouncetime</code> to no avail).</p>

<p>My other guess is that the state returned by <code class="language-plaintext highlighter-rouge">GPIO.input</code> isn’t updated when the <code class="language-plaintext highlighter-rouge">cb</code> function is fired by the callback, likely due to the slow discharge. To confirm that, I include a little pause (200ms) on the function before I read the state, and, lo and behold, that fixes the problem. The code above consistently prints “0” when I turn the TV off:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">RPi.GPIO</span> <span class="k">as</span> <span class="n">GPIO</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="n">GPIO</span><span class="p">.</span><span class="n">setmode</span><span class="p">(</span><span class="n">GPIO</span><span class="p">.</span><span class="n">BOARD</span><span class="p">)</span>
<span class="n">GPIO</span><span class="p">.</span><span class="n">setup</span><span class="p">(</span><span class="mi">11</span><span class="p">,</span> <span class="n">GPIO</span><span class="p">.</span><span class="n">IN</span><span class="p">,</span> <span class="n">pull_up_down</span><span class="o">=</span><span class="n">GPIO</span><span class="p">.</span><span class="n">PUD_DOWN</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">cb</span><span class="p">(</span><span class="n">port</span><span class="p">):</span>
  <span class="n">time</span><span class="p">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.2</span><span class="p">)</span> <span class="c1"># Pause for 200ms
</span>  <span class="k">print</span> <span class="n">GPIO</span><span class="p">.</span><span class="nb">input</span><span class="p">(</span><span class="n">port</span><span class="p">)</span>
<span class="n">GPIO</span><span class="p">.</span><span class="n">add_event_detect</span><span class="p">(</span><span class="mi">11</span><span class="p">,</span> <span class="n">GPIO</span><span class="p">.</span><span class="n">BOTH</span><span class="p">,</span> <span class="n">callback</span><span class="o">=</span><span class="n">cb</span><span class="p">,</span> <span class="n">bouncetime</span><span class="o">=</span><span class="mi">1000</span><span class="p">)</span>
</code></pre></div></div>

<p>I <em>could</em> change the Home Assistant code on the Pi to do that (maybe accepting an optional delay parameter in the same way that it accepts a bounce time), but I had a hard time running their tests, so it will be a while before I can submit a contribution to the project (which may or may not be accepted), so for now I went with ha different approach:</p>

<h3 id="attempt-2-arduino-nodemcu-esp8266-gpio-">Attempt 2: Arduino (NodeMcu ESP8266) GPIO (👍)</h3>

<p>To be honest, I haven’t been using the Raspberry Pi GPIO for a while precisely because of this type of issue: running I/O on a non-realtime (or at least not very predictable OS) leads to inconsistent reads. Instead, I’ve switched all the I/O on my home automation to a separate board (a <a href="https://www.dx.com/p/esp8266-esp-12-nodemcu-lua-wifi-internet-things-development-board-esp8266-nodemcu-v3-wireless-module-for-arduino-compatible-black-2016051.html">NodeMcu Lua ESP8266</a>, which behaves like an Arduino, but is more compact <em>and</em> has built-in Wi-Fi).</p>

<p>The board runs <a href="https://github.com/1technophile/OpenMQTTGateway">OpenMQTTGateway</a>, a software that makes it easy to forward hardware events to the Raspberry Pi (<a href="https://chester.me/archives/2019/07/cheap-433mhz-leak-detectors-home-assistant-arduino-openmqttgateway-telegram-alerts/">here</a> is how I set it up to work with Home Assistant) and brings us the best of two worlds: the stability of the microcontroller and the software flexibility of the Pi.</p>

<p>For this setup, we don’t have the Rapsberry-pi-provided pull-down, so we’ll need two resistors to provide the voltage divider (i.e., bring the TV USB 5v down to 3.3v that the board can monitor).</p>

<p>There is <a href="https://www.youtube.com/watch?v=XxLKfAZrhbM">a formula</a> that you can use to find a pair of resistors, but I was lazy and just used <a href="https://www.allaboutcircuits.com/tools/voltage-divider-calculator/">this calculator</a>, throwing 5V as the voltage input and playing with values until I got a pair that I had lying around (R1 = 75Ω and R2 = 150Ω) and gave an approximate 3.3v output.</p>

<p>Here is how I wired them (you must choose a pin you are not using for some other I/O):</p>

<p><img src="/img/2020/06/tv-usb-esp.png" alt="Schematics of USB-to-ESP connection" class="center" /></p>

<p>Opening OpenMQTTGateway’s <a href="https://github.com/1technophile/OpenMQTTGateway">source code</a> in the <a href="https://www.arduino.cc/en/Main/Software">Arduino IDE</a>, I enabled the monitoring by removing the trailing <code class="language-plaintext highlighter-rouge">//</code> from this line in <code class="language-plaintext highlighter-rouge">User_config.h</code>:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define ZsensorGPIOInput "GPIOInput" //ESP8266, Arduino, ESP32
</span></code></pre></div></div>

<p>and in <code class="language-plaintext highlighter-rouge">config_GPIOInput.h</code>, I configured the pin I’m using by adding it to the first <code class="language-plaintext highlighter-rouge">#define</code> on the block below <code class="language-plaintext highlighter-rouge">PIN_DEFINITIONS</code> (the correct number <a href="https://randomnerdtutorials.com/esp8266-pinout-reference-gpios/">depends on your board</a>). In the one depicted above, D5 means GPIO14, so we’d go with:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#if defined(ESP8266) || defined(ESP32)
</span>  <span class="cp">#define GPIOInput_PIN 14
#else
</span>  <span class="cp">#define GPIOInput_PIN 7
#endif
</span></code></pre></div></div>

<p>Of course there are other configurations you may want to change to ensure the software connects to your Wi-Fi network, and that the Raspberry Pi can subscribe to the events published by OpenMQTTGateway (see the docs and <a href="https://chester.me/archives/2019/07/cheap-433mhz-leak-detectors-home-assistant-arduino-openmqttgateway-telegram-alerts/">my previous post</a>).</p>

<p>Once everything is set up, it is possible to ssh into the Raspberry Pi and monitor the queue with:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mosquitto_sub -t \# -v
</code></pre></div></div>

<p>As the TV is turned on and off, the following events appear:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>home/OpenMQTTGateway/GPIOInputtoMQTT {"gpio":"HIGH"}
home/OpenMQTTGateway/GPIOInputtoMQTT {"gpio":"LOW"}
</code></pre></div></div>

<p>That allowed me to add a <code class="language-plaintext highlighter-rouge">binary_sensor</code> to Home Assistant’s <code class="language-plaintext highlighter-rouge">configuration.yaml</code>. Like I did with the sensors in the aforementioned post, I used the <code class="language-plaintext highlighter-rouge">mqtt</code> platform, telling it to watch for the messages above:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">binary_sensor</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="na">platform</span><span class="pi">:</span> <span class="s">mqtt</span>
    <span class="na">name</span><span class="pi">:</span> <span class="s">Living Room TV Power</span>
    <span class="na">state_topic</span><span class="pi">:</span> <span class="s2">"</span><span class="s">home/OpenMQTTGateway/GPIOInputtoMQTT"</span>
    <span class="na">payload_on</span><span class="pi">:</span> <span class="s1">'</span><span class="s">{"gpio":"HIGH"}'</span>
    <span class="na">payload_off</span><span class="pi">:</span> <span class="s1">'</span><span class="s">{"gpio":"LOW"}'</span>
    <span class="na">device_class</span><span class="pi">:</span> <span class="s">power</span>
</code></pre></div></div>

<p>That makes the switch appear, and this time it reacts to on and off!</p>

<h2 id="using-the-power-state-as-a-condition-to-toggle-tv-state-when-chromecast-playsstops">Using the power state as a condition to toggle TV state when Chromecast plays/stops</h2>

<p>The final goal is to to monitor my Chromecast (<code class="language-plaintext highlighter-rouge">media_player.living_room_tv</code>)’s <code class="language-plaintext highlighter-rouge">state</code>. When it changes from <code class="language-plaintext highlighter-rouge">off</code> to anything else, I want it to send a power toggle command to my TV (which I defined as the <code class="language-plaintext highlighter-rouge">switch.tv</code> when I set up IR) - but only if the sensor we just installed says the TV is <code class="language-plaintext highlighter-rouge">off</code>.</p>

<p>In Home Assistant language, that translates to these lines in <code class="language-plaintext highlighter-rouge">automations.yaml</code>:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="pi">-</span> <span class="na">alias</span><span class="pi">:</span> <span class="s">tv_on_when_start_casting</span>
  <span class="na">trigger</span><span class="pi">:</span>
    <span class="na">platform</span><span class="pi">:</span> <span class="s">state</span>
    <span class="na">entity_id</span><span class="pi">:</span> <span class="s">media_player.living_room_tv</span>
    <span class="na">from</span><span class="pi">:</span> <span class="s1">'</span><span class="s">off'</span>
  <span class="na">condition</span><span class="pi">:</span>
    <span class="na">condition</span><span class="pi">:</span> <span class="s">state</span>
    <span class="na">entity_id</span><span class="pi">:</span> <span class="s">binary_sensor.living_room_tv_power</span>
    <span class="na">state</span><span class="pi">:</span> <span class="s1">'</span><span class="s">off'</span>
  <span class="na">action</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="na">service</span><span class="pi">:</span> <span class="s">switch.toggle</span>
    <span class="na">entity_id</span><span class="pi">:</span> <span class="s">switch.tv</span>
</code></pre></div></div>

<p>Conversely, if I want it to turn off the TV when I’m done with the Chromecast (and again, only if I haven’t turned it off already):</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="pi">-</span> <span class="na">alias</span><span class="pi">:</span> <span class="s">tv_off_when_stop_casting</span>
  <span class="na">trigger</span><span class="pi">:</span>
    <span class="na">platform</span><span class="pi">:</span> <span class="s">state</span>
    <span class="na">entity_id</span><span class="pi">:</span> <span class="s">media_player.living_room_tv</span>
    <span class="na">to</span><span class="pi">:</span> <span class="s1">'</span><span class="s">off'</span>
  <span class="na">condition</span><span class="pi">:</span>
    <span class="na">condition</span><span class="pi">:</span> <span class="s">state</span>
    <span class="na">entity_id</span><span class="pi">:</span> <span class="s">binary_sensor.living_room_tv_power</span>
    <span class="na">state</span><span class="pi">:</span> <span class="s1">'</span><span class="s">on'</span>
  <span class="na">action</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="na">service</span><span class="pi">:</span> <span class="s">switch.toggle</span>
    <span class="na">entity_id</span><span class="pi">:</span> <span class="s">switch.tv</span>
</code></pre></div></div>

<p>A few quirks still remain. For example, if I switch sources without giving the setup a few seconds to catch up, the TV will turn off, but not on again. Worse: if I switch to another HDMI source without disconnecting, the Chromecast will become idle after a while, and turn the TV off at the worst possible moment.</p>

<p>But those are likely fixable by tweaking the automations, and in general I just start casting and everything works!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[ZX Spectrum Next]]></title>
    <link href="https://chester.me/archives/2020/04/zx-spectrum-next/"/>
    <updated>2020-04-25T00:00:00+00:00</updated>
    <id>https://chester.me/archives/2020/04/zx-spectrum-next</id>
    <content type="html"><![CDATA[<p>The <a href="https://www.kickstarter.com/projects/1835143999/zx-spectrum-next">ZX Spectrum Next</a> was a Kickstarter-backed initiative aiming to recreate the iconic ZX Spectrum using FPGA and lots of ingenuity. I am a bit too Marie-Kondo-ed for physical retrocomputing these days, and, on top of that, have been skeptical of such projects (for <a href="https://vintageisthenewold.com/failed-campaign-recreated-zx-spectrum-backers-unlikely-to-get-their-devices/">good reasons</a>).</p>

<p>However, this one had names like <a href="https://www.victortrucco.com/">Victor Trucco</a> (one of the most respected Brazilian retrocomputing hackers) and <a href="https://www.theregister.co.uk/2018/04/26/rick_dickinson_dies/">Rick Dickinson</a> (industrial designer behind several Sinclair computer cases, who sadly passed away before it was finished) behind it, so in May 2017 I gave it a shot and backed the campaign in exchange for a unit.</p>

<p>Expected to ship January 2018, it was delayed for more than two years, but for good reasons: the people behind the project would not accept anything but the best quality, continuously pressuring manufacturers to go on-spec. And it was worht the wait - the computer is sturdy and gorgeous:</p>

<p><a href="/img/2020/04/next_large.jpg"><img src="/img/2020/04/next.jpg" alt="click to enlarge" class="center" /></a></p>

<!--more-->

<p><a href="/img/2020/04/keyboard_large.jpg"><img src="/img/2020/04/keyboard.jpg" alt="click to enlarge" class="center" /></a></p>

<h3 id="zx-what">ZX what?</h3>

<p>The ZX Spectrum was one of the most influential computers from the 80s. It matched the (relatively) low price of its Sinclair predecessors with capabilities like color graphics, sound and enough RAM made it capable of all sorts of tasks - in particular games.</p>

<p>In Brazil (where, at the time, it was legal to clone any foreign computer) we had the <a href="https://www.youtube.com/watch?v=ky07bgePeUk">TK90X</a>, a clone of the ZX Spectrum 48K, which I was lucky enough to have access to during my formative years. Here is one (from my retrocollector days), with a few software titles in cassete tapes, and a homemad sound chip expansion module:</p>

<p><a href="/img/2020/04/tk90x_large.jpg"><img src="/img/2020/04/tk90x.jpg" alt="click to enlarge" class="center" /></a></p>

<p>(I <em>did</em> eventually own a ZX Spectrum +2 as a retrocomputing enthusiast, but that’s <a href="https://chester.me/spectrumplus2/">another story</a> entirely. Back to the ZX Spectrum Next!)</p>

<h3 id="packaging-and-manual-also-unboxing-video-">Packaging and Manual (also: unboxing video 🙈)</h3>

<p>Computer boxes at that time were neitehr the unimaginative packaging of typical PCs, nor the sterile whiteness of Apple ones. They used to showcase what the computer could do, and the Next goes with that idea, but with a modern look. I loved it.</p>

<p><a href="/img/2020/04/box_front_large.jpg"><img src="/img/2020/04/box_front.jpg" alt="click to enlarge" class="center" /></a></p>

<p><a href="/img/2020/04/box_back_large.jpg"><img src="/img/2020/04/box_back.jpg" alt="click to enlarge" class="center" /></a></p>

<p>The manual is another highlight: like manuals of the era, it covers everything from handling the hardware to teaching you BASIC - in this case, a souped-up version that unleashes the new hardware features, yet feels like the classic.</p>

<p>I am not a huge fan of unboxing videos, but the packaging of this computer deserved some special attention, so here it is:</p>

<iframe width="700" height="393" src="https://www.youtube.com/embed/4vdH_S0r1sw" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<h3 id="playing-with-it">Playing with it</h3>

<p>Between the material and the <a href="https://www.specnext.com/">portal</a>, there is a lot of material covering the Next, so I decided to just post a couple videos made right when I unboxed it.</p>

<p>The first one shows me turning it on and (after the one-time configuration screens) typing the classic “Hello World” program.</p>

<iframe width="700" height="393" src="https://www.youtube.com/embed/DDQd_jlDVbw" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<p>On the second one, I recreate a prototype “game” that draws a glyph on the screen and moves it in the four directions when directional keys are pressed. It’s a bit long, and the result won’t beat Fortnite in popularity so soon, but it shows how fun it is to just play freely in BASIC. Was happy doing it back then, am happy doing it now!</p>

<iframe width="700" height="393" src="https://www.youtube.com/embed/ZJqOoa5PtAk" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<p><a href="/img/2020/04/game_large.jpg"><img src="/img/2020/04/game.jpg" alt="click to enlarge" class="center" /></a></p>

<p><a href="/img/2020/04/me_large.jpg"><img src="/img/2020/04/me.jpg" alt="click to enlarge" class="center" /></a></p>

<h3 id="credits">Credits</h3>

<p>Video and stills by <a href="https://www.youtube.com/raquelcamargo">Raquel Camargo</a></p>

<p>TK90x photo by <a href="https://vimeo.com/edunogueira">Carlos Eduardo Nogueira</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Enable dynamic DNS (DynDNS, Duck DNS, etc.) inside networks without NAT loopback support on router]]></title>
    <link href="https://chester.me/archives/2019/08/a-fix-for-domestic-dynamic-dns-inside-network/"/>
    <updated>2019-08-18T00:00:00+00:00</updated>
    <id>https://chester.me/archives/2019/08/a-fix-for-domestic-dynamic-dns-inside-network</id>
    <content type="html"><![CDATA[<p>Dynamic DNS providers like <a href="https://dyn.com/dns/">DynDNS</a> or <a href="https://www.duckdns.org">Duck DNS</a> are great to let you access software like <a href="https://www.home-assistant.io/">Home Assistant</a> running on your <a href="https://www.raspberrypi.org/documentation/configuration/security.md">properly secured</a> computer or Raspberry Pi from anywhere.</p>

<p>One problem that I was having with them: the custom URL did not work <em>inside</em> my network, just outside. That happens because my router does not support <a href="https://en.wikipedia.org/wiki/Network_address_translation#NAT_loopback">NAT loopback</a>, blocking any requests from the internal network to the external IP (which is what my custom domain points to).</p>

<!--more-->

<p>On a computer, there is an easy fix. Let’s assume your custom domain is <code class="language-plaintext highlighter-rouge">foobar.duckdns.org</code>, and the <em>internal</em> IP (the one that you configured the router to forward a given port to) is 1.2.3.4. Adding a line like this to <code class="language-plaintext highlighter-rouge">/etc/hosts</code> (and commenting it out with <code class="language-plaintext highlighter-rouge">#</code> if the computer ever leaves the house) does it:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>foobar.duckdns.org 1.2.3.4
</code></pre></div></div>

<p>For mobile devices, it isn’t that easy: neither Android, nor iOS expose <code class="language-plaintext highlighter-rouge">/etc/hosts</code>. And those devices enter and leave the house all the time, making it impractical anyway.</p>

<p>The workaround: since I already have the Raspberry Pi lying around, I installed <code class="language-plaintext highlighter-rouge">dnsmasq</code> (a lightweight DNS server) on it:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt-get <span class="nb">install </span>dnsmasq
</code></pre></div></div>

<p>and opened the firewall for its port, so my mobile devices can use that DNS when they are inside the network:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>ufw allow dns
</code></pre></div></div>

<p>Several online tutorials suggest config changes (such as enabling DHCP on <code class="language-plaintext highlighter-rouge">dnsmasq</code> - a no-no for my otherwise working network). I just kept the default config and added this line to <code class="language-plaintext highlighter-rouge">/etc/dnsmasq.conf</code> and restarting the service:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>address=/foobar.duckdns.org/1.2.3.4"
</code></pre></div></div>

<p>With that, the DNS server will respond with the internal IP for the custom domain:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>dig @1.2.3.4 foobar.duckdns.org

<span class="p">;</span> &lt;&lt;<span class="o">&gt;&gt;</span> DiG 9.10.6 &lt;&lt;<span class="o">&gt;&gt;</span> @1.2.3.4 foobar.duckdns.org
...
<span class="p">;;</span> Got answer:
<span class="p">;;</span> -&gt;&gt;HEADER<span class="o">&lt;&lt;-</span> <span class="no">opcode</span><span class="sh">: QUERY, status: NOERROR, id: 10291
;; flags: qr aa rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
...
;; ANSWER SECTION:
foobar.duckdns.org.  0       IN      A       1.2.3.4
...
</span></code></pre></div></div>

<p>and everything else will go to the normal DNS server for normal resolution:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>dig @1.2.3.4 google.com

<span class="p">;</span> &lt;&lt;<span class="o">&gt;&gt;</span> DiG 9.10.6 &lt;&lt;<span class="o">&gt;&gt;</span> @1.2.3.4 google.com
...
<span class="p">;;</span> Got answer:
<span class="p">;;</span> -&gt;&gt;HEADER<span class="o">&lt;&lt;-</span> <span class="no">opcode</span><span class="sh">: QUERY, status: NOERROR, id: 55137
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
...
;; ANSWER SECTION:
google.com.             171     IN      A       172.217.165.14
...
</span></code></pre></div></div>

<p>The final step was to edit the Wi-Fi connection on the devices, so they would ask <code class="language-plaintext highlighter-rouge">dnsmasq</code> for names when inside the network. iOS was the easiest: you just click <code class="language-plaintext highlighter-rouge">Configure DNS</code>, switch to <code class="language-plaintext highlighter-rouge">Manual</code>, remove the auto-configured value(s) and add <code class="language-plaintext highlighter-rouge">1.2.3.4</code>. Android requires changing the whole <code class="language-plaintext highlighter-rouge">IP settings</code> to <code class="language-plaintext highlighter-rouge">Static</code> (which also means you’ll need an IP assigned to your mobile phone on your router) and enter the information manually.</p>

<p>But that is a minor nuisance (that I only had to go through once). After that, the devices work inside and outside the house (which is great for Home Assistant, in particular if you have security things you want to check from away). The downside: if the Pi is down, the devices won’t have internet (which is why I kept the computer on the ‘/etc/hosts’ solution), but you can always switch back (or to data) if that happens. Overall, I’m happy now.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[(Cheap) 433Mhz Leak Detectors in Home Assistant via Arduino + OpenMQTTGateway (with Telegram alerts)]]></title>
    <link href="https://chester.me/archives/2019/07/cheap-433mhz-leak-detectors-home-assistant-arduino-openmqttgateway-telegram-alerts/"/>
    <updated>2019-07-30T00:00:00+00:00</updated>
    <id>https://chester.me/archives/2019/07/cheap-433mhz-leak-detectors-home-assistant-arduino-openmqttgateway-telegram-alerts</id>
    <content type="html"><![CDATA[<p>Water incidents in a condo can be catastrophic, and surely things like shutting your main water valve when you go out for long periods and having the proper coverage in your insurance are important. But for added peace of mind, leak detectors aren’t a bad idea.</p>

<p>When I saw these <a href="https://www.ebay.com/itm/302368775388">$3 leak detectors</a> on eBay, I decided to give them a shot. Not only for low price, but also because they used 433Mhz RF - the same tech I use to <a href="https://chester.me/archives/2017/12/controlling-rf-outlets-from-a-raspberry-pi/">voice-control my lights from a Raspberry Pi</a>.</p>

<p><img src="/img/2019/06/sensor_open.jpg" alt="" class="center" /></p>

<p>Once they arrived, I ran <code class="language-plaintext highlighter-rouge">RFSniffer</code> and indeed, when they get wet, the Raspberry Pi prints a different value for each sensor - so it should be easy to wire up an alert system… <em>right?</em></p>

<!--more-->

<h3 id="mqtt">MQTT</h3>

<p>Well, it wasn’t. I found it odd that <a href="https://www.home-assistant.io/">Home Assistant</a> doesn’t have a 433MHz input integration (despite having a few for output). The reason is that “sniffing” from Raspbian can be clunky (you need a daemon running) and unreliable (due to its non-realtime nature).</p>

<p><a href="https://technicalpickles.com/">technicalpickles</a> suggested I should check out <a href="http://mqtt.org/">MQTT</a>, so I did. It is a “publish/subscribe message transport” - something I’m familiar with (having worked with a few pub-sub systems, including the venerable IBM MQSeries <a href="https://en.wikipedia.org/wiki/MQTT">from which the “MQ” in “MQTT” comes</a>), but honestly, it felt like over-engineering at first.</p>

<p>Eventually, I realized it is more of a divide-and-conquer approach, with these parts:</p>

<ul>
  <li>A “broker” software that sits in the middle of everything.</li>
  <li>A dedicated device that monitors the RF frequency and publishes events to this broker when a sensor “says” it’s wet.</li>
  <li>A Home Assistant integration that subscribes to these events and triggers automations to notify me.</li>
</ul>

<p>Splitting things like that (and using MQTT as the glue) means I don’t have to write <em>any</em> new software:</p>

<ul>
  <li><a href="https://mosquitto.org/">Mosquitto</a> is an MQTT broker that runs on the Pi and requires no configuration at all.</li>
  <li><a href="https://github.com/1technophile/OpenMQTTGateway">OpenMQTTGateway</a> transforms Arduino-compatible devices in monitors for all sorts of inputs (including our 433Mhz RF), publishing  their signals as MQTT events into a broker.</li>
  <li>Home Assistant has an <a href="https://www.home-assistant.io/components/mqtt/">MQTT integration</a> that, once properly configured, consumes events from a broker and exposes them as <a href="https://www.home-assistant.io/components/sensor/">sensors</a>.</li>
</ul>

<h3 id="assembling-the-monitorpublisher">Assembling the monitor/publisher</h3>

<p>I got a new <a href="https://store.arduino.cc/usa/arduino-uno-rev3/">Arduino Uno</a> for the project (my other Arduino clones/models lacked the memory requirements for OpenMQTTGateway). Since it needs to send the events to the network, I added an <a href="https://www.amazon.ca/dp/B00HG82V1A/ref=pe_3034960_236394800_TE_dp_1">Ethernet Shield</a>, and for RF I used my newest <a href="https://www.dx.com/p/open-smart-long-range-433mhz-rf-wireless-transceiver-kit-for-arduino-2004619#.XT5sQCUpCtE">Long Range 433Mhz RF Receiver module</a>. The long range and built-in antenna made this my receiver of choice over the <a href="https://www.dx.com/p/rf-transmitter-receiver-module-433mhz-wireless-link-kit-w-spring-antennas-for-arduino-2057011#.XT5tMiUpCtF">more popular</a> RF modules - and it’s just as cheap as those.</p>

<p>By bending the data output pin on the RF receiver a little bit, the receiver can be inserted directly on the shield, just matching the VCC and GND pins with 5V and GND on the board (respectively). The data pin can be then connected to Arduino digital input 3 with a small <a href="https://www.dx.com/p/diy-male-to-female-dupont-breadboard-jumper-wires-black-multi-color-40-pcs-10cm-2045521#.XT5t8yUpCtE">breadboard jumper wire</a>.</p>

<p>The final result is a bit taller than I wished, but hey, no soldering required:</p>

<p><img src="/img/2019/06/arduino_assembled.jpg" alt="" class="center" /></p>

<h3 id="mosquitto-mqtt-broker-configuration">Mosquitto MQTT broker configuration</h3>

<p>Assuming you are using <a href="https://www.raspberrypi.org/downloads/raspbian/">Raspbian Buster</a> or later, just log on the Pi and type:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt-get <span class="nb">install </span>mosquitto mosquitto-clients
</code></pre></div></div>

<p>and you are good. Seriously, that’s it.</p>

<p>Technically you just need the <code class="language-plaintext highlighter-rouge">mosquitto</code> package, but the other one allows you to test your installation by running:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mosquitto_sub <span class="nt">-t</span> <span class="se">\#</span> <span class="nt">-v</span>
</code></pre></div></div>

<p>which prints all messages published to the broker. You can publish a message by opening a second terminal window and running a command like this:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mosquitto_pub <span class="nt">-t</span> <span class="s2">"some/test/topic"</span> <span class="nt">-m</span> <span class="s2">"hi this is the message"</span>
</code></pre></div></div>

<p>The first terminal will show <code class="language-plaintext highlighter-rouge">some/test/topic hi this is the message</code>, indicating <code class="language-plaintext highlighter-rouge">hi this is the message</code> was published under the topic <code class="language-plaintext highlighter-rouge">some/test/topic</code>.</p>

<h3 id="openmqttgateway-configuration">OpenMQTTGateway configuration</h3>

<p>This project’s <a href="https://github.com/1technophile/OpenMQTTGateway/wiki">wiki</a> contains several configuration guides, including <a href="https://github.com/1technophile/OpenMQTTGateway/wiki/Arduino-RF-Send-and-Receive">one for my setup</a>, that is, an Arduino reading RF signals and publishing to a MQTT broker.</p>

<p>Here are the changes I made to <a href="https://github.com/1technophile/OpenMQTTGateway/blob/development/main/User_config.h">User_config.h</a> (after downloading <a href="https://github.com/1technophile/OpenMQTTGateway/releases">the “CODE-“ release</a> and moving the <code class="language-plaintext highlighter-rouge">lib</code> folder as explained on the wiki):</p>

<ul>
  <li>After <code class="language-plaintext highlighter-rouge">DEFINE THE MODULES YOU WANT BELOW</code>, uncomment (that is, remove the <code class="language-plaintext highlighter-rouge">//</code> from):</li>
</ul>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define ZgatewayRF     "RF"       //ESP8266, Arduino, ESP32
</span></code></pre></div></div>

<ul>
  <li>
    <p>Leave all other <code class="language-plaintext highlighter-rouge">##define Z...</code> lines commented (with <code class="language-plaintext highlighter-rouge">//</code>).</p>
  </li>
  <li>
    <p>In the line <code class="language-plaintext highlighter-rouge">char mqtt_server[40] = "..."</code>, put the IP address of the Raspberry Pi (between the quotes).</p>
  </li>
  <li>
    <p>Replace the zeros in the line <code class="language-plaintext highlighter-rouge">const byte ip[] = { 0, 0, 0, 0 }; //ip adress</code> with an IP address for the Ethernet Shield that is compatible with the network (even though the comments say the software supports DHCP, it wasn’t working for me).</p>
  </li>
  <li>
    <p><strong>IMPORTANT</strong>: Uncomment the line below so each sensor publishes events to a specific MQTT topic (instead of a single topic for all of them, which results in a barrage of <code class="language-plaintext highlighter-rouge">No matching payload found for entity: ... with state_topic: ...'</code>).</p>
  </li>
</ul>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define valueAsASubject true
</span></code></pre></div></div>

<p>Uploading a sketch with those changes will make the Arduino connect to your broker (Serial Monitor on the IDE will help you debugging; fiddle with baud speed until you see text instead of garbage).</p>

<p>If you still have <code class="language-plaintext highlighter-rouge">mosquitto_sub -t \# -v</code> open, you should see something like:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>home/OpenMQTTGateway/LWT online
home/OpenMQTTGateway/version 0.9.1
</code></pre></div></div>

<p>and whenever a sensor gets wet:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>home/OpenMQTTGateway/433toMQTT/VALUE {"value":VALUE,"protocol":...,"length":...,"delay":...}
</code></pre></div></div>

<p>where <code class="language-plaintext highlighter-rouge">VALUE</code> is (hopefully) unique for each of your sensor. In fact, you’ll see those events for all other things transmitting in the 433MHz frequency in your vicinity. I get a couple every minute in my apartment.</p>

<h3 id="home-assistant">Home Assistant</h3>

<p>First thing is to make Home Assistant aware of your new broker. You can do it on the UI (clicking on <code class="language-plaintext highlighter-rouge">+</code>, selecting “MQTT” and setting <code class="language-plaintext highlighter-rouge">localhost</code> as the broker address), or by adding to <code class="language-plaintext highlighter-rouge">configuration.yaml</code>:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">mqtt</span><span class="pi">:</span>
  <span class="na">broker</span><span class="pi">:</span> <span class="s">localhost</span>
</code></pre></div></div>

<p>That will make Home Assistant subscribe to the broker, but you need to expose the events. There are two ways:</p>

<ul>
  <li>Use the <a href="https://www.home-assistant.io/docs/automation/trigger/#mqtt-trigger">MQTT Trigger</a> and directly trigger actions when events for a specific topic (sensor) are published.</li>
  <li>Use the <a href="https://www.home-assistant.io/components/binary_sensor.mqtt/">MQTT Binary Sensor</a> to represent the actual state of the sensors in the UI.</li>
</ul>

<p>The trigger was tempting for my goal (getting notifications on my computer/phone when a potential leak is detected), but putting the sensors in the UI allows for richer integrations with other elements in the home. It also allows configuring fine details - for example, defining that a sensor is “on” when you get the message, but only gets “off” after X seconds without a message, so I went with it.</p>

<p>Just add these values to <code class="language-plaintext highlighter-rouge">configuration.yaml</code>, one <code class="language-plaintext highlighter-rouge">-</code> session for each sensor (replacing “11111111”, “22222222”, etc. with the <code class="language-plaintext highlighter-rouge">VALUE</code>s from <code class="language-plaintext highlighter-rouge">mosquitto_sub</code> or <code class="language-plaintext highlighter-rouge">RFSniffer</code>):</p>

<!--  -->
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">binary_sensor</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="na">platform</span><span class="pi">:</span> <span class="s">mqtt</span>
    <span class="na">name</span><span class="pi">:</span> <span class="s">Washroom Leak Sensor</span>
    <span class="na">payload_on</span><span class="pi">:</span> <span class="s2">"</span><span class="s">11111111"</span>
    <span class="na">value_template</span><span class="pi">:</span> <span class="s2">"</span><span class="s">{{</span><span class="nv"> </span><span class="s">value_json.value</span><span class="nv"> </span><span class="s">}}"</span>
    <span class="na">off_delay</span><span class="pi">:</span> <span class="m">10</span>
    <span class="na">device_class</span><span class="pi">:</span> <span class="s">moisture</span>
    <span class="na">state_topic</span><span class="pi">:</span> <span class="s2">"</span><span class="s">home/OpenMQTTGateway/433toMQTT/11111111"</span>
  <span class="pi">-</span> <span class="na">platform</span><span class="pi">:</span> <span class="s">mqtt</span>
    <span class="na">name</span><span class="pi">:</span> <span class="s">Kitchen Sink Leak Sensor</span>
    <span class="na">payload_on</span><span class="pi">:</span> <span class="s2">"</span><span class="s">22222222"</span>
    <span class="na">value_template</span><span class="pi">:</span> <span class="s2">"</span><span class="s">{{</span><span class="nv"> </span><span class="s">value_json.value</span><span class="nv"> </span><span class="s">}}"</span>
    <span class="na">off_delay</span><span class="pi">:</span> <span class="m">10</span>
    <span class="na">device_class</span><span class="pi">:</span> <span class="s">moisture</span>
    <span class="na">state_topic</span><span class="pi">:</span> <span class="s2">"</span><span class="s">home/OpenMQTTGateway/433toMQTT/22222222"</span>
  <span class="pi">-</span> <span class="na">platform</span><span class="pi">:</span> <span class="s">mqtt</span>
    <span class="na">name</span><span class="pi">:</span> <span class="s">Some Other Leak Sensor</span>
    <span class="s">...</span>
</code></pre></div></div>
<!--  -->

<p>Once you restart, the sensors should be available in your Home Assistant main dashboard. I manually config mine, so I built a nice little card with them:</p>

<p><img src="/img/2019/06/home_assistant_sensors.png" alt="" class="center" /></p>

<p>The page updates dynamically, so you should see them flip as you wet the sensors, then go back after 10s (or how long you set the <code class="language-plaintext highlighter-rouge">off_delay</code> above):</p>

<p><img src="/img/2019/06/home_assistant_sensors_wet.png" alt="" class="center" /></p>

<h3 id="notifications-via-telegram">Notifications via Telegram</h3>

<p>No one looks at a dashboard all the time (well, <strong>I</strong> don’t 😁), so we need a way to send notifications to my mobile phone. The <a href="https://www.home-assistant.io/components/telegram/">Telegram integration</a> is a great way to do it.</p>

<p>Just open <a href="https://telegram.me/botfather">BotFather</a> on the app, send it a <code class="language-plaintext highlighter-rouge">/newbot</code> command to create a bot for you, and get its <code class="language-plaintext highlighter-rouge">TOKEN</code>. Send any message to the newly-created bot, then visit <code class="language-plaintext highlighter-rouge">https://api.telegram.org/botTOKEN/getUpdates</code> (replace <code class="language-plaintext highlighter-rouge">TOKEN</code> accordingly) to get the <code class="language-plaintext highlighter-rouge">ID</code> of your personal user for that bot.</p>

<p>Then add these lines to <code class="language-plaintext highlighter-rouge">configuration.yaml</code>, replacing <code class="language-plaintext highlighter-rouge">TOKEN</code> and <code class="language-plaintext highlighter-rouge">ID</code> with yours.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">telegram_bot</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="na">platform</span><span class="pi">:</span> <span class="s">polling</span>
    <span class="na">api_key</span><span class="pi">:</span> <span class="s">TOKEN</span>
    <span class="na">allowed_chat_ids</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">ID</span>
<span class="na">notify</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">my_telegram</span>
    <span class="na">platform</span><span class="pi">:</span> <span class="s">telegram</span>
    <span class="na">chat_id</span><span class="pi">:</span> <span class="s">ID</span>
</code></pre></div></div>

<p>Another Home Assistant restart, and you should be able to send messages to your Telegram app by clicking on “Services” and calling <code class="language-plaintext highlighter-rouge">notify.my_telegram</code> with something like <code class="language-plaintext highlighter-rouge">{ "message": "hi" }</code>. The result:</p>

<p><img src="/img/2019/06/telegram.png" alt="" class="center" /></p>

<h3 id="wiring-it-all-together">Wiring it all together</h3>

<p>The grand finale: sending the notification when a sensor gets on (wet) or off (dry). Here is where Home Assistant shines - something like this in <code class="language-plaintext highlighter-rouge">automations.yaml</code> does the trick:</p>

<!--  -->
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="pi">-</span> <span class="na">alias</span><span class="pi">:</span> <span class="s">kitchen_sink_leak_sensor_state_change_alert</span>
  <span class="na">trigger</span><span class="pi">:</span>
    <span class="na">platform</span><span class="pi">:</span> <span class="s">state</span>
    <span class="na">entity_id</span><span class="pi">:</span> <span class="s">binary_sensor.kitchen_sink_leak_sensor</span>
  <span class="na">action</span><span class="pi">:</span>
    <span class="na">service</span><span class="pi">:</span> <span class="s">notify.my_telegram</span>
    <span class="na">data</span><span class="pi">:</span>
      <span class="na">message</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Kitchen</span><span class="nv"> </span><span class="s">Sink</span><span class="nv"> </span><span class="s">Leak</span><span class="nv"> </span><span class="s">Sensor</span><span class="nv"> </span><span class="s">is</span><span class="nv"> </span><span class="s">{{</span><span class="nv"> </span><span class="s">states('binary_sensor.kitchen_sink_leak_sensor')</span><span class="nv"> </span><span class="s">}}"</span>
</code></pre></div></div>
<!--  -->

<p>Had to add one for each sensor, but it was worth it. Here is my phone, telling me I should check the pipes under my sink:</p>

<p><img src="/img/2019/06/sensor_message_on_phone.png" alt="" class="center" /></p>

<p>How cool is that? Not at all? Well… <em>I</em> find it cool. 🤓</p>

<h3 id="possible-improvements">Possible improvements</h3>

<p>I’m quite happy with the results so far, but here are some things that could be improved:</p>

<ul>
  <li>Maybe I could bend the two pins and keep the data one straight, fitting the RF module in parallel with the other boards and reducing the height. On the other hand, this mount keeps the antenna high… decisions, decisions. 🤔</li>
  <li>The sensors aren’t bad for their price, but I found that often batteries can get displaced (depending on how you hang the sensor’s main unit). If I keep working with those, I may consider some adaptation to the case (for now, some tape did the trick).</li>
  <li>The Arduino + Ethernet shield are a good option if you have them lying around. But an <a href="https://en.wikipedia.org/wiki/ESP8266">ESP8266</a> would likely be a better choice, with its built-in Wi-Fi, small size and <a href="https://www.dx.com/p/nodemcu-lua-esp8266-wifi-development-board-2607279#.XUD5JCUpCtE">ridiculous price</a>.</li>
  <li>I use the Raspberry Pi to control <a href="https://chester.me/archives/2017/12/voice-control-for-a-non-smart-tv-with-google-home-raspberry-pi-lirc-nginx-lua-ifttt/">my TV with an IR blaster</a> and <a href="https://chester.me/archives/2017/12/controlling-rf-outlets-from-a-raspberry-pi/">lights using 433MHz RF outlets</a>, which require some software setup that often breaks as Raspbian and Home Assistant get updates. Maybe I could offload those functions to the Arduino (or ESP8266).</li>
</ul>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Fixing a loose Nintendo Switch Joy-Con]]></title>
    <link href="https://chester.me/archives/2019/07/fixing-loose-nintendo-switch-joycon/"/>
    <updated>2019-07-06T00:00:00+00:00</updated>
    <id>https://chester.me/archives/2019/07/fixing-loose-nintendo-switch-joycon</id>
    <content type="html"><![CDATA[<p>The Nintendo Switch is surprisingly sturdy, but this is a common problem: joy-cons that still click (and oh, how I <em>love</em> <a href="https://www.youtube.com/watch?v=JFu6l6Gqh7o">that click</a>) and snap to the console, but slide off when they shouldn’t (e.g., right in the middle of an online game match).</p>

<p>The cause is a plastic latch that erodes slightly with use (or maybe after it gets <a href="https://www.imore.com/how-fix-jammed-switch-controller">jammed</a> on the backplate when you mis-connect it). There is a cheap replacement for that latch that you can order <a href="https://www.amazon.ca/dp/B07D327NKW/ref=pe_3034960_233709270_TE_item">here</a>.</p>

<p>The replacement latch is made of metal (which should have been Nintendo’s original choice), and several videos (like <a href="https://www.youtube.com/watch?v=GhtTQ2LHEl0">this</a> one) show how to replace it. No soldering is required, just some careful screw removal and disassembly.</p>

<p>With the usual caveats (you do it on your own risk, it voids your warranty, etc.), here is how it went for me.</p>

<p><img src="/img/2019/06/joycon_kit.jpg" alt="" class="center" /></p>

<!--more-->

<p>Nintendo things often use tri-wing screws (in addition to the more common Phillips ones), so the kit comes with one of each screwdriver. It would be handy - if they weren’t <strong>horrible</strong>. Seriously, do yourself a favour and get <a href="https://www.amazon.ca/dp/B00KWRS3GY/">a decent tri-wing</a>.</p>

<p>Once you open the joy-con, be careful so you don’t damage the ribbon cables connecting the two halves.</p>

<p><img src="/img/2019/06/joycon_open.jpg" alt="" class="center" /></p>

<p>Remove the screws that connect the black board to the back half, and put the later aside.</p>

<p><img src="/img/2019/06/joycon_split.jpg" alt="" class="center" /></p>

<p>After you get to the black board, lift the metal blade that holds the latch in its place.</p>

<p><img src="/img/2019/06/joycon_lift.jpg" alt="" class="center" /></p>

<p>Once the blade is removed, just replace the plastic latch with a metal one from the kit, fitting it over the old one’s spring.</p>

<p><img src="/img/2019/06/joycon_replacement.jpg" alt="" class="center" /></p>

<p>When removing the old latch, be careful so the spring doesn’t fly off. Don’t worry if the spring or any buttons fall out of place - just put them back as you reassemble the controller.</p>

<p>It takes a little time, but it’s worth it: now my joy-con stays firm on its place, only sliding off when I press the button on the back.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Using Ansible to configure a Raspberry Pi (Home Assistant, LIRC, 433Utils, Z-Wave, etc.)]]></title>
    <link href="https://chester.me/archives/2019/04/using-ansible-to-configure-a-raspberry-pi-home-assistant-lirc-433utils-zwave-etc/"/>
    <updated>2019-04-13T00:00:00+00:00</updated>
    <id>https://chester.me/archives/2019/04/using-ansible-to-configure-a-raspberry-pi-home-assistant-lirc-433utils-zwave-etc</id>
    <content type="html"><![CDATA[<p>A while ago I built a couple inexpensive hacks that added <a href="/archives/2017/12/voice-control-for-a-non-smart-tv-with-google-home-raspberry-pi-lirc-nginx-lua-ifttt/">voice-command to my tv</a> and then <a href="/archives/2017/12/controlling-rf-outlets-from-a-raspberry-pi/">to my lights</a> using a Raspberry Pi, Google Home Mini, infrared and RF radio. Since then, I added other things, which prompted me to move the hacks into the popular <a href="https://www.home-assistant.io/">Home Assistant</a> home hub software.</p>

<p>With so much of my routine depending on that setup, backup became a concern. I’d make an occasional copy of the SD card with <code class="language-plaintext highlighter-rouge">dd</code>, but that isn’t a good long-term solution. Ideally, I wanted to rebuild my setup easily, should the card get corrupt, slow or just wrecked by my ongoing hacking.</p>

<p><img src="/img/2019/04/raspberry-pi-with-ir-blaster-rf-transmitter.jpg" alt="" class="center" /></p>

<p>Enter <a href="https://github.com/ansible/ansible">Ansible</a>. Sysadmins use it to write “playbooks” that represent the changes they would manually apply to a server. If done right, such playbooks can be applied to an existing server (fixing any broken configs), or a brand new one (to recreate its services).</p>

<p>The Raspberry Pi is just a (tiny) server - meaning hobbyists can use Ansible as well!</p>

<p>I’m not an Ansible expert (there are <a href="https://www.packtpub.com/books/info/authors/jesse-keating">better</a> <a href="https://www.ansiblefordevops.com/">places</a> to learn about it), but <a href="https://github.com/chesterbr/chester-ansible-configs#home-automation-raspberry-pi">my Ansible configs</a> and these notes may be useful for anyone interested in automating Raspberry Pi setups (for home automation or anything else).</p>

<!--more-->

<h3 id="the-general-idea-tldr">The general idea (TL;DR)</h3>

<p>Raspberry Pi setup is typically done by <a href="https://www.raspberrypi.org/downloads/raspbian/">downloading Raspbian</a> and <a href="https://www.balena.io/etcher/">writing it to a (micro)SD card</a>. I usually download the latest “Lite” version, so I can install just what I need and keep it snappy.</p>

<p>With that as a starting point, I created two Ansible playbooks:</p>

<ul>
  <li>The <a href="https://github.com/chesterbr/chester-ansible-configs/blob/master/rpi_provisioning.yml">provisioning playbook</a> uses the default “pi” user to configure the hostname and create a new, better-secured user. It grabs the public SSH keys from my GitHub account, ensuring only the person with matching private keys (myself) can access it.</li>
  <li>The <a href="https://github.com/chesterbr/chester-ansible-configs/blob/master/rpi.yml">main playbook</a> uses the new user to further harden the security, then configure all the things I need on my Pi (infrared, RF, Z-Wave utilities, Home Assistant, <a href="https://letsencrypt.org/">Let’s Encrypt</a> certificates, <a href="https://www.duckdns.org/">DuckDNS</a> updates, etc.).</li>
</ul>

<p>The main playbook can be ran as many times as needed - it will only configure things that aren’t already set up (Ansible peeps call that an “idempotent playbook”, I’ve heard).</p>

<h3 id="secrets-and-home-assistant">Secrets and Home Assistant</h3>

<p>Every server needs a couple passwords and keys, and since my playbooks are public, I encrypt those secrets using <a href="https://docs.ansible.com/ansible/latest/user_guide/vault.html">Ansible Vault</a>. That works nicely for everything… except Home Assistant.</p>

<p>In theory, you can provide Home Assistant secrets <a href="https://www.home-assistant.io/docs/configuration/secrets/">on a separate file</a> and just encrypt it, provision manually, etc. <a href="https://github.com/chesterbr/chester-ansible-configs/blob/f3012060c69a02d895b07fb95a921dc003615ecc/rpi.yml#L230-L244">I have tried that</a>, but every time I built the system from zero, I realized something was stored outside the standard config files (e.g., logins), or even scattered in binary datafiles (dynamic device information, some configs made on the UI, etc.).</p>

<p>After lots of frustration, I went with a different plan: I set up <a href="https://github.com/chesterbr/chester-ansible-configs/blob/23cbf9fa96f36587ea48155ce77ae13dd6dd795a/templates/ha-backup.sh.j2#L17-L25">an encrypted daily backup</a> of the Home Assistant configuration to a network drive (just a thumb drive on my router), and made the playbook <a href="https://github.com/chesterbr/chester-ansible-configs/blob/23cbf9fa96f36587ea48155ce77ae13dd6dd795a/templates/ha-backup.sh.j2#L5-L14">restore the latest backup</a> when a config-less install is detected.</p>

<p>The main downside is that my automations aren’t easily shared. But I can always write a post if I ever come with something useful (so far, they are all pretty boring 😅).</p>

<h3 id="why-dont-you-reuse-roles-from-ansible-galaxy">Why don’t you reuse roles from <a href="https://galaxy.ansible.com/">Ansible Galaxy</a>?</h3>

<p>What a <em>horrible</em> programmer I must be, because, you know, reuse is good™️… right? 😁</p>

<p>I tried to use Ansible Galaxy. Really. But the roles I found were often not generic enough (like <em>almost</em> doing what I wanted) and don’t always support Raspbian. Galaxy also lacks a robust package management system (which may not even be feasible, given the free-form, “script-y” nature of Ansible that I like so much), so I went solo.</p>

<p>Of course I took inspiration in a lot of third party roles and playbooks (on Galaxy and around the web), and highly recommend doing so.</p>

<h3 id="why-dont-you-just-use-hassio">Why don’t you just use <a href="https://www.home-assistant.io/hassio/">Hass.io</a>?</h3>

<p>Good question! Hass.io is a prebuilt SD card image that manages a minimal OS with Home Assistant baked in, automatically updated with Docker.</p>

<p>I personally found it a bit too slow (at least on earlier-gen Raspberry Pi models), and I feel more comfortable with a Debian-based system that I can poke with a stick. But hey, all the cool kids are using Docker 😜. Seriously though, if it works for you, awesome - you’ll save yourself a lot of trouble.</p>

<p>The automatic Home Assistant updates are appealing, but with my solution, I can just axe the application directory (or the whole SD card, for the matter) and run the playbook, and the latest version will be there, with my configs unchanged.</p>

<h3 id="wait-so-you-do-things-on-the-pi-without-ansible-wont-your-changes-be-overwritten-when-you-run-it">Wait, so you do things on the Pi <em>without</em> Ansible? Won’t your changes be overwritten when you run it?</h3>

<p><strong>Oh yes I do!</strong> With gusto. The main point of having a custom-made solution (other than cost and security) is tinkering. Ansible makes me confident that I can rebuild the whole thing quickly if I screw up, but yes, that requires me to keep the Ansible file up-to-date.</p>

<p>That’s actually easier than it sounds: once I’m happy with my changes, I type <code class="language-plaintext highlighter-rouge">history</code> and figure which steps (installed packages, changed config files) are <em>really</em> needed, and add those to the playbook. Run it a few times, undo some changes, check that it does nothing when changes are already there… and that’s it.</p>

<p>If the change was super complex and/or I’m afraid I forgot something, I can always run the playbooks against a fresh card, pop it in and kick the tires - it’s a great opportunity to get a fresh, snappy OS install for my tiny computer!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Renovating an Atari 2600 (AV mod + capacitor/power adaptor replacement)]]></title>
    <link href="https://chester.me/archives/2019/02/renovating-an-atari-2600-av-mod-capacitors-and-power-adaptor-replacement/"/>
    <updated>2019-02-18T00:00:00+00:00</updated>
    <id>https://chester.me/archives/2019/02/renovating-an-atari-2600-av-mod-capacitors-and-power-adaptor-replacement</id>
    <content type="html"><![CDATA[<p>A while ago I got this beautiful Atari 2600 all-black, 4-switch model - often nicknamed “Darth Vader”, for obvious reasons:</p>

<p><img src="/img/2019/02/atari.jpg" alt="" class="center" /></p>

<p>The console generates a TV signal, which the TV has to tune in just like a normal over-the-air channel. It was quite convenient at the time (and quality was good enough for the TV sets we had), but modern TVs show degradation - not to mention some can’t even pick up the faint signal - I <a href="/archives/2014/10/it-was-easy-to-plug-this-atari-dot-dot-dot/">had to hook mine to a VCR</a> that would decode the signal into A/V.</p>

<p>That quirky setup led me to make the popular A/V conversion (“mod”) - and, while at it, replace the power adaptor (with one that I can actually keep on the wall without fear of burning down the house) and capacitors (something that <a href="https://antiqueradio.org/recap.htm">should be done</a> to any vintage electronics that you want to keep humming).</p>

<!--more-->

<p>There are <a href="http://www.cheeptech.com/2600mods/2600mods.shtml">different types</a> of of mods, varying in how they mix (or split) the video and audio signal and what sort of output they generate. I opted to get an A/V output from the signals mixed by the Atari board (but before they get modulated into a TV signal), with the video one amplified by a single transistor and a couple resistors.</p>

<p>I based my mod on <a href="http://blog.tynemouthsoftware.co.uk/2015/02/atari-2600-composite-video-modification.html">this version</a>, which throws in a third 75Ω resistor that adjusts the impedance. Following the schematics there, I aligned the components like this (transistor is a 2N3904, flat side up; resistors are, from left to right, 75Ω, 3K3Ω and 2K2Ω):</p>

<p><img src="/img/2019/02/av-mod-schematics.png" alt="" class="center" /></p>

<p>There are ready-made circuit boards, but I just cut a piece of protoboard. Hint: don’t solder the cables like I did - instead, follow the “strain relief” tip <a href="https://makezine.com/2015/10/15/how-and-when-to-use-protoboard/">here</a> for better securing.</p>

<p><img src="/img/2019/02/av-mod-front.jpg" alt="" class="center" /></p>

<p>The layout reduced the number of connections, so I could just throw an extra gob of solder over the terminals before cutting to make the jumper connections. Maybe I could have used a little <em>less</em> solder, but heh, it worked.</p>

<p><img src="/img/2019/02/av-mod-back.jpg" alt="" class="center" /></p>

<p>You need to pick up <em>Video In</em> and <em>+5V</em>/<em>GND</em> from the Atari board. Mine was a Rev 16, which has those three right on the connector of the RF box. That box had to be removed anyway, and doing so opened some space for the protoboard.</p>

<p><img src="/img/2019/02/audio-out.jpg" alt="" class="center" /></p>

<p>Audio comes straight from the Atari board into the inner part of the audio jack. I strongly recommend checking this <a href="http://www.coolretroprojects.com/Atari_2600_AV_Mod_Installation_Guide.pdf">mod assembly guide</a> to figure out where to pick it up in your particular model/board revision.</p>

<p><img src="/img/2019/02/av-rear-connectors.jpg" alt="" class="center" /></p>

<p>The guide also helps figuring out which components to remove in order to reduce interference. I was able to test before removing anything from the board (just disconnected the RF box, something easy to revert if it did’t work). I just cut one resistor (R209) and one transistor (Q202).</p>

<p>This is a good moment to replace the capacitors. Again, each model has its own set, but <a href="http://atariage.com/forums/topic/262206-cap-and-vr-kit-specifications-replacement-locations-for-the-2600-variants/">this thread</a> has it figured out. I could not find a bulky C243 (guess the technology for eletrolytics improved), but stretching the legs on the modern one allowed me to solder it.</p>

<p><img src="/img/2019/02/atari-board-with-mod.jpg" alt="" class="center" /></p>

<p>You can find a lot of Atari 2600 <a href="https://www.amazon.ca/Childhood-Supply-Adapter-System-Portable/dp/B01N5G4RX0?SubscriptionId=AKIAILSHYYTFIVPWUY6Q&amp;tag=duc12-20&amp;linkCode=xm2&amp;camp=2025&amp;creative=165953&amp;creativeASIN=B01N5G4RX0">power brick replacements</a> online. But most of them have short cables, so I reused the original’s loooong cord on <a href="https://www.creatroninc.com/product/9v-2a-switching-power-supply/">a high quality 2A power supply</a>) with the proper <a href="https://www.creatroninc.com/product/1mm-dc-barrel-m-to-terminal-adapter/">adapter</a>. Just ensure that it supplies 9V and a minimum of 0.5A with polarity <a href="https://dfarq.homeip.net/atari-2600-power-supply-specs/">as labeled on the original</a> (⊖-outside, ⊕-inside).</p>

<p>The most unexpected improvement was in audio quality. Even without a second audio jack, I get <strong>much</strong> better sound now that what I had with RF. Image has almost no artifacts now (it seems the occasional faint vertical line/shadow <a href="http://atariage.com/forums/topic/266659-blue-vertical-lines-on-2600/">is a fact of life</a> unless you go with <a href="http://electronicsentimentalities.com/Assembled%20Mods.html">more sophisticated mods</a>.</p>

<p>Personally, I’m pretty happy with the results I got:</p>

<p><img src="/img/2019/02/pacman.jpg" alt="" class="center" />
<img src="/img/2019/02/seaquest.jpg" alt="" class="center" />
<img src="/img/2019/02/space-invaders.jpg" alt="" class="center" /></p>

<p>My friends were also super happy:</p>

<p><img src="/img/2019/02/happy-friends.jpg" alt="" class="center" /></p>

<p>One of them got enough points in Frostbite to <a href="http://www.atariage.com/2600/archives/activision_patches.html">earn an Activision Patch</a> 😁. Too bad we are a few decades late to send a picture to Actvision, but here are the proof and her honorary patch.</p>

<p><img src="/img/2019/02/frostbite-patch-record.jpg" alt="" class="center" /></p>

<p><img src="/img/2019/02/frostbite-patch.jpg" alt="" class="center" /></p>
]]></content>
  </entry>
  
</feed>
