Purr Programming Shirt Part 1 — The Hardware

If you’ve met the folks at Polyglot Programming, you know that we love cats, t-shirts, and wearables. Which is, of course, exactly why we recently came up with an idea to combine all three into a project. No, we didn’t decide to create a wearable for a cat (granted, we gave it serious consideration.) Instead, we settled on the next best thing… a Purr Programming t-shirt with LED lights that can be controlled with a MetaWear board. The concept further evolved to make the LEDs flash and change color when someone tweets to us or mentions our hashtags on Twitter.

Screen Shot 2016-03-05 at 1.03.53 AM

Parts Needed

For this project, we chose to use MbientLab’s MetaWear R board, some NeoPixels and printed LEDs from Nth Light.

The complete list of parts consists of:

Laying Out the Circuit

Before sewing and wiring, we laid out the circuit. The MetaWear has onboard voltage and can switch low current loads, but NeoPixels and printed LED strips are bright and can draw more power than the board is designed to handle. For this reason, we opted to wire the NeoPixels directly to the battery and used an I2C line to control the strip. The printed LEDs need to stay in a 3V-range (else they will burn out) and are controlled individually by hooking each one to a GPIO pin. Since a LiPo battery operates above 3V, we added a voltage regulator to that part of the circuit, along with a FET to both of the light strips to control them.

circuit_shirt

Putting it All Together

Sewing requires a certain skill level, but sewing wearables pose unique challenges because you’re creating circuits. Some things to keep in mind:

  • Conductive thread has higher resistance than wire. A seemingly short run can add a noticeable amount of resistance that can affect the circuit’s operation.
  • Make sure that you use low resistance thread and keep circuit runs short.
  • While you can double up your thread in order to lower the amount of resistance, it can make the thread more difficult to work with.
  • It’s a good idea to add backing to your design to add stiffness and prevent your circuits from shorting out

Have a look at our next post where we discuss how to create an Android app to control the shirt. If you want a sneak peek at the code you can find it over here.

Screen Shot 2016-03-05 at 8.23.37 PM

Posted in Android, Development, MetaWear, Mobile, Uncategorized, Wearables Tagged with: , , ,

Measuring Your Heart Rate on Android Using MetaWear

MetaWear Heart Rate Screenshot While the MbientLab MetaWear has a number of sensors built into the board, it also has the ability to interface with a host of analog sensors. With many wearable devices focusing on fitness, you might find yourself needing to integrate a heart rate sensor into your board.

Getting Started

To get started you will need to have a heart rate sensor in addition to a MetaWear board. This post on the MbientLab projects page will give you information on where to find and how to wire up the sensor to your board. Once you are done with this you will need to set up your project to include the MetaWear API, app permissions etc.. Our post on logging thermistor data here goes over the steps to set up your project and connect to the board.

Reading The Data

Now that you are able to connect to the board you will need to read analog data from a GPIO pin. To do that we first need to get the GPIO module.


try {
      gpio = metaWearBoard.getModule(Gpio.class);
    } catch (UnsupportedModuleException e) {
      Log.e("HeartRateSensorFragment", e.toString());
      return false;
    }

For this application we are going to stream the data the GPIO pin to a stream that we will call HEART_RATE and pass in CompletionHandler called gpioHandler that will set up the rest of the chain once the route has been configured.


private final byte GPIO_PIN = 0;
private final String HEART_RATE = "heart_rate";
    
gpio.routeData().fromAnalogIn(GPIO_PIN, Gpio.AnalogReadMode.ADC).stream(HEART_RATE)
                .commit().onComplete(gpioHandler);

Our CompletionHandler is going to do a couple of things in a over-ridden success method. First it is gonig to subscribe to our stream with a data handler that will process reads from the pin (more on that handler later in this post).


result.subscribe(HEART_RATE, dataHandler);

Then it needs to set up a timer to periodically get a reading from the pin.


private final int SCAN_INTERVAL = 50;

try {
     AsyncOperation taskResult = metaWearBoard.getModule(Timer.class).scheduleTask(
        new Timer.Task() {
            @Override
            public void commands() {
                 gpio.readAnalogIn(GPIO_PIN, Gpio.AnalogReadMode.ADC);
            }
        }, SCAN_INTERVAL, false);
     taskResult.onComplete(
        new AsyncOperation.CompletionHandler() {
            @Override
            public void success(Timer.Controller result) {
                  result.start();
            }
          }
        );
    } catch (UnsupportedModuleException e) {
        Log.e("HeartRateSensorFragment", e.toString());
    }

The entire handler ends up looking like this.


    private final AsyncOperation.CompletionHandler gpioHandler = new AsyncOperation.CompletionHandler() {
        @Override
        public void success(RouteManager result) {
            result.subscribe(HEART_RATE, dataHandler);
            try {
                AsyncOperation taskResult = metaWearBoard.getModule(Timer.class).scheduleTask(
                        new Timer.Task() {
                            @Override
                            public void commands() {
                                gpio.readAnalogIn(GPIO_PIN, Gpio.AnalogReadMode.ADC);
                            }
                        }, SCAN_INTERVAL, false);
                taskResult.onComplete(
                        new AsyncOperation.CompletionHandler() {
                            @Override
                            public void success(Timer.Controller result) {
                                result.start();
                            }
                        }
                );
            } catch (UnsupportedModuleException e) {
                Log.e("HeartRateSensorFragment", e.toString());
            }
        }

    };

