Migrating From Machine to Machine with Smokeping (and Armbian)

After having purchased an Orange Pi I have been looking for services that it can host on my network. One of the first services that come to mind for me is Smokeping. I love Smokeping it does one thing, and it does it well a true embodiment of the Unix Philosophy.

Enough glorification of Smokeping how do we get it running.

In this case I wasn’t starting from scratch. I already have an installation running on a Raspberry Pi elsewhere in my network. My first attempt had me copying all the files in the /etc/smokeping directory over to the Orange Pi directly. However this did not work. What I came to find is that the RRD files are architecture-specific, as it turns out, while both the Raspberry Pi and Orange Pi are ARM-based, they are not the same version of ARM and hence the RRD files are not directly compatible.

Starting fresh is no good here because I have years of Smokeping data in my existing install that I don’t want to lose; so how to migrate that data.

Scouring some obscure Smokeping mailing lists I was able to put together this procedure.

NOTE: I’m assuming preshared keys have already been setup between the root account of the old and new machines.

#######################
# On the New Machine
####################### 
sudo su
# Install Smokeping
apt-get install smokeping rrdtool sendmail -y
systemctl stop smokeping
#######################
# On the Old Machine
#######################
sudo su

echo <<EOT >/tmp/smokeping_backup.sh
#!/bin/bash

NEWMACHINE="192.168.1.100"

cd /var/lib/smokeping
echo "Stoping SMOKEPING"
service smokeping stop

echo "GENERATING XML..."
rm -v ./*/*.xml
for f in ./*/*.rrd; do echo ${f}; rrdtool dump ${f} > ${f}.xml; done

echo "SENDING FILES TO NEW MACHINE..."
scp -rv ./* root@$NEWMACHINE:/var/lib/smokeping/
scp -v /etc/smokeping/config.d/General root@$NEWMACHINE:/etc/smokeping/config.d/General
scp -v /etc/smokeping/config.d/Targets root@$NEWMACHINE:/etc/smokeping/config.d/Targets
scp -v /etc/smokeping/config.d/Probes root@$NEWMACHINE:/etc/smokeping/config.d/Probes

echo "CLEANING-UP AND RESTARTING SMOKEPING..."
rm -v ./*/*.xml
service smokeping start

echo "DONE!"
EOT

chmod +x /tmp/smokeping_backup.sh
/tmp/smokeping_backup.sh
#######################
# On the New Machine
#######################
sudo su
cat <<EOT > /tmp/smokeping_restore.sh 
#!/bin/bash

# convert XML to RRD
cd /var/lib/smokeping

systemctl stop smokeping

echo "REMOVING ANY EXISTING RRD FILES..."
rm -v ./*/*.rrd

echo "CONVERTING XML FILES BACK INTO RRD..."
for f in ./*/*.xml; do echo ${f}; rrdtool restore $f `echo $f |sed s/.xml//g`; done

echo "REMOVING Interim XML FILES..."
rm -v ./*/*.xml
sleep 1

echo "CHANGING OWNERSHIP ON SMOKEPING FILES..."
chown -v smokeping:www-data /var/lib/smokeping/*/*.rrd
chmod 755 -Rv /var/lib/smokeping

echo "STARTING SMOKEPING."
systemctl restart apache2
systemctl start smokeping

echo "DONE!"
EOT

chmod +x /tmp/smokeping_restore.sh
/tmp/smokeping_restore.sh

This can convert the RRD files to an intermediary XML format that can then be converted back to RRD on the migration target, on Armbian, even with Smokeping installed, rrdtool itself was not installed. After installing rrdtool I operated on the subdirectories full of RRD files in the /var/lib/smokeping/ directory. Once converted to XML I moved the XML files in place on the new machine and converted them back to RRD.

These scripts were used on my machines, hopefully they can help you too!

 

Advertisements

Should I Leave The Window Open?

As the days start to get cooler again in North Carolina I’m always left with this conundrum… should I leave the window open or not?

On one hand I could feel a pleasant draft that cools me and my wife down all evening without having to pay for air conditioning, on the other hand I could end up waking up to a soaked wall as it’s rained in the middle of the night or the air conditioning has kicked on and I’m pumping lovely cool air that I’ve just paid for directly out the open window.

#firstworldproblems…. I know but it is never the less something I think about. So what can be done here? I’ve got a Nest thermostat and am a reasonably competent scripter.

Here is what I put together, a quick webpage that you can hit from any device on the home network and displays the following info…

selection_064

