<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://coconauts.net/blog/feed.xml" rel="self" type="application/atom+xml" /><link href="https://coconauts.net/blog/" rel="alternate" type="text/html" /><updated>2026-02-12T12:15:39+00:00</updated><id>https://coconauts.net/blog/feed.xml</id><title type="html">The Coconauts Blog</title><subtitle>Hardware and software projects</subtitle><entry><title type="html">Pizza&amp;amp;Peli: personal movie session planner and tracker</title><link href="https://coconauts.net/blog/blog/2026/02/05/pizzaypeli/" rel="alternate" type="text/html" title="Pizza&amp;amp;Peli: personal movie session planner and tracker" /><published>2026-02-05T00:00:00+00:00</published><updated>2026-02-05T00:00:00+00:00</updated><id>https://coconauts.net/blog/blog/2026/02/05/pizzaypeli</id><content type="html" xml:base="https://coconauts.net/blog/blog/2026/02/05/pizzaypeli/"><![CDATA[<p>At home we do a weekly movie session with the kids, which is met with high anticipation. But we’re not the kind of folks that just pop open Netflix of Disney+ and watch whatever is there - no, we take our children’s education seriously, and as hopeless geeks, that obviously includes carefully curating the selection of movies we consume, so that we expose them to cinematic gems at an age-appropriate rate.</p>

<p>We used to just keep a list in <a href="https://obsidian.md/">Obsidian</a> with movie ideas as they came along, but as the list grew longer it became difficult to manage. Also, often other parents ask for recommendations on which movies we’ve watched and liked, but we had to rely on our memory to recall them.</p>

<p>So, we’ve built an app to manage both usecases: Pizza&amp;Peli.</p>

<div class="img-with-text" style="display: block; margin: 0 auto; text-align: center;">
    <img src="/images/posts/pizzaypeli/pizzaypeli.png" alt="Pizza&amp;Peli app screenshot" style="max-width: 600px; width: 100%;" />
    <p>Named after the way we call our movie sessions at home 🍕</p>
</div>

<!--more-->

<p>It’s a <a href="https://www.djangoproject.com/">Django app</a> that uses <a href="https://github.com/tveronesi/imdbinfo">scraped metadata from iMDB</a>, and allows to keep track of the upcoming and previously shown movies in our home sessions. We self-host it in our home server, and pop it up every time we have a new idea for a movie to add to the list, and also to keep of what movies we’ve watched and when.</p>

<p><a href="https://github.com/coconauts/pizzaypeli">The source code is on Github</a>. Currently it’s an MVP, but we plan to add more features, like trailers, PG rating, or multiple accounts (so we can use it to keep track of our grown-up movie sessions too).</p>

<p>The app was developed as an experiment to code with the aid of <a href="https://code.claude.com/">claude code</a>, which allowed for a much faster development than if it would have been written from scratch. I’ve kept <a href="https://github.com/coconauts/pizzaypeli/blob/main/claude_log/prompts.md">a log of the evolution of the app</a>, with prompts and screenshots.</p>]]></content><author><name>Mar Bartolome</name></author><category term="software" /><category term="django" /><category term="webdev" /><category term="movies" /><summary type="html"><![CDATA[We built our own personal movie session planner app]]></summary></entry><entry><title type="html">My journey as a Djangonaut - from zero to contributor in one space mission</title><link href="https://coconauts.net/blog/blog/2025/11/06/my-journey-as-a-djangonaut/" rel="alternate" type="text/html" title="My journey as a Djangonaut - from zero to contributor in one space mission" /><published>2025-11-06T10:00:00+00:00</published><updated>2025-11-06T10:00:00+00:00</updated><id>https://coconauts.net/blog/blog/2025/11/06/my-journey-as-a-djangonaut</id><content type="html" xml:base="https://coconauts.net/blog/blog/2025/11/06/my-journey-as-a-djangonaut/"><![CDATA[<p>Disclaimer: I’m a fan of open source. The spirit of openness and collaboration just makes software better, and hackers happier. The benefits of open source are noticeable even if you’re just a user - but multiply when you become a contributor as well.</p>

<p>However, contributing into an existing project is always daunting. Specially when it comes to popular projects, with a huge codebase and thousands of participants - such as <a href="https://www.djangoproject.com/">the Django project</a>, for example. It’s hard to know where to start, how to proceed, and how to get your changes accepted. For all the years I’ve been working as a software engineer, contributing to open source is something that has always been on my wishlist, but never got to achieve.</p>

<p>But as it turns out, Django has an amazing community and runs a periodic program to help aspiring contributors along their journey into their first contribution to the project: <a href="https://djangonaut.space/">the Djangonauts program</a>. I joined <a href="https://djangonaut.space/sessions/2025-session-5/">session 5, running October-November 2025</a>.</p>

<div class="img-with-text" style="display: block; margin: 0 auto; text-align: center;">
    <img src="/images/posts/djangonauts/logo.png" alt="djangonauts logo" />
    <p>Similarity to the Coconauts name purely coincidental 😬</p>
</div>

<!--more-->

<h2 id="ready-for-takeoff">Ready for takeoff</h2>

<p>The program is whimsically themed around a space mission, so I’m following the same convention through this post. Djangonauts (which are the participants who want to become contributors) are placed into teams leaded by a Captain and a Navigator (which are respectively, experienced members of the community and stablished contributors, whose role is to guide the Djangonauts along their journey). Each team is focused around a Django subproject: there are teams for the Django framework itself, but also for the <a href="https://github.com/django-commons/django-debug-toolbar">debug toolbar</a>, <a href="https://github.com/DjangoGirls/djangogirls">Django Girls</a> or in my case, my team was working on <a href="https://github.com/django-cms/django-cms">Django CMS</a>.</p>

<p>The spirit of the program is that of low-structured guidance and support from senior members of the community to aspiring ones, and between the Djangonaut peers themselves. During the program, each Djangonaut is expected to achieve a contribution into their assigned projects, even if it’s a small one - as more important than the contribution itself, is the experience of the contribution process and the integration into the community.</p>

<h2 id="start-the-engines">Start the engines</h2>

<p>The first week of the program is used to familiarise ourselves with the project - <a href="https://www.django-cms.org/en/">Django CMS</a> is not as popular as it’s big brother, and none of the Djangonauts in the team were acquainted with it. So the first thing to do was spending some time going through tutorials, documentation and setting up a sample project before we do any hacking.</p>

<p>Going through a project onboarding with a contributor mindset is extremely valuable: it’s only the first time that you go through the introductory materials that you get to experience them with fresh eyes, and are able to evaluate it’s effectiveness. So simply going through this learning process, before writing any code, allowed to identify some areas where the documentation was confusing. And as new contributors, we’re encouraged to fix it!</p>

