<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gabriel Simmer</title>
    <description>The latest articles on DEV Community by Gabriel Simmer (@gmemstr).</description>
    <link>https://dev.to/gmemstr</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F473314%2F7df239e4-e082-4c17-870a-d7ebab41672f.jpeg</url>
      <title>DEV Community: Gabriel Simmer</title>
      <link>https://dev.to/gmemstr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gmemstr"/>
    <language>en</language>
    <item>
      <title>Tiny eink Dashboard</title>
      <dc:creator>Gabriel Simmer</dc:creator>
      <pubDate>Thu, 18 Feb 2021 20:30:02 +0000</pubDate>
      <link>https://dev.to/gmemstr/tiny-eink-dashboard-29a4</link>
      <guid>https://dev.to/gmemstr/tiny-eink-dashboard-29a4</guid>
      <description>&lt;p&gt;Lately I'm been pinning for new and exciting things to build. When I came across &lt;a href="https://thepihut.com/products/pi-zero-case-for-waveshare-2-13-eink-display"&gt;PiHut's case&lt;/a&gt; for the Raspberry Pi Zero and Waveshare Epaper Display, I quickly snapped it up, knowing I could put it to use - at the very least I would have my own eink display, which is a technology I am very keen on.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;sidenote: I will be using eink and epaper interchangeably in this post. "E Ink" is a trademarked term but is typically used in a more generic form of "eink".&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Having never done much, if anything, with the Raspberry Pi's hardware and "hat" capabilities, the first step was figuring out how the two interacted. Thankfully, Waveshare has a &lt;a href="https://github.com/waveshare/e-Paper"&gt;repository containing examples&lt;/a&gt; in both C and Python, the latter being the languages I opted for due to my familiarity. Setup is relatively straightforward, requiring one or two libraries fetched via &lt;code&gt;apt-get&lt;/code&gt; followed by a &lt;code&gt;git clone&lt;/code&gt; of the repository.&lt;/p&gt;

&lt;p&gt;Hold on though! The Pi Zero I have on hand does not have WiFi! How does one connect it to the internet? It's relatively straightforward, truth be told, when using Windows or macOS (Linux is another story, but we'll get to that). The Pi Zero (I am unsure if this extends to the full fat Pi) has a "gadget mode", wherein it can appear as a network adapter and allow your computer to connect over this. From there you can share your actual internet connection with it. Adafruit has a nifty little guide &lt;a href="https://learn.adafruit.com/turning-your-raspberry-pi-zero-into-a-usb-gadget/ethernet-gadget"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With the internet connection sorted and the repository cloned and tested, it was time to create a minimal viable product. This was more or less taking the example code and extracting the valuable bits, giving it a smaller footprint and easier to navigate layout. This simpler version &lt;a href="https://github.com/gmemstr/epaper-dashboard/tree/1.0"&gt;has been tagged&lt;/a&gt; for your viewing pleasure.&lt;/p&gt;

&lt;p&gt;One interesting note about this particular display is that the Python library draws on the display upside down. Why, I am not particularly sure, but it's a relatively easy thing to compensate for until I can figure out the root cause. This is why in the code the image is flipped at the end!&lt;/p&gt;