Turns out there are a few libraries that help us get off to a useful start.

  • weather-cli — this one allows us to pull real time hourly weather info for the next 24 hours based on precise location.
  • flask — flask can be used to quickly serve up a webpage in python
  • python-nest — this is used to get/set data with Nest thermostats.

Interestingly, python-nest and the nest-API  provides some hourly weather info back in a pretty useful form. However it is missing one pivotal piece of data… which is the actual weather conditions for those individual hours, is it raining? is it sunny? that very important datapoint is not present and pretty much the primary reason I’m using weather-cli here.

There’s not a ton of documentation on weather-cli but for the few things that I wanted to know that weren’t documented, there’s always the source-code, and the code was helpful here.

Installing Software

sudo apt-get install python-pip
sudo pip install pip --upgrade
sudo pip install setuptools --upgrade
sudo pip install  weather-cli flask python-nest

Setting Up Weather-CLI

To use weather-cli, you’re going to need a Forecast.io API key, register here to obtain one. With the basic free plan, you have 999 API calls per day for free, enough to check the weather a couple hundred times per day which is more than enough for me.

To get weather-cli set up we need to use the setup argument.

pi@underhousepi ~/scripts/weather_predictor $ sudo weather-cli --setup

Enter your forecast.io api key (required):xxxxxxxxxxxxxxxxx
Warning:
The script will try to geolocate your IP.
If you fill the latitude and longitude, you avoid the IP geolocation.
Use it if you want a more acurated result, use a different location,
or just avoid the IP geolocation.
Check your latitude and longitude from http://www.travelmath.com/

Enter the latitude (optional): 36.982917
Enter the longitude (optional): -75.402301
generating config file...
setup complete

Once setup is complete we can simply call weather-cli and it will return data for us based on the location we used for initial setup.

The rest is writing a quick flask app. Here is the code for that in the gist below. You’ll notice the flask app calls a template. I’ve placed that index.html template in a templates directory as shown below.

https://gist.github.com/ericpulvino/b7753c1f598642f3bbd64895553232db

Note that I’m also calling the nest api to query the target temperature of the nest device and using that as a basis for whether or not the window open. You could hard-code that value alternatively if you don’t have a nest or for testing purposes. I also have more than one nest in my home so in line 29 I’m calling devices[1] to get to query the second nest in my environment. You may want to change this to devices[0] or another value based on your output from the python-nest api’s documentation page.

user@raspi4 ~/scripts/window_open $ tree
.
├── templates
│   └── index.html
└── window_open.py

Here is the code for the template too.

https://gist.github.com/ericpulvino/8196a057493dec94d0f48c495ad5f706

Hope this might save you a few minutes in your search for cool air at an affordable price.

Autoplaying Files in Kodi Isengard

Almost all the affects of the change in naming from XBMC to Kodi have been realized at this point except for a few small areas. One of those areas is using the on-box API to send commands into Kodi or automate certain actions.

In my case I was trying to automatically play a file as soon as my Kodi player boots. To do that you simply place a file with the right content in the right place.

My System Details:

  • Hardware: Raspberry Pi 2 /w Edimax EW-7811UTC AC600 Wifi Adapter
  • Software: OpenELEC v6.0.3 (Kodi 15.2 Isengard)

Specifically, create a file called autoexec.py in the /storage/.kodi/userdata/ directory.

import xbmc
xbmc.executebuiltin( "PlayMedia(smb://192.168.1.20/usenet/Baby_Stream.strm)" )
xbmc.executebuiltin( "PlayerControl(repeat)" )

If you’re trying to test the script on the CLI via ssh by using the python interpreter you might notice that calls to import the xbmc module fail.