<p>The process of making a change to an Open Source process, even it it’s in the docs, goes through <strong>discussion and collaboration with the existing project maintainers</strong>. They need to evaluate your change and guide the direction to be taken. So the first step is to <a href="https://github.com/django-cms/django-cms/issues/8361">raise tickets</a> for <a href="https://github.com/django-cms/djangocms-frontend/issues/312#issuecomment-3442345184">the issues that you encountered</a>. Those tickets (or <em>issues</em>, as Github calls them) might give way into <a href="https://github.com/django-cms/djangocms-frontend/pull/317">pull requests implementing the proposed changes</a> - which might not necessarily be implemented by the same person! <strong>Publishing a ticket/issue</strong> helps current and future contributors become aware of a bug, a possible enhancement, or even feature ideas, and is in essence another useful way of contributing to open source, without writing any code.</p>

<p><img src="/images/posts/djangonauts/issue.png" alt="Github issue" style="display: block; margin: 0 auto; text-align: center;" /></p>

<p>For example, later during the program, we discovered a bug in Django CMS. <a href="https://github.com/django-cms/djangocms-frontend/issues/318">I raised a ticket reporting it</a>, and <a href="https://github.com/django-cms/djangocms-frontend/issues/318">our navigator promptly pushed a fix</a>.</p>

<h2 id="launch">Launch!</h2>

<p>And now comes the time to really get started: our navigator offered a curated list of tickets that are approachable for newcomers into the project, and we are to pick one and start hacking.</p>

<p>This is perhaps the biggest barrier of entry for aspiring contributors in most OS projects - when you are lacking the project context, most tickets won’t even make any sense to you. And here’s where community and curation come to the rescue: many projects use tags for their issues, which can be used for example to tell apart features, from bugs, from documentation. Or a common pattern is to use them to <strong>mark tickets that are friendlier to new contributors</strong>, with names such as <strong>“easy pickings”</strong> or <strong>“good first issue”</strong>.</p>

<p><img src="/images/posts/djangonauts/issuestags.png" alt="Tagged github issues" style="display: block; margin: 0 auto; text-align: center;" /></p>

<p>In my case, I went for <a href="https://github.com/django-cms/djangocms-frontend/issues/250">a bug ticket</a>, which was marked as “easy pickings”. The ticket had a very clear description on how to reproduce the bug, with even screenshots included - so I settled into doing just that.</p>

<p>And sure enough, reproducing the bug locally was pretty straightforward. But then discovering the source of the bug was a different matter… It turned out to be a tricky one, rather than an easy picking! It required plenty of discussion with our navigator to be able to triage the bug, and decide on a solution - which does not fix the source of the bug, but at least is an UI improvement.</p>

<p>These changes were implemented and <a href="https://github.com/django-cms/djangocms-frontend/pull/316">raised as a feature pull request</a>. The pull request had a bit of back and forth to get the automated CI system to give it the green light, as well as a passing review from our navigator, which helped make sure the changes were backwards compatible and wouldn’t break existing instances of djangocms. <a href="https://en.wikipedia.org/wiki/Move_fast_and_break_things">Moving fast and breaking things</a> is not the way of open source!</p>

<div class="img-with-text" style="display: block; margin: 0 auto; text-align: center;">
    <img src="/images/posts/djangonauts/mergedPR.png" alt="Merged pull request" />
    <p>Success!</p>
</div>

<p>Once again, the key takeout is that <strong>collaboration with a project maintainer</strong> was essential during the process.</p>

<h2 id="work-as-a-crew">Work as a crew</h2>

<p>The Djangonauts is not a solo mission: the spirit of the program is collaboration not only with your mentors, but also with the other Djangonauts. There’s a lot of diversity in the participants: not just in terms of geography of demographics, but also there’s people from very disparate backgrounds. There’s people who are already active members of the Python/django community, as well as people with very little exposure to the project, and there’s experienced developers alongside people who are newer to programming. Just like in open source projects in the wild, if you think about it!</p>

<p>The magic of open source is that <strong>every part of the process is open, and anyone can collaborate</strong>. So even if a ticket is mainly driven by one contributor, it doesn’t mean that others can’t lend a hand as well. As the famous quote goes: <a href="https://en.wikipedia.org/wiki/Linus%27s_law"><em>given enough eyeballs, all bugs are shallow</em></a> - i.e., more people have a broader view.</p>

<p>Djangonauts are encouraged to “chip in” into their peer’s doings, not just to help, but also to learn further. Peeking into you peer’s tickets and pull requests is a great way to learn, but also gives you the necessary context to help them if they get stuck - via chat discussions or even live <a href="https://en.wikipedia.org/wiki/Pair_programming">pair programming</a> sessions.</p>

<p><img src="/images/posts/djangonauts/pair.png" alt="Djangonauts pair programming" style="display: block; margin: 0 auto; text-align: center;" /></p>

<p>There’s nothing stopping you from adding comments into other people’s pull requests in fact, to provide further help or feedback. Or even having multiple people collaborating by pushing code into the same branch (with prior coordination, to avoid <a href="https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/about-merge-conflicts">conflicts!</a>).</p>

<h2 id="to-infinity-and-beyond">To infinity and beyond</h2>

<p>We’re still halfway through the program, but already I feel like it’s been a rewarding experience. It taught me valuable etiquette and best practices that will guide my future open source efforts, and most importantly, it helped me break that first barrier of making <a href="(https://github.com/django-cms/djangocms-frontend/pull/316)">my first successful code contribution to an open source project</a>, which has given me the necessary confidence to keep going at it.</p>

<p>I’m really grateful to the Django community for their welcomeness and dedication - it comes to show that when you cultivate a great community, you grow a great project!</p>

<p>This is just the first mission, but I’m sure more adventures in Django an open source will follow! 🚀</p>]]></content><author><name>Mar Bartolome</name></author><category term="software" /><summary type="html"><![CDATA[Disclaimer: I’m a fan of open source. The spirit of openness and collaboration just makes software better, and hackers happier. The benefits of open source are noticeable even if you’re just a user - but multiply when you become a contributor as well. However, contributing into an existing project is always daunting. Specially when it comes to popular projects, with a huge codebase and thousands of participants - such as the Django project, for example. It’s hard to know where to start, how to proceed, and how to get your changes accepted. For all the years I’ve been working as a software engineer, contributing to open source is something that has always been on my wishlist, but never got to achieve. But as it turns out, Django has an amazing community and runs a periodic program to help aspiring contributors along their journey into their first contribution to the project: the Djangonauts program. I joined session 5, running October-November 2025. Similarity to the Coconauts name purely coincidental 😬]]></summary></entry><entry><title type="html">Backup Internet Setup for Emergencies</title><link href="https://coconauts.net/blog/blog/2025/10/28/backup-internet-setup/" rel="alternate" type="text/html" title="Backup Internet Setup for Emergencies" /><published>2025-10-28T10:00:00+00:00</published><updated>2025-10-28T10:00:00+00:00</updated><id>https://coconauts.net/blog/blog/2025/10/28/backup-internet-setup</id><content type="html" xml:base="https://coconauts.net/blog/blog/2025/10/28/backup-internet-setup/"><![CDATA[<p>We take so many things for granted in life when they are working fine, but when they fail, you suddenly realize they hanging by a thread - like, literally, THE INTERNET.</p>

