<?xml version="1.0" encoding="utf-8"?>

<feed xmlns="http://www.w3.org/2005/Atom">
<title>Tyler Cipriani: pages tagged computing</title>
<link href="https://tylercipriani.com/tags/computing/"/>
<link href="https://tylercipriani.com/tags/computing/index.atom" rel="self" type="application/atom+xml"/>
<author>

<name>Tyler Cipriani</name>

</author>




<id>https://tylercipriani.com/tags/computing/</id>

<subtitle type="html">Tyler Cipriani</subtitle>
<generator uri="http://ikiwiki.info/">ikiwiki</generator>
<updated>2022-12-01T03:26:08Z</updated>
<entry>
	<title>Home temperature monitoring on the cheap</title>

	<id>https://tylercipriani.com/blog/2022/11/30/home-temperature-monitoring-on-the-cheap/</id>

	<link href="https://tylercipriani.com/blog/2022/11/30/home-temperature-monitoring-on-the-cheap/"/>

	<author><name>Tyler Cipriani</name></author>


	<rights type="html" xml:lang="en">

		Copyright © 2022 Tyler Cipriani

	</rights>



	<category term="computing" />


	<updated>2022-12-01T03:26:08Z</updated>
	<published>2022-12-01T01:05:02Z</published>


	<content type="html" xml:lang="en">
	&lt;blockquote&gt;
