<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US"><generator uri="https://jekyllrb.com/" version="4.1.1">Jekyll</generator><link href="https://blogs.swee.codes/feed.xml" rel="self" type="application/atom+xml" /><link href="https://blogs.swee.codes/" rel="alternate" type="text/html" hreflang="en-US" /><updated>2026-01-26T22:13:21+00:00</updated><id>https://blogs.swee.codes/feed.xml</id><title type="html">SweeBlogs</title><subtitle>A small community of writing tech blogs!</subtitle><entry><title type="html">Using Cloudflare R2 object storage with Nextcloud</title><link href="https://blogs.swee.codes/swee-nextcloud-r2/" rel="alternate" type="text/html" title="Using Cloudflare R2 object storage with Nextcloud" /><published>2025-04-10T22:11:00+00:00</published><updated>2026-01-26T21:48:23+00:00</updated><id>https://blogs.swee.codes/swee-nextcloud-r2</id><content type="html" xml:base="https://blogs.swee.codes/swee-nextcloud-r2/"><![CDATA[<p>By <a href="/team#Swee">Swee</a></p>

<p>Don’t have enough storage on your nextcloud box? You can use Object Storage providers like Cloudflare R2, I will how you how.</p>

<h2 id="why-i-recommend-cloudflare-r2">Why I recommend Cloudflare R2</h2>

<p>Cloudflare offers cheap object storage, and Nextcloud has decent performance with R2.</p>

<h3 id="1-storage-capacity">1. Storage capacity</h3>

<ul>
  <li>10GB free each month, then ~$0.02 each GB exceeded</li>
</ul>

<p>This means you can have infinite storage for free, but you will be charged a small amount for the month if you exceed 10GB in that month.</p>

<h3 id="2-low-costs-for-io">2. Low costs for I/O</h3>

<ul>
  <li>1 Million Write operations for free each month, then $4.50 USD for the other millions</li>
  <li>10 Million Read operations for free each month, then $0.40 USD for the other millions</li>
</ul>

<p>This means you will have 1M write operations and 10M read operations completely for free,
If you host a personal Nextcloud instance (like I do), then it is very unlikely for your
instance to exceed this in a matter of a month.</p>

<p>If you want to check more on Cloudflare’s pricing, check out their <a href="https://r2-calculator.cloudflare.com/">R2 pricing calculator</a>.</p>

<h2 id="configuring-nextcloud">Configuring Nextcloud</h2>

<p>To do this, you must have Nextcloud extracted but not installed via the web UI yet, here’s a <a href="https://www.geeksforgeeks.org/how-to-install-nextcloud-on-ubuntu/">tutorial on installing nextcloud</a> so you can get started.</p>

<p>Now, assuming Nextcloud is in <code class="language-plaintext highlighter-rouge">/var/www/nextcloud</code> we are going to create a new configuration file while we create our storage bucket.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /var/www/nextcloud/config/s3.config.php
</code></pre></div></div>

<p>On another browser window, go to the <a href="https://dash.cloudflare.com">Cloudflare Dashboard</a> and go to R2 &gt; Overview</p>

<p><img src="1.png" alt="" /></p>

<p>In that page, create a new bucket, doesn’t matter what the name is.</p>

<p><img src="2.png" alt="" />
<img src="3.png" alt="" /></p>

<p>Then, go to your bucket’s Settings, and copy the “S3 API” url.</p>

<p><img src="4.png" alt="" /></p>

<p>After this, go back to the R2 overview page and create an API token</p>

<p><img src="5.png" alt="" /></p>

<p><img src="6.png" alt="" /></p>

<p>This should be the configuration for the API token</p>

<p><img src="7.png" alt="" /></p>

<p>For extra security, you can restrict what IP can use the API token</p>

<p><img src="8.png" alt="" /></p>

<p>When you click create, do not copy the Token Value, copy the Access Key ID and Secret Access Key.</p>

<p><img src="9.png" alt="" /></p>

<p>Now you are ready to configure Nextcloud pre-install.</p>

<p>Go back to your terminal, and write a configuration like this:</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?php</span>
<span class="nv">$CONFIG</span> <span class="o">=</span> <span class="k">array</span> <span class="p">(</span>
  <span class="s1">'objectstore'</span> <span class="o">=&gt;</span> <span class="p">[</span>
       <span class="s1">'class'</span> <span class="o">=&gt;</span> <span class="s1">'\\OC\\Files\\ObjectStore\\S3'</span><span class="p">,</span>
       <span class="s1">'arguments'</span> <span class="o">=&gt;</span> <span class="p">[</span>
               <span class="s1">'bucket'</span> <span class="o">=&gt;</span> <span class="s1">'nextcloud-tutorial'</span><span class="p">,</span>
               <span class="s1">'hostname'</span> <span class="o">=&gt;</span> <span class="s1">'xxxxx.r2.cloudflarestorage.com'</span><span class="p">,</span>
               <span class="s1">'key'</span> <span class="o">=&gt;</span> <span class="s1">'access_key_id'</span><span class="p">,</span>
               <span class="s1">'secret'</span> <span class="o">=&gt;</span> <span class="s1">'secret_access_key'</span><span class="p">,</span>
               <span class="s1">'use_path_style'</span> <span class="o">=&gt;</span> <span class="kc">true</span><span class="p">,</span>
               <span class="s1">'region'</span> <span class="o">=&gt;</span> <span class="s2">"auto"</span><span class="p">,</span>
               <span class="s1">'use_ssl'</span> <span class="o">=&gt;</span> <span class="kc">true</span><span class="p">,</span>
               <span class="s1">'use_path_style'</span> <span class="o">=&gt;</span> <span class="kc">true</span><span class="p">,</span>
               <span class="s1">'verify_bucket_exists'</span> <span class="o">=&gt;</span> <span class="kc">false</span><span class="p">,</span>
               <span class="s1">'validateWrites'</span> <span class="o">=&gt;</span> <span class="kc">false</span><span class="p">,</span>
               <span class="s1">'concurrency'</span> <span class="o">=&gt;</span> <span class="mi">1</span><span class="p">,</span>
               <span class="s1">'sse_c_key'</span> <span class="o">=&gt;</span> <span class="s1">'your_encryption_key_here'</span><span class="p">,</span>
       <span class="p">],</span>
<span class="p">],</span>
<span class="p">);</span>
</code></pre></div></div>

<p>(Edited slightly in 2025-06-07 for <a href="https://help.nextcloud.com/t/226052/5">this fix</a>)</p>

<p>Here’s what you need to change:</p>

<ul>
  <li>Change <code class="language-plaintext highlighter-rouge">nextcloud-tutorial</code> to your R2 bucket’s name.</li>
  <li>Change <code class="language-plaintext highlighter-rouge">xxxxx.r2.cloudflarestorage.com</code> to the S3 API URL you copied, remove the bucket name from the URL.</li>
  <li>Change <code class="language-plaintext highlighter-rouge">access_key_id</code> to the <strong>Access Key ID</strong> you copied.</li>
  <li>Change <code class="language-plaintext highlighter-rouge">secret_access_key</code> to the <strong>Secret Access Key</strong> you copied.</li>
  <li>Change <code class="language-plaintext highlighter-rouge">your_encryption_key_here</code> to an encryption key, use <code class="language-plaintext highlighter-rouge">openssl rand --base64 32</code> to generate one, this is optional, if you don’t want to encrypt, delete the line.</li>
</ul>

<p>Then, save your file by pressing <code class="language-plaintext highlighter-rouge">CTRL-S</code> then exiting nano by pressing <code class="language-plaintext highlighter-rouge">CTRL-X</code></p>

<p>After that, you can access your Nextcloud URL and install Nextcloud like normal.
Instead of files being stored in internal storage, your files are now in an R2 bucket, enjoy the free space!</p>]]></content><author><name>Swee</name></author><category term="swee-tutorial" /><summary type="html"><![CDATA[Don't have enough storage on your nextcloud box? Here's how to use Cloudflare's R2 Object storage with your nextcloud instance!]]></summary></entry><entry><title type="html">Why the name `Swee` or `Nova Cat`?</title><link href="https://blogs.swee.codes/swee-why-the-name/" rel="alternate" type="text/html" title="Why the name `Swee` or `Nova Cat`?" /><published>2025-02-15T05:17:40+00:00</published><updated>2026-01-26T21:48:23+00:00</updated><id>https://blogs.swee.codes/swee-why-the-name</id><content type="html" xml:base="https://blogs.swee.codes/swee-why-the-name/"><![CDATA[<p>By <a href="/team#Swee">Swee</a></p>

<p><img src="https://swee.codes/assets/sweelogo-invert.png" alt="" /></p>

<p>So this question has been circulating for a while:</p>

<blockquote>
  <p>Why am I called Swee?</p>
</blockquote>

<p>The answer for this is not quite simple.
Around 5-6 years ago at time of posting, I registered a scratch account with the name <a href="https://scratch.mit.edu/users/sweetiepieh1">SweetiePieH1</a>, I actually liked using it, but later on as I matured,
I realize the name’s a bit long… and quite embarrassing <code class="language-plaintext highlighter-rouge">&gt;//&gt;</code></p>

<p><img src="https://discuss.swee.codes/uploads/default/optimized/1X/0678d1f880b7b07fb98a9e5a00cf3f3dff3e0d41_2_690x239.jpeg" alt="" /></p>

<p>So I decided to try something creative, take some part of the same out to make a name that’s easy to type, and not embarrassing, it’s a win win!</p>

<p>What I didn’t realize was that there was a lotta accounts named “Swee” around the web, so from inspiration from Dream (Yes, that Minecraft YouTuber) <code class="language-plaintext highlighter-rouge">DreamWasTaken</code>, I set my usernames in GitHub, Discord, etc. to <code class="language-plaintext highlighter-rouge">Sweeistaken</code></p>

<hr />

<p>So that settles the Swee part, but we haven’t gotten halfway through the question.</p>

<blockquote>
  <p>How/Why did I pick the name “Nova Cat” for my fursona?</p>
</blockquote>

<p>Okay, the name part is simple, but this explains some lore about the character.</p>

<p>At the time, what is called now “SweeZero” started as a Roblox group named “Swee Studios”. It used accent colors of green and red in the logo, which don’t mix well because they’re complementary colors.</p>

<p>I thought it might be time for Swee Studios to have a new name.
Rookie mistake: I used AI to do so, and everyone knows the only thing AI is good at is plagiarism.</p>

<p>So I decided to make my own name &amp; logo again, and came up with SweeZero when thinking about binary.</p>

<p>The SweeZero logo uses the same colors as NovaSoftia because Light Green mixes well with Medium Blue since they’re Analogous colors. But the logo design took inspiration from the Swee Studios design (SZ)</p>

<p><img src="https://discuss.swee.codes/uploads/default/optimized/1X/353be64d1a078fe39c39f7901fa87618a9cfdf0f_2_500x500.jpeg" alt="" /></p>

<p>This is a sketched concept of the choice, the real logos exist, but aren’t drawn to exact.
So my latest fursona is a soft(ia) cat named Nova.
He also has colors of SweeZero &amp; NovaSoftia.</p>

<p>Similarly, Nova Cat’s trauma was connected to NovaSoftia’s sudden name change (everyone wants to get rid of him.)</p>

<p>Since I’m now a furry, I decide that I have my display name set as Nova Cat, but still known as Swee.</p>

<p>You can comment here if you want more info.</p>]]></content><author><name>Swee</name></author><category term="swee-lore" /><summary type="html"><![CDATA[This articles discusses the decision of my internet names]]></summary></entry><entry><title type="html">Goodbye WordPress, Hello Jekyll!</title><link href="https://blogs.swee.codes/swee-hello-jekyll/" rel="alternate" type="text/html" title="Goodbye WordPress, Hello Jekyll!" /><published>2025-01-24T06:44:20+00:00</published><updated>2026-01-26T21:48:23+00:00</updated><id>https://blogs.swee.codes/swee-hello-jekyll</id><content type="html" xml:base="https://blogs.swee.codes/swee-hello-jekyll/"><![CDATA[<p>By <a href="/team#Swee">Swee</a></p>

