thinkl33t.co.ukhttps://thinkl33t.co.uk/2019-08-20T00:00:00+01:00Make all the thingsUSB-PD Miniware TS1002019-08-20T00:00:00+01:002019-08-20T00:00:00+01:00Bob Cloughtag:thinkl33t.co.uk,2019-08-20:/usb-pd-miniware-ts100<p>The Miniware TS-100 is a cute little portable soldering iron. It can be powered off any 2.1mm jack 12-24v power brick, and I've had one since 2016 as i can keep it in my bag and have the ability to solder wherever i am.</p>
<p>I used to power it off a dedicated 12v wall wart, then i found a neat little lenovo 'square' to 2.1mm adaptor plug on aliexpress so i could use the laptop power brick i was already carrying with me, but since upgrading my laptop and going full usb-c i've not really been carrying anything thats been able to power the iron.</p>
<p>Miniware have since released the TS-80, which is a USB-C version of the TS-100. Great! The only problem is its designed for phone chargers, and so speaks QC 3.0. Given my phone and laptop both use the 'standard' USB-PD protocol (the same one used by all laptops, ipad pros, chromebooks etc), so i'd still have to carry another power brick around with me!</p>
<p>That was, until i found the ZYPDS USB-C "Power Trigger" - this is a tiny board that takes USB-C in one side, and does the protocol negotiation to ask for 15V or 20V out the other side, perfect!</p>
<p>So. ZYPDS board + 2.1mm jack.</p>
<p>Remove the outside of the jack, and snip the 'shield' pin so that its about the same length as the center pin. The TS-100 (and pretty much everything else that uses a 2.1mm jack) is center-positive, so solder the center pin to the + pad on the ZYPDS module, and the shield to the - pin.</p>
<p><img alt="Barrel Jack" src="https://thinkl33t.co.uk/usb-pd-miniware-ts100/images/ts100-barreljack.jpg" />
<img alt="Soldered Thing" src="https://thinkl33t.co.uk/usb-pd-miniware-ts100/images/ts100thing-1.jpg" /></p>
<p>Add a bit of heatshrink, and you're sorted! Soldering on the move!</p>
<p><img alt="Heatshrunk Thing" src="https://thinkl33t.co.uk/usb-pd-miniware-ts100/images/ts100thing-2.jpg" />
<img alt="Final Thing" src="https://thinkl33t.co.uk/usb-pd-miniware-ts100/images/ts100thing-3.jpg" /></p>
<p>This <strong>probably</strong> wont last particularly long, as its basically using the solder as a mechanical joint. If it fails i'll likely make another one by connecting the module to a short piece of flex, similar to my old lenovo to 2.1mm adaptor, but until then i'm happy with it :)</p>Modifying a Xiaomi Zigbee Button2019-02-05T19:00:00+00:002019-02-05T19:00:00+00:00thinkl33ttag:thinkl33t.co.uk,2019-02-05:/zigbee-button<p>In late 2017, i was fiddling around trying to teach myself fusion 360, and accidentally found myself designing a giant red button. I didn't really have a use for it at the time, so i added a microswitch, printed it out, and had a random giant button sat around in my office, mostly getting in the way.</p>
<p><img alt="The Button" src="https://thinkl33t.co.uk/zigbee-button/images/big-red-button.jpg" /></p>
<p>Fast forward a bit, and i've implemented a home automation system with a zigbee network, and a £5 Xiaomi Aqara Zigbee button. This button is around 5cm x 5cm, battery powered, and as far as I can tell lasts for infinity time from a single coin cell. I can't help but think though... what if it was giant instead?</p>
<p><img alt="Inside" src="https://thinkl33t.co.uk/zigbee-button/images/aqara-inside.jpg" /></p>
<p>Step one was of course to open up my nice new button. Quick attack of the spudger had the case popped open and ready for a bit of probing. Now, if i was designing this board, i'd probably duplicate the button out to a test pad or pin header somewhere. Luckily the engineers at xiaomi appear to agree with me, and the header in the top right is connected directly across the input switch, score!</p>
<p><img alt="Wires to the front of the board" src="https://thinkl33t.co.uk/zigbee-button/images/aqara-wire-front.jpg" />
<img alt="Wires to the back of the board" src="https://thinkl33t.co.uk/zigbee-button/images/aqara-wire-back.jpg" /></p>
<p>I soldered a couple of wires to the board, and added some hotglue to provide a minimum of strain relief. As an aside, look at all those lovely labelled test points on the back of the board, this could make a fairly nice development board for the NXP zigbee microcontroller.</p>
<p><img alt="Wires to the microswitch" src="https://thinkl33t.co.uk/zigbee-button/images/aqara-wire-switch.jpg" /></p>
<p>I wired in a microswitch to the other end of my cables, and pressing the microswitch triggers the button, yay!</p>
<p><img alt="Reassembled" src="https://thinkl33t.co.uk/zigbee-button/images/aqara-reassembled.jpg" /></p>
<p>A small amount of poking with a scalpel let me remove enough plastic from the corner of the case to feed the wire through and assemble the Aqara button.</p>
<p><img alt="Fitted into button" src="https://thinkl33t.co.uk/zigbee-button/images/big-red-button-aqara.jpg" /></p>
<video width="600" controls>
<source src="https://thinkl33t.co.uk/zigbee-button/images/big-red-button.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
<p>Assemble into the button, and a little bit of hacking to make an automation in homeassistant, and we have a light switch for the 3d printer light!</p>Deploying a Raspberry Pi Chromium Kiosk using Ansible2019-02-05T00:00:00+00:002019-02-05T00:00:00+00:00Bob Cloughtag:thinkl33t.co.uk,2019-02-05:/deploying-a-raspberry-pi-chromium-kiosk-using-ansible<p>Years ago, at a previous job, i was asked to put up a monitoring display showing
details from our service desk. I was given a TV and a Raspberry Pi, and told to
go at it.</p>
<p>I hacked around a bit, eventually had something that sort of worked, noted down
how i'd done it, and moved on. When a friend asked me for more details i passed
on my notes, and after a couple of years of poking around between a few of us,
we have a pretty good idea how to implement this. Tas has documented it in
great detail on her blog
<a href="https://tamarisk.it/raspberry-pi-kiosk-mode-using-raspbian-lite/">here</a> and
<a href="https://tamarisk.it/raspberry-pi-kiosk-mode-using-full-raspbian/">here</a>.</p>
<p>So, at work i've set up a new monitoring system for our servers and services.<br />
And i've found a nice dashboard that hooks into it and gives a ten-foot view.<br />
And i have a spare raspberry pi and projector. Hmm.</p>
<p>I decided this time though, i'd do it properly. I've faffed about running
through those instructions too many times in the past few years, and i'm now
pretty handy with ansible for automation. Seems logical to implement it using
that right?</p>
<p>So to start with, we have a raspberry pi running raspbian lite. We don't need
all the full everything installed on it, just the few bits we want to display a
browser full screen. We need to specify the user we plan on running as, and the
url to display. I do this in <code>host_vars/kiosk.example.com</code></p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="nt">kiosk</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="nt">url</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">http://example.com/monitoring-dashboard</span><span class="w"></span>
<span class="w"> </span><span class="nt">user</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">pi</span><span class="w"></span>
</code></pre></div></td></tr></table></div>
<p>Then we have a role set up to actually do the thing. This is the playbook
itself, at <code>roles/chromium-kiosk/tasks/main.yml</code>:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Install X etc</span><span class="w"></span>
<span class="w"> </span><span class="nt">apt</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="s">"{{item}}"</span><span class="w"></span>
<span class="w"> </span><span class="nt">state</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">present</span><span class="w"></span>
<span class="w"> </span><span class="nt">install_recommends</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">no</span><span class="w"></span>
<span class="w"> </span><span class="nt">with_items</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">xserver-xorg</span><span class="w"></span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">xinit</span><span class="w"></span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">xserver-xorg-video-fbdev</span><span class="w"></span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">lightdm</span><span class="w"></span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">chromium-browser</span><span class="w"></span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">unclutter</span><span class="w"></span>
<span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Enable auto-login to x for user</span><span class="w"></span>
<span class="w"> </span><span class="nt">lineinfile</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="nt">regexp</span><span class="p">:</span><span class="w"> </span><span class="s">"{{item.r}}"</span><span class="w"></span>
<span class="w"> </span><span class="nt">line</span><span class="p">:</span><span class="w"> </span><span class="s">"{{item.l}}"</span><span class="w"></span>
<span class="w"> </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">/etc/lightdm/lightdm.conf</span><span class="w"></span>
<span class="w"> </span><span class="nt">with_items</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="p p-Indicator">{</span><span class="s">'r'</span><span class="p p-Indicator">:</span><span class="w"> </span><span class="s">"^#?autologin-user="</span><span class="p p-Indicator">,</span><span class="w"> </span><span class="s">'l'</span><span class="p p-Indicator">:</span><span class="s">"autologin-user={{kiosk.user}}"</span><span class="p p-Indicator">}</span><span class="w"></span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="p p-Indicator">{</span><span class="s">'r'</span><span class="p p-Indicator">:</span><span class="w"> </span><span class="s">"^#?autologin-user-timeout="</span><span class="p p-Indicator">,</span><span class="w"> </span><span class="s">'l'</span><span class="p p-Indicator">:</span><span class="s">"autologin-user-timeout=0"</span><span class="p p-Indicator">}</span><span class="w"></span>
<span class="w"> </span><span class="nt">notify</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">restart lightdm</span><span class="w"></span>
<span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Set up xsession for user</span><span class="w"></span>
<span class="w"> </span><span class="nt">template</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="nt">src</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">xsession.j2</span><span class="w"></span>
<span class="w"> </span><span class="nt">dest</span><span class="p">:</span><span class="w"> </span><span class="s">"/home/{{kiosk.user}}/.xsession"</span><span class="w"></span>
<span class="w"> </span><span class="nt">notify</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">restart lightdm</span><span class="w"></span>
<span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Make sure user has passwordless sudo for running fbset command</span><span class="w"></span>
<span class="w"> </span><span class="nt">copy</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="nt">content</span><span class="p">:</span><span class="w"> </span><span class="s">"{{kiosk.user}}</span><span class="nv"> </span><span class="s">ALL=(ALL:ALL)</span><span class="nv"> </span><span class="s">NOPASSWD:</span><span class="nv"> </span><span class="s">/bin/fbset\n"</span><span class="w"></span>
<span class="w"> </span><span class="nt">dest</span><span class="p">:</span><span class="w"> </span><span class="s">"/etc/sudoers.d/kiosk-user"</span><span class="w"></span>
<span class="w"> </span><span class="nt">owner</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">root</span><span class="w"></span>
<span class="w"> </span><span class="nt">group</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">root</span><span class="w"></span>
<span class="w"> </span><span class="nt">mode</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">0444</span><span class="w"></span>
<span class="w"> </span><span class="nt">notify</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">restart lightdm</span><span class="w"></span>
<span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">stat</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">/boot/config.txt</span><span class="w"></span>
<span class="w"> </span><span class="nt">register</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">pi_config</span><span class="w"></span>
<span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">disable overscan if we're on a pi</span><span class="w"></span>
<span class="w"> </span><span class="nt">lineinfile</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="nt">regexp</span><span class="p">:</span><span class="w"> </span><span class="s">"{{item.r}}"</span><span class="w"></span>
<span class="w"> </span><span class="nt">line</span><span class="p">:</span><span class="w"> </span><span class="s">"{{item.l}}"</span><span class="w"></span>
<span class="w"> </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">/etc/lightdm/lightdm.conf</span><span class="w"></span>
<span class="w"> </span><span class="nt">with_items</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="p p-Indicator">{</span><span class="s">'r'</span><span class="p p-Indicator">:</span><span class="w"> </span><span class="s">"^#?disable_overscan="</span><span class="p p-Indicator">,</span><span class="w"> </span><span class="s">'l'</span><span class="p p-Indicator">:</span><span class="s">"disable_overscan=1"</span><span class="p p-Indicator">}</span><span class="w"></span>
<span class="w"> </span><span class="nt">notify</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">restart lightdm</span><span class="w"></span>
<span class="w"> </span><span class="nt">when</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">pi_config.stat.exists</span><span class="w"></span>
</code></pre></div></td></tr></table></div>
<p>We then have a handler to restart lightdm when we change any settings. This
will cause the kiosk display to restart. It sits at
<code>roles/chromium-kiosk/handlers/main.yml</code></p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">restart lightdm</span><span class="w"></span>
<span class="w"> </span><span class="nt">service</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">lightdm</span><span class="w"></span>
<span class="w"> </span><span class="nt">state</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">restarted</span><span class="w"></span>
</code></pre></div></td></tr></table></div>
<p>And finally, the template for the xsession, this has a few modifications, it
will automatically detect your screen size, and checks that it can see a http
200 code from the specified URL before starting the browser. It lives at
<code>roles/chromium-kiosk/templates/xsession.j2</code></p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="c1"># Set this to your URL - it must return a 200 OK when called, not a redirect.</span>
<span class="nb">export</span> <span class="nv">URL</span><span class="o">={{</span>kiosk.url<span class="o">}}</span>
<span class="c1"># Dont want screensavers or screen blanking</span>
xset s off <span class="p">&</span>
xset -dpms <span class="p">&</span>
xset s noblank <span class="p">&</span>
<span class="c1"># Hide the mouse cursor</span>
unclutter -idle <span class="m">10</span> -noevents <span class="p">&</span>
<span class="c1"># Sit and wait until you can hit the URL you'll be showing in the kiosk</span>
<span class="k">while</span> ! curl -s -o /dev/null -w <span class="s2">"%{http_code}"</span> <span class="si">${</span><span class="nv">URL</span><span class="si">}</span> <span class="p">|</span> grep -q <span class="s2">"200"</span><span class="p">;</span> <span class="k">do</span>
sleep <span class="m">1</span>
<span class="k">done</span>
<span class="c1"># get screen resolution</span>
<span class="nv">WIDTH</span><span class="o">=</span><span class="sb">`</span>sudo fbset -s <span class="p">|</span> grep <span class="s2">"geometry"</span> <span class="p">|</span> cut -d <span class="s2">" "</span> -f6<span class="sb">`</span>
<span class="nv">HEIGHT</span><span class="o">=</span><span class="sb">`</span>sudo fbset -s <span class="p">|</span> grep <span class="s2">"geometry"</span> <span class="p">|</span> cut -d <span class="s2">" "</span> -f7<span class="sb">`</span>
<span class="c1"># Open chrome in incognito mode + kiosk mode</span>
/usr/bin/chromium-browser --window-size<span class="o">=</span><span class="si">${</span><span class="nv">WIDTH</span><span class="si">}</span>,<span class="si">${</span><span class="nv">HEIGHT</span><span class="si">}</span> --window-position<span class="o">=</span><span class="m">0</span>,0 --hide-scrollbars --incognito --kiosk <span class="si">${</span><span class="nv">URL</span><span class="si">}</span>
</code></pre></div></td></tr></table></div>Connecting to Sky Broadband from Debian2018-08-06T00:00:00+01:002018-08-06T00:00:00+01:00Bob Cloughtag:thinkl33t.co.uk,2018-08-06:/connecting-to-sky-broadband-from-debian<p>Due to price, I've just changed my broadband supplier from Zen to NowTV.<br />
While I love the service Zen have provided me over the years, i'm trying
to save for a big project, so i'm cost-cutting across the board.</p>
<p>So I paid for the transfer, got everything sorted on that front, then had a
look at how I could get the pppoe credentials for NowTV. Turns out Sky (Who run
the NowTV broadband service) don't actually <em>use</em> PPPoE like every other Fibre
provider, and have their own authentication system. Bugger.</p>
<p>Reading through the information around the web, you have to send a DHCP
<code>Option 61</code> with the credentials for your connection, and will be sent an IP
address in response. Seems easy enough, once you can get the credentials.</p>
<p>Most of the information I could find points towards generating a username /
password pair based on the mac address of your router, or extracting the
credentials from an existing router. I also noticed some posts from 2016
saying this was no longer necessary, and you could send <em>any</em> credentials
as long as they are in the correct format. Hmm. Lets try that.</p>
<p>DHCP <code>Option 61</code> is a fancy name for the Client ID. This can be set manually
in most quality routers. Personally, I have a Debian box that takes care of my
home network firewall, so I added the following to <code>/etc/dhcp/dhclient.conf</code>:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="n">send</span><span class="w"> </span><span class="n">dhcp</span><span class="o">-</span><span class="n">client</span><span class="o">-</span><span class="n">identifier</span><span class="w"> </span><span class="ss">"hellothere@skydsl|thisshouldbeapassword"</span><span class="p">;</span><span class="w"></span>
</code></pre></div></td></tr></table></div>
<p>rebooted the box, changed my iptables rules to use <code>eth0</code> instead of the old
<code>ppp0</code> connection and it just... worked \o/</p>iptables for libvirt2018-02-14T00:00:00+00:002018-07-17T00:00:00+01:00Bob Cloughtag:thinkl33t.co.uk,2018-02-14:/iptables-for-libvirt<h1>iptables for forwarding entire ip addresses to an internal IP</h1>
<p>This is one way of achieving forwarding a whole IP to an internal IP. Personally i now use macvtap interfaces on the host, so the VM sits directly at layer 2 and the host doesn't have to worry about it, however sometimes you will want be able to <em>block</em> specific ports from ingress / egress on your vm and this solution helps.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span>
<span class="normal">7</span>
<span class="normal">8</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="c1"># VM is allowed to receive packets</span>
sudo iptables -I FORWARD -o virbr0 -d <span class="o">{</span>internal_ip<span class="o">}</span> -j ACCEPT
<span class="c1"># All packets arriving at {external_ip} need to go to {internal_ip}</span>
sudo iptables -t nat -I PREROUTING -p tcp -d <span class="o">{</span>external_ip<span class="o">}</span> -j DNAT --to <span class="o">{</span>internal_ip<span class="o">}</span>
<span class="c1"># All packets leaving {internal_ip} should go from {external_ip}</span>
sudo iptables -t nat -I POSTROUTING -s <span class="o">{</span>internal_ip<span class="o">}</span> -j SNAT --to-source <span class="o">{</span>external_ip<span class="o">}</span>
</code></pre></div></td></tr></table></div>
<h1>Iptables for forwarding a single port</h1>
<p>If you only want to open pinholes from the internet to your libvirt VMs, you'll want to add a specific rule for each port. </p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="c1"># Allow the server to receive packets aimed at the port we're forwarding</span>
iptables -I FORWARD -m state --state NEW,RELATED,ESTABLISHED -p tcp --dport <span class="o">{</span>port_number<span class="o">}</span> -d <span class="o">{</span>internal_ip<span class="o">}</span> -j ACCEPT
<span class="c1"># Forward packets arriving on the port on the host to the port on the internal ip</span>
iptables -t nat -I PREROUTING -p tcp --dport <span class="o">{</span>port_number<span class="o">}</span> -j DNAT --to-destination <span class="o">{</span>internal_ip<span class="o">}</span>:<span class="o">{</span>port_number<span class="o">}</span>
</code></pre></div></td></tr></table></div>
<p>Note that this will forward packets arriving on any interface where there isn't already a rule in place! If you only want to forward packets from a specific external IP, change the second line to:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><code>iptables -t nat -I PREROUTING -p tcp -d <span class="o">{</span>external_ip<span class="o">}</span> --dport <span class="o">{</span>port_number<span class="o">}</span> -j DNAT --to-destination <span class="o">{</span>internal_ip<span class="o">}</span>:<span class="o">{</span>port_number<span class="o">}</span>
</code></pre></div></td></tr></table></div>
<h1>Making iptables persist across reboots</h1>
<p>To make iptables persist across reboots, i sugges using debian's iptables-persistent package.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span></pre></div></td><td class="code"><div><pre><span></span><code>sudo apt-get install iptables-persistent
sudo service netfilter-persistent save
</code></pre></div></td></tr></table></div>Beginners Guide to Badge Hacking2016-08-05T00:00:00+01:002018-07-30T00:00:00+01:00Bob Cloughtag:thinkl33t.co.uk,2016-08-05:/beginners-guide-to-badge-hacking<p>We're going to create an LED torch for seeing our way around the camp.</p>
<h2>Soldering the LED</h2>
<p>You should have received an LED and a resistor with your badge. First, grab the resistor. Bend the legs over so they fit in the holes in the board, using the resistor lead bender.</p>
<p><img alt="Leg Bender" src="https://thinkl33t.co.uk/beginners-guide-to-badge-hacking/images/hackpad.com_Rs7awClTQDH_p.554927_1470420913282_legbender.jpg" /></p>
<p>It doesn't matter way round the resistor goes.</p>
<p><img alt="Resistor Fitted" src="https://thinkl33t.co.uk/beginners-guide-to-badge-hacking/images/hackpad.com_Rs7awClTQDH_p.554927_1470307053798_P1010517.JPG" /></p>
<p>Flip over your board and solder the resistor in place, then trim down the legs to be flush against the board.</p>
<p>Next, the LED. It does matter which way round the LED goes - look for a flat side on the LED and match it up with the flat side on the board. Pull your LED out about a centimetre and bend it over a bit.</p>
<p><img alt="LED Fitted" src="https://thinkl33t.co.uk/beginners-guide-to-badge-hacking/images/hackpad.com_Rs7awClTQDH_p.554927_1470307470838_P1010533.JPG" /></p>
<p>Flip the board over and solder the LED into place. </p>
<h2>Testing</h2>
<p>Plug your badge into your laptop, and use the information on <a href="https://micropython.org/doc/tut-repl"></a>https://micropython.org/doc/tut-repl to connect to the usb-serial port. If you hit Ctrl-C, you drop out of the badge software, and get a REPL prompt. You can tell this is working because you'll see three > symbols.</p>
<p>Type the following at the prompt. This should turn your LED on!</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="o">>>></span> <span class="kn">import</span> <span class="nn">pyb</span>
<span class="o">>>></span> <span class="n">pin</span> <span class="o">=</span> <span class="n">pyb</span><span class="o">.</span><span class="n">Pin</span><span class="p">(</span><span class="s2">"LED_TORCH"</span><span class="p">)</span>
<span class="o">>>></span> <span class="n">pin</span><span class="o">.</span><span class="n">high</span><span class="p">()</span>
</code></pre></div></td></tr></table></div>
<p>Of course, thats a bit of a pain to do every time we want the LED on, so let's make an app!</p>
<h2>The App</h2>
<p>Your badge should have shown up as a USB drive. Open the folder <strong>apps</strong>, and create a folder within it called <strong>torch.</strong></p>
<p>Create a file within this called <strong>main.py</strong>. This is your app's main file. Open it in a text editor.</p>
<p>First, we need to tell the badge some details about your app. This is done in a header section at the top of the file</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="c1">### Author: Your Name</span>
<span class="c1">### Description: Torch</span>
<span class="c1">### Category: Flashy</span>
<span class="c1">### License: MIT</span>
<span class="c1">### Appname : Torch</span>
<span class="c1">### Built-in: no</span>
</code></pre></div></td></tr></table></div>
<p>You could save and run your app now, but it won't actually do anything yet. Lets add the code:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="c1">### Author: Your Name</span>
<span class="c1">### Description: Torch</span>
<span class="c1">### Category: Flashy</span>
<span class="c1">### License: MIT</span>
<span class="c1">### Appname : Torch</span>
<span class="c1">### Built-in: no</span>
<span class="kn">import</span> <span class="nn">pyb</span>
<span class="n">pin</span> <span class="o">=</span> <span class="n">pyb</span><span class="o">.</span><span class="n">Pin</span><span class="p">(</span><span class="s2">"LED_TORCH"</span><span class="p">)</span>
<span class="n">pin</span><span class="o">.</span><span class="n">high</span><span class="p">()</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="k">pass</span>
</code></pre></div></td></tr></table></div>
<p>Save, and run your app. When you run it the LED should turn on, brill!</p>
<p>Of course, we're not showing anything on the screen. Lets have a nice dialog box to show we're in the torch instead of that while loop.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="c1">### Author: Your Name</span>
<span class="c1">### Description: Torch</span>
<span class="c1">### Category: Flashy</span>
<span class="c1">### License: MIT</span>
<span class="c1">### Appname : Torch</span>
<span class="c1">### Built-in: no</span>
<span class="kn">import</span> <span class="nn">ugfx</span><span class="o">,</span> <span class="nn">pyb</span><span class="o">,</span> <span class="nn">dialogs</span>
<span class="n">pin</span> <span class="o">=</span> <span class="n">pyb</span><span class="o">.</span><span class="n">Pin</span><span class="p">(</span><span class="s2">"LED_TORCH"</span><span class="p">)</span>
<span class="n">pin</span><span class="o">.</span><span class="n">high</span><span class="p">()</span>
<span class="n">ugfx</span><span class="o">.</span><span class="n">init</span><span class="p">()</span>
<span class="n">ugfx</span><span class="o">.</span><span class="n">clear</span><span class="p">(</span><span class="n">ugfx</span><span class="o">.</span><span class="n">html_color</span><span class="p">(</span><span class="mh">0x7c1143</span><span class="p">))</span>
<span class="n">dialogs</span><span class="o">.</span><span class="n">notice</span><span class="p">(</span><span class="s2">"Shine a light!"</span><span class="p">,</span> <span class="n">title</span><span class="o">=</span><span class="s2">"Torch"</span><span class="p">,</span> <span class="n">close_text</span><span class="o">=</span><span class="s2">"Exit"</span><span class="p">)</span>
</code></pre></div></td></tr></table></div>
<p>Run your app again and you should have a nice button you can press to shine a light in the camp!</p>
<p>You can unplug the badge from your computer when the LED has finished flashing, but we recommend you eject the drive first.</p>TiLDA for Wearable Electronics2016-08-03T00:00:00+01:002018-07-30T00:00:00+01:00Bob Cloughtag:thinkl33t.co.uk,2016-08-03:/tilda-for-wearables<p>Did you know that as well as being an awesome internet-connected, python-powered portal to nirvana (OK, one of those may be a lie), your badge is also a rad wearables controller?</p>
<p>At badge HQ, we love flashy LEDs, and we love sewing them to ourselves for no apparent reason. That's why each badge has support for attaching and driving a string of Neopixel / WS2812 LEDs up to X LEDs long.</p>
<p>If you already have some neopixels, you'll need to add a three-pin connector to the end of the string for connecting to the badge. The pinout is a servo-style pinout, with the +v in the center, which makes it more difficult to explode things if you plug it in backwards! </p>
<p><img alt="Neopixel Header" src="https://thinkl33t.co.uk/tilda-for-wearables/images/hackpad.com_XtI0TwNKSv9_p.554927_1469649993656_badge-3-neo.jpg" /></p>
<p>I would suggest using a right-angled connector, and having your wire go off the side of the badge. That way it isn't sticking out or stabbing you in the chest.</p>
<p><strong>NOTICE: </strong>Unfortunately, the badges we've made for the event have the onboard neopixel fitted backwards (oops!), so unless you want to have a go at rotating it (we can help with that at the Badge Tent), you cant use the onboard header. Luckily, CH2 on the Servos connector block is also able to be used for neopixels, so you can solder the connector there instead.</p>
<p>The central V+ pin is at battery voltage when running from battery, so varies between 4.2 and 3.6 volts depending on how flat your battery is. We've tested this with a string of 5V neopixels, and it is enough to power them up fine. However, if you are worried about your battery running out too fast, or want to drive more neopixels than the badge can handle, you can plug a USB battery pack into the badge, and the LED strip will be provided with a full 5V.</p>
<h2>The App</h2>
<p>OK, so thats the hardware, now for the software. Step one is to load up the Wearables from the App Library. As soon as you reboot, the neopixel on your badge (or the first on your strip) should start cycling through the colour wheel. </p>
<p>What we need to do is tell the app what sequence to run, and how many LEDs you have connected to your badge. Lets try the rainbow:</p>
<p><img alt="Rainbow" src="https://thinkl33t.co.uk/tilda-for-wearables/images/hackpad.com_XtI0TwNKSv9_p.554927_1470232898582_IMG_20160803_145153.jpg" /></p>
<p><img alt="Number of LEDs" src="https://thinkl33t.co.uk/tilda-for-wearables/images/hackpad.com_XtI0TwNKSv9_p.554927_1470232903179_IMG_20160803_145204.jpg" /></p>
<p><img alt="Speed" src="https://thinkl33t.co.uk/tilda-for-wearables/images/hackpad.com_XtI0TwNKSv9_p.554927_1470232931593_IMG_20160803_145210.jpg" /></p>
<p><img alt="Pretty Rainbow" src="https://thinkl33t.co.uk/tilda-for-wearables/images/hackpad.com_XtI0TwNKSv9_p.554927_1470232770786_IMG_20160803_145125.jpg" /></p>
<p>Rad.</p>
<p>Note that once you've set up the number of LEDs connected, you can just press B to skip that screen in the future, it'll keep the setting.</p>
<p>Matrix next. This doesnt need anything extra configuring, and shows a green flickery pattern like on the film (which i'm informed is now 17 years old, what?!):</p>
<p><img alt="There is no spoon" src="https://thinkl33t.co.uk/tilda-for-wearables/images/hackpad.com_XtI0TwNKSv9_p.554927_1470233036722_IMG_20160803_145249.jpg" /></p>
<p>And lastly, Colour displays a single colour so you can make everything pink! You need to enter a HTML colour code, this is ff00ff:</p>
<p><img alt="HTML Colour Code" src="https://thinkl33t.co.uk/tilda-for-wearables/images/hackpad.com_XtI0TwNKSv9_p.554927_1470233198091_IMG_20160803_145326.jpg" /></p>
<p><img alt="Pink!" src="https://thinkl33t.co.uk/tilda-for-wearables/images/hackpad.com_XtI0TwNKSv9_p.554927_1470233205871_IMG_20160803_145353.jpg" /></p>
<p>If you want to add any extra sequences, code for the wearables app is available at <a href="https://github.com/thinkl33t/TiLDA-Wearables">https://github.com/thinkl33t/TiLDA-Wearables</a> . Just dump it on your badge at apps/wearables/ I'll accept pull requests if you add any extra sequences, so get making!</p>Automatically starting a Python script at boot on Raspbian Jessie2016-07-06T16:20:00+01:002016-07-06T16:20:00+01:00thinkl33ttag:thinkl33t.co.uk,2016-07-06:/automatically-starting-a-python-script-at-boot-on-raspbian-jessie<p>As part of the Hackspace Manchester door control system, we have a
raspberry pi running a little script that checks scanned cards against a
database of members and opens the door if the card is known. This has
been humming along happily for around 3 years now, until recently it
stopped updating card IDs when they were changed via the webui.</p>
<p>This led to a bit of a bug hunt, concluding with the fact the version of
openssl on raspbian wheezy was waaaaay out of date, and we'd recently
updated our members system to disable insecure cyphers on the HTTPS
protocol. We fixed it by upgrading to jessie, which as a side effect
completely killed the auto-start of the door opening programme. Yay?</p>
<p>So. Jessie. Systemd. Init system is a a bit different from sysvinit,
but on the whole i find it a lot more sensible. We want to run a script
as the user 'alfred' (the door entry service user). We also want to
wait until the system is booted, and the serial port is available.</p>
<p>My script is called alfred, so i create the following file in
<code>/lib/systemd/system/alfred.service</code></p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">[Unit]</span><span class="w"></span>
<span class="na">Description</span><span class="o">=</span><span class="s">alfred</span><span class="w"></span>
<span class="na">After</span><span class="o">=</span><span class="s">dev-ttyAMA0.device multi-user.target</span><span class="w"></span>
<span class="k">[Service]</span><span class="w"></span>
<span class="na">Type</span><span class="o">=</span><span class="s">idle</span><span class="w"></span>
<span class="na">ExecStart</span><span class="o">=</span><span class="s">/home/alfred/FRED/fred/fred.py</span><span class="w"></span>
<span class="na">WorkingDirectory</span><span class="o">=</span><span class="s">/home/alfred/FRED/fred/</span><span class="w"></span>
<span class="na">User</span><span class="o">=</span><span class="s">alfred</span><span class="w"></span>
<span class="k">[Install]</span><span class="w"></span>
<span class="na">WantedBy</span><span class="o">=</span><span class="s">multi-user.target</span><span class="w"></span>
</code></pre></div></td></tr></table></div>
<p>The <code>After=</code> says what services need to be up before this is run. In
this case, it wants ttyAMA0 to be available, along with multi-user (this
is the point where you could normally log in)</p>
<p><code>ExecStart=</code> specifies the script I will be running,
<code>WorkingDirectory=</code> is the directory to run the thing from (as i use
relative paths in my python script, i need to set this), and <code>User=</code>
says what unprivileged user to run the script as, since you don't want
to be running random things as root if at all possible!</p>
<p><code>WantedBy=</code> says that this should be started at the same time as
multi-user.target, so at the end of the boot process, at the point you
could normally log in.</p>
<p>We can then set up our new service to start on boot, and run it for the
first time:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span></pre></div></td><td class="code"><div><pre><span></span><code>$ systemctl enable alfred
$ systemctl start alfred
No errors, so lets check the status:
$ sudo systemctl status alfred
● alfred.service - alfred
Loaded: loaded (/lib/systemd/system/alfred.service; enabled)
Active: active (running) since Wed 2016-07-06 16:42:59 BST; 30min ago
Main PID: 709 (fred.py)
CGroup: /system.slice/alfred.service
└─709 /usr/bin/python /home/alfred/FRED/fred/fred.py
Jul 06 16:42:59 alvin systemd[1]: Starting alfred...
Jul 06 16:42:59 alvin systemd[1]: Started alfred.
Jul 06 16:43:01 alvin fred.py[709]: 2016-07-06 16:43:01,577 FRED 0.7
</code></pre></div></td></tr></table></div>
<p>Looks good, service is started, and we're getting some log output from
it. Reboot to check everything comes up correctly and you're done!</p>
<p>... Though i wasnt. One gotcha I ran into is that because of the way
raspbian's networking is set up, you can't get systemd to wait until
after you have a network connection configured before starting the
script (it will wait until the networking service is <strong>started</strong>, but
not wait for the network to actually be up). This can be worked around
pretty easily by setting the "Wait for network on boot" option in
<code>raspi-config</code>, which will pause the whole boot process until it gets a
DHCP lease.</p>Anatomy of a Scam: the tale of the £40 3D printer.2015-10-05T14:31:00+01:002015-10-05T14:31:00+01:00thinkl33ttag:thinkl33t.co.uk,2015-10-05:/anatomy-of-a-scam-the-tale-of-the-40-3d-printer<p><img alt="Aliexpress Screenshot" src="https://thinkl33t.co.uk/anatomy-of-a-scam-the-tale-of-the-40-3d-printer/images/3d-printer-scam.jpg" /></p>
<p>When i saw this, I thought "£40 for a 3d printer? Including UPS
shipping? This is too good to be true!"</p>
<p>Though thinking about it a bit more, I couldn't think of any way they
could get away with the money. Aliexpress offers full buyer protection
if you buy through alipay, and money is held in escrow. So I bought a
couple to see what the dealio is. If it does arrive and its shit, just
the motors would cost more then £40 to buy, and I can definitely reuse
them. I figured going into this paranoid, I might just about be able to
figure it out before they run away with my money.</p>
<p>This morning, I got shipping confirmation, with a china post shipping
code. "Wow, maybe its not a scam?" I thought. Then I received this
message:</p>
<blockquote>
<p>hi. friend. Because you choose courier suspended. We send you the
goods by China Post Air Parcel. Give you cause delays receive the
package, so we give you $15 in compensation. You may submit
disputes. A partial refund of $15 agreement. We give you a refund in
a timely manner. Thank you</p>
</blockquote>
<p>Ok, yeah, thats a bit odd. This is the penny dropping.</p>
<p>The way AliExpress works, you can open a dispute on any order for either
the full, or part of the purchase price. If the seller agrees, the
refund is paid out to you right away. But if I open a dispute for the
shipping, maybe I lose the ability to open a dispute for the remainder
if the item doesn't arrive? The FAQs were unclear, so I set off to
AliExpress customer support:</p>
<blockquote>
<blockquote>
<p>If I open a dispute for a partial refund (for the shipping), can I then open another dispute later if the item does not arrive</p>
</blockquote>
<p>No, if the dispute has been agreed the seller with partial refund, the
remaining payment will be release to the seller automatically</p>
<p>With this, I highly suggest to please ask a full refund instead.</p>
</blockquote>
<p>So there it is. Beautiful in its simplicity. You ask for a dispute for
the shipping charges, get your £8 shipping back, and lose the ability to
claim back your £32 for the rest the item when it doesnt arrive. Since
I have 40 days of purchase protection remaining, I'm going to hold off
claiming a full refund for a couple of weeks, and I'll update here if I
turn out to be wrong and something does arrive!</p>
<h2>Update!</h2>
<p>Another message is being sent to those of us who have ignored the first
message, or replied that the refund is not necessary:</p>
<blockquote>
<p>Friends. Goods are in transit. Do not worry. We give you a refund of
compensation today. Tomorrow no longer compensate, please submit the
dispute in a timely manner, thank you</p>
</blockquote>
<p>Ahh, a time limit! Best get the refund quick, otherwise they wont offer
it anymore! I've received this second message, as have others. I'm
guessing it wont be long until aliexpress close their account, so
they've gotta try and get as much cash out asap.</p>
<h2>Update!</h2>
<p>Just got an email from aliexpress:</p>
<blockquote>
<p>Your order --REDACTED-- has been frozen due to suspicious
seller activity.</p>
<p>We have suspended this seller’s account because we detected unsafe
trading activities. All of your pending orders with this seller have
been frozen for your security.</p>
<p>We have asked this supplier to provide supporting evidence, such as
shipping documents and qualification certificates. If the supplier is
unable to provide the evidence or if the evidence is insufficient, we
will close the order and process the refund for you within 5 business
days (In case of certain circumstance, the processing period may be
extended).</p>
<p>We apologize for this inconvenience. At AliExpress we are committed to
ensuring you enjoy a safe shopping experience. We will continue
striving to improve. Your understanding and cooperation are highly
appreciated, if you have any question or suggestion, please click here</p>
<p>Your understanding and cooperation are highly appreciated.</p>
<p>Sincerely,</p>
<p>AliExpress Trade Security Department</p>
</blockquote>
<p>I'm fairly unsurprised by this, hopefully the refund will be forthcoming
fairly quickly.</p>
<h2>Final Update</h2>
<blockquote>
<p>Your Order No:-REDACTED- has been closed because the supplier did not
provide necessary evidence. The payment will be refunded to you within
7-10 working days.</p>
<p>AliExpress strives to continuously improve our trading environment.
Thank you for your understanding and continued support.</p>
<p>Sincerely,</p>
<p>AliExpress Trade Security Department</p>
</blockquote>
<p>And its over. This experience has massively reaffirmed my confidence in
aliexpress' customer services and payment systems. Other sales websites
should take notice!</p>Setting up a self-healing SSH tunnel for Raspberry Pi using Debian.2015-04-30T15:38:00+01:002015-04-30T15:38:00+01:00thinkl33ttag:thinkl33t.co.uk,2015-04-30:/setting-up-a-self-healing-ssh-tunnel-for-raspberry-pi-using-debian<p>I use quite a few raspberry pi's in locations that dont have the ability
for me do incoming SSH to update / reboot / maintain them. This is how
i set up a reverse SSH tunnel to them, allowing me to access them from
anywhere with internet access!</p>
<p>If the site has a proxy, first you'll need to install a proxy puncher to
allow you to bypass it.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><code>$ sudo http_proxy="http://proxy.ip.address:port" apt-get install corkscrew
</code></pre></div></td></tr></table></div>
<p>Then install screen. Screen allows you to start a process running
'detached' from your current shell, so you dont have to be logged in to
keep the tunnel up.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><code>$ sudo apt-get install screen
</code></pre></div></td></tr></table></div>
<p>Create a user for your ssh tunnel. You could just use the default pi
user, but i prefer to use a dedicated tunnel user.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><code>$ sudo adduser --system tunnel
</code></pre></div></td></tr></table></div>
<p>Create tunnel config</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span></pre></div></td><td class="code"><div><pre><span></span><code>$ sudo -u tunnel mkdir /home/tunnel/.ssh
$ sudo -u tunnel vim /home/tunnel/.ssh/config
</code></pre></div></td></tr></table></div>
<p>Paste the following into the file. This forwards port 22 (ssh) and 80
(http) on the raspberry pi to ports 8022 and 8080 on your VPS.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span>
<span class="normal">7</span>
<span class="normal">8</span>
<span class="normal">9</span></pre></div></td><td class="code"><div><pre><span></span><code>ProxyCommand corkscrew 127.0.0.1 3128 %h %p
Host tunnel
Hostname your.vps.hostname
Remoteforward 8022 localhost:22
Remoteforward 8080 localhost:80
Port 443
User tunnel
ServerAliveInterval 10
ServerAliveCountMax 3
</code></pre></div></td></tr></table></div>
<p>NOTE: If you are not using a proxy, remove the corkscrew line and the
port 443 line. The port 443 line above is only needed if you are behind
a proxy and firewall that disallows port 22 outgoing. I have set up my
SSH daemon on the VPS to listen to port 443 (the https port) as well as
the normal 22 as this will manage to punch its way through most proxies.</p>
<p>The <code>ServerAliveInterval</code> and <code>ServerAliveMax</code> variables above basically say
"send a packet across the tunnel every 10 seconds. If you don't get
anything back after 3 tries, close the tunnel"</p>
<p>The above config also assumes you have set up a tunnel user on the
machine you are SSHing to. If not, either create a tunnel user the same
way we did above, or change the user line in the config to the username
you will be using on the VPS side.</p>
<p>Generate your RSA key and upload to the VPS</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span></pre></div></td><td class="code"><div><pre><span></span><code>$ sudo -su tunnel
$ export HOME=/home/tunnel
$ ssh-keygen
$ ssh-copy-id tunnel
</code></pre></div></td></tr></table></div>
<p>At this point, you should be able to SSH to tunnel without typing in any
passwords etc.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span></pre></div></td><td class="code"><div><pre><span></span><code>$ ssh tunnel
Linux thinkl33t 3.2.0-4-686-pae \#1 SMP Debian 3.2.65-1+deb7u2 i686
</code></pre></div></td></tr></table></div>
<p>Set up our shell scripts to automatically start the tunnel.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span></pre></div></td><td class="code"><div><pre><span></span><code>$ sudo -su tunnel
$ mkdir /home/tunnel/bin
$ echo 'PATH="\$HOME/bin:\$PATH"' | tee /home/tunnel/.bashrc
$ echo '\#!/bin/bash' | tee /home/tunnel/bin/monitor\_tunnel.sh
$ echo 'APPCHK=\$(screen -ls | grep -c tunnel)' | tee -a /home/tunnel/bin/monitor\_tunnel.sh
$ echo 'if \[ \$APPCHK = "1" \]; then' | tee -a /home/tunnel/bin/monitor\_tunnel.sh
$ echo ' echo "Starting SSH tunnel"' | tee -a /home/tunnel/bin/monitor\_tunnel.sh
$ echo ' screen -mdS tunnel ssh -N tunnel' | tee -a /home/tunnel/bin/monitor\_tunnel.sh
$ echo 'fi' | tee -a /home/tunnel/bin/monitor\_tunnel.sh
$ echo 'exit' | tee -a /home/tunnel/bin/monitor\_tunnel.sh
$ chmod a+x /home/tunnel/bin/monitor\_tunnel.sh
</code></pre></div></td></tr></table></div>
<p>The above script checks for an already open screen session with the name
'tunnel'. If it doesn't exist, it creates it. If it does exist it just
ends. The screen session is launched in a detached state (in the
background), and will automatically end when the SSH tunnel falls over.</p>
<p>Set up the crontab to automatically run our monitoring script once a
minute</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><code>$ echo '\*/1 \* \* \* \* /home/tunnel/bin/monitor\_tunnel.sh' | crontab
</code></pre></div></td></tr></table></div>
<p>Your tunnel should come up shortly, woo!</p>
<p>To test it out, from your VPS, type</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span></pre></div></td><td class="code"><div><pre><span></span><code>$ ssh localhost -p 8022
parag0n@localhost's password:
Linux thinkl33t 3.2.0-4-686-pae \#1 SMP Debian 3.2.65-1+deb7u2 i686
</code></pre></div></td></tr></table></div>
<p>Brill, you can now SSH in from your VPS... But by default SSH tunnel
ports are only available from localhost, so you'd have to log into your
VPS every time you wanted to get into the pi. So, lets edit the SSH
config file on your local machine!</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span></pre></div></td><td class="code"><div><pre><span></span><code>Host pi
Hostname localhost
Port 8022
ProxyCommand ssh your.vps.hostname nc %h %p
</code></pre></div></td></tr></table></div>
<p>This will allow you to type in <code>ssh pi</code> on your local
machine, and will automatically ssh into your VPS, then SSH into
localhost. Sorted.</p>Project - Lil' Buggers2014-05-12T13:35:00+01:002014-05-12T13:35:00+01:00thinkl33ttag:thinkl33t.co.uk,2014-05-12:/project-lil-buggers<p><img alt="Lil Buggers" src="https://thinkl33t.co.uk/project-lil-buggers/images/buggers-big.jpg" /></p>
<p>We like to do occasional workshops at the
<a href="http://hacman.org.uk">Hackspace</a>, so when
we were asked to make something 'bug themed' for a workshop, we jumped on it.
The first thought we had was to make up some bug-shaped PCBs with a circuit to
flash LEDs, and run a soldering workshop. When we found out the workshop was a
week away, we panicked a little, as that's not really enough time to get PCBs
manufactured at a sensible price.</p>
<p>We decided instead to make little laser cut bugs with LED eyes, as they
can be made with easily available materials, and infinitely customised.</p>
<p>Step one was to choose a material. Our first experiments were with
acrylic. I whipped up some designs for 'joints', which would friction
fit onto the side or top of a 'body'. I attached these to a curved path
in inkscape for the legs, and bug #0 was born!</p>
<p><img alt="Bug 0" src="https://thinkl33t.co.uk/project-lil-buggers/images/IMG_20140511_151815.jpg" /></p>
<p>Bug #0 had a couple of issues, mainly due to the material choice. Acrylic
thicknesses can be a bit variable, the tolerance can be as wide as ±10%, and it
is fairly brittle. the combination of these two issues caused at least one
broken leg (hence #0 having 5 legs!).</p>
<p>We decided to have a go at laser MDF instead. Laser MDF is basically
MDF made with a glue that is less harmful to people and laser cutters
than regular MDF. It has the advantage of being very dimensionally
accurate (our 3.2mm MDF was measured at 3.21mm), and having a bit of
bend before it breaks.</p>
<p><img alt="Bug 1" src="https://thinkl33t.co.uk/project-lil-buggers/images/IMG_20140511_153449.jpg" /></p>
<p>Bug #1 was born. It assembled a lot easier than #0, and has cool
looking scorched edges. At this point I started designing some add-on
parts to allow attendees to customise their bugs, including wings,
tails, hairy legs, and mandibles.</p>
<p>The only issue with #1 was losing the wide range of colours available
from acrylic. However, I had a flash of inspiration, and gave a sheet
of laser MDF a light coat of red spraypaint. This dries fast, and
gives an awesome splash of colour.</p>
<p><img alt="Bug 2" src="https://thinkl33t.co.uk/project-lil-buggers/images/photo167559306172016646.jpg" />
Bug #2 is alive! This time sporting a lovely pair of wings and some
antennae. #2 was done with just one side of the wood painted, which
gives a cool effect. depending on what side of the bug you're looking
at.</p>
<p>Then things got a bit silly...</p>
<p><img alt="Bugs" src="https://thinkl33t.co.uk/project-lil-buggers/images/IMG_20140511_212955.jpg" /></p>
<p>We now have a swarm of these delightful Lil' Buggers invading the
hackspace. With a magnet and a dab of hotglue they'll stick to anything
metallic, and their LED eyes last for a couple of days on a coin cell.</p>45 Minute Project - £4.10 XBMC Remote Receiver2014-03-01T12:22:00+00:002014-03-01T12:22:00+00:00thinkl33ttag:thinkl33t.co.uk,2014-03-01:/45-minute-project-ps410-xbmc-remote-receiver<p>I'm a big fan of XBMC, and have an Ouya running XBMC set up in my
lounge, streaming from my NAS. I normally use XBMC remote on my phone
for controlling it, but this gets annoying when the phone is on charge,
or I'm using it for something else.</p>
<p>I noticed that the majority of my TV remote is completely unused when
the TV is in HDMI mode, and had a bit of a lightbulb moment!</p>
<p><img alt="Remote" src="https://thinkl33t.co.uk/45-minute-project-ps410-xbmc-remote-receiver/images/IMG_20140301_113035.jpg" />
Almost none of these buttons are used!</p>
<p>I already had an <a href="http://www.ebay.co.uk/sch/i.html?_nkw=arduino+pro+micro">Arduino Pro
Micro</a> (£3) lying
about i'd bought for testing out as an upgrade path for the minimus
based projects i've been playing with. It is leonardo compatible,
small, cheap and pretty easily available. I added an <a href="http://uk.farnell.com/jsp/search/productdetail.jsp?sku=1703546">IR
Receiver</a> (£1.10)
to the weekly Hackspace Farnell order to complete the parts list.</p>
<p>The pinout of the IR receiver makes it very easy to connect to the pro
micro, using the RAW (VUSB), GND, and A3 pins. I just bent the OUT pin
(pin 1) on the receiver to the left a bit as follows:</p>
<p><img alt="Front" src="https://thinkl33t.co.uk/45-minute-project-ps410-xbmc-remote-receiver/images/IMG_20140301_113050.jpg" />
<img alt="Back" src="https://thinkl33t.co.uk/45-minute-project-ps410-xbmc-remote-receiver/images/IMG_20140301_113101.jpg" />
The body of the receiver fits
perfectly behind the USB plug, flat against the voltage regulator. I
used the <a href="https://github.com/shirriff/Arduino-IRremote">IRremote</a> arduino
library to grab data from the remote using the IRrecvDemo sketch and mushed some
buttons:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="mf">8</span><span class="n">B452ADFFFFFFFFFFFFFFFF8B410EFFFFFFFFFFFFFFFFFFFFFFFFF8B4D22DFFFFFFFF8B4926DFFFFFFFFFFFFFFFF</span><span class="w"></span>
</code></pre></div></td></tr></table></div>
<p>My remote uses 0xFFFFFFFF as a 'key repeat' code, about every 200ms when
the button is held down. I found that in practice I had to ignore the
first of these, as it was repeating way too fast and doing double
presses.</p>
<p>I tweaked the IRrecvDemo sample code, added in a bit of keyboard and
came up with some working code:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span>
<span class="normal">30</span>
<span class="normal">31</span>
<span class="normal">32</span>
<span class="normal">33</span>
<span class="normal">34</span>
<span class="normal">35</span>
<span class="normal">36</span>
<span class="normal">37</span>
<span class="normal">38</span>
<span class="normal">39</span>
<span class="normal">40</span>
<span class="normal">41</span>
<span class="normal">42</span>
<span class="normal">43</span>
<span class="normal">44</span>
<span class="normal">45</span>
<span class="normal">46</span>
<span class="normal">47</span>
<span class="normal">48</span>
<span class="normal">49</span>
<span class="normal">50</span>
<span class="normal">51</span>
<span class="normal">52</span>
<span class="normal">53</span>
<span class="normal">54</span>
<span class="normal">55</span>
<span class="normal">56</span>
<span class="normal">57</span>
<span class="normal">58</span>
<span class="normal">59</span>
<span class="normal">60</span>
<span class="normal">61</span>
<span class="normal">62</span>
<span class="normal">63</span>
<span class="normal">64</span>
<span class="normal">65</span>
<span class="normal">66</span>
<span class="normal">67</span>
<span class="normal">68</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="cp">#include IRrecv</span>
<span class="kt">int</span><span class="w"> </span><span class="n">RECV_PIN</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">A3</span><span class="p">;</span><span class="w"></span>
<span class="n">IRrecv</span><span class="w"> </span><span class="nf">irrecv</span><span class="p">(</span><span class="n">RECV_PIN</span><span class="p">);</span><span class="w"></span>
<span class="n">decode_results</span><span class="w"> </span><span class="n">results</span><span class="p">;</span><span class="w"></span>
<span class="kt">int</span><span class="w"> </span><span class="n">key</span><span class="p">;</span><span class="w"></span>
<span class="kt">int</span><span class="w"> </span><span class="n">count</span><span class="p">;</span><span class="w"></span>
<span class="kt">void</span><span class="w"> </span><span class="nf">setup</span><span class="p">()</span><span class="w"></span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">irrecv</span><span class="p">.</span><span class="n">enableIRIn</span><span class="p">();</span><span class="w"> </span><span class="c1">// Start the receiver</span>
<span class="p">}</span><span class="w"></span>
<span class="kt">void</span><span class="w"> </span><span class="nf">loop</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">irrecv</span><span class="p">.</span><span class="n">decode</span><span class="p">(</span><span class="o">&</span><span class="n">results</span><span class="p">))</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="k">switch</span><span class="w"> </span><span class="p">(</span><span class="n">results</span><span class="p">.</span><span class="n">value</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="mh">0x8B452AD</span><span class="p">:</span><span class="w"> </span><span class="c1">// up</span>
<span class="w"> </span><span class="n">key</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">KEY_UP_ARROW</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">count</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">break</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="mh">0x8B410EF</span><span class="p">:</span><span class="w"> </span><span class="c1">// right</span>
<span class="w"> </span><span class="n">key</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">KEY_RIGHT_ARROW</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">count</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">break</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="mh">0x8B4D22D</span><span class="p">:</span><span class="w"> </span><span class="c1">// down</span>
<span class="w"> </span><span class="n">key</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">KEY_DOWN_ARROW</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">count</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">break</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="mh">0x8B4D02F</span><span class="p">:</span><span class="w"> </span><span class="c1">// left</span>
<span class="w"> </span><span class="n">key</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">KEY_LEFT_ARROW</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">count</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">break</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="mh">0x8B4926D</span><span class="p">:</span><span class="w"> </span><span class="c1">// enter</span>
<span class="w"> </span><span class="n">key</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">KEY_RETURN</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">count</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">break</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="mh">0x8B412ED</span><span class="p">:</span><span class="w"> </span><span class="c1">// red</span>
<span class="w"> </span><span class="n">key</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">KEY_BACKSPACE</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">count</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">break</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="mh">0x8B4B24D</span><span class="p">:</span><span class="w"> </span><span class="c1">// green</span>
<span class="w"> </span><span class="n">key</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sc">' '</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">count</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">break</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="mh">0x8B44AB5</span><span class="p">:</span><span class="w"> </span><span class="c1">// yellow</span>
<span class="w"> </span><span class="n">key</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">KEY_ESC</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">count</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">break</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="mh">0x8B450AF</span><span class="p">:</span><span class="w"> </span><span class="c1">// blue</span>
<span class="w"> </span><span class="n">key</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sc">'s'</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">count</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">break</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="mh">0xFFFFFFFF</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="n">count</span><span class="o">++</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">break</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">default</span><span class="o">:</span><span class="w"></span>
<span class="w"> </span><span class="n">key</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">-1</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">break</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">((</span><span class="n">key</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="mi">-1</span><span class="p">)</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="p">(</span><span class="n">count</span><span class="o">!=</span><span class="mi">1</span><span class="p">))</span><span class="w"> </span><span class="c1">// if count = 1, it is the first key repeat, so ignore it.</span>
<span class="w"> </span><span class="n">Keyboard</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">key</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">irrecv</span><span class="p">.</span><span class="n">resume</span><span class="p">();</span><span class="w"> </span><span class="c1">// Receive the next value</span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div></td></tr></table></div>
<p>Total cost £4.10, total time 45 minutes. Sorted!</p>
<p><img alt="Zappp" src="https://thinkl33t.co.uk/45-minute-project-ps410-xbmc-remote-receiver/images/IMG_20140301_121939.jpg" /></p>3D printing - Bandsaw Fence2013-03-21T15:23:00+00:002013-03-21T15:23:00+00:00thinkl33ttag:thinkl33t.co.uk,2013-03-21:/3d-printing-bandsaw-fence<p>I spent some time earlier in the week getting the bandsaw at <a href="http://hacman.org.uk">Hackspace
Manchester</a> working, so now its cutting again!
The main problem with the bandsaw is cutting straight, as it was an
ebay purchase it diddnt come with a fence, so there was nothing to run
the cut material against. This model of bandsaw hasnt been made in
around 30 years, so trying to buy a new one will be impossible, and ebay
is too much hard work.</p>
<p>Though we do have a 3d printer... and a workshop. Idea!</p>
<p>Step one was to have a look at the bandsaw. It has a channel running
along the front , so I took some measurements to see what I was working
with.</p>
<p><img alt="channel" src="http://farm9.staticflickr.com/8232/8577868988_f31b476c7b.jpg" />
<img alt="paper" src="http://farm9.staticflickr.com/8094/8576768033_20e7125921.jpg" /></p>
<p>So, i had the measurements, it was time to take to my CAD software and
design something to fit in the channel. My choice for this is OpenSCAD.
I used it to first create the shape of the channel, then to carve this
shape out of a block.</p>
<p><img alt="openscad1" src="http://farm9.staticflickr.com/8093/8577868606_5a464b3139.jpg" />
<img alt="openscad2" src="http://farm9.staticflickr.com/8387/8577868598_733b0b8278.jpg" /></p>
<p>I extruded this to a few mm wide, then printed it to test. There was a
bit of tweaking needed to get it to fit exactly, so i ended up doing 4
iterations with the sizes tweaked slightly.</p>
<p><img alt="testpieces" src="http://farm9.staticflickr.com/8099/8577868660_9215fdace0.jpg" /></p>
<p><img alt="testprint" src="http://farm9.staticflickr.com/8103/8576767789_00d9ccd2df.jpg" />
<img alt="test" src="http://farm9.staticflickr.com/8087/8577868768_3400b94299.jpg" /></p>
<p>Once i had one that fitted, i printed it out extruded to 20mm to check
it would fit and slide correctly.</p>
<p><img alt="testfits" src="http://farm9.staticflickr.com/8377/8577868700_be3556e79d.jpg" /></p>
<p>It did, so i moved onto designing the actual fence. Step one was to cut
some aluminium extrusion to size, and measure it. A month or so ago I
had managed to womble a nice straight piece of 16mm x 16mm 3.2mm thick
L channel, which was pretty much the perfect size. I cut this to size,
and modelled it in openscad.</p>
<p><img alt="cad" src="http://farm9.staticflickr.com/8102/8577868624_06d79a8613.jpg" /></p>
<p>The actual cad modelling took a couple of hours of tweaking, but i the
above picture shows the basic steps.</p>
<p>First off i extruded my clamp to 50mm wide, and added a wedge to the
side of it. 50mm gives enough width for it to sit in the runner, and
counteract twisting force from the back of the fence being pushed on.
The wedge is to give support to the top part of the L channel.</p>
<p>Second, I added two captive nuts and holes for M5 bolts. Mainly because
we have a massive bag of M5 hex-head bolts that are perfect for printed
thumbscrews. Theoretically i could have threaded into the ABS directly,
but i felt this wouldnt last, so embedding a nut seemed like the best
option.</p>
<p>Third, i carved out the hole for the L channel. This leaves a bit of an
odd shaped unsupported piece, which may be weak. Because this piece will
be in the channel, i decided to leave it, as it'll make measuring up on
the built-in ruler more accurate.</p>
<p>Lastly, i added some pilot holes for attaching the aluminium to the 3d
printed part. i decided to use 3mm x 12mm self tapping screws for this,
because i had them on hand, and they can be countersunk fairly easily.</p>
<p><img alt="printed" src="http://farm9.staticflickr.com/8106/8577868870_a27193a163.jpg" /></p>
<p>I test-assembled the whole thing in the vice, it fitted nicely in the
channel, so it was ready for connecting together. I marked, center
punched, drilled and countersunk the holes for the 3 screws that hold
the whole thing together. Add some screws and we're sorted!</p>
<p><img alt="fits" src="http://farm9.staticflickr.com/8528/8576768083_bf5fac8104.jpg" /></p>
<p>Of course, i had to do a test cut at this point, so some of the scrap
acrylic pile was chopped into little strips.</p>
<p><img alt="cutting" src="http://farm9.staticflickr.com/8378/8576768155_f6c9a1fa09.jpg" /></p>
<p>Woohoo, it worked! All it needed to be complete is some knobs. So i
headed over to thingiverse to find a knob that'll fit nicely over an m5
nut... and found nothing useful. No worries, i just OpenSCADdded one
up.</p>
<p><img alt="knob" src="http://farm9.staticflickr.com/8385/8576768051_63bb55da7d.jpg" /></p>
<p><img alt="finished" src="http://farm9.staticflickr.com/8508/8577868956_d4ce86dab5.jpg" /></p>
<p>So there it is, a useful thing i've made on the 3d printer that wasnt a
part for a 3d printer!</p>
<p>Source files (stl, openscad) are available on <a href="https://github.com/thinkl33t/Things/tree/master/BandSaw%20Fence">My
GitHub</a> </p>Minimus Pin Functions v1.22012-09-14T12:42:00+01:002012-09-14T12:42:00+01:00thinkl33ttag:thinkl33t.co.uk,2012-09-14:/minimus-pin-functions-v12<p><img alt="Minimus Pin Layout v1.2" src="http://farm9.staticflickr.com/8455/7985314192_ef2fe72e2a.jpg" /></p>
<p>Got fed up of not having the interrupt identifiers on the original
minimus pinout i made, so here is version 1.1 with interrupt numbers
labelled!</p>
<p>Stay tuned for a pinout of the Minimus 32K, as UK hackspacers have just
bought over 300 of them to play with!</p>
<p><strong>UPDATE</strong>: I have checked the atmega32u2 datasheet, and all pins and
functions are the same as the at90usb162, so the above sheet will work
for both. Yay!</p>
<p><strong>UPDATE</strong>: Oops, had the LED pins switched. fixed in v1.2</p>The PANIC Button2012-02-19T09:37:00+00:002012-02-19T09:37:00+00:00thinkl33ttag:thinkl33t.co.uk,2012-02-19:/the-panic-button<p>Ok, bit of explanation first. We have an iMac set up as a 'democratic
jukebox' at <a href="http://www.hacman.org.uk">Hackspace Manchester</a>. The idea being
that anyone can put music on it, and it plays the entire library on
shuffle during our hack sessions for a bit of background music.</p>
<p>The problem is, of course, some people have an... odd taste in music, so
sometimes the jukebox ends up flipping between Aqua and Cannibal Corpse
for ten minutes, and the horror of this was just too much!</p>
<p>Enter the PANIC button.</p>
<p><img alt="PANIC" src="http://farm8.static.flickr.com/7054/6901421941_62e1405295.jpg" /></p>
<p>The button uses a <a href="http://wiki.hacman.org.uk/Minimus">minimus</a> board.
The minimus is a carrier for the AT90USB162, an AVR microcontroller with
onboard USB hardware, which means it can be programmed to show up as any
USB device. Before getting the button I modified one of the pieces of
LUFA demo software, a media keyboard, and stripped it down to just read
the one button on the minimus. When the button is pressed, it sends the
keycode for next track. </p>
<p>The button's housing is a <a href="http://www.play.com/Gadgets/Gadgets/4-/5601209/The-Panic-Button/Product.html">joke
button</a>
that played an alarm and flashed when pressed, I ripped its guts out to
get to the switch. After finding the switch contacts on the original
board, i soldered on two wires to connecto to the AVR.</p>
<p><img alt="Inside" src="http://farm8.static.flickr.com/7183/6901422311_13f6fc6fdb.jpg" /></p>
<p>Next, I stripped off the USB connector from the minimus, and added a
1m USB lead directly to the pads, to make it fit in the old speaker
housing section of the button. I connected the leads from the button to
PD7 and GND on the minimus, the same as the onboard button. This has
the handy side effect that if the button is pressed while being plugged
in, it boots into DFU mode, allowing me to upgrade the firmware easily.</p>
<p><img alt="Minimus" src="http://farm8.static.flickr.com/7048/6901422707_1d5ce9d67c.jpg" /></p>
<p>I cut a slot in the casing for the wire to escape, and added a couple of
cable ties for strain relief.</p>
<p>Press Button, Song Skips, Panic averted!</p>
<p><img alt="Finished" src="http://farm8.static.flickr.com/7070/6901498651_594e993f0e.jpg" /></p>Minimus Pin Functions2012-02-13T13:04:00+00:002012-02-13T13:04:00+00:00thinkl33ttag:thinkl33t.co.uk,2012-02-13:/minimus-pin-functions<p><img alt="Minimus Pin Functions" src="http://farm8.staticflickr.com/7202/6869267721_c6540aa6a7_o.png" /></p>
<p>Whipped up this quick cheat sheet with all the different functions each
minimus pin can perform.</p>Speak and Spell - Keyboard Matrix2011-01-27T00:20:00+00:002011-01-27T00:20:00+00:00thinkl33ttag:thinkl33t.co.uk,2011-01-27:/speak-and-spell<p><img alt="Speak and Spell" src="http://farm6.static.flickr.com/5253/5390930693_2c334d1131.jpg" /></p>
<p>Tonight i spent some time at <a href="http://hacman.org.uk">Hackspace Manchester</a>
reverse engineering the keyboard matrix on our speak and spell,
in preparation for hooking it up to an MBED. Since nobody else has
released this information (as far as i can tell), here is the pinout:</p>
<table>
<thead>
<tr>
<th>pin</th>
<th>3</th>
<th>4</th>
<th>5</th>
<th>6</th>
<th>7</th>
<th>8</th>
<th>9</th>
<th>10</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>u</td>
<td>k</td>
<td>off</td>
<td>a</td>
<td>f</td>
<td>?</td>
<td>p</td>
<td>z</td>
</tr>
<tr>
<td>2</td>
<td>v</td>
<td>l</td>
<td>go</td>
<td>b</td>
<td>g</td>
<td>&</td>
<td>q</td>
<td>`</td>
</tr>
<tr>
<td>11</td>
<td>w</td>
<td>m</td>
<td><</td>
<td>c</td>
<td>h</td>
<td>???</td>
<td>r</td>
<td>#</td>
</tr>
<tr>
<td>12</td>
<td>x</td>
<td>n</td>
<td>"</td>
<td>d</td>
<td>i</td>
<td>:)</td>
<td>s</td>
<td>/</td>
</tr>
<tr>
<td>13</td>
<td>y</td>
<td>o</td>
<td>_</td>
<td>e</td>
<td>j</td>
<td>on</td>
<td>t</td>
<td>return</td>
</tr>
</tbody>
</table>
<p>This means that when the 'off' button is pressed, for example, pin 1 and
pin 5 will be connected together.</p>
<p>To read a matrix keyboard like this, we write some code that steps
through the 'down' set of pins (1, 2, 11, 12, 13), holding them low one
at a time, then checks each of the other pins (3-10) to see if anything
is being held low. If so, we perform a lookup on the table above.</p>AVR GCC Bit Manipulation Macros2008-07-27T16:44:00+01:002008-07-27T16:44:00+01:00thinkl33ttag:thinkl33t.co.uk,2008-07-27:/avr-gcc-bit-manipulation-macros<p>These are some macros i originally found on
<a href="http://avrfreaks.net">avrfreaks</a> for bit manipulation. I have posted
them here in case they are useful to anyone.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span>
<span class="normal">7</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="cp">#define bit_get(p,m) ((p) & (m))</span>
<span class="cp">#define bit_set(p,m) ((p) |= (m))</span>
<span class="cp">#define bit_clear(p,m) ((p) &= \~(m))</span>
<span class="cp">#define bit_flip(p,m) ((p) \^= (m))</span>
<span class="cp">#define bit_write(c,p,m) (c ? bit_set(p,m) : bit_clear(p,m))</span>
<span class="cp">#define BIT(x) (0x01 << (x))</span>
<span class="cp">#define LONGBIT(x) ((unsigned long)0x00000001 << (x))</span>
</code></pre></div></td></tr></table></div>SQL Fun2006-02-10T13:46:00+00:002006-02-10T13:46:00+00:00thinkl33ttag:thinkl33t.co.uk,2006-02-10:/sql-fun<p>Had a bit of fun today, trying to pick out only singleton entries from a
database table, finding the lowest unique bid for the reverse auction
app i'm doing at work. this is what i came up with:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span>
<span class="normal">2</span>
<span class="normal">3</span>
<span class="normal">4</span>
<span class="normal">5</span>
<span class="normal">6</span>
<span class="normal">7</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"></span>
<span class="k">FROM</span><span class="w"> </span><span class="n">bids</span><span class="w"></span>
<span class="k">WHERE</span><span class="w"> </span><span class="n">auction_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="w"></span>
<span class="k">GROUP</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">value</span><span class="w"></span>
<span class="k">HAVING</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="k">COUNT</span><span class="p">(</span><span class="w"> </span><span class="n">value</span><span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="mi">1</span><span class="w"> </span><span class="p">)</span><span class="w"></span>
<span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">value</span><span class="w"> </span><span class="k">ASC</span><span class="w"></span>
<span class="k">LIMIT</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"></span>
</code></pre></div></td></tr></table></div>