<p>At home, we get our Internet from a fiber connection, which, as it turns out, it’s just light pulses coming thru a cable down the street. And this is a single point of failure, ready to be attacked by unlikely adversaries…</p>

<!--more-->

<p><img src="/images/posts/rat.webp" alt="A cheeky rat" style="display: block; margin: 0 auto; text-align: center;" /></p>

<p>Rats! These pesky critters happen to co-live in our neighborhood, and for mysterious reasons they love chewing on the fiber Internet cables - so light pulses no longer reach our home: the LED pilots fade out in our router, and despair looms, for we are now isolated from the digital world.</p>

<div class="img-with-text" style="display: block; margin: 0 auto; text-align: center;">
    <img src="/images/posts/ohnointernet.png" alt="Router lights out" />
</div>

<p>Our Internet provider eventually sends a technician to fix the broken cables and bring us back to civilization, but sometimes they take a few days (or even weeks!). They are nice enough to give us complimentary 100GBs of mobile data per day (ie 4G/5G), so we can get going with our lives as we wait.</p>

<h2 id="but-the-problem-escalates">But the problem escalates…</h2>

<p>However, this solution is severely limited for our needs. We can only tap into this connection with a mobile phone, and use it to provide a WiFi hotspot using tethering. This is an acceptable solution if you just need temporary internet on a laptop to work, or a tablet to watch Netflix. But in our case, we don’t just use the internet for work and leisure: we need it for our house to function.</p>

<p>We’re the kind of geeks that are fond of domotics and home automations, and our house is riddled with smart devices to the point of ridiculous: we have around a hundred devices connected to our network, each of them with a fixed IP, integrated with <a href="https://www.home-assistant.io/">Home Assistant</a>, <a href="https://nodered.org/">node-red</a>, <a href="https://uptime.kuma.pet/">kuma</a>, and more… They rely on a local DHCP server that lives in a secondary router, so when that router can’t get Internet, nothing works: we don’t have a doorbell, our blinds don’t roll, our garden doesn’t get watered, our heat pump does not trigger… Reconfiguring all this would be absolutely hellish.</p>

<p><img src="/images/posts/network_broken.png" alt="Broken network diagram" style="display: block; margin: 0 auto; text-align: center;" /></p>

<h2 id="solution-the-single-responsibility-principle">Solution: the single responsibility principle</h2>

<p>There was a simple solution to all this: we purchased <a href="https://www.amazon.com/dp/B07RM95YFC">a 4G router</a> to act as an Internet gateway, in stead of our regular fiber router. This router works by inserting a SIM card, and connects to the Internet via the 4G network, like smartphones do, but other than that it acts like any regular router.</p>

<p>Because the responsibility of the main router in our case is limited to just be a dumb proxy for internet access, it’s completely replaceable: we can choose to use the fiber or 4G router as Internet provider as the need arises. The rest of the network setup remains intact, and our house can keep business as usual during the outage with zero effort.</p>

<p><img src="/images/posts/network_fixed.png" alt="Fixed network diagram" style="display: block; margin: 0 auto; text-align: center;" /></p>

<p>In order to keep using my phone normally, I requested a <a href="https://en.wikipedia.org/wiki/Multi-SIM_card">multi-SIM</a> to my network operator, so that I could have two SIM cards with the same account, one on my phone and another one on the 4G router.</p>

<p>The 4G connection is obviously not as good as the fiber, and we’re still limited to 100GB per day. But by cutting downloads and streaming we get a near-normal Internet experience until the fiber can get fixed.</p>

<div class="img-with-text" style="display: block; margin: 0 auto; text-align: center;">
    <img src="/images/posts/spaghetti.jpg" alt="spaghetti cables" />
    <p>If you dread spaghetti code, try spaghetti cables</p>
</div>

<p>Then we simply swap the entry routers again, and it’s as if nothing ever happened.</p>]]></content><author><name>Mar Bartolome</name></author><category term="hardware" /><summary type="html"><![CDATA[We take so many things for granted in life when they are working fine, but when they fail, you suddenly realize they hanging by a thread - like, literally, THE INTERNET. At home, we get our Internet from a fiber connection, which, as it turns out, it’s just light pulses coming thru a cable down the street. And this is a single point of failure, ready to be attacked by unlikely adversaries…]]></summary></entry><entry><title type="html">NFC Floppy Disk Game Launcher</title><link href="https://coconauts.net/blog/blog/2025/07/25/nfc-floppy-disks/" rel="alternate" type="text/html" title="NFC Floppy Disk Game Launcher" /><published>2025-07-25T10:00:00+00:00</published><updated>2025-07-25T10:00:00+00:00</updated><id>https://coconauts.net/blog/blog/2025/07/25/nfc-floppy-disks</id><content type="html" xml:base="https://coconauts.net/blog/blog/2025/07/25/nfc-floppy-disks/"><![CDATA[<p>As retro-gaming enthusiasts, we have a broad collection of old PC game files that we can conveniently play on modern PCs via DOSBox, SCUMMVM, and other utilities. But when playing on modern hardware, you lose some of the “magic” - for the <em>real</em> retro experience, those who are true purists will actually go and find some old hardware, set it up with an old DOS or Windows 3.1 build, and then install the actual games there. But this is very impractical… so, what if there was a way to simulate the retro experience, with modern technology?</p>

<p>That is exactly what we’ve done: we’re built ourselves a retro PC, using a 386x case, but with a modern PC inside. On it, we’ve installed a fake floppy drive that loads games using NFC - but seemingly, it looks as if they are magically loading from the floppy disks. Read on to learn how!</p>

<video width="400" height="600" controls="" style="display: block; margin: 0 auto; text-align: center;">
  <source src="/images/posts/nfc-floppy/demo.mp4" type="video/mp4" />
  Your browser does not support the video tag.
</video>

<!--more-->

<h2 id="in-a-nutshell">In a nutshell</h2>

<p>As you can imagine, there’s nothing more to this than using retro facades to hide modern hardware: we replaced the innards of the floppy drive with an Arduino hooked to an NFC reader module; Then, each floppy disk has an NFC sticker, that when inserted in the drive gets it’s ID read.</p>

<p>The Arduino program is continuously reading for IDs, and sends them to the PC through the USB-serial port. On the PC, a python script runs in the background reading this port, and has a hardcoded list of NFC ids, each mapped to an execution command that gets run on a subprocess.</p>

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

<p><img src="/images/posts/nfc-floppy/mfrc522.png" alt="MFRC522 module" style="display: block; margin: 0 auto; text-align: center;" /></p>

<p>We used an <em>Arduino UNO</em>, with an MFRC522 NFC/RFID module running at 13.56MHz, which supports ISO/IEC 14443 Type A cards, MIFARE, and NTAG formats and has a reading range of 1-3cm. And most importantly, <a href="https://github.com/miguelbalboa/rfid">there’s a community-maintained Arduino library</a> for these modules.</p>

<p>The MFRC522 module needs to be positioned where it can reliably read NFC tags inside inserted floppy disks. However, we found that the metallic shell holding the disks in place was interfering with the readings, so we had to replace it with a more inert material - including the insertion/ejection button. We made a replacement structure out of LEGO building blocks - it was incredibly simple to put together and works like a charm!</p>

<p>&lt;video width=”600” height=”400” controls style=”display: block; margin: 0 auto; text-align: center;&gt;</p>
<source src="/images/posts/nfc-floppy/lego.mp4" type="video/mp4" />

<p>Your browser does not support the video tag.
&lt;/video&gt;</p>

<p>The NFC is connected to the Arduino with the following pinage:</p>
<ul>
  <li>VCC → 3.3V (important: not 5V!)</li>
  <li>GND → Ground</li>
  <li>RST → Digital Pin 9</li>
  <li>SS → Digital Pin 10</li>
  <li>MOSI → Pin 11 (SPI)</li>
  <li>MISO → Pin 12 (SPI)</li>
  <li>SCK → Pin 13 (SPI)</li>
</ul>

<p>And the Arduino itself is connected to the computer via USB for both power and serial communication.</p>

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

<p>The Arduino is running a script that continuously polls for NFC tags using the aforementioned <a href="https://github.com/miguelbalboa/rfid">MFRC522 library</a> (needs installing as a prerequisite) and sends their unique identifiers via serial communication.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;SPI.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;MFRC522.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;Wire.h&gt;</span><span class="cp">
</span>
<span class="cp">#define SS_PIN 10
#define RST_PIN 9
</span>
<span class="n">MFRC522</span> <span class="nf">mfrc522</span><span class="p">(</span><span class="n">SS_PIN</span><span class="p">,</span> <span class="n">RST_PIN</span><span class="p">);</span>

<span class="kt">void</span> <span class="nf">setup</span><span class="p">()</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">9600</span><span class="p">);</span>
  <span class="n">SPI</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span>
  <span class="n">mfrc522</span><span class="p">.</span><span class="n">PCD_Init</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="s">"NFC Floppy Reader Ready"</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="n">loop</span><span class="p">()</span> <span class="p">{</span>
  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">mfrc522</span><span class="p">.</span><span class="n">PICC_IsNewCardPresent</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">if</span> <span class="p">(</span><span class="o">!</span><span class="n">mfrc522</span><span class="p">.</span><span class="n">PICC_ReadCardSerial</span><span class="p">())</span> <span class="p">{</span>
    <span class="k">return</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="c1">// Send UID via serial</span>
  <span class="k">for</span> <span class="p">(</span><span class="n">byte</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">mfrc522</span><span class="p">.</span><span class="n">uid</span><span class="p">.</span><span class="n">size</span><span class="p">;</span> <span class="n">i</span><span class="o">++</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="n">mfrc522</span><span class="p">.</span><span class="n">uid</span><span class="p">.</span><span class="n">uidByte</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;</span> <span class="mh">0x10</span> <span class="o">?</span> <span class="s">"0"</span> <span class="o">:</span> <span class="s">""</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="n">mfrc522</span><span class="p">.</span><span class="n">uid</span><span class="p">.</span><span class="n">uidByte</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">HEX</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">mfrc522</span><span class="p">.</span><span class="n">PICC_HaltA</span><span class="p">();</span>
  <span class="n">delay</span><span class="p">(</span><span class="mi">1000</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And the PC is running a Python script that monitors the serial port, mapping the NFC tag IDs to different followup commands, to launch the games or applications. Uses the <a href="https://pypi.org/project/pyserial/">pyserial</a> library, which you’ll need to install too.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">serial</span>
<span class="kn">import</span> <span class="nn">subprocess</span>
<span class="c1"># Mapping NFC tag UIDs to games/applications
</span><span class="n">rfid_to_game</span> <span class="o">=</span> <span class="p">{</span>
    <span class="s">"04a1b2c3"</span><span class="p">:</span> <span class="s">"wine ~/.wine/drive_c/Games/DoomII/doom2.exe"</span><span class="p">,</span>
    <span class="s">"05d4e5f6"</span><span class="p">:</span> <span class="s">"/usr/games/dosbox ~/Games/Commander_Keen/keen.exe"</span><span class="p">,</span>
    <span class="s">"06g7h8i9"</span><span class="p">:</span> <span class="s">"steam steam://rungameid/12345"</span><span class="p">,</span>
    <span class="s">"07j8k9l0"</span><span class="p">:</span> <span class="s">"/home/user/scripts/launch_emulator.sh"</span>
<span class="p">}</span>
<span class="k">try</span><span class="p">:</span>
    <span class="n">arduino</span> <span class="o">=</span> <span class="n">serial</span><span class="p">.</span><span class="n">Serial</span><span class="p">(</span><span class="s">'/dev/ttyUSB0'</span><span class="p">,</span> <span class="mi">9600</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"Connected to NFC Floppy Reader"</span><span class="p">)</span>
    
    <span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">arduino</span><span class="p">.</span><span class="n">in_waiting</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
            <span class="n">tag_id</span> <span class="o">=</span> <span class="n">arduino</span><span class="p">.</span><span class="n">readline</span><span class="p">().</span><span class="n">decode</span><span class="p">(</span><span class="s">'utf-8'</span><span class="p">).</span><span class="n">strip</span><span class="p">().</span><span class="n">lower</span><span class="p">()</span>
            
            <span class="k">if</span> <span class="n">tag_id</span> <span class="ow">in</span> <span class="n">rfid_to_game</span><span class="p">:</span>
                <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Launching game for tag: </span><span class="si">{</span><span class="n">tag_id</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
                <span class="n">subprocess</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">rfid_to_game</span><span class="p">[</span><span class="n">tag_id</span><span class="p">],</span> <span class="n">shell</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Unknown tag: </span><span class="si">{</span><span class="n">tag_id</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
                
<span class="k">except</span> <span class="nb">KeyboardInterrupt</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"Shutting down..."</span><span class="p">)</span>
<span class="k">finally</span><span class="p">:</span>
    <span class="n">arduino</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
</code></pre></div></div>

<p>This approach allows for maximun flexibility: a game can use wine, while another can run on DosBOX, or even if you need a sequence of commands, you can map to a custom shell script. The script spawns a subprocess shell to run the game launch command, and that’s it.</p>

<p>We’re using Ubuntu on the PC, so these commands are run in the default shell (bash). The script is setup to autoload at system startup using crontab. But we’ll leave all the details of the retro-pc for another post.</p>

<h2 id="creating-game-disks">Creating Game Disks</h2>

<p>Arguably, the most fun part of the project is creating the game collection. We used old floppy disks, and attached an NFC tag on the back of each of them - and of course, a sticker label on the front. We use a mini thermal printer for the stickers, which also give them a clunky retro feel.</p>

<p>For each disk, we’ll need to know the NFC tag ID so that we can add it to the hardcoded list on the python script. When the script reads an unknown tag, it prints the ID in the log, so we can copy and then paste it in the mapping list with the adequate command.</p>

<p><img src="/images/posts/nfc-floppy/disks.jpg" alt="Floppy disks" /></p>

<h2 id="final-experience">Final experience</h2>

<p>The whole thing is mounted on an old 386x case, keeping the floppy drive frontal panel, so it looks completely inconspicuous. We have the experience of the look and feel of a retro-PC, with the games magically loading instantly. And with the convenience of a modern OS with emulators for installation and maintenance.</p>

<p><img src="/images/posts/nfc-floppy/final.jpg" alt="How it looks" /></p>

<p>For reference, you can find <a href="https://github.com/rephus/nfc-floppy-disk-reader">the updated source code for this project on GitHub</a>. We’d love to know if you build your own!</p>]]></content><author><name>Mar Bartolome</name></author><category term="hardware" /><category term="arduino" /><category term="nfc" /><category term="retro" /><category term="gaming" /><category term="hardware" /><summary type="html"><![CDATA[Using hidden NFC tags and reader to simulate physically loading retro games]]></summary></entry><entry><title type="html">Hiring Demystified</title><link href="https://coconauts.net/blog/blog/2021/09/28/hiring-demystified/" rel="alternate" type="text/html" title="Hiring Demystified" /><published>2021-09-28T12:00:14+00:00</published><updated>2021-09-28T12:00:14+00:00</updated><id>https://coconauts.net/blog/blog/2021/09/28/hiring-demystified</id><content type="html" xml:base="https://coconauts.net/blog/blog/2021/09/28/hiring-demystified/"><![CDATA[<p>It’s not secret that the hardest problems in computer science are cache invalidation and naming things… oh, and hiring. In our industry we’ve developed a culture and a mysticism around hiring, with certain rituals and practices which are often so detached from reality that you see numerous jokes and memes about the subject.</p>

<p>Hiring is a difficult problem, yet important to get right. Many developers are faced with the challenge of hiring other team members, without much clue into how to proceed, and end up just copying the well known rituals without stopping to analyse their effectiveness or implications. Often, this results in hindering both companies and candidates, especially those of under represented demographics.</p>

<p>In this talk I gave at EuroPython 2021, I share my experiences and personal opinions both as a candidate and as an interviewer, analyze the implications of popular hiring tactics, and discuss what I consider effective ones, in order to hire the right developers for your team with minimum hassle for both sides.</p>

<iframe width="560" height="315" src="https://www.youtube.com/embed/mnzX3LhZ0VI?si=L4mtK5I4A33q2TCe" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" style="display: block; margin: 20px auto; text-align: center;"></iframe>

<p>This talk is actually an updated version of <a href="https://www.youtube.com/embed/UBLTaQ_tRl4">the one I gave a year earlier at PyConES</a>.</p>]]></content><author><name>Mar Bartolome</name></author><category term="software" /><category term="speaking" /><category term="talks" /><category term="hiring" /><category term="companies" /><category term="pycon" /><summary type="html"><![CDATA[A talk at EuroPython 2021 about engineering hiring practices]]></summary></entry><entry><title type="html">Microservices: the small print</title><link href="https://coconauts.net/blog/blog/2020/11/18/microservices-the-small-print/" rel="alternate" type="text/html" title="Microservices: the small print" /><published>2020-11-18T12:00:14+00:00</published><updated>2020-11-18T12:00:14+00:00</updated><id>https://coconauts.net/blog/blog/2020/11/18/microservices-the-small-print</id><content type="html" xml:base="https://coconauts.net/blog/blog/2020/11/18/microservices-the-small-print/"><![CDATA[<p>Microservices get a lot of sales talk, which leads many teams to adopt them eagerly. However, people are not always aware that they come at a price.</p>