<p>If you didn’t know, SweeBlogs used to be on <a href="https://wordpress.com">WordPress</a>,<br />
later in 2025, I’ve decided to migrate this old wordpress site to Jekyll.</p>

<p>This is just a test post to announce that my migration is in progress!</p>]]></content><author><name>Swee</name></author><category term="jekyll" /><summary type="html"><![CDATA[We are migrating SweeBlogs from WordPress to Jekyll]]></summary></entry><entry><title type="html">Why Linux? What distro do you use and why?</title><link href="https://blogs.swee.codes/swee-linux/" rel="alternate" type="text/html" title="Why Linux? What distro do you use and why?" /><published>2025-01-08T00:18:00+00:00</published><updated>2026-01-26T21:48:23+00:00</updated><id>https://blogs.swee.codes/swee-linux</id><content type="html" xml:base="https://blogs.swee.codes/swee-linux/"><![CDATA[<p>By <a href="/team#Swee">Swee</a></p>

<blockquote>
  <p>Why Linux?</p>
</blockquote>

<p>It’s a simple question, but doesn’t have a simple answer.<br />
Most of my opinions on Linux over Windows are from experience for years, so it will probably be biased.</p>

<h1 id="1-privacy">1. Privacy</h1>

<p>Trying to get the maximum privacy on a Windows box is hard, especially patches/tools that aren’t power user-friendly.</p>

<p>Linux, however, has privacy in your own hands/paws, whatever you choose has a mixed capability of privacy, most importantly,</p>

<blockquote>
  <p>Linux and (almost all of) its software are open-source, meaning anyone has the ability to read its code &amp; what it does, that also means people can contribute to its code or make their own versions of it to increase features or more importantly, privacy.</p>
</blockquote>

<p>Windows completely lacks this as it is a proprietary operating system, with mostly proprietary software (since it’s easier to do so)</p>

<h1 id="2-performance">2. Performance</h1>

<p>Mainly, the latest version of Windows (Right now, 11) is a very bloated piece of shit, it “requires” high-end hardware and even then, computers that meet the requirement suffer from the OS’ use of resources, I also believe Windows services (like Update) are a waste of time.</p>

<p>Linux offers more of a choice of your balance of a lightweight system, or a heavy (but beautiful) look. With many choices of a desktop environment like:</p>

<ul>
  <li>XFCE (Popular and lightweight)</li>
  <li>GNOME (Kind of in the middle)</li>
  <li>KDE (Great looks, lots of GPU power)</li>
</ul>

<h1 id="3-virtualization">3. Virtualization</h1>

<p>We all know virtualization is quite an important part of testing application development, we all know of VirtualBox &amp; VMWare workstation, in my opinion they’re all quite shit.</p>

<p>KVM is a great hypervisor for Linux, there’s no denying. It’s fast, it’s free, and it fully supports Linux. My recommended alternative for KVM on Windows would be Hyper-V.</p>

<h1 id="what-distro-do-i-use">What distro do I use?</h1>

<p>Last year, I’ve been using <a href="https://wiki.debian.org/DebianTesting">Debian Testing</a> for more up-to-date packages. In 2025 I decided to try <a href="https://alpinelinux.org/">Alpine Linux</a>.</p>

<p>![Screenshot of my fastfetch output in January 8th, 2025(1.jpeg)</p>

<h1 id="why-alpine">Why Alpine?</h1>

<p>Alpine Linux is a linux distribution that uses an alternative suite of programs/services than other distributions like Debian or the 10 billion Red Hat Linuxes (no offense lol).</p>

<ul>
  <li>Regular Linux distros use <a href="https://systemd.io/">systemd</a>, Alpine (and Gentoo) uses <a href="https://en.wikipedia.org/wiki/OpenRC">OpenRC</a></li>
  <li>Regularly, Linux distros today have the <a href="https://en.wikipedia.org/wiki/GNU_Core_Utilities">GNU Coreutils</a>, Alpine (and other minimal distros) still use <a href="https://www.busybox.net/about.html">BusyBox</a>.</li>
  <li>Almost all Linux distros use <a href="https://en.wikipedia.org/wiki/Glibc">GNU C Library (glibc)</a> while Alpine uses the more recent <a href="https://musl.libc.org/">musl libc</a>, which can ruin compatibility though.</li>
</ul>

<h1 id="but-alpine-is-for-containers">But Alpine is for containers!</h1>

<p>Shut up, Alpine is just as good as a desktop distribution. It has the latest KDE 6 and its suite. While Debian Testing does have KDE 6, it still has components that are stuck in version 5. Plus, I find Alpine more snappier than Debian-based distributions with the same DE. I also love the OpenRC init system, it makes my boot speed way faster.</p>

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

<p>I love using Linux on all of my machines, it’s fast, private, and easy to develop with. I really love Alpine for its more lightweight approach in a system suite. despite Alpine being popular for containers (especially docker), it’s just as good for desktops.</p>

<p>Though I am aware Linux is more friendly for geeks, but IMO, Linux seems to be evolving a lot when it comes to user friendliness, and will probably be ready for regular users in the upcoming years.</p>]]></content><author><name>Swee</name></author><summary type="html"><![CDATA[Why do I use Linux?]]></summary></entry><entry><title type="html">2025 is near! What was new with Swee in 2024?</title><link href="https://blogs.swee.codes/swee-2025/" rel="alternate" type="text/html" title="2025 is near! What was new with Swee in 2024?" /><published>2024-12-27T00:30:00+00:00</published><updated>2026-01-26T21:48:23+00:00</updated><id>https://blogs.swee.codes/swee-2025</id><content type="html" xml:base="https://blogs.swee.codes/swee-2025/"><![CDATA[<p>By <a href="/team#Swee">Swee</a></p>

<p><img src="1.png" alt="A banner for 2025 :3" /></p>

<p>This post is mainly showing how my life completely changed in 2024.</p>

<h1 id="1-joined-irc-this-year">1. Joined IRC this year.</h1>

<p><img src="2.jpeg" alt="An illustration of IRC, with logos of several clients, the channel syntax, and the usual formatting of a message." /></p>

<p>IRC is a rather old chatting platform, possibly one of the oldest on the net! I’ve decided to try out IRC when I saw “Quassel IRC” preinstalled on Lubuntu, after that, I decided to register my first IRC account, on the Libera.Chat network as <code class="language-plaintext highlighter-rouge">swee</code> using my galaxy tab 3.</p>

<p>What stood out most was some popular off-topic channels (Like <code class="language-plaintext highlighter-rouge">##</code> and <code class="language-plaintext highlighter-rouge">##chat</code>) and the <code class="language-plaintext highlighter-rouge">##furry</code> channel, but we’ll get to that later.</p>

<p>The Libera.Chat network has an interesting but rather friendly community, I spent most of my time staying awake the whole night, using my tab 3 to chat on IRC. It was a nice experience actually! People were quite impressed with my skills for such a young age.</p>

<p>IRC also changed my path when it came to programming, my most successful projects being <a href="https://git.swee.codes/swee/meownex">MeowNexUS</a> and <a href="https://ircat.xyz">Codename IRCat</a>.</p>

<h1 id="2-became-a-furry">2. Became a furry.</h1>

<p><img src="3.jpeg" alt="rawr I became a furry :3" /></p>

<p>Now this is another one of the major changes I had.</p>

<p>Either last year or two years ago, I tried to become a furry on scratch. Rookie mistake: I told my parents about it.</p>

<p>This time, in the <code class="language-plaintext highlighter-rouge">##furry</code> channel on libera, I’ve decided to fake myself as a furry with the nickname <code class="language-plaintext highlighter-rouge">sweeCat</code> though the “pretending” didn’t last long when I began making fursonas and ref sheets, months later I decide “fuck it, I’m a furry now.”</p>

<p>So I basically faked it ‘till I made it.</p>

<p>Honestly, I absolutely adore furry roleplay (as long as it’s SFW &amp; wholesome), although the thought of being e-cuddled lots (and enjoying it) might sound weird to you, but whatever, it’s cute :3</p>

<h1 id="3-got-a-domain--vps">3. Got a domain &amp; VPS.</h1>

<p>Yeah, all this work to get my website up, and this discourse instance too!<br />
I now get an allowance of $5/mo so it’s pretty easy if I get a budget VPS like I have right now.<br />
It’s not <strong>that</strong> much work for me to moderate all of this, so yeah :3</p>

<p><img src="4.gif" alt="" /></p>

<h1 id="other-things">Other things:</h1>
<ul>
  <li>Joined discord</li>
  <li>Tried the Mastodon Fediverse</li>
  <li>Joined Matrix</li>
  <li>Started migrating to Linux</li>
</ul>]]></content><author><name>Swee</name></author><summary type="html"><![CDATA[This post is mainly showing how my life completely changed in 2024.]]></summary></entry><entry><title type="html">Raspberry Pi Camera Module 3 NoIR review</title><link href="https://blogs.swee.codes/savalio-picam/" rel="alternate" type="text/html" title="Raspberry Pi Camera Module 3 NoIR review" /><published>2024-05-16T04:04:00+00:00</published><updated>2026-01-26T21:48:23+00:00</updated><id>https://blogs.swee.codes/savalio-picam</id><content type="html" xml:base="https://blogs.swee.codes/savalio-picam/"><![CDATA[<p>By <a href="/team#Savalio">Savalio</a></p>

