The final prototype

Monitor your services (and everything else) with Raspberry Pi, Android Things and Firebase

We were searching for an easy way to visualize the status of our backend services, the current state of our Jira board and the progress of our automated tests.

A traffic light turning from green to yellow, a siren going off, or a voice telling you that you broke the WIP limit. The tool we were looking for should be able to handle it all.

If dealing with a tight budget but still wanting to have access to a powerfull physical computing device, Raspberry Pi will be your knight in shining armor. A surprisingly powerful barebone computing device with a miriad of functionalities for half the price of a budget mobile phone.

There are several operating systems that can run on a Raspberry Pi, one of them being Android Things.

Android Things (codenamed Brillo) is an Android-based embedded operating system platform by Google, announced at Google I/O 2015. It is aimed to be used with low-power and memory constrained Internet of Things (IoT) devices, which are usually built from different MCU platforms.

If you are familiar with Android development, you will feel at home imidiatly but even for non mobile developers the learning curve won’t be very steep. In fact, all you have to do is to create an empty Android project with a home screen (A.K.A Activity) and overwrite the „onCreate“ and „onDestroy“ methods.

Prerequisites

For our pototype we use a Raspberry Pi 3 B (the B+ version is not supported by Android at the moment), three LEDs, a button, some cables and a micro-SD card

Raspberry Pi 3B (c) MyToys

The first step will be to flash the Android Things OS onto the micro-SD card and to setup the Raspberry Pi. Just follow the steps explained on the Google Developers website.

In the next step we connect the Raspberry Pi to our computer. Make sure you have the latest version of Android Studio and the Android SDK installed. If you are on your home Wifi network, writing „adb connect Android.local“ in a console should be enough to establish a connection between your computer and the Raspberry Pi.

If this setup doesn’t work, you have to find out the Raspberry Pi’s IP address manually and run the command „adb connect YOUR-IP-ADDRESS“.

If you have access to the router, you can look up the Ip address under the „connected devices section“ in the router’s admin section, if not, you can connect a monitor and a keyboard to the Raspberry Pi and look up the IP adress directly on the device.

Once you have the connection established, it’s time to create your first App and to test it. I would recommend to, again, follow the steps on the Google Developer website.

After finishing the tutorial, you should end up with a running Android Things App on your Raspberry Pi.

Time to connect to the outside world

There are several ways to connect the Raspberry Pi to the cloud, a very quick and easy one, that fulfills all our needs, is using Firebase.

Firebase allows us:

  • to integrate it’s functionalities into our project via a simple gradle plugin

  • to create data bases in the cloud and sync them in real time with our devices

  • to create endpoints to manipulate the database, using serverless computing (lambdas)

  • to use their services for free for small projects

Prepare the App

In the build.gradle in the app folder you have to add the following lines in the dependencies section

implementation 'com.google.firebase:firebase-core:16.0.1'
implementation 'com.google.firebase:firebase-database:16.0.1'

and at the end of the file

apply plugin: 'com.google.gms.google-services'

In the build.gradle of the root of your project add

classpath 'com.google.gms:google-services:4.0.0'

in the dependencies section and you are done setting up Firebase in the client.

The next step would be the setup of the physical pins of the Raspberry Pi to communicate with the LEDs and the Reset Button. I am using the following pins:

  • Red LED -> BCM14
  • Yellow LED -> BCM15
  • Green LED -> BCM18
  • Reset Button -> BCM23

You can have a look on the Google Developer Website on how to identify the different pins.

Pin selection on Raspberry Pi (c)myToys 2018

Now, let’s update the code to interact with the cloud data base we are going to set up later:

private var databaseRef: DatabaseReference? = null // reference to Firebase DB
// object that takes care of interacting with the Raspberry Pi
private val manager = PeripheralManager.getInstance()
private var redPin: Gpio? = null
private var greenPin: Gpio? = null
private var yellowPin: Gpio? = null
private var resetPin: Gpio? = null
//Callback listening to button events
private val resetCallback = GpioCallback {
Log.i(TAG, "GPIO changed, button pressed")
reset() // data base is reset to initial state
true
}

In the onCreate method we initialize the data base connection and set the data and the LEDs to their initial state:

databaseRef = FirebaseDatabase.getInstance().reference
databaseRef?.addValueEventListener(this)
reset() // data base is reset to initial state
initPin() // pins are initialised

Our Activity implements the ValueEventListener that listens to changes in the firebase data base:

override fun onDataChange(dataSnapshot: DataSnapshot) {
val color = dataSnapshot.child("status").getValue(RGBColor::class.java)
// update pins
color?.let {
updatePin(redPin!!, it.red)
updatePin(greenPin!!, it.green)
updatePin(yellowPin!!, it.yellow)
}
}

The rest should be pretty self-explanatory. See the whole code as a reference:

