Category Archives: Python

Pygal US Map fork progress

I’m happy to report some progress in adding an option in pygal for the generation of SVG maps of the United States. There’s a few snags that I need to work out, but it’s 90% there.

I’m going to modify the borders of the states so that there is greater contrast, fix the mouseover effects, and see about improving the contrast between the states with creating a darker static border, fixing the mouseover effects, and [be] hopefully expanding the range of the color gradient.

Here’s the original France map from pygal that demonstrates the additional mouseover effects and has higher contrast borders.

Edit 9/25: All’s working well now, just don’t have the grouping functionality originally present and the stroke width seems to be too fat for the map compared to France. That’s an aesthetic issue that can wait, though.

Edit 11/9: No progress made in the last two months. Haven’t had internet since the last the update due to relocation to Barrow, Alaska for a work assignment. I’ll upload what I have to github and post a link here accordingly.

Edit 3/15: Just kidding. I’m never updating this. Lost interest 6 months ago and lost the files I was working on about 2 months ago.

 

You’re welcome, Internet

Introducing the “Wolverine Crush” meme image generator

Because it had to be made at some point or other.

Generate your own wolverine crush image

Try it out

You will need your desired image to have an approximate aspect ratio of 1:1.14 to fit properly in the Wolverine photo frame. You can crop to a proper aspect ratio / proportions here (I have already set the parameters, but that site is screwy… double check that it is set at 1:1.14 and not 1:1).

The actual size of the image is not important (for best results, use an image over 300px one each side though) as it will be resized correctly as long as the aspect ratio of 1:1.14 is observed. Incorrect proportions will not fit properly and will result in a skewed image or whitespace in Wolverine picture frame.

Image:

The code

The Python code behind making it was surprisingly straight forward. I had been avoiding doing anything that involved the PIL (Python Imaging Library) for some time. I always assumed it would be a nightmare to manipulate images via scripts, but this was actually far easier than I thought it  would be (admittedly, this is a simple manipulation) and is an inspiration to look into making simple custom GIMP scripts or learning a little more PIL at some point down the road.

Most of what I needed to know for this meme generator project came from just two Stack Exchange questions [1][2]

# 'WOLVERINE CRUSH' meme generator
# JS Kouri
# 8/2014
# No restrictions on use

import Image
import hashlib
import time

def file_name():
  # Generate unique file name (variable 'name') based on hash of time
  global name
  t = time.time()
  h = hashlib.md5()
  h.update(str(t))
  name = str(h.hexdigest())
  name = name[0:5] + ".png"

''' Note: I hate sequential file names and I keep forgetting the syntax of the hashlib library, hence this odd naming scheme method. It's personally useful to me for memorizing syntax with repeat exposure.  '''
 
  
file_name()

# user selected image to go into pic frame
fn = "imagetogointopictureframe.png" 
location = "/dir/to/img" + fn

# open base image and image to be superimposed:
wolverine = Image.open("../wp-content/uploads/2014/08/wolverine_generator.png")
user_img = Image.open(location)


# rotate user image to match angle of picture frame, preserve quality with bicubic interpolation
user_img.thumbnail((280,320))
rot = user_img.rotate(6, resample=Image.BICUBIC, expand=1)


# create a new empty image with alpha, set to base (wolverine) image size
new_im = Image.new('RGBA', (480,700))


# paste rotated user image first, paste base image with alpha in picture frame second
new_im.paste(rot, (120,350) )
new_im.paste(wolverine, (0,0), mask=wolverine)


# save
location = "../desired/save/dir/" + name
new_im.save(location)


# DEBUG 'print' image, useful when running on local machine for debugging
#new_im.show()

 

State Gas Prices Project

EDIT: Thanks to not having a computer up and running consistently, I only gathered about 2 months worth of data. Project cancelled to pursue more interesting things. Check out gasbuddy.com for a great source of data!

 

How much would gas be in your state without state and/or federal taxes? What is the current average price of gasoline in your state? Compared to other states? Historically? What would gas cost without the required ethanol component? What would be the average change in MPG from removal of ethanol? These are the questions to be addressed by the upcoming State Gas Price Project.