<p>In this talk I gave at PyconES 2018 I discuss the basic theory around microservices architectures, and go over the common pain points that they bring, and how they often get you in the opposite direction than you intended with them.</p>

<iframe width="560" height="315" src="https://www.youtube.com/embed/ch0A_lcaPG0" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" style="display: block; margin: 20px auto; text-align: center;"></iframe>]]></content><author><name>Mar Bartolome</name></author><category term="software" /><category term="microservices" /><category term="speaking" /><category term="talks" /><category term="pycon" /><summary type="html"><![CDATA[A talk at pyconES 2018 about the hidden cost of microservices]]></summary></entry><entry><title type="html">Paint walls in VR</title><link href="https://coconauts.net/blog/blog/2019/01/19/paint-rooms-vr/" rel="alternate" type="text/html" title="Paint walls in VR" /><published>2019-01-19T01:00:14+00:00</published><updated>2019-01-19T01:00:14+00:00</updated><id>https://coconauts.net/blog/blog/2019/01/19/paint-rooms-vr</id><content type="html" xml:base="https://coconauts.net/blog/blog/2019/01/19/paint-rooms-vr/"><![CDATA[<p>Have you ever wanted to paint a room but did not decide which color to choose ?</p>

<p>We found an easy and cool solution, all you need is a phone (mainly an Android, but if you IOS, just replace the apps and locations with the IOS equivalent) and an image editor to paint your room in Virtual Reality.</p>

<p><img src="/images/posts/2019-01-19-paint-rooms-vr/before.vr.jpg" alt="before" />
<img src="/images/posts/2019-01-19-paint-rooms-vr/after.vr.jpg" alt="after" /></p>

<!--more-->

<h2 id="create-your-360-picture">Create your 360 picture</h2>

<p>First, download the <a href="https://play.google.com/store/apps/details?id=com.google.samples.apps.cardboarddemo">Google cardboard</a> app for Android.</p>

<p>Open the app, (after a few configuration steps), and go to <code class="language-plaintext highlighter-rouge">cardboard camera</code> and take the picture by rotating the phone slowly.</p>

<p>The picture will be stored in <code class="language-plaintext highlighter-rouge">sdcard/DCIM/CarboardCamera</code> with a .vr.jpg extension. Copy that file into your computer.</p>

<p><img src="/images/posts/2019-01-19-paint-rooms-vr/before.vr.jpg" alt="before" /></p>

<h2 id="export-_left-and-_right-images">Export <code class="language-plaintext highlighter-rouge">_left</code> and <code class="language-plaintext highlighter-rouge">_right</code> images</h2>

