Arduino/iOS – Bike speedometer tracking using bluetooth

Scope of the project,
add a speedometer on my MTB to store and track the trip using only Bluetooth transmission, send data to iPhone and store to cloud for later data-analysis.

Used components:

  • digital display (controlled by the iOS app). Can show current speed (km/h), total km, current temperature, current humidity.
  • GPS module
  • bluetooth module
  • DHT sensor for temperature and humidity
  • Swift backend
  • mongoDB as database
  • Swift iOS App

Putting things together

Connecting a DHT sensor

Connecting a temperature and humidity sensor. This component is optional, I use this sensor only for data-analysis on backend side for calculating analytics on the speed and track based on the environment variables.

Connecting a GPS module

A GPS module is used to track your movements. I use this module from Parallax

Connect it to Arduino:

remember to go outside to test it… in your house, this module can have some problems detecting the signal from satellites.

Attaching a bluetooth module

I’ve used a Bluetooth 3 module to make communication between sensors and the iOS app. This is not a BLE module, you must connect to the peripheral to send and receive data in Bluetooth.

Connect a seven segment display

I’ve used the HT16K33 display (that use a few pins on Arduino) and this library: to show the data on display.

The iOS App:

The iOS app is created using Swift. The goal of this app is to read data ONLY from the Bluetooth and draw the live-route on a map that you’ve done with your bike.

Of course, I could have an app that uses the GPS of the phone, but I want to use the Bluetooth packets.

Data transmission:

The main screen permits you to change the settings of the 7-segment display (sending Bluetooth commands to Arduino).

Data is sent via Bluetooth using the CoreBluetooth library for iOS, in particular:

func writeValue(_ data: Data, for characteristic: CBCharacteristic, type: CBCharacteristicWriteType)

Arduino module, receive data reading the BTSerial:;


In the iOS app you can control the 7-segments display and switch between:

  • speed in km/h
  • total distance
  • environment temperature
  • environment humidity

And of course, you can start tracking your route. Data is cached in a Realm database.

When a route is completed, is automatically saved in the list, you can view the track, delete and share.

Communication between devices

Every run loop, the Arduino collect data, append to a data structure and when connection with Bluetooth is available, start transmit.

Example for GPSData structure and DHTData structure:

struct GPSData {
struct DHTData {

In these data structures are stored the informations collected real-time by GPS and DHT.

When the app send the command to change the display mode (passing letters: A, B, C or D), Arduino use it to display something different.


if ( btReceivedData == 'A' ) {
  writeOnDisplay( gpsData->kmh );
} else if ( btReceivedData == 'B' ) {
  writeOnDisplay( gpsData->lat ); // example
} else if ( btReceivedData == 'C' ) {
  writeOnDisplay( dhtData->temp );
} else if ( btReceivedData == 'D' ) {
  writeOnDisplay( dhtData->hum );

The data received from the app is a little bit different, because is a delimited string.

In order to minimize the size of the transmission, this string can be changed using bytes. More fast and secure. It’s not showed here but you can find it in the source code.

The original data format is like this:

StringbtOutputStr = String(gps->lat);
btOutputStr += "§";
btOutputStr += String(gps->lon);
btOutputStr += "§";
btOutputStr += String(gps->alt);
btOutputStr += "§";
btOutputStr += String(gps->kmh);
btOutputStr += "§";
btOutputStr += String(gps->date);
btOutputStr += "§";
btOutputStr += String(gps->time);
btOutputStr += "§";
btOutputStr += String(dht->temp);
btOutputStr += "§";
btOutputStr += String(dht->hum);
btOutputStr += "#";


A string separated with “§” and terminated with “#“.

lat § lon § altitude § km/h § date § time § temperature § humidity#

The iOS app read this data and draw a point on the map for each line received from Arduino.

The result is a live tracking of your control unit (that is our speedometer!).

Live recording using Bluetooth data

( In a common sports shop you can buy for 10€ more or less… ;D, but there is no fun if is already done by someone else! )

When the track recording is complete, the data are stored on a no-SQL database (MongoDB in this case) hosted on Heroku (

The entire backend and the API (POST/GET) are written completely in Swift using Vapor framework.

Next step of the project, analyze the collected data for statistics/performance/speed and whatever, based on the environment climatic conditions for instance.  But now holidays are finished, I’ll start a new job so have no more free time…

The app of course if only a draft. Is not on the App Store, was created just for fun and to play a little bit with the Bluetooth.

Here the original circuit…:

Source code (for iOS app and Backend) is not yet available. It will be available soon.



Alberto Pasca

Software engineer @ Pirelli & C. S.p.A. with a strong passion for mobile  development, security, and connected things.