Then our MessageHandler (what we refer to as our dataHandler) will look like this.


    private final RouteManager.MessageHandler dataHandler = new RouteManager.MessageHandler() {
        @Override
        public void process(Message message) {
            short rawValue = message.getData(Short.class);
            Log.i("HeartRateSensorFragment", String.valueOf(rawValue));

            .
            .
            . heart rate calculations
            .
            .

            getActivity().runOnUiThread(
                    new Runnable() {
                        @Override
                        public void run() {
                            bpmView.setText(String.valueOf(bpm));
                        }
                    }
            );
            Log.i("HRSFragment BPM", String.valueOf(bpm));

        }
    };

You can find the code here . Feel free to fork it and make it your own. The application can also be found on the play store here.

Posted in Android, MetaWear, Mobile, Wearables Tagged with: , ,

Logging Thermistor Data With The MetaWear

Screenshot_20151228-234310
The MetaWear board allows you to easily create bluetooth enabled low power wearable devices. Unlike many solutions, as an Android developer you can write applications that program, and interact with the board using a API. We recently created an application using their new Android API to log thermistor temperature readings. The readings are read at one minute intervals and store the values on the board for retrieval from the phone.

The new API simplifies the process significantly from the previous version. So lets take a look at what is needed to get your application going with it.

Setting Things Up

To get started you need to add a reference to the Mbientlab repositories in the project level gradle file.


    repositories {
        jcenter()
        ivy {
            url "http://ivyrep.mbientlab.com"
            layout "gradle"
        }
    }

Then you are going to need to add a dependency to it in the app level file. The compile directive for com.mbientlab.metawear is required. The one for com.mbientlab.bletoolbox is optional but makes it easier to establish bluetooth connections as you will see later on.


dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.mbientlab:metawear:2.2.0'
    compile 'com.mbientlab.bletoolbox:scanner:0.2.0'
}

The API uses a service to communicate with the board. To use this you will need to add a reference to it in your applications manifest.xml file.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.polyglotprogramminginc.andevcon">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <service android:name="com.mbientlab.metawear.MetaWearBleService" />
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Next you will need to bind the service to your application using an intent in the onCreate method of your Activity.


        getApplicationContext().bindService(new Intent(this, MetaWearBleService.class),
                this, Context.BIND_AUTO_CREATE);

Then you will need to get a reference to the binder once the service is connected by implementing ServiceConnection and over-riding the onServiceConnected method.


   @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        ///< Get a reference to the MetaWear service from the binder
        mwBinder = (MetaWearBleService.LocalBinder) service;
        Log.i("Main Activity", "Service Connected");
    }

Connecting To The Board

To make finding and connecting to our board easier we are using the BleToolbox scanner which you can find here. For our example we created scanner DialogFragment that has a reference to the BleToolbox in the layout file.

<fragment xmlns:tools="http://schemas.android.com/tools" android:id="@+id/metawear_blescanner_popup_fragment"
        android:name="com.mbientlab.bletoolbox.scanner.BleScannerFragment"
        tools:layout="@layout/blescan_device_list" android:layout_width="match_parent"
        android:layout_height="match_parent" />

To scan for a board we display our fragment.


   if (mwScannerFragment == null) {
        mwScannerFragment = new ScannerFragment();
        mwScannerFragment.show(getFragmentManager(), "metawear_scanner_fragment");
   } else {
        mwScannerFragment.show(getFragmentManager(), "metawear_scanner_fragment");
   }

Then we implement a few callbacks to manage the scanner settings and to connect the board once we have finished scanning.


    /**
     * callbacks for Bluetooth device scan
     */
    @Override
    public void onDeviceSelected(BluetoothDevice device) {
        connect(device);
        Fragment metawearBlescannerPopup = getFragmentManager().findFragmentById(R.id.metawear_blescanner_popup_fragment);
        FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
        fragmentTransaction.remove(metawearBlescannerPopup);
        fragmentTransaction.commit();
        mwScannerFragment.dismiss();
        Toast.makeText(this, String.format(Locale.US, "Selected device: %s",
                device.getAddress()), Toast.LENGTH_LONG).show();
    }

    @Override
    public UUID[] getFilterServiceUuids() {
        ///< Only return MetaWear boards in the scan
        return new UUID[]{UUID.fromString("326a9000-85cb-9195-d9dd-464cfbbae75a")};
    }

    @Override
    public long getScanDuration() {
        ///< Scan for 10000ms (10 seconds)
        return 10000;
    }

These need to be implemented in the activity that initiated the fragment. This activity also needs to implement BleScannerFragment.ScannerCommunicationBus. The getFilterServiceUuids tells the fragment to only scan for boards with the specified UUID values. In our example we are only scanning for MetaWear boards. The getScanDuration tells it how long to scan for devices and the onDeviceSelected is called when you select a device. This hands you a BluetoothDevice object that you can use to connect to the board.