OpenELEC:~ # python
Python 2.7.3 (default, Feb 29 2016, 21:17:05) 
[GCC 4.9.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import xbmc
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
ImportError: No module named xbmc
>>>

This is expected because the xbmc module is not exposed to the default python path.

Testing your Script:

In order to test your script try having Kodi send it through it’s python namespace using the kodi-send command:

OpenELEC:~ #kodi-send -a "RunScript(/storage/.kodi/userdata/autoexec.py)"

Quick and easy automation in Kodi. To see other functions that can be called either via kodi-send or  automated in xbmc.executebuiltin statements, check Kodi’s official docs on the subject.

Basic Raspberry Pi Home Wifi Router

The Goal of This Post:

This post is an extension to Jacob Salema’s Guide that was picked up by Lifehacker. My main issue with his post is that he refers to the end result as a wireless router, which is not entirely accurate. This device is not meant to be internet-facing and is really more of a wireless/ethernet bridge with the configurations provided.

My goal here was to extend what was provided in his initial post and make it suitable for placing a Raspberry Pi directly behind a cable modem and fully exposed to the internet.

raspberry_pi_pi_ap
image kindly borrowed from adafruit

Materials:

  • Raspberry Pi B (gen 2 model) any Raspberry Pi could potentially work here though
  • Edimax EW-7811Un
  • Short piece of Ethernet (to connect to cable modem)
  • Power Adapter and cord for Pi
  • SD card with Raspbian installed
  • (Optional) USB Keyboard and HDMI Monitor to access the PI. All of these steps can be performed over SSH with a little creativity however.

Performance:

The Raspberry Pi’s performance is limited by the USB throughput of the WLAN adapter; which on the Raspberry Pi is a USB2.0 hub limited to a theoretical maximum of 480mbps, so you’ll never be able to pull gigabit ethernet here but this will get the job done for small sites. However if you have really crappy broadband like I do in this location the chokepoint will be the crappy broadband and not the Raspberry Pi.

I have maxed out my crappy broadband connection with the following speedtest.net performance results:

A BLAZING — 2.78mbps download
A SIMILARLY BLAZING — 1.28mbps upload

I repeated the same speedtest.net tests using a top-notch Lenovo X1 Gen3 laptop and got the exact same results so there is no lag using the raspberry pi here (for this crappy broadband connection). Since my broadband is so crappy here I’m using 802.11G wifi which won’t choke anything.

Note: I probably wouldn’t trust this for anything over 10mbps. I think the Raspberry Pi 2 with 802.11n wifi could handle a standard 40mbps connection based on some of the numbers I’m seeing here.

1). Required Installs:

Perform these first before any of the other steps.

sudo apt-get update -y
sudo apt-get install rfkill zd1211-firmware hostapd hostap-utils iw dnsmasq bridge-utils -y

 

2). Interfaces Configuration (/etc/network/interfaces):

Modify the interfaces file (/etc/network/interfaces) as shown below.

allow-hotplug wlan0
allow-hotplug eth0

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet dhcp
 
auto wlan0
iface wlan0 inet static
   address 192.168.2.1
   netmask 255.255.255.0

3). DNSmasq Configuration (/etc/dnsmasq.conf):

Modify the DNSmasq configuration file to look exactly like what you see below.

Feel free to modify your domain.

domain=example.com
bogus-priv
no-resolv
server=8.8.8.8
server=8.8.4.4
cache-size=10000
interface=wlan0
dhcp-range=192.168.2.2,192.168.2.254,12h

4). HostAPD Configuration (/etc/hostapd/hostapd.conf):

Modify the configuration file for hostapd to have the following content.

Notice we’re using the “hw_mode=g” option here this is because my limited internet connection couldn’t support max throughput of a wifi-N connection so there would be minimal benefit. If you’re interested in N and have a Raspberry Pi2 and a faster internet connection it may make sense to enable that in your scenario.

Also feel free to modify the SSID to whatever you like and modify the password too, you’ll need at least 8 characters for the password. The channel can also be set to any value between 1-14 (1,6,11,14 are common in the USA)

interface=wlan0
driver=rtl871xdrv
country_code=US
ctrl_interface=wlan0
ctrl_interface_group=0
ssid=NETWORKNAME
hw_mode=g
channel=1
wpa=3
wpa_passphrase=password
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP
rsn_pairwise=CCMP
beacon_int=100
auth_algs=3
macaddr_acl=0
wmm_enabled=1
eap_reauth_period=360000000


5). HostAPD Default Configuration (/etc/default/hostapd):

Modify the defaults file for hostapd (/etc/default/hostapd) to have the same DAEMON_CONF line. The type of quotes used to surround the /etc/hostapd/hostapd.conf file are mission critical; if you use the wrong kind of quotes, hostapd will not start. You can debug the start of hostapd with the command “hostapd -d /etc/hostapd/hostapd.conf” which puts it into debugging mode.

# Defaults for hostapd initscript
#
# See /usr/share/doc/hostapd/README.Debian for information about alternative
# methods of managing hostapd.
#
# Uncomment and set DAEMON_CONF to the absolute path of a hostapd configuration
# file and hostapd will be started during system boot. An example configuration
# file can be found at /usr/share/doc/hostapd/examples/hostapd.conf.gz
#
DAEMON_CONF="/etc/hostapd/hostapd.conf"