<p>So, I was away for a bit. Why? I just wanted to take a break and just follow my heart. Soo I ended up with 2 Pi Zero 2 W’s, and a Pi camera module I’m going to be talking about. Let’s see if this is as good as the regular!</p>

<h2 id="part-1-setup">Part 1: Setup</h2>

<p>So, for this you’ll need:</p>

<ul>
  <li>The camera (DO NOT OPEN BOX YET)</li>
  <li>A Pi</li>
  <li>Some kind of grounding*</li>
  <li>Pi Camera to Pi Zero CSI port**</li>
</ul>

<blockquote>
  <p>* although optional, still highly recommended. I accidentally killed my first camera module with static even though the humidity in my room is at the comfortable 50%.</p>

  <p>** required only if you’re using any kind of Pi Zero.</p>
</blockquote>

<p>After getting the supplies, ground yourself and open the camera module box. It should include the camera, a regular cable and a piece of blue film. At first I thought that was a filter that will remove the saturation, but it made things worse on the color side.</p>

<p>Get out your camera module, and if you’re using the Pi Zero, yoink that cable and take out the cable you bought. Both for the Pi and the camera, have the piece of film on the cable face away from the board(image 2).</p>

<p>If you’re on the regular Pi, then, on the most versions, film should be facing the Ethernet port(image 1). Lift up the black tab and insert in the correct orientation.</p>

<p><img src="1.jpg" alt="" /></p>

<p><img src="2.jpg" alt="" /></p>

<p>Look closely near the Pi, black film is looking upwards</p>

<p>Now, the great thing is, Camera Module 3 works without any software setup, so it’s plug-and-play. Just boot up your pi and enter this into terminal:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>libcamera-hello
</code></pre></div></div>

<p>In a second, you’ll see a camera preview if you have a desktop environment and copies of a line like this outputted in the console:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#111 (30.01 fps) exp 16834.00 ag 1.12 dg 1.06</span>
</code></pre></div></div>

<p>To take a photo, you can enter this command:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>libcamera-still <span class="nt">-o</span> coolname.jpg
</code></pre></div></div>

<blockquote>
  <p>Note: the setup and use applies to the regular camera module 3 too</p>
</blockquote>

<h2 id="part-2-review">Part 2: Review</h2>

<p>Note: the review only applies to the NoIR version. Normal camera module review and more expansive testing will be done in the second part</p>

<p>So, let’s get to the pros and cons shall we?</p>

<p>Pros:</p>

<ul>
  <li>Picks up IR light</li>
  <li>Includes an IR filter to correct the colors</li>
  <li>Picks up most if not all the colors indoors</li>
  <li>High quality photos</li>
  <li>High quality build</li>
  <li>Low price ($25 for regular &amp; NoIR, $35 for regular &amp; NoIR wide)</li>
  <li>Easy to use</li>
  <li>Ships with a cable compatible with most of the RPi versions</li>
</ul>

<p>Cons:</p>

<ul>
  <li>Colors are lost if photos are taken of the outdoors</li>
  <li>IR filter doesn’t do that great of a job correcting colors</li>
  <li>Very ESD static sensitive</li>
  <li>Doesn’t include a cable for Pi Zero</li>
  <li>Focus is off sometimes</li>
</ul>

<p>To clear some things up, it’s a pretty dang good camera. Indoor photos all looked good and I was wondering why were people showing the scarily saturated photos. But when I took photos of the outside, I understood why.</p>

<p>So this is not really recommended if you’re doing any kind of outdoor photography where color really matters. It’s not big deal if you want to do object recognition, using the camera for security reasons or if you don’t care about the color. I couldn’t get it to work with motioneye though. So, here are all the test images:</p>

<h2 id="indoor">INDOOR:</h2>

<p>Camera module:</p>

<p><img src="3.jpg" alt="" /></p>

<p>My phone:</p>

<p><img src="4.jpg" alt="" /></p>

<p>Camera module:</p>

<p><img src="5.jpg" alt="" /></p>

<p>Original image:</p>

<p><img src="6.jpg" alt="" /></p>

<p>Natural light test indoors:</p>

<p><img src="7.jpg" alt="" /></p>

<p>Natural light test indoors 2:</p>

<p><img src="8.jpg" alt="" /></p>

<h2 id="outdoor">OUTDOOR:</h2>

<p>Camera Module:</p>

<p><img src="9.jpg" alt="" /></p>

<p>Camera Module w/ Included Filter:</p>

<p><img src="10.jpg" alt="" /></p>

<p>My phone:</p>

<p><img src="11.jpg" alt="" /></p>

<p>Camera Module 3:</p>

<p><img src="12.jpg" alt="" /></p>

<p>My phone:</p>

<p><img src="13.jpg" alt="" /></p>]]></content><author><name>Savalio</name></author><summary type="html"><![CDATA[Review of the Raspberry Pi Camera Module 3NoIR with a Pi Zero 2W]]></summary></entry><entry><title type="html">Weekly Tutorial: Bad USB with Arduino</title><link href="https://blogs.swee.codes/savalio-weekly-tutorial-4/" rel="alternate" type="text/html" title="Weekly Tutorial: Bad USB with Arduino" /><published>2024-03-27T04:57:00+00:00</published><updated>2026-01-26T21:48:23+00:00</updated><id>https://blogs.swee.codes/savalio-weekly-tutorial-4</id><content type="html" xml:base="https://blogs.swee.codes/savalio-weekly-tutorial-4/"><![CDATA[<p>By <a href="/team#Savalio">Savalio</a> (Edited by <a href="/team#Swee">Swee</a> for updates)</p>

<p>Yes, this is real! You don’t have to spend $100 on a practically illegal item for a funny prank or to educate your loved ones! In this guide, I will explain how to use USB HID libraries.</p>

<h2 id="part-0-legality-yap">Part 0: Legality yap</h2>

<p>Please be VERY sure that whatever your doing with this project is legal and follows the policies of the place if you’re doing it at a public place. DO NOT use this on stranger’s computers. I wish you happy jail-free fun!</p>

<h2 id="part-1-required-items">Part 1: Required items</h2>

<p>Here’s your shopping list for the project:</p>

<ul>
  <li>
    <p>Arduino capable of HID. This includes but is not limited to Arduino Leonardo, Arduino Nano ESP32, Arduino Due, Arduino Uno R4(both versions), etc.</p>
  </li>
  <li>
    <p>A cable to program the board.</p>
  </li>
</ul>

<p>Optional:</p>

<ul>
  <li>
    <p>A wire to short B1 and GND while programming.</p>
  </li>
  <li>
    <p>A breadboard for ease of use and shorting B1 and GND.</p>
  </li>
  <li>
    <p>A dummy computer to make sure you don’t ruin the main one.</p>
  </li>
</ul>

<h2 id="part-2-code-mouse">Part 2: Code (Mouse)</h2>

<p>Now open Arduino IDE, and paste in this code provided in the official Arduino Nano ESP32 cheatsheet:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">"USB.h"</span><span class="cp">
#include</span> <span class="cpf">"USBHIDMouse.h"</span><span class="cp">
</span><span class="n">USBHIDMouse</span> <span class="n">Mouse</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="c1">// put your setup code here, to run once:</span>
  <span class="n">Mouse</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span>
  <span class="n">USB</span><span class="p">.</span><span class="n">begin</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">// put your main code here, to run repeatedly:</span>
  <span class="n">Mouse</span><span class="p">.</span><span class="n">move</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</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="p">}</span>
</code></pre></div></div>

<p>If you upload this to your Arduino and keep it plugged in, it should start moving your mouse! We can easily modify the script to turn it into an annoying mouse jitterer:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">"USB.h"</span><span class="cp">
#include</span> <span class="cpf">"USBHIDMouse.h"</span><span class="cp">
</span><span class="n">USBHIDMouse</span> <span class="n">Mouse</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="c1">// put your setup code here, to run once:</span>
  <span class="n">Mouse</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span>
  <span class="n">USB</span><span class="p">.</span><span class="n">begin</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">// put your main code here, to run repeatedly:</span>
  <span class="n">Mouse</span><span class="p">.</span><span class="n">move</span><span class="p">(</span><span class="n">random</span><span class="p">(</span><span class="o">-</span><span class="mi">50</span><span class="p">,</span> <span class="mi">50</span><span class="p">),</span> <span class="n">random</span><span class="p">(</span><span class="o">-</span><span class="mi">50</span><span class="p">,</span> <span class="mi">50</span><span class="p">),</span> <span class="mi">0</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="p">}</span>
</code></pre></div></div>

<p>Now upload the code again and see your mouse jitter like crazy!</p>

<p>Tip: I recommend turning on boot loader mode on your Arduino before uploading, because uploading will get difficult to do!</p>

<p>Here’s the syntax for the function <code class="language-plaintext highlighter-rouge">Mouse.move()</code>:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">mouseObj</span><span class="p">.</span><span class="n">move</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="kt">int</span> <span class="n">y</span><span class="p">,</span> <span class="kt">int</span> <span class="n">wheel</span><span class="p">,</span> <span class="kt">int</span> <span class="n">pan</span><span class="p">);</span>
</code></pre></div></div>

<p>Now time to talk clicks. Paste this code into Arduino IDE:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">"USB.h"</span><span class="cp">
#include</span> <span class="cpf">"USBHIDMouse.h"</span><span class="cp">
</span><span class="n">USBHIDMouse</span> <span class="n">Mouse</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="c1">// put your setup code here, to run once:</span>
  <span class="n">Mouse</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span>
  <span class="n">USB</span><span class="p">.</span><span class="n">begin</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">// put your main code here, to run repeatedly:</span>
  <span class="n">Mouse</span><span class="p">.</span><span class="n">click</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="p">}</span>
</code></pre></div></div>