Connecting is then a matter of getting a reference to the board by passing in a reference to your BluetoothDevice, setting up a connectionStateHandler for callbacks when the board is connected/disconnected and then calling connect() on the board.


    /**
     * Connection callbacks
     */
    private MetaWearBoard.ConnectionStateHandler connectionStateHandler = new MetaWearBoard.ConnectionStateHandler() {
        @Override
        public void connected() {
            Log.i("Metawear Controller", "Device Connected");
            runOnUiThread(new Runnable() {
                              @Override
                              public void run() {
                                  DeviceConfirmationFragment deviceConfirmationFragment = new DeviceConfirmationFragment();
                                  deviceConfirmationFragment.flashDeviceLight(mwBoard, getFragmentManager());

                                  Toast.makeText(getApplicationContext(), R.string.toast_connected, Toast.LENGTH_SHORT).show();
                              }
                          }
            );

        }

        @Override
        public void disconnected() {
            Log.i("Metawear Controler", "Device Disconnected");
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(getApplicationContext(), R.string.toast_disconnected, Toast.LENGTH_SHORT).show();
                }
            });

        }
    };

    private void connect(BluetoothDevice metaWearDevice){
        mwBoard = mwBinder.getMetaWearBoard(metaWearDevice);
        mwBoard.setConnectionStateHandler(connectionStateHandler);
        mwBoard.connect();
    }

Reading And Logging Data

The MetaWear Android API lets you access the sensors and logging with modules. First we need to get a reference to the thermistor module and set a source for it.


        try {
            tempModule = mwBoard.getModule(MultiChannelTemperature.class);
        } catch (UnsupportedModuleException e){
            Log.e("Thermistor Fragment", e.toString());
            return false;
        }

        List tempSources= tempModule.getSources();
        MultiChannelTemperature.Source tempSource = tempSources.get(MultiChannelTemperature.MetaWearRChannel.NRF_DIE);

Each module has the ability to route data via a DSL. In our example we are going to route our data from our MultiChannelTemperature module to a log with a id of “log_stream” and when the route has successfully been registered set up the rest of the process.


tempModule.routeData().fromSource(tempSource).log("log_stream")
        .commit().onComplete(temperatureHandler);

In our callback we will set up a timer that reads the temperature at a set interval and start it.


    private final AsyncOperation.CompletionHandler temperatureHandler = new AsyncOperation.CompletionHandler() {
        @Override
        public void success(RouteManager result) {
            result.setLogMessageHandler("log_stream", loggingMessageHandler);

            // Read temperature from the NRF soc chip
            try {
                AsyncOperation taskResult = mwBoard.getModule(Timer.class)
                        .scheduleTask(new Timer.Task() {
                            @Override
                            public void commands() {
                                tempModule.readTemperature(tempModule.getSources().get(MultiChannelTemperature.MetaWearRChannel.NRF_DIE));
                            }
                        }, TIME_DELAY_PERIOD, false);
                taskResult.onComplete(new AsyncOperation.CompletionHandler() {
                    @Override
                    public void success(Timer.Controller result) {
                        // start executing the task
                        result.start();
                    }
                });
            }catch (UnsupportedModuleException e){
                Log.e("Temperature Fragment", e.toString());
            }

        }
    };

We are also setting a log message handler. This is simply a callback that processes each log entry as it comes from the board. Our implementation logs the entry and saves it to a SqlLite Table.


   private final RouteManager.MessageHandler loggingMessageHandler =  new RouteManager.MessageHandler() {
                @Override
                public void process(Message msg) {
                    Log.i("MainActivity", String.format("Ext thermistor: %.3fC",

                            msg.getData(Float.class)));
                    java.sql.Date date = new java.sql.Date(msg.getTimestamp().getTimeInMillis());
                    TemperatureSample sample = new TemperatureSample(date,  msg.getData(Float.class).longValue(), mwBoard.getMacAddress());
                    sample.save();
                }
            };

The final part is to call downloadLog on the loggingModule when we want to retrieve the logs from the board.


        loggingModule.downloadLog((float)0.1, new Logging.DownloadHandler() {
            @Override
            public void onProgressUpdate(int nEntriesLeft, int totalEntries) {
                Log.i("Thermistor", String.format("Progress= %d / %d", nEntriesLeft,
                        totalEntries));
                //mwController.waitToClose(false);
                thermistorCallback.totalDownloadEntries(totalEntries);
                thermistorCallback.downloadProgress(totalEntries - nEntriesLeft);
                if(nEntriesLeft == 0) {
                    GraphFragment graphFragment = thermistorCallback.getGraphFragment();
                    graphFragment.updateGraph();
                    thermistorCallback.downloadFinished();
                }
            }
        });

This method takes a callback that will give you a progress update on the data download along with a float indicating the percentage interval to give you a status update. For example if you set this value at .10 and have 100 entries to download, it will call this method each time 10 records have been transferred. BLE is a much slower than standard Bluetooth, so a large number of data points can easily take more than a minute to transfer to your Android device. In the code above we are using this to trigger a callback that updates the UI on the download progress.

Persisting Board State Between sessions

