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ć.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 4 of 5 of this article. Click here to view the first page.

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:

  1. You use the PeripheralManager to open a connection with the GPIO pin wired to the Blue LED.
  2. 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:

  1. Reads the button state with the it.value property. The it field is the buttons GPIO instance.
  2. 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:

  1. Doorbell – a button tap on a board will simulate a doorbell.
  2. Database – ring events will be sent to the Firebase database.
  3. 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:

Note: The logic for saving ring events to the Firebase is implemented for you. You need to create a project in Firebase, ensure that a database has been created for it and that it has public permissions for read and write. Once you have done that, create an app for it and download the 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:

  1. When you receive a response boolean it indicates whether to unlock the door or not. You get this boolean by using dataSnapshot?.value as Boolean
  2. 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.
  3. 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.