I recently wrote a piece of software for a friend working on a project, you can find it on github here. The following is from the README.md:
zipcode-distance-excel
This is a command line utility to automatically calculate the distance between two zipcodes and then put the results in an excel (.xlsx) file. It works for US postal codes only.
It was developed to help a colleague and is very application-specific.
Prerequisites
Downloading is easy git, which is already on most systems, on ubuntu use:
A step by step series of examples that tell you have to get a development env running
Say what the step will be
git clone https://github.com/esologic/zipcode-distance-excel
cd zipcode-distance-excel
python3 setup.py install
Usage
in a directory with the .xlsx file that you want to modify, run:
python3 zde.py
The program skips the first row in the spreadsheet to avoid headers.
Example Usage
Before:
Terminal output:
Which file would you like to modify?
[0] - International Addresses.xlsx
[1] - testbook.xlsx
File Number: 1
You've selected [testbook.xlsx] to edit.
Which sheet would you like to modify?
[0] - Sheet1
[1] - Sheet2
[2] - Sheet3
Sheet Number: 0
You've selected [Sheet1] to edit.
Which column to read? (ie. A, B, AA): A
Which column to write result? (ie. A, B, AA): B
Point A Zipcode? 02114
Job Complete. 10 modifications made.
This circuit aims to replace a traditional toggle switch for switching large amounts of current. Instead of the bulky and expensive traditional toggle switch, this circuit allows for a cheap pushbutton, and a few transistors and resistors to be used and have the same effect.
For my application, I wanted a way to have the circuit draw very little curren
t when in the off state, be able to be powered on with a pushbutton, and then turned off through software on the Arduino.
Here is the circuit diagram:
Here’s a video of the circuit in operation:
The code running on the Arduino is very simple:
int button = 3;
int led = 2;
void setup() {
pinMode(button, INPUT);
pinMode(led, OUTPUT);
digitalWrite(led, LOW);
}
void loop() {
if (digitalRead(button)) {
digitalWrite(led, HIGH);
}
}
I’m constantly loosing the remote for my RGB LED strip lights, and I have a few days for spring break, time to get hacking. Here’s a demo and explanation video:
I don’t mention it in the video, but the cool part of this project is how the different processes communicate with each other. Rather than interacting with the different processes through pipes, or something like stdin, I’ve decided to use a TCP websocket server:
Processes on the device send RGB values to the Strip Server via a TCP packet. This very very easy to implement, and almost all of the hard work is taken care of via the socketserver module included in python3. This also allows for interactions with that main process (the StripPi Server process) to take place off of the Raspberry Pi as well. I plan on writing an Alexa integration for this project moving forward, and this should make that a lot easier.
The analog to digital conversion is handled by an MCP3008, exactly the same way as I did it here.
This was one of those rare times where I had a hunch, followed it, and had a great result.
So for a project I’m working on for school, we have a robot with multiple composite video cameras onboard. We will be using those cameras seen on DIY drones or in simple security systems. We will be transmitting this video feed via a 5.8GHz video transmitter meant for a drone. We want the operator to be able to switch which feed they’re viewing at a given time, but we don’t want to have to use 3 transmitters and receivers. So to get around this, I thought we might just connect video feeds to a simple analog multiplexer I had laying around from a previous project and see if you could switch the feed that way. Turns out, you totally can. Here’s the eventual block diagram of this part of our project if you’re interested:
The following is the code running on the arduino. Remember, this isn’t doing anything special other than driving the mux:
#define NUMSELECTS 4
int s0 = 2;
int s1 = 3;
int s2 = 4;
int s3 = 5;
int selects[NUMSELECTS] = {s0, s1, s2, s3};
int select_state[NUMSELECTS] = {0, 0, 0, 0};
void setup()
{
Serial.begin(9600);
for (int index = 0; index < NUMSELECTS; index++)
{
pinMode(selects[index], OUTPUT);
digitalWrite(selects[index], select_state[index]);
}
}
void loop()
{
if (Serial.available() > 0)
{
char inchar = Serial.read(); //assigns one byte (as serial.read()'s only input one byte at a time
switch(inchar)
{
case '0':
Serial.println("Switching to video signal 0");
select_state[0] = 0;
select_state[1] = 0;
select_state[2] = 0;
select_state[3] = 0;
write_selects();
break;
case '1':
Serial.println("Switching to video signal 1");
select_state[0] = 1;
select_state[1] = 0;
select_state[2] = 0;
select_state[3] = 0;
write_selects();
break;
default:
Serial.println("Bad input");
break;
}
}
}
void write_selects()
{
for (int index = 0; index < NUMSELECTS; index++)
{
digitalWrite(selects[index], select_state[index]);
}
}
Trying to get the most out of a day has been big theme of my life lately, as I’m sure it is for many people. I’ve found that I always manage my time better when things are urgent; I’m considerably more productive when I have to be.
I want an ascetically pleasing way to be able to represent how much time is left in the day at a granular scale, like an hourglass. Watching individual seconds disappear will look cool and (hopefully) create that sense of urgency that I want to induce.
Technically, this is a really simple thing to accomplish thanks to python and pygame. Here’s a video of a proof of concept running on my laptop:
At the start of each day, the display is filled with squares at random locations, with a random color. As each second elapses, a square will vanish.
To make it easier to see for the video, I’ve made the squares much bigger than they will actually be for the final build. This is what the display looks like with the squares at their actual size:
The code really really simple, like less than 100 lines simple. Here’s how it works:
Here’s the version of the code running on my computer in the video:
import pygame
from random import randint
from apscheduler.schedulers.blocking import BlockingScheduler
import datetime
class random_square(object):
def __init__(self, max_x_location, max_y_location):
self.x_loc = randint(0, max_x_location)
self.y_loc = randint(0, max_y_location)
max_color_value = 255
red = randint(0, max_color_value)
green = randint(0, max_color_value)
blue = randint(0, max_color_value)
self.color = [red, green, blue]
class clock(object):
def __init__(self, initial_count, max_count, screen_w, screen_h):
self.max_count = max_count
self.screen_w = screen_w
self.screen_h = screen_h
# create the screen object, force pygame fullscreen mode
self.screen = pygame.display.set_mode([screen_w, screen_h], pygame.FULLSCREEN)
# the screen's width in pixels is stored in the 0th element of the array
self.square_size = screen_w / 200
# create the list of squares, initially as empty
self.squares = []
# fill the squares with the inital seconds until midnight
for second in range(initial_count):
self.squares.append(random_square(screen_w, screen_h))
# starts ticking the clock
def start(self):
scheduler = BlockingScheduler()
scheduler.add_job(self.tick, 'interval', seconds=1)
try:
scheduler.start()
except (KeyboardInterrupt, SystemExit):
pass
# this occurs once every time a unit of time elapses
def tick(self):
# this will happen once per "day"
if len(self.squares) == 0:
# fill the list of squares to be drawn
for second in range(self.max_count):
self.squares.append(random_square(self.screen_w, self.screen_h))
# draw a blank screen
self.screen.fill([0, 0, 0])
# draw the squares
for square in self.squares:
rect = (square.x_loc, square.y_loc, self.square_size, self.square_size)
pygame.draw.rect(self.screen, square.color, rect, 0)
pygame.display.update()
# remove a single square from the list as one tick has elapsed
self.squares.pop()
# initialize pygame
pygame.init()
# figure out the parameters of the display we're connected to
screen_width = pygame.display.Info().current_w
screen_height = pygame.display.Info().current_h
screen_size = screen_width, screen_height
# determine the number of seconds until midnight
seconds_in_a_day = 86400
now = datetime.datetime.now()
midnight = now.replace(hour=0, minute=0, second=0, microsecond=0)
seconds_until_midnight = seconds_in_a_day - (now - midnight).seconds
# create and start the clock!
cl = clock(seconds_until_midnight, seconds_in_a_day, screen_width, screen_height)
cl.start()
Let’s walk through some of the design decisions of this code. The first thing that’s worth talking about is how the data for the squares is handled:
class random_square(object):
def __init__(self, max_x_location, max_y_location):
self.x_loc = randint(0, max_x_location)
self.y_loc = randint(0, max_y_location)
max_color_value = 255
red = randint(0, max_color_value)
green = randint(0, max_color_value)
blue = randint(0, max_color_value)
self.color = [red, green, blue]
It’s just an object with no methods, and on initialization, all the parameters of the square (location and color) are generated randomly as opposed to just floating the raw numbers in arrays around (even though that’s basically what is happening). This let’s us fill the squares array very easily later on in the file here:
# fill the squares with the inital seconds until midnight
for second in range(initial_count):
self.squares.append(random_square(screen_w, screen_h))
and here:
# this will happen once per "day"
if len(self.squares) == 0:
# fill the list of squares to be drawn
for second in range(self.max_count):
self.squares.append(random_square(self.screen_w, self.screen_h))
When it comes time to draw these squares, it also makes that pretty intuitive:
# draw the squares
for square in self.squares:
rect = (square.x_loc, square.y_loc, self.square_size, self.square_size)
pygame.draw.rect(self.screen, square.color, rect, 0)
Again, very simple stuff, but worth it to talk about.
I’ll be back at my place that has the Raspberry Pi and display I would like to use for this project, so more on this then.
So in the final chapter of the long saga that has been connecting my Raspberry Pi to my Campus’s WiFi network, I needed a way to obtain the IP address of the Pi without using a display or a serial cable.
I’m actually pretty proud of this and I think it’s an elegant solution to a fairly annoying problem. Here’s a video of the system in action:
The program starts with three blinks. After that, the pattern goes as follows:
Etc. Four short blinks indicate a 0 and six short blinks indicate a “.”
Once the address is fully read out, three long blinks will occur.
Here’s the code:
import RPi.GPIO as GPIO ## Import GPIO library
import time
GPIO.setmode(GPIO.BCM) ## Use board pin numbering
led = 20
button = 21
GPIO.setup(led, GPIO.OUT) ## Setup GPIO Pin 7 to OUT
GPIO.setup(button, GPIO.IN)
from subprocess import *
while 1:
if (GPIO.input(button)):
ip = Popen("ip addr show wlan0 | grep inet | awk '{print $2}' | cut -d/ -f1", shell=True, stdout=PIPE).communicate()[0]
for x in range(3): #three rapid blinks to indicate procedure is starting
GPIO.output(led,True)
time.sleep(.2)
GPIO.output(led,False)
time.sleep(.2)
time.sleep(3) # followed by a delay
for x in list(ip):
time.sleep(4) #a long delay between characters
if x.isdigit():
if (int(x) == 0):
for x in range(4): #four rapid blinks indicate a 0
GPIO.output(led,True)
time.sleep(.2)
GPIO.output(led,False)
time.sleep(.2)
elif (int(x) != 0):
for y in range(int(x)):
GPIO.output(led,True)
time.sleep(.5)
GPIO.output(led,False)
time.sleep(.5)
elif (x == '.'):
for x in range(6): #six rapid blinks indicate a .
GPIO.output(led,True)
time.sleep(.1)
GPIO.output(led,False)
time.sleep(.1)
time.sleep(5)
elif (x == '\n'):
for x in range(3): #six rapid blinks indicate a '.'
GPIO.output(led,True)
time.sleep(2)
GPIO.output(led,False)
time.sleep(2)
I use this code constantly. It basically packages serial data for strtok_r to split into pieces paced on predefined deliminators. Each bit of data is separated by a “,” and the end of the set of data is a “.”
If you send in a string like:
10,50,100.
You can split it into three varaibles that equate to those different values. In this case:
int x = atoi(subStr(serialbuf, ",", 1))
The Variable x would equate to 10.
Here’s the code:
const char EOPmarker = '.'; //This is the end of packet marker
char serialbuf[32]; //This gives the incoming serial some room. Change it if you want a longer incoming.
#include <SoftwareSerial.h>
#include <string.h> // we'll need this for subString
#define MAX_STRING_LEN 20 // like 3 lines above, change as needed.
SoftwareSerial SoftSer(11, 10); // RX, TX
void setup(){
Serial.begin(9600);
SoftSer.begin(9600);
}
void loop() {
if (SoftSer.available() > 0) { //makes sure something is ready to be read
static int bufpos = 0; //starts the buffer back at the first position in the incoming serial.read
char inchar = SoftSer.read(); //assigns one byte (as serial.read()'s only input one byte at a time
if (inchar != EOPmarker) { //if the incoming character is not the byte that is the incoming package ender
serialbuf[bufpos] = inchar; //the buffer position in the array get assigned to the current read
bufpos++; //once that has happend the buffer advances, doing this over and over again until the end of package marker is read.
}
else { //once the end of package marker has been read
serialbuf[bufpos] = 0; //restart the buff
bufpos = 0; //restart the position of the buff
/*
THIS IS WHERE THE CODE HAPPENS
*/
}
}
}
char* subStr (char* input_string, char *separator, int segment_number) {
char *act, *sub, *ptr;
static char copy[MAX_STRING_LEN];
int i;
strcpy(copy, input_string);
for (i = 1, act = copy; i <= segment_number; i++, act = NULL) {
sub = strtok_r(act, separator, &ptr);
if (sub == NULL) break;
}
return sub;
}
Here’s an example.
Say you have a serial device hooked up to your softserial port and in inputs “10,50,100.” to the arduino to be split up. If you want to set each of these numbers to separate integers and then print them to the serial console, you’d do it like this.
const char EOPmarker = '.'; //This is the end of packet marker
char serialbuf[32]; //This gives the incoming serial some room. Change it if you want a longer incoming.
#include <SoftwareSerial.h>
#include <string.h> // we'll need this for subString
#define MAX_STRING_LEN 20 // like 3 lines above, change as needed.
SoftwareSerial SoftSer(11, 10); // RX, TX
void setup(){
Serial.begin(9600);
SoftSer.begin(9600);
}
void loop() {
if (SoftSer.available() > 0) { //makes sure something is ready to be read
static int bufpos = 0; //starts the buffer back at the first position in the incoming serial.read
char inchar = SoftSer.read(); //assigns one byte (as serial.read()'s only input one byte at a time
if (inchar != EOPmarker) { //if the incoming character is not the byte that is the incoming package ender
serialbuf[bufpos] = inchar; //the buffer position in the array get assigned to the current read
bufpos++; //once that has happend the buffer advances, doing this over and over again until the end of package marker is read.
}
else { //once the end of package marker has been read
serialbuf[bufpos] = 0; //restart the buff
bufpos = 0; //restart the position of the buff
int x = atoi(subStr(serialbuf, ",", 1));
int y = atoi(subStr(serialbuf, ",", 2));
int z = atoi(subStr(serialbuf, ",", 3));
Serial.print("The first number, x is: ");
Serial.print(x);
Serial.print(" - The second number, y is: ");
Serial.print(y);
Serial.print(" - The third number, z is: ");
Serial.print(z);
Serial.println();
}
}
}
char* subStr (char* input_string, char *separator, int segment_number) {
char *act, *sub, *ptr;
static char copy[MAX_STRING_LEN];
int i;
strcpy(copy, input_string);
for (i = 1, act = copy; i <= segment_number; i++, act = NULL) {
sub = strtok_r(act, separator, &ptr);
if (sub == NULL) break;
}
return sub;
}
The following is a very specific guide and like all guides of this nature written by me it is mostly for my benefit so I can come back to it later. It is a modification of this guide written by Campus IT. If you have any suggestions to improve anything, PLEASE shoot me an email or leave me a comment below.
I will be connecting my Raspberry Pi Model B+ running the latest build of Raspbian using the Edimax EW-7811Un WiFi dongle to this kind of network (From Campus IT):
Having an internet connection will make doing this much much easier. In fact, if all you need to do is share your laptops WiFi with the Pi over the Ethernet port on your laptop that is quite easy (For WPI people please note that this is a violation of the networks’ acceptable use policy). For windows 8.1:
If you’re using a fresh install, make sure you set the Pi’s internal time to the proper time using raspi-config. It’s under internationalization options.
sudo raspi-config
You will then need to register the MAC address
Next we need to acquire the proper certificates.
Campus IT has already created a good tutorial for doing this found here. You’ll want two get two certificates seen here:
Move those two documents onto the Pi as well. I’m using
/home/pi/certs/
as the location for my certificates for the sake of this tutorial.
From there you’ll have to convert the ‘certificate.p12’ document to a .pem format with OpenSSL. OpenSSL is installed by default in Raspian. Do this with the following command:
Enter the password for the NETWORK when prompted. We now have 3 certificate files. The CA-.pem, certificate.p12 and certificate.pem all located in the /home/pi/certs directory on the pi.
Next we have to disable all the default wifi settings that come with Raspian. Do this by changing your /etc/network/interfaces file to the following:
auto lo
iface lo inet loopback
iface eth0 inet dhcp
#allow-hotplug wlan0
#iface wlan0 inet manual
#wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
#iface default inet dhcp
Doing this stops the Pi from trying to use the wlan0 device at boot and will allow us to use it directly.
Now we must configure wpa_supplicants. It doesn’t really matter where you put the configuration file, but the raspberry pi places it by default here:
/etc/wpa_supplicant/wpa_supplicant.conf
Edit the file to look like the following. Note that things you WILL have to change are marked with []’s. Also note that this config places all 3 certs in that directory I’ve mentioned a few times.
I found that in an example configuration of wpa_supplicant.conf specifically notes the need of a .pem file for the client cert, thus the conversion.
We’re pretty much done, all we need to do is add a few steps to the boot process to start the whole process each time the device boots. We can use crontab or /etc/rc.local (thanks Greg Tighe) to accomplish this.