Will include the following:

  • code for a web scraper program to harvest pricing data and store to local and/or remote database
  • image mapping script to dynamically adjust state colors based on price range and map pricing labels to them (like so)
  • option to export image to svg and png
  • depending on time this week, an alternative HTML5 interactive svg map with mouseover effects. (oooh fancy!)

 

 

Arduino Sous Vide Machine: Part 2

Note: For an updated version with simpler code and important information about hardware issues see this new post: Arduino Sous Vide, Version 2

Darwin Award Disclaimer: Playing with electricity around big containers of water can be dangerous!

sous vide_fritz
The wiring scheme

After several successful cooks with the sous vide machine and ironing out a few software bugs, I decided it’s good enough to post. Like my other entries, it’s hardly pythonic, but gets the job done and it’s not all that bad for two months of self taught lackadaisical python study.

Photos to follow this post

I will upload some photos when I get a chance in the coming weeks.

The Assembly

You will need the parts listed in Part 1. The machine is assembled relatively easily from here. The immersion heaters plug into the GFCI relay box. The relay should be connected to the arduino with M to F jumper wires as pictured in the first post.

The thermistor should be enclosed in something that will lend additional waterproofing (partially sealing it in a piece of vacuum bag is a good idea or any old ziploc). The thermistor is connected to the arduino as depicted in the image above.  Don’t bother moving on unless you know the resistance of your thermistor at 25C and have determined your specific resistor’s Steinhart-Hart equation coefficients as described in this post. When you have these values, you will need to add them to the code below. (My values will work fine for the 4.7k ohm epoxy thermistor linked in Part 1).

The binder clips mentioned in Part 1 are useful for holding the Thermistor / waterproofing in place and keeping food filled vacuum bags in place when needed. The coat hanger / safety wire is used to hold the immersion heaters at the proper place in the container. I used two and have the heaters pinched in between.  It’s important to not submerge them completely, but leave some space between the water and the start of the electrical cord. The aquarium pump goes at the bottom along a wall of the container to ensure constant heat redistribution. The container lid is not necessary, but can be placed on top once you’ve started.

sousvideconsole2
This console output will refresh every 30 seconds with an updated temperature, time remaining, and whether the heater is on or off.

The Code

Code available for download. Hack it, improve it, MIT license yada yada yada…

# ARDUINO SOUS VIDE 
# v 0.1
# Simple arduino sous vide program
# Controls relay based on thermistor readings

import time
import os
import pyfirmata
from math import log

status = 'off'

def slp():
  '''
  INSERTS 5 SECOND DELAY 
  '''
  time.sleep(5)

def cls():
  '''
  CLEARS CONSOLE BETWEEN READINGS AND USER ENTRIES
  '''
  os.system('clear')

