<?xml version='1.0' encoding='UTF-8'?>
<rss version='2.0'>
<channel>
<generator>
clj-rss
</generator>
<title>
Twice the Mega Power
</title>
<link>
http://blog.eikeland.se
</link>
<description>
Personal blog of Stian Eikeland
</description>
<lastBuildDate>
Thu, 30 Sep 2021 14:57:34 +0200
</lastBuildDate>
<item>
<title>
That garage opener again..
</title>
<description>
&lt;p&gt;Remember the &lt;a href=&quot;/2017/03/27/garage-opener/&quot;&gt;garage opener&lt;/a&gt; I made a couple of years ago?&lt;/p&gt;
</description>
<link>
http://blog.eikeland.se/2019/10/26/garage-opener-revisisted/
</link>
<pubDate>
Sat, 26 Oct 2019 14:00:00 +0200
</pubDate>
<guid isPermaLink='false'>
/2019/10/26/garage-opener-revisisted/
</guid>
</item>
<item>
<title>
Coding a rolling Oloid
</title>
<description>
&lt;p&gt;Did you know there's a whole class rolling objects that's not spherical or cylindrical and still able to roll in a given direction? I didn't!&lt;/p&gt;&lt;p&gt;Some of them have them even have interesting properties like the fact that every point on their surface touch the ground as they're rolling. The &lt;a href=&quot;https://en.wikipedia.org/wiki/Sphericon&quot;&gt;Sphericon&lt;/a&gt; and the &lt;a href=&quot;https://en.wikipedia.org/wiki/Oloid&quot;&gt;Oloid&lt;/a&gt; are two such objects.&lt;/p&gt;&lt;p&gt;As a fun little experiment I wanted to code and print one.&lt;/p&gt;&lt;p&gt;&lt;figure&gt; &lt;iframe allowfullscreen=&quot;allowfullscreen&quot; frameborder=&quot;0&quot; src=&quot;https://www.youtube.com/embed/wXE3L8EU5U4?VQ=HD720&quot; height=&quot;315&quot; width=&quot;560&quot;&gt;&lt;/iframe&gt; &lt;figcaption&gt;TL;DR, just watch the video - coding a rolling Oloid. Fullscreen it for readability.&lt;/figcaption&gt; &lt;/figure&gt;&lt;/p&gt;&lt;p&gt;The code to construct an oloid is really super simple, you can construct one by creating a convex hull around two perpendicular circles positioned with the centers at radius distance from each other, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;olid&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;radius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;m/cylinder&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;radius&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;m/translate&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;/ &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;radius&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;-2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;c&lt;/span&gt;
               &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;m/rotate&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;/ &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Math/PI&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
               &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;m/translate&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;/ &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;radius&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;))]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;m/hull&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;script src=&quot;https://gist.github.com/stianeikeland/cf9e1e2d63a0a9e774d520a7c3dc497d.js&quot;&gt;&lt;/script&gt;&lt;p&gt;Print it! &lt;/p&gt;
&lt;div style=&quot;position:relative; padding-bottom:calc(56.25% + 44px)&quot;&gt;&lt;iframe allowfullscreen=&quot;allowfullscreen&quot; style=&quot;position:absolute;top:0;left:0;&quot; height=&quot;100%&quot; width=&quot;100%&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; src=&quot;https://gfycat.com/ifr/UnsightlyUncommonBat?hd=1&amp;amp;controls=0&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;And let it roll!&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div style=&quot;position:relative; padding-bottom:calc(56.25% + 44px)&quot;&gt;&lt;iframe allowfullscreen=&quot;allowfullscreen&quot; style=&quot;position:absolute;top:0;left:0;&quot; height=&quot;100%&quot; width=&quot;100%&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; src=&quot;https://gfycat.com/ifr/UnfortunateAbandonedEarthworm?hd=1&amp;amp;controls=0&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p&gt; &lt;a href=&quot;https://gfycat.com/unfortunateabandonedearthworm&quot;&gt;via Gfycat&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;If i were to print it again, I would probably use a higher in-fill percentage to make it a bit heavier. You can also buy these made in &lt;a href=&quot;https://www.mattercollection.com/the-oloid-1&quot;&gt;metal&lt;/a&gt;, which probably feels amazing!&lt;/p&gt;&lt;h4&gt;Using scad-clj&lt;/h4&gt;&lt;p&gt;Some people have asked how I use Clojure and OpenSCAD, how to set up the live reloading, etc, as the documentation is a bit lacking.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;spit&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;render.scad&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scad-clj.scad/write-scad&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I have this simple helper defined that writes a model to a file. Open the file using OpenSCAD. OpenSCAD will watch the file, and every time you call render on something, it will update the display. You can hide all UI elements other than the display in OpenSCAD, put it side by side with the editor, and even set them up to use the same theme - creating the illusion that your editor and OpenSCAD is the same program.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;m/union&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;m/cylinder&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                 &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;m/cube&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I usually leave a call to render at the bottom of the file I'm working on, and evaluate it as needed. That way a quick call to &lt;code&gt;cider-eval-buffer&lt;/code&gt; will update the display.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://adereth.github.io/blog/2014/04/09/3d-printing-with-clojure/&quot;&gt;Adereth&lt;/a&gt; got some great tips on how to get started over at his blog. Be sure to check out his amazing keyboard!&lt;/p&gt;&lt;h4&gt;The y-split function&lt;/h4&gt;&lt;p&gt;I got asked about the y-split function used in the video. It's a simple axis split with a hollowed out cube to make it easier to print, no supports required. I didn't want to make the video more complex than necessary, so I simply used it like magic.&lt;/p&gt;&lt;p&gt;It was custom made for this oloid and looked like this. Quick and dirty, and a bit repetitious.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;y-split&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;box&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;m/cube&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;holed-obj&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;m/difference&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;obj&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;m/scale&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.005&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.2&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.005&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;box&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;m/cube&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
               &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;m/translate&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;-50&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
               &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;m/intersection&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;holed-obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
               &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;m/rotate&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;/ &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Math/PI&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;-2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
               &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;m/translate&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;35&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;m/cube&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
               &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;m/translate&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
               &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;m/intersection&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;holed-obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
               &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;m/rotate&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;/ &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Math/PI&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
               &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;m/translate&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;-35&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;m/union&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;m/translate&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;-20&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;box&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt; 
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I just guessed at the tolerances needed, and it worked perfectly, no glue needed. It seems like a useful function for 3D-printing with Clojure, so I think I'll make a general one later.&lt;/p&gt;
</description>
<link>
http://blog.eikeland.se/2019/04/13/oloid/
</link>
<pubDate>
Sat, 13 Apr 2019 14:00:00 +0200
</pubDate>
<guid isPermaLink='false'>
/2019/04/13/oloid/
</guid>
</item>
<item>
<title>
Bluetooth LE garage opener
</title>
<description>
&lt;p&gt;The yak I'm trying to shave here is the garage opener (keychain-)remote. You know those big clunky remotes people carry around on their keychains? I try to maintain a minimum (viable?) keychain and I absolutely hate keychain remotes and big keys with a passion.&lt;/p&gt;&lt;p&gt;Remotes are fine in the car, but I don't want to carry one. The garage in question here only have access through the main port - no door. And since I live on a hill, with a garage down by the road, connected by long flight of stairs, it's annoying to have to go all the way to fetch the remote when you just want to grab something real quick from the garage..&lt;/p&gt;&lt;p&gt;&lt;figure&gt; &lt;iframe allowfullscreen=&quot;allowfullscreen&quot; frameborder=&quot;0&quot; src=&quot;https://www.youtube.com/embed/1c1G_Ok_XsM?VQ=HD720&quot; height=&quot;315&quot; width=&quot;560&quot;&gt;&lt;/iframe&gt; &lt;figcaption&gt;My Bluetooth LE garage opener.&lt;/figcaption&gt; &lt;/figure&gt;&lt;/p&gt;&lt;p&gt;I usually carry my iPhone, so my thinking was that it could work as a decent remote.&lt;/p&gt;&lt;h1&gt;Requirements:&lt;/h1&gt;
&lt;ul&gt;
  &lt;li&gt;Connect to iPhone wirelessly somehow..&lt;/li&gt;
  &lt;li&gt;No wifi from house available (garage is in a wifi-shadow)&lt;/li&gt;
  &lt;li&gt;Connect to existing garage door opener expansion port.&lt;/li&gt;
  &lt;li&gt;Powered directly from garage door opener bus (24v max 50ma)&lt;/li&gt;
&lt;/ul&gt;&lt;h1&gt;Connectivity&lt;/h1&gt;&lt;p&gt;Wifi is out of the question since it's hard to reach without running cables and putting up antennas on both locations (and no, I don't want to connect to a garage-AP from my phone).&lt;/p&gt;&lt;p&gt;A cellular connected microcontroller would probably work, but I wanted to avoid that. And then, there's Bluetooth. And more importantly - Bluetooth Low Energy (BLE).&lt;/p&gt;&lt;h1&gt;Microcontroller&lt;/h1&gt;&lt;p&gt;I looked around for a microcontroller with integrated bluetooth (and preferably an available cheap dev board with an external antenna). The nRF51822 sparked my interest. It's cheap, packs a 32 bit ARM Cortex M0 core and supports BLE.&lt;/p&gt;&lt;p&gt;I found a small PCB with all the required supporting electronics from CJMCU (probably designed for use in a cheap drone? as it includes a LIS3DH accelerometer). By adding a 24v -&amp;gt; 3.3v step down voltage regulator, a switch, a led, an optocoupler (for triggering the garage door), and a few inputs for magnetic reed switches (for detecting door open or closed) I pretty much had a working prototype.&lt;/p&gt;&lt;p&gt;&lt;figure class=&quot;half&quot;&gt;  &lt;img src=&quot;http://blog.eikeland.se/images/2017-garage/nrf51822.jpg&quot; /&gt;  &lt;img src=&quot;http://blog.eikeland.se/images/2017-garage/app.jpg&quot; /&gt;  &lt;figcaption&gt;Microcontroller board and the iOS app.&lt;/figcaption&gt; &lt;/figure&gt;&lt;/p&gt;&lt;h1&gt;App&lt;/h1&gt;&lt;p&gt;I've never really done any serious iOS development. But I launched Xcode and managed to hobble together some lines of swift code that connects to a bonded BLE device, exchanges some secrets, and makes a &quot;Sesame!&quot;-button go solid blue when the garage is within range. It's not pretty, but it works.&lt;/p&gt;&lt;p&gt;Now - the bad parts. Unless you pay Apple, then your app will stop working after 7 days (free signing cert only lasts for a week). Paying for proper membership costs $99. Refreshing it every 7 days is too much of a chore, so I ended shelling out for a proper developer account. (This was the most expensive part of the whole project)&lt;/p&gt;&lt;p&gt;I also looked into CarPlay, would be pretty cool if you could open the garage from a car's interface, but sadly it seems that Apple have locked this down and requires you to register for some kind of special entitlement license. :(&lt;/p&gt;&lt;h1&gt;Firmware&lt;/h1&gt;&lt;p&gt;I might release the source code for the firmware, but there's a few things I want to iron out first. Overall this was probably the biggest learning experience, I've done some bluetooth stuff before, but BLE is a completely different beast (with it's own nuances, own lingo, etc..)&lt;/p&gt;&lt;p&gt;Making it secure was also harder than it should be, IMHO, there was way too much fidling around to make a decently secure BLE device.&lt;/p&gt;&lt;p&gt;I implemented security the following way:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;I've hooked up a physical button on the device to put it in pairing mode. You  have to manually implement &quot;pairing&quot;-mode and &quot;secure&quot;-mode by selectively  broadcast your services, and once in secure mode maintain a whitelist of  authorized devices.&lt;/li&gt;
  &lt;li&gt;After pairing you can exchange long term secure keys, this is called bonding.  This makes future communication encrypted.&lt;/li&gt;
  &lt;li&gt;And, in an effort of cooking bacon in butter, I exchange an application layer  secret while opening the door (just as an extra layer of security in case i  fucked something up in the BLE communication layer).&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;I'm not going to go much into details about how to do this, but I recommend looking at this &lt;a href=&quot;https://github.com/lancaster-university/microbit-dal&quot;&gt;BBC micro:bit firmware&lt;/a&gt; (also based on nRF51822) for how to set up a whitelist, pairing/bonding, broadcast services, etc.&lt;/p&gt;&lt;p&gt;And to be honest, what's easier if you want to break into a garage? A 2 minute job with a crowbar or hours of sig int and analysis?&lt;/p&gt;&lt;h1&gt;Conclusion&lt;/h1&gt;&lt;p&gt;The opener has been running for a few months now, and it's been working great for the most part. Sometimes the app is a bit slow to connect, or even require me to get quite close before it manages to detect the device. I've a few ideas how to iron this out in software (or the nuclear option of hooking it up to an outside 2.4 ghz panel antenna) - but it hasn't annoyed me enough yet to make me put in the effort :)&lt;/p&gt;&lt;p&gt;TLDR; Just watch the video...&lt;/p&gt;