Now that we have our board logging the temperature and an app that can download it we need to make sure we can persist the references to our logging when our app pauses/stops and then restarts. We can persist the majority of the app state from the MetaWearBoard object using the serializeState method. In our application we did this in the onSaveInstanceState lifecycle method of our activity.


    @Override
    protected void onSaveInstanceState(Bundle state) {
        super.onSaveInstanceState(state);
        if (mwBoard != null) {
            mwBoard.disconnect();
            state.putByteArray(mwBoard.getMacAddress(), mwBoard.serializeState());
        }
    }

Our logging callback will not be serialized in the serializeState method. This becomes a problem when we restore our app state because we need to have a reference to the routeManager so that we can add our logging callback when restarting the app. To fix this we will need to persist the RouteManager id in our temperature handler success callback.


bundle.putInt(mwBoard.getMacAddress() + "_log_id", result.id());

Now when we restore our app state we can deserialize the state for our board.


            String boardState = bundleState.getString(bleMacAddress, null);
            if (boardState != null) {
                mwBoard.deserializeState(boardState.getBytes());
                Log.i("connect device", "Found instance state");
            }

After deserializing we will need to get the route manager that we had initially used for our logs via the RouteManager id and add the logging message handler to it.


        RouteManager route = mwBoard.getRouteManager(sharedPreferences.getInt(mwBoard.getMacAddress() + "_log_id", 0));
        route.setLogMessageHandler("log_stream", loggingMessageHandler);

You can see a working application that uses this here. All of the code is available on Github over here so that you can make it your own.

Posted in Android, MetaWear, Mobile, Wearables Tagged with: , ,

Using MetaWear with Node.js

Back in October 2014 I attended a talk by Erica Stanley called “Open Source and the Internet of Things” at the All Things Open conference in Raleigh. We were just starting to do wearable development beyond Android Wear and Google Glass and had been playing with some prototyping boards. At the time, working with boards that included any kind of wireless chipset posed a challenge: You needed to write code that could run on the board whilst developing a protocol to communicate between the two devices. In addition, most boards, albeit smaller than an Arduino, were still fairly sizable if you were trying to develop a wearable type of application.
IMG_20151210_001737
In Erica’s talk she mentioned a board called the MetaWear that seemed perfect for wearable applications. It’s small and the base unit has built-in Bluetooth radio, an accelerometer, temperature sensor, LED, switch, LiPo charging circuit, haptic driver, 4 digital/analog pins, 4 digital pins, GPIO support and can even act as a beacon. Also, you can simply use their Android or iOS API to program and read data from the board without having to write C++ sketches. All of that for a mere $45! Before the end of the talk, I had ordered a MetaWear. Soon thereafter, I began using it for projects and started doing conference talks that featured the board. MetaWear has since expanded their offerings to include boards with additional sensors.

Going Beyond iOS and Android

Most wearable devices will likely interface with an iOS or Android-based device, but developers doing Node.js and Windows development didn’t always have an easy way to communicate with, and use, these devices. That recently changed with the release of the C++ API, a C# wrapper, and Node.js NPM package. We’ve also been working on a Cordova plugin. The cool thing about the Node and Cordova efforts are that they are driven by enthusiasts in the community.

Getting Started

We have personally tested the Node.js package on MacOS, Ubuntu (running under Crouton in Chrome OS), and on a Raspberry Pi. It works great on all three platforms with a few minor tweaks. Note, however, that MetaWear uses Bluetooth 4.0 to communicate with other devices, so make sure that your device supports Bluetooth 4.0.

Mac OS

I tested the MetaWear board on a Mac that has Bluetooth 4.0 support. In theory, it would be possible to use a third party adapter, but you may need to tweak some settings. On a standard Mac is it really easy, assuming that you have a recent version of Node.


git clone git@github.com:brainexe/node-metawear.git
cd node-metawear
npm install
DEBUG="noble-device" node examples/all.js

Running this code snippet will clone the repo, install the Node modules and create a test app called all.js. If you have a MetaWear that is running (but not currently connected to another device), and within range of your Mac, you can expect to see the light on it start to flash and some sensor output on your terminal. If it doesn’t immediately work correctly, you may need to close and restart Node.

Ubuntu in Crouton under Chrome OS

Again, I conducted the test with a Chromebook Pixel LS that has built-in Bluetooth 4.0 support. It should, however, work on other machines.


sudo setcap cap_net_raw+eip $(eval readlink -f `which node`)
git clone git@github.com:brainexe/node-metawear.git
cd node-metawear
npm install
export DEBUG="noble-device" 
host-dbus node examples/all.js

The main difference here is that you’ll need to run Node through host-dbus, since it’s accessing the Bluetooth adapter attached through Chrome OS.

Raspberry Pi Running Raspbien

Finally, I tested the board using a Pi Zero with a WiFi and BLE dongle. I opted to clone the Node repo and build it on the platform (yes, it does take a while). Once that was done, the rest was easy.


sudo setcap cap_net_raw+eip $(eval readlink -f `which node`)
git clone git@github.com:brainexe/node-metawear.git
cd node-metawear
npm install
export DEBUG="noble-device" 
node examples/all.js