<p>Although the image taken by the cardboard camera looks like a normal jpg image, it contains some metadata that allows the app to support VR.</p>

<p>Because of this, we need to export the .vr.jpg into two separate images using https://cctoolkit.vectorcult.com/#, this step is key to the whole process.</p>

<p>Upload your picture into that website and it will get splitted into two (one for each eye). Right click on the images and save them on your computer with <code class="language-plaintext highlighter-rouge">_left</code> and <code class="language-plaintext highlighter-rouge">_right</code> names.</p>

<p><img src="/images/posts/2019-01-19-paint-rooms-vr/split.png" alt="split" /></p>

<h2 id="editing-the-vr-picture">Editing the VR picture</h2>

<p>We used GIMP to edit the image, but you can use photoshop or any other image editor, just open both <code class="language-plaintext highlighter-rouge">_left</code> and <code class="language-plaintext highlighter-rouge">_right</code> images you exported before with it and you will see a plain wide image.</p>

<p><img src="/images/posts/2019-01-19-paint-rooms-vr/gimp.png" alt="gimp" /></p>

<p>Now you can edit the images in any way you want, what I did was to use the different select tools to select just (and only) the walls on the room, then move it to another layer (for easier management) and then used the <code class="language-plaintext highlighter-rouge">colourise</code> tool to change the color.</p>

<p><img src="/images/posts/2019-01-19-paint-rooms-vr/colourise.png" alt="colourise" /></p>

<p>You need to repeat this operation for both images. Once you’re done, save both images and be ready to combine them together again.</p>

<h2 id="generate-new-vr-image">Generate new VR image</h2>

<p>Go back to the same website as before https://cctoolkit.vectorcult.com/# and join both images this time, remember to keep the <code class="language-plaintext highlighter-rouge">_left</code> and <code class="language-plaintext highlighter-rouge">_right</code> names before uploading.</p>

<p>This will generate a new .vr.jpg page. Copy the image back on <code class="language-plaintext highlighter-rouge">DCIM/CardboardCamera</code>. If you did everything correctly, you will see both pictures (the new one and the old one) on the cardboard. If you upload a non-vr image, it won’t show on the app.</p>

<p><img src="/images/posts/2019-01-19-paint-rooms-vr/cardboard.png" alt="cardboard" /></p>

<p>Click on the image and you will see it on VR. That’s it, enjoy.</p>

<p><img src="/images/posts/2019-01-19-paint-rooms-vr/vr.png" alt="vr" /></p>]]></content><author><name>Javier Rengel</name></author><category term="software" /><category term="vr" /><summary type="html"><![CDATA[Paint room walls in virtual reality]]></summary></entry><entry><title type="html">Escaperoom x unlock</title><link href="https://coconauts.net/blog/blog/2018/09/07/escape-room-demo/" rel="alternate" type="text/html" title="Escaperoom x unlock" /><published>2018-09-07T14:00:14+00:00</published><updated>2018-09-07T14:00:14+00:00</updated><id>https://coconauts.net/blog/blog/2018/09/07/escape-room-demo</id><content type="html" xml:base="https://coconauts.net/blog/blog/2018/09/07/escape-room-demo/"><![CDATA[<p>A year ago we showed you a <a href="">generative escaperoom</a> game on Unity3D. Based on that formula, we decided to create some manually-crafted levels to make the game even better. So we decided to copy the first level design of a card based escaperoom game called <a href="https://boardgamegeek.com/boardgame/213460/unlock-escape-adventures">Unlock</a>. And the result was as good as we expected.</p>

<p><img src="/images/posts/2018-09-07-escape-room-demo/unlock-cards.jpg" alt="unlock" /></p>

<p><img src="/images/posts/2018-09-07-escape-room-demo/overview.png" alt="uniy3d-design" /></p>

<p>The game is not yet finished, but because we are going to move to a different project, we thought about showing you a demo of what we’ve built so far.</p>

<!--more-->

<h2 id="demo">Demo</h2>

<p>This is a first look of the mechanics of the game</p>

<p><img src="/images/posts/2018-09-07-escape-room-demo/level1.gif" alt="demo" /></p>

<p>You can play this demo in here http://unity3d.coconauts.net/escaperoom-unlock/. Remember, it is not finished so it could be buggy and you will not be able to finish the level.</p>

<h2 id="level-design">Level design</h2>

<p>We copied the gameplay of the first level of the unlock game, with the same clues, same objects, similar text entries  and even the similar wall textures.</p>

<p><img src="/images/posts/2018-09-07-escape-room-demo/main-room.png" alt="main-room" /></p>

<h2 id="the-inventory-system">The inventory system</h2>

<p>We added to this game a new inventory wheel system, where you pick items and you use them on any other object in the scene using the right click, showing all the items you have on a wheel.</p>

<p><img src="/images/posts/2018-09-07-escape-room-demo/inventory.gif" alt="uniy3d-design" /></p>

<p>But of course, different items will have a different effect on the item you’re trying to use it on.</p>

<h2 id="conclussions">Conclussions</h2>

<p>It takes a lot to generate the 3d models, implement the logic and replace the card-only mechanics into a 3D videogame; but the result is worth it.</p>

<p>I think, (now that we have proved the concept with a working level design) we could start building our own  levels, adding more interactive puzzles (like the laptop one in our previous game).</p>

<p>However, we will pause this project for a while to start working on different stuff, but let us know if you have any interest on playing a game like this at some point in the future.</p>

<p>What do you think about the game?
Your feedback is really valuable to us! so please let us know on the comments or <a href="http://twitter.com/coconauts">on twitter</a>.</p>]]></content><author><name>Javier Rengel</name></author><category term="games" /><category term="unity3d" /><category term="escaperoom" /><category term="unlock" /><summary type="html"><![CDATA[Escaperoom game on unity3d based on unlock! level design]]></summary></entry><entry><title type="html">Coconauts 2017 Retrospective</title><link href="https://coconauts.net/blog/blog/2018/01/18/coconauts-2017-retrospective/" rel="alternate" type="text/html" title="Coconauts 2017 Retrospective" /><published>2018-01-18T19:14:46+00:00</published><updated>2018-01-18T19:14:46+00:00</updated><id>https://coconauts.net/blog/blog/2018/01/18/coconauts-2017-retrospective</id><content type="html" xml:base="https://coconauts.net/blog/blog/2018/01/18/coconauts-2017-retrospective/"><![CDATA[<p>It’s the fourth year we’re doing this, my, time flies!</p>

<p>2017 was an incredibly packed year for us at a personal level, and the fun is still to continue in 2018. We still managed to scratch a bit of time for Coconauts, with highlights being:</p>

<ul>
  <li>The start of a <a href="http://coconauts.net/blog/categories/podcast/">podcast</a>. 
We only recorded three episodes, but each of them managed a listener count of over 100 on
<a href="https://www.ivoox.com/podcast-coconauts_sq_f1385224_1.html">ivoox</a> alone.</li>
  <li>We started setting up <a href="https://coconauts.net/blog/tags/hackday/">hackdays</a>