# SET COOKING PARAMETERS
def setup():
  ''' 
  SET UP COOKING PARAMETERS SUCH AS TEMP SCALE, TEMP, LENGTH OF TIME, PRECISION
  '''
  global cook_temp
  global cook_time
  global end_time
  global cook_temp_f
  global scale

  # CHOOSE TEMPERATURE SCALE AND COOKING TEMP
  n = True
  while n == True:
    cls()
    # SELECT TEMPERATURE SCALE
    scale = raw_input("Select temperature scale\n\n   1) Celsius \n\n   2) Fahrenheit \n\nEnter your selection: ")
    scale = scale.strip()
    if scale == '1':
      scale = [scale, 'Celsius', 1.0]			# scale list is temperature scale selection from menu, followed by name of scale, and last value is number of +/- degrees deviation allowed from cook_temp in cook() 
    elif scale == '2':
      scale = [scale, 'Fahrenheit', 2.66]
    else:
      print '\n\nERROR: You must enter 1 for Celsius or 2 for Fahrenheit\n\n'
      slp()
      continue
    cls()

    # SELECT COOKING TEMPERATURE; DON'T ALLOW NONSENSE ENTRIES SUCH AS < ROOM TEMP OR > BOILING POINT
    cook_temp = float(raw_input('Enter desired cooking temperature in degrees ' + scale[1] + ': '))
    if (scale[0] == '1' and cook_temp > 100) or (scale[0] == '2' and cook_temp > 212):
      print '\n\nERROR: Temperature may not be higher than boiling point of water (BP: 100 C, 212 F)\n\n'
      slp()
      continue

    elif (scale[0] == '1' and cook_temp < 25) or (scale[0] == '2' and cook_temp < 77):       print '\n\nERROR: Temperature may not be lower than room temperature (RT: 25 C, 77 F)\n\n'        slp()       continue          try:     # SET ALLOWED TEMPERATURE DEVIATION. DON'T ALLOW DEVIATION BEYOND +/- 5 DEGREES.        deviation = float((raw_input('Enter allowed +/- degrees deviation from setpoint. Press enter for default of ' +str(scale[2]) + ' degrees ' + scale[1] +': ')))       if deviation > 5:
	print '\n\nERROR: Deviation of ' +str(deviation) + ' degrees ' + scale[1] + ' is too great. Reduce your value to 5 degrees or lower for greater precision cooking.'
	print '\n\nExample: cook temp of 70 degrees C with 5 degrees deviation will allow a low temp of 65 C to be achieved before heaters are turned on and a high temp of 75 C before heaters are shut off'
	slp()
	continue
      scale[2] = deviation
    except:
      pass

    # SET COOKING TIME LENGTH IN MINUTES
    cook_time = raw_input("Enter desired cook time in minutes: ")
    cook_time = float(cook_time) * 60
    start_time = time.time()
    end_time = start_time + cook_time
    cls()

    # SETUP VERIFICATION / START
    print 'COOKING SETTINGS'
    print '\n\nSet for ' +str(cook_temp) +' degrees ' + scale[1] ,
    print 'for ' +str(cook_time / 60) +' minutes'
    print time.strftime('Cooking will complete at %a %I:%M %p', time.localtime(end_time)) #convert end_time seconds to readable day H:m format
    start = raw_input('\n\nDo you wish to continue with current settings? ')
    if start.lower() == 'n' or start.lower() == 'no':
      continue
    if start.lower() == 'y' or start.lower() == 'yes':
      n = False

def connection():
  '''
  CONNECT TO ARDUINO
  '''

  global pin0
  global pin4
  global board
  n = 0							# first port number to try ie: ttyACM0
  PORT = '/dev/ttyACM' + str(n)    			# device location, yours may very. if unable to connect, try /dev/USB or check dmesg
  connected = False 

  # ATTEMPT TO CONNECT TO ARDUINO. ITERATE THROUGH 1000 PORT NUMBERS UNTIL CONNECTED OR FAIL ON 1001.
  while connected == False:
    try:
      print 'Trying ' + PORT
      board = pyfirmata.Arduino(PORT)
      print 'Port found, connecting...'
      connected = True
      print "Connection established"
    except:
      n = n+1
      if n > 1000:
	raise Exception("Error connecting to arduino. Check to make sure it's connected and check dmesg for correct location. If other than /dev/ttyACMx, edit line #102 of sousvide.py to reflect your location.")
      PORT = '/dev/ttyACM' + str(n)
      pass

  pin0 = board.get_pin('a:0:i')				# edit to reflect your setup
  pin4 = board.get_pin('d:4:o')

  it = pyfirmata.util.Iterator(board)
  it.start()

  pin4.write(0)						# start with pin off
  pin0.enable_reporting()

  print 'Waiting on reading...'
  while pin0.read() is None:				# ignore input until pin is active
      pass

def temp_check():
  '''
  FUNCTION THAT POLLS ANALOG PIN FOR TEMPERATURE, USED EVERY 30 SECONDS
  '''

  global current_temperature
  current_temperature = ''				# reset temperature each time 

  while pin0.read() is None:				# ignore input until pin is active
      print 'waiting on thermistor reading...'
      pass

  analog_value = pin0.read()

  # VOLTAGE DIVIDER CALCULATION
  analog_value = analog_value  * 5			
  analog_value = 4700.0 * ((5.0/analog_value) -1.0) 	# make sure you use the correct number here reflecting your thermistor. ie: for 10k ohm resistor, replace 4700 with 10000

  # STEINHART-HART EQUATION 
  temp = (1 / (0.001308463361 + 0.0002344771590 * log(analog_value) + 0.0000001041772095 * log(analog_value)**3)) # substitute your thermistor's unique values for A, B, C. 

  # CONVERT TEMPS FROM KELVIN 

  # TEMP IN CELSIUS
  if scale[0] == '1':
    current_temperature = temp - 272.15

  # TEMP IN FAHRENHEIT
  if scale[0] == '2':
    current_temperature= 9/5.0*(temp-272.15) + 32

  # TIME / TEMPERATURE LOGGING
  f = open('/tmp/sousvide.log', 'a')
  f.write(str(time.time()) + ' ' + str(current_temperature) + '\n')
  f.close()

  # STATUS REPORTING TO CONSOLE
  cls()
  print 'ARDUINO SOUS VIDE v 0.1'
  print '-'*80+'\n\n'
  print ' '*5 + 'Set temperature: ' + str(cook_temp) + '\n\n'
  print ' '*5 + 'Current temperature: ' + str(current_temperature) + ' ' + scale[1] + '\n\n'
  print ' '*5 + 'Heating element(s): ' + status + '\n\n'
  print ' '*5 + 'Time remaining: ' + str((end_time - time.time())/60.0) + ' minutes\n\n\n\n'
  print  '-'*80
  slp()