# Additional daemon options to be appended to hostapd command:-
# -d show more debug messages (-dd for even more)
# -K include key data in debug messages
# -t include timestamps in some debug messages
#
# Note that -B (daemon mode) and -P (pidfile) options are automatically
# configured by the init.d script and must not be added to DAEMON_OPTS.
#
#DAEMON_OPTS=""

6). Reboot the Pi

Reboot the Pi to apply the interfaces config, start the hostapd daemon, start dnsmasq daemon. After the reboot you should see your new wireless SSID being broadcast and you should be able to login to it too with your provided password. At this point we need to proceed with the IP tables configuration to setup routing and PAT (port address translation).

7). Enable NAT and Routing Non-Persistently

Execute the following commands to enable NAT and routing for this particular session (we will make these settings persistent across reboots in steps 9 and 10).

#Enable Routing
sudo sysctl -w net.ipv4.ip_forward=1

#Apply the NAT/PAT config 
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

Routing allows the Pi to move (or “route”) packets between the two interfaces (Wlan0 and Eth0). Making the Pi a Router allows packets which come in on the Wlan interfaces to be forwarded through the Pi and out the Eth0 port.

NAT stands for Network Address Translation. In this case we’re technically performing PAT or Port Address Translation because we are aggregating the connections and streams of multiple downstream/client IP addresses across a single public IP address using different source ports. As a result packets will be re-written as they pass through a NAT router to be sourced from the public IP address of the NAT router. This re-write hides the original source IP address of the client which generated the traffic. In order to keep track of which stream should be returned to which client, the NAT router keeps a table that maps the Egress destination port to an client IP and source port. This table is called a NAT translation table. You can view the content of the Translation table at any time with the following command:

cat /proc/net/ip_conntrack

8). IP Tables Configuration:

IPtables is a program which interacts with the networking stack in the Linux kernel and tells the kernel how to handle incoming network traffic. There are all kinds of customizations that can be made to an internet facing router. What I show below are pretty basic and generally recognized as safe defaults.

Apply the default config by pasting the following commands into the command line on your device:

#allow incoming traffic from the localhost
sudo iptables -A INPUT -i lo -j ACCEPT
#explicitly allow all icmp/ping traffic
sudo iptables -A INPUT -p icmp -m icmp --icmp-type any -j ACCEPT
#explicitly allow all traffic that is already established
sudo iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
#Allow new traffic only from the local/WLAN network
sudo iptables -A INPUT -i wlan0 -m state --state NEW -j ACCEPT
#Drop all other new traffic
sudo iptables -A INPUT -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -m state --state NEW -j DROP<
#Drop all fragments
sudo iptables -A INPUT -f -j DROP 
# Drop XMAS packets
sudo iptables -A INPUT -p tcp --tcp-flags ALL ALL -j DROP
# Drop NULL packets
sudo iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP
#allow our dns traffic 
sudo iptables -A INPUT -i wlan0 -p udp -m udp --sport 53 -j ACCEPT
#log everything else that is about to get dropped. 
sudo iptables -A INPUT -j LOG --log-prefix "IPTABLES Dropped: " --log-level 7 
#drop everything else that has made it this far down and not matched. 
sudo iptables -A INPUT -j DROP

You can see the presently applied iptables rules using the “iptables-save” command with sudo.

pi@raspberrypi:~ $ sudo iptables-save
# Generated by iptables-save v1.4.21 on Thu Dec 24 17:37:34 2015
*nat
:PREROUTING ACCEPT [7039:855804]
:INPUT ACCEPT [1138:80267]
:OUTPUT ACCEPT [1167:81793]
:POSTROUTING ACCEPT [21:3945]
-A POSTROUTING -o eth0 -j MASQUERADE
COMMIT
# Completed on Thu Dec 24 17:37:34 2015
# Generated by iptables-save v1.4.21 on Thu Dec 24 17:37:34 2015
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [444346:360889024]
:OUTPUT ACCEPT [4390:510099]
-A INPUT -i lo -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type any -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i wlan0 -m state --state NEW -j ACCEPT
-A INPUT -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -m state --state NEW -j DROP
-A INPUT -f -j DROP
-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,PSH,ACK,URG -j DROP
-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP
-A INPUT -i wlan0 -p udp -m udp --sport 53 -j ACCEPT
-A INPUT -j LOG --log-prefix "IPTABLES Dropped: " --log-level 7
-A INPUT -j DROP
COMMIT
# Completed on Thu Dec 24 17:37:34 2015

Once you’ve setup the rules you’d like, and you’ve tested that they behave as expected, proceed to step 8 to save the IP tables rules.