during the local bank holidays, which brought us: 
<a href="https://coconauts.net/blog/2017/05/29/bank-holiday-hackday-escape-room-on-unity3d/">a escape room game</a> 
and <a href="https://coconauts.net/blog/2017/08/29/bank-holiday-hackday-algorithmic-trading/">algorithmic trading experiments</a>.</li>
  <li>On the hardware front, <a href="https://coconauts.net/blog/tags/energenie/">energenies</a> 
have been our favorite toys. Worthy of mention are also a 
<a href="https://coconauts.net/blog/2017/11/27/live-picture/">live picture frame</a> (featured on 
<a href="http://www.instructables.com/id/Live-Picture-Frame-With-Raspberry-PI/">Instructables</a>) and a 
<a href="https://coconauts.net/blog/2017/02/21/stair-lights/">smart LED-illuminated staircase</a>.</li>
  <li>Gamedev didn’t stop this year either. We did a bit of fiddling with 
<a href="https://coconauts.net/projects/rps/">Phaser</a> and 
<a href="https://coconauts.net/blog/2017/10/30/proc-websockets/">Cocos2D</a>, 
but in the end we keep coming back to Unity3D for anything serious. 
Aside from the already mentioned <a href="https://coconauts.net/projects/escaperoom/">Escape Room</a>,
 we’ve done a <a href="https://coconauts.net/projects/spaceroads/">Skyroads remake</a>.</li>
  <li>What about purely software projects? Two little handy utilities: a 
<a href="https://coconauts.net/projects/github-pr-tracker/">Github PR tracker</a> and an 
<a href="https://coconauts.net/projects/infinify/">infinite playlist generator for Spotify</a>.</li>
  <li>And last but not least: we’ve broken a record of blogposts this year! 
with 21 of them, almost two per month.</li>
</ul>

<p>Hoping all of our readers enjoyed following us during 2017. It’s still not
too late to whish everyone a happy 2018, and stay tuned for more exciting 
stuff to happen over at Coconauts!</p>]]></content><author><name>Mar Bartolome</name></author><category term="general" /><category term="coconauts" /><category term="retrospective" /><summary type="html"><![CDATA[A look back at 2017, and plans for the year ahead]]></summary></entry><entry><title type="html">Live picture frame</title><link href="https://coconauts.net/blog/blog/2017/11/27/live-picture/" rel="alternate" type="text/html" title="Live picture frame" /><published>2017-11-27T14:14:46+00:00</published><updated>2017-11-27T14:14:46+00:00</updated><id>https://coconauts.net/blog/blog/2017/11/27/live-picture</id><content type="html" xml:base="https://coconauts.net/blog/blog/2017/11/27/live-picture/"><![CDATA[<p>I recently moved from UK back to Spain to work remotely, and since then, I’ve been curious about how the weather is there, specially when talking with people on the other country. Is it raining today ? Is the sun gone already ?</p>

<p>To address that problem, I found a few live videos/webcams about london like <a href="http://www.earthtv.com/en/webcam/london-millennium-bridge">earthtv</a> or <a href="https://www.youtube.com/watch?v=SMOb9d9s_mI">London Tower Bridge</a> so I kept those videos on one of the tabs of my browser.</p>

<p>But, wouldn’t be cool to have it on a separate picture frame, always  there, just like a normal picture, but live.</p>

<p><img src="/images/posts/2017-11-27-live-picture/picture.gif" alt="picture-gif" /></p>

<p>That’s why I built a slim picture frame from old recycled components. To see the Tower Bridge at day and at night.</p>

<p><img src="/images/posts/2017-11-27-live-picture/picture-day.jpg" alt="picture-day" /></p>

<p><img src="/images/posts/2017-11-27-live-picture/picture-night.jpg" alt="picture-night" /></p>

<!--more-->

<h2 id="materials">Materials</h2>

<p>These are the materials I used to create the live picture. All these items were already on my inventory:</p>

<ul>
  <li>Old ultra-thin LCD screen from a broken laptop (10 years old)</li>
  <li>12v LCD controller board with VGA output</li>
  <li>Raspberry PI Zero</li>
  <li>HDMI to VGA adaptor</li>
  <li>12v to 5v converter regulator</li>
  <li>Ikea <a href="http://www.ikea.com/us/en/catalog/products/00297440/">KNOPPANG</a> picture frame for A4</li>
  <li>Sonoff wireless switch (optional)</li>
  <li>VGA cable, micro usb cable, 12v splitter cable</li>
</ul>

<h2 id="adjusting-the-picture-frame">Adjusting the picture frame</h2>

<p>The Ikea picture frame was made for A4 pictures, however, my 15’’ LCD screen is slightly bigger than that, therefore we need to make some adjustments, first, increasing the hole in the white inner frame to 15’’.</p>

<p>Then, cutting the back of the frame to the same size</p>

<p><img src="/images/posts/2017-11-27-live-picture/cutting-board.jpg" alt="cutting-board" /></p>

<p>Everything should fit together, so you should be able to see all the screen inside the inner frame</p>

<p><img src="/images/posts/2017-11-27-live-picture/picture-screen.jpg" alt="picture-screen" /></p>

<h2 id="lcd-screen">LCD screen</h2>

<p>Since a few years ago, I had an ultra thin LCD screen from an old broken laptop. After finding and using a controller board, I’ve been able to use it as extra screen for my desktop computer sugin a VGA connection.</p>

<p><img src="/images/posts/2017-11-27-live-picture/screen-front.jpg" alt="screen-front" /></p>

<p>Controller boards are specific to the LCD screen, you need to use an specific model for the serial number of your screen, you can find it on the back. Then it’s a matter of searching ebay/aliexpress for a controller board listing compatibility with your screen model.</p>

<p><img src="/images/posts/2017-11-27-live-picture/controller-board.png" alt="controller-board" /></p>

<p>So I decided to recycle this screen now to create the canvas, because it’s thin and lightweight.</p>

<p>I removed the front case, but left the back side to protect the screen, isolate the components and glue the cables and raspberry pi to it.</p>

<p><img src="/images/posts/2017-11-27-live-picture/assembling-back.jpg" alt="assembling-back" /></p>

<p>The Raspberry PI zero, glued to the back of the screen, is powered by the same power adaptor that powers the LCD screen, using a 12v to 5v conversor. So we don’t need another extra cable connected into the screen. This is how it looks from the back.</p>

<p><img src="/images/posts/2017-11-27-live-picture/back.jpg" alt="back" /></p>

<h2 id="wall-mounting">Wall mounting</h2>

<p>After everything has been assembled together, and tested, we’re ready to hang it into the wall. For this I’ve just added two L shape hooks into the wall, and another two round hooks screwed into the plastic back of the screen.</p>