Personally, I consider Pi Zero to be the most interesting use for a Node.js integration with Metawear. Unlike previous Pi releases, it has a lower power consumption profile and a small size, which, in theory, might be useful when creating wearable devices that interact with MetaWear.

In Summary

IMG_20151210_034705

Support for Node.js is still somewhat limited and it would require adding lots of additional features in order to go beyond basic experimentation. As with any open source project, if you want to see a specific feature implemented, you can always do it yourself and submit it as a pull request. If you’re interested in using Cordova/Phone Gap to interact with your MetaWear, be sure to look out for an upcoming blog post and introduction to using our library.

Posted in ChromeOS, Development, Javascript, MetaWear, Node.js, Raspberry Pi, Ubuntu, Wearables Tagged with: , , , , ,

Adventures in 3D Printing

IMG_20151209_130801
About a year ago we decided to get a 3D printer. Although there are lots of pre-made options available, it’s much less expensive to get a RepRap Prusa I3 kit and build one yourself. The Prusa I3 is an open source 3D printer design that allows anybody to make components for it, and the community members, in turn, contribute plans for print heads, cases etc. It’s a pretty neat concept: The main controller is an Arduino mega board, the software is open source, and you can order the printer preassembled or as a DIY kit. This, of course, means that the printer can actually print parts for another printer, which can then go on to print parts for another, and so on.

We opted to put it together ourselves. The good news is that we learned a lot about 3D printing. The bad news is that it took a LOT of time. Building the kit, installing the software, and calibrating the printer took approximately 80 hours. Now, in fairness, some of that effort was also dedicated toward getting familiar with 3D printing in general.
IMG_20151209_130504
Once we had the printer up and running, the first project was to create some extra parts for the printer. We started without cable guides, so we went to ThingVerse, found a design and voila! Next, we used ABS plastic to print a case for the controller boards as well as one for the power supply. Along the way, we learned a few valuable lessons.

Firstly, you need to buy a special ramps shield for your Arduino to interface with the various motors and sensors on the printer. Die-hard enthusiasts may opt to solder components to their own board, but we decided to buy a pre-made one and it worked great… well, initially. Because we were printing ABS, we needed to have a heated print bed, which is controlled via this board. After a week, the bed stopped working and upon closer inspection we noticed that the terminal for the heater had turned black. IMG_20151209_164603

A component on this board called a MOSFET was drawing a lot of current through it, and it obviously became very hot. It really should have had a heat sink on it, but the instructions online were not clear about this and the board didn’t come with one installed. So we ordered a new ramps and continued to print more parts for the printer. Before the cable chains were done, we had already had a wire failure on the head bed from repeated flexing. So what to print next?

How About a Full Size Chair?

Your first question might be: “How can you do that with a small desktop printer?” The answer comes from a group called Bits and Parts who created a open source design for a chair constructed from 85 individual puzzle pieces that interlock together.
IMG_20151126_200208

It looked like a great way to use the printer for something utilitarian. Albeit reasonably simple, in retrospect it was a very time consuming project, because it required printing plastic supports for overhangs. Each of these took between 30 minutes and an hour to cut and file.

Other Printer Problems Along the Way

Like most DIY projects created from kits, we ran into a few issues with components. First, the cheap aluminum nozzle developed a second hole that rendered it unusable. We learned about a small shop in Pennsylvania that sells brass ones. The store’s proprietor is actually the designer of these heads, so it was worth the extra money spent. After installing it, we also needed to add a different thermistor because the original one differs from the one in the head. Things went great until the thermistor wire to the print nozzle broke (due to a bad cable routing that flexes too much) and the plastic assembly in the head melted. Again, we ordered a new part from the Pennsylvania shop, rewired the thermistor, did some calibration, and continued to print puzzle pieces when we had some spare time.
FIN1FKGHCAXRZX5.MEDIUM
One day, however, we tried to turn on the printer and none of the components worked. After a lot of digging, we discovered that the kit’s cheap power supply had died. We replaced it with a higher-rated PC power supply. As a nice side bonus, it also reduced some of the printer noise.

Putting It All Together

Finally, after many hours hours of printing, sanding, finishing some broomsticks as chair legs, and some minor glueing and tweaking, we ended up with a complete chair. It looks great in the living room, and yes, you can sit in it!

IMG_20151127_004256IMG_20151209_130615 (1)

Posted in 3d printing, Arduino, Development, Maker, RepRap Tagged with: , , , ,

Adding Gradients to Android Graphs with MPAndroidChart and DecoView

Recently, we worked on a project that required us to add graphs with gradients to an Android application. Below is an example of one such graph that we needed to create:

Android graphs with gradients

There are lots of examples online that show how to create graphs with gradated backgrounds, but we quickly discovered that it’s nearly impossible to find information on how to incorporate a gradient effect as part of the axis, trend line, or doughnut. We finally figured out how to do it, so let’s go over the steps and it’ll hopefully make things easier for you if you’d like to try a similar project.

MPAndroidChart