9). Make the IPtables Settings Persistent

During the installation of the iptables-persistent program it will ask you if you want to save the presently applied rules, select YES.

sudo apt-get install iptables-persistent -y

Once the rules are saved, they can be edited at the /etc/iptables/rules.v4 (for normal IPv4 traffic). If you’re testing your iptables changes by applying the rules directly using the iptables syntax in step 7 then as you make changes, they can be made persistent by writing the output of the “iptables-save” command directly to the rules.v4 file like so.

sudo iptables-save > /etc/iptables/rules.v4

10). Enable Routing Persistently

The following change allows the Raspi Router to move packets from one interface (wlan0) to another (eth0) by making the device a router.

sudo sed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/g' /etc/sysctl.conf

Halloween Home Automation

Now that my son is 13 months old I finally had  at least a moment or two to work on a Halloween display so naturally I wanted to get some automation activities integrated with my platform of choice, the Raspberry Pi.

Note: My code is available at the bottom of the project.

My goal for this project was to use every trick I could with a minimal budget to scare as many neighborhood kids as I could. Mission Accomplished.

Here was the rough order of operations.

  1. Motion sensor runs in a loop looking for motion.
  2. When motion is detected start the smoke machine smoking immediately and run for all additional events in the list.
  3. Wait for a moment or two then cut all of the exterior property lighting.
  4. Wait for another moment then play one of the spooky sounds from the hidden speakers in the bushes very loudly.
  5. Revive the property lighting.
  6. Wait 15 seconds then repeat.

Controlling the Smoke Machine

The first order of business was to reverse engineer how the smoke machine remote actually works. Two years ago I had purchased the biggest non-commercial smoke machine I could find as part of my annual Halloween budget. That first year I just used the included remote but even then I knew I would eventually have to figure out how to automate the smoking functionality. I know they also sell remotes that don’t have the simple on/off button like mine has; instead you can pay $16.99 for a remote with an interval smoking function from a store like Spirit Halloween– but again, I didn’t want an interval– smoke juice is expensive I want to use it only when a person is actually nearby to enjoy it. So this led me down the path of figuring out how to control it.

Using a standard multimeter set to measure resistance I determined what each of the 3 pins in the remote did and determined that in order to produce smoke I needed simply to bridge two of them. This is the enterance-point for my 4-way relay I had purchased a year ago for just such a task.

IMG_20151031_120801

Hooking up the relay to bridge the necessary pins I was able to produce smoke — SUCCESS! Now to set this up a little more permanently, as it turns out the remote is actually switching 120v wall power so extra care is needed when wiring this up to do it right. I obtained some extra lumber I had from another project and started building a control board that everything would be permanently affixed to.

Breadboarding with 120v

At this point, I’ve used a combination of drilling and ziptieing to secure the raspberry pi (with case), breadboard, and relay bank to the control board which was a sheet of 1/4 inch MDF.

Adding Motion Sensing

The next phase was to setup the smoke machine to fire when motion was detected. To accomplish this I used a cheap PIR sensor that I had purchased off of E-bay last year for about $3.00 via the direct from China route.

It took a bit of adjusting on the PIR sensor to get it setup correctly for my application. In this case there are two adjustments, one is sensitivity, and the other is time-delay (how long the signal wire stays high when motion is detected). For this project I essentially set the PIR sensor to maximum sensitivity and the shortest time delay for a hair-trigger. I wanted to maximize the granularity of the sensor and push the false positive detection into software where I could control it with variables in a program instead of by turning physical knobs.

Once configured I did a bit of trial and error by moving back and forth in front of the sensor in my garage. My neighbors would probably have thought me crazy moving back and forth in my garage for 15 minutes but they know better by now. I found that the effective range of the sensor was about 15 feet.

Now that I had the sensor working with some test code (included PIR_test2.py) it was time to setup some spooky noises to be triggered with the motion sensing.

Setting up the Audio

I wanted to use the included headphone jack on the Pi to play audio into a little class T amplifier (I swear this used to cost just under $20 when I bought it, it has AMAZING PERFORMANCE for the price) and an old pair of extra speakers that had been collecting dust around my workshop.

IMG_20151108_140653

As it turns out there was an issue with some of the updates I had performed most recently on my Pi that left my audio broken, after a bit of soul-searching on google for the error message I saw when trying to use Aplay to play a sample audio file I decided to do some updates and see if that would solve the issue.

sudo apt-get update -y && sudo apt-get upgrade -y