&lt;p&gt;This ran fine, but a few days after I made the leap to Linux full time (again) and left my Windows install behind. I was under the impression that sharing the connection would be just as straightforward, but it turned out &lt;a href="https://bbs.archlinux.org/viewtopic.php?id=216968"&gt;it was a bit more complex than that&lt;/a&gt; (it's entirely possible I was trying to rush through it and missed a critical piece) and I quickly gave up after many failed attempts to configure the necessary rules. Without this internet connection, the Pi was unable to sync the date and time, which was a small issue for a device showing the time. Since my desktop and Pi did, however, have a solid network connection, I figured I may as well leverage it to the best of my ability, and set out to rework the script in a more traditional webserver/client configuration, with my desktop generating the image. This has the added advantage of lessening the work the Pi itself has to do, hopefully lengthening the lifespan of it or the eink display.&lt;/p&gt;

&lt;p&gt;There's nothing particular to note about &lt;a href="https://github.com/gmemstr/epaper-dashboard/tree/2b2259eae4093036e1692513bba8b9dc22e303c2"&gt;the new codebase&lt;/a&gt;, beyond the minimal dependencies and routing system that I borrowed from a previous project, which looks for properly named files and functions in the &lt;code&gt;lib/&lt;/code&gt; directory before returning the 404.  It was especially important to keep dependencies on the Pi-side minimal since the lack of internet connection would require me to manually fetch them and sftp them up. This lack of connection also constrained me to Python 2, since the dependencies I had previously installed were done under that version. To combat the largest issue regarding the time and date of the Pi, I ran a small snippet over SSH that synced the time with my desktop's with a small offset to account for lag, and hope to integrate this sync directly into the script. While this single snippet could have solved the lack of internet problem without needing to rewrite the application, I think it was a worthwhile time investment for future expansion.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;update: since this post, I have set up an ntp server local to my desktop to sync the Pi with, so a lot of the problems regarding time being out of sync are solved for good! This sort of invalidates part of the need for the client &amp;lt;-&amp;gt; server, but oh well.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Overall, I'm very happy with the end product, especially with the new client/server structure. It will allow me to do some more complex things without worrying about bogging down the smaller CPU. The clock can lag behind by a few seconds, but that's not a deal breaker in my case. Porting the client to another Waveshare eink display should be as easy as switching out the display library and adjusting the parameters in the script, and I hope to obtain a larger display in the future to have more real estate for information.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What would you do with such a device connected to your computer? What information would you find useful? I'd love to gain some more inspiration for this!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>eink</category>
      <category>raspberrypi</category>
      <category>showdev</category>
    </item>
    <item>
      <title>CI/CD for Minecraft Resource Packs</title>
      <dc:creator>Gabriel Simmer</dc:creator>
      <pubDate>Tue, 22 Sep 2020 16:51:18 +0000</pubDate>
      <link>https://dev.to/gmemstr/ci-cd-for-minecraft-resource-packs-3hhp</link>
      <guid>https://dev.to/gmemstr/ci-cd-for-minecraft-resource-packs-3hhp</guid>
      <description>&lt;p&gt;I have recently been getting back into the world of modifying &lt;a href="//minecraft.net"&gt;Minecraft&lt;/a&gt; Java Edition, and as a part of that I have been spending some time learning the ins and outs of the new resource pack system.&lt;/p&gt;

&lt;p&gt;Historically, within Minecraft, it was possible to create "texture packs", which would change out textures of blocks, items, mobs, and sounds. This lead to the creation of a fairly sizeable community, and provided a fantastic outlet for many creatives playing Minecraft. However, this approach was rather simplistic, with some clear limitations, which were later solved with the current iteration of "resource packs". Resource packs extend beyond switching out textures, allowing for the modification of the physical model of items and blocks, changes to in-game text, and replacing the music completely. Both of these systems draw their resources from either .zip files or directories with a particular structure.&lt;/p&gt;

&lt;p&gt;While resource packs are associated much more closely with the creative side of Minecraft, I couldn't help but examine the technical possibilities regarding them. Since a large amount of metadata is stored as JSON files, specifically when it comes to custom models and defining alternative models or textures, it's easy to leverage version control systems such as Git to track changes. This is where the continuous integration and continuous eployment side of things comes into play. While developing a resource pack for a server, I realized quickly that deployment of changes was going to be difficult (for some context, Minecraft servers can define a custom resource pack to use, which clients can opt to download upon connecting), and started to investigate what could be done to make this process easier. The solution was relatively easy, but makes a huge impact on productivity and shipping new models or textures.&lt;/p&gt;

&lt;p&gt;Step one was finding a place to host the finalized zip file, so that client connecting to the server can fetch and apply it. To this end, I opted for a free F1-micro instance on Google Cloud. The only potentially limiting factor in this case is the 1GB of egress traffic from the server, but given the small size that the resource pack is currently (~11kb, so roughly ~1,100,000 downloads if my math is correct), I can safely ignore this for the time being. To serve the files themselves, I installed nginx and grabbed a certificate using certbot and LetsEncrypt.&lt;/p&gt;

&lt;p&gt;With the basic hosting out of the way, we can focus on the process of delivering the zip file. For this project, I'm using &lt;a href="https://sourcehut.org"&gt;sourcehut&lt;/a&gt;, and opted to use the available builds system for convenience (and to take a look at the competition!). There are three things to do to ensure the resource pack can be delivered:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Ensure the JSON resources are correctly formatted. Otherwise, models and textures will be broken. Unfortunately, checking the correctness of the data itself is another problem.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Package the resource pack as a zip file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Upload this zip file to the server.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of the steps above are necessarily "novel" when it comes to testing and delivering code, and was relatively simple to implement with the build manifest on sourcehut.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alpine/edge&lt;/span&gt;
&lt;span class="na"&gt;packages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;zip&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;rsync&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;jq&lt;/span&gt;
&lt;span class="na"&gt;secrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Secrets go here.&lt;/span&gt;
&lt;span class="na"&gt;sources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;git@git.sr.ht:~username/repository&lt;/span&gt;
&lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;username@deployment-server&lt;/span&gt;
&lt;span class="na"&gt;tasks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;cd repository&lt;/span&gt;
      &lt;span class="s"&gt;# Ensure all JSON files are readable JSON.&lt;/span&gt;
      &lt;span class="s"&gt;find . -type f -name "*.json" -exec cat {} + | jq . &amp;gt; /dev/null&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;cd repository&lt;/span&gt;
      &lt;span class="s"&gt;zip -r resource-pack.zip assets pack.mcmeta&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;cd repository&lt;/span&gt;
      &lt;span class="s"&gt;rsync -e "ssh -o StrictHostKeyChecking=no -i $HOME/.ssh/private-ssh-key" -avz resource-pack.zip $deploy:/public-directory&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Fantastic! End of story, right? It very well could be, but we can take this a step further. Minecraft servers can also specify a SHA-1 hash so clients can verify the integrity of the resource pack before applying it. While in most cases this is not an issue, it is helpful to specify.&lt;/p&gt;

&lt;p&gt;Rather than creating a small webserver to run continuously on an already constrained machine, I opted instead to leverage nginx and a simple static page, which is modified during the deployment process with the new SHA-1. This way, we save on resources, and there are fewer moving parts over all. The &lt;code&gt;&amp;lt;code id="resource-pack.zip"&amp;gt;&amp;lt;/code&amp;gt;&lt;/code&gt; portion will be replaced when we deploy the resource pack!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Resource Pack Repository&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/mvp.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;header&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Resource Pack Repository &lt;span class="nt"&gt;&amp;lt;small&amp;gt;&lt;/span&gt;server-ready&lt;span class="nt"&gt;&amp;lt;/small&amp;gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;Resource Pack&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;A basic resource pack!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Download: &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/packages/resource-pack.zip"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;code&amp;gt;&lt;/span&gt;/packages/resource-pack.zip&lt;span class="nt"&gt;&amp;lt;/code&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;sha1sum: &lt;span class="nt"&gt;&amp;lt;code&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"resource-pack.zip"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;index.html&lt;/code&gt; file is then deployed to our nginx server's web directory, to be served up when a visitor arrives at the website.&lt;/p&gt;

&lt;p&gt;We can then add the following commands to the &lt;code&gt;deploy&lt;/code&gt; step in our build manifest.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Fetch the old index file.&lt;/span&gt;
curl http://deployment-server &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; index-old.html
&lt;span class="c"&gt;# Update the code block with the new SHA-1&lt;/span&gt;
&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"s/(&amp;lt;code id=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;resource-pack&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;zip&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;).*(&amp;lt;&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="s2"&gt;code&amp;gt;)/&lt;/span&gt;&lt;span class="se"&gt;\1&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;resource-pack.zip | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{print $1}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="se"&gt;\2&lt;/span&gt;&lt;span class="s2"&gt;/g"&lt;/span&gt; index-old.html &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; index.html
&lt;span class="c"&gt;# Send the index file back up to the web host&lt;/span&gt;
rsync &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"ssh -o StrictHostKeyChecking=no -i &lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.ssh/private-ssh-key"&lt;/span&gt; &lt;span class="nt"&gt;-avz&lt;/span&gt; index.html &lt;span class="nv"&gt;$deploy&lt;/span&gt;:/public-web-directory
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And voila! We now have a static site that will always have the most recent SHA-1 hash available.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jK5O1sRS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/omd1mlcurr2yukgtdqri.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jK5O1sRS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/omd1mlcurr2yukgtdqri.png" alt="Final resource pack landing page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are a few improvements that could be made here, such as minifying any JSON data before compressing, or testing the actual content to ensure it matches a schema, but given the small scope of this project, I'm happy with where it landed, and I can now focus on completing the rest of the resource pack. Feel free to ask any question in the discussion below!&lt;/p&gt;

</description>
      <category>minecraft</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