Our go-to tool for graphing in Android applications is typically MPAndroidChart. It’s a versatile and powerful open source charting library that’s fairly straight forward to use. (The line graph shown in our screenshot was created with it.) Now, say we want to create a chart that shows how many minutes someone is active each hour of the day. The MPAndroidChart documentation found here offers good instructions on setting up the main parts of the graph. But how do you add vertical shading to the data?

If you delve deeper into the library, you’ll discover that the line chart uses Android’s Paint to render its lines. Among other things, you can set a shader in a Paint object to paint everything using that specific shader. To learn more about Android graphics and shaders, take a look at this post. Armed with this knowledge, we can now add a shader to the Paint object for our graph, which will give us a line gradient.


Paint paint = lineChart.getRenderer().getPaintRender();
int height = 200;

LinearGradient linGrad = new LinearGradient(0, 0, 0, height,
       getResources().getColor(R.color.lineGraphHigh),
       getResources().getColor(R.color.lineGraphLow),
       Shader.TileMode.REPEAT);
       paint.setShader(linGrad);

This gets us most of what we need. The chart renders, and if our graph has a height of 200px, it’ll also produce a gradient that changes from dark blue (our lineGraphLow color) to yellow (our lineGraphHigh color). However, one problem is that most Android applications need to adjust the size it objects on the screen to account for various screen sizes. In our test app, we used a weightSum along with layout_weights in a LinearLayout object. A fixed shading height would therefore result in a repeated pattern if the graph height extends beyond 200 pixels. In order to solve this, we need to obtain the height of our graph.


int height = lineChart.getHeight();

By adding this code snippet to a call that’s part of onStart, you’ll end up with a height of zero and no gradient.

Screen Shot 2015-12-09 at 12.51.55 AM

So, we need to populate our chart data and get the size after the view has rendered, which can be done via the POST method on the view.


    @Override
    public void onStart(){
        super.onStart();
        getView().post(new Runnable() {
            @Override
            public void run() {
                drawLineGraph();
            }
        });
    }
    /**
     *  The code for creating the line graph
     */
    private void drawLineGraph(){
        setupLineChart();

        // Get the paint renderer to create the line shading.
        Paint paint = lineChart.getRenderer().getPaintRender();
        int height = lineChart.getHeight();

        LinearGradient linGrad = new LinearGradient(0, 0, 0, height,
                getResources().getColor(R.color.lineGraphHigh),
                getResources().getColor(R.color.lineGraphLow),
                Shader.TileMode.REPEAT);
        paint.setShader(linGrad);

        setupLineChartData();

        // Don't forget to refresh the drawing
        lineChart.invalidate();
    }

Now we have a dynamically resizable graph that gives us a line with shading that changes from dark blue to yellow!

DecoView

After accomplishing part one, we also wanted to add a shaded arc graph to another part of our application. Unfortunately, MPAndroidChart couldn’t do what we wanted, so we turned to DecoView. DecoView is a focused library that allows you to create animated circular graphs. Alas, again, the documentation didn’t clearly explain how to add a gradient to a graph.

For DecoView, you add a series to define arcs for a graph. The series are added via a Builder object that can take either one or two colors in the constructor. All of the examples only show one color, but if you add in a second, you actually end up with a gradient. Then you simply add in a range that specifies the values that correspond to the starting and ending color.


 int seriesIndex = decoView.addSeries(
       new SeriesItem.Builder(getResources().getColor(R.color.lineGraphLow),
       getResources().getColor(R.color.lineGraphHigh))
                .setRange(0, stepGoal, 0)
                .setInitialVisibility(false)
                .setLineWidth(getDimension(18f))
                .build());

The end result is a arc graph with a gradient that changes from blue to yellow. You can find documentation for DecoView here , and an example app with both of these graphs over here.

Posted in analytics, Android, Data Science, Development, Mobile Tagged with: , , , , ,

Giving Thanks by Giving Laptops to Those in Need

Nelson Mandela once said: “There can be no keener revelation of a society’s soul than the way in which it treats its children.”

While Madiba is no longer with us, about a year ago I had the honor of meeting another South African who is carrying on the late president’s legacy of creating positive change in the community. His name is Mandla Magagula.
mandla-n

Humble Beginnings

Mandla was born in Piet Retief, a small town in the Mpumalanga province in South Africa. Like many black children in apartheid-era South Africa, he grew up in a very poor in a segregated settlement reserved for non-whites, known as the township.

The local school had dirt floors and no running water. Books were not readily available and often tough to come by. Many of the things that we take for granted in the United States, even in the poorest school districts, would have been considered luxuries for Mandla and his fellow students. Thankfully, Mandla was blessed with unfettered intellectual curiosity and abundant self-motivation and he voraciously read what was on hand: religious pamphlets and tracts. His matriculation grades earned him a full scholarship to the University of Pretoria.

piet_retief

Despite the fact that Mandla had never actually used a computer before starting his university studies, he wanted to major in Computer Science. In class, while his fellow students attempted to hone their skills in basic programming, he looked at them to learn the basics, like typing and using a mouse. Since the scholarship money didn’t cover much more than tuition, he often had to forego things like personal toiletries. However difficult, Mandla’s tenacity and desire to succeed finally paid off when he graduated with a master’s degree in Computer Science, landed a job as a software engineer, and paid to move his mother from a shack in Piet Retief to a house in Johannesburg.