&lt;p&gt;One accurate measurement is worth a thousand expert opinions&lt;/p&gt;
&lt;p&gt;– Grace Hopper&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://photos.tylercipriani.com/thumbs/29/572c7a17b2370f5a2a9e3b32760166/large.jpg&quot;
alt=&quot;One of my many AcuRite 06044M Wireless Temperature and Humidity Monitor Sensors&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;One of my many AcuRite 06044M Wireless
Temperature and Humidity Monitor Sensors&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;As I meandered around our new house, it was apparent some rooms were
sweltering, others were freezing, and the thermostat was lying about
everything.&lt;/p&gt;
&lt;p&gt;I could &lt;strong&gt;feel&lt;/strong&gt; it.&lt;/p&gt;
&lt;p&gt;But I felt compelled to &lt;strong&gt;measure&lt;/strong&gt; it. I was struck by
the need to know:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The temperature of each room&lt;/li&gt;
&lt;li&gt;How it changed throughout the day&lt;/li&gt;
&lt;li&gt;And how to monitor changes over time&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And I fulfilled my weird compulsion with a few simple tools:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;Cheap temperature and humidity sensors from Home Depot&lt;/li&gt;
&lt;li&gt;Home Assistant&lt;/li&gt;
&lt;li&gt;The original internet of things protocol: radio.&lt;/li&gt;
&lt;/ol&gt;
&lt;section id=&quot;cheap-temperature-sensors&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;Cheap temperature sensors&lt;/h2&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://photos.tylercipriani.com/thumbs/a8/92ab5b5fa2723e87cab3c833b53dad/large.jpg&quot;
alt=&quot;My rtl-sdr.com-branded rtl2832u dvb-t dongle I’ve had since 2013&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;My rtl-sdr.com-branded rtl2832u dvb-t
dongle I’ve had since 2013&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I have a handful of &lt;a
href=&quot;https://www.amazon.com/gp/product/B01G7BE9WK/ref=ox_sc_act_title_1?smid=ATVPDKIKX0DER&amp;amp;th=1&quot;&gt;AcuRite
sensors&lt;/a&gt; sprinkled throughout my house.&lt;/p&gt;
&lt;p&gt;These sensors are $16 today, but I bought mine around 2017 for $12
each at Home Depot.&lt;/p&gt;
&lt;p&gt;I know I could cobble together a cheaper temperature sensor:&lt;/p&gt;
&lt;table&gt;
&lt;tbody&gt;
&lt;tr class=&quot;odd&quot;&gt;
&lt;td&gt;&lt;a href=&quot;https://www.aliexpress.com/item/32678741657.html&quot;&gt;SHT30&lt;/a&gt;
temperature/humidity sensor&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;$1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;even&quot;&gt;
&lt;td&gt;&lt;a
href=&quot;https://www.aliexpress.com/item/1005004005586872.html&quot;&gt;WeMos
esp8266&lt;/a&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;$5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;odd&quot;&gt;
&lt;td&gt;&lt;a href=&quot;https://aliexpress.com/item/32800979738.html&quot;&gt;D1Mini OLED
screen&lt;/a&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;$2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;even&quot;&gt;
&lt;td&gt;Shipping&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;~$2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;odd&quot;&gt;
&lt;td&gt;A month of waiting for shipping&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;priceless&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;So for like $10 + solder + a weekend fiddling, you could make a
craptastic internet-equipped temperature/humidity sensor.&lt;/p&gt;
&lt;p&gt;But I dreaded building it.&lt;/p&gt;
&lt;p&gt;Tinkering with electronic doodads is a fun hobby. But I just wanted
something cheapish that would work.&lt;/p&gt;
&lt;p&gt;And the AcuRites work.&lt;/p&gt;
&lt;p&gt;Plus, the AcuRites work forever on a couple AAAs because they eschew
power-hungry wifi in favor of squawking data on 433 MHz.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;mhz-the-original-iot-protocol&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;433 MHz, the original IoT protocol&lt;/h2&gt;
&lt;p&gt;Even though 433.92 MHz sits squarely in the 70cm ham band, tons of
electronic junk spews signals on that frequency.&lt;/p&gt;
&lt;p&gt;And with a &lt;a
href=&quot;https://www.amazon.com/NooElec-NESDR-Mini-Compatible-Packages/dp/B009U7WZCA/ref=sr_1_6&quot;&gt;$25
USB dongle&lt;/a&gt; and &lt;a
href=&quot;https://github.com/merbanan/rtl_433/blob/6e1f120212005a5549dc184d9cd18002d49fdd10/src/devices/acurite.c#L974&quot;&gt;free
software&lt;/a&gt;, it’s easy to decode messages chirped out by your AcuRite
temperature sensors.&lt;/p&gt;
&lt;p&gt;So far, this project had been cheap and simple. But the next step,
gathering the data into a time-series database, required more fiddling
than I’d expected.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;home-assistant-mqtt-prometheus-and-grafana.&quot;
class=&quot;level2&quot;&gt;
&lt;h2&gt;Home Assistant, MQTT, Prometheus, and Grafana.&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://photos.tylercipriani.com/2022-11-30_rtl-433.png&quot;
alt=&quot;rtl_433’s commandline output&quot; /&gt; &lt;img
src=&quot;https://photos.tylercipriani.com/2022-11-30_house-temp.png&quot;
alt=&quot;Grafana graph of rooms of my house&quot; /&gt;&lt;/p&gt;
&lt;p&gt;It was a pain to get &lt;code&gt;rtl_433&lt;/code&gt; data into Home
Assistant.&lt;/p&gt;
&lt;p&gt;Maybe I’m missing something. But I ended up with a more complex
system than I wanted:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;a systemd unit running rtl_433 with syslog output over UDP:
&lt;code&gt;rtl_433 -F syslog:127.0.0.1:1433&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;a systemd unit relaying and filtering syslog output to MQTT (based
on &lt;a
href=&quot;https://github.com/merbanan/rtl_433/blob/54f0ebe4865327f89452d8e30ecb4c02fde065ae/examples/rtl_433_mqtt_relay.py&quot;&gt;this
upstream example&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;a systemd timer to restart rtl_433 when it unexpectedly hangs
(often)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After endless fiddling, the relay has an uptime measured in
months—it’s stable.&lt;/p&gt;
&lt;p&gt;From there, pushing data to Home Assistant, exposing it via the &lt;a
href=&quot;https://www.home-assistant.io/integrations/prometheus/&quot;&gt;Prometheus&lt;/a&gt;
plugin, and graphing it with Grafana was a breeze.&lt;/p&gt;
&lt;p&gt;Given all this work I’m happy to confirm what I’d long suspected:
&lt;strong&gt;some rooms in my house are hot while others are
cold&lt;/strong&gt;.&lt;/p&gt;
&lt;/section&gt;

	</content>


	<link rel="comments" href="//tylercipriani.com/blog/2022/11/30/home-temperature-monitoring-on-the-cheap/#comments" type="text/html" />


	<link rel="comments" href="//tylercipriani.com/blog/2022/11/30/home-temperature-monitoring-on-the-cheap/comments.atom" type="application/atom+xml" />

</entry>
<entry>
	<title>Git Notes: git&#x27;s coolest, most&#xA0;unloved&#xAD;&#xA0;feature</title>

	<id>https://tylercipriani.com/blog/2022/11/19/git-notes-gits-coolest-most-unloved-feature/</id>

	<link href="https://tylercipriani.com/blog/2022/11/19/git-notes-gits-coolest-most-unloved-feature/"/>

	<author><name>Tyler Cipriani</name></author>


	<rights type="html" xml:lang="en">

		Copyright © 2022 Tyler Cipriani

	</rights>



	<category term="computing" />


	<updated>2022-11-27T20:11:22Z</updated>
	<published>2022-11-19T22:43:37Z</published>


	<content type="html" xml:lang="en">
	&lt;blockquote&gt;
&lt;p&gt;the short of it is: they’re cool for appending notes from automated
systems (like ticket or build systems) but not really for having
interactive conversations with other developers (at least not yet)&lt;/p&gt;
&lt;p&gt;– Scott Chacon, &lt;a
href=&quot;https://github.blog/2010-08-25-git-notes-display/&quot;&gt;GitHub.blog&lt;/a&gt;,
Aug. 2010&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Git notes are almost a secret.&lt;/p&gt;
&lt;p&gt;They’re buried by their own distressing usability.&lt;/p&gt;
&lt;p&gt;But git notes are continually rediscovered by engineers trying to
stash metadata inside git.&lt;/p&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://photos.tylercipriani.com/2022-10-30_simonw-git-notes.png&quot;
alt=&quot;Sun, 30 Oct 2022 11:05 @simonw&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Sun, 30 Oct 2022 11:05 &lt;a
href=&quot;https://twitter.com/simonw/status/1586766260842266625&quot;&gt;&lt;span
class=&quot;citation&quot; data-cites=&quot;simonw&quot;&gt;@simonw&lt;/span&gt;&lt;/a&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Git notes are powerful tools.&lt;/strong&gt; And they could solve
so many problems—if only they were better known and easier to use.&lt;/p&gt;
&lt;section id=&quot;what-are-git-notes&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;&lt;span&gt;🧐&lt;/span&gt; What are git notes?&lt;/h2&gt;
&lt;p&gt;A common use of git notes is tacking metadata onto commits.&lt;/p&gt;
&lt;p&gt;Once a commit cements itself in git’s history—that’s it. It’s
impossible to amend a commit message buried deep in a repo’s log&lt;a
href=&quot;https://tylercipriani.com/tags/computing/#fn1&quot; class=&quot;footnote-ref&quot; id=&quot;fnref1&quot;
role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But git notes enable you to amend new information about old commits
in a special namespace. And they’re capable of so much more.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Notes stow metadata about anything tracked by
git&lt;/strong&gt;—any object: commits, blobs, and trees. All without futzing
with the object itself.&lt;/p&gt;
&lt;p&gt;You add notes to the latest commit in a repo like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git notes add -m &amp;#39;Acked-by: &amp;lt;tyler@tylercipriani.com&amp;gt;&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then it shows up in &lt;code&gt;git log&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;commit 1ef8b30ab7fc218ccc85c9a6411b1d2dd2925a16
Author: Tyler Cipriani &amp;lt;thcipriani@gmail.com&amp;gt;
Date:   Thu Nov 17 16:51:43 2022 -0700

    Initial commit

    Notes:
        Acked-by: &amp;lt;tyler@tylercipriani.com&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;git-notes-in-the-wild&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;&lt;span&gt;🥾&lt;/span&gt; Git notes in the wild&lt;/h2&gt;
&lt;p&gt;The git project itself offers an example of git notes in the wild.
They link each commit to its discussion on their mailing list.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;commit 00f09d0e4b1826ee0519ea64e919515032966450
Author: &amp;lt;redacted&amp;gt;
Date:   Thu Jan 28 02:05:55 2010 +0100

    bash: support &amp;#39;git notes&amp;#39; and its subcommands
    ...

Notes (amlog):
    Message-Id: &amp;lt;1264640755-22447-1-git-send-email-szeder@ira.uka.de&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This commit’s notes point intrepid users to the &lt;a
href=&quot;https://lore.kernel.org/git/1264640755-22447-1-git-send-email-szeder@ira.uka.de/&quot;&gt;thread
where this patch was discussed&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Other folks are using notes for things like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tracking time spent per commit or branch&lt;/li&gt;
&lt;li&gt;Adding review and testing information to git log&lt;/li&gt;
&lt;li&gt;And even fully distributed code review&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;storing-code-reviews-and-test-results-in-git-notes&quot;
class=&quot;level2&quot;&gt;
&lt;h2&gt;&lt;span&gt;📦&lt;/span&gt; Storing code reviews and test results in git
notes&lt;/h2&gt;
&lt;p&gt;Here is a plea for all forges: make code review metadata available
offline, inside git.&lt;/p&gt;
&lt;p&gt;The &lt;a
href=&quot;https://gerrit.googlesource.com/plugins/reviewnotes/+/refs/heads/master/src/main/resources/Documentation/refs-notes-review.md&quot;&gt;reviewnotes&lt;/a&gt;
plugin for Gerrit&lt;a href=&quot;https://tylercipriani.com/tags/computing/#fn2&quot; class=&quot;footnote-ref&quot; id=&quot;fnref2&quot;
role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; is an example of how to do this
well. It makes it easy to see who reviewed code in git log:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git fetch origin refs/notes/review:refs/notes/review
git log --show-notes=review&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command above shows me all the standard git log info alongside
information about what tests ran and who reviewed the code. All without
forcing me into my browser.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;commit d1d17908d2a97f057887a4afbd99f6c40be56849
Author: User &amp;lt;user@example.com&amp;gt;
Date:   Sun Mar 27 18:10:51 2022 +0200

    Change the thing

Notes (review):
    Verified+1: SonarQube Bot
    Verified+2: jenkins-bot
    Code-Review+2: Reviewer Human &amp;lt;reviewerhuman@wikimedia.org&amp;gt;
    Submitted-by: jenkins-bot
    Submitted-at: Tue, 14 Jun 2022 21:59:58 +0000
    Reviewed-on: https://gerrit.wikimedia.org/r/c/mediawiki/core/+/774005
    Project: mediawiki/core
    Branch: refs/heads/master&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id=&quot;distributed-code-review-inside-git-notes&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;&lt;span&gt;💠&lt;/span&gt; Distributed code review &lt;u&gt;inside&lt;/u&gt; git notes&lt;/h2&gt;
&lt;p&gt;Motivated hackers can knead and extend git notes. Using them as
distributed storage for any madcap idea.&lt;/p&gt;
&lt;p&gt;Someone at Google cobbled together a full-on code review system
teetering atop git notes called &lt;a
href=&quot;https://github.com/google/git-appraise&quot;&gt;git-appraise&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Its authors have declared it a “fully distributed code
review”—independent of GitHub, GitLab, or any other code forge.&lt;/p&gt;
&lt;p&gt;This system lets you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Request review of a change&lt;/li&gt;
&lt;li&gt;Comment on a change&lt;/li&gt;
&lt;li&gt;Review and merge a change&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And you can do all this from your local computer, even if GitHub is
down.&lt;/p&gt;
&lt;p&gt;Plus, it’s equipped with an affectedly unaesthetic web interface, if
that’s your thing.&lt;/p&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://photos.tylercipriani.com/2022-11-27_git-appraise-web.png&quot;
alt=&quot;The git-appraise web interface, in all its NaN-line-numbering glory.&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;The git-appraise web interface, in all
its NaN-line-numbering glory.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;no-one-uses-git-notes&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;&lt;span&gt;😭&lt;/span&gt; No one uses git notes&lt;/h2&gt;
&lt;p&gt;Git notes are a pain to use.&lt;/p&gt;
&lt;p&gt;And GitHub &lt;a
href=&quot;https://github.blog/2010-08-25-git-notes-display/&quot;&gt;opted to stop
displaying commit notes in 2014&lt;/a&gt; without much explanation.&lt;/p&gt;
&lt;p&gt;For commits, you can make viewing and adding notes easier using fancy
options in your gitconfig&lt;a href=&quot;https://tylercipriani.com/tags/computing/#fn3&quot; class=&quot;footnote-ref&quot; id=&quot;fnref3&quot;
role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt;. But for storing notes about blobs
or trees? Forget it. You’d need to be comfortable rooting around in
git’s &lt;a
href=&quot;https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain&quot;&gt;plumbing&lt;/a&gt;
first.&lt;/p&gt;
&lt;p&gt;So, for now: &lt;strong&gt;git notes are relegated to obscurity&lt;/strong&gt;.
Forever hamstrung by an obscure and clunky interface and limited
adoption—I often forget they’re there.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;forge-independence&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;&lt;span&gt;🗽&lt;/span&gt; Forge independence&lt;/h2&gt;
&lt;p&gt;Git is a distributed code review system. But much of the value of git
repos ends up locked into forges, like GitHub.&lt;/p&gt;
&lt;p&gt;Git notes are a path toward an alternative.&lt;/p&gt;
&lt;p&gt;Git distributes the history of a piece of code. &lt;strong&gt;Git notes
could make it possible to distribute the history of an entire
project.&lt;/strong&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section class=&quot;footnotes footnotes-end-of-document&quot;
role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot; role=&quot;doc-endnote&quot;&gt;&lt;p&gt;Without having to endure the &lt;a
href=&quot;https://groups.google.com/g/jenkinsci-dev/c/-myjRIPcVwU/m/mrwn8VkyXagJ&quot;&gt;perils
of a force push&lt;/a&gt;, anyway.&lt;a href=&quot;https://tylercipriani.com/tags/computing/#fnref1&quot; class=&quot;footnote-back&quot;
role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot; role=&quot;doc-endnote&quot;&gt;&lt;p&gt;The code review system used for &lt;a
href=&quot;https://gerrit.wikimedia.org/r/&quot;&gt;a&lt;/a&gt; &lt;a
href=&quot;https://go-review.googlesource.com/&quot;&gt;couple&lt;/a&gt; of &lt;a
href=&quot;https://android-review.googlesource.com/&quot;&gt;bigish&lt;/a&gt; &lt;a
href=&quot;https://chromium-review.googlesource.com/&quot;&gt;projects&lt;/a&gt;.&lt;a
href=&quot;https://tylercipriani.com/tags/computing/#fnref2&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn3&quot; role=&quot;doc-endnote&quot;&gt;&lt;p&gt;Noteably by automagically fetching
notes and displaying them in &lt;code&gt;git log&lt;/code&gt; via:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git config --add \
remote.origin.fetch \
&amp;#39;+refs/notes/*:refs/notes/*&amp;#39;
$ git config \
notes.displayRef \
&amp;#39;refs/notes/*&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;a href=&quot;https://tylercipriani.com/tags/computing/#fnref3&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;

	</content>


	<link rel="comments" href="//tylercipriani.com/blog/2022/11/19/git-notes-gits-coolest-most-unloved-feature/#comments" type="text/html" />


	<link rel="comments" href="//tylercipriani.com/blog/2022/11/19/git-notes-gits-coolest-most-unloved-feature/comments.atom" type="application/atom+xml" />

</entry>
<entry>
	<title>f.lux, but for your house</title>

	<id>https://tylercipriani.com/blog/2022/10/17/whole-house-circadian-lighting-with-home-assistant/</id>

	<link href="https://tylercipriani.com/blog/2022/10/17/whole-house-circadian-lighting-with-home-assistant/"/>

	<author><name>Tyler Cipriani</name></author>


	<rights type="html" xml:lang="en">

		Copyright © 2022 Tyler Cipriani

	</rights>



	<category term="computing" />


	<updated>2022-10-18T21:35:21Z</updated>
	<published>2022-10-17T19:10:21Z</published>


	<content type="html" xml:lang="en">
	&lt;blockquote&gt;
&lt;p&gt;Artificial lighting is omnipresent in contemporary society with
disruptive consequences for human sleep&lt;/p&gt;
&lt;p&gt;– Sarah L Chellappa, &lt;a
href=&quot;https://doi.org/10.1093/sleep/zsaa214&quot;&gt;https://doi.org/10.1093/sleep/zsaa214&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://photos.tylercipriani.com/thumbs/e3/bca0651e47a7d6aed643f9560bdd5c/large.jpg&quot;
alt=&quot;Night &amp;amp; Day – 🌛 left-side is 18:14 MDT (light color @ 2600 K); 🌞 right-side is 15:20 MDT (light color @ 4900 K)&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Night &amp;amp; Day – 🌛 left-side is 18:14
MDT (light color @ 2600 K); 🌞 right-side is 15:20 MDT (light color @
4900 K)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Light messes with my sleep, mood, and alertness.&lt;/p&gt;
&lt;p&gt;My house lights should auto-adjust themselves—like &lt;a
href=&quot;https://justgetflux.com/&quot;&gt;f.lux&lt;/a&gt; or &lt;a
href=&quot;http://jonls.dk/redshift/&quot;&gt;redshift&lt;/a&gt; on my laptop:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;🌞 White/Blue, bright light during the day&lt;/li&gt;
&lt;li&gt;🌛 Red/Yellow, dim light at night&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I was worried that getting this to work for my whole house meant
endless fiddling with &lt;a
href=&quot;https://twitter.com/internetofshit&quot;&gt;“smart”&lt;/a&gt; devices.&lt;/p&gt;
&lt;p&gt;But &lt;a href=&quot;https://www.home-assistant.io/&quot;&gt;Home Assistant&lt;/a&gt;
papered over the vendor and hardware woes and made setup simple.&lt;/p&gt;
&lt;section id=&quot;the-goals-of-my-house-lighting&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;The goals of my house lighting&lt;/h2&gt;
&lt;p&gt;I had the following goals for this project:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Circadian lighting in all rooms&lt;/strong&gt; – Bright,
blue/white light during the day; dim, red/yellow light after
sunset.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Control by switches&lt;/strong&gt; – I disdain fiddling with
tablets/phones to turn lights on and off. I’d also hoped to avoid an
always-on speaker listening to me.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automatic&lt;/strong&gt; – Light should shift temperature and
brightness automatically throughout the day.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ability to override&lt;/strong&gt; – I should be able to override
the automatic settings quickly with a switch. Sometimes it’s nice to be
able to see what you’re doing late at night—circadian rhythm be
damned.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Platform independent&lt;/strong&gt; – Because hue bulbs are
expensive, I need to be able to add to the system over time. Everything
from DIY light strips to hue bulbs to random smart bulbs from
Alibaba.com should work together.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Self-hosted&lt;/strong&gt; – All software should live on my home
network and work with only a local network.&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;the-results&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;The Results&lt;/h2&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://photos.tylercipriani.com/thumbs/18/b3386a14e8de005cbb0460f590e51b/large.jpg&quot;
alt=&quot;Red light from my Taloya smart light in the bathroom, so I’m not blinded in the middle of the night&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Red light from my Taloya smart light in
the bathroom, so I’m not blinded in the middle of the night&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The effects have been subtle but noticeable.&lt;/p&gt;
&lt;p&gt;During the day, I’m sharp, and at night I’m ready to sleep.&lt;/p&gt;
&lt;p&gt;In the evenings, after the sun sets, the lights dim, and it gets
harder to read and work on projects—&lt;strong&gt;that’s a feature&lt;/strong&gt;.
It’s a signal that it’s time for bed.&lt;/p&gt;
&lt;p&gt;The most significant benefit I’ve noticed is that &lt;strong&gt;I can get
back to sleep&lt;/strong&gt; after getting up in the middle of the night—now
that I’m no longer blinded by harsh overhead light in the bathroom.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;home-assistant-setup&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;Home Assistant setup&lt;/h2&gt;
&lt;figure&gt;
&lt;img src=&quot;https://photos.tylercipriani.com/2022-10-18_HA-kitchen.png&quot;
alt=&quot;Home Assistant Lovelace card to control my Circadian Lighting&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Home Assistant Lovelace card to control
my Circadian Lighting&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Home Assistant made this possible.&lt;/p&gt;
&lt;p&gt;The &lt;a
href=&quot;https://github.com/claytonjn/hass-circadian_lighting&quot;&gt;Circadian
lighting component&lt;/a&gt; (available via &lt;a href=&quot;https://hacs.xyz/&quot;&gt;Home
Assistant Community Store (HACS)&lt;/a&gt;) computes solar noon based on my
location and auto-adjusts the brightness of my lights and the color
temperature based on the time of day.&lt;/p&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://photos.tylercipriani.com/2022-10-17_circadian-lighting-grafana.png&quot;
alt=&quot;Grafana graph of all the lights in my house—brightness % vs. color temperature in Kelvin over a week&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Grafana graph of all the lights in my
house—brightness % vs. color temperature in Kelvin over a
week&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I use &lt;a href=&quot;https://www.zigbee2mqtt.io/&quot;&gt;Zigbee2MQTT&lt;/a&gt; to
capture events from my switches and send them to Home Assistant over &lt;a
href=&quot;https://www.home-assistant.io/integrations/mqtt&quot;&gt;MQTT&lt;/a&gt;—I found
this easier than adding a Zigbee gateway to Home Assistant directly.&lt;/p&gt;
&lt;p&gt;I have &lt;a
href=&quot;https://www.home-assistant.io/getting-started/automation/&quot;&gt;automation&lt;/a&gt;
that allows me to override circadian lighting when I need maximum
brightness or when I want the nightlight.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;the-hardware-setup&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;The hardware setup&lt;/h2&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://photos.tylercipriani.com/thumbs/b9/9dba616bfc80749e863e52bf110a24/large.jpg&quot;
alt=&quot;Tiny linux box for running Home Assistant VM + Conbee II Zigbee Gateway&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Tiny linux box for running Home Assistant
VM + Conbee II Zigbee Gateway&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Lights&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hue bulbs – I have a lot of hue bulbs.
&lt;ul&gt;
&lt;li&gt;Some are &lt;a
href=&quot;https://www.amazon.com/Philips-Hue-Bluetooth-compatible-Assistant/dp/B07QV9XB87/&quot;&gt;full-color
bulbs&lt;/a&gt;, while others do &lt;a
href=&quot;https://www.amazon.com/gp/product/B07QV9XLSD/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&amp;amp;psc=1&quot;&gt;color
temperature&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Three different form factors—A19 bulbs, &lt;a
href=&quot;https://www.amazon.com/gp/product/B07WTJZCZL/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&amp;amp;psc=1&quot;&gt;GU10s&lt;/a&gt;
for the &lt;a
href=&quot;https://www.ikea.com/us/en/p/tidig-ceiling-light-with-5-spotlights-nickel-plated-00262657/&quot;&gt;Ikea
Tidig&lt;/a&gt; in our kitchen, and the &lt;a
href=&quot;https://www.amazon.com/Philips-Hue-Bluetooth-compatible-activated/dp/B07VRF9NWK/&quot;&gt;Edison
bulb&lt;/a&gt; for our fancy dining room light.&lt;/li&gt;
&lt;li&gt;These are good light bulbs.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href=&quot;https://www.amazon.com/gp/product/B07WY3VM1M/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&amp;amp;psc=1&quot;&gt;Taloya
smart ceiling light&lt;/a&gt; – this is the bathroom light, integrated with
Home Assistant via &lt;a
href=&quot;https://github.com/rospogrigio/localtuya&quot;&gt;LocalTuya&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Buttons&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a
href=&quot;https://www.amazon.com/gp/product/B07D19YXND/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&amp;amp;psc=1&quot;&gt;Aqara
mini switch&lt;/a&gt; – one each for me and my partner for controlling the
bedroom lamps.&lt;/li&gt;
&lt;li&gt;&lt;a
href=&quot;https://www.amazon.com/gp/product/B099KDS3W9/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&amp;amp;th=1&quot;&gt;MOES
Zigbee 4-gang switch&lt;/a&gt; – bathroom lights—one button for on/off, one
button for bright, one for dim, one for the red nightlight.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Other hardware&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a
href=&quot;https://www.amazon.com/gp/product/B07PZ7ZHG5/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&amp;amp;psc=1&quot;&gt;Conbee
II Zigbee Gateway&lt;/a&gt; – Handles the incoming Zigbee signals.&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;todo-finish-lighting&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;TODO: finish lighting&lt;/h2&gt;
&lt;p&gt;House lighting is never done. I have ideas for my lights that I’m
still pondering.&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;&lt;strong&gt;SAD office light&lt;/strong&gt; – I’m lacking an extremely bright
office light—this is especially noticeable when winter brings darkness
at 4:30pm. I’m pondering building something that I can attach to this
system.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hyperion media lighting&lt;/strong&gt; – Ambiant bias lighting for
the TV via &lt;a
href=&quot;https://sequr.be/blog/2021/04/diy-ambilight-for-your-tv-or-computer-using-a-rpi-and-hyperion/&quot;&gt;Hyperion&lt;/a&gt;.
This is neat, but it’s a low priority since I don’t watch much TV (and
my TV is from 2012, anyway. I’m not fancy).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Moar WLED&lt;/strong&gt; – I added &lt;a
href=&quot;https://kno.wled.ge&quot;&gt;WLED&lt;/a&gt; strip lighting over the sink (which
works perfectly with Home Assistant), but I need more to brighten up the
whole space.&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;

	</content>


	<link rel="comments" href="//tylercipriani.com/blog/2022/10/17/whole-house-circadian-lighting-with-home-assistant/#comments" type="text/html" />


	<link rel="comments" href="//tylercipriani.com/blog/2022/10/17/whole-house-circadian-lighting-with-home-assistant/comments.atom" type="application/atom+xml" />