Sure-enough my audio was now working with Aplay after the dust cleared from the updates and a reboot was performed.

At this point I began searching the net and collecting spooky noises from various sound effect websites. I collected all ten of the wav files which made the final cut and renamed them from 1-10 (My code actually randomly generates an integer from 1-10 and plays the corresponding file 1.wav – 10.wav for simplicity).

Adding The Exterior Lighting Control

Since the majority of my exterior property lighting is already wired for automation with WEMOs I wanted to include this in my Halloween setup. I bought 3 red LED bulbs and went to town replacing the exterior lights with an eerie red glow. They actually created a lovely scary effect. The bulbs were certainly not cheap though.

Regarding the code for the WEMOs, I already had this code built from various WEMO projects but I wanted to do something very simple for this project, just an on/off, no database tracking, no fancy behaviors, no logging etc. so I re-wrote some of the code to run a little faster and added a little pair of bash scripts (allon.sh and alloff.sh) to bring up multiple switches in rapid succession, the effect is truly instant when kicked off in this manner so I was very happy.

Carving the Monster Pumpkin

I’ll have to add a picture of the beast when it was all carved but I picked up a gigantic pumpkin from the Raleigh State Farmer’s Market for $50. I’ve always wanted a pumpkin this big. I figured with this no one would be able to doubt my Halloween spirit. This pumpkin was so large that it took two grown men to move it on a towel. I honestly could not lift it myself which was very emasculating but also thrilling that it was so incredibly huge.

IMG_20151004_152307

I know I have a carved picture of it somewhere but I can’t seem to find it at the moment so I’ll post that bit later. These super huge pumpkins are actually a different species and produce really nasty seeds that you can’t cook up which is an interesting fact I learned when I opened this bad-boy up.

When the scary face was all carved I then carved a 3inch diameter hole in the back for the dryer hose…. dryer hose you ask?  Of course you need dryer hose when you’re…

Building the Fog Chiller

One of my favorite pieces of Halloween tech is a good fog chiller. When you cool the fog down to a temperature that is lower than the outside air it will actually sink down to the ground and drift along making an extra scary effect. This was a trick I masterminded when I was organizing the annual public Haunted House in my fraternity days. The effect is great and luckily I had an old 50 gallon plastic drum that I had purchased off of Craigslist several years ago that was a perfect fit for the project.

IMG_20151031_202446

Essentially you cut a hole in your container, coil the dryer-hose around within the container then run the hose to your destination which in my case was the back of the gigantic pumpkin. I also added a string of green LED lights in the pumpkin as well to give the fog a cool effect.

Lastly you fill the container with a combination of ice and water. I actually began saving up ice from my refrigerator and storing it in my chest freezer several weeks in advance in order to be able to fill up the drum and not spend any direct dollars from the Halloween budget on frivolous things like store-bought ice.

Putting All the Pieces Together With Code

Now that all the individual pieces were functional all that was left to do was to write the code to unify the individual pieces and create the coordinated show.

This code can be found in the halloween.py file.

IMG_20151108_140600

Results

The effect was awesome! Many neighborhood kids and parents were scared some wouldn’t even set foot on the property which is a personal win because that means more candy for me and as an adult lets be honest, there are few joys in life like making kids you’ve never met cry. I will probably grow this by adding motion activated lawn effects next year but this year was a total success!

Get the Code

I’ve posted my code from the endeavor to my github page in a new Halloween 2015 repo: https://github.com/ericpulvino/halloween2015

Amazon Dash Button Automation

Screen-Shot-2015-03-31-at-9.23.22-AM-620x311

If you haven’t heard about them, Amazon is putting out these shiny new buttons which are basically walking advertisements for certain brands of products. You can stick them to a wall with the included adhesive or hang them somewhere with the included ring (not pictured). What is even more interesting is that when you press one of these buttons they are supposed to place an order for a new product without any interaction on your part. They connect up to your home WIFI (with a bit of initial setup through the Amazon app) and beam the order request out to Amazon on the double so you can have your new garbage bags in a jiffy.

They come in veritable cornucopia of flavors right now, 18 buttons in all at the time of this writing. With multiple different companies vying for the opportunity to pitch their wares to you and get a little ad-space on your wall. Rumor has it that these companies are even paying Amazon for the privilege of being button-ized.

856b77326349b311da4c8fa3f8c8082a