But the story doesn’t end there. When Mandla joined Driven Alliance in 2014, he asked them for support in launching a program to give township children some of the opportunities that he never had.

Fixing the Future

His new employer happily obliged and established a program called “Driven Spark Sisonke Rising”. The concept was simple: To provide 6 kids from a township with 3 laptops and teach them how to program using Python and the Agile process.

By the time I spoke with Mandla in December, the program had proven to be a huge success, and they were getting ready to grow the class size to 12 students. With the kind help of friends and acquaintances, we were able to donate 12 additional used machines to the program.

Screen Shot 2015-11-24 at 8.11.13 PM

Screen Shot 2015-11-24 at 8.21.35 PM

You Can Help

The class has since grown to 30 students, but they still have only 15 laptops. If you have an old laptop (10 years old or newer), please consider donating it to this worthy project, instead of letting it end up in the trash. You can get more information by contacting me at lgleason@polyglotprogramminginc.com. A small effort on your part could make an enormous difference in the lives of disadvantaged youths by given them a seat at the digital table.

Posted in Agile, Development, Ethics, Giving Back, Python Tagged with: , , , , ,

Interacting with the Android lifecycle in a Cordova Plugin

Anyone who’s attended one of my talks during the past year, knows that I love Mbientlab’s MetaWear boards. They’re great for prototyping wearables that offer rich APIs for Android and iOS. That said, when you’re prototyping a device, you may not want to have to invest a lot of time developing native Android and iOS applications. For this very reason, we decided to develop a Cordova plugin that allows you to use Cordova in order to quickly prototype MetaWear applications.

pluggycordova

We’ve done a lot of Android and iOS development, but this was, in fact, the first plugin we developed. One thing quickly became very apparent: While there’s lots of information on the Web about developing applications that use Cordova, there are not that many tutorials available about actually writing plugins. Most of these articles provide general directions on how to get started, and for many plugins, it’ll give you enough information to reach into the native APIs for the device, but in order to use the MetaWear API in Android, you need binding to a Service that exposes the API and handles communication to and from the board.

Now, if you were writing a native Android application, this step would be pretty straightforward. You’d create an activity by extending Activity, implement a Service connection and then override onCreate, onDestroy, onServiceConnected, and onServiceDisconnected. Then you’d bind the service in onCreate, get a reference to it in onServiceConnected, and unbind it in onDestroy. Your code might look something like this:


public class MainActivity extends Activity implements ServiceConnection {
    private MetaWearBleService.LocalBinder serviceBinder;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedIFinally,nstanceState);
        setContentView(R.layout.activity_main);

        // Bind the service when the activity is created
        getApplicationContext().bindService(new Intent(this, MetaWearBleService.class),
                this, Context.BIND_AUTO_CREATE);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

        // Unbind the service when the activity is destroyed
        getApplicationContext().unbindService(this);
    }

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        // Typecast the binder to the service's LocalBinder class
        serviceBinder = (MetaWearBleService.LocalBinder) service;
    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) { }
}

Cordova plugins are a bit different. Instead of extending an activity or creating a fragment, you extend CordovaPlugin, which, in turn, doesn’t extend or implement anything else. So how do you get to the activity lifecycle? If you dig around in the documentation or source code, you’ll notice that it gives you a number of methods that you can override as part of the lifecycle. They include: onPause, onResume, onStart, onStop, onDestroy, onNewIntent, onMessage, and onActivityResult.

Armed with this, we can therefore create our plugin and make it bind and unbind a service at the correct point in the Android lifecycle. Our new code now looks something like this:


public class MWDevice extends CordovaPlugin implements ServiceConnection{
    public static final String TAG = "com.mbientlab.metawear.cordova";
    private MetaWearBleService.LocalBinder serviceBinder;
    private CallbackContext callbackContext;
    private String mwMacAddress;
    private MetaWearBoard mwBoard;
    private HashMap mwCallbackContexts;
    private boolean initialized = false;
    
    /**
     * Constructor.
     */
    public MWDevice() {}
    /**
     * Sets the context of the Command. This can then be used to do things like
     * get file paths associated with the Activity.
     *
     * @param cordova The context of the main Activity.
     * @param webView The CordovaWebView Cordova is running in.
     */
    public void initialize(CordovaInterface cordova, CordovaWebView webView) {
        super.initialize(cordova, webView);
        rssi = new RSSI(this);
        mwAccelerometer = new MWAccelerometer(this);
        mwCallbackContexts = new HashMap(); 
        bluetoothScanner = new BluetoothScanner(this);
        Context applicationContext = cordova.getActivity().getApplicationContext();
        applicationContext.bindService(
                                       new Intent(cordova.getActivity(),
                                                  MetaWearBleService.class),
                                       this, Context.BIND_AUTO_CREATE
                                       );
        Log.v(TAG,"Init Device");
    }

    public HashMap getMwCallbackContexts(){
        return mwCallbackContexts;
    }

    public MetaWearBoard getMwBoard(){
        return mwBoard;
    }