</entry>
<entry>
	<title>GitHub&#x27;s missing merge option</title>

	<id>https://tylercipriani.com/blog/2022/09/30/githubs-missing-merge-option/</id>

	<link href="https://tylercipriani.com/blog/2022/09/30/githubs-missing-merge-option/"/>

	<author><name>Tyler Cipriani</name></author>


	<rights type="html" xml:lang="en">

		Copyright © 2022 Tyler Cipriani

	</rights>



	<category term="computing" />


	<updated>2022-09-30T23:24:26Z</updated>
	<published>2022-09-30T20:56:36Z</published>


	<content type="html" xml:lang="en">
	&lt;blockquote&gt;
&lt;p&gt;github is a perfectly fine hosting site, and it does a number of
other things well too, but merges is not one of those things.&lt;/p&gt;
&lt;p&gt;– &lt;a
href=&quot;https://lore.kernel.org/lkml/CAHk-=wjbtip559HcMG9VQLGPmkurh5Kc50y5BceL8Q8=aL0H3Q@mail.gmail.com/&quot;&gt;Linus
Torvalds&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Git possesses parts of a decent &lt;a
href=&quot;https://en.wikipedia.org/wiki/Forge_(software)&quot;&gt;software
forge&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When git was developed by the Linux kernel community, they already
had bug tracking, documentation, and a mailing list, so (unlike &lt;a
href=&quot;https://fossil-scm.org/home/doc/trunk/www/fossil-v-git.wiki&quot;&gt;fossil&lt;/a&gt;)
git has none of those things.&lt;/p&gt;
&lt;p&gt;Enter GitHub. It uses “issues” for bug tracking and discussion, and
its code browser is unrivaled.&lt;/p&gt;
&lt;p&gt;But for all of its features, GitHub implements only a subset of git.
For instance, GitHub lacks the default merge strategy of git—the
fast-forward merge.&lt;/p&gt;
&lt;p&gt;And after some pondering I realized there’s a good reason for that:
it’s a cop-out.&lt;/p&gt;
&lt;section id=&quot;git-log-can-be-clean-or-accurate-not-both&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;&lt;code&gt;git log&lt;/code&gt; can be clean or accurate, not both&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;I want clean history, but that really means (a) clean and (b)
history.&lt;/p&gt;
&lt;p&gt;– &lt;a
href=&quot;https://www.mail-archive.com/dri-devel@lists.sourceforge.net/msg39091.html&quot;&gt;Linus
Torvalds&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Git log will always suck for someone.&lt;/p&gt;
&lt;p&gt;An eternal war rages between team “git log should be clean” vs. team
“git log should have an accurate history.”&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;📚 &lt;strong&gt;Team History&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Method: &lt;code&gt;git merge --no-ff&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;🟢 Pros: A complete history of how everything was developed&lt;/li&gt;
&lt;li&gt;🔴 Cons: You’ve opened a pandoras box of strange git situations. And
your git log looks like this now&lt;a href=&quot;https://tylercipriani.com/tags/computing/#fn1&quot; class=&quot;footnote-ref&quot;
id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;* (refs/heads/B)
* * Merge &amp;#39;C&amp;#39; into &amp;#39;B&amp;#39;
* |\
* | | * (refs/heads/C -- git revert B8)
* | | * Merge &amp;#39;B&amp;#39; into &amp;#39;C&amp;#39;
* | |/|
* | |/
* |/|
* * | B8
* | * C3
* |/
* * A (refs/heads/A)&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
&lt;img src=&quot;https://photos.tylercipriani.com/2022-09-30_git-merge.png&quot;
alt=&quot;Team history uses git merge --no-ff to ensure a merge commit is always created&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Team history uses
&lt;code&gt;git merge --no-ff&lt;/code&gt; to ensure a merge commit is always
created&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;✨ &lt;strong&gt;Team Clean&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Methods: &lt;code&gt;git merge --ff-only&lt;/code&gt; or
&lt;code&gt;git rebase &amp;amp;&amp;amp; git merge&lt;/code&gt; (extreme clean freaks add
the &lt;code&gt;--squash&lt;/code&gt; option)&lt;/li&gt;
&lt;li&gt;🟢 Pros: Linear history, &lt;code&gt;git log&lt;/code&gt; is easy to read,
&lt;code&gt;git revert&lt;/code&gt; requires no thought.&lt;/li&gt;
&lt;li&gt;🔴 Cons: You’re erasing history—you can no longer tell if two
commits were written together on a single feature branch.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
&lt;img src=&quot;https://photos.tylercipriani.com/2022-09-30_git-rebase.png&quot;
alt=&quot;Team clean uses git rebase &amp;amp;&amp;amp; git merge --ff-only to make it appear there was never a feature branch at all&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Team clean uses &lt;code&gt;git rebase&lt;/code&gt;
&amp;amp;&amp;amp; &lt;code&gt;git merge --ff-only&lt;/code&gt; to make it appear there was
never a feature branch at all&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;why-is-git-merge-bad&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;Why is &lt;code&gt;git merge&lt;/code&gt; bad?&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;git merge&lt;/code&gt; opted out.&lt;/p&gt;
&lt;p&gt;If a branch can be fast-forwarded, &lt;code&gt;git merge&lt;/code&gt; sticks the
commits on the end of the branch and never tells you there was a
merge—team clean.&lt;/p&gt;
&lt;p&gt;But if a branch has conflicts, you’ll need to fix them and create a
merge commit to say what you did—team history.&lt;/p&gt;
&lt;p&gt;Sometimes there’s a merge commit; sometimes not: Madness.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;what-does-github-do&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;What does GitHub do?&lt;/h2&gt;
&lt;p&gt;When you mash “merge” in GitHub it never executes plain
&lt;code&gt;git merge&lt;/code&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://photos.tylercipriani.com/2022-09-30_git-merge-button.png&quot;
alt=&quot;The GitHub merge options (the command line instructions are a lie)&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;The GitHub merge options (the command
line instructions are a lie)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;And sussing out what git command it will run is kafkaesque. I spent
some time mapping all the checkboxes and merge strategies into something
you could type into bash.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr class=&quot;header&quot;&gt;
&lt;th&gt;command&lt;/th&gt;
&lt;th&gt;GitHub&lt;/th&gt;
&lt;th&gt;Alignment&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class=&quot;odd&quot;&gt;
&lt;td&gt;&lt;code&gt;git merge&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;not implemented&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;¯\_(ツ)_/¯&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;even&quot;&gt;
&lt;td&gt;&lt;code&gt;git merge --ff-only&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;not implemented&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✨ Team Clean&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;odd&quot;&gt;
&lt;td&gt;&lt;code&gt;git rebase &amp;amp;&amp;amp; git merge --ff-only&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Rebase and Merge&lt;/td&gt;
&lt;td&gt;✨ Team Clean&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;even&quot;&gt;
&lt;td&gt;&lt;code&gt;git merge --no-ff&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a merge commit&lt;/td&gt;
&lt;td&gt;📚 Team History&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;odd&quot;&gt;
&lt;td&gt;&lt;code&gt;git merge --squash --ff-only BRANCH&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Squash and merge&lt;/td&gt;
&lt;td&gt;✨ Team Clean&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;even&quot;&gt;
&lt;td&gt;&lt;code&gt;git merge --is-ancestor &amp;amp;&amp;amp; git merge --no-ff&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a merge commit + &lt;a
href=&quot;https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/about-protected-branches#require-linear-history&quot;&gt;Require
linear history&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;✨ Team Clean&lt;a href=&quot;https://tylercipriani.com/tags/computing/#fn2&quot; class=&quot;footnote-ref&quot; id=&quot;fnref2&quot;
role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;There is a distinction between
&lt;code&gt;git rebase &amp;amp;&amp;amp; git merge --ff-only&lt;/code&gt; and
&lt;code&gt;git merge --ff-only&lt;/code&gt;. Rebasing modifies the commit—you end
up with a different SHA1.&lt;/p&gt;
&lt;p&gt;By not using the “merge if necessary” strategy of
&lt;code&gt;git merge&lt;/code&gt;, GitHub forces you to choose a side in the
eternal war. And that’s a good thing.&lt;/p&gt;
&lt;/section&gt;
&lt;section class=&quot;footnotes footnotes-end-of-document&quot;
role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot; role=&quot;doc-endnote&quot;&gt;&lt;p&gt;This is a contrived example of a “&lt;a
href=&quot;https://gist.github.com/thcipriani/0749be2a13815f398550a2865197dc49&quot;&gt;criss-cross
merge&lt;/a&gt;”&lt;a href=&quot;https://tylercipriani.com/tags/computing/#fnref1&quot; class=&quot;footnote-back&quot;
role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot; role=&quot;doc-endnote&quot;&gt;&lt;p&gt;In GitLab this is “Merge Commit with
Semi-linear history” which seems like a nicer UI vs the buried option to
“Require linear history”. This option mitigates some of the pain of an
ugly git log.&lt;a href=&quot;https://tylercipriani.com/tags/computing/#fnref2&quot; class=&quot;footnote-back&quot;
role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;

	</content>


	<link rel="comments" href="//tylercipriani.com/blog/2022/09/30/githubs-missing-merge-option/#comments" type="text/html" />


	<link rel="comments" href="//tylercipriani.com/blog/2022/09/30/githubs-missing-merge-option/comments.atom" type="application/atom+xml" />

</entry>
<entry>
	<title>Staging is a trap</title>

	<id>https://tylercipriani.com/blog/2022/09/15/staging-is-a-trap/</id>

	<link href="https://tylercipriani.com/blog/2022/09/15/staging-is-a-trap/"/>

	<author><name>Tyler Cipriani</name></author>


	<rights type="html" xml:lang="en">

		Copyright © 2022 Tyler Cipriani

	</rights>



	<category term="computing" />


	<updated>2022-09-16T17:38:11Z</updated>
	<published>2022-09-15T21:41:02Z</published>


	<content type="html" xml:lang="en">
	&lt;figure&gt;
&lt;img src=&quot;https://photos.tylercipriani.com/2022-09-15_staging-tweet.png&quot;
alt=&quot;@mipsytipsy&quot; /&gt;
&lt;figcaption
aria-hidden=&quot;true&quot;&gt;&lt;a href=&quot;https://twitter.com/mipsytipsy&quot;&gt;&lt;span
class=&quot;citation&quot;
data-cites=&quot;mipsytipsy&quot;&gt;@mipsytipsy&lt;/span&gt;&lt;/a&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Software staging clusters only grow.&lt;/p&gt;
&lt;p&gt;As production accrues more services, staging’s costs ramp up.&lt;/p&gt;
&lt;p&gt;And maintaining a single, massive, production-like staging may no
longer be the right answer.&lt;/p&gt;
&lt;p&gt;But several, small staging clusters—each fit for their purpose—offers
a more maintainable, cheaper alternative.&lt;/p&gt;
&lt;section
id=&quot;there-is-no-perfect-staging-there-are-only-perfect-stagings&quot;
class=&quot;level2&quot;&gt;
&lt;h2&gt;🍝 There is no perfect staging; there are only perfect stagings&lt;/h2&gt;
&lt;p&gt;Each reason for having a staging cluster requires a different level
of “production-likeness” to fit its use.&lt;/p&gt;
&lt;p&gt;You could put Apache and PHP on raspberry pi and call it Wikipedia’s
“staging.”&lt;/p&gt;
&lt;p&gt;And that’d be a fine place to demo a MediaWiki patch. But to be
confident deploying that patch into Wikipedia’s production: (to
paraphrase “Jaws” 🦈): you’re gonna need a bigger staging .&lt;/p&gt;
&lt;p&gt;In the 1970s, the pasta sauce brand Ragu tasked the psychophysicist
Howard Moskowitz with finding the perfect pasta sauce.&lt;a href=&quot;https://tylercipriani.com/tags/computing/#fn1&quot;
class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Moskowitz concluded the perfect pasta sauce doesn’t exist—it depends
on each individual’s wants and needs. &lt;strong&gt;There is no perfect pasta
sauce; there are only perfect pasta sauces.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Howard’s work is why you’ll find &lt;a
href=&quot;https://www.ragu.com/our-sauces/old-world-style-sauces/old-world-style-marinara-sauce/&quot;&gt;Ragu
Old World Style®&lt;/a&gt; next to &lt;a
href=&quot;https://www.ragu.com/our-sauces/ragu-simply/chunky-garden-vegetable&quot;&gt;Ragu
Chunky Garden Vegetable&lt;/a&gt; next to 10s of other Ragus.&lt;/p&gt;
&lt;p&gt;And much like pasta sauce&lt;a href=&quot;https://tylercipriani.com/tags/computing/#fn2&quot; class=&quot;footnote-ref&quot;
id=&quot;fnref2&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;: &lt;strong&gt;there can be no
perfect staging; only perfect stagings&lt;/strong&gt;.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;staging-trades-cost-vs.-production-likeness&quot;
class=&quot;level2&quot;&gt;
&lt;h2&gt;💱 Staging trades cost vs. production-likeness&lt;/h2&gt;
&lt;p&gt;The requirements for a staging cluster depend on its use.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Demos&lt;/strong&gt; – Demoing new code requires the same
software, maybe a few microservices, and (possibly) a subset of
production data.
&lt;ul&gt;
&lt;li&gt;🟢 Low cost&lt;/li&gt;
&lt;li&gt;🟢 Low production-likeness&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Exploratory testing&lt;/strong&gt; – QA requires the same
software, services, and a subset of production data. It’d be nice to run
it on the same type of infrastructure, too.
&lt;ul&gt;
&lt;li&gt;🟡 Medium cost&lt;/li&gt;
&lt;li&gt;🟡 Medium production-likeness&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deployment confidence&lt;/strong&gt; – 100% confidence requires a
parallel universe you destroy whenever a deployment goes wrong.
&lt;ul&gt;
&lt;li&gt;🔴 High cost&lt;/li&gt;
&lt;li&gt;🔴 High production-likeness&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
&lt;img src=&quot;https://photos.tylercipriani.com/2022-09-15_staging.png&quot;
alt=&quot;Staging trades costs for nearness to production&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Staging trades costs for nearness to
production&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Staging is a trade-off: resources (money, people, time) against
asymptotically approaching &lt;strong&gt;actual&lt;/strong&gt; production.&lt;/p&gt;
&lt;p&gt;The closer you get to production, the higher the costs and
complexity.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;production-should-be-reproducable&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;🔁 Production should be reproducable&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Setting up a staging server should be easy.&lt;/strong&gt; If it is
not easy, you already have a problem in your infrastructure, you just
don’t know it yet&lt;/p&gt;
&lt;p&gt;– Patrick McKenzie 🐉, &lt;a
href=&quot;https://www.kalzumeus.com/2010/12/12/staging-servers-source-control-deploy-workflows-and-other-stuff-nobody-teaches-you/&quot;&gt;Staging
Servers, Source Control &amp;amp; Deploy Workflows, And Other Stuff Nobody
Teaches You&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Configuration management should make it easy to rebuild production
from scratch. Otherwise, you’ve got a disaster in the offing.&lt;/p&gt;
&lt;p&gt;This creates an environment suitable for demos and end-to-end test
automation.&lt;/p&gt;
&lt;p&gt;But organizations are evolving away from using pre-production staging
to build deployment confidence.&lt;/p&gt;
&lt;p&gt;They’ve replaced their high-cost staging with a mix of &lt;a
href=&quot;https://martinfowler.com/bliki/CanaryRelease.html&quot;&gt;canary
deployments&lt;/a&gt; and advanced &lt;a
href=&quot;https://martinfowler.com/bliki/FeatureToggle.html&quot;&gt;feature
flagging&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Small environments with narrow scope—like testing or demoing—seem
like a reasonable trade-off of cost vs. benefit.&lt;/p&gt;
&lt;p&gt;But using pre-production staging as insurance for your
deployments—requiring snapshots of production data and maybe even
replayed traffic—seems too. darn. expensive.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;further-reading&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;📚 Further reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a
href=&quot;https://squeaky.ai/blog/development/why-we-dont-use-a-staging-environment&quot;&gt;Why
we don’t use a staging environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://devops.com/dear-staging-were-done/&quot;&gt;Dear staging,
we’re done&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href=&quot;https://flagsmith.com/blog/delete-your-staging-environment/&quot;&gt;Delete
your staging environment&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section class=&quot;footnotes footnotes-end-of-document&quot;
role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot; role=&quot;doc-endnote&quot;&gt;&lt;p&gt;This is an anecdote related by
Malcolm Gladwell in a 2007 Ted Talk, “&lt;a
href=&quot;https://www.ted.com/talks/malcolm_gladwell_choice_happiness_and_spaghetti_sauce&quot;&gt;Choice,
Happiness, and Spaghetti Sauce&lt;/a&gt;&lt;a href=&quot;https://tylercipriani.com/tags/computing/#fnref1&quot;
class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot; role=&quot;doc-endnote&quot;&gt;&lt;p&gt;There’s a joke here about “spaghetti
code” that I’m too lazy to find.&lt;a href=&quot;https://tylercipriani.com/tags/computing/#fnref2&quot; class=&quot;footnote-back&quot;
role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;

	</content>


	<link rel="comments" href="//tylercipriani.com/blog/2022/09/15/staging-is-a-trap/#comments" type="text/html" />


	<link rel="comments" href="//tylercipriani.com/blog/2022/09/15/staging-is-a-trap/comments.atom" type="application/atom+xml" />

</entry>
<entry>
	<title>Meshtastic: A Review</title>

	<id>https://tylercipriani.com/blog/2022/07/31/meshtastic-a-review/</id>

	<link href="https://tylercipriani.com/blog/2022/07/31/meshtastic-a-review/"/>

	<author><name>Tyler Cipriani</name></author>


	<rights type="html" xml:lang="en">

		Copyright © 2022 Tyler Cipriani

	</rights>



	<category term="computing" />


	<updated>2022-08-01T01:55:54Z</updated>
	<published>2022-07-31T22:15:47Z</published>


	<content type="html" xml:lang="en">
	&lt;p&gt;The Meshtastic is my solarpunk dream—a cheap, encrypted, offgrid
communicator. But the project is still in the alpha stages (and it
shows).&lt;/p&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://photos.tylercipriani.com/thumbs/f3/350cee528c8c41071befaffc524dc1/large.jpg&quot;
alt=&quot;LILYGO® TTGO Meshtastic T-Beam V1.1 ESP32 LoRa&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;LILYGO® TTGO Meshtastic T-Beam V1.1 ESP32
LoRa&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;a href=&quot;https://meshtastic.org/&quot;&gt;Meshtastic&lt;/a&gt; is a communication
system. Its firmware runs on bare-bones “T-Beam” devices. T-Beams are
available fully-assembled and pre-flashed &lt;a
href=&quot;https://www.aliexpress.com/item/2255800992363816.html&quot;&gt;for about
$35&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The devices enable encrypted, text-message-style communication via an
app on your smartphone. No cell service required.&lt;/p&gt;
&lt;p&gt;I bought two Meshtastic T-Beams for a recent trip to &lt;a
href=&quot;https://www.nps.gov/yell/index.htm&quot;&gt;Yellowstone National Park&lt;/a&gt;.
The devices worked as advertised—we could share texts and locations
between our Android phones even though we had no service.&lt;/p&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://photos.tylercipriani.com/thumbs/90/377211ff8add4dc1e3950dc71c8ae9/medium.jpg&quot;
alt=&quot;Meshtastic in Yellowstone National Park&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Meshtastic in Yellowstone National
Park&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;section id=&quot;problems-meshtastic-solves&quot; class=&quot;level1&quot;&gt;
&lt;h1&gt;Problems Meshtastic solves&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;Communication infrastructure fails&lt;/strong&gt;. Whether an &lt;a
href=&quot;https://www.arrl.org/news/american-red-cross-asks-arrl-s-assistance-with-puerto-rico-relief-effort&quot;&gt;earthquake
in Puerto Rico&lt;/a&gt; or a trip to a national park—it’s easy to imagine a
situation where your smartphone is useless.&lt;/p&gt;
&lt;p&gt;And &lt;strong&gt;it’s trivial to surveil your
communications&lt;/strong&gt;—AT&amp;amp;T established room &lt;a
href=&quot;https://en.wikipedia.org/wiki/Room_641A&quot;&gt;641A&lt;/a&gt; to funnel
communication to the NSA. And there are reports of “&lt;a
href=&quot;https://theintercept.com/2020/07/31/protests-surveillance-stingrays-dirtboxes-phone-tracking/&quot;&gt;stingrays&lt;/a&gt;”—devices
that masquerade as cell towers—intercepting the text messages of
protestors.&lt;/p&gt;
&lt;p&gt;Meshtastic attempts to solve these problems using cheap, readily
available parts and open-source software.&lt;/p&gt;
&lt;p&gt;Shut up and take my money.&lt;/p&gt;
&lt;section id=&quot;what-i-dislike&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;What I dislike&lt;/h2&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://photos.tylercipriani.com/thumbs/13/b962ea3b15638114a64e5750f7d0c6/large.jpg&quot;
alt=&quot;Opus BT-C3100 battery charger&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Opus BT-C3100 battery
charger&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;There’s no way around it: this is an alpha quality project. Right
now, it’s only usable by nerds (like me 🌠). You’ll probably have a bad
time if you’re not a tinkerer or a hobbyist.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Alpha quality&lt;/strong&gt; – The project is hard to use, even
for the basics. During our trip to Yellowstone, we repeatedly lost our
bluetooth connection to the devices—they kept going to sleep. And the
interface is sometimes unclear—I ended up holding down buttons, waiting
for something (anything) to happen.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;iOS requires Testflight&lt;/strong&gt; – The Android mobile app
worked well, but the iOS app requires Testflight to install—which seems
like a pain.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Batteries&lt;/strong&gt;/&lt;a href=&quot;https://xkcd.com/651/&quot;&gt;small
bombs&lt;/a&gt; – The T-Beams run off big honkin’ 18650 batteries—the same
lithium-ion cells used in Tesla battery packs. While the batteries last
all day, I had to make extra purchases. Later I realized they run fine
off of USB battery packs, but I was uncertain about that when I bought
it. These things added to my costs:
&lt;ul&gt;
&lt;li&gt;&lt;a
href=&quot;https://www.18650batterystore.com/products/opus-btc3100-v2-2&quot;&gt;Opus
BT-C3100 battery charger&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href=&quot;https://www.18650batterystore.com/products/sanyo-ncr18650ga&quot;&gt;Sanyo
NCR18650GA 3500mAh 10A Battery&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PCBs are intimidating&lt;/strong&gt; – Holding a PCB (printed
circuit board) intimidates electronics neophytes. There are stickers
available on the discourse that read: “&lt;a
href=&quot;https://meshtastic.discourse.group/t/limited-run-meshtastic-stickers/6092&quot;&gt;Meshtastic:
this is not a bomb&lt;/a&gt;” (for &lt;a
href=&quot;https://uniteng.com/wiki/doku.php?id=meshtastic:station&quot;&gt;base
stations&lt;/a&gt; in the field).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“Meshtastic”&lt;/strong&gt; – My brain refuses to type
“meshtastic” on the first try; this may be a personal problem.&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;what-i-love&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;What I love&lt;/h2&gt;
&lt;p&gt;There is a lot to love about this project.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;FOSS&lt;/strong&gt; – Meshtastic is free software—the firmware is
GPL-3.0 licensed—the &lt;a
href=&quot;https://www.gnu.org/philosophy/free-sw.html&quot;&gt;four software
freedoms&lt;/a&gt; are essential for users to trust this device.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Encryption&lt;/strong&gt; – Data moving between T-Beam devices is
encrypted via AES256—an as-yet &lt;a
href=&quot;https://www.youtube.com/watch?v=O4xNJsjtN6E&quot;&gt;unbroken
standard&lt;/a&gt;. Although, the documentation on this worries me a little:
“It is pretty likely that the AES256 security is implemented ‘correctly’
and an observer will not be able to decode your messages.”&lt;a href=&quot;https://tylercipriani.com/tags/computing/#fn1&quot;
class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;
😅&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LoRa&lt;/strong&gt; – The Meshtastic devices work via LoRa
(&lt;b&gt;Lo&lt;/b&gt;ng &lt;b&gt;Ra&lt;/b&gt;nge) radio. In the US, LoRa uses the ISM band (on
915mHz). The ISM band has no license requirement—which means it’s legal
to encrypt traffic, unlike ham radio. In testing, LoRa works up to a few
miles away with a good line of sight.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Community&lt;/strong&gt; – There’s a vibrant community on &lt;a
href=&quot;https://github.com/meshtastic&quot;&gt;GitHub&lt;/a&gt;, &lt;a
href=&quot;https://www.thingiverse.com/thing:4753247&quot;&gt;Thingiverse&lt;/a&gt;, &lt;a
href=&quot;https://meshtastic.discourse.group/&quot;&gt;Discourse&lt;/a&gt;, and &lt;a
href=&quot;https://meshtastic.discourse.group/&quot;&gt;Discord&lt;/a&gt;. There’s
excellent &lt;a href=&quot;https://meshtastic.org/docs/about&quot;&gt;Documentation&lt;/a&gt;
and folks &lt;a
href=&quot;https://hackaday.com/2020/02/26/lora-mesh-network-with-off-the-shelf-hardware/&quot;&gt;blogging&lt;/a&gt;
(and &lt;a
href=&quot;https://www.youtube.com/watch?v=TY6m6fS8bxU&quot;&gt;vlogging&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;the-verdict&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;The verdict&lt;/h2&gt;
&lt;p&gt;I’m thrilled with this project. The talented people bolstering this
community experiment with setting up &lt;a
href=&quot;https://meshtastic.discourse.group/t/do-you-plan-on-going-to-burning-man-2022/4170&quot;&gt;base
stations at Burning Man&lt;/a&gt; and running &lt;a
href=&quot;https://meshtastic.discourse.group/t/guide-ssh-over-meshtastic/2579&quot;&gt;ssh
tunnels via LoRa&lt;/a&gt;—they’re doing awesome things.&lt;/p&gt;
&lt;p&gt;I’ve not yet begun to nerd out on this.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section class=&quot;footnotes footnotes-end-of-document&quot;
role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot; role=&quot;doc-endnote&quot;&gt;&lt;p&gt;&lt;a
href=&quot;https://meshtastic.org/docs/developers/Firmware/encryption&quot;
class=&quot;uri&quot;&gt;https://meshtastic.org/docs/developers/Firmware/encryption&lt;/a&gt;&lt;a
href=&quot;https://tylercipriani.com/tags/computing/#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;

	</content>


	<link rel="comments" href="//tylercipriani.com/blog/2022/07/31/meshtastic-a-review/#comments" type="text/html" />


	<link rel="comments" href="//tylercipriani.com/blog/2022/07/31/meshtastic-a-review/comments.atom" type="application/atom+xml" />

</entry>
<entry>
	<title>Cool desktops don&#x2019;t change&#xA0;&#x1F60E;</title>

	<id>https://tylercipriani.com/blog/2022/06/15/choose-boring-desktop-technology/</id>

	<link href="https://tylercipriani.com/blog/2022/06/15/choose-boring-desktop-technology/"/>

	<author><name>Tyler Cipriani</name></author>


	<rights type="html" xml:lang="en">

		Copyright © 2022 Tyler Cipriani

	</rights>



	<category term="computing" />


	<updated>2022-06-16T18:52:30Z</updated>
	<published>2022-06-15T19:08:21Z</published>


	<content type="html" xml:lang="en">
	&lt;blockquote&gt;
&lt;p&gt;Tools can be a subtle trap.&lt;/p&gt;
&lt;p&gt;– Neil Gaiman, &lt;strong&gt;&lt;a
href=&quot;https://en.wikipedia.org/wiki/The_Sandman_(comic_book)&quot;&gt;The
Sandman&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://photos.tylercipriani.com/thumbs/ff/009e411ecaa6134a44d729bf0129e0/large.jpg&quot;
alt=&quot;My ThinkPad X220 in all its glory&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;My ThinkPad X220 in all its
glory&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Working on my old
&lt;a href=&quot;https://tylercipriani.com/blog/2016/11/13/coreboot-on-the-thinkpad-x220-with-a-raspberry-pi/&quot;&gt;ThinkPad
x220&lt;/a&gt; feels easy because I’ve used the same software for over a
decade.&lt;/p&gt;
&lt;p&gt;And while it’s tempting to switch to one of the endless new apps out
there, &lt;strong&gt;there are good reasons to trust old tools&lt;/strong&gt;.&lt;/p&gt;
&lt;section id=&quot;the-lindy-effect&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;The Lindy Effect&lt;/h2&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://photos.tylercipriani.com/thumbs/ff/19ab08fafac299e6c4ec2507042b7e/medium.jpg&quot;
alt=&quot;My boring desktop&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;My boring desktop&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The &lt;a href=&quot;https://en.wikipedia.org/wiki/Lindy_effect&quot;&gt;Lindy
effect&lt;/a&gt; posits &lt;strong&gt;the older something is, the longer it’ll be
around&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;According to the Lindy Effect, you can assume most software is
halfway through its lifespan.&lt;/p&gt;
&lt;p&gt;So, &lt;strong&gt;Vi will be around in 2068&lt;/strong&gt;, whereas Visual Studio
Code will be defunct before the end of this decade.&lt;a href=&quot;https://tylercipriani.com/tags/computing/#fn1&quot;
class=&quot;footnote-ref&quot; id=&quot;fnref1&quot; role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;table&gt;
    &lt;tbody&gt;
    &lt;tr class=&quot;odd&quot;&gt;
        &lt;td&gt;&lt;a href=&quot;https://www.debian.org/&quot;&gt;Debian&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;1993&lt;/td&gt;
        &lt;td&gt;28 years old&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr class=&quot;even&quot;&gt;
        &lt;td&gt;&lt;a href=&quot;https://www.gnu.org/software/bash/&quot;&gt;Bash&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;1989&lt;/td&gt;
        &lt;td&gt;33 years old&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr class=&quot;odd&quot;&gt;
        &lt;td&gt;&lt;a href=&quot;https://xmonad.org/&quot;&gt;XMonad&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;2007&lt;/td&gt;
        &lt;td&gt;15 years old&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr class=&quot;even&quot;&gt;
        &lt;td&gt;&lt;a href=&quot;http://software.schmorp.de/pkg/rxvt-unicode.html&quot;&gt;URXvt&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;2001&lt;/td&gt;
        &lt;td&gt;20 years old&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr class=&quot;odd&quot;&gt;
        &lt;td&gt;&lt;a href=&quot;https://github.com/tmux/tmux/wiki&quot;&gt;Tmux&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;2007&lt;/td&gt;
        &lt;td&gt;15 years old&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr class=&quot;even&quot;&gt;
        &lt;td&gt;&lt;a href=&quot;https://www.vim.org&quot;&gt;Vim&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;1991&lt;/td&gt;
        &lt;td&gt;30 years old&lt;/td&gt;
    &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The average software running my laptop is 24 years old. So, 24 more
years of this desktop (right!? 😅).&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;preserve-your-flow-state&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;Preserve your flow state&lt;/h2&gt;
&lt;p&gt;My desktop has features that are missing from other people’s
computers.&lt;/p&gt;
&lt;p&gt;These features whisk me into a flow state and keep me there; they
preserve my limited attention, willpower, and (frankly) mental
capacity.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;vim-instead-of-a-new-notetaking-app&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;Vim instead of a new notetaking app&lt;/h2&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://photos.tylercipriani.com/2022-06-11_twitter-netcapgirl-vimmaxing.png&quot;
alt=&quot;Sage advice from @netcapgirl on Twitter, 2022-04-27&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Sage advice from &lt;span class=&quot;citation&quot;
data-cites=&quot;netcapgirl&quot;&gt;@netcapgirl&lt;/span&gt; on Twitter,
2022-04-27&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The problem with most notetaking apps is &lt;strong&gt;editing text outside
Vim breaks my brain&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a
href=&quot;https://vimawesome.com/plugin/vimwiki-the-lucky-one&quot;&gt;Vimwiki&lt;/a&gt;
has piqued my interest, but I have yet to use it.&lt;/p&gt;
&lt;p&gt;Meanwhile, I keep boring notes in Vim using &lt;a
href=&quot;https://gist.github.com/thcipriani/7efb15b2057fe6348b45df26a3e3c479&quot;&gt;a
bash script&lt;/a&gt;, &lt;a href=&quot;https://pandoc.org/&quot;&gt;Pandoc&lt;/a&gt;, &lt;a
href=&quot;https://commonmark.org/&quot;&gt;markdown&lt;/a&gt;, and a &lt;a
href=&quot;https://vimawesome.com/plugin/goyo-vim&quot;&gt;distraction-free&lt;/a&gt;
writing environment.&lt;/p&gt;
&lt;p&gt;In the end, I get a bunch of webpages available on
&lt;code&gt;http://localhost/~thcipriani/brain&lt;/code&gt;:&lt;/p&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://photos.tylercipriani.com/2022-06-15_boring-brain-index-page.png&quot;
alt=&quot;This is basically Roam + Obsidian + Notion…right?&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;This is basically Roam + Obsidian +
Notion…right?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;bash-instead-of-duckduckgo&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;Bash instead of DuckDuckGo&lt;/h2&gt;
&lt;p&gt;Some folks rely on DuckDuckGo (or, worse yet, Google) for basic
utilities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Calculator&lt;/li&gt;
&lt;li&gt;Dictionary&lt;/li&gt;
&lt;li&gt;Spell check&lt;/li&gt;
&lt;li&gt;Unit conversion&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But you can achieve the same thing faster, without breaking your
concentration.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Calculator&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I stole the &lt;a
href=&quot;https://github.com/addyosmani/dotfiles/blob/master/.functions#L1-L17&quot;&gt;&lt;code&gt;calc&lt;/code&gt;
bash function&lt;/a&gt; from Addy Osmani in 2012 and have used it daily
since.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(/^ヮ^)/*:・ﾟ✧ calc 6922251*8
55378008&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dictionary&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I 😍 &lt;a
href=&quot;https://nicolaiarocci.com/youre-probably-using-the-wrong-dictionary/&quot;&gt;dictionaries&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One of the &lt;a href=&quot;https://www.websters1913.com/&quot;&gt;best dictionaries
for writers&lt;/a&gt; is available as the &lt;code&gt;gcide-dict&lt;/code&gt; package in
Debian:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(/^ヮ^)/*:・ﾟ✧ dict fustian
  Fustian \Fus&amp;quot;tian\, n.
     1. A kind of coarse twilled cotton or cotton and linen stuff,
        including corduroy, velveteen, etc.
        [1913 Webster]

     2. An inflated style of writing; a kind of writing in which
        high-sounding words are used, above the dignity of the
        thoughts or subject; bombast.
        [1913 Webster]

              Claudius . . . has run his description into the most
              wretched fustian.                              --Addison.
        [1913 Webster]&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Spell checker&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Spellcheck is available almost everywhere, but when it isn’t, people
tend to search for whatever word they’re spelling. I
&lt;a href=&quot;https://tylercipriani.com/blog/2017/08/14/offline-spelling-with-aspell/&quot;&gt;wrote a
script called &lt;code&gt;spell&lt;/code&gt;&lt;/a&gt; which uses &lt;code&gt;aspell&lt;/code&gt; to
improve my spelling:&lt;/p&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://photos.tylercipriani.com/thumbs/od/46c92a641342553f36e77e406e1613/original.gif&quot;
alt=&quot;spell in action&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;&lt;code&gt;spell&lt;/code&gt; in action&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Temperature conversion&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;units&lt;/code&gt; is a unit conversion and calculation program. And
its &lt;a
href=&quot;https://gist.github.com/thcipriani/0d9d977e3aba2c10be4f5072d7e265a8#file-definitions-units-L32-L68&quot;&gt;database&lt;/a&gt;
is one of my favorite sources of trivia.&lt;/p&gt;
&lt;p&gt;You can make &lt;a
href=&quot;https://gist.github.com/thcipriani/915b47d59308db2bd9ea8a70e6719b1c&quot;&gt;scripts&lt;/a&gt;
for the most common functions. I made one called &lt;code&gt;temp&lt;/code&gt;,
which uses &lt;code&gt;units&lt;/code&gt; to show temp in both °C and °F—handy for
talking about the weather.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(/^ヮ^)/*:・ﾟ✧ temp 100
37.777778°C
212°F&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;scratchpads-instead-of-pinned-tabs&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;Scratchpads instead of pinned tabs&lt;/h2&gt;
&lt;p&gt;Scratchpads are little windows you summon with a keyboard shortcut.
I’ve combined &lt;a
href=&quot;https://hackage.haskell.org/package/xmonad-contrib-0.13/docs/XMonad-Util-NamedScratchpad.html&quot;&gt;XMonad&lt;/a&gt;
and &lt;a href=&quot;https://superuser.com/a/33553&quot;&gt;Chrome&lt;/a&gt; to get little
floating web apps all over my desktop.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;⌘ + Shift + p is an ever-present notetaking terminal window.&lt;/li&gt;
&lt;li&gt;⌘ + Shift + s is Google calendar.&lt;/li&gt;
&lt;li&gt;⌘ + Shift + o used to bring up an org-mode capture template, but now
it brings up todoist (yes, I’m suitably ashamed).&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
    &lt;video autoplay loop muted&gt;
        &lt;source src=&quot;https://photos.tylercipriani.com/2022-06-15_namedscratchpads.mp4&quot; type=&quot;video/mp4&quot;&gt;
    &lt;/video&gt;
    &lt;figcaption&gt;XMonad NamedScratchpads 👏&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;the-year-decade-of-linux-on-the-desktop&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;The &lt;strike&gt;year&lt;/strike&gt; decade of Linux on the desktop&lt;/h2&gt;
&lt;p&gt;There’s a bitter joke that goes like this: &lt;strong&gt;“It’s the year of
Linux on the desktop.”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;People say it in video calls when they can’t get their audio to work.
But, honestly, I’ve had a pleasant &lt;strong&gt;decade&lt;/strong&gt; of Linux on
the desktop.&lt;/p&gt;
&lt;p&gt;And when &lt;a href=&quot;https://wayland.freedesktop.org/&quot;&gt;Wayland&lt;/a&gt;
finally happens? Well. I guess I’ll have no choice but to stop using
computers forever &lt;code&gt;¯\_(ツ)_/¯&lt;/code&gt;&lt;a href=&quot;https://tylercipriani.com/tags/computing/#fn2&quot;
class=&quot;footnote-ref&quot; id=&quot;fnref2&quot;
role=&quot;doc-noteref&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Anyway. Here’s to the next decade and beyond.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;small&gt;Thanks to &lt;a href=&quot;https://p1k3.com&quot;&gt;Brennen&lt;/a&gt;, &lt;a
href=&quot;https://www.kostaharlan.net/&quot;&gt;Kostah&lt;/a&gt;, and &lt;a
href=&quot;https://filipin.eu/&quot;&gt;Željko&lt;/a&gt; for reading an early draft of this
post and making it less terrible. &amp;lt;3&lt;/small&gt;&lt;/p&gt;
&lt;/section&gt;
&lt;section class=&quot;footnotes footnotes-end-of-document&quot;
role=&quot;doc-endnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn1&quot; role=&quot;doc-endnote&quot;&gt;&lt;p&gt;There is precedent here: &lt;a
href=&quot;https://github.blog/2022-06-08-sunsetting-atom/&quot;
class=&quot;uri&quot;&gt;https://github.blog/2022-06-08-sunsetting-atom/&lt;/a&gt;&lt;a
href=&quot;https://tylercipriani.com/tags/computing/#fnref1&quot; class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&quot;fn2&quot; role=&quot;doc-endnote&quot;&gt;&lt;p&gt;or, I suppose, I could finally figure
out how to use &lt;a href=&quot;https://swaywm.org/&quot;&gt;SwayWM&lt;/a&gt;&lt;a href=&quot;https://tylercipriani.com/tags/computing/#fnref2&quot;
class=&quot;footnote-back&quot; role=&quot;doc-backlink&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;

	</content>


	<link rel="comments" href="//tylercipriani.com/blog/2022/06/15/choose-boring-desktop-technology/#comments" type="text/html" />


	<link rel="comments" href="//tylercipriani.com/blog/2022/06/15/choose-boring-desktop-technology/comments.atom" type="application/atom+xml" />

</entry>
<entry>
	<title>Explaining git diff to myself</title>

	<id>https://tylercipriani.com/blog/2022/05/14/git-diffs-deep-deception/</id>

	<link href="https://tylercipriani.com/blog/2022/05/14/git-diffs-deep-deception/"/>

	<author><name>Tyler Cipriani</name></author>


	<rights type="html" xml:lang="en">

		Copyright © 2022 Tyler Cipriani

	</rights>



	<category term="computing" />


	<updated>2022-05-16T17:56:21Z</updated>
	<published>2022-05-14T00:26:49Z</published>


	<content type="html" xml:lang="en">
	&lt;blockquote&gt;
&lt;p&gt;But try to understand&lt;br&gt; Try to understand&lt;br&gt; Try try try to
understand&lt;br&gt; Git’s a magic command.&lt;/p&gt;
&lt;p&gt;– &lt;a
href=&quot;https://www.youtube.com/watch?v=Ps7tVvQHLyo&quot;&gt;Heart  💕&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Once upon a time, I believed git was storing diffs somewhere. But
then I learned I was wrong.&lt;/p&gt;
&lt;p&gt;It’s challenging to wield git’s clunky interface when you have a
broken mental model of its internals. Learning more about what’s
happening inside git transformed me into a more effective git user.&lt;/p&gt;
&lt;p&gt;In this post, I’ll attempt to explain all the deep details of
&lt;code&gt;git diff&lt;/code&gt; to my past self.&lt;/p&gt;
&lt;section id=&quot;git-add-makes-blobs&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;📍 Git add makes blobs&lt;/h2&gt;
&lt;p&gt;We can add files to repos using &lt;code&gt;git add&lt;/code&gt;. But behind the
&lt;a
href=&quot;https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain&quot;&gt;porcelain&lt;/a&gt;,
git’s busy compressing and storing this file deep in its bowels. Git
terms the results of this process a “blob.”&lt;/p&gt;
&lt;p&gt;Git stores blobs (among other things) inside the
&lt;code&gt;.git/objects&lt;/code&gt; directory.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git init
Initialized empty Git repository in /tmp/bar/.git/
$ echo &amp;quot;Hi, I&amp;#39;m blob&amp;quot; &amp;gt; foo
$ git add foo
$ tree .git/objects/
.git/objects/
└── 26
  └── 45aab142ef6b135a700d037e75cd9f1f1c94dc&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But what’s in a blob? And why is this blob stored as
&lt;code&gt;./26/45aab142ef6b135a700d037e75cd9f1f1c94dc&lt;/code&gt;?&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;git-stores-things-by-their-hash&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;🗃️ Git stores things by their hash&lt;/h2&gt;
&lt;p&gt;Why did &lt;code&gt;git add foo&lt;/code&gt; store the contents of
&lt;code&gt;foo&lt;/code&gt; as
&lt;code&gt;2645aab142ef6b135a700d037e75cd9f1f1c94dc&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;Git mapped our file to a number via a hash function.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A hash function maps data to a unique number&lt;/strong&gt; (&lt;a
href=&quot;https://shattered.io&quot;&gt;mostly&lt;/a&gt;)—whenever the data changes, the
hash function’s output changes dramatically.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/SHA-1&quot;&gt;SHA1&lt;/a&gt; is the hash
function git uses by default. And when we &lt;code&gt;git add foo&lt;/code&gt; git
applies SHA1 to the contents of
&lt;code&gt;foo&lt;/code&gt;—&lt;code&gt;Hi, I&#39;m blob\n&lt;/code&gt;—and that spits out
&lt;code&gt;2645aab142ef6b135a700d037e75cd9f1f1c94dc&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Blobs are all about content. The filename “foo” doesn’t matter at
all! We could have named the file “🌈”—git still would have stored it in
the same place. If the file contents are EXACTLY the same, then the hash
will be exactly the same.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;git-commit-creates-commits-and-trees&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;🌱 Git commit creates commits and trees&lt;/h2&gt;
&lt;p&gt;You already know &lt;code&gt;git commit&lt;/code&gt; creates a commit, but what
is a commit?&lt;/p&gt;
&lt;p&gt;A commit is a type of object. Git uses the word “object” to mean: a
commit, a folder or directory (tree), a file (blob), or a tag. Git
stores objects in its object database—everything inside the
&lt;code&gt;.git/objects&lt;/code&gt; directory.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git commit -m &amp;#39;Initial Commit&amp;#39;
[main (root-commit) 0644991] Initial Commit
1 file changed, 1 insertion(+)
create mode 100644 foo
$ tree .git/objects/
.git/objects/
├── 06
│   └── 449913ac0e43b73bfbd3141f5643a4db6d47f8
├── 26
│   └── 45aab142ef6b135a700d037e75cd9f1f1c94dc
└── 41
  └── 81320a57137264d436b2ef861c31f430256bf4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After our commit, the object database has three objects:
&lt;code&gt;06449913&lt;/code&gt;, &lt;code&gt;2645aab1&lt;/code&gt;, and
&lt;code&gt;4181320a&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So now we’ve established that one of these three objects is our blob
(&lt;code&gt;2645aab1&lt;/code&gt;)—let’s see if we can suss out the others.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;the-magic-command&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;✨ The magic command&lt;/h2&gt;
&lt;p&gt;The magic command to learn about any object is
&lt;code&gt;git cat-file -p&lt;/code&gt;. We can use that command to find out more
about our mystery objects:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git cat-file -p 06449913ac0e43b73bfbd3141f5643a4db6d47f8
tree 4181320a57137264d436b2ef861c31f430256bf4
author Tyler Cipriani &amp;lt;tcipriani@wikimedia.org&amp;gt; 1652310544 -0600
committer Tyler Cipriani &amp;lt;tcipriani@wikimedia.org&amp;gt; 1652310544 -0600

Initial Commit&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This object (&lt;code&gt;06449913&lt;/code&gt;) appears to be our commit. A
commit is metadata compressed and stored inside git’s object
database.&lt;/p&gt;
&lt;p&gt;Some of the metadata is obvious, but then there’s a tree. And that
tree points to our other mystery object, &lt;code&gt;418132&lt;/code&gt;. Let’s see
what we can learn about our last remaining mystery object using our
magic command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git cat-file -p 4181320a57137264d436b2ef861c31f430256bf4
100644 blob 2645aab142ef6b135a700d037e75cd9f1f1c94dc    foo&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So a &lt;strong&gt;tree is an object that stores a directory listing of
objects by their SHA1s&lt;/strong&gt;. And a &lt;strong&gt;commit is an object that
points at a tree&lt;/strong&gt; by recording the tree’s SHA1!&lt;/p&gt;
&lt;p&gt;Commits point to trees, and trees point to blobs and other trees.
Neat!&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;gits-dependency-graph&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;📈 Git’s dependency graph&lt;/h2&gt;
&lt;p&gt;So if we graphed the state of dependencies in our object database,
we’d get something like this:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;http://photos.tylercipriani.com/2022-05-15_git-merkle-1.png&quot;
alt=&quot;Simple git repo’s object dependency graph&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Simple git repo’s object dependency
graph&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The commit incorporates our tree, which includes our blob—everything
depends on our blob!&lt;/p&gt;
&lt;p&gt;So if we change even a single bit inside a single file: git will
notice—everything is entirely traceable from the commit down to the bit
level. We get this for free by hashing objects and including those
hashes in other objects.&lt;/p&gt;
&lt;p&gt;This is the whole concept of a &lt;a
href=&quot;https://en.wikipedia.org/wiki/Merkle_tree&quot;&gt;Merkle Directed Acyclic
Graph&lt;/a&gt; (Merkle DAG)!&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;so-wheres-the-diff&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;🍔 So, where’s the diff?&lt;/h2&gt;
&lt;p&gt;When we type &lt;code&gt;git diff&lt;/code&gt;, git presents us a diff. We know
there are blobs and trees and commits—so where’s the diff!?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Git doesn’t store diffs anywhere at all!&lt;/strong&gt; It derives
diffs from what’s stored in the object database.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ echo &amp;quot;I&amp;#39;m ALSO blob&amp;quot; &amp;gt; baz
$ git add baz
$ git commit -m &amp;#39;Add baz&amp;#39;
$ tree .git/objects/
.git/objects/
├── 06
│   └── 449913ac0e43b73bfbd3141f5643a4db6d47f8
├── 26
│   └── 45aab142ef6b135a700d037e75cd9f1f1c94dc
├── 41
│   └── 81320a57137264d436b2ef861c31f430256bf4
├── 95
│   └── 42599fac463c434456c0a16b13e346787f25da
├── 9b
│   └── 2716e4540c11e8d590e906dd8fa5a75904810a
└── e6
   └── 5a7344c46cebe61d052de6e30d33636e1cd0b4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We made a new commit, and now we have three new objects. We added a
new file (blob), which made our directory different (tree), and we
committed it (commit).&lt;/p&gt;
&lt;p&gt;Our graph now looks like this:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;http://photos.tylercipriani.com/2022-05-15_git-merkle-2.png&quot;
alt=&quot;Simple git repo’s updated object dependency graph&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Simple git repo’s updated object
dependency graph&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;You might be surprised by a few things in the graph:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Our new commit stores its parent commit as metadata&lt;/li&gt;
&lt;li&gt;Our new tree points to our old blob, and our NEW blob&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So now what happens when we try git diff:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git diff 064499..e65a73
diff --git a/baz b/baz
new file mode 100644
index 0000000..9b2716e
--- /dev/null
+++ b/baz
@@ -0,0 +1 @@
+I&amp;#39;m ALSO blob&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Git compares the two commits, finds their trees, sees a new blob in
the second commit, and shows you the diff of &lt;code&gt;/dev/null&lt;/code&gt; and
&lt;code&gt;baz&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;No diffs. Just Merkle DAGs. And now you know.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;small&gt;Thanks to &lt;a href=&quot;https://github.com/joescottswanson&quot;&gt;Joe
Swanson&lt;/a&gt; for providing excellent early feedback on this post. And
thanks to &lt;a href=&quot;https://www.kostaharlan.net/&quot;&gt;Kostah Harlan&lt;/a&gt; for
reading an early draft of this post and making it less terrible.
&amp;lt;3&lt;/small&gt;&lt;/p&gt;
&lt;/section&gt;

	</content>


	<link rel="comments" href="//tylercipriani.com/blog/2022/05/14/git-diffs-deep-deception/#comments" type="text/html" />


	<link rel="comments" href="//tylercipriani.com/blog/2022/05/14/git-diffs-deep-deception/comments.atom" type="application/atom+xml" />

</entry>
<entry>
	<title>The Unreasonable Fight for Municipal Broadband</title>

	<id>https://tylercipriani.com/blog/2022/04/20/the-unreasonable-fight-for-municipal-broadband/</id>

	<link href="https://tylercipriani.com/blog/2022/04/20/the-unreasonable-fight-for-municipal-broadband/"/>

	<author><name>Tyler Cipriani</name></author>


	<rights type="html" xml:lang="en">

		Copyright © 2022 Tyler Cipriani

	</rights>



	<category term="computing" />


	<updated>2022-04-20T17:31:39Z</updated>
	<published>2022-04-20T14:17:08Z</published>


	<content type="html" xml:lang="en">
	&lt;p&gt;I love Longmont’s municipal broadband, but we had to fight Comcast
every step of the way to get it.&lt;/p&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://photos.tylercipriani.com/thumbs/8e/9534dace7708c006b964a93fa95abb/large.jpg&quot;
alt=&quot;NextLight—Longmont’s Broadband&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;NextLight—Longmont’s
Broadband&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;As a gracious person, I’ll dutifully pretend that the problem
&lt;em&gt;might be&lt;/em&gt; on my side of the Zoom call. But the problem is never
me—my internet is just too good.&lt;/p&gt;
&lt;p&gt;Since 2016, I’ve been using Longmont’s municipal
broadband—NextLight—and it’s been objectively awesome.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It’s fast—1Gbps symmetric&lt;/li&gt;
&lt;li&gt;It’s cheap(ish)—$49.95 per month&lt;/li&gt;
&lt;li&gt;It’s rock-solid—I’ve never had an outage&lt;/li&gt;
&lt;li&gt;I’ve never hit a data cap&lt;/li&gt;
&lt;li&gt;PC Magazine ranks NextLight among the &lt;a
href=&quot;https://www.pcmag.com/news/the-fastest-isps-of-2021&quot;&gt;top five ISPs
in the United States&lt;/a&gt; every year—often besting Google Fiber&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And, even better, the city insists I’ll pay $49.95 forever.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;But Longmont spent more than a decade fighting Comcast to
provide this excellent internet&lt;/strong&gt;. And any city working on its
municipal broadband offering should prepare to do the same.&lt;/p&gt;
&lt;section id=&quot;canceling-comcast&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;🎉 Canceling Comcast&lt;/h2&gt;
&lt;p&gt;In 2016, I was paying Comcast $150 a month for their top-tier (at the
time) 100Mbps speeds. I could usually eke out a little more than 30Mbps
on a good day.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I lept at the chance for gigabit internet.&lt;/strong&gt; I signed
up for NextLight as a charter member—locking in $49.95/mo for life (the
current price is only $69.95 last I checked). And I took the opportunity
to upgrade my $20 router from 2008 at the same time.&lt;/p&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://photos.tylercipriani.com/thumbs/1c/86afb64500c8b266736799ff98a147/large.jpg&quot;
alt=&quot;My new fancy router—Ubiquiti EdgeRouter Lite + EdgeSwitch 16-POE&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;My new fancy router—Ubiquiti EdgeRouter
Lite + EdgeSwitch 16-POE&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;And when I returned my cable box to Comcast to cancel my service, the
representative felt compelled to counsel me: “NextLight, huh? you know,”
he said, leaning in, “if you miss even a single payment, they’ll raise
your price?”&lt;/p&gt;
&lt;p&gt;“I’ll take my chances.”&lt;/p&gt;
&lt;p&gt;I’ve been automatically billed $49.95 every month since, and this is
what my speed looks like this morning:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&quot;https://photos.tylercipriani.com/2022-04-19_fast.com.png&quot;
alt=&quot;930Mbps is not quite 1Gbps, but I’ll take it&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;930Mbps is not quite 1Gbps, but I’ll take
it&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;why-cant-we-have-nice-things&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;🥺 Why can’t we have nice things?&lt;/h2&gt;
&lt;p&gt;Big cable companies suck. &lt;strong&gt;Big cable companies burned hundreds
of thousands of dollars to stop Longmont’s municipal
broadband.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In 2005, Comcast and CenturyLink rammed through the egregious &lt;a
href=&quot;http://cityofalamosa.org/wp-content/uploads/2016/12/152_enr.pdf&quot;&gt;Colorado
SB-05-152&lt;/a&gt;, prohibiting municipalities in the state of Colorado from
offering telecommunication services.&lt;/p&gt;
&lt;p&gt;Longmont had to hold two referendums on the measure—one in 2009,
which failed, and another in 2011, which passed:&lt;/p&gt;
&lt;p&gt;In 2009, “&lt;a
href=&quot;https://www.boulderweekly.com/news/montanabased-org-pours-cash-into-conservative-coffers-in-longmont-city-council-race/&quot;&gt;No
Blank Check Longmont&lt;/a&gt;” (Comcast/CenturyLink) &lt;strong&gt;spent
$250,000&lt;/strong&gt; to dash our dreams of municipal broadband. They framed
it as a choice between fast internet vs. police and firefighters.&lt;/p&gt;
&lt;p&gt;In 2011, “&lt;a
href=&quot;https://www.boulderweekly.com/news/terrifying-telecom-tale/&quot;&gt;Look
Before You Leap Longmont&lt;/a&gt;” (Comcast/CenturyLink) &lt;strong&gt;spent
$300,000&lt;/strong&gt; urging us to rethink our municipal broadband plans.
They stood in lone opposition to our unanimous city council and our
local paper.&lt;/p&gt;
&lt;p&gt;Comcast spent $500,000 in a tiny city of less than 100,000 people.
You can be sure, Comcast will do all this again in a heartbeat.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;lessons&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;📓 Lessons&lt;/h2&gt;
&lt;p&gt;Rather than use their vast resources to improve their service,
&lt;strong&gt;Comcast will spend big to ensure they never have to
compete&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Let Longmont be a lesson. In 2011, &lt;strong&gt;Longmont won because it
formed an honest citizens’ advisory group&lt;/strong&gt;: &lt;a
href=&quot;https://web.archive.org/web/20111008235441/http://www.longmontsfuture.com/&quot;&gt;Longmont’s
Future&lt;/a&gt;. Longmont’s Future got the word out about the vote on
Facebook, its website, and the local press.&lt;/p&gt;
&lt;p&gt;And ever since, Longmonsters (that’s right—Longmont’s demonym is
“Longmonster”) have &lt;a
href=&quot;https://muninetworks.org/content/more-half-longmonters-choose-nextlight-fiber-because-nextlight-fiber&quot;&gt;chosen
NextLight over competing services&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Real competition won. Fuck Comcast. Long live municipal
broadband.&lt;/p&gt;
&lt;/section&gt;

	</content>


	<link rel="comments" href="//tylercipriani.com/blog/2022/04/20/the-unreasonable-fight-for-municipal-broadband/#comments" type="text/html" />


	<link rel="comments" href="//tylercipriani.com/blog/2022/04/20/the-unreasonable-fight-for-municipal-broadband/comments.atom" type="application/atom+xml" />

</entry>
<entry>
	<title>My Home Assistant Music Cube</title>

	<id>https://tylercipriani.com/blog/2022/03/27/my-home-assistant-music-cube/</id>

	<link href="https://tylercipriani.com/blog/2022/03/27/my-home-assistant-music-cube/"/>

	<author><name>Tyler Cipriani</name></author>


	<rights type="html" xml:lang="en">

		Copyright © 2022 Tyler Cipriani

	</rights>



	<category term="computing" />


	<updated>2022-03-28T00:02:13Z</updated>
	<published>2022-03-27T19:19:04Z</published>


	<content type="html" xml:lang="en">
	&lt;p&gt;Last year, I spent $17 on an &lt;a
href=&quot;https://www.aqara.com/us/cube.html&quot;&gt;Aqara cube&lt;/a&gt;, and it’s been
one of my best purchases for enjoyment per dollar spent.&lt;/p&gt;
&lt;figure&gt;
    &lt;video autoplay loop muted&gt;
        &lt;source src=&quot;https://photos.tylercipriani.com/2022-03-27_squeezebox-cube.mp4&quot; type=&quot;video/mp4&quot;&gt;
    &lt;/video&gt;
    &lt;figcaption&gt;I control my multi-room audio using a gyroscopic gesture-recognition cube -- yes, this basically makes me Iron Man.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The Aqara cube is a three-inch square plastic cube that sends
gestures over Zigbee to a &lt;a
href=&quot;https://www.amazon.com/dresden-elektronik-ConBee-Universal-Gateway/dp/B07PZ7ZHG5/ref=sr_1_4?keywords=zigbee+dongle&amp;amp;qid=1648415026&amp;amp;sr=8-4&quot;&gt;cheap
off-the-shelf dongle&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;By pairing this cube with &lt;a
href=&quot;https://www.home-assistant.io/&quot;&gt;Home Assistant&lt;/a&gt;, I have a
three-dimensional button with 45 unique interactions to control whatever
I want.&lt;/p&gt;
&lt;p&gt;And over the last six months, I’ve used it to control a small fleet
of antiquated streaming devices to help me discover new music.&lt;/p&gt;
&lt;section id=&quot;the-tragedy-of-the-logitech-squeezebox&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;🎭 The Tragedy of the Logitech Squeezebox&lt;/h2&gt;
&lt;p&gt;The Logitech Squeezebox is a bygone streaming device that was too
beautiful for this world. Logitech snuffed the Squeezebox in 2012.&lt;/p&gt;
&lt;p&gt;But because others share my enthusiasm for Squeezeboxes, there’s
still hope. The second-hand market persists. And there are wonderful
nerds &lt;a href=&quot;https://www.picoreplayer.org/&quot;&gt;cobbling together
Squeezeboxes from Raspberry Pis&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://photos.tylercipriani.com/2022-03-27_dozens-of-us-arrested-development.gif&quot;
alt=&quot;Logitech Squeezebox fans&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Logitech Squeezebox fans&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I built a DIY Squeezebox from a Pi Zero &lt;a
href=&quot;https://shop.pimoroni.com/products/pirate-radio-pi-zero-w-project-kit?variant=38476372426&quot;&gt;Pimoroni
PirateRadio&lt;/a&gt; kit and &lt;a
href=&quot;https://github.com/ralph-irving/squeezelite&quot;&gt;Squeezelite&lt;/a&gt;
software.&lt;/p&gt;
&lt;p&gt;I blanket my humble abode in music by combining a DIY PirateRadio, a
Squeezebox Boom, and a Squeezebox Touch.&lt;/p&gt;
&lt;p&gt;My Dockerized Logitech Media Server perfectly synchronizes these
three devices. Music from Spotify or &lt;a
href=&quot;https://www.wqxr.org/&quot;&gt;WQXR&lt;/a&gt; is seamless when you walk from
bedroom to kitchen to dining room.&lt;/p&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://photos.tylercipriani.com/thumbs/4a/d8cc93b5fd5ac94334d78034bb0ffe/large.jpg&quot;
alt=&quot;🏴‍☠️ Pimoroni PirateRadio&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;🏴‍☠️ Pimoroni PirateRadio&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;home-assistant-is-magic&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;Home Assistant is ✨magic✨&lt;/h2&gt;
&lt;p&gt;Home Assistant is open-source home automation software, and it’s the
only IoT software I don’t find myself screaming at regularly.&lt;/p&gt;
&lt;p&gt;And, of course, there’s a &lt;a
href=&quot;https://www.home-assistant.io/integrations/squeezebox&quot;&gt;Logitech
Squeezebox integration for Home Assistant&lt;/a&gt;. The integration lets you
use Logitech Media Server’s (somewhat &lt;a
href=&quot;https://gist.github.com/samtherussell/335bf9ba75363bd167d2470b8689d9f2&quot;&gt;esoteric&lt;/a&gt;)
API to control your devices from Home Assistant.&lt;/p&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://photos.tylercipriani.com/2022-03-27_squeezebox-homeassistant-honky-tonkin.png&quot;
alt=&quot;Home Assistant Squeezebox Lovelace Card&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Home Assistant Squeezebox Lovelace
Card&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I also use a community-made &lt;a
href=&quot;https://community.home-assistant.io/t/mi-magic-cube-deconz-45-actions/256656&quot;&gt;Home
Assistant Blueprint&lt;/a&gt; that automates each of the cube’s 45 unique
gestures.&lt;/p&gt;
&lt;figure&gt;
&lt;img
src=&quot;https://photos.tylercipriani.com/2022-03-27_homeassistant-magic-cube.png&quot;
alt=&quot;Mi Magic Cube in Home Assistant&quot; /&gt;
&lt;figcaption aria-hidden=&quot;true&quot;&gt;Mi Magic Cube in Home
Assistant&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Currently, since my mental stack is tiny, I only use four
gestures:&lt;/p&gt;
&lt;ol type=&quot;1&quot;&gt;
&lt;li&gt;&lt;strong&gt;Shake&lt;/strong&gt;: Turn on all players, and start playing a
random album from Spotify (that’s right, &lt;strong&gt;album&lt;/strong&gt; – I’m
old enough to yearn for the halcyon days of &lt;a
href=&quot;https://github.com/thcipriani/rdio-shit#rdio-shit&quot;&gt;Rdio&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Double-tap&lt;/strong&gt;: Turn off all players.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flip&lt;/strong&gt;: Next track.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Twist&lt;/strong&gt;: Twist right for volume up; twist left for
volume down – like a volume knob.&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
&lt;section id=&quot;why-would-anyone-do-this&quot; class=&quot;level2&quot;&gt;
&lt;h2&gt;🧐 Why would anyone do this?&lt;/h2&gt;
&lt;p&gt;In a 2011 article, “&lt;a
href=&quot;http://worrydream.com/ABriefRantOnTheFutureOfInteractionDesign/&quot;&gt;A
Brief Rant on the Future of Interaction Design&lt;/a&gt;,” Brett Victor
describes &lt;strong&gt;touchscreens&lt;/strong&gt; as “pictures under glass.”
&lt;strong&gt;I loathe pictures under glass&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;It’s impossible to use a device with a touchscreen without looking at
it. And touchscreen interaction is slow – traversing a menu system is
all point-and-click, there are no shortcuts.&lt;/p&gt;
&lt;p&gt;Another alternative is control via &lt;strong&gt;smart speakers&lt;/strong&gt; –
devices literally straight out of a dystopian novel.&lt;/p&gt;
&lt;p&gt;While the smart speaker is the closest thing to a ubiquitous
command-line interface in everyday use, &lt;strong&gt;I’m too weirded-out to
have a smart speaker in my house&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I’ve opted for a better way: shake a cube and music appears.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The cube is a pleasant tactile experience&lt;/strong&gt; – shake
it, tap it, spin it – its a weighty and fun fidget toy. &lt;strong&gt;Its
design affords instant access to all its features&lt;/strong&gt; – there is no
menu system to dig through.&lt;/p&gt;
&lt;p&gt;The cube is frictionless &lt;a href=&quot;https://calmtech.com/&quot;&gt;calm
technology&lt;/a&gt; and it’s behaved beautifully in the background of my
day-to-day for months.&lt;/p&gt;
&lt;/section&gt;

	</content>


	<link rel="comments" href="//tylercipriani.com/blog/2022/03/27/my-home-assistant-music-cube/#comments" type="text/html" />


	<link rel="comments" href="//tylercipriani.com/blog/2022/03/27/my-home-assistant-music-cube/comments.atom" type="application/atom+xml" />

</entry>

</feed>