<p><img src="/images/posts/2017-11-27-live-picture/wall-hooks.jpg" alt="wall-hooks" /></p>

<p>After hanging it to the wall, I connected the 12v cable, and try to hide it using white tape.</p>

<p><img src="/images/posts/2017-11-27-live-picture/picture-wall.jpg" alt="picture-wall" /></p>

<h2 id="automatically-schedule-screen">Automatically schedule screen</h2>

<p>I’d like to schedule the frame, so it runs from 10AM to 7PM on weekdays, my working hours, so I can see London while I work remotely.</p>

<p>My first approach was to add some scripts on the Raspberry PI (cronjobs) to automatically switch ON/OFF the video output  using <code class="language-plaintext highlighter-rouge">tvservice --off</code> or <code class="language-plaintext highlighter-rouge">xset dpms force off</code> however it didn’t work pretty well in my case, because my LCD controller was not going into standby after turning off the HDMI signal.</p>

<p>So I decided to use a cheap wireless smart switch I’ve been using for a while, which can be scheduled and controlled by the phone, called <a href="http://sonoff.itead.cc/en/">Sonoff</a>. You could be using an <a href="https://coconauts.net/blog/2016/04/15/energinie-and-raspberry-pi-setup/">Energenie</a>, Xiaomi or something similar if you like.</p>

<p><img src="/images/posts/2017-11-27-live-picture/sonoff.png" alt="sonoff" /></p>

<p>This device needs to be connected in between your power cable, then you can configure it via the phone app.</p>

<p><img src="/images/posts/2017-11-27-live-picture/sonoff-cable.jpg" alt="sonoff" /></p>

<p><img src="/images/posts/2017-11-27-live-picture/sonoff-menu.jpeg" alt="sonoff" /></p>

<p>Then you can add the schedule so the Sonoff, and the Raspberry PI and the screen will be turned ON and OFF automatically.</p>

<p><img src="/images/posts/2017-11-27-live-picture/sonoff-schedule.jpeg" alt="sonoff" /></p>

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

<p>Because I have now a Raspberry PI powered LCD screen hanging in the wall, I can pretty much display whatever I want. Like for example:</p>

<ul>
  <li>
    <p>Web page using chrome <code class="language-plaintext highlighter-rouge">chromium-browser --kiosk $url</code></p>
  </li>
  <li>
    <p>Video using omxplayer <code class="language-plaintext highlighter-rouge">omxplayer video.mp4</code></p>
  </li>
  <li>
    <p>Use Kodi to display videos or other plugins.</p>
  </li>
  <li>
    <p>Youtube, twitch live video using the Livestreamer</p>
  </li>
  <li>
    <p>etc.</p>
  </li>
</ul>

<p><img src="/images/posts/2017-11-27-live-picture/raspberry.jpg" alt="raspberry" /></p>

<h3 id="display-live-video-using-livestreamer">Display live video using livestreamer</h3>

<p>For this project, I chose to display the London Tower Bridge from a live stream in youtube.</p>

<iframe width="560" height="315" src="https://www.youtube.com/embed/SMOb9d9s_mI" frameborder="0"></iframe>

<p>This can be easily achieved using <a href="https://github.com/chrippa/livestreamer">livestreamer</a> open source app, which allow us to display any live content from Youtube, twitch, livestream, dailymotion, etc… into a local video player, without using a web browser.</p>

<p>This is the command I’m using to display a Youtube link using omxplayer on fullscreen.</p>

<p><code class="language-plaintext highlighter-rouge">livestreamer $youtube_url 720p -n -p "omxplayer --no-osd --win '0 0 1280 800' "</code></p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">$youtube_url</code> is a variable with the url of the livestream on youtube</li>
  <li><code class="language-plaintext highlighter-rouge">720</code> is to select the resolution of the video, you can also use best or worst.</li>
  <li><code class="language-plaintext highlighter-rouge">-n</code> or <code class="language-plaintext highlighter-rouge">--fifo</code> Make the player read the stream through a named pipe instead of the stdin pipe</li>
  <li><code class="language-plaintext highlighter-rouge">-p</code> player to use</li>
  <li><code class="language-plaintext highlighter-rouge">--no-osd</code> hide the UI from omxplayer</li>
  <li><code class="language-plaintext highlighter-rouge">--win</code> display video on full screen (my screen resolution) on omxplayer</li>
</ul>

<p><a href="https://github.com/popcornmix/omxplayer">Omxplayer</a> is the best open source video player on Raspberry PI, you could try using VLC, but it will not work or display anything because of the lack of native hardware acceleration on Raspberry PI.</p>

<h3 id="script-to-display-on-startup">Script to display on startup</h3>

<p>I wanted to automatically run the video on startup, without any manual interaction.</p>

<p>There are a few ways to do it, but the best I found is using the <code class="language-plaintext highlighter-rouge">autostart</code> script located in <code class="language-plaintext highlighter-rouge">/home/pi/.config/lxsession/LXDE-pi/autostart</code>. On this script, you need to add <code class="language-plaintext highlighter-rouge">@</code> before every command.</p>

<p>If you want to keep the display ON, you’ll need to add these lines to prevent the screen going OFF after a few minutes.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>@xset s off
@xset -dpms
@xset s noblank
</code></pre></div></div>

<p>Then you can add the command from before to start the livestream on startup. This is all you need to add into the <code class="language-plaintext highlighter-rouge">/home/pi/.config/lxsession/LXDE-pi/autostart</code> script:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>@xset s off
@xset -dpms
@xset s noblank
@livestreamer https://youtu.be/SMOb9d9s_mI 720p -n -p "omxplayer --no-osd --win '0 0 1280 800' "
</code></pre></div></div>

<h2 id="conclussions-and-improvements">Conclussions and improvements</h2>

<p>This was an easy and cheap project to build, if you have an old screen, or you get a cheap one. The picture frame looks very nice hanging on the wall, and thanks to youtube and livestreamer, we can display any video very easily.</p>

<p>It took me some time to find the best streaming combination on Raspberry PI Zero. I tried using <code class="language-plaintext highlighter-rouge">chromium-browser --kiosk</code> but after sometime the browser was crashing; I tried using VLC to display M3U8 streaming video, but VLC was not efficient enough. Some links did not play on omxplayer, so at the end, I decided to use livestreamer, which works pretty well, and you can use it with other sources too.</p>

<p>I’d like to have a better LCD screen, maybe LED, with a direct HDMI connection and better viewing angle.</p>

<p>You could use the spare 12v connector to add a LED strip on the back of the frame, if you want to have some extra light effect.</p>

<p>Let me know what you think about this project, and if you’ve built your own.</p>]]></content><author><name>Javier Rengel</name></author><category term="hardware" /><category term="raspberry" /><category term="picture" /><category term="live" /><category term="youtube" /><summary type="html"><![CDATA[Live picture frame]]></summary></entry></feed>