def cook():
  while True:

    global status

    while time.time() < end_time: # continue cook function until time up
      temp_check()
      if current_temperature < (cook_temp - scale[2]): 	# start heating element every time temp drops X degrees below goal temp 	pin4.write(0)	# START HEAT 	board.pass_time(5) 	time.sleep(20) 	status = 'on'       elif current_temperature > (cook_temp + 0.4 * scale[2]): # kill heating element every time temp goes 0.5X degrees over goal temp
	pin4.write(1)	# KILL HEAT
	board.pass_time(5)
	time.sleep(20)
	status = 'off'
      else:  				      		# if temperature is within X*2 degrees (-X goal +X) of goal temp, continue with whatever is currently happening
	board.pass_time(5)
	time.sleep(20)
	pass 

    if time.time() > end_time or time.time() == end_time:
      pin4.write(1)
      cls()
      print "all finished, killing heat..."
      slp()
      board.exit()
      exit()

setup()
connection()
cook()

Features

The code offers the following features:

  • Fahrenheit and Celsius heating options
  • Status updates every 30 seconds
  • Control over hysteresis with modifiable temperature range from setpoint (the deviation option)
  • Automatic logging of temperature and time to /tmp/sousvide.log

What’s Next

Now to get cooking, there are some excellent resources online. Douglas Baldwin offers some of the most oft quoted resources. He has some good information on his website, including some carefully calculated pasteurization tables that if followed, let you cook food low and slow while still getting all the nasties.

For a more general overview, you can check out his presentations that he did for the American Chemical Society, Sous Vide Cooking and Chemistry and Giving Thanks for the Water Bath: Sous Vide Cooking for the Holidays.

Limitations

This set up and code is good to go as-is ‘out of the box’. FYI: timer starts immediately after accepting  cook settings. You must take into account preheat time (approximately one hour to obtain 60C from room temp water, see ‘future updates’ section below).

A little fine tuning may be helpful to get the most precise and near constant temperature. In order to avoid a constant on/off, a hysteresis curve is simulated in the cook() function. After about 6 cooks, I’ve gotten it calibrated pretty well. It originally was giving some wild peaks due to the fact that the heaters continue to heat after shutting off.

Case in point:

sous vide premodification

I found that reducing the deviation variable to 40% for the cut off temp and reducing the temperature check interval by 10s greatly improved the outcome. I may go one step further and reduce the polling interval by another 5s to try to get equidistant ‘peaks’ to ‘troughs’ from setpoint temp).

I cooked my chicken for more than 1 hour. Scale abbreviated to better match above graph.
I cooked my chicken for more than 1 hour. Scale abbreviated to better match above graph.

If your sous vide cooking relies on even more precise cooking that deviates less than 1C from setpoint, feel free to fiddle with the cook() function and/or set deviation to something very low (< 0.5 degrees).

Future Updates

I ran out of time in the short run to make any new updates to this. For my own satisfaction, I will likely add a preheat function from the data gleaned in the last post that will preheat the water bath and once preheated, start the timer from there. Should be a quick fix. As an exercise in dealing with formatting Python time strings, I may make the time input a little smarter with options other than minutes.

I’m also considering modifying the code to make use of PyPi and the Raspberry Pi via its GPIO pins.

Arduino Sous Vide Machine: Part 1

Note: For an updated version with simpler code and important information about hardware issues see this new post: Arduino Sous Vide, Version 2

Heavily inspired by an old blog post by the brilliant Seattle Food Geek, I set out to build an arduino powered sous vide / thermal immersion circulator machine.  Instead of a PID controller, it uses an arduino with a relay + waterproof thermistor. A little less sexy, but just as effective with the added bonus of being modular with reusable parts.

Materials

  1. Sterilite® Ultra Latch 17 L container $4
    • Made of polyproplyene, softens at ~155°C according to the Merck index, melts at 165°C; perfect for our application of temps < 100°C.
    • Avoid long term exposure to UV light as paranoid precaution against degradation
    • You can simply use a big pot instead of the plastic container. I Outlet boxhave an enamelled cast iron pot that is excellent for maintaining a steady temperature.
  2. Arduino (I’m using UNO rev3) $35
  3. Waterproof temperature sensor / thermistor (DS18b20 ) $2.03

    • This thermistor is waterproof but not rated for full immersion
    • I sealed mine in a small bit of plastic with the vacuum sealer. problem solved
    • See previous post for how to calibrate
  4. Immersion heater (2x) $13
  5. 3 prong power cable free if sacrificed, otherwise $6+
  6. 5V 1 channel relay  $1.36
    • This relay is really cheap and was starting to fall apart on me; I substituted it with another one I had laying around. YMMV
  7. Aquarium water pump 80GPH $6.88
  8. Ziploc V150 vacuum sealer system $30 (on clearance at Target)
  9. GFCI outlet $12.30
  10. Outlet faceplate $1 (optional)
  11. Outlet box $0.50 (link is to pack of 100, cheaper to buy in store)
  12. Wire coat hanger / safety wire
  13. Large binder clips (2x) $0.50
  14. Male to female (3x) and male to male jumper wires (the more the merrier) $2.00
  15. A 4.7 k Ω resistor for thermistor $0.05

Grand Total:  $114.62 if you buy everything. You can add an extra heater or two if desired. I found that two alone work pretty well. My units have been calculated to heat at about 0.01 C per second, taking an hour to get up to an average cooking temp of 65C from room temperature water.

norpro temperature graph

Step 1: Building the relay

The first step is building a functioning relay. The beauty of this sous vide machine is that it is comprised of parts that can be cannibalized and put to other uses when you’re not sous vide cooking. The relay is especially cool as it allows you to control high voltage devices from the measly 5V microcontroller of the arduino. The options from here are limited only by your creativity and/or depravity. (Lots of options of pairing it with motion!)

I followed a Sparkfun tutorial on how to build a Controllable Power Outlet. Quite frankly, there is no need to rehash something that is described better there. Check it out.

Here’s a diagram for the relay listed  in the parts list. You can figure it all out from this picture alone.

relay wiring

Step 2: Testing Relay

Controlling a relay with pyfirmata

Controlling the relay is incredibly easy with pyfirmata. It’s as simple as turning a pin on and off to open and close the relay. If you know how to switch a LED on, you can control a relay.

Here’s some example code to function test it.

import pyfirmata

port = '/dev/ttyACM0'

board = pyfirmata.Arduino(port)

it = pyfirmata.util.Iterator(board)
it.start()

pin4 = board.get_pin('d:4:o')

while True:
	ui = raw_input("Enter 'on' or 'off': ")
	if ui == 'on':
		pin4.write(1)
	elif ui == 'off':
		pin4.write(0)
	else:
		pass

Plug your relay into the arduino, plug your arduino into a PC and test it out by plugging in your relay controlled power outlet and lamp into the outlet.

That’s all there is to it. It’s only a small leap from here to put some devices online that you can control remotely. (Check out X10 for anything beyond a few devices).

Next…

Building a feedback loop with a thermistor and using thermostat-like hysteresis curves for controlling the immersion heaters.

Thermistor + pyfirmata

Want to know how to use a thermistor with your arduino via pyfirmata? Look no further…

I’ve been playing with thermistors as part of a home monitoring system I’ve been building and for an upcoming sous vide project. Thermistors are cheap and can be highly accurate for a pretty wide range of temperatures. I’m using an epoxy coated and waterproofed thermistor for my sous vide project.

