FontAwesome icons in Android's MapFragment

I spent some time trying to customize MapMarkers in Google Maps Android SDK, I hope this guide is useful if you're trying to integrate FontAwesome's icons in your app's map layout. Android Iconfiy is a great library that provides FontAwesome icons in Android, so we'll use that as our source of icons.

Google Map's custom markers needs a BitmapDescriptor:

// Specify an icon
Iconify.IconValue iv = Iconify.IconValue.fa_car;

// Get the bitmap descriptor, we need to build this yet
BitmapDescriptor customMarker = getCustomMarker(iv);

// Setup the marker
MarkerOptions marker = new MarkerOptions()  
                .position(new LatLng(latitude, longitude))
                .title("My title")
                .snippet("My snippet")
                .icon(customMarker)
                .draggable(false);

// Add it to your map instance
mMap.addMarker(marker);  

We can generate the BitmapDescriptor as follows:

public BitmapDescriptor getCustomMarker(final IconValue iconValue) {  
    IconDrawable id = new IconDrawable(getBaseContext(), iconValue).actionBarSize();
    Drawable d = id.getCurrent();
    Bitmap bm = Bitmap.createBitmap(id.getIntrinsicWidth(), id.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
    Canvas c = new Canvas(bm);

    d.draw(c);

    return BitmapDescriptorFactory.fromBitmap(bm);
}

This generate a stroked icon:

I would rather have the shape filled. This is somehow tricky since we need to override the IconDrawable's draw method:

public BitmapDescriptor getCustomMarker(IconValue iconValue) {  
    IconDrawable id = new IconDrawable(getBaseContext(), iconValue) {
         @Override
         public void draw(Canvas canvas) {
             // The TextPaint is defined in the constructor
            // but we override it here
            TextPaint paint = new TextPaint();
            paint.setTypeface(Iconify.getTypeface(getBaseContext()));
            paint.setStyle(Paint.Style.STROKE_AND_FILL);
            paint.setTextAlign(Paint.Align.CENTER);
            paint.setUnderlineText(false);

            // If you need a custom color specify it here
            paint.setColor(Color.BLACK);

            paint.setAntiAlias(true);
            paint.setTextSize(getBounds().height());
            Rect textBounds = new Rect();
            String textValue = String.valueOf(iconValue.character());
            paint.getTextBounds(textValue, 0, 1, textBounds);
            float textBottom = (getBounds().height() - textBounds.height()) / 2f + textBounds.height() - textBounds.bottom;
            canvas.drawText(textValue, getBounds().width() / 2f, textBottom, paint);
        }

    }.actionBarSize();
     Drawable d = id.getCurrent();
    Bitmap bm = Bitmap.createBitmap(id.getIntrinsicWidth(), id.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
    Canvas c = new Canvas(bm);

    d.draw(c);

    return BitmapDescriptorFactory.fromBitmap(bm);
}

This gives us a filled icon:

Comparison between Raspberry Pi, BeagleBone Black, Arduino, and Intel Galileo

I've been teaching an embedded systems course in PUC's CS department for a while, where we use the msp430f5529 experimenter board. It really serves the purpose of learning the bare bones of embedded systems, but unfortunately they tend to be unreliable and sometimes it gets to EE-oriented.

Part of the perks of teaching at a university is that you can apply to university programs and get to play with cool stuff. In advance. For free. So I applied to the Intel Galileo university program, and they kindly donated 20 boards we'll use this semester.

So here's a picture of 4 popular embedded boards: Raspberry Pi, BeagleBone Black, Arduino Uno and Intel Galileo:

If you look closely you'll guess which one is which :)

The following lines compare each one of them, just in case you're wondering which one to use for your next embedded project.

Raspberry Pi (Model B)

Processor: ARM1176JZF-S (ARMv6k) 700-800 MHz

Memory: 512 MB RAM, 128 Kb L2 cache, SD card for OS.

On-board peripherals: Ethernet, 2 USB host ports, true HDMI, Camera connector, Audio, Analog Video.

GPIO and interfaces: 26-pin GPIO header with 1 UART, 2 SPI, 1 I2C, 1 PWM and several other GPIO.

Operating Systems: Raspbian (Debian), ArchLinux, PiDora (Fedora) and some others.

Price: $35

Some remarks on the model B+:

  • Thank god they fixed the USB power supply issue. If you want to connect power-hungry usb devices be sure to get a B+ model. That should fix a lot of reliability issues.
  • It was about time they changed the full-size SD card for a micro SD.
  • If you'll be doing audio stuff then also get the B+, they'v designed a less noisy power source.
  • 9 more GPIO pins
  • 2 more USB ports

BeagleBone Black

This is the big sister of the first embedded board I played with, the BeagleBoard xM /nostalgia

Processor: AM335x Cortex-A8 (ARMv7) 1 GHz

Memory: 4GB on-board memory, 512 MB RAM, 256 Kb L2 cache, SD card for OS. On board-memory can be a huge improvement in performance and overall reliability.

On-board peripherals: Ethernet, 1 USB OTG, mini HDMI

GPIO and interfaces: 92-pin GPIO header, including analog inputs, LCD and MMC headers, I2C, PWM and SPI.

Operating Systems: Debian, Ubuntu, Android and others.

Price: $45

Intel Galileo

I'm just getting started with this one, so I can't comment on long-term reliability or issues.

Processor: Intel Quark SoC X1000 400 MHz (x86). Since this board is based on the x86 architecture it might be possible to see a port of windows embedded for this board.

Memory: 8 MB on-board memory, 256 MB RAM, 16 Kb L2 cache, SD card for OS. SD card for OS. The on-board memory is enough to get it running, though.

On-board peripherals: Ethernet, mini-PCI, 1 USB client, 1 USB host, serial port.

GPIO and interfaces: Same header as Arduino, including analog inputs, PWM, UART, I2C and SPI.

Operating Systems: Linux, based on the Yocto project. Since this is not a full-blown linux distro there's lots of functionalities not available, such as a package manager, man pages or vim.

Price: $70

Arduino Uno

Not an embedded board per-se, but I thought it would be unfair to leave it out of the discussion:

Processor: ATmega 328p, 8-bit, 20 MHz. This allows this board to use several thousand times less power than the other embedded boards.

Memory: 32 Kb on-board memory, 2Kb RAM, 512b EEPROM.

On-board peripherals: None, although it has a lot of expansion boards called "shields" that add a lot of functionality (including satellite modems). The USB port is only for programming the board.

GPIO and interfaces: 25-pin header, including analog inputs, PWM, UART, I2C and SPI.

Operating Systems: N/A

Price: $25

Which one should I buy?

It depends:

  • Do you want to operate this with a small battery? Then your only choice is the Arduino. Also consider taking a look at the very cheap msp430 launchpads.
  • Are you getting started with programming? Then the Rapberry Pi is a good choice. Its community is huge and using google as a problem solver will come in handy. The galileo is also a good choice, but expect to have less support from the community.
  • Already know arduino but want some more? The Galileo is an excellent choice, since you'll be using almost the same IDE and language. If you want to dive into Linux then the Galileo is also useful.
  • Are you used to fighting with linux setting ups? The BeagleBone Black will is a good option. Although you might feel a bit short on expansion board alternatives.

Database backups in S3

While I work on a Go backend for RunHedgie, I'm still hosting the database locally on a Raspberry Pi. That requires me to be at the office to play with the data, which is sub-optimal.

So I'd like to make a database backup each day and upload it to AWS's S3 storage service. That way I can download a copy of the data and use it in my computer whenever I want, not depending from an external CPU or server.

Database backup

To make a DB dump with PostgreSQL we'll need pg_dump:

# Create a temporary file
tmp_file=$(mktemp -t backup.XXXXXX)  
# Dump the db
pg_dump -p 3306 -h $DBHOST -U $DBUSER -p$DBPASS $DBNAME > $tmp_file  
# Zip it
gzip $tmp_file $tmp_file.gz  

mktemp is a great utility to generate random temporary files. Fixed-value temporary files are usually a bad option.

If you're in Linux you should take a look at ionice. It tells the SQL dump program to go easy on OS I/O operations, lowering disk and CPU usage (but making your backups a bit longer). I prefer using the -c2 options, which makes the "best effort" to back it up as quickly and seemlessly as possible.

File upload

To upload the file to S3, we'll need the AWS command line utilities. With those we can easily upload a file to S3:

aws s3 cp $tmp_file.gz s3://my_bucket/any_format  

Running it periodically

Finally, let's put it in a script (I'll call it backup.sh and put it in the $HOME folder):

#!/bin/bash
ionice -c2 pg_dump -p 3306 -h $DBHOST -U $DBUSER $PASS $DBNAME > $tmp_file

gzip $tmp_file

aws s3 cp "$tmp_file.gz" s3://$BUCKET_NAME/$FOLDER_FORMAT/

rm $tmp_file.gz

and configure crontab to run it every day at 1 p.m. UTC:

$ chmod +x bachup.sh
$ crontab -e
$ # Put the following line:
$ # * 13 * * * ~/.backups/backup.sh &> /dev/null

And that's it.

Dialogs and activity lifecycle

Here's a typical situation with Android:

  1. Make an HTTP request specifying a callback.
  2. When the callback is executed, show a dialog requesting user input.
  3. Continue with your app's flow based on that input.

Unfortunately, your activity may have been dismissed between steps 1 and 2. So when you actually try to show the dialog, you'll get a nice exception:

 java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
 FragmentManager.java:1343 in "android.support.v4.app.FragmentManagerImpl.checkStateLoss"
FragmentManager.java:1361 in "android.support.v4.app.FragmentManagerImpl.enqueueAction"  
BackStackRecord.java:595 in "android.support.v4.app.BackStackRecord.commitInternal"  
BackStackRecord.java:574 in "android.support.v4.app.BackStackRecord.commit"  
DialogFragment.java:127 in "android.support.v4.app.DialogFragment.show"  

The context of the request is still valid, so the callback will be executed anyways. We should be using the DialogFragment's utilities to manage the dialog's lifecycle, but unfortunately that's available only for API level >= 11.

Another option is to check if the activity is paused and only show the dialog if it's not. A modular way to do that is to specify a base activity and make all your activities inherit from that one:

public class BaseFragmentActivity extends SherlockFragmentActivity {

    private boolean mIsPaused = false;

    protected boolean isPaused() {
        return mIsPaused;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mIsPaused = false;
    }
    @Override
    protected void onPause() {
        super.onPause();
        mIsPaused = true;
    }
    @Override
    protected void onResume() {
        super.onResume();
        mIsPaused = false;
    }
    @Override
    protected void onStart() {
        super.onStart();
        mIsPaused = false;
    }

}

Then in our activity we can check if it is paused. If not, then show the dialog:

public class MyActivity extends BaseFragmentActivity {

    ...

    protected void someCallback() {
        if (!this.isPaused()) {
            dialog.show();
        }
    }

    ...
}

Trying to crash the activity

Now we would like to test if this is working. An easy way to pause your activity can be done calling a new activity or app with adb. For example, to open the browser you can run the following command from the terminal:

adb shell am start -a android.intent.action.VIEW -d 'http://www.google.com'  

References and inspiration

http://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html
http://stackoverflow.com/questions/3512198/need-command-line-to-start-web-browser-using-adb
http://stackoverflow.com/questions/10685460/how-to-determine-in-onpostexecute-that-activity-is-not-paused-now-or-destroyed

Reliability and magnetic sensors

RunHedgie suffered an outage of about 3 days without tweeting. There were two reasons for this which I'll explain in the following lines.

Don't forget to add a reboot strategy for your embedded system

In the first days of RunHedgie's rollout I'd come back from the office, connect via SSH to the Raspberry Pi that receives the packets from the wireless node which senses the wheel counts, change a few stuff and re-run the program that manages it all.

The thing is that one day we had a power outage, the system rebooted and I never noticed that the internal server was not running, so there were no counts and even no tweeting at all.

Solving it is quite simple, just add a command in your /etc/rc.local file and that will be executed on startup.

Reed Switches are unreliable

The counting system consists of a magnet, a Reed Switch and a microcontroller that is interrupted whenever an edge ocurrs (with a fraction of a second for debouncing). The effectiveness of this depends heavily on the distance between the magnet and the switch, the angle with which the switch is placed and how centered the magnet is with respect to the switch. That leaves us with very little margin.

Edit: @rbasoalto pointed out an excelent piece on Reed Switches, which confirms my empirical observations. A very nice illustrative explanation is included in the paper, which I'll show you here:

That's an image of a reed switch along with the magnetic field generated by a permanent magnet. As you can see, the switch's state will depend on the angle and how centered it is.

Hedgehogs are a bit filthy, they 'poop' in their wheels, so they have to be cleaned up frequently. That's why I made the whole system to be easily detachable so that it can be cleaned easily. One time after cleaning it I placed the switch a bit to far away from the magnet, resulting in no counts that night.

I've considered using a Hall Efect sensor. They seem to be much more reliable, but on the downside they need to be powered continously, since I need to detect edges, not only states. And at 3 mA of current that would drain the battery pretty quickly.

Anyways, I ordered a couple of them along with an Infrared Camera so that you can watch him run all night. They'll be arriving in a couple of weeks, so stay tuned!

Formula evaluation with python

I've been working on an Internet of Things platform with some principles in mind:

  1. Simple (i.e. 'dumb') devices
  2. Powerful processing in the backend
  3. Flexibility in value calculation

To achieve the first goal, the physical devices (nodes, sensors, whatever you call them) will be uploading an array of values which will have to be processed by a server.

For example, our node will be sending a reading for the battery and a temperature sensor, packed in an array of 16-bit values, with the following sequence:

  • array[0]: Battery
  • array[1]: Temperature

Since these values are 16-bit integers, we need to transform them to a meaningful representations. For example, the real temperature (in degrees Celcius) is calculated like this:

temp_celcius = (temp_read - 5500) / 100  

A simple and generic way to do define this transformation would be defining string formulas and using an evaluation module, such as python's parser module:

x = arr[1]  
formula_temp = "(x - 5500) / 100"  
code = parser.expr(formula_temp).compile()  
print eval(code)  

But what if we need to combine multiple array values into a single calculation? I figured that a JSON-defined reading would be a good way to do this. So, let's say we have a 32-bit value divided in two different places:

  • array[2]: Higher part of counter (16-bit)
  • array[3]: Lower part of counter (16-bit)

We can define a formula that combines both:

formula = {'2': "x << 16", '3': "x"}  

and then add both entries:

result_arr = []  
for key, value in formula:  
    # Get the value in the array
    x = arr[int(key)]
    # Parse the formula contained in the JSON
    code = parser.expr(value).compile()
    # Add the result to the list of results
    result_arr = result_arr + [eval(code)]

# Add all results
result = sum(result_arr)  

there, we have a simple yet generic system to combine readings into meaningful values using any formula that we want.