<p>Now unplug the board and repeatedly left click somewhere on the screen. Now plug in the board, and you should see the exact same behavior.</p>

<p>Here’s <code class="language-plaintext highlighter-rouge">Mouse.click()</code> syntax:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">mouseObj</span><span class="p">.</span><span class="n">click</span><span class="p">(</span><span class="kt">uint8_t</span> <span class="n">button</span> <span class="o">=</span> <span class="n">MOUSE_LEFT</span><span class="p">);</span>
</code></pre></div></div>

<p>NOTE: You don’t have to stick to the left click. You can do middle and right clicks too!</p>

<p>And last mouse functions: <code class="language-plaintext highlighter-rouge">Mouse.press()</code> and <code class="language-plaintext highlighter-rouge">Mouse.release()</code>, where <code class="language-plaintext highlighter-rouge">Mouse.press()</code> acts like a click and hold, and <code class="language-plaintext highlighter-rouge">Mouse.release()</code> acts like a button release. Syntax is similar to <code class="language-plaintext highlighter-rouge">Mouse.click()</code>.</p>

<h2 id="part-3-code-keyboard">Part 3: Code (Keyboard)</h2>

<p>Mouse was pretty fun, but keyboard is even more fun! You can write words, you can activate shortcuts, and more with pressing keys! But before that, lets first write something with it, just to see. Here’s Arduino-provided example of the keyboard:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">"USB.h"</span><span class="cp">
#include</span> <span class="cpf">"USBHIDKeyboard.h"</span><span class="cp">
</span><span class="n">USBHIDKeyboard</span> <span class="n">Keyboard</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="c1">// put your setup code here, to run once:</span>
  <span class="n">Keyboard</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span>
  <span class="n">USB</span><span class="p">.</span><span class="n">begin</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">// put your main code here, to run repeatedly:</span>
  <span class="n">Keyboard</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s">"Hello World"</span><span class="p">);</span>
  <span class="n">delay</span><span class="p">(</span><span class="mi">500</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Now hit upload and click on a search bar or inside the code editor. You will see <code class="language-plaintext highlighter-rouge">Hello World!</code> being typed! You can basically use a text file as a serial monitor! Here’s the syntax for the <code class="language-plaintext highlighter-rouge">Keyboard.print()</code> function:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">keyboardObj</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">var</span><span class="p">);</span>
</code></pre></div></div>

<p>Now, let’s get to keys! Paste this into the Arduino IDE:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">"USB.h"</span><span class="cp">
#include</span> <span class="cpf">"USBHIDKeyboard.h"</span><span class="cp">
</span><span class="n">USBHIDKeyboard</span> <span class="n">Keyboard</span><span class="p">;</span>

<span class="c1">// Windows and Linux:</span>
<span class="kt">char</span> <span class="n">ctrlKey</span> <span class="o">=</span> <span class="n">KEY_LEFT_CTRL</span><span class="p">;</span>
<span class="c1">// MacOS X:</span>
<span class="c1">//char ctrlKey = KEY_LEFT_GUI;</span>

<span class="kt">void</span> <span class="nf">setup</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">Keyboard</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span>
  <span class="n">USB</span><span class="p">.</span><span class="n">begin</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="n">delay</span><span class="p">(</span><span class="mi">1000</span><span class="p">);</span>
  <span class="n">Keyboard</span><span class="p">.</span><span class="n">press</span><span class="p">(</span><span class="n">ctrlKey</span><span class="p">);</span>
  <span class="n">Keyboard</span><span class="p">.</span><span class="n">press</span><span class="p">(</span><span class="sc">'n'</span><span class="p">);</span>
  <span class="n">delay</span><span class="p">(</span><span class="mi">100</span><span class="p">);</span>
  <span class="n">Keyboard</span><span class="p">.</span><span class="n">releaseAll</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<p>After you hit upload, don’t exit Arduino IDE. And in a second after the sketch uploads, you should see a new Arduino IDE window pop up. And this was done with the help of the guys named Keyboard.press()(presses the keys) and Keyboard.releaseAll()(releases the keys). Here’s the syntax for both:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">keyboardObj</span><span class="p">.</span><span class="n">press</span><span class="p">(</span><span class="kt">uint8_t</span> <span class="n">key</span><span class="p">);</span>
<span class="n">keyboardObj</span><span class="p">.</span><span class="n">releaseAll</span><span class="p">();</span>
</code></pre></div></div>

<p>Now, let’s make some more complicated projects with this. I won’t go too advanced (i.e. using other libraries, more than 100 lines of code), but you definitely can!</p>

<h2 id="part-4-example-projects">Part 4: Example projects</h2>

<h3 id="1-chaotic-mouse">1: Chaotic mouse</h3>

<p>This will not only jitter the mouse like crazy, it will also make it randomly click and hold buttons!</p>

<p>WARNING: Please save all important files before uploading the code!</p>

<p>Here’s the code:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">"USB.h"</span><span class="cp">
#include</span> <span class="cpf">"USBHIDMouse.h"</span><span class="cp">
</span><span class="n">USBHIDMouse</span> <span class="n">Mouse</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">Mouse</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span>
  <span class="n">USB</span><span class="p">.</span><span class="n">begin</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">pressChoice</span> <span class="o">=</span> <span class="n">random</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
  <span class="kt">int</span> <span class="n">pressButChoice</span> <span class="o">=</span> <span class="n">random</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">pressChoice</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">pressButChoice</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">Mouse</span><span class="p">.</span><span class="n">press</span><span class="p">();</span>
    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">pressButChoice</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">Mouse</span><span class="p">.</span><span class="n">press</span><span class="p">(</span><span class="n">MOUSE_MIDDLE</span><span class="p">);</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
      <span class="n">Mouse</span><span class="p">.</span><span class="n">press</span><span class="p">(</span><span class="n">MOUSE_RIGHT</span><span class="p">);</span>
    <span class="p">}</span>
  <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">pressChoice</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">pressButChoice</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">Mouse</span><span class="p">.</span><span class="n">click</span><span class="p">();</span>
    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">pressButChoice</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">Mouse</span><span class="p">.</span><span class="n">click</span><span class="p">(</span><span class="n">MOUSE_MIDDLE</span><span class="p">);</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
      <span class="n">Mouse</span><span class="p">.</span><span class="n">click</span><span class="p">(</span><span class="n">MOUSE_RIGHT</span><span class="p">);</span>
    <span class="p">}</span>
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="n">Mouse</span><span class="p">.</span><span class="n">release</span><span class="p">();</span>
    <span class="n">Mouse</span><span class="p">.</span><span class="n">release</span><span class="p">(</span><span class="n">MOUSE_MIDDLE</span><span class="p">);</span>
    <span class="n">Mouse</span><span class="p">.</span><span class="n">release</span><span class="p">(</span><span class="n">MOUSE_RIGHT</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="n">Mouse</span><span class="p">.</span><span class="n">move</span><span class="p">(</span><span class="n">random</span><span class="p">(</span><span class="o">-</span><span class="mi">100</span><span class="p">,</span> <span class="mi">100</span><span class="p">),</span> <span class="n">random</span><span class="p">(</span><span class="o">-</span><span class="mi">100</span><span class="p">,</span> <span class="mi">100</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="p">}</span>
</code></pre></div></div>

<p>Now, be ready for the chaos! I tested this on my school laptop and accidentally resized all the shortcuts…</p>

<h3 id="2-tab-closing-thing">2: Tab closing thing</h3>

<p>Your friend took embarrassed you for no reason? Got you in trouble at school or with your parents? Now you can get back! Close all their windows, which will demolish their progress in a game, destroy their unsaved part of the essay, remove part of their class notes and more.</p>

<p>Code to activate on Windows/Linux(shortcut tested on Ubuntu):</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">"USB.h"</span><span class="cp">
#include</span> <span class="cpf">"USBHIDKeyboard.h"</span><span class="cp">
</span><span class="n">USBHIDKeyboard</span> <span class="n">Keyboard</span><span class="p">;</span>

<span class="kt">char</span> <span class="n">altKey</span> <span class="o">=</span> <span class="n">KEY_LEFT_ALT</span><span class="p">;</span>
<span class="kt">char</span> <span class="n">f4Key</span> <span class="o">=</span> <span class="n">KEY_F4</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">Keyboard</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span>
  <span class="n">USB</span><span class="p">.</span><span class="n">begin</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="n">delay</span><span class="p">(</span><span class="mi">250</span><span class="p">);</span>
  <span class="n">Keyboard</span><span class="p">.</span><span class="n">press</span><span class="p">(</span><span class="n">altKey</span><span class="p">);</span>
  <span class="n">Keyboard</span><span class="p">.</span><span class="n">press</span><span class="p">(</span><span class="n">f4Key</span><span class="p">);</span>
  <span class="n">delay</span><span class="p">(</span><span class="mi">100</span><span class="p">);</span>
  <span class="n">Keyboard</span><span class="p">.</span><span class="n">releaseAll</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And this code for MacOS X:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">"USB.h"</span><span class="cp">
#include</span> <span class="cpf">"USBHIDKeyboard.h"</span><span class="cp">
</span><span class="n">USBHIDKeyboard</span> <span class="n">Keyboard</span><span class="p">;</span>

<span class="kt">char</span> <span class="n">cmdKey</span> <span class="o">=</span> <span class="n">KEY_LEFT_GUI</span><span class="p">;</span>
<span class="kt">char</span> <span class="n">f4Key</span> <span class="o">=</span> <span class="n">KEY_F4</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">Keyboard</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span>
  <span class="n">USB</span><span class="p">.</span><span class="n">begin</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="n">delay</span><span class="p">(</span><span class="mi">250</span><span class="p">);</span>
  <span class="n">Keyboard</span><span class="p">.</span><span class="n">press</span><span class="p">(</span><span class="n">cmdKey</span><span class="p">);</span>
  <span class="n">Keyboard</span><span class="p">.</span><span class="n">press</span><span class="p">(</span><span class="n">f4Key</span><span class="p">);</span>
  <span class="n">delay</span><span class="p">(</span><span class="mi">100</span><span class="p">);</span>
  <span class="n">Keyboard</span><span class="p">.</span><span class="n">releaseAll</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Now plug it in when they’re not looking and see your burning revenge!</p>

<h2 id="see-more-in-the-part-2">See more in the <del>Part 2!</del></h2>

<p>Sorry, there’s no part 2 coming anytime soon!</p>]]></content><author><name>Savalio</name></author><category term="savalio-weekly-tutorial" /><summary type="html"><![CDATA[Yes, this is real! You don’t have to spend $100 on a practically illegal item for a funny prank or to educate your loved ones!]]></summary></entry><entry><title type="html">Weekly tutorial: 3D-Printed springs?</title><link href="https://blogs.swee.codes/savalio-weekly-tutorial-3/" rel="alternate" type="text/html" title="Weekly tutorial: 3D-Printed springs?" /><published>2024-03-16T19:05:00+00:00</published><updated>2026-01-26T21:48:23+00:00</updated><id>https://blogs.swee.codes/savalio-weekly-tutorial-3</id><content type="html" xml:base="https://blogs.swee.codes/savalio-weekly-tutorial-3/"><![CDATA[<p>By <a href="/team#Savalio">Savalio</a></p>

<p><img src="1.jpeg" alt="" /></p>

<p>Ever had projects stopped because you didn’t have springs? You’re in the right place! Here’s a guide on how to design a 3D printable spring.</p>

<h2 id="part-0-files">Part 0: Files</h2>

<p>Heres the <a href="https://thangs.com/designer/savalio.anananimus/3d-model/3D%20printed%20spring-1031639?source=All+Files">Thangs 3D</a> page with the STL I am using for this project.</p>

<h2 id="part-1-design-rules-for-these-springs">Part 1: Design rules for these springs</h2>

<p>Here’s an example of how to design these:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>*  ****  ****  *
*  *  *  *  *  *
*  *  *  *  *  *
*  *  *  *  *  *
****  ****  ****

----------
Key:      |
* - .5 mm |
NOTE:     |
The coil  |
is 1 wall |
thick.    |
</code></pre></div></div>

<p>So, as you can see, it’s not very hard.<br />
The only real requirement is to 3D print these 1 wall thick.<br />
The actual lines can be any length and height.</p>

<p>You can try this in your own slicer when you will 3D print this coil later in this guide.</p>

<p>Generally, the wall thickness depends on the thickness of your nozzle. I was using a .4 mm nozzle, so I designed the walls as .5 mm, and printed as .625 mm. So if I had a .2 mm nozzle, I would design it as approximately .3 mm thick.</p>

<h2 id="part-2-software-prep">Part 2: Software prep</h2>

<p>For this project I used:</p>

<ul>
  <li>
    <p>SketchUp (free) - You can use any CAD software that you’re comfy with, but for this guide I will also explain the workflow for SketchUp.</p>
  </li>
  <li>
    <p>Ultimaker Cura (free) - Again, you can use any slicer, but I will explain the workflow for Cura.</p>
  </li>
</ul>

<h2 id="part-3-design">Part 3: Design</h2>

<p>Step 1: Get a rectangle as wide as the thickness of the walls in your slicer</p>

<blockquote>
  <p><strong>How do I do that in SketchUp?</strong></p>

  <p>First, get out this tool called “Rectangle” by searching the toolbox or typing “R” on your keyboard.</p>

  <p>Then, make it any random length, and as wide as your walls are (as described in Part 2). After that, get the “Push/Pull” tool by searching for it in the toolbox or pressing “P”, select the rectangle you made and pull up until you feel like it’s good.</p>

  <p><img src="2.png" alt="" /></p>

  <p><img src="3.png" alt="" /></p>

  <p><img src="4.png" alt="" /></p>

  <p><img src="5.png" alt="" /></p>
</blockquote>

<p>Step 2: Add a second rectangle to the first one, with the same width as the first, but shorter.</p>

<blockquote>
  <p><strong>How do I do that?</strong></p>

  <p>From any edge, measure the double of the wall thickness of the first rectangle with the “Tape Measure” tool allocated to the “T” key, and draw the line from the little plus that appears after you measure (MAKE SURE IT’S ON THE FACE) with the “Line” tool on the “L” key,</p>

  <p>then find the midpoint between the line and the edge, and draw the second line parallel to the first line. Erase the first line with the “Eraser” tool linked to the E button. Extrude from the segment you made with the line tool</p>

  <p><img src="6.png" alt="" /></p>

  <p><img src="7.png" alt="" /></p>

  <p><img src="8.png" alt="" /></p>

  <p><img src="9.png" alt="" /></p>

  <p><img src="10.png" alt="" /></p>

  <p><img src="11.png" alt="" /></p>

  <p><img src="12.png" alt="" /></p>

  <p><img src="13.png" alt="" /></p>

  <p><img src="4.png" alt="" /></p>
</blockquote>

<p>Step 3: Add a third rectangle to the second one so that first and this rectangle would be parallel and equal to each other.</p>

<p>Step 4: Repeat a few more times until it looks something like this:</p>

<blockquote>
  <p><img src="14.png" alt="" /></p>
</blockquote>

<h2 id="part-4-slicing">Part 4: Slicing</h2>

<p>This part is fairly quick and should be a breeze. Make sure that you use appropriate settings for your printer and if you haven’t used the printer in awhile, I advise you to print a calibration print and calibrate before tackling this.</p>

<blockquote>
  <p><strong>How to change the settings?</strong></p>

  <p>In Cura, click this:</p>

  <p><img src="15.png" alt="" /></p>

  <p>You will see the “Recommended print settings” appear. Click “Show Custom” to find more versatile settings, and it will look like this:</p>

  <p><img src="16.png" alt="" /></p>

  <p>Now feel free to change any settings you want.</p>
</blockquote>

<p>Now, assuming everything is done, export your STL file into the slicer and slice the print. Then, save to the removable drive after you’re satisfied with the print time.</p>

<blockquote>
  <p><strong>How to export file as STL in SketchUp?</strong></p>

  <p>First, click on the 3 parallel lines in your top left corner. Next, find and click “Download.” Then, click “STL”, and you should see your browser notify you about the download.</p>

  <p><strong>How do I import the STL file into Cura?</strong></p>

  <p>First, click on the folder icon. Then, choose the file you exported. After choosing, you will see your file appear as yellow. Any red areas indicate that it will print in the air. This is not a big deal if you’re printing overhangs or bridges, but if it was unintentional, make sure to either add supports or optimize your design.</p>
</blockquote>

<h2 id="part-5-printing">Part 5: Printing</h2>

<p>This might be the most frustrating part about this process, which is why I have quit 3D printing several times. So make sure the settings are right!</p>

<p>Now, insert the removable drive into the printer, select the file and hit print. Make sure to look for any potential flaws in the first layers and check in for once in awhile- is what I would say if this was a more than 20 min print.</p>

<p>You can just leave it alone while printing, it took me 9 minutes to print.</p>

<h2 id="part-6-now-what">Part 6: Now what?</h2>

<p>If you found this useful, great! If you can see some improvements, remix it on Thangs and share the link here in the comments. See ya next week!</p>]]></content><author><name>Savalio</name></author><category term="savalio-weekly-tutorial" /><summary type="html"><![CDATA[Ever had projects stopped because you didn’t have springs? You’re in the right place! Here’s a guide on how to design a 3D printable spring.]]></summary></entry><entry><title type="html">Weekly tutorial: Make a simple games console with Arduino</title><link href="https://blogs.swee.codes/savalio-weekly-tutorial-2/" rel="alternate" type="text/html" title="Weekly tutorial: Make a simple games console with Arduino" /><published>2024-03-11T04:59:00+00:00</published><updated>2026-01-26T21:48:23+00:00</updated><id>https://blogs.swee.codes/savalio-weekly-tutorial-2</id><content type="html" xml:base="https://blogs.swee.codes/savalio-weekly-tutorial-2/"><![CDATA[<p>By <a href="/team#Savalio">Savalio</a></p>

<p>Sorry for not posting for a week! I got kinda busy after the winter break was over. In this tutorial I’ll teach you how to make a super simple games console.</p>

<h2 id="1-supplies">1. Supplies</h2>

<p>You will need the following components:</p>

<ul>
  <li>An Arduino-compatible, I2C inclusive dev board (Xiao ESP32-S3 Sense in my case)</li>
  <li>An I2C OLED that is SSD1306 compatible: <a href="https://www.adafruit.com/product/938">get on Adafruit</a></li>
  <li>Neokey board: <a href="https://www.adafruit.com/product/4980">get on Adafruit</a></li>
  <li>MX-compatible mechanical switches: <a href="https://www.adafruit.com/product/4955">get on Adafruit</a></li>
  <li>Keycaps for the switches (optional if you’re on a VERY tight budget or you’re a psycho): <a href="https://www.adafruit.com/product/4956">get on Adafruit</a></li>
  <li>Arduino IDE</li>
  <li>Some prior Arduino IDE experience.</li>
</ul>

<blockquote>
  <p>This project was not optimized for the parts from other manufacturers, so you might need to do some debugging, like changing a library or changing an I2C address.</p>
</blockquote>

<h2 id="2-setup">2. Setup</h2>

<p>This project will require some simple wiring if you’re using Stemma QT, but you will need to solder if you want to use pins. Here’s a quick list of steps to connect:</p>

<ul>
  <li>Get your dev board’s I2C pin position</li>
  <li>Place the key caps on the switches</li>
  <li>Insert the switches on the flatter side of the PCB by pushing the switches into the sockets</li>
  <li>Insert the Stemma QT cable into the Stemma QT socket (if using Stemma QT)</li>
  <li>Connect the other end of the cable into the I2C pins of the dev board (blue -&gt; SDA; yellow -&gt; SCL)</li>
  <li>Repeat the last 2 steps for the OLED</li>
</ul>

<h2 id="3-code">3. Code</h2>

<p>Insert this code into your Arduino IDE:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">"Adafruit_NeoKey_1x4.h"</span><span class="cp">
#include</span> <span class="cpf">"seesaw_neopixel.h"</span><span class="cp">
#include</span> <span class="cpf">"Adafruit_GFX.h"</span><span class="cp">
#include</span> <span class="cpf">"Adafruit_SSD1306.h"</span><span class="cp">
</span> 
<span class="n">Adafruit_NeoKey_1x4</span> <span class="n">neokey</span><span class="p">;</span>  <span class="c1">// Creates the NeoKey object</span>
 
