Android Things Tutorial: Getting Started
Did you ever want to tinker with all those little pins on hardware boards? Well in this tutorial, you’ll learn how to do just that, with AndroidThings! By Dean Djermanović.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Android Things Tutorial: Getting Started
30 mins
- Developing for Android Things
- Getting Started
- Connect the Hardware
- Install Android Things
- Connect to the Internet
- Download and Explore the Starter Project
- Communication with Hardware
- Manage the Connection
- Read from an Input
- Listen for Input State Changes
- Write to an Output
- Connect with Firebase
- Capture the Ring Event
- Notify the User
- Handle Response
- Where to Go From Here?
Write to an Output
Next you will turn the Blue LED on the Rainbow HAT ON and OFF on button taps based on the state of your A button.
First open your BoardManager
class and add the following:
private lateinit var blueLedGpio: Gpio
This defines your GPIO field for the blue LED light. Next, paste in the following method:
private fun initializeLedLights() {
try {
//1
blueLedGpio = peripheralManager.openGpio(BLUE_LED_PIN_NAME)
//2
blueLedGpio.apply {
setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW)
}
} catch (exception: IOException) {
handleError(exception)
}
}
This adds a initializeLedLights()
function that does the following:
- You use the
PeripheralManager
to open a connection with the GPIO pin wired to the Blue LED. - You configure pin as an output using
setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW)
. This will also set the initial state of the pin to zero volts, which means LED light will be turned off initially.
Now, add a call to initializeLedLights
in your initialize()
function. Next, replace initializeButtonCallback()
with the following:
private fun initializeButtonCallback() {
buttonCallback = GpioCallback {
try {
//1
val buttonValue = it.value
//2
blueLedGpio.value = buttonValue
} catch (exception: IOException) {
handleError(exception)
}
true
}
}
This does the following:
- Reads the button state with the
it.value
property. Theit
field is the buttons GPIO instance. - Sets the LEDs value with the
blueLedGpio.value
and set it to on if you press the button, and off if you release it.
Finally, replace your clear()
function with the following:
fun clear() {
buttonGpio.unregisterGpioCallback(buttonCallback)
arrayOf(buttonGpio, blueLedGpio)
.forEach {
try {
it.close()
} catch (exception: IOException) {
handleError(exception)
}
}
}
This cleans up your resources. Instead of closing GPIO connections individually, you add the blue LED GPIO and button GPIO to an array that you iterate over.
That’s it. Build and run the app. When you press the blue button, the LED light will be turned on. When you release it, it will be turned off.
Great job so far! But turning LED light ON and OFF isn’t that exciting, unless you’re a fish, so let’s connect your app with Firebase! :]
Connect with Firebase
You’ll create a simple infrastructure that will simulate a doorbell. To do that, you need three things:
- Doorbell – a button tap on a board will simulate a doorbell.
- Database – ring events will be sent to the Firebase database.
- Mobile app – ring events will be displayed on your mobile app. Using this app, you’ll control whether you’ll let the person at the door in or not.
This is how it looks graphically:
google-services.json
file for the app. If you are unfamiliar with how to do this, refer on our Firebase tutorial, which is linked at the beginning of this tutorial.Capture the Ring Event
First, add RingEvent
singleton class to the bottom of the BoardManager
class by pasting the following:
object RingEvent
Next, add a ringEvent
field of MutableLiveData
type:
private val ringEvent = MutableLiveData()
Now, add a function which will expose ring events:
fun listenForRingEvents() = ringEvent
Next, replace the initializeButtonCallback()
function with the following:
private fun initializeButtonCallback() {
buttonCallback = GpioCallback {
try {
val buttonValue = it.value
blueLedGpio.value = buttonValue
// call the database
ringEvent.postValue(RingEvent)
} catch (exception: IOException) {
handleError(exception)
}
true
}
}
When you press a button on the board, a ring event will be sent to the database.
Then, in your MainActivity
class paste in the following code:
private fun onRingEvent(ringEvent: RingEvent?) = ringRepository.saveRingEvent()
This function will handle ring events, by notifying the ringRepository
.
Now, replace your MainActivity
‘s initialize()
with the following:
private fun initialize() {
boardManager = BoardManager()
// initialize your ring repository
ringRepository = RingRepository()
boardManager.initialize()
// listen for ring events
boardManager
.listenForRingEvents()
.observe(this, Observer { ringEvent ->
onRingEvent(ringEvent)
})
}
This listens for ring events coming from your board and triggers your onRingEvent
function.
Finally, add the Google Play Services plug-in to your app level build.gradle
.
apply plugin: 'com.google.gms.google-services'
Notify the User
In your materials there is also a knockknockmobile
project. Open it in Android Studio and copy the google-services.json
file that you have in the knockknock
project to the knockknockmobile
project.
Open the google-services.json
file and search for the package_name
attribute and replace its value with com.raywenderlich.knockknockmobile
package name.
Build and run the mobile app on your mobile device. You’ll see this screen:
Build and run your Android Things app on the board. Tap on a button and check the Firebase database data. You should see ring event there:
Your mobile app will also change and you should now see the following screen:
By tapping the YES or NO buttons you will decide whether to let the person in or not. The answer is sent to Firebase.
Handle Response
Right now your board doesn’t do anything with the response, but you’re going to fix that!
To begin, paste the following into your BoardManager
class:
private lateinit var redLedGpio: Gpio
private lateinit var greenLedGpio: Gpio
This adds the GPIO fields for the red and green LEDs. Next paste the following into the same class:
fun turnRedLedLightOn() {
redLedGpio.value = true
}
fun turnRedLedLightOff() {
redLedGpio.value = false
}
fun turnGreenLedLightOn() {
greenLedGpio.value = true
}
fun turnGreenLedLightOff() {
greenLedGpio.value = false
}
This adds methods for turning red and green LED lights ON and OFF. Now, add the following to your MainActivity
:
private fun turnLightsOffAfterDelay() {
Handler().postDelayed({
boardManager.turnGreenLedLightOff()
boardManager.turnRedLedLightOff()
}, LIGHT_OFF_DELAY_MILLIS)
}
This adds a turnLightsOffAfterDelay()
function which turns LED lights off after a small delay. Next, paste the following in the same class.
private fun onRingResponseReceived(dataSnapshot: DataSnapshot?) {
//1
val unlockDoor = dataSnapshot?.value as Boolean
//2
if (unlockDoor)
boardManager.turnGreenLedLightOn()
else
boardManager.turnRedLedLightOn()
//3
turnLightsOffAfterDelay()
}
This adds a onRingResponseReceived(dataSnapshot: DataSnapshot?)
function which you call on every ring response event.
Going through it:
- When you receive a response
boolean
it indicates whether to unlock the door or not. You get thisboolean
by usingdataSnapshot?.value as Boolean
- If you should unlock the door, you’ll turn on the green LED light on the board, otherwise you turn on the red LED light.
- This function turns the LED light off after 3 seconds.
Now, replace the initialize
function of your MainActivity
with:
private fun initialize() {
boardManager = BoardManager()
ringRepository = RingRepository()
boardManager.initialize()
boardManager
.listenForRingEvents()
.observe(this, Observer { ringEvent ->
onRingEvent(ringEvent)
})
// ringRepository listener
ringRepository
.listenForRingResponseEvents()
.observe(this, Observer { dataSnapshot ->
onRingResponseReceived(dataSnapshot)
})
}
This adds an observer to your ringRepository
to observe ring response events. Now there are two more things you will need to do to button this up.
First, replace initializeLedLights
with the following in your BoardManager
class:
private fun initializeLedLights() {
try {
// initialize red LEDs
redLedGpio = peripheralManager.openGpio(RED_LED_PIN_NAME)
redLedGpio.apply { setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW) }
// initialize green LEDs
greenLedGpio = peripheralManager.openGpio(GREEN_LED_PIN_NAME)
greenLedGpio.apply { setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW) }
blueLedGpio = peripheralManager.openGpio(BLUE_LED_PIN_NAME)
blueLedGpio.apply { setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW) }
} catch (exception: IOException) {
handleError(exception)
}
}
This initializes the red and green LED lights.
Finally, replace your clear()
function with the following:
fun clear() {
buttonGpio.unregisterGpioCallback(buttonCallback)
arrayOf(buttonGpio, redLedGpio, greenLedGpio, blueLedGpio)
.forEach {
try {
it.close()
} catch (exception: IOException) {
handleError(exception)
}
}
}
This updates your array with the red and green LED GPIOs so that they are closed properly.
Build and run the app. Press the button on the board and use mobile app to either let the person in or deny them access. The green LED will light up if you let them in and the red one will light up if you deny access. You can find the final project in the downloaded materials.