Amazon is pitching these things for $5 a piece right now to Amazon Prime members only. Although supposedly you’ll get a $5 discount when you place your first order of product X using the button. You’ve really got to hand it to Amazon here, they’re making money on both ends, from the business AND the user. Let’s forget the fact that the whole concept is just a bit ridiculous (even for a technophile like me)… that they’d expect you to pay $5 for the convenience of hitting a button to order a product. That you would be so lazy as to not even perform the most rudimentary of price comparisons. That you would be willing to pay the iron price Amazon price for whatever good… whatever it happens to be. Are we all really that lazy busy?

Poor product ideas aside, I immediately plopped down $10 in Amazon gift card money and bought two of them right before my Prime subscription ran up because something tells me these aren’t going to be on the market for very long. After being inspired by Ted Benson I had a feeling there must be something I could set these up for.

61yJkst6nVL._SY355_

I purchased the most basic dash button model I could find with the least offensive advertisements… in this case this was the Amazon Elements model. When they arrived I immediately covered up the amazon logos with a label maker and called the buttons, very memorably, #1 and #2.

IMG_20150921_080310
Here you can see the hanging rings included with the buttons, the button on the right is naked.

Setup of the buttons is really simple but you must be careful to NOT COMPLETE THE SETUP. You wouldn’t want these buttons to actually order something hahaha. If you accidentally do complete the setup (like I did), you can dissociate the button from whatever product you picked but I recall it being an extra annoying step. Read the Ted Benson article here for clues on where to abort the setup process. For me it was as simple as force-closing the app on my phone when it prompted me to select the radio-button for a corresponding product. Presto chango the button was now rendered useless. It will still connect to your home Wifi and communicate to Amazon but it will not complete the ordering process.

Actually if you were to stop right here things would be quite annoying for you because every time you hit the button it still communicates with Amazon and then the silly phone app blows-off an annoying message to you reminding you to finish setting up your button. This gets old really quickly even when I was testing– even more fun is that the notifications stack up in Android so you’d have a list a mile long of notifications unless you take the next steps.

1). Setup a static IP for the button

2). Block all traffic from that IP out to the internet

You can use “discover mode” shown in python code below to learn which MAC address your dash button has in order to properly bind it to a static IP. Regarding the ability to block traffic, not every home Wifi router can support this function but if you have a newer router like the super-awesome Asus RT-AC68U you’re good to go. In my case I built a rule that applied to all hours of every day and applied that to the IP addresses of the two buttons for all of both kinds of traffic, TCP and UDP. Basically these things are now entirely disconnected from the internet.

Selection_168

Sure enough, when I applied these rules and continued pressing these buttons, I no longer received any notifications from Amazon. One side effect of this action is that the buttons stay awake longer as they try (and fail) to communicate with Amazon; I would estimate about 30 seconds in total although I have not specifically timed it.

Onto the fun stuff.

Now that the buttons are setup I cannibalized and re-factored some code to listen for them on the network. Here is what I ended up with.

#!/usr/bin/python

import sys
import time
import socket
import struct
import logging
import binascii
import subprocess

logging.basicConfig(filename='/var/log/dashbutton.log',
                    level=logging.INFO,
                    format='%(asctime)s %(message)s', datefmt='%Y-%m-%d %H:%M:%S -- ')

discover_mode=False

if len(sys.argv) > 1:
    if sys.argv[1] == "discover": discover_mode=True

rawSocket = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(0x0003))
buttons={
    "00bb3aff6aea_192.168.1.00":["Button One",0,["/home/pi/scripts/WEMO/send_wemo_commands.py","sendall.toggle"]],
    "747548bd4908_192.168.1.255":["Button Two",0,["/home/pi/scripts/WEMO/send_wemo_commands.py","kitchensink.toggle"]]}

logging.info(' ### Dash Button Service Started ### ')
while True:
    packet = rawSocket.recvfrom(2048)
    ethernet_header = packet[0][0:14]
    ethernet_detailed = struct.unpack('!6s6s2s', ethernet_header)
    arp_header = packet[0][14:42]
    arp_detailed = struct.unpack('2s2s1s1s2s6s4s6s4s', arp_header)
    # skip non-ARP packets
    ethertype = ethernet_detailed[2]
    if ethertype != '\x08\x06': continue
    source_mac = binascii.hexlify(arp_detailed[5])
    dest_ip = socket.inet_ntoa(arp_detailed[8])
    identifier=source_mac+"_"+str(dest_ip)

    if discover_mode:
       logging.info("We saw an arp from MAC: " + str(source_mac) + " ip: " + str(dest_ip)+ "\n")
       continue

    if identifier in buttons:
        buttons[identifier][1] += 1 #iterate the count of button presses
        logging.info(buttons[identifier][0] + " Pressed " + str(buttons[identifier][1]) + " times.\n")
        subprocess.Popen(buttons[identifier][2],stdout=subprocess.PIPE).communicate()[0]