The Setup

You need:

  • an arduino
  • a thermistor
  • a resistor that matches your thermistor (ie: 10k ohm resistor with 10 k ohm thermistor)
  • a breadboard with jumper wires

pyfirmata thermistor

The Code

Code available for download

### THERMISTOR TEMPERATURE READINGS VIA PYFIRMATA 
### JS Kouri 2/1/2014, no rights reserved
### In this example, I am using a 4.7 kΩ resistor 
### (Digi-Key Part Number NTCLE400E3472H)
### Values for Steinhart-Hart equation calculated 
### at http://bit.ly/1nPiOLv from datasheet info

import pyfirmata
from math import log
from time import sleep

n = 0							#first port number to try ie: ttyACM0
PORT = '/dev/ttyACM' + str(n)    			# device location, yours may very. if unable to connect, try /dev/USB or check dmesg
connected = False 

def connection():
  global board
  board = pyfirmata.Arduino(PORT)
  print 'Port found, connecting...'
  it = pyfirmata.util.Iterator(board) # start iterator thread
  it.start()

# ATTEMPT TO CONNECT TO ARDUINO. ITERATE THROUGH PORT NUMBERS UNTIL CONNECTED  
while connected == False:
  try:
    print 'Trying' + PORT
    connection()
    connected = True
    print "Connection established"
  except:
    n = n+1
    PORT = '/dev/ttyACM' + str(n)
    pass

# WAIT UNTIL INPUT RECEIVED AT ANALOG PIN  
pin0 = board.get_pin('a:0:i')				# edit to reflect your setup
print 'Waiting on reading...'
while pin0.read() is None:				# ignore input until pin is active
    pass

while True:

  analog_value = pin0.read()
  #print analog_value 					# optional debug info

  # VOLTAGE DIVIDER CALCULATION
  analog_value = analog_value * 5			# we multiply by 5 (volts) to get the true voltage read at pin (ie: we get 3 v instead of 0.6. pyfirmata reports analog values in the range of 0 to 1. 
  analog_value = 4700.0 * ((5.0/analog_value) -1.0) 	# solve for resistance at thermistor. change 4700 to match your resistor used.

  #print str(analog_value) + ' this is calculated resistance in ohms at thermistor' # optional debug info

# STEINHART-HART EQUATION
  temp = (1 / (0.001308463361 + 0.0002344771590 * log(analog_value) + 0.0000001041772095 * log(analog_value)**3)) # substitute your thermistor's unique values for A, B, C. 

  # TEMP IN KELVIN
  print str(temp) + ' kelvin'

  #TEMP IN CELSIUS
  t_celsius = temp - 273.15
  print str(temp) + ' degrees celsius'

  #TEMP IN FAHRENHEIT
  t_fahrenheit = 9/5.0*temp + 32
  print str(t_fahrenheit) + ' degrees fahrenheit\n\n'  

  sleep(30) 						# wait 30 seconds between polling pin

The Explanation

The code features a few important aspects that understanding will be helpful.

Converting Pyfirmata Analog Values to Voltage

Pyfirmata reports analog values as a float of 0 to 1. We need to determine what the voltage is at the analog pin. We’re using 5 VDC so we multiply it by 5.  This will provide Va for the next portion.

The Voltage Divider

A neat little explanation of why we use voltage divider circuits with thermistors and other sensors can be found here. No need to rehash it.

In order to obtain the resistance of the thermistor, we need to calculate it based off the voltage readings from the analog pin. (Which we just adjusted). We use an equation derived from Ohm’s Law that lets us calculate the resistance in a voltage divider.

RT = R  [1 / (V / VA – 1) ]

Where RT = thermistor resistance in ohms, R = resistor resistance, V = input voltage, VA = voltage reading from analog pin (Read more at Wikipedia Voltage Divider)

 Armed with the resistance at the thermistor, we can finally calculate the temperature.

Steinhart-Hart Equation

There are  a couple ways of calculating this, I chose the Steinhart-Hart equation, but you can also use the simpler β equation. (See Wikipedia)

Where R = thermistor resistance. (Written as RT in last section)

It is very important to have your datasheet in order to accurately calculate the values needed for this equation. If you don’t have the datasheet, you can determine your own values by obtaining resistance in ohms at three known temperatures.