private var redPin: Gpio? = null
private var greenPin: Gpio? = null
private var yellowPin: Gpio? = null
private var resetPin: Gpio? = null
//Callback listening to button events
private val resetCallback = GpioCallback {
Log.i(TAG, "GPIO changed, button pressed")
reset()
true
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home)
databaseRef = FirebaseDatabase.getInstance().reference
databaseRef?.addValueEventListener(this)
reset()
initPin()
}
override fun onCancelled(p0: DatabaseError) {
Log.e(TAG, p0.message)
}
override fun onDataChange(dataSnapshot: DataSnapshot) {
val color = dataSnapshot.child("status").getValue(RGBColor::class.java)
Log.d(TAG, "Red [" + color?.red + "]")
Log.d(TAG, "Green [" + color?.green + "]")
Log.d(TAG, "Yellow [" + color?.yellow + "]")
// update pins
color?.let {
updatePin(redPin!!, it.red)
updatePin(greenPin!!, it.green)
updatePin(yellowPin!!, it.yellow)
}
}
private fun initPin() {
try {
resetPin = manager.openGpio(RESET_PIN)
resetPin?.setDirection(Gpio.DIRECTION_IN)
resetPin?.setEdgeTriggerType(Gpio.EDGE_FALLING)
resetPin?.registerGpioCallback(resetCallback)
redPin = manager.openGpio("BCM14")
redPin?.setDirection(Gpio.DIRECTION_OUT_INITIALLY_HIGH)
greenPin = manager.openGpio("BCM18")
greenPin?.setDirection(Gpio.DIRECTION_OUT_INITIALLY_HIGH)
yellowPin = manager.openGpio("BCM15")
yellowPin?.setDirection(Gpio.DIRECTION_OUT_INITIALLY_HIGH)
} catch (ioe: IOException) {
Log.e(TAG, "Unable to open pins")
}
}
private fun updatePin(pin: Gpio, value: Int) {
try {
pin.value = value > 0
} catch (e: IOException) {
e.printStackTrace()
}
}
private fun reset() {
try {
databaseRef?.child("status")?.updateChildren(mutableMapOf(Pair("green"
, 1), Pair("red", 0), Pair("yellow", 0)) as Map<String, Any>)
} catch (e: NullPointerException) {
Log.e(TAG, "moeeegg")
}
}
override fun onDestroy() {
super.onDestroy()
if (resetPin != null) {
resetPin?.unregisterGpioCallback(resetCallback)
try {
}
}
resetPin?.close()
} catch (e: IOException) {
Log.e(TAG, "Error on PeripheralIO API", e)
}
}
data class RGBColor(var red: Int = 100, var green: Int = 100, var yellow: Int = 100)

Prepare the Data Base in the cloud:

In the next step we create a new project online in Firebase and setup a data base with the following structure:

Firebase data base structure
Firebase data base structure (c)myToys 2018

While setting up the project, a „google-services.json“ file is generated. Download it and add it in the app folder of your project. Now your App and the Firebase project are connected. If everything went well you can run the App and changing the values in the data base should change which LED is on. Pressing the push button should reset the data base back to the green led being set to 1.

The final prototype
The final prototype (c)myToys 2018

React to events using Lambdas:

If „Serverless Architecture“ or „Function as a Service“ do not say anything to you, please have a look at Martin Fowler’s article about Serverless Architecture first.

In Firebase lambdas are called „functions“. You can use different programming languages. For our project we are using node.js.

If you are new to programming „functions“ in Firebase, please follow this tutorial first and use it as a base for your project

The idea is to have three different endpoints, „statusGreen“, „statusYellow“ and „statusRed“. Calling one of these endpoints should set the corresponding LED value to 1 and reset the other two to 0.

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.statusGreen = functions.https.onRequest((req, res) => {
// Push the new message into the Realtime Database using the Firebase Admin SDK.
return admin.database().ref('/status').update({"green": 1,"yellow": 0,"red": 0})
.then((snapshot) => {
return res.status(200).send("status Ok")
}); });
exports.statusYellow = functions.https.onRequest((req, res) => {
// Push the new message into the Realtime Database using the Firebase Admin SDK.
return admin.database().ref('/status').update({"green": 0,"yellow": 1,"red": 0})
.then((snapshot) => {
return res.status(200).send("status Warning")
}); });
exports.statusRed = functions.https.onRequest((req, res) => {
// Push the new message into the Realtime Database using the Firebase Admin SDK.
return admin.database().ref('/status').update({"green": 0,"yellow": 0,"red": 1})
.then((snapshot) => {
return res.status(200).send("status Alarm")
}); });

When deploying these functions to Firebase via a terminal you should see the coresponding urls to call. You can now hook up these urls to all kind of events (eg. jenkins job fails).

Conclusion

Raspberry Pi, Android Things and Firebase allow us to create a real time monitoring system in no time, even if you are an Embedded Computing or Android Development newbee.

For suggestions or questions feel free to leave a comment or to contact me directly under jeldrik.schmuch@mytoys.de

Share

Schreibe einen Kommentar