<span class="cp">#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
</span> 
<span class="c1">// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)</span>
<span class="c1">// The pins for I2C are defined by the Wire-library. </span>
<span class="cp">#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3D ///&lt; See datasheet for Address
#define NEOKEY_ADDRESS 0x30 // Change this as needed
</span><span class="n">Adafruit_SSD1306</span> <span class="nf">display</span><span class="p">(</span><span class="n">SCREEN_WIDTH</span><span class="p">,</span> <span class="n">SCREEN_HEIGHT</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">Wire</span><span class="p">,</span> <span class="n">OLED_RESET</span><span class="p">);</span>
 
<span class="kt">int</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="c1">// Integers for the sprite position</span>
<span class="kt">int</span> <span class="n">y</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
 
<span class="kt">void</span> <span class="nf">writeTextReset</span><span class="p">(</span><span class="n">String</span> <span class="n">text</span><span class="p">,</span> <span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="kt">int</span> <span class="n">y</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// Function to save some time coding</span>
  <span class="n">display</span><span class="p">.</span><span class="n">clearDisplay</span><span class="p">();</span> <span class="c1">// Clears the display</span>
  <span class="n">display</span><span class="p">.</span><span class="n">setCursor</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">);</span> <span class="c1">// Sets the cursor to the x and y parameters</span>
  <span class="n">display</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="n">text</span><span class="p">);</span> <span class="c1">// Writes the text to the display</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">delay</span><span class="p">(</span><span class="mi">1000</span><span class="p">);</span> <span class="c1">// Delay to initialize I2C</span>
  <span class="n">display</span><span class="p">.</span><span class="n">begin</span><span class="p">(</span><span class="n">SSD1306_SWITCHCAPVCC</span><span class="p">,</span> <span class="n">SCREEN_ADDRESS</span><span class="p">);</span> <span class="c1">// Starts the display</span>
 
  <span class="c1">// Show initial display buffer contents on the screen --</span>
  <span class="c1">// the library initializes this with an Adafruit splash screen.</span>
  <span class="n">display</span><span class="p">.</span><span class="n">display</span><span class="p">();</span>
  <span class="n">delay</span><span class="p">(</span><span class="mi">2000</span><span class="p">);</span> <span class="c1">// Pause for 2 seconds</span>
 
  <span class="c1">// Clear the buffer</span>
  <span class="n">display</span><span class="p">.</span><span class="n">clearDisplay</span><span class="p">();</span>
 
  <span class="n">display</span><span class="p">.</span><span class="n">setTextSize</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> <span class="c1">// Sets the text size</span>
  <span class="n">display</span><span class="p">.</span><span class="n">setTextColor</span><span class="p">(</span><span class="n">SSD1306_WHITE</span><span class="p">);</span> <span class="c1">// Draw white text</span>
  <span class="n">writeTextReset</span><span class="p">(</span><span class="s">"Awaiting connection..."</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">);</span>
  <span class="n">display</span><span class="p">.</span><span class="n">display</span><span class="p">();</span> <span class="c1">// Displays the text. This function is used to show the graphics that were prepared.</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="c1">// Begins searial</span>
  <span class="c1">//while (! Serial) delay(10); // Uncomment if you want to prevent the game to run without serial</span>
   
  <span class="n">delay</span><span class="p">(</span><span class="mi">100</span><span class="p">);</span>
 
  <span class="k">if</span> <span class="p">(</span><span class="o">!</span> <span class="n">neokey</span><span class="p">.</span><span class="n">begin</span><span class="p">(</span><span class="n">NEOKEY_ADDRESS</span><span class="p">))</span> <span class="p">{</span>     <span class="c1">// begin with I2C address, default is 0x30</span>
    <span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="s">"Could not start NeoKey, check wiring?"</span><span class="p">);</span>
    <span class="n">writeTextReset</span><span class="p">(</span><span class="s">"Could not connect"</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">);</span>
    <span class="n">display</span><span class="p">.</span><span class="n">display</span><span class="p">();</span>
    <span class="k">while</span><span class="p">(</span><span class="mi">1</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="p">}</span>
   
  <span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="s">"NeoKey started!"</span><span class="p">);</span>
  <span class="n">writeTextReset</span><span class="p">(</span><span class="s">"Key's animation playing..."</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">);</span> <span class="c1">// Tells the user that the NeoKey animation is playing</span>
  <span class="n">display</span><span class="p">.</span><span class="n">display</span><span class="p">();</span>
 
  <span class="c1">// Pulse all the LEDs on to show they're working</span>
  <span class="k">for</span> <span class="p">(</span><span class="kt">uint16_t</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">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">numPixels</span><span class="p">();</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// The animation itself</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">i</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">setPixelColor</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="mh">0xFF0000</span><span class="p">);</span> <span class="c1">// Changes the NeoPixel's color</span>
    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">i</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">setPixelColor</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="mh">0xFFFFFF</span><span class="p">);</span>
    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">i</span> <span class="o">==</span> <span class="mi">2</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">setPixelColor</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="mh">0x00FF00</span><span class="p">);</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
      <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">setPixelColor</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mh">0x00FFFF</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">show</span><span class="p">();</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">i</span> <span class="o">==</span> <span class="mi">0</span> <span class="o">|</span> <span class="n">i</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">delay</span><span class="p">(</span><span class="mi">250</span><span class="p">);</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
      <span class="n">delay</span><span class="p">(</span><span class="mi">500</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">setPixelColor</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="k">for</span> <span class="p">(</span><span class="kt">uint16_t</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">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">numPixels</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">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">setPixelColor</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="mh">0x000000</span><span class="p">);</span> <span class="c1">// Turns off the LEDs</span>
    <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">show</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="p">}</span>
 
  <span class="n">writeTextReset</span><span class="p">(</span><span class="s">"Key started! Key key: </span><span class="se">\n</span><span class="s"> A = red/Go left </span><span class="se">\n</span><span class="s"> B = white/Go up  </span><span class="se">\n</span><span class="s"> C = green/Go down  </span><span class="se">\n</span><span class="s"> D = blue/Go right"</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">);</span> <span class="c1">// Displays the controls on the display</span>
  <span class="n">display</span><span class="p">.</span><span class="n">display</span><span class="p">();</span>
 
  <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">setPixelColor</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mh">0xFF0000</span><span class="p">);</span> <span class="c1">// Shows the user which key is which</span>
  <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">setPixelColor</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mh">0xFFFFFF</span><span class="p">);</span>
  <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">setPixelColor</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mh">0x00FF00</span><span class="p">);</span>
  <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">setPixelColor</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mh">0x00FFFF</span><span class="p">);</span>
  <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">show</span><span class="p">();</span>
  <span class="n">delay</span><span class="p">(</span><span class="mi">5000</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">uint8_t</span> <span class="n">buttons</span> <span class="o">=</span> <span class="n">neokey</span><span class="p">.</span><span class="n">read</span><span class="p">();</span>
 
  <span class="c1">// Check each button, if pressed, light the matching neopixel</span>
   
  <span class="k">if</span> <span class="p">(</span><span class="n">buttons</span> <span class="o">&amp;</span> <span class="p">(</span><span class="mi">1</span><span class="o">&lt;&lt;</span><span class="mi">0</span><span class="p">))</span> <span class="p">{</span> <span class="c1">// If the button 0 (A) is pressed, then...</span>
    <span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="s">"Button A"</span><span class="p">);</span> <span class="c1">// Tell the Serial</span>
    <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">setPixelColor</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mh">0xFF0000</span><span class="p">);</span> <span class="c1">// Set the NeoKey color to red</span>
    <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">show</span><span class="p">();</span> <span class="c1">// Show the color</span>
    <span class="n">x</span> <span class="o">-=</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">// Move the character in the right direction</span>
    <span class="n">display</span><span class="p">.</span><span class="n">display</span><span class="p">();</span> <span class="c1">// Display is used in here and not at the end to remove flicker</span>
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="c1">// If not...</span>
    <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">setPixelColor</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="c1">// make sure that the neokey is off</span>
    <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">show</span><span class="p">();</span>
  <span class="p">}</span>
 
  <span class="k">if</span> <span class="p">(</span><span class="n">buttons</span> <span class="o">&amp;</span> <span class="p">(</span><span class="mi">1</span><span class="o">&lt;&lt;</span><span class="mi">1</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="s">"Button B"</span><span class="p">);</span>
    <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">setPixelColor</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mh">0xFFFFFF</span><span class="p">);</span> <span class="c1">// walter heisenberg white</span>
    <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">show</span><span class="p">();</span>
    <span class="n">y</span> <span class="o">-=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">display</span><span class="p">.</span><span class="n">display</span><span class="p">();</span>
     
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">setPixelColor</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
    <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">show</span><span class="p">();</span>
  <span class="p">}</span>
   
  <span class="k">if</span> <span class="p">(</span><span class="n">buttons</span> <span class="o">&amp;</span> <span class="p">(</span><span class="mi">1</span><span class="o">&lt;&lt;</span><span class="mi">2</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="s">"Button C"</span><span class="p">);</span>
    <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">setPixelColor</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mh">0x00FF00</span><span class="p">);</span> <span class="c1">// green</span>
    <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">show</span><span class="p">();</span>
    <span class="n">y</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">display</span><span class="p">.</span><span class="n">display</span><span class="p">();</span>
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">setPixelColor</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
    <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">show</span><span class="p">();</span>
  <span class="p">}</span>
 
  <span class="k">if</span> <span class="p">(</span><span class="n">buttons</span> <span class="o">&amp;</span> <span class="p">(</span><span class="mi">1</span><span class="o">&lt;&lt;</span><span class="mi">3</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="s">"Button D"</span><span class="p">);</span>
    <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">setPixelColor</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mh">0x00FFFF</span><span class="p">);</span> <span class="c1">// blue</span>
    <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">show</span><span class="p">();</span>
    <span class="n">x</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">display</span><span class="p">.</span><span class="n">display</span><span class="p">();</span>
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">setPixelColor</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
    <span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">show</span><span class="p">();</span>
  <span class="p">}</span>
   
  <span class="n">writeTextReset</span><span class="p">(</span><span class="s">":)"</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</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">// Gives the dev board some time to show the NeoPixels</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Add this chunk of code if you want to translate RGB into HEX:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Input a value 0 to 255 to get a color value.</span>
<span class="c1">// The colors are a transition r - g - b - back to r.</span>
 
<span class="kt">uint32_t</span> <span class="nf">Wheel</span><span class="p">(</span><span class="n">byte</span> <span class="n">WheelPos</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">if</span><span class="p">(</span><span class="n">WheelPos</span> <span class="o">&lt;</span> <span class="mi">85</span><span class="p">)</span> <span class="p">{</span>
   <span class="k">return</span> <span class="n">seesaw_NeoPixel</span><span class="o">::</span><span class="n">Color</span><span class="p">(</span><span class="n">WheelPos</span> <span class="o">*</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">255</span> <span class="o">-</span> <span class="n">WheelPos</span> <span class="o">*</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
  <span class="p">}</span> <span class="k">else</span> <span class="k">if</span><span class="p">(</span><span class="n">WheelPos</span> <span class="o">&lt;</span> <span class="mi">170</span><span class="p">)</span> <span class="p">{</span>
   <span class="n">WheelPos</span> <span class="o">-=</span> <span class="mi">85</span><span class="p">;</span>
   <span class="k">return</span> <span class="n">seesaw_NeoPixel</span><span class="o">::</span><span class="n">Color</span><span class="p">(</span><span class="mi">255</span> <span class="o">-</span> <span class="n">WheelPos</span> <span class="o">*</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">WheelPos</span> <span class="o">*</span> <span class="mi">3</span><span class="p">);</span>
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
   <span class="n">WheelPos</span> <span class="o">-=</span> <span class="mi">170</span><span class="p">;</span>
   <span class="k">return</span> <span class="n">seesaw_NeoPixel</span><span class="o">::</span><span class="n">Color</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">WheelPos</span> <span class="o">*</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">255</span> <span class="o">-</span> <span class="n">WheelPos</span> <span class="o">*</span> <span class="mi">3</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>What should happen:</p>

<ul>
  <li>The display shows the Adafruit splash screen</li>
  <li>The same display shows text saying “Key’s animation playing…”</li>
  <li>After it finishes, the OLED shows the controls and NeoKey shows the color code for each button</li>
  <li>When the NeoPixels eventually turn off and you press the NeoKeys, a moving smiley face will appear.</li>
  <li>Try pressing different keys and key combos and see how the smiley moves.</li>
</ul>

<blockquote>
  <video autoplay="" loop=""><source type="video/mp4" src="1.mp4" />Your browser doesn't support HTML video</video>
</blockquote>

<p>Now we’re gonna go into the juicy stuff, which is</p>

<h2 id="4-code-explanation">4. Code Explanation</h2>

<p>First, We’ll dive into the code outside of the functions. If we scroll for a bit, you can see this line of code:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define SCREEN_ADDRESS 0x3D
</span></code></pre></div></div>

<p>This defines the screen’s address, which is required if you want to use the module with I2C. This info is usually in:</p>

<ul>
  <li>Product description</li>
  <li>Official guide</li>
  <li>Datasheet</li>
</ul>

<p>Usually, the I2C have these weird solder pads.<br />
You might think, “what is this for?”. The answer is changing the I2C address.</p>

<p>This is useful when you want to use multiple I2C modules at once, but one of the modules has the same I2C address as another module you want to use.</p>

<p>For example, you want to use an I2C time of flight sensor, but you’re also using a screen, and both of them have the 0x3D address, and with those solder pads, you can take any one of the modules and your all-mighty soldering iron and solder it on.</p>

<blockquote>
  <p><img src="2.png" alt="" /> <br />
The solder pads I was talking about</p>
</blockquote>

<p>Next, we have this:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Adafruit_SSD1306</span> <span class="nf">display</span><span class="p">(</span><span class="n">SCREEN_WIDTH</span><span class="p">,</span> <span class="n">SCREEN_HEIGHT</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">Wire</span><span class="p">,</span> <span class="n">OLED_RESET</span><span class="p">);</span>
</code></pre></div></div>

<p>This makes the screen object. Now let’s talk about our first function in the program:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">writeTextReset</span><span class="p">(</span><span class="n">String</span> <span class="n">text</span><span class="p">,</span> <span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="kt">int</span> <span class="n">y</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// Function to save some time coding</span>
  <span class="n">display</span><span class="p">.</span><span class="n">clearDisplay</span><span class="p">();</span>
  <span class="n">display</span><span class="p">.</span><span class="n">setCursor</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">);</span>
  <span class="n">display</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="n">text</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>I made this function to save some time, and I think this is a good way to explain the display’s basic functions and text functions. First, we have two most important functions, these are:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>display.display();
display.clearDisplay();
</code></pre></div></div>

<p>The first function displays EVERYTHING you put on the canvas after the boot or last clearDisplay call, which clears the display.</p>

<p>If you call the first function after the boot, it will show the Adafruit splash screen. Here’s the syntax for the functions:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">dispObj</span><span class="p">.</span><span class="n">display</span><span class="p">();</span>
<span class="n">dispObj</span><span class="p">.</span><span class="n">clearDisplay</span><span class="p">();</span>
</code></pre></div></div>

<blockquote>
  <p><code class="language-plaintext highlighter-rouge">dispObj</code>: display object name</p>
</blockquote>

<p>Now, let’s come back and talk about the display object. The display object is created with this syntax:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Adafruit_SSD1306</span> <span class="nf">dispObjName</span><span class="p">(</span><span class="n">SCREEN_WIDTH</span><span class="p">,</span> <span class="n">SCREEN_HEIGHT</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">Wire</span><span class="p">,</span> <span class="n">RESET_PIN</span><span class="p">);</span>
</code></pre></div></div>

<p>Now, we’re writing. Literally! The functions for writing to the display are the same as if you were using serial.</p>

<p>The cursor function changes the position of the text and syntax looks like this:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">dispObj</span><span class="p">.</span><span class="n">setCursor</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">);</span>
</code></pre></div></div>

<p>The function for changing the text color applies to all Adafruit display libraries and looks like this:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">dispObj</span><span class="p">.</span><span class="n">setTextColor</span><span class="p">(</span><span class="n">str</span><span class="p">);</span>
</code></pre></div></div>

<blockquote>
  <p><code class="language-plaintext highlighter-rouge">str</code> = String variable</p>
</blockquote>

<p>And last but not least, we have the function that changes the size, the syntax looks like this:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">dispObj</span><span class="p">.</span><span class="n">setTextSize</span><span class="p">(</span><span class="n">Int</span><span class="p">);</span>
</code></pre></div></div>

<blockquote>
  <p><code class="language-plaintext highlighter-rouge">Int</code> = int variable</p>
</blockquote>

<p>Now, that we finished with the display functions, we can talk about our dear friend: NeoKey! The first NeoKey’s function used is this:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Adafruit_NeoKey_1x4</span> <span class="n">neokey</span><span class="p">;</span>
</code></pre></div></div>

<p>This defines the NeoKey object. Next we have this:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">setPixelColor</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="mh">0xFF0000</span><span class="p">);</span>
</code></pre></div></div>

<p>This changes the NeoKey’s color. The syntax looks like this:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">setPixelColor</span><span class="p">(</span><span class="n">Int</span><span class="p">,</span> <span class="n">hexCol</span><span class="p">);</span>
</code></pre></div></div>

<blockquote>
  <p><code class="language-plaintext highlighter-rouge">neokey</code> = NeoKey object
<code class="language-plaintext highlighter-rouge">Int</code> = NeoPixel number
<code class="language-plaintext highlighter-rouge">hexCol</code> = Color (HEX)</p>
</blockquote>

<p>Then, we have this:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">neokey</span><span class="p">.</span><span class="n">pixels</span><span class="p">.</span><span class="n">show</span><span class="p">();</span>
</code></pre></div></div>

<p>This shows the NeoPixel’s color that you set previously. To turn off the NeoPixels, you can just use the setPixelColor and write 0 in the color parameter.</p>

<p>And it looks like we came to the end! See ya next week.</p>]]></content><author><name>Savalio</name></author><category term="savalio-weekly-tutorial" /><summary type="html"><![CDATA[In this tutorial I’ll teach you how to make a super simple games console.]]></summary></entry><entry><title type="html">Make your own Arch Linux Distro with ArchISO</title><link href="https://blogs.swee.codes/swee-archiso/" rel="alternate" type="text/html" title="Make your own Arch Linux Distro with ArchISO" /><published>2024-03-09T23:12:00+00:00</published><updated>2026-01-26T21:48:23+00:00</updated><id>https://blogs.swee.codes/swee-archiso</id><content type="html" xml:base="https://blogs.swee.codes/swee-archiso/"><![CDATA[<p>By <a href="/team#Swee">Swee</a></p>

<p>Welcome to this tutorial on making a Linux Distro with <code class="language-plaintext highlighter-rouge">archiso</code>!<br />
Here are the requirements:</p>

<ul>
  <li>Arch Linux</li>
  <li>20GB or more disk space</li>
  <li>4GB RAM recommended</li>
  <li>64-Bit CPU recommended for regular use</li>
</ul>

<blockquote>
  <p>Tip: If you don’t want to use Arch linux, you can use a VM, but you won’t be able to test the new ISO unless you import the ISO to your host, then use a VM there.</p>
</blockquote>

<h2 id="why-archiso">Why ArchISO?</h2>

<p><code class="language-plaintext highlighter-rouge">archiso</code> is a simple tool for creating ISO images and respins (distros) of Arch Linux.<br />
Fact: Arch Linux’ official ISO images are made with <code class="language-plaintext highlighter-rouge">archiso</code>.</p>

<h2 id="preparing-tools">Preparing tools</h2>

<p>To install <code class="language-plaintext highlighter-rouge">archiso</code> on your machine, run this command as <code class="language-plaintext highlighter-rouge">root</code>:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pacman <span class="nt">-Syu</span> archiso
</code></pre></div></div>

<blockquote>
  <p>Tip: There could be an enchanced or newer version of <code class="language-plaintext highlighter-rouge">archiso</code> in AUR.</p>
</blockquote>

<p>According to <a href="https://wiki.archlinux.org/title/archiso#Prepare_a_custom_profile">Arch Linux Wiki</a>, there are two default profiles, <code class="language-plaintext highlighter-rouge">base</code> and <code class="language-plaintext highlighter-rouge">releng</code>. We’re going to use <code class="language-plaintext highlighter-rouge">releng</code> because it is recommended for respins.</p>

<p>To use the <code class="language-plaintext highlighter-rouge">releng</code> profile, you must copy the profile to the current directory you’re in. You can run this command without root:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cp</span> <span class="nt">-r</span> /usr/share/archiso/configs/releng ./archlive
</code></pre></div></div>

<p>Now that you’ve got a base profile, you’ll need to check <a href="https://gitlab.archlinux.org/archlinux/archiso/-/blob/master/docs/README.profile.rst">this README file</a> to get an understanding of what’s in the profile directory.</p>

<h2 id="editing-packages">Editing packages</h2>

<p>Now that you prepared the profile, you should edit the <code class="language-plaintext highlighter-rouge">packages.x86_64</code> file located in the root directory of the profile, you can also remove some unwanted packages that are originally for the Arch Linux installation medium.</p>

<blockquote>
  <p>WARNING: Make sure the packages exist in your <code class="language-plaintext highlighter-rouge">pacman</code> repositories or the ISO build will fail!</p>
</blockquote>

<p>If your package is located in AUR or isn’t in an online repository, you can append this code to <code class="language-plaintext highlighter-rouge">pacman.conf</code> and make a custom repository with that. <a href="https://wiki.archlinux.org/title/Pacman/Tips_and_tricks#Custom_local_repository">Click here if you need information about custom repositories.</a></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[customrepo]
SigLevel = Optional TrustAll
Server = file:///path/to/customrepo
</code></pre></div></div>

<blockquote>
  <p>Tip: You can also uncomment the <code class="language-plaintext highlighter-rouge">multilib</code> repository in <code class="language-plaintext highlighter-rouge">pacman.conf</code> if you need any packages there.</p>
</blockquote>

<h2 id="adding-files">Adding files</h2>

<p>If you use a graphical file manager like pcmanfm, then it will be simple to transfer your current configuration to your <code class="language-plaintext highlighter-rouge">archiso</code> profile.</p>

<blockquote>
  <p>Note: even if your machine has the default configuration of the program you want, you can copy the one from your machine to airootfs and edit it.</p>
</blockquote>

<p>if you are using the command line to prepare your profile, then you can use the following command to copy <code class="language-plaintext highlighter-rouge">iptables</code> (can be any file) to your <code class="language-plaintext highlighter-rouge">archiso</code> profile.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cp</span> <span class="nt">-r</span> /etc/iptables ./archlive/airootfs/etc
</code></pre></div></div>

<p>Tip: files like <code class="language-plaintext highlighter-rouge">/etc/sudoers</code> should copied to <code class="language-plaintext highlighter-rouge">archlive/airootfs/etc/</code>. think of airootfs being a filesystem offset.</p>

<h2 id="changing-os-branding">Changing OS branding</h2>

<p>Now it’s your turn for rebranding your OS, you can start with copying and editing <code class="language-plaintext highlighter-rouge">/etc/os-release</code> to airootfs and then editing the profile’s <code class="language-plaintext highlighter-rouge">grub</code> and <code class="language-plaintext highlighter-rouge">syslinux</code> folders. with editing these folders, you can change the OS names and descriptions in different bootloaders. plus a new splash for SYSLINUX is great.</p>

<h2 id="enabling-systemd-services">Enabling SystemD services</h2>

<p>To enable <code class="language-plaintext highlighter-rouge">systemd</code> services on your <code class="language-plaintext highlighter-rouge">archiso</code> profile, you have to add the service’s packages to both your <code class="language-plaintext highlighter-rouge">packages.x86_64</code> file and your system.</p>

<p><code class="language-plaintext highlighter-rouge">systemd</code> units run by <strong>wants targets</strong>, for example, <code class="language-plaintext highlighter-rouge">multi-user.target</code> can be added to the system by using this command.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mkdir</span> <span class="nt">-p</span> ./archlive/airootfs/etc/systemd/system/multi-user.target.wants
</code></pre></div></div>

<p>And to enable the services that is wanted by <code class="language-plaintext highlighter-rouge">multi-user.target</code> such as <code class="language-plaintext highlighter-rouge">gpm.service</code>, you can run this command to make a symlink of the service just like <code class="language-plaintext highlighter-rouge">systemctl enable</code> will.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ln</span> <span class="nt">-s</span> /usr/lib/systemd/system/gpm.service ./archlive/airootfs/etc/systemd/system/multi-user.target.wants/
</code></pre></div></div>

<blockquote>
  <p>WARNING: Point the symlink to the system file, symbolic links do not care if the target path doesn’t exist. If you set the target to an <code class="language-plaintext highlighter-rouge">airootfs</code> path, then the environment will still try to use that same path without translating to a system path.</p>
</blockquote>

<h3 id="how-to-enable-display-manager">How to enable display manager?</h3>

<p>You can also use systemd to add a display manager to your distro, to do this with LXDM, you can check <code class="language-plaintext highlighter-rouge">display-manager.service</code> to see which display manager is set.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ls</span> <span class="nt">-l</span> /etc/systemd/system/display-manager.service
</code></pre></div></div>

<p>And then to enable LXDM by creating a symbolic link.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ln</span> <span class="nt">-s</span> /usr/lib/systemd/system/lxdm.service ./archlive/airootfs/etc/systemd/system/display-manager.service
</code></pre></div></div>

<h2 id="creating-users-and-passwords">Creating users and passwords</h2>

<p>Adding users is pretty complicated but it’s simple to encrypt the password. to add a user named <code class="language-plaintext highlighter-rouge">user</code>, follow these steps:</p>

<h3 id="step-1-edit-etcpasswd">Step 1: Edit <code class="language-plaintext highlighter-rouge">/etc/passwd</code></h3>

<p>To add a user, you can change <code class="language-plaintext highlighter-rouge">/etc/passwd</code> like this</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root:x:0:0:root:/root:/usr/bin/zsh
user:x:1000:1000::/home/user:/usr/bin/zsh
</code></pre></div></div>

<p>and create the respective home directory in <code class="language-plaintext highlighter-rouge">airootfs</code>.</p>

<h3 id="step-2-generate-encrypted-password">Step 2: Generate encrypted password</h3>

<p>To make the encrypted password, create a dummy user with the password you want, then use the following command and copy the encrypted password after the colon (<code class="language-plaintext highlighter-rouge">:</code>) next to the username and before the colon next to <code class="language-plaintext highlighter-rouge">14871</code>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cat</span> /etc/shadow
</code></pre></div></div>

<p>Now, create /etc/shadow in <code class="language-plaintext highlighter-rouge">airootfs</code> and edit it like this.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root::14871::::::
user:enc:14871::::::
</code></pre></div></div>

<p>Replace enc with the password hash you just copied.</p>

<h3 id="step-3-add-groups">Step 3: Add groups</h3>

<p>Groups are an important part of the multi-user linux, it allows to tell programs what permissions someone has. create and edit <code class="language-plaintext highlighter-rouge">/etc/group</code> and add these important groups.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root:x:0:root
adm:x:4:user
wheel:x:10:user
uucp:x:14:user
user:x:1000:
</code></pre></div></div>

<h3 id="step-4-create-etcgshadow">Step 4: Create <code class="language-plaintext highlighter-rouge">/etc/gshadow</code></h3>

<p>You can create and edit <code class="language-plaintext highlighter-rouge">/etc/gshadow</code> like this.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root:!*::root
user:!*::
</code></pre></div></div>

<h2 id="setting-autologin">Setting autologin</h2>

<p>To set autologin on the <strong>console</strong>, you must create or change <code class="language-plaintext highlighter-rouge">/etc/systemd/systemgetty@tty1.service.d/autologin.conf</code> on the airootfs like this.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Service]
ExecStart=
ExecStart=-/sbin/agetty --autologin user --noclear %I 38400 linux
</code></pre></div></div>

<p>Replace <code class="language-plaintext highlighter-rouge">user</code> with the username of the user for the profile.</p>

<h2 id="how-to-set-autologin-on-lxdm">How to set autologin on LXDM?</h2>

<p>to setup autologin on LXDM, copy <code class="language-plaintext highlighter-rouge">/etc/lxdm/lxdm.conf</code> to airootfs and uncomment the following line.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#autologin=dgod</span>
</code></pre></div></div>

<p>Replace <code class="language-plaintext highlighter-rouge">dgod</code> with the username of the user for the profile.</p>

<blockquote>
  <p>Info: To setup autologin on any other Display Manager other than LXDM, you must follow their documentation.</p>
</blockquote>

<h2 id="build-the-iso">Build the ISO</h2>

<p>to build the ISO, you must prepare an empty folder that <code class="language-plaintext highlighter-rouge">archiso</code> will use to prepare the ISO for compilation.</p>

<blockquote>
  <p>Note: If you have enough RAM and the system allows to do so, you can make an empty folder in <code class="language-plaintext highlighter-rouge">/tmp</code> and use it as the work directory.</p>
</blockquote>

<p>After preparing the folder, you must run the following command, replacing each directory path with the ones on your machine:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkarchiso <span class="nt">-v</span> <span class="nt">-w</span> /path/to/work_dir <span class="nt">-o</span> /path/to/out_dir /path/to/profile/
</code></pre></div></div>

<blockquote>
  <p>Tip: After making the ISO, you can try <a href="https://wiki.archlinux.org/title/Secure_Boot#Booting_an_installation_medium">making your ISO bootable with secure boot enabled machines</a>, but I’m not that experienced to describe it for beginners yet.</p>
</blockquote>

<blockquote>
  <p>Warning: you must delete everything in the folder before building again, or archiso will skip the building entirely!</p>
</blockquote>

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

<p>To test your new ISO on an emulator, you can install the required packages using this command as <code class="language-plaintext highlighter-rouge">root</code>:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pacman <span class="nt">-Syu</span> qemu-desktop edk2-ovmf
</code></pre></div></div>

<p>And after installing <code class="language-plaintext highlighter-rouge">qemu</code>, run <code class="language-plaintext highlighter-rouge">archiso</code>’s built-in command for testing the ISO, replacing the file path(s) with the path(s) on your machine:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>run_archiso <span class="nt">-i</span> /path/to/file.iso
</code></pre></div></div>

<blockquote>
  <p>Tip: you can emulate UEFI by adding the <code class="language-plaintext highlighter-rouge">-u</code> argument to the command.</p>
</blockquote>

<h2 id="now-what">Now what?</h2>

<p>Now that you have created your own distro, go ahead and customize it as you like and improve it to the way you want it to be.</p>

<p>If you liked this tutorial, please like this post and subscribe to SweeBlogs for more Tutorials and blogs!</p>

<p>Arch Linux and the Arch Linux Logo are trademarks of the Arch Linux project.</p>]]></content><author><name>Swee</name></author><category term="swee-tutorial" /><summary type="html"><![CDATA[Archiso is a simple tool for creating ISO images and respins of Arch Linux.]]></summary></entry></feed>