Or download the code from my Github Gist page.

The code has two modes in which it can be run:

  • Discover mode: ./dash_button.py discover
  • Vanilla mode: ./dash_button.py

In discover mode the script will call out whatever MAC addresses it sees sourcing ARP packets… Press your button here and see what addresses your button owns. Once you’ve defined the static IPs in your router come back to the script and update the buttons dictionary with your “tuple” of MAC and IP address followed by your colloquial name for the button, the number of times it’s been pressed and lastly the command that should be executed by subprocess when the button is pressed.

Now you can run the script in vanilla mode to test pressing your button.

A simple few lines of code which sniff all incoming traffic listening for ARPs from a specific tuple of source MAC and IP address. Since this script is essentially sniffing all incoming packets you’ll want to situate this code on a remote part of your network that doesn’t process big file transfers or the like. In my case I have this code sitting on a Raspberry Pi that isn’t used for much.

Reading the code, you can see the “tuple” as the key for the “buttons” dictionary this is the key to identifying traffic we care about. The format for the buttons dictionary is rudimentary but functional and avoids making a class for something really simple.

In my example I’m kicking off WEMO Events whenever buttons are pressed. I keep button #2 by my nightstand and press it to turn off my kitchen light when I go to bed. Button #1 just toggles every light switch in the house for fun.

Starting the Script on Boot:

I built an Upstart job to start the script at each boot. In order to use this method, you’ll need to install Upstart on your Pi with:

pi@pi ~ $ sudo apt-get install upstart
Reading package lists... Done
Building dependency tree 
Reading state information... Done
Suggested packages:
 graphviz
The following packages will be REMOVED:
 sysvinit
The following NEW packages will be installed:
 upstart
WARNING: The following essential packages will be removed.
This should NOT be done unless you know exactly what you are doing!
 sysvinit
0 upgraded, 1 newly installed, 1 to remove and 81 not upgraded.
Need to get 502 kB of archives.
After this operation, 940 kB of additional disk space will be used.
You are about to do something potentially harmful.
To continue type in the phrase 'Yes, do as I say!'
 ?] Yes, do as I say!
Get:1 http://mirrordirector.raspbian.org/raspbian/ wheezy/main upstart armhf 1.6.1-1 [502 kB]

You can see during the Upstart install the system actually prompts you for such a big change with some special language [bolded above].

After Upstart is installed give your Pi a reboot:

sudo reboot

Lastly build the Upstart job by creating a file called “/etc/init/dashbutton.conf” and adding the following contents [replacing the exec line with the location where you have stored the script on your machine]:

author "Eric Pulvino -- AlwaysTinkering.wordpress.com"
description "Upstart Script to run Amazon Dash Button service"

start on runlevel [2345]
stop on runlevel [016]

respawn

exec /home/pi/scripts/dash_button.py

That’s it. You can reboot your Pi to automatically start the service now however you could also just run the following command to start the service manually:

sudo service dashbutton start

Summary:

I’m sure there will be more in store for the buttons down the road with Halloween so close by. My typical Halloween goal is to literally scare the neighborhood children (and adults to death) so I might setup the use of the buttons to disable some of the really scary effects for 30-60 seconds when I see little children coming up the walk. Either way I’ll be sure to post some of my Halloween antics this year!

Raspberry Pi WeMo Home Automation Control Center

WeMo PlugFor the last year I’ve had a Raspberry Pi that is always on mounted underneath my house. I power this device using PoE (Power over Ethernet) so there is literally a single ethernet cable that provides it with the ability to run for simplicity’s sake. This unit was the first Pi I had ever purchased so I’m a little nostalgic about it until you consider that I make it live in a crawlspace under my home.

While it is sitting under the house it’s performing a few vital services for me.

Service 1: Property Temperature Monitoring — Perhaps someday I’ll do a write up on this aspect.

Service 2: Amazon Dash Button Receiver

Service 3: Home Automation Control Center 

I have been meaning to write an article on Service 3 for some time. Of course I didn’t actually get around to doing it until there was a contest involved because it is a well known fact that I will do unspeakable things for free t-shirts. The write up on my Raspberry Pi Home Automation Control Center can be found on Instructables.com

http://www.instructables.com/id/Raspberry-Pi-WEMO-Control-Center/?ALLSTEPS