Skip to content
Snippets Groups Projects
Commit c60fc9ad authored by Anton Sarukhanov's avatar Anton Sarukhanov
Browse files

Import all (real) blog posts and associated images from WordPress

parent cbee16f8
No related branches found
No related tags found
No related merge requests found
Showing
with 449 additions and 0 deletions
Title: Garden Automation
Description: Watering a container garden with computers.
Date: Feb 14, 2015 22:15
Cover: /media/garden/soil-wide.jpg
Since moving in 2013, I've been trying to take full advantage of my
balcony and its (relative) abundance of sunlight. Obviously, **plants!**
So Jess and I bought plants, and seeds, and pots, and soil, and more
seeds, and more pots, and more soil. And eventually we had a problem:
**that's a metric shit-ton of water** to carry, in pitchers, to these
thirsty jerks almost every single day. A second problem is that
different pot-plant-soil combinations consume water at different rates.
That means not only carrying water in pitchers, but also checking almost
every pot to see if it even *needs* water. That's a lot of repetitive
work. As a programmer, I don't like doing repetitive work. That's what
we have computers for. And so, naturally, I employed a computer to do
the job.
![Summer 2014](/media/garden/thumbnails/1000x_/plants-summer.jpg)
The Idea
========
My goals were simple: to reduce **how often** I need to make trips to
water my plants, and to reduce the **amount of effort** involved in
watering them (I'd prefer not to poke wet soil 15 times a day). The
first part could be addressed with a simple **large barrel of water
sitting on my balcony** - no more 15 trips to the sink. But that's not
enough, I don't want to water the plants by hand at all!
The steps one follows to water a plant are generally to: check the soil
moisture level, decide if it needs water, and (if needed) pour water in
it. Soil moisture sensors have been researched by tech-savvy farmers for
years, and the Internet offered a plethora of reading materials on the
subject. More reading than I expected.
Sensing Moisture
================
![Tomatoes, VH400 Sensors, and
Sprinklers](/media/garden/thumbnails/1000x_/growing.jpg)
Resistive
---------
The most simple method of electronically sensing moisture is
**resistive**. That is, measuring the resistance between two pins
inserted into the test medium. The resistance will vary with the
moisture content: moisture improves conductivity, reducing resistance.
Preliminary tests of this were promising, but the method fell on its
face merely hours into testing.
As electrons flow from one pin to the other,
[electrolysis](http://en.wikipedia.org/wiki/Electrolysis) occurs. This
results in corrosion, which substantially affects the measured
resistance. The effect was substantial enough to entirely void any
long-term measurements taken with this method.
Capacitive
----------
Another common method of moisture measurement, one that doesn't
necessitate corrosion of the probes, is **capacitive**. When two flat
metal rods are inserted side-by-side in some medium (even air), the
space surrounding them forms a capacitor. By measuring the capacitance
of this "capacitor", we can detect the **dielectric permittivity** of
the surrounding medium. Roughly, this means how much energy can be
stored in that space. Conveniently, this correlates with moisture
content just like resistance.
Inconveniently, my first attempts at making a conductive moisture sensor
were failures. I have some suspicions as to why, and a more detailed
blog post may follow dedicated to that. In the meantime, I took a
shortcut.
Not Doing It Yourself
---------------------
I preferred to have this system working **now** rather than perfect
**later**. Spending $37 on a [third party
sensor](http://www.vegetronix.com/Products/VH400/) was an acceptable
tradeoff to take in pursuit of this. I found the Vegetronix VH400 to be
reliable, and accurate in its measurements.
Deciding When to Water
======================
![Arduino Prototyping](/media/garden/thumbnails/1000x_/arduino-proto.jpg)
Now that I had a way of measuring soil moisture, I wanted to automate
acting on that information. Time to write a simple program and load it
on a microcontroller, of course! For this job I chose an
[Arduino](http://arduino.cc/en/Main/ArduinoBoardMega). After spending a
while playing with Arduino shields to give this thing network
capabilities, I settled on a slightly more complex approach. The Arduino
would be equipped with a Bluetooth 4 (also known as Bluetooth Low
Energy) shield, allowing it to communicate with other devices without
wires.
I didn't feel like developing a mobile app to interact with this thing,
so it would need to somehow talk to my computer. Since my computer is on
the internet, I would need to connect my electronic gardener to the
internet somehow. I did this with a Raspberry Pi equipped with a
Bluetooth 4 dongle. A quick Python program later, my Arduino gardener
was using the Raspberry Pi (named "GardenGate") as a gateway to talk to
a server on the internet.
The remote server has a [web interface](http://pl.ant.sr) for me to
monitor moisture levels and set irrigation thresholds. These thresholds
are passed back to the Arduino, which refers to them as it constantly
monitors the soil moisture content.
![Raspberry Pi used as a Bluetooth-to-Internet
gateway](/media/garden/thumbnails/1000x_/raspi-gardengate.jpg)
Watering
========
![The watering rig](/media/garden/thumbnails/1000x_/cooler-rig.jpg)
The Arduino checks moisture levels nonstop. When it detects that a pot's
moisture level has fallen below the target zone set for that pot, it
checks to ensure that it is daytime (watering plants at night can cause
diseases and rotting). If it is an acceptable time to water the plants,
the Arduino triggers a pump submerged in a large cooler. The pump is
connected to a flow meter to monitor water consumption, which in turns
leads to a network of tubes leading to potted sprinklers.
All in all the system did the job, but there are **many** improvements
to be made.
![Cayenne Peppers](/media/garden/thumbnails/1000x_/cayenne.jpg)
Title: Test Box v2
Description: Design and construction of Test Box v2, a device for equipment control at fencing tournaments.
Date: February 20, 2015
Cover: /media/testbox/bodycord-fail.jpg
This post details the design and construction of Test Box v2, a custom device used for equipment control at fencing tournaments.
## Background <small>[In a rush? Skip this section.](#objectives)</small>
In 2007, I was semi-formally named Club Armorer at [Cobra Fencing](http://cobrafencing.com). The job entails testing and repairing fencing equipment owned by members and the club itself, some general facility maintenance tasks, and serving on the equipment inspection committee at tournaments. Equipment inspection, as the name implies, involves testing each competitor's gear to ensure that it meets requirements set forth by the [USFA](http://www.usfencing.org/page/show/695208-rulebook "US Fencing Association"). The tests are primarily concerned with ensuring the safety of the fencer as well as the integrity of the competition. The safety-related tests ensure that protective gear is, in fact, protective. The integrity-related tests were what I found more intriguing, and what the rest of this post is concerned with. Modern competitive fencing uses a system of wires, contacts, and tiny springs to detect when a point has been scored. At the center of the fencing strip, there is a scoring machine, which is connected to a spring-loaded reel of wire at each end of the strip. The fencer clips the reel wire onto the back of his or her jacket, and connects it to his weapon with a body cord worn inside the jacket. Inside the tip of the weapon, there is a button which is depressed when the weapon tip strikes a surface, such as one's opponent. This closes a circuit, which is detected by the scoring machine. An additional circuit is completed between the weapon (which is made of conductive metal) and the opponent's metallic vest or jacket, to indicate that the touch was on-target. To ensure that all scoring machines reliably detect a hit made by a fencer, the body cords, weapons, and conductive jackets are tested to ensure that the item's electrical resistance does not exceed a defined limit. This is done by a panel of armorers, many of whom use custom testing devices ranging from a small adapter for off-the-shelf multimeters to complex all-in-one setups.
## The Precursor
[![og-box](/media/testbox/thumbnails/1000x_/og-box.jpg)](https://ant.sr/test-box/og-box)
I felt the need for a club test box. My grandfather got me into circuits and electrical engineering at a young age, so I felt (perhaps overly) prepared for the task. Many internet hours and a few meetings with my grandpa later, the original Test Box was born. It has now faithfully served me and Cobra Fencing for almost **7 years**, so I rewarded it (and myself) by replacing the meters which had become sticky and sluggish with age. Despite breathing new life into the original, I felt it was time to design a new version.
## Objectives
I didn't have many complaints about the original test box. In fact, it worked pretty damn well for a "v1" product. Initial goals for v2 were to:
* Reduce size
* Eliminate the need for regular calibration
* Simplify power supply (v1 uses **four** D cells!)
* Simplify pass/fail indication for untrained onlookers
The test box would need to test for a few things to fully examine a piece of equipment. For example, a body cord contains three parallel wires, running from one three-prong plug to another three-prong plug (or a two-prong plug and a clip, used in Foil and Saber fencing). A common of failure is a break in the wire, which can be tested for by **measuring conductivity end-to-end** and applying some stress to the wire. Sometimes the wire can be so damaged that conductors are exposed and shorting. This can be tested for by **passing a current down one wire, and checking if it appears on any incorrect wires**. The box needs to have **all standard fencing connectors**. It needs to measure very precisely and accurately, as the pass/fail thresholds are strict. A body cord may not have an end-to-end resistance higher than **one ohm**. A weapon is permitted **two ohms**. A conductive jacket, mask, or glove is permitted **five ohms**. The box needs to **detect which piece of gear is being tested**, and apply the relevant ohm threshold by **displaying the item's resistance in green (pass) or red (fail)**.
## Design
[![Raspberry Pi, PiTFT, ADC Pi](/media/testbox/thumbnails/1000x_/first-test-multimeter.jpg)](https://ant.sr/test-box/first-test-multimeter)
I decided early on that Test Box v2, or at least my first prototype of it, would be built around a Raspberry Pi. It can reliably run Linux, and is exceptionally cheap at $35\. I liked the ability to build multiple prototypes and replace parts easily. I found the $45 [Adafruit PiTFT 2.8" Cap Touch display](https://learn.adafruit.com/adafruit-2-8-pitft-capacitive-touch) an attractive proposition as well, as installation is almost entirely plug-and-play with the Raspberry Pi. My first PiTFT seems to be defective, as the touchscreen has a pretty bad jumpy cursor issue. When I reported this to Adafruit support, they told me to [wipe down the display with a dryer sheet](http://forums.adafruit.com/viewtopic.php?f=50&t=61328). This didn't help. I haven't had this issue with the second one. The box needed an Analog Digital Converter to perform the measurements, and the Raspberry Pi does not have one onboard. The [AB Electronics ADC Pi](https://www.abelectronics.co.uk/products/3/Raspberry-Pi/17/ADC-Pi-V2---Raspberry-Pi-Analogue-to-Digital-converter) is doing the job. It is an 8-channel 17-bit ADC, providing ample resolution for my needs. It is mounted on top of the Raspberry Pi in the photo to the right. A bit of research showed that the easiest way to measure resistance with an ADC would be to build a [voltage divider](http://en.wikipedia.org/wiki/Voltage_divider) circuit (a resistor, essentially) for each channel. With a bit of soldering, I had the core components of Test Box v2 completed.
## Prototype
[![First attempt at fitting it all together](/media/testbox/thumbnails/1000x_/prototype-interior.jpg)](https://ant.sr/test-box/prototype-interior-1)
Afraid of butchering the enclosure, I decided that a prototype was necessary. A piece of cardboard came in handy, along with some banana jacks from Radio Shack. This allowed me to ensure all the hardware worked, mock real use-cases looking for any unforeseen problems, and think through any final design details. Mounting the LCD on my makeshift lid also kept the different circuit boards from shorting each other out. My first guess at positioning the screen turned out to be just fine, and I transferred much of the layout to the final version.
[![The prototype, all wired up.](/media/testbox/thumbnails/1000x_/prorotype-interior-flash.jpg)](https://ant.sr/test-box/prorotype-interior-flash)
I proceeded to mount the voltage divider board, and wire each channel to the appropriate connector(s) on the panel. Having all of this set up, I turned my attention to the software needed to make it tick.
## Code
[![Prototype Exterior](/media/testbox/thumbnails/1000x_/prototype-exterior.jpg)](https://ant.sr/test-box/prototype-exterior-1)
Writing the code for this was fairly straightforward, as the ADC manufacturer provides a [Python library](https://github.com/abelectronicsuk/ABElectronics_Python_Libraries/tree/master/ADCPi "ADCPi Python Library"). I used [Kivy](http://kivy.org/ "Kivy - A python framework for UI development") to build the UI. My code is public at [git.xhost.io/anton/test-box](https://git.xhost.io/anton/test-box) (be warned: The code is somewhat of a mess. A thorough rewrite is pending.) [testbox.py](https://git.xhost.io/anton/test-box/blob/master/testbox.py "anton/test-box/blob/master/testbox.py") is the main program, which runs on the Raspberry Pi as a daemon. It uses [measure.py](https://git.xhost.io/anton/test-box/blob/master/measure.py "anton/test-box/blob/master/measure.py") to interact with the ADC and retrieve resistance measurements.
[![The user interface (first iteration).](/media/testbox/thumbnails/1000x_/prototype-bodycord.jpg)](https://ant.sr/test-box/prototype-bodycord)
Kivy was slightly troublesome to install on the Pi as it had a few prerequisites which took **ages** to compile and install on the 700 MHz single-core ARM processor. Once it was working however, developing the UI was easier than I imagined possible. 10/10, would use again. The completed UI shows a "Connect something!" call to action when idle. When the box detects a body cord, weapon, or other test subject connected, the screen displays the resistance of that item. The measurement is shown in green or red, depending on the resistance threshold for that type of item.
## The Build
[![Transplanted into the real enclosure](/media/testbox/thumbnails/1000x_/almost-done-open-with-battery.jpg)](https://ant.sr/test-box/almost-done-open-with-battery)
With working code, I set out to re-assemble the test box in its permanent (aluminum) enclosure. Lacking access to a proper machine shop, I decided to make do with a vice, a drill, and a coping saw. The banana jacks used for test connections required a simple round hole, and so were very quick to complete. Cutting, and subsequently filing, the opening for the LCD took way longer than I care to admit. This assembly has one flaw, which I'm one online order away from fixing. The Raspberry Pi and the other two circuit boards are both mounted to the conductive aluminum+steel enclosure with conductive steel bolts. This grounded the enclosure, which is problematic when a test connector is accidentally shorted to the case (with a finger, for example). When this happens, measurements become unpredictable and incorrect. The bolts will be replaced with [adhesive PCB standoffs](http://www.banzaimusic.com/Adhesive-Standoffs/) as soon as I can get my hands on some (Radio Shack let me down, as always), which should address the fault.
[![RJ45 and Micro USB jacks](/media/testbox/thumbnails/1000x_/connectors.jpg)](https://ant.sr/test-box/connectors)
The last step left before the hardware is complete is to install Micro USB and Ethernet ports on the back of the box. The Raspberry Pi is powered through USB (which is convenient, as almost any cell phone charger can be used as a power source). The Ethernet port is used for programming. When the Pi detects an available network and receives an IP address from DHCP, the address is displayed on-screen. This allows me to SSH in and get to work.
## Closing Thoughts
The test box surpassed my own expectations. It is possible (likely, even) that this was due to low expectations, but I'm still calling it a success. It is **smaller** than the predecessor. There is no **need for calibration**. Power is supplied over USB, and an optional battery can be installed inside to act as a backup. I haven't purposefully tested battery runtime yet, but the device has been used for over an hour without a power supply attached without problems. There may be a follow-up with more technical details and some extra features. Stay [tuned](http://ant.sr/feed "Follow my RSS feed!")!
[![weapon-test](/media/testbox/thumbnails/1000x_/weapon-test.jpg)](https://ant.sr/test-box/weapon-test)
Title: Email Deliverability
Date: November 1, 2015
<img src="/media/mailbox-on-the-street.jpg" class="inline-left" alt="a red mailbox">
Email may be simple conceptually, but actually getting a message to a recipient's inbox seems to get harder every year. This is primarily caused by the arms race between mail service providers and spammers, phishers, and other bad actors. New offensive tactics lead to new defensive tactics, in the form of new protocols and rules. For the innocent server admin sending a few notifications, this results in quite a game of catch-up.
Here are a few ways to avoid the spam filter:
## Check Blacklists
Mail servers use a number of [blacklists](https://en.wikipedia.org/wiki/DNSBL) to track IP addresses used by known spammers. If your emails are being consistently rejected or spam-filtered, check your server's IP address against these blacklists in case the previous owner of your IP address did some bad things. MXToolBox has a [nifty tool for this](http://mxtoolbox.com/blacklists.aspx).
Should you find yourself on a list, check the list's website for information on getting de-listed.
## Forward-confirmed reverse DNS
Your server probably has a DNS hostname (eg. `mail.example.com`). That _forward_ record is used for resolving a name to an IP address. A _reverse_ record is one that maps an IP address back to a hostname. You can look up a forward record using `nslookup mail.example.com`, and you can look up a reverse record with `nslookup 203.0.113.123`. **Your forward record should match the reverse record**. A server at `mail.example.com` shouldn't have a reverse hostname of `c-123-113-0-203.hsd1.nj.comcast.net`!
To fix this, update the reverse DNS record for your server's IP address to contain its correct hostname. This record is managed by whoever owns the IP address: your ISP or hosting provider.
## SPF Records
SPF ([Sender Policy Framework)](https://en.wikipedia.org/wiki/Sender_Policy_Framework) uses DNS records to verify that a server sending mail with a `From: somewhere@example.com` header is actually allowed to send mail on behalf of `example.com`. Access your DNS management interface, and create a TXT and an SPF record (with identical contents):
:::text
example.com. 86400 IN TXT "v=spf1 a ip4:203.0.113.123 ip6:2001:DB8::aa:bb:cc:dd ~all"
example.com. 86400 IN SPF "v=spf1 a ip4:203.0.113.123 ip6:2001:DB8::aa:bb:cc:dd ~all"
Replace the IP addresses with your own, of course. You can include multiple `ip4` and `ip6` sections if you have more than one server. For an SPF syntax reference, see [this helpful page](http://www.openspf.org/SPF_Record_Syntax). Remember that DNS records are cacheable, so an SPF update can take a day or longer to reach some mail servers. If you aren't sure about your changes, replace that `86400` (cache time-to-live in seconds) with a smaller value like 60 (one minute) so you can revert them quickly.
## DKIM Records (and headers)
DKIM ([DomainKeys Identified Mail](https://en.wikipedia.org/wiki/DomainKeys_Identified_Mail)) uses cryptographic keys to prove that your server is authorized to send mail for your domain (the same reason we have SPF). You'll need to generate a private/public key pair for your mail server, configure your mail server to sign outgoing messages with the private key, and share the public key with the world using another DNS record.
First, generate the keypair. Don't make the key smaller than 1024 bits (otherwise Gmail, among others, won't trust it). Here's how you might do this on Linux:
:::text
openssl genrsa -out private.pem 1024 -outform PEM
openssl rsa -in private.pem -out public.pem -pubout -outform PEM
After generating a keypair, configure your mail server to sign outgoing messages using the private key. Debian-administration.org has an [excellent tutorial on doing this with exim4](https://www.debian-administration.org/article/718/DKIM-signing_outgoing_mail_with_exim4).
Finally, announce the public key with a DNS record. Here's the format:
your_key_label._domainkey.example.com. 86400 IN TXT "v=DKIM1; k=rsa; p=PUB_KEY_GOES_HERE"
Replace `your_key_label` with whatever key label you configured in your mail software, and replace `PUB_KEY_GOES_HERE` with the contents of your public key (don't include the "BEGIN" and "END" lines, and remove any line breaks).
## Test the Records
Its easy to check your work with SPF and DKIM: send a message to the [Port25 Solutions Email Verification test tool](https://www.port25.com/support/authentication-center/email-verification/) and you will receive an automated report moments later. For a second opinion, send a test message to a Gmail account. Find the message, and [look at the headers](https://support.google.com/mail/answer/22454). The `Authentication-Results` header will show the result of Google's SPF and DKIM checks. Here's what you want to see:
#!text
Authentication-Results: mx.google.com;
spf=pass (google.com: domain of you@example.com designates 203.0.113.123 as permitted sender) smtp.mailfrom=you@example.com;
dkim=pass header.i=@example.com
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=example.com; s=your_key_label;
h=Date:Message-Id:To:From:Subject; bh=vaDhn7R9d+nyJO//MTxaFLQMaXlBbkuQTL3obpK83gM=;
b=c0d7YN4+xPMxUoFccfXYnwUSh3cvRwzyQ3K68DIogrHYTNej5TzZ4w4aiY5N92wZyzd3tgjGQwV/sQbfxH/EQpF+leg6HHPVsv1pYR78/4hjEBJgrX6b/E2ezw3ICTOglC//Cyz7RLdniSqavXQr3elIJI4giliNU0Eu6Qb3mOo=;
## DMARC
[DMARC](https://en.wikipedia.org/wiki/DMARC), configured by yet another DNS entry, gives you two capabilities:
* Tell mail servers how strictly they should treat messages claiming to originate from your domain.
* Be notified anytime an email from your domain fails authentication checks.
Here's a DMARC record which says "reject any mail claiming to be from my domain if it fails authentication checks. Send daily failure reports to postmaster@example.com":
_dmarc.example.com. 86400 IN TXT "v=DMARC1; p=reject; rua=mailto:postmaster@example.com"
Check the [authoritative source](https://dmarc.org/overview/) for more details.
## Working "From:" address and postmaster
The address in your `From:` header should be able to receive mail (somewhere, not necessarily on this server) and should be monitored for bounces and other mail-delivery-related notifications. A postmaster@example.com account should also exist, and should also be monitored.
## Working MX records
This may be obvious from the previous section, but you should have working MX records enabling the delivery of incoming mail. You **do not** need to have an MX record for every server that sends mail, just the ones which receive it. I use Google Apps for my personal domain, so my MX records point to their servers (even though I send messages from plenty of other places).
## Anything else?
These steps have been sufficient to get consistent mail delivery for my websites and those of my clients. If I've missed something, please drop a line below or [let me know directly](contact).
## References
1. [Bulk Senders Guidelines - Gmail help](https://support.google.com/mail/answer/81126)
2. [Add a DMARC record - Google Apps Administrator Help](https://support.google.com/a/answer/2466563)
3. [DKIM-signing outgoing mail with exim4](https://www.debian-administration.org/article/718/DKIM-signing_outgoing_mail_with_exim4)
Title: PyBusMap
Description: A real-time bus map powered by Python, SQLAlchemy, Flask, Celery and Leaflet. This is a rewrite of the PHP version from 2013.
Date: Feb 4, 2016
Cover: /media/pybusmap/sac.png
Three years ago, I made a real-time map of Rutgers buses as a side project. It was a messy PHP script which grabbed data from the NextBus API, and displayed it on a Leaflet map. That map worked nicely, but the code was an embarrassment. I decided to try again, and [re-wrote it](https://git.xhost.io/anton/pybusmap).
There's an instance for Rutgers buses at [rutge.rs](https://rutge.rs), but this version actually supports all Nextbus-tracked bus agencies. Just set a config parameter!
## Tech Stack
PyBusMap is written in Python 3. It uses a lightweight web framework called [Flask](http://flask.pocoo.org/) for the HTTP stuff, the [SQLAlchemy ORM](http://www.sqlalchemy.org/), and PostgreSQL. [Celery](http://www.celeryproject.org/) manages background tasks.
## Design
The goal was to take data from the [NextBus API Feed](https://www.nextbus.com/xmlFeedDocs/NextBusXMLFeed.pdf), store it in a database, and display it on a map. I wanted the database cache for two reasons:
1. I can record historic data for future data science projects.
2. The NextBus data has tons of quirks. Normalizing it server-side and storing the result allows for multiple front-ends (a mobile app?) without re-writing the normalization code each time.
Being familiar with SQLAlchemy, I was excited to try it out on a clean-slate project. I used Flask because it provides URL routing, templating, and a slew of other features without getting in my way.
Celery is used here to sync new data from NextBus on a schedule. It kicks off a data update job every few seconds for vehicle locations and predictions, and once a day for route and stop information.
Some data has to be fetched with large batches of requests. These are done asynchronously (using [requests-futures](https://github.com/ross/requests-futures)).
## Code
![PyBusMap running, in development.](/media/pybusmap/thumbnails/1000x_/pbm-work.png)
The object models are defined in [models.py](https://git.xhost.io/anton/pybusmap/blob/master/models.py). Logic for interfacing with NextBus is in [nextbus.py](https://git.xhost.io/anton/pybusmap/blob/master/nextbus.py). There are three entry points:
* [app.py](https://git.xhost.io/anton/pybusmap/blob/master/app.py) uses Flask to serve the user-facing webpage with the map, as well as the AJAX endpoint providing real-time data.
* [celerytasks.py](https://git.xhost.io/anton/pybusmap/blob/master/celerytasks.py) is where the Celery tasks are called from - these use the NextBus logic to populate the database.
* In addition to these, [manage.py](https://git.xhost.io/anton/pybusmap/blob/master/manage.py) has a few functions which can be used from the command line to initially populate the database, watch the Nextbus API quota usage, and more.
## Next
I have a few things I'd like to add to PyBusMap, such as routing (building the quickest route to a destination and providing directions).
Here's the map in action. Or go see the [full version](https://rutge.rs).
<iframe style="width: 100%; border: none; height: 300px;" src="//rutge.rs/em#S41" height="150" width="300"></iframe>
Title: Setting up a Debian 8 development machine
Description: My process for setting up a new development server.
Date: May 7, 2015 18:17
This post was going to be a note in Evernote, but [their](http://chrisshattuck.com/blog/adding-syntax-highlighting-code-snippets-evernote) [interface](https://discussion.evernote.com/topic/44714-request-embed-code-snippets-with-auto-formatting-and-syntax-highlighting/) [is](http://www.quora.com/The-best-way-to-make-Evernote-support-Code-Syntax-Highlighting-and-Formatting) [completely](https://discussion.evernote.com/topic/67201-feature-request-syntax-highlighting-for-code/) [unusable](https://discussion.evernote.com/topic/40770-quick-way-to-format-text-that-is-a-code-snippet/) for storing code, so it's going here. These are steps I took to set up a [Debian 8](https://www.debian.org/News/2015/20150426) server for personal websites, perhaps small web apps, and other projects in PHP and Python.
This is far from a universal setup guide! It's more of a public scratchpad for me to document my current process. It might suit your needs, or it might not. Scroll below the code block to see why I chose certain packages. Replace `YOU` and `SERVERNAME` accordingly.
:::bash
# <Create VM, connect as root.>
# Make user
adduser YOU && adduser YOU sudo # Create user with sudo privs.
# SSH Key
sudo -iu YOU # Become non-root.
mkdir ~/.ssh # Make ssh directory
vi ~/.ssh/authorized_keys # Paste SSH key (use a unique one, 4096 bits)
# Verify that your SSH key works before you forget...
# Secure login
sudo -i # Become root again
passwd -d root # Destroy root's password. No need for it.
vi /etc/ssh/sshd_config # PermitRootLogin no, PasswordAuthentication no
# Set network, hostname, DNS as appropriate
vi /etc/network/interfaces # Configure static network settings as appropriate.
echo 'SERVERNAME' > /etc/hostname # Set the hostname
vi /etc/resolv.conf # Set domain and search to your domain name, and set your favorite nameservers.
reboot # Verify network settings, hostname, SSH access.
# <Connect as non-root user>
ssh-keygen -b4096 # Make an SSH key (for git, outgoing SSH, etc.)
# Setup your apps. Tmux:
vi ~/.tmux.conf # Paste your tmux configuration
scp -r YOU@old-server.example.com:~/.tmux ~/.tmux # Grab any plugins (from old server in this case)
vi ~/.bashrc # Put stuff at the end to make tmux autostart.
# Vim
vi ~/.vimrc # Paste your vim config
# Vim plugins would go here. I'm a noob and don't use any.
# Time for more root stuff!
sudo -i
# Set firewall rules
vi /etc/iptables.rules # Sample ruleset here: https://wiki.debian.org/iptables
# Install must-haves
apt-get update
apt-get upgrade
apt-get install fail2ban tmux iptables-persistent git build-essential
# Dev/Hosting Stuff (edit as needed)
apt-get install nginx ssl-cert # Web
apt-get install php-pear php5-{fpm,mysql,ldap} # PHP
apt-get install python-{dev,virtualenv} virtualenvwrapper python3{,-dev,-psycopg2} # Python
apt-get install mariadb-{server,client} # MySQL Equivalent
apt-get install postgresql libpq-dev # PostgreSQL
# Done
logout # go back to regular user
source ~/.bashrc # load up tmux (logging out works too, but this is faster)
# Package Choices
### nginx
Apache has long stood as the default Linux webserver, and for good reason. It's a fantastic piece of software. In recent years, [nginx](http://nginx.org/en/) seems to be rapidly rising in popularity while Apache (and IIS) fall. Besides being substantially slower, Apache contains a lot of historic cruft. Nginx is faster and more lightweight. I also find its configuration syntax easier to work with.
### mariadb
MySQL is a staple in web applications small and large. Its easy to install, widely available, and has decent tooling on most platforms. My biggest [problem](http://blog.smartbear.com/open-source/5-reasons-its-time-to-ditch-mysql/) with it is that it is owned and driven by Oracle, which means that corporate interests come before community interests. That's enough to turn me off from relying on a piece of software as a building block of my code and infrastructure, especially when a drop-in alternative like [mariadb](https://mariadb.com/blog/why-should-you-migrate-mysql-mariadb) is available.
### Others
**ssl-cert** is a [convenient way](http://www.microhowto.info/howto/create_a_self_signed_ssl_certificate.html#idp35392) to have a self-signed SSL certificate generated for you on Debian. **php-pear** is a PHP [package manager.](https://pear.php.net/) **iptables-persistent** loads up your desired iptables settings at reboot, otherwise they would go away. **postgresql** is [preferable over mysql](http://stackoverflow.com/a/8184478/2274664) for some/many uses**, libpq-dev** are development headers for building postgres clients. **tmux** is a [terminal multiplexer](https://en.wikipedia.org/wiki/Tmux). It lets you break a single console session into panes, have multiple "windows" that you can switch between with a keystroke, and much more. If you feel that working through SSH is limiting or unwieldy, you need this. **git** is a decentralized version control system (DCVS). If you aren't using version control, **[use it](http://git-scm.com/book/en/v2/Getting-Started-Git-Basics).** If you're using a different system for version control (svn, cvs), I strongly recommend that you [check out git](http://git-scm.com/book/en/v2/Getting-Started-Git-Basics) anyway.
# Other Considerations
### Backups
I host with [Linode](https://linode.com/), and they provide a [backup service](https://www.linode.com/backups). I plan to set up a second, offsite, backup system (maybe [Tarsnap](https://www.tarsnap.com/), or [rsync.net](http://rsync.net/)) eventually, just in case.
### SSH IP Restrictions
I want to have the ability to remotely admin this from, say, my [phone](https://panic.com/prompt/). Since I don't have a reliable VPN set up right now, I leave this open. fail2ban and disabling passwords help me feel better about this. Its definitely a good idea to set up a VPN to use as a [jump host](https://en.wikipedia.org/wiki/Jump_server) instead.
<!-- Do you have a documented procedure for this? Leave a note! -->
Title: Squashing SQLAlchemy Migrations with Flask-Migrate
Date: January 17, 2016
<img src="/media/yodawg-migration.jpg" alt="Yo dawg" class="inline-right" />While developing a Python application with SQL<wbr>Alchemy, you may find yourself rapidly iterating on database schemas as your project evolves. If you are committing your work often (**as you should be**), this can lead to oodles of [schema migration scripts](http://alembic.readthedocs.org/en/latest/tutorial.html). When a project is in production, these migrations are great for rapidly deploying changes. Until then, there is little use in accumulating a pile of migrations representing every small tweak you made to your models. Squashing these migration scripts into a single "initial" migration is good for your sanity, and results in a leaner git repository. I didn't find the process of squashing your alembic migrations to be well-documented online, so here's my version.
# Squashing _Some_ Migrations
If you only want to squash _some_ of your migration history, but not all of it, follow the instructions outlined in [this StackOverflow answer](http://stackoverflow.com/a/27889622).
# Squashing _All_ Migrations
This may be obvious already, but I'll share hoping it saves someone a few minutes of hassle. If you want to squash all of your migrations into one "initial migration", do the following. Your migrations will be re-created as a single script, based on the current state of your models.
**Note:** These steps may need to be adapted depending on your project's structure. I am using Alembic via [Flask-Migrate](https://github.com/miguelgrinberg/Flask-Migrate).
* Truncate your **alembic_version** table.
`sql> TRUNCATE TABLE alembic_version;`
* Delete the **migrations** directory.
`rm -rf migrations`
* Re-create the **migrations** directory from scratch.
`python manage.py db init`
* Create your database schema (from your model definitions) as a single migration.
`python manage.py db migrate`
* Apply any pending migrations (if your database isn't already up-to-date).
`python manage.py db upgrade`
content/media/garden/arduino-proto.jpg

1.82 MiB

content/media/garden/cayenne.jpg

2.17 MiB

content/media/garden/cooler-rig.jpg

2.32 MiB

content/media/garden/growing.jpg

1.37 MiB

content/media/garden/plants-summer.jpg

2.53 MiB

content/media/garden/raspi-gardengate.jpg

2.29 MiB

content/media/garden/soil-wide.jpg

972 KiB

content/media/mailbox-on-the-street.jpg

138 KiB

content/media/pybusmap/pbm-work.png

115 KiB

content/media/pybusmap/sac.png

327 KiB

content/media/testbox/ChoiPerrier2013.jpg

5.48 MiB

content/media/testbox/Voltage-Divider-Circuit.png

38.5 KiB

content/media/testbox/almost-done-open-with-battery.jpg

2.13 MiB

content/media/testbox/bodycord-fail.jpg

2.59 MiB

0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment