Jekyll2023-04-23T19:25:36+00:00https://www.jacklew.is/feed.xmlJack LewisBlogBooting Home Assistant OS on TrueNAS/bhyve2021-10-30T00:00:00+00:002021-10-30T00:00:00+00:00https://www.jacklew.is/homeassistant-truenas-bhyve<p>I love using Home Assistant to control all of my smart home devices and create
cool automations. But I’ve found that running it on Raspberry Pis or even the
<a href="https://www.home-assistant.io/blue/">Home Assistant Blue</a> to be somewhat unreliable.
In the case of Raspberry Pis, they boot from SD cards which are notoriously unreliable.
In the case of the Home Assistant Blue, it boots from an internal eMMC card,
which is better but still not perfect. I also had hardware issues with the ODroid
N2+ in the Home Assistant Blue, my USB ports died which rendered it useless to me
since many of my smart home devices are Z-Wave, which requires a Z-Wave USB stick
to act as the base station.</p>
<p>Instead, I wanted to run Home Assistant OS (the fully managed Linux distro
built by Home Assistant) on my NAS, which is an old Dell R510 server with dual
socket Xeons, 24gb of RAM, and 8 hot swap hard drive bays. I currently run TrueNAS,
which only supports the bhyve hypervisor. However, the Home Assistant OS team only
provide VirtualBox, QEMU and VMWare images. However, it is fairly easy to convert
the QEMU <code class="language-plaintext highlighter-rouge">.qcow2</code> to a raw image file, and boot it under bhyve.</p>
<h1 id="step-1-create-a-zvol-for-the-vm-disk">Step 1: Create a Zvol for the VM disk</h1>
<p>Under Storage/Pools, expand the ZFS pool you want to create the Zvol under.
Click the 3 dot options menu, and select add <code class="language-plaintext highlighter-rouge">Add ZVol</code>. Add a name and set the size
to 40gb.</p>
<h1 id="step-2-optional">Step 2 (optional):</h1>
<p>If you need USB support in the VM for Z-Wave or Zigbee, you’ll need to pass through
a PCIe USB interface. Depending on your hardware, you may need to add a USB card.
I used <a href="https://www.amazon.com/dp/B072LS4JH7">this card</a> and it works well.</p>
<p>You will need to set a few FreeBSD tunables in order for the USB interface to be
able to be passed through to the VM.
<a href="https://wiki.freebsd.org/bhyve/pci_passthru">Follow these steps</a>.
After setting those tunables, you’ll need to reboot TrueNAS.</p>
<h1 id="step-3-create-and-configure-the-vm">Step 3: Create and configure the VM</h1>
<p>In the <code class="language-plaintext highlighter-rouge">Virtual Machines</code> page, click the <code class="language-plaintext highlighter-rouge">Add</code> button to add a VM. Choose Linux
as the guest OS, enter a name, cloose system clock as UTC, and click <code class="language-plaintext highlighter-rouge">Next</code>.
Add CPU and memory resources as needed, and click <code class="language-plaintext highlighter-rouge">Next</code>. Choose <code class="language-plaintext highlighter-rouge">Use existing disk image</code>,
and select the Zvol created in step 1. No other settings need to be changed, so
continue pressing <code class="language-plaintext highlighter-rouge">Next</code> until the VM is created.</p>
<p>Next, go back to the Virtal Machine page and expand the info for the VM. Select
Devices, then Add, select type PCI Passthru Device, select the PCI Passthru device
and save.</p>
<h1 id="step-4-download-the-home-assistant-os-image-and-convert-it-to-raw">Step 4: Download the Home Assistant OS image and convert it to raw</h1>
<p>Download the <a href="https://www.home-assistant.io/installation/linux">KVM image</a> from
Home Assistant. Extract the image (for this step you’ll need Linux):</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ unxz haos_ova-X.X.qcow2.xz
</code></pre></div></div>
<p>Next, convert the image to a raw disk image:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo apt install qemu-utils
$ qemu-img convert haos_ova-X.X.qcow2 haos.raw
</code></pre></div></div>
<p>Next, you’ll need to move the image to your TrueNAS server:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ scp haos.raw user@truenas.local:</path/to/haos.raw>
</code></pre></div></div>
<p>Now you’ll need to write the image over top of the Zvol created in step 1.</p>
<p>SSH into TrueNAS (or use the shell from the UI), and run the following as root.
Replace the necessary paths, and be careful since we’re using
<a href="https://www.freebsd.org/cgi/man.cgi?dd(1)">dd(1)</a>
which is a fairly dangerous command. You can very easily destroy your data, and you
should be backing up your data regularly both onsite and offsite.</p>
<p>When running anything dangerous like dd, it’s a good idea to type a <code class="language-plaintext highlighter-rouge">#</code> first, and
then type out your command. Once you’ve quadruple checked the paths and syntax,
use the arrow keys to go back and remove the <code class="language-plaintext highlighter-rouge">#</code>.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># dd if=</path/to/haos.raw> of=</dev/zvol/your-pool-name/your-zvol-name>
</code></pre></div></div>
<h1 id="step-5-start-the-vm">Step 5: Start the VM</h1>
<p>At this point the VM should be ready to start, and you should be done! If you didn’t
already, you probably want to set the VM to start on boot.</p>I love using Home Assistant to control all of my smart home devices and create cool automations. But I’ve found that running it on Raspberry Pis or even the Home Assistant Blue to be somewhat unreliable. In the case of Raspberry Pis, they boot from SD cards which are notoriously unreliable. In the case of the Home Assistant Blue, it boots from an internal eMMC card, which is better but still not perfect. I also had hardware issues with the ODroid N2+ in the Home Assistant Blue, my USB ports died which rendered it useless to me since many of my smart home devices are Z-Wave, which requires a Z-Wave USB stick to act as the base station.Using Tail Call Optimization in Node.js2017-07-10T00:00:00+00:002017-07-10T00:00:00+00:00https://www.jacklew.is/nodejs-tco<p>Everyone who has used recursion has probably seen something like the following:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>RangeError: Maximum call stack size exceeded
at recursive (/Users/jack/recursive.js:1:1)
at recursive (/Users/jack/recursive.js:1:1)
at recursive (/Users/jack/recursive.js:1:1)
...
</code></pre></div></div>
<p>There is a language feature that can prevent this, tail call optimization. The compiler can transform self-recursive functions into loops so that only a single stack frame is needed, regardless of the number of times a function calls itself.</p>
<p>Node.js (as of July 2017) offers a work-in-progress implementation of tail call optimization behind a feature flag, <code class="language-plaintext highlighter-rouge">--harmony_tailcalls</code>.</p>
<p>Running the following program without <code class="language-plaintext highlighter-rouge">--harmony_tailcalls</code>, we can see each recursive call will slowly fill the function call stack:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="dl">'</span><span class="s1">use strict</span><span class="dl">'</span><span class="p">;</span> <span class="c1">// --harmony_tailcalls will not work without strict mode</span>
<span class="kd">function</span> <span class="nx">countdown</span> <span class="p">(</span><span class="nx">x</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">trace</span><span class="p">(</span><span class="nx">x</span><span class="p">);</span> <span class="c1">// Print a stack trace for each countdown() call</span>
<span class="k">return</span> <span class="nx">x</span> <span class="o">!==</span> <span class="mi">0</span> <span class="p">?</span> <span class="nx">countdown</span><span class="p">(</span><span class="nx">x</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="p">:</span> <span class="kc">null</span><span class="p">;</span>
<span class="p">}</span>
<span class="nx">countdown</span><span class="p">(</span><span class="mi">10</span><span class="p">);</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ node countdown.js
Trace: 10
at countdown (/Users/jack/countdown.js:4:11)
at Object.<anonymous> (/Users/jack/countdown.js:8:1)
at Module._compile (module.js:571:32)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)
at Function.Module._load (module.js:439:3)
at Module.runMain (module.js:605:10)
at run (bootstrap_node.js:425:7)
at startup (bootstrap_node.js:146:9)
Trace: 9
at countdown (/Users/jack/countdown.js:4:11)
at countdown (/Users/jack/countdown.js:5:20)
at Object.<anonymous> (/Users/jack/countdown.js:8:1)
at Module._compile (module.js:571:32)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)
at Function.Module._load (module.js:439:3)
at Module.runMain (module.js:605:10)
at run (bootstrap_node.js:425:7)
...
Trace: 0
at countdown (/Users/jack/countdown.js:4:11)
at countdown (/Users/jack/countdown.js:5:20)
at countdown (/Users/jack/countdown.js:5:20)
at countdown (/Users/jack/countdown.js:5:20)
at countdown (/Users/jack/countdown.js:5:20)
at countdown (/Users/jack/countdown.js:5:20)
at countdown (/Users/jack/countdown.js:5:20)
at countdown (/Users/jack/countdown.js:5:20)
at countdown (/Users/jack/countdown.js:5:20)
at countdown (/Users/jack/countdown.js:5:20)
</code></pre></div></div>
<p>When running with the tail call feature flag, we see that only a single stack frame is generated:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ node --harmony_tailcalls countdown.js
Trace: 10
at countdown (/Users/jack/countdown.js:4:11)
at Object.<anonymous> (/Users/jack/countdown.js:8:1)
at Module._compile (module.js:571:32)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)
at Function.Module._load (module.js:439:3)
at Module.runMain (module.js:605:10)
at run (bootstrap_node.js:425:7)
at startup (bootstrap_node.js:146:9)
Trace: 9
at countdown (/Users/jack/countdown.js:4:11)
at Object.<anonymous> (/Users/jack/countdown.js:8:1)
at Module._compile (module.js:571:32)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)
at Function.Module._load (module.js:439:3)
at Module.runMain (module.js:605:10)
at run (bootstrap_node.js:425:7)
at startup (bootstrap_node.js:146:9)
...
Trace: 0
at countdown (/Users/jack/countdown.js:4:11)
at Object.<anonymous> (/Users/jack/countdown.js:8:1)
at Module._compile (module.js:571:32)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)
at Function.Module._load (module.js:439:3)
at Module.runMain (module.js:605:10)
at run (bootstrap_node.js:425:7)
at startup (bootstrap_node.js:146:9)
</code></pre></div></div>Everyone who has used recursion has probably seen something like the following:How I built a keyboard by hand2016-10-08T00:00:00+00:002016-10-08T00:00:00+00:00https://www.jacklew.is/keyboard<p><img src="https://farm9.staticflickr.com/8746/30166008906_e0ac5eb5b2_k_d.jpg" alt="The finished product" /></p>
<p>I had spare mechanical keyboard switches and keycaps from other keyboard projects, and I wanted to see if it would be feasible to build a keyboard using only hand tools.</p>
<p><img src="https://farm6.staticflickr.com/5195/30085878312_5dce857134_k_d.jpg" alt="Testing the layout" /></p>
<p>I started with some aluminum sheet stock from the hardware store. It was perfectly sized to build a 5 column, 13 row grid keyboard, without any wasted space.</p>
<p><img src="https://farm6.staticflickr.com/5146/30115575711_dcf028bc00_k_d.jpg" alt="Scribed aluminum sheet" /></p>
<p>I started by laying out where the switch holes would be cut. The holes are 14 mm squares, with 5.5 mm in between. I used a blade to scribe the layout into the metal.</p>
<p><img src="https://farm6.staticflickr.com/5260/30166053386_b6716ac935_k_d.jpg" alt="Test fitting a switch" /></p>
<p>I drilled a hole for each switch, and filed them square.</p>
<p><img src="https://farm6.staticflickr.com/5628/30115561731_eb20eaa807_k_d.jpg" alt="First two rows cut" /></p>
<p><img src="https://farm6.staticflickr.com/5468/30115558701_c8f07f5f15_k_d.jpg" alt="Test fitting first two rows" /></p>
<p><img src="https://farm6.staticflickr.com/5008/30115556111_e159eb5fb8_k_d.jpg" alt="Completed keyboard plate" /></p>
<p>Once the top plate was done, I used another piece of the same aluminum stock for the bottom of the keyboard, with metal standoffs to complete the case.</p>
<p><img src="https://farm6.staticflickr.com/5130/30166046486_9d0175777c_k_d.jpg" alt="Keyboard case assembly" /></p>
<p><img src="https://farm6.staticflickr.com/5594/29904585790_9586465493_k_d.jpg" alt="Test fitting all switches" /></p>
<p>I painted the case black. This helps hide the misaligned keys, and makes it look more uniform.</p>
<p><img src="https://farm6.staticflickr.com/5215/29571182703_ea05a1cfed_k_d.jpg" alt="Painted case" /></p>
<p><img src="https://farm6.staticflickr.com/5128/30200419565_21edb9f4d7_k_d.jpg" alt="Test fitting switches and keycaps after painting" /></p>
<p>I used 1N4148 diodes to connect the rows together, and wired the columns together. I referred to the <a href="https://atreus.technomancy.us/assembly-hand-wired.pdf">Atreus keyboard hand-wiring guide</a> to help with the wiring.</p>
<p><img src="https://farm8.staticflickr.com/7484/29571168153_4c94df32ef_k_d.jpg" alt="Column and row wiring" /></p>
<p>Each of the columns and rows are connected to a Teensy microcontroller. I had to take care to avoid the standoffs when wiring the keyboard.</p>
<p><img src="https://farm6.staticflickr.com/5557/29571161073_047f4003c0_k_d.jpg" alt="Complete wiring" /></p>
<p>I used a micro USB extension cable to complete the keyboard, and glued the end of it to the bottom of the case.</p>
<p><img src="https://farm6.staticflickr.com/5553/29904544790_6f279a5252_k_d.jpg" alt="USB extender glued to case" /></p>
<p><img src="https://farm9.staticflickr.com/8624/29904541790_be33c79916_k_d.jpg" alt="Top view of keyboard" /></p>
<p>To program the keyboard, I used the open source <a href="https://github.com/jackhumbert/qmk_firmware">QMK firmware</a>. I started with the <a href="https://atreus.technomancy.us">Atreus keyboard</a> configuration, and edited the configuration header file to match the wiring of the rows and columns. I then edited the keymap header for the keyboard layout. The QMK firmware provides macros for function layers, and will automatically produce a standard shift layer.</p>
<p>Then, (after installing some build tools), I compiled the firmware and flashed it to the Teensy using the Teensy loader tool provided by PJRC.</p>Arduino Temperature Sensor2015-02-13T00:00:00+00:002015-02-13T00:00:00+00:00https://www.jacklew.is/arduino-temp-sensor<p><img src="https://farm9.staticflickr.com/8638/16554037441_e3580ac3c7_z_d.jpg" alt="Project board built" /></p>
<p>I previously worked on an enclosure for the Computer Club server rack, and I thought it would be a good idea to put together a standalone temperature sensor system. Preferably it would interface over the internet so that IRC bots and other programs could talk to it.</p>
<p><img src="https://farm9.staticflickr.com/8612/16524942312_81b622a8aa_z_d.jpg" alt="Server rack cabinet" /></p>
<p>Here is the project, using an Arduino Uno for testing.</p>
<p><img src="https://farm8.staticflickr.com/7339/16525954455_dae4872608_z_d.jpg" alt="The project using an Arduino Uno" /></p>
<p>The project will use four DHT-11 temperature sensors, an ATMega 328 with an Arduino bootloader (for ease of programming), and an ENC28J60 ethernet module.</p>
<p>The microcontroller will take a temperature reading every few seconds, and when a connection comes in on its port 80, it will send back HTTP headers, <code class="language-plaintext highlighter-rouge">text/json</code>, and JSON data for easy parsing, in the following format:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{
"sensor one": {
"humidity": "34",
"celcius": "25",
"fahrenheit": "77"
},
...
"sensor four": {
"humidity": "34",
"celcius": "24",
"fahrenheit": "75"
}
}
</code></pre></div></div>
<p>The sensors are not all that accurate, so I cast the floating point values generated by the Adafruit DHT library to integers for reporting.</p>
<p><img src="https://farm8.staticflickr.com/7399/16338473020_17f4c32a53_z_d.jpg" alt="The project, fully breadboarded" /></p>
<p>Here is the project built out on the breadboard.</p>
<p>The code, along with necessary libraries for this project is <a href="https://github.com/rhinoceraptor/arduino-server-sensor">available here</a>.</p>
<h3 id="building-the-project">Building the project</h3>
<p><img src="https://farm8.staticflickr.com/7435/15935531923_c2ed41a00a_z_d.jpg" alt="Underside of the board" /></p>
<p><img src="https://farm8.staticflickr.com/7410/16529706886_7436424da5_z_d.jpg" alt="Project in box" /></p>
<p>Since this project will live in a server rack, it needs to be put in a project box. The DHT11 and ENC28J60 module both need 3.3 volts, and the ATMega will run on 3.3 volts, so I used an LM317 voltage regulator to knock down 5 volts from a USB phone charger to 3.3 volts.</p>
<p>Running an ATMega 328 by itself is pretty simple, it needs a 16 Mhz clock connected between pin 9 and 10, and both of those connected to ground through a 10 uF capacitor. The, connect VCC, AVCC and AREF to 3.3 volts, and use a 10K ohm resistor to pull up RST.</p>
<p>Then, connect both GND pins to ground, and hook up a normally open switch to RST to ground.</p>
<p>For the DHT11 modules, each of them needs to be connected to 3.3 volts and ground, and each of their sensor output pins is pulled up to 3.3 volts with a 10K ohm resistor.</p>
<p><img src="https://farm9.staticflickr.com/8628/16368048798_f96d413423_z_d.jpg" alt="ENC28J60 headers" /></p>
<p>Finally, the ENC28J60 needs to be connected to 3.3 volts and ground, and its SPI bus connected to the pins as programmed on the microcontroller. I used female headers on the perfboard so that the module fits to the board, unmodified.</p>
<p><img src="https://farm9.staticflickr.com/8641/16555724555_a1649e63f6_z_d.jpg" alt="Board mounted in project box" /></p>
<p><img src="https://farm9.staticflickr.com/8654/16368047228_286b7fa863_z_d.jpg" alt="Stereo jacks used to connect DHT11s" /></p>
<p>I used 3.5mm stereo audio jacks to connect the DHT11 modules. They each only need three pins to connect, so this is a convenient and cheap way to do it. Then, each DHT11 is wired to a length of stranded phone wire, terminated with a 3.5mm stereo plug.</p>
<p><img src="https://farm8.staticflickr.com/7393/16554609972_d4335be86f_z_d.jpg" alt="Power connector" /></p>
<p>I used a spare DC barrel jack, wired to a USB cable. On the perfboard I used female headers and solid core wire to connect everything so that it is easy to take apart.</p>3D Printed Servo Deadbolt Opener2015-01-30T00:00:00+00:002015-01-30T00:00:00+00:00https://www.jacklew.is/deadbolt-opener<p><img src="https://farm8.staticflickr.com/7419/16220687689_758c59722b_z_d.jpg" alt="Finished Project" /></p>
<p>I wanted to design a part that would allow a common hobby servo to unlock a deadbolt. You could then use RFID or some other means of authentication to open a door.</p>
<p>I used the larger size available at Radio Shack.</p>
<p><img src="https://farm9.staticflickr.com/8593/15784047683_03cc051e13_z_d.jpg" alt="Common Hobby Servo" /></p>
<p>To start, I designed this mount in OpenSCAD, to be bolted or double side taped to a door, over the deadbolt:</p>
<p><img src="https://farm8.staticflickr.com/7334/16221026167_8ef630b0b6_z_d.jpg" alt="Servo mount" /></p>
<p>Then I needed a cup to fit over the deadbolt handle. I designed the included screw to fit to secure the arm on the servo, but I ended up not using it.</p>
<p><img src="https://farm9.staticflickr.com/8663/16380957196_cdd2093e7d_z_d.jpg" alt="Deadbolt Cup" /></p>
<p>On the other side, I used OpenSCAD code from Charles Rincheval for the servo spindle teeth, the code of which is available at <a href="https://github.com/hugokernel/OpenSCAD_ServoArms">https://github.com/hugokernel/OpenSCAD_ServoArms</a>. Despite each tooth on the servo being only 0.5 mm in length, the Prusa i3 printer I used was able to print the spindle teeth to be more than strong enough for this purpose. The torque that you can get from them is more than the servo can generate itself.</p>
<p><img src="https://farm8.staticflickr.com/7284/16406012172_bdbc72a7a8_z_d.jpg" alt="Servo Teeth" /></p>
<p>Here is a test fit of the cup I made. It took two tries but it fits snugly.</p>
<p><img src="https://farm8.staticflickr.com/7297/16219276838_5d179f1b31_z_d.jpg" alt="Printed deadbolt cup" /></p>
<p>Here is the servo mounted to the base, the inset screw heads fit great.</p>
<p><img src="https://farm8.staticflickr.com/7300/16220689909_16ea6b4149_z_d.jpg" alt="Servo mount printed" /></p>
<p><img src="https://farm8.staticflickr.com/7420/15784047953_9af0521620_z_d.jpg" alt="Inset screws" /></p>
<p>Here is the device, assembled and mounted, in the open position.</p>
<p><img src="https://farm8.staticflickr.com/7419/16220687689_758c59722b_z_d.jpg" alt="Open position" /></p>
<p>Here it is, in the closed position.</p>
<p><img src="https://farm8.staticflickr.com/7297/16220687979_86d3ecf63a_z_d.jpg" alt="Closed position" /></p>
<p>The OpenSCAD files used in this project are available at <a href="https://github.com/rhinoceraptor/arduino-deadbolt-opener">https://github.com/rhinoceraptor/arduino-deadbolt-opener</a>.</p>Raspberry Pi Door Opener Redux2015-01-26T00:00:00+00:002015-01-26T00:00:00+00:00https://www.jacklew.is/raspberry-pi-redux<p><img src="https://farm8.staticflickr.com/7335/16198184960_53fbb76b60_b.jpg" alt="The new opener, installed" /></p>
<p><img src="https://farm8.staticflickr.com/7329/16359614766_eb8db7795e_o_d.jpg" alt="Outside view of the magnetic card reader" /></p>
<p>Here is an outside view of the door. All that is visible is the card reader.</p>
<p>The code I’ve written for this project is available <a href="https://github.com/rhinoceraptor/door">here</a>.</p>
<h3 id="new-room-new-door-opener">New Room, New Door Opener</h3>
<p>When the Computer Club moved rooms, I wanted to improve the software that I had written for the door opener. It also turned out that the existing door opener was not able to open the new door. The old handle was very easy to turn, but the new one was more rigid, so I had to build an opener that had more torque.</p>
<p><img src="https://farm9.staticflickr.com/8573/16198184980_4632b94c22_b.jpg" alt="Side View of the new opener" />
I accomplished this using a NEMA 17 stepper motor, and gears printed on the Computer Club’s RepRap 3D printer. The smaller gear is mounted using a captive nut to the stepper motor’s axle, and it turns the larger gear. String wraps around the shaft of the larger gear, between it and the body of the lid.</p>
<p><img src="https://farm8.staticflickr.com/7347/16384671762_d04ee75958_o_d.jpg" alt="Top view of the new opener" /></p>
<p><img src="https://farm8.staticflickr.com/7300/16359614906_230b6787ea_o_d.jpg" alt="Internal Wiring of the project" />
Here is the wiring for the project. I am using the <a href="http://www.schmalzhaus.com/EasyDriver/">Easy Driver</a> stepper motor driver from SparkFun. All you need to do is connect your stepper motor’s coils correctly, provide 12 volts, and then pulse the step and direction pins to control your stepper.</p>
<p>I am using a 5 volt relay, (triggered using an NPN transistor, connected to a GPIO pin and the Raspberry Pi’s 5 volt output) to turn off power to the Easy Driver board when the stepper is not in use. Stepper motors use a considerable amount of current while idle, and they can get pretty hot.</p>
<p><img src="https://farm8.staticflickr.com/7384/16383857131_df876e12d0_o_d.jpg" alt="Rear view of the project" />
The power supply has a standard Molex power connector. I used JB weld to secure the male side of a Molex cable to the project box. The 5 volt connection is wired to a micro USB cable, and the 12 volts is wired through the relay as I described.</p>
<p><img src="https://farm9.staticflickr.com/8673/16383857201_25c52c2472_o_d.jpg" alt="Limit switch project box" />
Since stepper motors have no context for what step the axle is in, I needed a way to know when the handle is actually open. I used a small limit switch in another project box for this purpose. When the handle is completely pulled, the limit switch is pressed, and the stepper motor will stop turning. This way, if the gearing is bumped, the stepper motor will continue to turn until the door is open.</p>
<p><img src="https://farm8.staticflickr.com/7447/15763141904_16c7478cd2_o_d.jpg" alt="Front view of the project" />
One of the mono jacks is used to connect the limit switch, and the other is used to connect to the magnetic contact switch that reads whether the door is open or not.</p>
<h3 id="basic-parts-list">Basic Parts List</h3>
<ul>
<li>medium size project box (from Radio Shack)</li>
<li>Raspberry Pi Model B</li>
<li><a href="http://www.amazon.com/Newest-Tracks-Magnetic-Stripe-Credit/dp/B00D3D3L8Y">USB Magnetic Card Reader</a></li>
<li><a href="http://www.amazon.com/SparkFun-SX09402-EasyDriver-Stepper-Driver/dp/B004G4XR60">Easy Driver from SparkFun</a></li>
<li><a href="http://www.amazon.com/CanaKit-Stepper-Motor-with-Cable/dp/B004G51AZ4/">NEMA 17 Stepper Motor</a>, prefer one with a machine flat on the axle.</li>
<li><a href="http://www.amazon.com/Coolerguys-100-240v-Molex-Power-Adapter/dp/B000MGG6SC">Molex Power Supply</a></li>
<li><a href="http://www.amazon.com/Ableware-Door-Knob-Extender-Package/dp/B000PGRKZW">Door Knob Extender</a> or a P clamp with an eye hook bolt</li>
<li><a href="http://www.amazon.com/Directed-Electronics-8601-Magnetic-Switch/dp/B0009SUF08">Magnetic Contact Switch</a></li>
<li>5 volt relay</li>
<li>NPN transistor (since the Raspberry Pi logic level is 3.3 volts)</li>
</ul>
<h3 id="new-software">New Software</h3>
<p>The existing Python scripts stored card track hashes in a CSV file, and used SSH to send the state of the door (open or closed) for our IRC bot. Registering new cards required SSHing to the Raspberry Pi and stopping the persistent Python script, running another Python script. These Python scripts also required root privileges, due to the GPIO being restricted on the Raspberry Pi.</p>
<p>The new system uses a Node.js server that runs on our IRC server. It provides a REST interface for the Raspberry Pi to authenticate users, and it uses a self generated SSL certificate authority to sign a client certificate, to validate the identity of the Raspberry Pi, and to protect the card track hashes in transit.</p>
<p>The card tracks, along with the state of the door (open or closed) is stored in a SQLite database. I used <a href="iddentao.github.io/squel/">squel</a> to generate the SQL strings, and <a href="https://www.npmjs.com/package/validator">validator</a> to escape and validate input.</p>
<p>The Node.js server also provides a web interface for viewing card swipe logs, registering users, and de-registering users. This is built using <a href="http://expressjs.com/">Express</a> with <a href="http://jade-lang.com/">Jade templating</a>. The login and session handling is done using <a href="http://passportjs.org/">Passport.js</a>, using its local strategy, and the SQLite database for storing the user password salts and hashes.</p>
<p><img src="https://farm9.staticflickr.com/8581/16088170224_c262c8c010_b_d.jpg" alt="Logging into the web ap" /></p>
<p>Here is what you see when you get to the web app.</p>
<p><img src="https://farm9.staticflickr.com/8594/16709434222_99d8295c30_b_d.jpg" alt="Logged in to the web app" /></p>
<p>Here is the default view in the web app. You see the door opening logs (which include all unsuccessful attempts). By default, a user sees the last week of logs, and they can opt to see more by entering the number of days in the box.</p>
<p>I used Jade’s templating engine to build the tables in the app, so when I render the view with Express, all I have to do is build an array with the data I need from the SQLite database, and then I can build the table in Jade:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>file: door-server/views/swipe-logs.jade
---------------------------------------
table.table.table-striped.table-bordered.table-hover
thead
tr
th User
th Card Swipe Timestamp
th Access Granted
for row in data
tr
th= row[0]
th= row[1]
if row[2] == "true"
th.success= row[2]
else
th.danger= row[2]
</code></pre></div></div>
<p>If the swipe was successful, then I apply the Bootstrap success class, and if not I apply the Bootstrap danger class to give the colors.</p>
<p>I couldn’t find a satisfactory way to use the stepper motor from Node.js. The <a href="https://www.npmjs.com/package/pi-gpio">pi-gpio</a> library works with Quick2Wire’s <a href="https://github.com/quick2wire/quick2wire-gpio-admin">gpio-admin</a> utility, and that is what is used for reading the door state. The disadvantage of the pi-gpio library is that opening the GPIO pins and writing to them require passing a callback for each action. By the time I opened all four needed pins, I was four callbacks deep.</p>
<p>I tried using the <a href="https://github.com/caolan/async">async</a> waterfall pattern, but once I got the stepper motor moving, it was very slow. I decided instead to write a small C program that only opens the door, and nothing else. Since it compiles to a binary, I can set a root setuid bit on it, and that way the Node.js program can run non-privileged.</p>
<p>I used the <a href="https://projects.drogon.net/raspberry-pi/wiringpi/download-and-install/">wiringPi library</a> for the C program. It gives you the same <code class="language-plaintext highlighter-rouge">digitalWrite()</code>, <code class="language-plaintext highlighter-rouge">digitalRead()</code>, and <code class="language-plaintext highlighter-rouge">delay()</code> functions you are used to if you’ve ever used the Arduino IDE.</p>Raspberry Pi Door Opener2014-08-17T00:00:00+00:002014-08-17T00:00:00+00:00https://www.jacklew.is/raspberry-pi-door-opener<h4 id="new-version-of-the-project">New version of the project</h4>
<p>I have done a new version of the project, you can read about it <a href="https://www.jacklew.is/raspberry-pi-redux/">here</a>.</p>
<h4 id="overview-of-the-project">Overview of the project</h4>
<p><img src="https://farm9.staticflickr.com/8666/16359613716_13cbf07f0c_o.jpg" alt="Completed Project" /></p>
<p>I wanted to build a door opener for my university computer club. Our office has doors that cannot be unlocked permanently, and giving out keys is problematic since it’s expensive, especially if we had to change the locks.</p>
<p>Therefore, it made sense to build an opener using a magnetic card reader. This makes it free to grant and revoke access at will.</p>
<h4 id="basic-parts-list">Basic Parts List</h4>
<ul>
<li><a href="http://www.amazon.com/RASPBERRY-MODEL-756-8308-Raspberry-Pi/dp/B009SQQF9C">Raspberry Pi Model B</a></li>
<li><a href="http://www.amazon.com/Newest-Tracks-Magnetic-Stripe-Credit/dp/B00D3D3L8Y">USB magstripe reader</a></li>
<li><a href="http://www.radioshack.com/product/index.jsp?productId=22472146">Radioshack Servo</a> (you can substitute a similar servo, it just needs to be 150 degrees or so. Most brands have identical form factors.)</li>
<li><a href="http://www.adafruit.com/products/167">Parallax servo wheel</a></li>
<li><a href="http://www.amazon.com/Ableware-Door-Knob-Extender-Package/dp/B000PGRKZW">Door knob extender</a> (Assuming you are building for a round knob. I built my own out of wood for this project. If you have a lever knob, you could substitute a hose clamp to tie string on the end of the lever)</li>
<li>Two DC jacks and plugs</li>
<li>Micro USB cable</li>
<li>Two 5 volt power supplies (for simplicity, the servo and the RPi get their own power. The RPi needs <strong>at least</strong> 700 mA. It’s better to be closer to a full one amp.)</li>
<li>A project box</li>
</ul>
<p><img src="https://farm9.staticflickr.com/8605/16359613746_e504b20770_o.jpg" alt="Internal Wiring" />
Here you can see everything wired up. The RPi is connected to the lid of the case using double sided case standoffs. This way I can remove the lid while the bottom is still attached to the door with foam tape.</p>
<h4 id="putting-the-parts-together">Putting the parts together</h4>
<p>One of the first things you’ll want to do is cut a groove in the servo wheel. I did it by using a hand drill as a makeshift lathe. You can use a small bolt to chuck it into the drill, and use a utility knife to carve away. This groove allows the string to ride on the wheel like a pulley.</p>
<p>Cutting the project box can be tricky. A dremel is useful, I then did all the fine cutting work using the utility knife to carve away plastic. You can see in the photo that mine has a fan, this isn’t strictly necessary.</p>
<p>As much as possible, I wanted to all the wiring to be removeable. You can see in the picture that the RPi micro USB is connected to a DC jack, as well as the servo/fan DC jack.</p>
<p>There are also two 1/8” mono audio jacks that are wired to magnetic sensors so the RPi can tell if the doors are closed. This data is used for an internal IRC bot for the computer club.</p>
<h4 id="powering-the-servo">Powering the servo.</h4>
<p>If you’ve using servos on a microcontroller project you can usually power them right from the dev board. Unless you have a great power supply (perhaps 1200 mA) you can’t get away with this on the Raspberry Pi.</p>
<p>Since this project uses seperate power supplies, the servo ground must be connected both to its power supply and to the RPi. The control is wired to a GPIO pin. Since the servo doesn’t need to precise, we can get away with the non-realtime OS on the RPi controlling it. If you need precision, you’ll want to have a microcontroller powering the servo that you can send commands to over serial.</p>
<h4 id="software">Software</h4>
<p>The software is all written in Python, using code written by <a href="https://github.com/jness/magtek_cardreader/blob/master/main.py">jness</a> on github to access the card reader. Most USB magnetic card readers act as a HID, but since this is a headless program, we can’t just read from stdin.</p>
<p>Controlling the servo is a pretty trivial addition to jness’s code. The authentication is done by storing a SHA 256 hex digest of the magnetic card’s input in a CSV file, along with the card owner’s name.</p>
<p>In the main program, we iterate through that file searching for that digest. If it’s found, we log the door opening event, and turn the servo. The build also includes red and green indicator LEDs for access denied and granted, respectively.</p>
<p>The software is not totally complete (or safe, it is written to require root), but feel free to clone it <a href="https://github.com/rhinoceraptor/RPiMagstripe">here</a>. I ran it on Arch Linux ARM.</p>New version of the project I have done a new version of the project, you can read about it here.