thermistor_datasheet
my thermistor’s data sheet and the values I used in the calculator

 

Once you get your  resistance values for three known temperatures from your datasheet or experimental data, plug them into a Steinhart-Hart calculator and build your equation.

Replace my values in the code above with yours. Be sure to format the coefficients properly. The calculator I linked to above gives coefficients in scientific notation. Convert scientific notation to the long form decimal notation. (n-1 preceding decimal places for E to the n power)

Now run it and get your temperature!

 Sky’s The Limit

And there you have it. From here you can easily save your values in a text file or a database, build cool charts with matplotlib (if you don’t pull your hair out first trying to get it to work), or do something more dynamic like create feedback loops and control things based on temperature.

Dropbox + Motion on the Raspberry Pi

Raspbian, the recommended default operating system of the Raspberry Pi, does not come with a native Dropbox package. The hacks I saw online were all pretty sloppy, with many showing how to bounce files from your raspberry pi to another device like a desktop PC that has dropbox installed, then using that PC to sync files. I wanted Dropbox synchronization for only a single folder, and for one purpose: to collect the photos my webcam takes when using the motion software.

(Motion is a pretty cool program that can give advanced motion sensing capabilities to a number of webcams, and live stream your webcam and/or automatically record video or take pictures when motion is detected. See: http://www.lavrsen.dk/foswiki/bin/view/Motion/WebHome)

I decided to use Dropbox’s Python API to create a script that could save my security footage. I had a number of uninvited painters scheduled to come to my apartment while I was away at work and needed something that would save to a remote location. The code that follows is tailored to the motion program. Since motion can automatically execute a program or script upon writing a file (ie: saving a photo or video triggered by motion), I decided to take advantage of this and upload each file individually as opposed to running an additional script that continually monitors the filesystem for changes.

(Will make that later… check back in a week or two). Update: more important things have cropped up like building a sous vide machine!

How to do it:

Assumptions:

  • You have a dropbox account
  • You have python and motion installed
Step 1: Download droppi script files

Accessible here

Step 2: Install Dropbox SDK Python module & create new dropbox app

Install the module:

sudo pip install dropbox

Create new app:

https://www.dropbox.com/developers/apps

Click:

Create App > Dropbox API app > Files & Datastores > Yes

Name your new app whatever you like.

Step 3: Copy down newly created app key and app secret

Paste your app key and app secret into the “keys” file downloaded in droppi.zip. There should be one key per line with app key on the first line. ie:

vg6l0juiiofvlsz8
av4hukwalmn8t9o

Step 4: Run link.py to allow dropbox API access so we can upload to dropbox

python link.py

Follow the directions in the console, you will need to click the link to allow API access. You’ll also need to paste the code received into console. This will be the last key you will need to use the droppi.py script. The rest of the keys and tokens are generated automatically for you and will be inserted into the “keys” file.

You can tell if it worked by checking your dropbox account. Do you see a new folder that bears the name of your app (may be located in a new “App” folder)? Is there a “test.txt” inside of it? If so, you’re all set for step 5.

Step 5: Configure Motion

Open the motion configuration file found at /etc/motion/motion.conf (always a good idea to make a copy). If you don’t have a configuration file, I used this sample one.

Disable video

I disabled video recording on mine because the dropbox account I’m using for motion is a new account with only about 2 gb of space in it. I disabled video recording by changing

ffmpeg_cap_new

to

ffmpeg_cap_new off

Set working directory

Choose the directory on your local machine where you would like to save your pictures and/or videos. /tmp is a good option if you don’t want long term storage. Make sure your directory is writeable by user motion.

target_dir /tmp

Add droppi upload

If you are saving images, modify the following the following (use absolute path for the droppi.py file, ie: /home/pi/droppi.py, and be sure to remove the semicolon at the front of the line)

on_picture_save python droppi.py %f

If you are saving videos:

on_movie_end value

Step 6: Enjoy your dropbox enabled surveillance system!

Save the motion.conf file, start or restart the motion daemon

sudo service motion restart

Dance in front of your camera and check your dropbox!

Coming soon: Real time Dropbox folder syncing for Raspberry Pi

This motion dropbox script was a quick proof of concept hack and was made overnight because I needed it to keep an eye on these seedy painters that were coming into my apartment while I was out all day.

Hello painters!

 05-20140109084638-00 05-20140109084641-00(1) 05-20140109084503-00 05-20140109084259-00

What’s next

A python program that continually monitors a directory for changes should not be much more difficult to create. Stay tuned…

Overengineered Morse Code with the Arduino

As a first foray into python, arduino, and pyfirmata (after lighting a single LED), I wrote this small python script for converting text into morse code. I first ran it with a single LED on a breadboard, but it was much more fun to throw in a piezo buzzer and get the unmistakeable morse beeps.

See the code and schematics below. As someone with less than a month of on and off again python study, don’t expect anything too ‘pythonic’ and pretty. It works though!

Script requires the pyfirmata module. Be sure to adjust the pin number and port/device location of the arduino in the script.

### Arduino / Raspi Morse Code Generator
### Enter a word, and get morse code translation in console output & LED lights / beeps



import pyfirmata


### MORSE CODE ALPHABET ###
morse = {'a':['.','-'],
	 'b':['-','.','.','.'],
	 'c':['-','.','-','.'],
	 'd':['-','.','.'],
	 'e':['.'],
	 'f':['.','.','-','.'],
	 'g':['-','-','.'],
	 'h':['.','.','.','.'],
	 'i':['.','.'],
	 'j':['.','-','-','-'],
	 'k':['-','.','-'],
	 'l':['.','-','.','.'],
	 'm':['-','-'],
	 'n':['-','.'],
	 'o':['-','-','-'],
	 'p':['.','-','-','.'],
	 'q':['-','-','.','-'],
	 'r':['.','-','.'],
	 's':['.','-','-','-'],
	 't':['-','.','-'],
	 'u':['.','-','.','.'],
	 'v':['-','-'],
	 'w':['-','.'],
	 'x':['-','-','-'],
	 'y':['.','-','-','.'],
	 'z':['-','-','.','-'],
	 ' ':' '}


### CONNECT TO ARDUINO ###
port = '/dev/ttyACM0'
board = pyfirmata.Arduino(port)

### SET PIN NUMBER ###
pin = 7 

def program():

### DELAY FACTORS ###
  delay = 0.15						# Length of time LED between inter elemental lighting
  delay_factor = 1					# Speed up or slow down entire program by set percentage Default: 1
  delay_intraletter = delay * delay_factor * 3		# Length of time between letters 
  delay_interword = delay * delay_factor * 7		# Length of time between words
  delay_dit = delay * delay_factor			# Length of illumination for dot/dit
  delay_dah = delay_intraletter	 


  user_list = [] 									# blank list
  user_input = raw_input("Enter your word to convert to morse code: ").lower()		# Take user input, convert to lowercase
  for x in user_input:
    user_list.extend(morse.get(x))
  print user_list
  print '\n Creating morse message now...'
  user_list = ''.join(user_list)
 # print 'DEBUG: joined user list'
 # print user_list
 
  for l in user_list:
    
    if l == '.':
      board.pass_time(delay_intraletter)
      board.digital[pin].write(1)
      print 'TRANSMITTING: .'
      board.pass_time(delay_dit)
      board.digital[pin].write(0)
    
    elif l == '-':
      board.pass_time(delay_intraletter)
      board.digital[pin].write(1)
      print 'TRANSMITTING: -'
      board.pass_time(delay_dah)
      board.digital[pin].write(0)
      
    elif l == ' ':
      board.pass_time(delay_interword)
      print 'NEW WORD'	

    else:
	pass
      
   
   
program()
  

The circuit is even simpler than the script. It amounts to nothing more than a piezo buzzer (unsure of the specs of mine), LED, and resistor in series.

Easy enough, right?
Easy enough, right?

So what had originally sprung up as an idea to play around with the pyfirmata syntax turned into a drive to learn morse code, which quickly faded into disinterest by the time I had finished transcoding the alphabet. I have since made an updated version that includes numbers and communicates between two computers on a network via the python SOCKS module. I was considering adding a reverse translator as well that translates user input (via pushbutton) morse into letters. I think I have a few other projects in mind that will be of more immediate practical use.

Download the latest source files for this project here

Morse key adopted from https://en.wikipedia.org/wiki/Morse_code.