    public boolean execute(final String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
        this.callbackContext = callbackContext;
        final int duration = Toast.LENGTH_SHORT;
        // Shows a toast
        Log.v(TAG,"mwDevice received:"+ action);
        if(action.equals(INITIALIZE)){
            mwCallbackContexts.put(INITIALIZE, callbackContext);
            return true;
        } 
        else{
            return false;}
    }

    @Override
    public void onDestroy(){
        cordova.getActivity().getApplicationContext().unbindService(this);
    }

    @Override
    public void onServiceConnected(ComponentName name, IBinder service){
        serviceBinder = (MetaWearBleService.LocalBinder) service;
        Log.i("MWDevice", "Service Connected");
        initialized = true;
        if(mwCallbackContexts.get(CONNECT) != null){
            connectBoard();
        }else if(mwCallbackContexts.get(SCAN_FOR_DEVICES) != null){
            bluetoothScanner.startBleScan();
        }

        if(mwCallbackContexts.get(CONNECT) == null &&
           mwCallbackContexts.get(SCAN_FOR_DEVICES) == null)
        {
            mwCallbackContexts.get(INITIALIZE).sendPluginResult(new PluginResult(PluginResult.Status.OK,
                                                                             "initialized"));
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {}

}

Now we’re able to listen for actions on execute and can call into any methods we need in the MetaWear service. If you want to see a complete implementation in action, head over here.

Once you understand how a Cordova plugin wires into the Android lifecycle, the rest will likely be fairly easy if you’re already an experienced Android developer. But, hopefully this overview makes the mechanics a bit clearer for you!

Posted in Android, Cordova, Development, Javascript, Mobile, Wearables Tagged with: , , ,

Creating a Pedometer Using MetaWear and Android

Six months ago we started to play with a really cool wearable prototyping board called MetaWear from Mbientlab. If you haven’t heard of them you can read about the platform over here.  The idea behind them is that they are really small boards that you can use to prototype wearables using their IOS and Android API.  No need to get into sorting out the communication protocol between the board and your device,  dealing with writing C firmware etc..

We have been so excited about this board that we have been giving talks to introduce mobile developers to it along with the basics for getting started with the device.  While the API does make things easier,  there are still a lot of nuances to using the API and board.  Mbientlab has published some great example apps and we are helping them fill in the gaps.  As part of a series of example apps to we just published a Android version of the MetaTracker Android app.  You can find out more about it over here.  http://projects.mbientlab.com/metatracker-android-version-turns-your-metawear-into-a-fitness-tracker/.

Look out for other examples from us and Mbientlab and if you have any questions about these boards feel free to reach out to us.

Screenshot_2015-05-03-22-18-31

Posted in Android, Mobile, Wearables Tagged with: , , ,

Allowing For More Signature Flexibility In The Ruby Passbook Gem

GiftApps-Passbook-645x611 Passbook is a often under utilized feature of IOS. For those who haven’t used it, Passbook is a app that comes with all phones running IOS 6 and above. Passes can be mailed, shared, retrieved from a website or delivered via a app. They also support push notifications that can update the pass along with the ability for the pass to show a notification if a user is in the proximity of certain locations or during certain times depending on the type of pass you have.

As a Rubiest you don’t have to learn Objective C or Swift to create them because passes are a zip file consisting of images, a pass.json file, a manifest and a signature file. The Passbook Ruby Gem makes this fairly straight forward. Recently we released version 0.4.0 of the gem, so what’s new?

Making It Easier To Get Started

While the gem makes it easy to get your gem signed and out the door, up until this release you needed to write a program or use IRB to generate your pass. There were also no templates to get you kick started. Well, technically there was in 0.3.x but we didn’t tell anyone about it. Now we are officially releasing this functionality. To get started you will need to install the gem.


gem install passbook

Next, create a directory for your passbook, go to the directory and then generate the passbook template.


pk generate honey_badger_pass

You will still need to go through the steps of setting up your pass name, certificates etc.. This article will show you how to do that. Then you can add content to your pass etc.. Once you have done this there is another command line utility that allows you to build your pass via.


pk build passbook_gem_name -w ./wwdc.pem -c ./your_pass_name_certificate.pem -k your_pass_name_key.pem -p '12345'

You will see a .pkpass file in your directory. To test out your new pass you can drop it on your IOS simulator or mail it to your phone.

Allowing Different Certificates For Different Passes

One limitation of the Passbook gem has been that you could only create one set of certificates for a program using the gem. For many applications that is all that is necessary, but some apps might need to have different certificates for different passes etc.. Now you can via the Signer class.

When you create a PKPass object, by default if you don’t pass it a Signer class it uses your Passbook application certificate configuration settings. If you want to use a different set of certificates you simply create a Signer class and pass in the references to the certificates you want to use.


  signer = Passbook::Signer.new {certificate: some_cert, password: some_password, key: some_key, wwdc_cert: some_wwdc_cert}
  pk_pass = Passbook::PKPass.new your_json_data, signer

  ....

What’s Next

We have been using Passbook in production but are always looking for ways to make it better. If there is a feature that you need please put in a feature request or send us a pull request. You can find the project here.

Posted in gems, IOS, Mobile, rails, ruby Tagged with: , , , , ,