</description>
<link>
http://blog.eikeland.se/2017/03/27/garage-opener/
</link>
<pubDate>
Mon, 27 Mar 2017 14:00:00 +0200
</pubDate>
<guid isPermaLink='false'>
/2017/03/27/garage-opener/
</guid>
</item>
<item>
<title>
Office coffee alarm WiFi-button for Slack (ESP8266)
</title>
<description>
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: The coffee alarm system no longer work like described below. The non-coffee-club office neighbors moved out, so we changed from a manual to an automatic system. We've reprogrammed a wifi power plug to notify the system when the coffee maker is turned on. The good old button described below is still operational, but now listens for events over MQTT and does the LED light dance when a new pot is brewing.&lt;/p&gt;&lt;p&gt;We have a Slack integrated coffee notification service at work. It's basically just a few lines of Clojure w/ PostgreSQL (for brew logs and stats), notifying our Slack channel whenever someone put on a brew. It recently got upgraded with a WiFi-connected hardware button button, and now the system operates like this:&lt;/p&gt;&lt;p&gt;&lt;figure&gt; &lt;iframe allowfullscreen=&quot;allowfullscreen&quot; frameborder=&quot;0&quot; src=&quot;https://www.youtube.com/embed/U0oF-PBfZIg?VQ=HD720&quot; height=&quot;315&quot; width=&quot;560&quot;&gt;&lt;/iframe&gt; &lt;figcaption&gt;Internet connected Coffee alarm button.&lt;/figcaption&gt; &lt;/figure&gt;&lt;/p&gt;&lt;p&gt;So.. how was this made? Let's start with a few of the requirements. Originally I wanted this to be automatic - maybe triggered by an inductive current-sensor connected to the coffee-maker - but since not everyone on the office floor is part of the light-roast-brew-slack-club we decided to go with an Internet connected button to avoid false alarms.&lt;/p&gt;&lt;h4&gt;Requirements:&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;Triggered via a big physical button.&lt;/li&gt;
  &lt;li&gt;Notify office floor via slack:
  &lt;ul&gt;
    &lt;li&gt;Connect to WiFi&lt;/li&gt;
    &lt;li&gt;Do HTTP POST to a service running on heroku.&lt;/li&gt;
  &lt;/ul&gt;&lt;/li&gt;
  &lt;li&gt;Battery powered.
  &lt;ul&gt;
    &lt;li&gt;Power down after use to conserve battery power.&lt;/li&gt;
  &lt;/ul&gt;&lt;/li&gt;
  &lt;li&gt;Made only using parts I have available. I do not want to wait to complete this  project, so we're just going to wing it.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;It makes a lot of sense to base this project on an ESP8266. It's a newish Chinese chip that's been quickly gaining traction with hardware hackers. 80 MHz 32 bit RISC CPU, integrated 802.11 b/g/n WiFi, reasonable amount of IO options. Best of all, it costs less than $5, and if you ask me, it's the first real glimpse of the promised Internet-of-Things wave (or should I say tsunami?). Internet connected 80 MHz CPUs (at the cost of a couple of dollars each) mean they can be added to everything - including your toaster.&lt;/p&gt;&lt;p&gt;Let's get building!&lt;/p&gt;&lt;p&gt;&lt;figure&gt; &lt;iframe allowfullscreen=&quot;allowfullscreen&quot; frameborder=&quot;0&quot; src=&quot;https://www.youtube.com/embed/5ThP1teWOPU?VQ=HD720&quot; height=&quot;315&quot; width=&quot;560&quot;&gt;&lt;/iframe&gt; &lt;figcaption&gt;Building the wifi button.&lt;/figcaption&gt; &lt;/figure&gt;&lt;/p&gt;&lt;h1&gt;Power&lt;/h1&gt;&lt;p&gt;I want the project to be battery-powered (by a 18650 li-ion cell), sadly the ESP8266 is quite power hungry while connected to WiFi. We could have the module stay in deep sleep most of the time, but I want to eliminate as much power drain as possible, so instead, we're going to power down the entire circuit, and only power the module when the big red button is pressed.&lt;/p&gt;&lt;p&gt;If we wire the button between our battery and the ESP8266, it will power up while the button is pressed, and power back down when the button is released. However, connecting to WiFi, receiving an IP via DHCP, doing a HTTP POST, etc - could take like 20-30 sec+ on a bad day, and I'm not going to stand around holding a big red button for 30 sec every time I make a pot of coffee.&lt;/p&gt;&lt;p&gt;We need a latch, a circuit that once triggered stays powered. And we also want the module to power down the circuit after finishing its' duties. Let's build a..&lt;/p&gt;&lt;h3&gt;Soft Latch Power Switch&lt;/h3&gt;&lt;p&gt;Latches are often made using a P-channel MOSFET and NPN transistor pair. Sadly, I only have big N-channel MOSFETS available. So let's try to make one using a PNP and NPN-transistor pair instead.&lt;/p&gt;&lt;p&gt;&lt;figure class=&quot;half&quot;&gt; &lt;a href=&quot;/images/2015-coffeebutton/latch.png&quot;&gt;&lt;img src=&quot;http://blog.eikeland.se/images/2015-coffeebutton/latch.png&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;/images/2015-coffeebutton/latch.gif&quot;&gt;&lt;img src=&quot;http://blog.eikeland.se/images/2015-coffeebutton/latch.gif&quot; /&gt;&lt;/a&gt; &lt;/figure&gt;&lt;/p&gt;&lt;p&gt;The theory is as follows. Hitting the button will connect the base of the PNP transistor &lt;em&gt;(Q1)&lt;/em&gt; to ground, the transistor will start to conduct, thus powering the micro-controller. Once booted, the micro-controller should immediately put one of it's GPIO pins high, GPIO pin will be connected to the base of NPN transistor &lt;em&gt;(Q2)&lt;/em&gt;. This will take over the role of the button and circuit will continue conducting until micro-controller sets GPIO pin low - at which point everything powers down.&lt;/p&gt;&lt;h4&gt;Problems and solutions&lt;/h4&gt;&lt;p&gt;Turns out the circuit works, but the ESP8266 has a pretty slow boot-time before pin is set high (1+ sec - WiFi calibration?). Meaning it works if you press and hold the button for at least 1-2 second. This is a problem, we need to give the micro-controller more time to finish booting before it can take over control of the power flow. I'm a programmer, not a miracle analog magician, but let's see if we can't figure this one out. We need power flow to continue through the base of &lt;em&gt;Q1&lt;/em&gt; for some time even after a very short button press, and how can we do that? We can try adding a capacitor right after the &lt;em&gt;R2&lt;/em&gt; resistor. In theory, when the button connects that part of the circuit to ground, power should flow quickly from the capacitor. Once button is released, power will flow slowly back into capacitor (through &lt;em&gt;R2&lt;/em&gt; resistor and &lt;em&gt;Q1&lt;/em&gt;'s base), keeping &lt;em&gt;Q1&lt;/em&gt; active for a while until the micro-controller can take over.&lt;/p&gt;&lt;p&gt;We add an overkill 1000uF capacitor, and it works. Now even a really short button press keeps the micro-controller powered for several seconds.&lt;/p&gt;&lt;h3&gt;Voltage regulation&lt;/h3&gt;&lt;p&gt;The ESP8266 can't really handle voltages above ~3.6v without risking damage, and I want to power the circuit from a regular 18650 li-ion cell (the battery cells often used in laptops, and even in the Tesla cars). Li-ion cells have a max voltage of 4.2v and a working voltage of ~3.7v. This turned out to be a bit of a problem, because I didn't really have any suitable voltage regulators laying around. I've a few &lt;a href=&quot;http://www.advanced-monolithic.com/pdf/ds1117.pdf&quot;&gt;AMS1117&lt;/a&gt; 3.3v, but their drop-out voltage (~1) is simply too much when running from a 3.7v cell.&lt;/p&gt;&lt;p&gt;What I really need is something like a MCP1702, but I don't want to wait around for parts - we're going to run unregulated from a partially depleted 18650. Hopefully I remember to not charge it all the way up if it ever gets depleted :) I might add a MCP1702 or similar modern LDO later.&lt;/p&gt;&lt;h1&gt;Spinning LED indicator&lt;/h1&gt;&lt;p&gt;My big red button from sparkfun comes with a single led, I want more, I want to add 3 so that I can display a spinning animation while the button is busy. I'm going to steal a few of &lt;a href=&quot;http://www.stuffandymakes.com/blog/2011/01/08/hack-the-sparkfun-big-red-dome-button&quot;&gt;Andy Frey's ideas&lt;/a&gt;, and hack my button similar as his, but with discrete control over each LED.&lt;/p&gt;&lt;p&gt;&lt;figure&gt; &lt;video style=&quot;max-width: 100%;&quot; loop=&quot;loop&quot; autoplay=&quot;autoplay&quot; preload=&quot;auto&quot; class=&quot;figvideo&quot;&gt; &lt;source type=&quot;video/webm&quot; src=&quot;http://blog.eikeland.se/images/2015-coffeebutton/snurr.webm&quot;&gt; &lt;source type=&quot;video/mp4&quot; src=&quot;http://blog.eikeland.se/images/2015-coffeebutton/snurr.mp4&quot;&gt; &lt;/source&gt;&lt;/source&gt;&lt;/video&gt; &lt;figcaption&gt;3 LED Busy indicator driven by an ULN2003 darlington array.&lt;/figcaption&gt; &lt;/figure&gt;&lt;/p&gt;&lt;p&gt;The ESP8266 can only source like 12 mA current per pin, so to drive the 3 LEDs I add a &lt;a href=&quot;https://en.wikipedia.org/wiki/ULN2003A&quot;&gt;ULN2003A&lt;/a&gt;. The ULN2003A is a NPN (darlington) transistor array, so instead of adding discrete transistors we get 7 of them in one package. Connect 3 GPIO from the ESP8266 to the transistor array's base side, and 3 LEDs (with resistors) to the collector side. This leaves 4 transistors for future expansion.&lt;/p&gt;&lt;p&gt;To make a spinning led indicator we'll use the &lt;a href=&quot;https://github.com/esp8266/Arduino/blob/esp8266-sdk-1.0/hardware/esp8266com/esp8266/libraries/Ticker/Ticker.h&quot;&gt;Ticker&lt;/a&gt; library to receive a callback every 0.2 seconds or so.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;c&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;Ticker&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;spinticker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;spincount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;spinLEDs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;spincount&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;led&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;led&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LEDCOUNT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;led&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;spincount&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LEDCOUNT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;led&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;digitalWrite&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LEDPINS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;led&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HIGH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;digitalWrite&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LEDPINS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;led&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOW&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;spinticker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SPININTERVAL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;spinLEDs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h1&gt;Enclosure&lt;/h1&gt;&lt;p&gt;&lt;figure&gt; &lt;a href=&quot;/images/2015-coffeebutton/enclosure2.jpg&quot;&gt;&lt;img src=&quot;http://blog.eikeland.se/images/2015-coffeebutton/enclosure2.jpg&quot; /&gt;&lt;/a&gt; &lt;figcaption&gt;Spray painted red junction box&lt;/figcaption&gt; &lt;/figure&gt;&lt;/p&gt;&lt;p&gt;I didn't really have any suitable sized electronic boxes laying around, only an ugly junction box. I hate ugly beige boxes, so, let's at least give it some color. Spray painted red looks OKish I guess.&lt;/p&gt;&lt;h1&gt;Code&lt;/h1&gt;&lt;p&gt;Next up, let's add a bit of code to make it work properly, it's all available on github at &lt;a href=&quot;https://github.com/revolverhuset/mokkameister&quot;&gt;revolverhuset/mokkameister&lt;/a&gt; and &lt;a href=&quot;https://github.com/revolverhuset/mokkameister-button&quot;&gt;revolverhuset/mokkameister-button&lt;/a&gt;. But let's have a look at the important stuff here anyway, it's quite small.&lt;/p&gt;&lt;h3&gt;ESP8266&lt;/h3&gt;&lt;p&gt;On the micro-controller we connect to wifi at the push of the button, and then do a simple hand crafted HTTP request. We also send an auth token, doesn't really add that much security since we're not doing HTTPS, but it's better than nothing I guess.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;c&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;host&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;myservice.herokuapp.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;/coffee-button/&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;httpPort&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;secret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;secret&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;notifyButtonPush&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;WiFiClient&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;httpPort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;POST &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; HTTP/1.1&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\r\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
                 &lt;span class=&quot;s&quot;&gt;&quot;Host: &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;host&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\r\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
                 &lt;span class=&quot;s&quot;&gt;&quot;Content-Type: application/x-www-form-urlencoded&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\r\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
                 &lt;span class=&quot;s&quot;&gt;&quot;Connection: close&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\r\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
                 &lt;span class=&quot;s&quot;&gt;&quot;Content-Length: &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;secret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\r\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
                 &lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\r\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
                 &lt;span class=&quot;s&quot;&gt;&quot;secret=&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;secret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\r\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
                 &lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\r\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;available&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()){&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;readStringUntil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;'\r'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Heroku/Clojure service&lt;/h3&gt;&lt;p&gt;Over at heroku we then create simple liberator resource that does something like the following: Validate token, persist brew-data to db, notify slack, wait 5 minutes, notify slack again. We do the waiting in an core.async go-thread.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;valid-button-token?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;secret&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get-in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ctx&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:request&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:params&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:secret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;= &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;secret&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;env&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:button-secret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;button-post!&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;db/persist-brew!&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;brewdata&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;slack/notify!&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Good news everyone! Coffee is brewing!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;&amp;lt;!&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;timeout&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;* &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;slack/notify!&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Coffee is ready!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&quot;OK&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;defresource&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;coffee-button&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:available-media-types&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text/plain&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:allowed-methods&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:authorized?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;valid-button-token?&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:post!&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;button-post!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Mount the resource on a suitable route, and be sure to add the default ring api-middleware (so that params are parsed).&lt;/p&gt;&lt;h1&gt;Conclusion&lt;/h1&gt;&lt;p&gt;Overall it's been a fun tiny side-project, I need to do more of these. Often I want to make something, order up the parts - but when they arrive one month later I've already moved on to other things - so I'm def going to build more with the parts I've at hand, even if they aren't optimal. Also, having a tiny assortment of ESP8266s around is awesome, they are quite useable for things you would want to Internet-able without much effort..&lt;/p&gt;&lt;p&gt;&lt;figure&gt; &lt;a href=&quot;/images/2015-coffeebutton/mug.jpg&quot;&gt;&lt;img src=&quot;http://blog.eikeland.se/images/2015-coffeebutton/mug.jpg&quot; /&gt;&lt;/a&gt; &lt;figcaption&gt;Enjoy a fresh light roast brew!&lt;/figcaption&gt; &lt;/figure&gt;&lt;/p&gt;&lt;p&gt;Oh.. and we seems to have a robot infestation problem (again..) :(&lt;/p&gt;
</description>
<link>
http://blog.eikeland.se/2015/07/20/coffee-button/
</link>
<pubDate>
Mon, 20 Jul 2015 14:00:00 +0200
</pubDate>
<guid isPermaLink='false'>
/2015/07/20/coffee-button/
</guid>
</item>
<item>
<title>
Capacitive touch banana piano in Clojure / Overtone.
</title>
<description>
&lt;p&gt;&lt;figure&gt; &lt;iframe allowfullscreen=&quot;allowfullscreen&quot; frameborder=&quot;0&quot; src=&quot;https://www.youtube.com/embed/EOjGsdDoicw?VQ=HD720&quot; height=&quot;315&quot; width=&quot;560&quot;&gt;&lt;/iframe&gt; &lt;figcaption&gt;Making of a banana piano, with a bit of swedish jazz from my co-worker &lt;a href=&quot;http://hsorbo.no&quot;&gt;Håvard Sørbø&lt;/a&gt;&lt;a&gt;&lt;/a&gt;&lt;/figcaption&gt; &lt;/figure&gt;&lt;/p&gt;&lt;p&gt;This weekend my niece-in-law is staying over, and to maintain my image as the crazy scientist uncle I've planned to make a banana piano (and lots of weird ice creams). In clojure there's a pretty cool programmable audio environment called &lt;a href=&quot;http://overtone.github.io&quot;&gt;Overtone&lt;/a&gt;. Overtone features a decent sampled piano, and I'm thinking this could be a great basis for a banana-piano.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Fun fact: a full piano requires about 11 kg bananas - at $3 per kg that's still way cheaper (and lighter) than a Steinway.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;There's a couple of ways we can make bananas act as tangents, one of them is to use the bananas as capacitive touch sensors. Using a nice little hack it's possible to do this using regular digital pins on a microcontroller. The hack is (afaik) originally from Mario Becker, Fraunhofer IGD, 2007 (website dead). Check out the article on capacitive sensors over at &lt;a href=&quot;http://playground.arduino.cc/Code/CapacitiveSensor&quot;&gt;arduino.cc&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Hook up a pin to something.&lt;/li&gt;
  &lt;li&gt;Disable interrupts.&lt;/li&gt;
  &lt;li&gt;Set pin as input.&lt;/li&gt;
  &lt;li&gt;Active pull-up on pin.&lt;/li&gt;
  &lt;li&gt;Count cycles until pin is high.&lt;/li&gt;
  &lt;li&gt;Enable interrupts&lt;/li&gt;
  &lt;li&gt;Set pin as output, low.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;The number of cycles needed before the pin goes high will depend on the capacitance of whatever connected to the pin. A banana might require 8 cycles before the pin goes high, while a touched banana might require 15.&lt;/p&gt;&lt;p&gt;We can connect a number of bananas to a microcontroller, iterate over the bananas, read their cycle count before banana-pin goes high, and then transmit a message over a serial connection indicating the pin number if this cycle count is above a given threshold.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;cuda&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PORTS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;THRESHOLDS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;touched&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;readCapacitivePin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pinToMeasure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;volatile&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;volatile&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ddr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;volatile&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;byte&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitmask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;portOutputRegister&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;digitalPinToPort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pinToMeasure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;ddr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;portModeRegister&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;digitalPinToPort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pinToMeasure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;bitmask&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;digitalPinToBitMask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pinToMeasure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;pin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;portInputRegister&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;digitalPinToPort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pinToMeasure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// Discharge the pin first by setting it low and output&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bitmask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ddr&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;|=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitmask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// Prevent the timer IRQ from disturbing our measurement&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;noInterrupts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// Make the pin an input with the internal pull-up on&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ddr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bitmask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitmask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// Now see how long the pin to get pulled up. This manual unrolling of the loop&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// decreases the number of hardware cycles between each read of the pin,&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// thus increasing sensitivity.&lt;/span&gt;

  &lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cycles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitmask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cycles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitmask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cycles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitmask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cycles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitmask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cycles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitmask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cycles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitmask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cycles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitmask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cycles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitmask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cycles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitmask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cycles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitmask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cycles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitmask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cycles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitmask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cycles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitmask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cycles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitmask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cycles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitmask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cycles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;14&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitmask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cycles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitmask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cycles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// End of timing-critical section&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;interrupts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// Discharge the pin again by setting it low and output&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bitmask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ddr&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;|=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitmask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cycles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Serial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;57600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;handlePort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cycles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;readCapacitivePin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PORTS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;touched&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cycles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;THRESHOLDS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;touched&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Serial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;touched&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cycles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;THRESHOLDS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;touched&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;loop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;handlePort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// cheap-ass debounce..&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Your computer must be grounded for this to work reliably, and it also helps to add a ground plane under the bananas (see video).&lt;/p&gt;&lt;p&gt;When touching a banana, the microcontroller will transmit a character from 0 to 7, we can then receive this value in clojure using a serial-port library, turn it into an int, map the value to a scale to get a note. And play this using an instrument - in this case - the excellent sampled piano available in Overtone.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;ns &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;musikk.core&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:require&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;serial-port&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;serial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;overtone.live&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:refer&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;overtone.inst.sampled-piano&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:refer&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;serial/open&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;/dev/tty.usbserial-A800F185&quot;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;57600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;chr-&amp;gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;-&amp;gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;char &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Integer.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;banana-touch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;index &lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;chr-&amp;gt;int&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;my-scale&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scale&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:C4&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:major&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;note&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;nth &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;my-scale&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sampled-piano&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:note&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;note&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:sustain&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;serial/on-byte&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;banana-touch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now enjoy and experiment with scales and different instruments in Overtone - your efforts will not be fruitless. Maybe I'll make a broccoli theremin next time my niece visits. :)&lt;/p&gt;&lt;h2&gt;Update:&lt;/h2&gt;&lt;p&gt;Since a few people have asked, here's a wiring diagram. It's super easy, only wires and no extra components. The ground plane (alu foil) is optional. If you're having problems in very noisy environments you can put a 1nF capacitor in line with the banana. I used an &lt;a href=&quot;http://www.arduino.cc/en/Main/ArduinoBoardNano&quot;&gt;arduino nano&lt;/a&gt;, but any atmega328 based arduino can be used (nano, uno, etc). (And probably all others with minor modifications). Any wires you can connect to a banana and an arduino works. My arduino had male headers, I used 4p dupont female-female cables, which i broke out to 1p male-male for each individual banana. These come in all shapes, genders and lengths on ebay for very little money.&lt;/p&gt;&lt;p&gt;Clojure libraries used: &lt;code&gt;[serial-port &quot;1.1.2&quot;]&lt;/code&gt; and &lt;code&gt;[overtone &quot;0.9.1&quot;]&lt;/code&gt;&lt;/p&gt;&lt;p&gt;&lt;figure&gt; &lt;a href=&quot;/images/banana/wiring.png&quot;&gt;&lt;img src=&quot;http://blog.eikeland.se/images/banana/wiring.png&quot; /&gt;&lt;/a&gt; &lt;figcaption&gt;Wiring setup for arduino nano.&lt;/figcaption&gt; &lt;/figure&gt;&lt;/p&gt;
</description>
<link>
http://blog.eikeland.se/2015/04/24/banana-piano/
</link>
<pubDate>
Fri, 24 Apr 2015 14:00:00 +0200
</pubDate>
<guid isPermaLink='false'>
/2015/04/24/banana-piano/
</guid>
</item>
<item>
<title>
Boiling Sous-Vide Eggs using Clojure's Transducers
</title>
<description>
&lt;p&gt;I love cooking, especially geeky molecular gastronomy cooking, you know, the type of cooking involving scientific knowledge, -equipment and ingredients like &lt;a href=&quot;/2013/02/04/liquid-nitrogen-hop-ice-cream/&quot;&gt;liquid nitrogen&lt;/a&gt; and similar. I already have a sous-vide setup, well, two actually (here is one of them: &lt;a href=&quot;/2011/08/17/sousvide-o-mator/&quot;&gt;sousvide-o-mator&lt;/a&gt;), but I have none that run Clojure. So join me while I attempt to cook up some sous-vide eggs using the new transducers coming in Clojure 1.7. If you don't know what transducers are about, take a look &lt;a href=&quot;/2014/08/14/transducers/&quot;&gt;here&lt;/a&gt; before you continue.&lt;/p&gt;&lt;p&gt;To cook sous-vide we need to keep the temperature at a given point over time. For eggs, around 65C is pretty good. To do this we use a PID-controller.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defrecord &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Pid&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;set-point&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;k-p&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;k-i&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;k-d&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;error-sum&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;error-last&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;output-max&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;make-pid&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&quot;Create a new PID-controller.&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;   Requires: target temperature, kp, ki, kd gain.&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;   Optional: output-max=100 (error-sum=0, error-last=0, output=0)&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;set-point&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;k-p&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;k-i&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;k-d&lt;/span&gt;
   &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:keys&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;error-sum&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;error-last&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;output-max&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:or&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;error-sum&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;error-last&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;output-max&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Pid.&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;set-point&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;k-p&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;k-i&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;k-d&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;error-sum&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;error-last&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;output-max&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;calculate-pid&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&quot;Calculate next PID iteration&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:keys&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;set-point&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;error-last&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;error-sum&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;k-p&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;k-i&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;k-d&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;output-max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;pid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;error&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;- &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;set-point&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;error-dv&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;- &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;error-last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;error-sum&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;+ &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;error-sum&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;output&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;min &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;output-max&lt;/span&gt;
                       &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;+ &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;* &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;k-p&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                          &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;* &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;k-i&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;error-sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                          &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;* &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;k-d&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;error-dv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;assoc &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pid&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:error-last&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:error-sum&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;error-sum&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:output&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Let's start by creating a record type for our PID-controller. The PID algorithm requires a few values: &lt;code&gt;set-point&lt;/code&gt; - the target temperature, example: 65C for a perfect sous-vide egg. &lt;code&gt;k-p&lt;/code&gt; - the proportional gain, &lt;code&gt;k-i&lt;/code&gt; - the integral gain and &lt;code&gt;k-d&lt;/code&gt; - the derivative gain. The proportinal gain is the most important part of the Algorithm, it controls how hard we push the pedal to the floor depending on the current error (distance to target-temperature). The integral factor looks at error over time. It's what tries to keep the output steady when we've reached our target. The derivative factor tries to counteract overshooting by looking at the error derivative (the change in error rate) - it dampens the other factors when we close on our target.&lt;/p&gt;&lt;p&gt;We also need to keep track of &lt;code&gt;error-sum&lt;/code&gt;, the previous error - &lt;code&gt;error-last&lt;/code&gt;, and we need a place to put the recommended output.&lt;/p&gt;&lt;p&gt;Next, we create &lt;code&gt;make-pid&lt;/code&gt; - a constructing function, this simply sets a few default values if they're not provided.&lt;/p&gt;&lt;p&gt;Then we implement the PID algorithm as a function - &lt;code&gt;calculate-pid&lt;/code&gt;. It accepts a PID-controller and the current input sample (ex: temperature). It returns the PID-controller record for the next iteration.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pid-transducer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;set-point&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;k-p&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;k-i&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;k-d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fn &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;xf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pid&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;volatile!&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;make-pid&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;set-point&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;k-p&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;k-i&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;k-d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))]&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fn&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;xf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;xf&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
           &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;vswap!&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;pid&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fn &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;calculate-pid&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
           &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;xf&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:output&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))))))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can then use this to create a &quot;stateful&quot; transducer for doing PID operations on an input (sequence, channel, stream, etc..). (Clarification from Alex Miller: The transducer isn't stateful, but the returning reducing function is, ofc - thanks!) Transducers look pretty weird (mostly because of their nested multi-arity lambdas), but they smell pretty nice, so I guess they're ok.&lt;/p&gt;&lt;p&gt;To help keep state in a transducer reducing function, clojure 1.7 introduces volatiles - volatiles work just like atoms - but with some limitations (rely on thread isolation for compound atomic swap! operations, etc). They are faster than atoms, but otherwise work just the same. If you're used to atoms, their use should be pretty self explanatory.&lt;/p&gt;&lt;p&gt;All values received by the transducer is given to the PID-controller. The PID-controller state is kept in a volatile, and updated for every iteration.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;into &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pid-transducer&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.2&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.05&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;31&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;45&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;61&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;81&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;91&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;98&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;105&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;110&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;120&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;110&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;; [5.0 9.95 14.8 19.5 24.0 28.0 31.45 34.2 36.15 37.1 37.55 37.65 37.65 37.4 36.9 35.9 35.4 35.4]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Let's test it out by pretend we're trying to make something reach 100C, we give the PID-controller a fake sequence of measured temperatures over time, and transduce into a vector. The output describes how hard the PID-algorithm (with these settings) would have pushed on the throttle if the system responded like the input temperature sequence.&lt;/p&gt;&lt;p&gt;The great thing about transducers is that they're general implementations of operations over data, they really do not care how the data arrives or how it should be delivered. It works with data structures, streams, channels, and so on.&lt;/p&gt;&lt;p&gt;So, imagine that we have an electric kettle. We can read the temperature of this kettle and we can control the heating element. We receive temperatures on a channel, and can push instructions to the heating element on another channel. If we have this setup, then we can simply plug in our PID transducer in the middle, and everything should work!&lt;/p&gt;&lt;p&gt;&lt;figure&gt; &lt;a href=&quot;/images/2014-cooking-transducers/diagram.svg&quot;&gt; &lt;img onerror=&quot;this.src='/images/2014-cooking-transducers/diagram.png'&quot; src=&quot;http://blog.eikeland.se/images/2014-cooking-transducers/diagram.svg&quot; /&gt; &lt;/a&gt; &lt;/figure&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c1&quot;&gt;;; Temperatures arrive via this channel&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;temperatures&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;chan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;;; This channel accepts temperatures, and supplies&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; PID outputs, trying to achieve a temperature of 65C&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pid-output&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pid-transducer&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;65&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.02&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.01&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;;; This channel is used to ask the kettle for the next&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; temperature sample (once our PID cycle is done.&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fetch-next&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;chan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;;; We pipe temperatures into the pid-controller:&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pipe&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;temperatures&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;pid-output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Next we create a few channels, one for temperatures, one for pid outputs, and one to ask for new temperature samples. We connect the temperatures to the pid channel.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;control-heater&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pid-output&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;fetch-next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;go-loop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;when-let &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pid-time&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;&amp;lt;!&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;pid-output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;time-on&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;* &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;300&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;pid-time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;time-off&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;- &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30000&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;time-on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))]&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;when &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;&amp;lt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;time-on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;heater-on!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;&amp;lt;!&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;timeout&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;time-on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;heater-off!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;&amp;lt;!&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;timeout&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;time-off&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;&amp;gt;!&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;fetch-next&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;recur&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))))&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;control-heater&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;pid-output&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;fetch-next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The above function will wait for a value from the PID-controller, calculate how long (ms) the power needs to be on, and how long (ms) it needs to be off in the next cycle. It then turns the heater on, waits a bit, turns it off, waits a bit, and requests the next value.&lt;/p&gt;&lt;p&gt;&lt;figure class=&quot;half&quot;&gt; &lt;a href=&quot;/images/2014-cooking-transducers/kettle.jpg&quot;&gt;&lt;img src=&quot;http://blog.eikeland.se/images/2014-cooking-transducers/kettle.jpg&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;/images/2014-cooking-transducers/power.jpg&quot;&gt;&lt;img src=&quot;http://blog.eikeland.se/images/2014-cooking-transducers/power.jpg&quot; /&gt;&lt;/a&gt; &lt;/figure&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;zmq-send!&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;conn&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:system&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;power&quot;&lt;/span&gt;
                 &lt;span class=&quot;ss&quot;&gt;:msgtype&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;command&quot;&lt;/span&gt;
                 &lt;span class=&quot;ss&quot;&gt;:location&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;kitchen-water&quot;&lt;/span&gt;
                 &lt;span class=&quot;ss&quot;&gt;:command&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;on&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In my case, the &lt;code&gt;heater-on!&lt;/code&gt; and &lt;code&gt;heater-off!&lt;/code&gt; functions simply send a message to my zeromq based home automation system. I already have power control of my water kettle and my coffee cooker - so all that's required is simply a JSON-formatted message on a message bus. Another way to do this would for example be an arduino with a solid state relay. See &lt;a href=&quot;/2012/07/08/building-a-home-automation-system-part-1-intro/&quot;&gt;intro&lt;/a&gt;, &lt;a href=&quot;/2012/09/24/building-a-home-automation-system-the-broker-and-sensors-part-2/&quot;&gt;sensors&lt;/a&gt; and &lt;a href=&quot;/2012/10/20/building-a-home-automation-system-power-control-part-3/&quot;&gt;power&lt;/a&gt; for more details of my home automation setup.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c1&quot;&gt;;; Open serial port&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;serial/open&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;/dev/tty.usbserial&quot;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;115200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;;; Put values into the temperatures channel&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;serial/on-value&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;partial &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;&amp;gt;!!&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;temperatures&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;;; Ask arduino for next temperature when we're ready for one..&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;go-loop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;&amp;lt;!&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;fetch-next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;serial/write-str&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;next&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;recur&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;&amp;lt;!&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;fetch-next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The input temperatures are received over the serial port from an arduino with a DS18B20 temperature probe.&lt;/p&gt;&lt;p&gt;&lt;figure&gt; &lt;a href=&quot;/images/2014-cooking-transducers/egg.jpg&quot;&gt;&lt;img src=&quot;http://blog.eikeland.se/images/2014-cooking-transducers/egg.jpg&quot; /&gt;&lt;/a&gt; &lt;/figure&gt;&lt;/p&gt;&lt;p&gt;Start the system by running: &lt;code&gt;(&amp;gt;!! fetch-next :next)&lt;/code&gt;, allow the system to stabilize, drop in a couple of eggs and wait 45 minutes. You should be awarded with the most perfect creamy egg yolk you have ever tasted. I like mine on a piece of bread with avocado and a sprinkle of salt. Enjoy, now you're cooking with clojure!&lt;/p&gt;
</description>
<link>
http://blog.eikeland.se/2014/10/06/pid-transducer/
</link>
<pubDate>
Mon, 06 Oct 2014 09:00:00 +0200
</pubDate>
<guid isPermaLink='false'>
/2014/10/06/pid-transducer/
</guid>
</item>
<item>
<title>
Transduce me up, Hickey!
</title>
<description>
&lt;p&gt;&lt;strong&gt;Transducers&lt;/strong&gt; (reducing function transformers) are apparently coming to Clojure in v1.7 - but what is a  transducer? Are they some sort of a &lt;a href=&quot;http://nb.urbandictionary.com/define.php?term=continuum%20transfunctioner&quot;&gt;continuum transfunctioner&lt;/a&gt;? Some say they are &lt;a href=&quot;http://www.reddit.com/r/haskell/comments/2cv6l4/clojures_transducers_are_perverse_lenses/&quot;&gt;perverse lenses&lt;/a&gt;, others that they are &lt;a href=&quot;http://oleksandrmanzyuk.wordpress.com/2014/08/09/transducers-are-monoid-homomorphisms/&quot;&gt;monoidals&lt;/a&gt;. I have no idea, but I want to find out! So let's figure out what's changed and play with them for a bit.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/clojure/clojure/commit/2a09172e0c3285ccdf79d1dc4d399d190678b670&quot;&gt;Here's&lt;/a&gt; the work in progress commit that added them to clojure.core. A few signatures were changed, and a few functions were added. In particular, it seems like most of the higher order functions that works on top of the sequence abstractions were altered - map, filter, reduce + friends. So, what's the new signature of map?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;clojure.core/map
([f] [f coll] [f c1 c2] [f c1 c2 c3] [f c1 c2 c3 &amp;amp; colls])
Added in 1.0
  Returns a lazy sequence consisting of the result of applying f to
  the set of first items of each coll, followed by applying f to the
  set of second items in each coll, until any one of the colls is
  exhausted.  Any remaining items in other colls are ignored. Function
  f should accept number-of-colls arguments. Returns a transducer when
  no collection is provided.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Okay! The first signature here is new. If you apply map to a function - and NO collection, it will return a transducer.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;increment&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;map &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;inc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;What do we actually have now? Is this simply partial function application (partial map inc) or currying or something like that? Let's naively give it a collection and see what happens.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;increment&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;;; Don't use them like this..&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;&amp;lt;core$map$fn__4338$fn__4339&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;clojure.core$map$fn__4338$fn__4339&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;e2f4944&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Hmm, no, this is defiantly not partial application of map, we get a function in return here, so I'm pretty sure this is not how they should be used. Let's look at how you are supposed to use them.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c1&quot;&gt;;; We can get a sequence of something via a transducer function.&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sequence&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;increment&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; (2 3 4 5 6)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;;; We can transduce into a collection:&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;into &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;increment&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; [2 3 4 5 6]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;;; We can transform and reduce a collection:&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;transduce&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;increment&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;+ &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; 20&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But.. I can already do all of these steps using the existing sequence abstractions.. Example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;reduce + &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;map inc &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; 20&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Transducers got one nice trick up their sleeve, they have a really nice composability.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c1&quot;&gt;;; Transducer functions:&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;add-2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;map &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;partial + &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;keep-odd&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;filter &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;odd?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;square&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;map &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;* &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;;; Composing multiple transducers&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;add-2-keep-odd-squared&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;comp &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;add-2&lt;/span&gt;
                                  &lt;span class=&quot;nv&quot;&gt;keep-odd&lt;/span&gt;
                                  &lt;span class=&quot;nv&quot;&gt;square&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sequence&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;add-2-keep-odd-squared&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;range &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; (9 25 49 81 121 169 225 289 361 441 529 625 729 841 961 1089 ....&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But.. similar stuff can already be done using existing functionality..&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;range &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
     &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;map &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;partial + &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
     &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;filter &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;odd?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
     &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;map &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;* &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; (9 25 49 81 121 169 225 289 361 441 529 625 729 841 961 1089 ....&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So, what's the point here really? I'm going to assume that there is a really good point, since the people creating this stuff are way smarter than me.. So let's dig deeper. Why couldn't we use the transducers directly earlier? Let's have a look at the signatures of these functions:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;map f: (a-&amp;gt;b)-&amp;gt;(x-&amp;gt;b-&amp;gt;x)-&amp;gt;(x-&amp;gt;a-&amp;gt;x)

filter pred: (a-&amp;gt;bool)-&amp;gt;(x-&amp;gt;a-&amp;gt;x)-&amp;gt;(x-&amp;gt;a-&amp;gt;x)

flatmap f: (a-&amp;gt;[b])-&amp;gt;(x-&amp;gt;b-&amp;gt;x)-&amp;gt;(x-&amp;gt;a-&amp;gt;x)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Aha, that's a bit clearer. Filter might be the easiest to look at, it takes a predicate and returns a transducer function. The transducer itself has signature &lt;code&gt;(x-&amp;gt;b-&amp;gt;x)-&amp;gt;(x-&amp;gt;a-&amp;gt;x)&lt;/code&gt; where &lt;code&gt;a = b&lt;/code&gt; for filter. It takes another function that takes something and an item type b, and returns something. The result of this again is another function that takes something and item a.. and output something. However, I still find this a bit confusing.&lt;/p&gt;&lt;p&gt;It might be easier if we have a look at what x might be here: collections, sequences, and so on. So, for a vector, I need to give a transducer a function that operates on a vector and on an item, and outputs a vector. Let's try to do that!&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c1&quot;&gt;;; let's call the x-&amp;gt;b-&amp;gt;x part &quot;builder&quot;..&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; and the x-&amp;gt;a-&amp;gt;x &quot;applier&quot;.. for a lack of better names.&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;;; Filtering transducer, remove even numbers:&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;keep-odd&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;filter &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;odd?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;;; A simple vector builder, takes x and b, returns x.&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;builder&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;vec&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;conj &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;;; Now, let's give the builder to the transducer..&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;applier&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;keep-odd&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We now have access to the inner function with signature &lt;code&gt;x-&amp;gt;a-&amp;gt;x&lt;/code&gt;, let's try to use it to filter a list of numbers, manually. It takes a something, and an item. We don't have this something yet, so let's give it nil, and let's give it the first number from our list as b.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c1&quot;&gt;;; Vector of numbers: [1 2 3 4 5]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;applier&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; [1]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;applier&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; [1]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;applier&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; [1 3]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;applier&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; [1 3]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;applier&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; [1 3 5]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Do you see what's going on? We are driving the vector collection logic here (deconstruction and construction). The transducer itself has zero knowledge about the collection it's working on!&lt;/p&gt;&lt;h2&gt;Why is this a good thing?&lt;/h2&gt;&lt;p&gt;In clojure there are a couple of different abstractions over collections of data. We have the sequence abstraction, allowing us to work on lazy sequences of data using operations like map, filter, reduce, take, etc - all chilled out working lazily hammock-style. Then we have reducers, a highly efficient (potentially concurrent/parallel) way of operating on collections through r/map, r/fold, r/filter, r/flatten, r/reduce, etc. We also have core.async, which work by shuffling data through channels (CSP-style), core.async has functions like map&amp;lt;, map&amp;gt;, filter&amp;lt;, filter&amp;gt;.&lt;/p&gt;&lt;p&gt;Do you see a pattern? Yes? Cool! Let's play with core.async a bit. The latest development-version of core.async that is. Let's look up the documentation for &lt;code&gt;chan&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;clojure.core.async/chan
([] [buf-or-n] [buf-or-n xform] [buf-or-n xform ex-handler])
  Creates a channel with an optional buffer, an optional transducer
  (like (map f), (filter p) etc or a composition thereof), and an
  optional exception-handler.  If buf-or-n is a number, will create
  and use a fixed buffer of that size. If a transducer is supplied a
  buffer must be specified. ex-handler must be a fn of one argument -
  if an exception occurs during transformation it will be called with
  the Throwable as an argument, and any non-nil return value will be
  placed in the channel.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Hey! there's an optional transducer here now.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;clojure.core.async&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:refer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;onto-chan&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;&amp;lt;!!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]])&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;;; Create a channel, buffer size 10, with a transducer added&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;add-2-keep-odd-square&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;;; Dump all the numbers from 1 to 100 into the channel (this runs in a go-block)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;onto-chan&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;range &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;;; Pull all the transformed numbers out of the channel, into a vector.&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;&amp;lt;!!&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;async/into&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; [9 25 49 81 121 169 225 289 361 441 529 625 729 841 961 1089 .... ]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Before transducers we would have had to express the add-2-keep-odd-square logic using core async's higher order functions, but now we can instead reuse the transducer we've already created. Here the transducer is used to map and filter over something that isn't even a collection/sequence. The transducer has no idea that it's handling data on a core.async channel, we didn't have to change the map/filter/etc logic in any way to make it work on channels instead of sequences.&lt;/p&gt;&lt;p&gt;This means that all the code for higher order convenience functions in core.async (map&amp;lt;&amp;gt;, mapcat&amp;lt;&amp;gt;, filter&amp;lt;&amp;gt;, etc) now basically is deprecated - and it has now been labeled as such in the documentation. Boom!&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;Transducers makes it so that that the logic you express using filter, map, reduce, take, random-sample, partition-by, etc, etc, etc, can be re-used in completely different contexts. The logic is all isolated, transducers are oblivious to the underlying collection, stream, observable, iterateable, whatever context. That's an useful abstraction if you ask me :)&lt;/p&gt;&lt;p&gt;&lt;strong&gt;For an example of how to make a transducer, head over to: &lt;a href=&quot;/2014/10/06/pid-transducer/&quot;&gt;Boiling Sous-Vide Eggs using Clojure's Transducers&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
</description>
<link>
http://blog.eikeland.se/2014/08/14/transducers/
</link>
<pubDate>
Thu, 14 Aug 2014 09:00:00 +0200
</pubDate>
<guid isPermaLink='false'>
/2014/08/14/transducers/
</guid>
</item>
<item>
<title>
GL.iNet Openwrt router
</title>
<description>
&lt;p&gt;I recently bought an interesting little router on eBay, a &lt;a href=&quot;http://www.ebay.com/itm/Portable-Smart-Router-GL-iNet-3G-OpenWrt-Mobile-App-control-16M-flash-/221462303933?pt=COMP_EN_Routers&amp;amp;hash=item33902e94bd&quot;&gt;GL.iNet&lt;/a&gt; router. Pretty cheap, about $25 + shipping.&lt;/p&gt;&lt;p&gt;It sports the same form factor as the sweet little &lt;a href=&quot;http://wiki.openwrt.org/toh/tp-link/tl-wr703n&quot;&gt;TL-WR703n&lt;/a&gt; - everyones favorite hackable cheap linux router. Not only is the form factor the same, it's the same SOC - a AR9330.&lt;/p&gt;&lt;p&gt;Here the similarites end however. Many people (me included) modify their WR703n routers, upgrading the hardware with larger flash, more ram, break out GPIO, etc, etc. And guess what - the GL.iNet router has all of these modifications - out of the box!&lt;/p&gt;&lt;p&gt;&lt;figure&gt; &lt;a href=&quot;/images/glinet/board.png&quot;&gt;&lt;img src=&quot;http://blog.eikeland.se/images/glinet/board.png&quot; /&gt;&lt;/a&gt; &lt;/figure&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;AR9330 SOC (same).&lt;/li&gt;
  &lt;li&gt;64 Mb ram (vs 32 Mb).&lt;/li&gt;
  &lt;li&gt;16 Mb nand flash (vs 4 Mb).&lt;/li&gt;
  &lt;li&gt;Serial UART on 3 header pin (vs serial on pads).&lt;/li&gt;
  &lt;li&gt;Friendly row of gpio broken out (vs pads spread all over the board).&lt;/li&gt;
  &lt;li&gt;2 ethernet (vs 1 ethernet).&lt;/li&gt;
  &lt;li&gt;USB2 (same)&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;It's like a pre-modded WR703n on steroids! Awesome!&lt;/p&gt;&lt;p&gt;The backside of the device has a sticker with all the settings you need, IP, SSID, passwords, etc, they even set up a ddns address for your device, making it availble from their domain (many people will probably want to disable this..) which I guess can be of great convenience to some.&lt;/p&gt;&lt;p&gt;If you enter the WebUI, it actually looks pretty nice, it's preloaded with stuff for downloading (web, torrent, etc) and sharing an external drive, or streaming from a web camera, etc. You're met with a decent wizard that helps you set up the device.&lt;/p&gt;&lt;p&gt;&lt;figure class=&quot;half&quot;&gt; &lt;a href=&quot;/images/glinet/glinet2.png&quot;&gt;&lt;img src=&quot;http://blog.eikeland.se/images/glinet/glinet2.png&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;/images/glinet/glinet1.png&quot;&gt;&lt;img src=&quot;http://blog.eikeland.se/images/glinet/glinet1.png&quot; /&gt;&lt;/a&gt; &lt;/figure&gt;&lt;/p&gt;&lt;p&gt;But.. guess what happens if you press the advanced settings button - boom! The OpenWRT webui.. It's actually running Barrier Breaker from OpenWRT Trunk, and a pretty recent version at that. They just add their own stuff on top of the immensly powerful OpenWRT distribution. All the goodies are right under the hood - and you can easily do a clean OpenWRT-install if you do not want any of the GL-iNet stuff.&lt;/p&gt;&lt;p&gt;This is the device to get if you need a cheap embedded low-powered linux device, with usb2, gpio, lan, wifi, etc for a project.&lt;/p&gt;&lt;p&gt;They even offer &lt;a href=&quot;http://www.gl-inet.com/w/?p=398&amp;amp;lang=en&quot;&gt;instructions&lt;/a&gt; on how to build a custom image for their router - how cool is that?&lt;/p&gt;&lt;p&gt;Though, I do wonder if the device is up to the best practices for the SOC, because the component count feel quite low vs the WR703N. One of the big components missing is the H1601CG ethernet transformer. Maybe they do the job using discrete passives, but the passive count is pretty low as well. This is a field where my knowhow is sorely lacking, so I really have no idea - take this with a metric grain of salt - I've had no issues with the device thus far.&lt;/p&gt;
</description>
<link>
http://blog.eikeland.se/2014/07/22/gl-inet-openwrt/
</link>
<pubDate>
Tue, 22 Jul 2014 09:00:00 +0200
</pubDate>
<guid isPermaLink='false'>
/2014/07/22/gl-inet-openwrt/
</guid>
</item>
<item>
<title>
Banana Phones, Clojure and the Expression Problem
</title>
<description>
&lt;p&gt;Clojure is a Functional First language, and I usually get by simply by passing around native datastructures such as maps, lists and vectors. Other than doing some simple Java interop I haven't really dug deep into the Object-Oriented features of Clojure until now. But, just because a language is FF doesn't mean that it's OO is weak sauce.&lt;/p&gt;&lt;h2&gt;The Banana&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;ns &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;oop.fruits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defprotocol &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Fruit&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;peel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;describe-fruit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defrecord &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Banana&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;degree&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;peeled?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;Fruit&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;peel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Banana.&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;degree&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;describe-fruit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;A &quot;&lt;/span&gt;
         &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;peeled?&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;peeled&quot;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;unpeeled&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;s&quot;&gt;&quot; banana with a &quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;degree&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; degrees bend&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;get-a-nice-banana&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Banana.&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Imagine that we have a namespace called &lt;code&gt;fruits&lt;/code&gt;, in this ns we have a Protocol defined - called &lt;code&gt;Fruit&lt;/code&gt; - anything that satisfied being a fruit needs two methods - a function to peel the fruit, and a function to describe the fruit. You can think of Protocols as being something pretty close to &quot;interfaces&quot; in OO languages such as Java and C#. (This whole setup works pretty much as traits).&lt;/p&gt;&lt;p&gt;We also describe a record, a &lt;code&gt;Banana&lt;/code&gt;. Think of this as a class, the banana accepts two values - a degree saying how bent the banana is, and a bool saying if it's peeled or not.&lt;/p&gt;&lt;p&gt;Records are often method-less, this one however has two methods &lt;code&gt;peel&lt;/code&gt; and &lt;code&gt;describe-fruit&lt;/code&gt;, this makes the &lt;code&gt;Banana&lt;/code&gt; satisfy the requirements for being a &lt;code&gt;Fruit&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;We also define a public &lt;code&gt;get-a-nice-banana&lt;/code&gt; function that returns an instance of Banana - a unpeeled 30 degree bend banana - since bananas with 30 degree bends are the best - as we all know.&lt;/p&gt;&lt;h2&gt;The Apple iPhone&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;ns &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;oop.phone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defprotocol &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;Phone&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;this&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defrecord &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;iPhone&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;Phone&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;this&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Calling &quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; using apple phone model &quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;..&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;call-using&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;phone&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;phone&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;get-a-nice-phone&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;iPhone.&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;5s&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Next, let's define a new namespace. This time we create a Phone protocol, phones should be able to &lt;code&gt;call&lt;/code&gt; numbers.&lt;/p&gt;&lt;p&gt;Then we create an iPhone, which fulfills the requirements of being a phone since it can actually call people (not just toot and instaface and..).&lt;/p&gt;&lt;p&gt;We create two functions, &lt;code&gt;call-using&lt;/code&gt; which allows you to call a number using a given phone. And a convenience function for getting a nice shiny new iPhone 5s.&lt;/p&gt;&lt;p&gt;We now have a couple of things defined.. We have Phones and Fruits, iPhones and Bananas. They have absolutely nothing to do with each other, and are isolated in their own namespaces.&lt;/p&gt;&lt;h2&gt;Apples and Bananas - to the core&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;ns &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;oop.core&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:require&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;oop.fruits&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;fruit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;oop.phone&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;phone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;oop.fruits&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;Banana&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Let's start a new namespace, &lt;code&gt;oop.core&lt;/code&gt;, this namespace imports the two other namespaces we've defined.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;iphone&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;phone/get-a-nice-phone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;phone/call-using&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iphone&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;80020123&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; &quot;Calling 80020123 using apple phone model 5s..&quot;&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iphone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; oop.phone.iPhone&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;satisfies?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;phone/Phone&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iphone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; true&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can use the convenience function from phone to get a shiny iPhone, we see that we can give this phone to &lt;code&gt;call-using&lt;/code&gt; which then can use it to call someone. No surprises here, as the iphone satisfies the Phone protocol.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;banana-phone&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fruit/get-a-nice-banana&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;banana-phone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; oop.fruits.Banana&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;satisfies?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;fruit/Fruit&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;banana-phone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; true&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fruit/describe-fruit&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;banana-phone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; &quot;A unpeeled banana with a 30 degrees bend&quot;&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fruit/describe-fruit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fruit/peel&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;banana-phone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; &quot;A peeled banana with a 30 degrees bend&quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Let's try to create a banana, it's a nice banana of the type &lt;code&gt;oop.fruits.Banana&lt;/code&gt;, it satisfies the &lt;code&gt;Fruit&lt;/code&gt; protocol from the &lt;code&gt;oop.fruits&lt;/code&gt; namespace. We can call describe-fruit on it, and we can peel it. No surprises here either.&lt;/p&gt;&lt;p&gt;Now, what if we could actually take our banana and call someone? Wouldn't that be wonderful? But alas..&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;phone/call-using&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;banana-phone&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;80020123&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; Booom exception.. no implementation of oop.phone/Phone for class oop.fruits.Banana&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;satisfies?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;phone/Phone&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;banana-phone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; false&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The banana blows up, spewing yellow goo all over our system - it turns out that a &lt;code&gt;Banana&lt;/code&gt; isn't actually a &lt;code&gt;Phone&lt;/code&gt;. That makes me a very sad panda :( I've always wanted a real banana phone.&lt;/p&gt;&lt;p&gt;&lt;figure&gt; &lt;a href=&quot;/images/sad-panda.jpg&quot;&gt;&lt;img src=&quot;http://blog.eikeland.se/images/sad-panda.jpg&quot; /&gt;&lt;/a&gt; &lt;/figure&gt;&lt;/p&gt;&lt;p&gt;In a regular OO language like Java or C#, I would probably attack this by encapsulating a banana instance in a new class, one that also satisfies the Phone interface.&lt;/p&gt;&lt;p&gt;But no worries, watch this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;extend-type&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;Banana&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;phone/Phone&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;this&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Calling &quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; using a &quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:degree&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; degrees bent banana.. WTF?&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Still in the oop.core namespace, we extend the &lt;code&gt;oop.fruits/Banana&lt;/code&gt; type to also satisfy the &lt;code&gt;oop.phone/Phone&lt;/code&gt; protocol.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fruit/get-a-nice-banana&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; oop.fruits.Banana&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Our banana is still just of type Banana.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;satisfies?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;phone/Phone&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fruit/get-a-nice-banana&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; true&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A &lt;code&gt;Banana&lt;/code&gt; is a &lt;code&gt;Phone&lt;/code&gt;, it actually satisfies the &lt;code&gt;Phone&lt;/code&gt; Protocol... and..&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;phone/call-using&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fruit/get-a-nice-banana&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;80020123&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; &quot;Calling 80020123 using a 30 degrees bent banana.. WTF?&quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Holy cow! We can now not only call using the Apple iPhone 5s, but also using the 30 degrees bent Banana! And that's using a fresh banana we just got from the &lt;code&gt;oop.fruits&lt;/code&gt; namespace - we didn't monkey patch it or modify it. We didn't change the &lt;code&gt;oop.fruits&lt;/code&gt; namespace or the &lt;code&gt;oop.phone&lt;/code&gt; namespace, we just passed it along to &lt;code&gt;oop.phone&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Mind blow, that's a really elegant solution to the &lt;a href=&quot;http://en.wikipedia.org/wiki/Expression_problem&quot;&gt;expression problem&lt;/a&gt; if you ask me..&lt;/p&gt;&lt;p&gt;&lt;figure&gt; &lt;iframe allowfullscreen=&quot;allowfullscreen&quot; frameborder=&quot;0&quot; src=&quot;//www.youtube.com/embed/j5C6X9vOEkU&quot; height=&quot;470&quot; width=&quot;620&quot;&gt; &lt;/iframe&gt; &lt;/figure&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Ring ring ring ring ring ring ring bananaphone.&lt;/p&gt;&lt;p&gt;Ping pong ping pong ping pong ping pananaphone.&lt;/p&gt;
&lt;/blockquote&gt;&lt;h2&gt;Bonus feature&lt;/h2&gt;&lt;p&gt;As a bonus, here's another pretty nice feature called &lt;code&gt;reify&lt;/code&gt;. Reification means to make something real, bring it into being or make something concrete.&lt;/p&gt;&lt;p&gt;In clojure using &lt;code&gt;reify&lt;/code&gt; you can actually implement an interface (protocol) anonymously. Observe:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;anon-phone&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;reify&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;phone/Phone&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;this&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Calling &quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; anonymously..&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;phone/call-using&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;anon-phone&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;80020123&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; &quot;Calling 80020123 anonymously..&quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;An anonymous implementation of the &lt;code&gt;Phone&lt;/code&gt; protocol. Try doing that in C# (Håvard tells me you can do it in F#). I thought this wasn't possible in Java, but apparently my limited J-knowledge had me fooled (Thanks Magnus) - so this bonus feature isn't as impressive as I thought :) (reify can do multiple interfaces in one go though, but I guess that's not something I'll use very often)&lt;/p&gt;
</description>
<link>
http://blog.eikeland.se/2014/07/13/clojure-banana-phone/
</link>
<pubDate>
Sun, 13 Jul 2014 09:00:00 +0200
</pubDate>
<guid isPermaLink='false'>
/2014/07/13/clojure-banana-phone/
</guid>
</item>
<item>
<title>
CSP-style concurrent prime sieve using core.async
</title>
<description>
&lt;p&gt;The Sieve of Eratosthenes is a well known old algorithm for finding prime numbers up to a given limit. If you don't know how it works, the short version is that you basically write up every number starting with 2 up to the limit. You then remove all multiples of 2, and the next number in the list (3) is prime. Remove all multiples of 3.. next number (5) is prime.. and so on.&lt;/p&gt;&lt;p&gt;&lt;figure&gt; &lt;a href=&quot;/images/2014-06-30-prime-sieve/sieve-anim.gif&quot;&gt;&lt;img src=&quot;http://blog.eikeland.se/images/2014-06-30-prime-sieve/sieve-anim.gif&quot; /&gt;&lt;/a&gt; &lt;figcaption&gt;Sieve of Eratosthenes (wikipedia).&lt;/figcaption&gt; &lt;/figure&gt;&lt;/p&gt;&lt;p&gt;Now imagine modeling the sieve using Communicating Sequential Processes (CSP). Start by creating a seed process, all it does it outputing all the numbers from 2 to n.&lt;/p&gt;&lt;p&gt;For every number x received, create a filtering process - a process which only job is to remove all multiples of x and pass all other values along. Daisy-chain these filtering process for every number you receive, each represents a prime number.&lt;/p&gt;&lt;p&gt;&lt;figure&gt; &lt;a href=&quot;/images/2014-06-30-prime-sieve/cspsieve.png&quot;&gt;&lt;img src=&quot;http://blog.eikeland.se/images/2014-06-30-prime-sieve/cspsieve.png&quot; /&gt;&lt;/a&gt; &lt;figcaption&gt;There's a typo above, filter / 2 should drop a 4, not 2.. sorry..&lt;/figcaption&gt; &lt;/figure&gt;&lt;/p&gt;&lt;p&gt;We can model this in clojure (and in go-lang) using go-blocks from core.async.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;ns &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;primesieve.core&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:require&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;clojure.core.async&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:refer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;go-loop&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;&amp;gt;!&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;&amp;lt;!&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;&amp;lt;!!&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;close!&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;filter&amp;lt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;to-chan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Start by setting up the namespace, we're going to need a few things from core.async.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;gen&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;upper-limit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to-chan&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;range &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;upper-limit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now create the generating seed process. &lt;code&gt;to-chan&lt;/code&gt; is sugar for creating a channel, return the channel and then continue add all items from a collection to the channel. In this case the collection is a lazy sequence of numbers between 2 and &lt;code&gt;upper-limit&lt;/code&gt;. It's all run in a microthread (go-block).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;sieve-filter&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;prime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;filter&amp;lt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pos? &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;rem &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;prime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Next we create a filtering process, &lt;code&gt;filter&amp;lt;&lt;/code&gt; is sugar for creating a channel, reading from a incoming channel, and outputing all values that pass a predicate test to the output channel. It's also launched in a go-block.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;sieve-builder&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;chan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;go-loop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;if-let &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;prime&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;&amp;lt;!&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;do &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;&amp;gt;!&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;prime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;recur&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sieve-filter&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;prime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;close!&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Next we create the function that will daisy-chain filtering blocks, there are no sugar for this, so manually launch a go-block, read a prime number from the input channel, pass this prime along to an output channel, and daisy-chain a new filtering process.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;collect&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;&amp;lt;!!&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;async/into&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To collect all the results, we can use &lt;code&gt;into&lt;/code&gt;, which will collect all received values and add them to the datastructure of your choice, a vector in this case.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;primes&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;upper-limit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;-&amp;gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gen&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;upper-limit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sieve-builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;collect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Create a function for generating primes below &lt;code&gt;upper-limit&lt;/code&gt;, it will spin up the generator, connect the generator to the sieve-builder, and connect the sieve-builder to the final result collector.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;user&amp;gt; (primes 20)
[2 3 5 7 11 13 17 19]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And it works! But.. is it fast? and what level of concurrency is achieved?&lt;/p&gt;&lt;p&gt;&lt;figure&gt; &lt;a href=&quot;/images/2014-06-30-prime-sieve/sieve1.png&quot;&gt;&lt;img src=&quot;http://blog.eikeland.se/images/2014-06-30-prime-sieve/sieve1.png&quot; /&gt;&lt;/a&gt; &lt;/figure&gt;&lt;/p&gt;&lt;p&gt;Not at all.. it's actually painfully slow, about 30 seconds to find all the primes below 100000. I aborted the run, since I didn't want to wait 5 minutes to complete 10 runs. It isn't really managing to use all cores (HT) properly, in addition to spending most of it's time context switching between the micro-threads. Go-threads are light weight, but there is still some context needed, and each process is doing so little work before blocking - waiting for the next value to be received.&lt;/p&gt;&lt;p&gt;If the processes could do more work before getting blocked and context-switched, maybe it would be faster. Let's try adding a 512 value buffer between them.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;clojure&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;bufsize&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;512&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;sieve-filter&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;prime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;filter&amp;lt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pos? &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;rem &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;prime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bufsize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;defn &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;sieve-builder&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bufsize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;.......&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;figure&gt; &lt;a href=&quot;/images/2014-06-30-prime-sieve/sieve2.png&quot;&gt;&lt;img src=&quot;http://blog.eikeland.se/images/2014-06-30-prime-sieve/sieve2.png&quot; /&gt;&lt;/a&gt; &lt;/figure&gt;&lt;/p&gt;&lt;p&gt;Now, that's better, from 30 seconds to 4 seconds to calculate primes below 100000. Now we get full CPU utilization as well.&lt;/p&gt;&lt;p&gt;But, is it any good? No, not at all! It's actually still pretty terrible, there are so many better and faster ways of doing this. The problem here is that we have a massive overhead because of communication, we're barely doing any computation before shuffling values along to the next guy.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;Also note that async channels are not intended for fine-grained computational parallelism, though you might see examples in that vein.&quot;&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;This is just a fun example, and core.async isn't really intended for this, as quoted above by the original &lt;a href=&quot;http://clojure.com/blog/2013/06/28/clojure-core-async-channels.html&quot;&gt;announcement post&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Top picture is taken by &lt;a href=&quot;https://www.flickr.com/photos/ryanprince1974/6959568500&quot;&gt;Ryan Prince&lt;/a&gt; (cc by-nc-sa 2.0)&lt;/li&gt;
&lt;/ul&gt;
</description>
<link>
http://blog.eikeland.se/2014/06/30/csp-prime-sieve/
</link>
<pubDate>
Mon, 30 Jun 2014 09:00:00 +0200
</pubDate>
<guid isPermaLink='false'>
/2014/06/30/csp-prime-sieve/
</guid>
</item>
</channel>
</rss>
