Project tutorial
Room Automation for Kids

Room Automation for Kids © Apache-2.0

A Google Assistant compatible box for kids (from 2 years old) to control lights and other devices in their room.

  • 1 comment
  • 38 respects

Components and supplies

1.pico imx7 emmc 1
TechNexion PICO-IMX7
Adafruit Mini USB Microphone
RC522 RFID Module
11114 01a
SparkFun Arduino Pro Mini 328 - 3.3V/8MHz
Acts as a proxy between the RC522 and the Android Things board
09181 03 l
SparkFun Big Red Dome Button
Red, Green, Blue, Yellow, White, Black
Mfr 25fbf52 221r sml
Resistor 221 ohm
Pull-up resistors
Mfr 25frf52 1k sml
Resistor 1k ohm
Pull-up resistor for the last button, connected to the 1.8V GPIO
11026 02
Jumper wires (generic)
12002 04
Breadboard (generic)
Audio Speakers 3.5mm jack USB powered
Or any compatible audio speaker

Apps and online services

About this project

Home automation is not limited to adults! This device lets children control lights and other devices in their rooms, in a fun and easy way.

This project is a box with an NFC sensor and 6 colored buttons. When a kid places an RFID device on top of the box (such as a "toys-to-life" figurine) and presses a color button, it will have a direction action in his room, depending on the RFID device.

Among the possible actions, you can:

  • Change the light color
  • Control the fan
  • Play some music
  • Learn colors in Chinese
  • Talk to the Google Assistant

Here's a video of the prototype, in action:


Children have lots of imagination. Here, controlling the light color is a fun way to imitate the police siren:

Police Siren Imitation

Handling RFID devices

To simplify using the RC522 RFID Module, we will use an Arduino Pro Mini 3.3V as a proxy.

The Arduino will read RFID devices UIDs, and forward those to the Serial bus, as you can see in the enclosed Arduino sketch (in the "Code" section below).

To receive UIDs from the RC522 module to the Android Things project, a LiveData (from the Android Architecture Components) wrapper will listen to the UART serial, and emit received data (see the enclosed Rc522LiveData file in the "Code" section below).

Now, when a device is detected, the Android Things project will know the ID. When pressed, buttons will have different actions, depending on the last emitted RFID UID.

Handling buttons events

The device has 6 buttons: red, green, blue, yellow, white and black.

We will therefore need 6 buttons and 6 (pull-up) resistors, and again create a LiveData wrapper, so that when a button is pressed, an event is emitted to the observer (our MainActivity)

(See the ButtonsLiveData in the "Code" section below)

Now, in our MainActivity, we can observe the ButtonsLiveData and execute an action depending on the last emitted RC522LiveData UID, and the last emitted ButtonsLiveData value:

viewModel.buttonsLiveData.observe({ lifecycle }) { buttonData ->
    Log.i(TAG, "Button pressed: $buttonData")
    val button = buttonData!!.first
    val isPressed = buttonData.second

    viewModel.rc522LiveData.value?.let { rfid ->
        val rfidDevice = RfidDevice.getFromRfidId(rfid)

        // Perform actions here depending on button and rfidDevice variables

Adding the Google Assistant

Children can also be able to talk to the Google Assistant, if parents allow them to providing them an RFID device to trigger Google Assistant actions.

That way, their fun device turns into a real Google Home device.

To setup the Google Assistant, you have to:

  • Enable the Google Assistant API and create an OAuth Client ID (name=androidthings-googleassistant ) (Read here for help)
pip install google-auth-oauthlib[tool]
google-oauthlib-tool --client-secrets client_secret_NNNN.json \
  --credentials ./google-assistant/src/main/res/raw/credentials.json \
  --scope \

Setting up buttons actions

As you have noticed, button actions (e.g. setting the lights to blue) are hard coded in the project and depend on specific hardware.

But since the device is connected to the Google Assistant, parents could be able to record predefined sentences (such as "Set the lights to red in the kid's room") for each RFID device and button. Those sentences will be persisted in the Android Things device, and forwarded to the Google Assistant when a button is pressed. That way, it makes the kids' assistant compatible with any devices in the market (as long as they support the Google Assistant). To add support to a new device, you won't have to write specific code for this project, but instead, use the Actions on Google SDK, to make your new device compatible with both the Google Home, and the Kids' Room Automation device.

Prettify the device

A tissue-box and RFID cards look boring, so my kid personalized everything with some drawings and stickers. We also used real "toys-to-life" figurine available in any video games store.

Here's what our own device looks like. Each device will be different depending on your children's tastes.

Drawing for each card

One example of prettifying the device.

Cloning the repository:

Full project is available on GitHub (see the Code section below).

We would love to see your own kids assistant too!

Schematics below are for the NXP.iMX7D. You can, of course use any Android Things compatible board.


A LiveData wrapper that emits RFID ids received from the Arduino UART interface
class Rc522LiveData : LiveData<String>() {

    companion object {
        private const val UART_NAME = "UART6"
        private const val UART_BUFFER_SIZE = 512

    private var handler: Handler? = null
    private var handlerThread: HandlerThread? = null

    private var uartDevice: UartDevice? = null
    private var pendingUartData = ""

    private val callback = object : UartDeviceCallback() {
        // This method is called when the Arduino write data to the Serial interface. We will get data and emit a LiveData value
        override fun onUartDeviceDataAvailable(uart: UartDevice): Boolean {
            val buffer = ByteArray(UART_BUFFER_SIZE)
            val read =, UART_BUFFER_SIZE)

            if (read > 0) {

            return true

        override fun onUartDeviceError(uart: UartDevice, error: Int) {
            Log.e(TAG, "UART device error ($error)")

    override fun onActive() {

    override fun onInactive() {

    // Open the UART connection
    private fun openUart() {
        handlerThread = HandlerThread(TAG).also { handlerThread ->
            handler = Handler(handlerThread.looper)

        uartDevice = PeripheralManagerService().openUartDevice(UART_NAME).apply {

            registerUartDeviceCallback(callback, handler)

    // Close the UART connection
    private fun closeUart() {
        handler = null
        handlerThread?.quitSafely().also { handlerThread = null }

        uartDevice?.let {
        }.also { uartDevice = null }
Arduino SketchArduino
#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN 9
#define SDA_PIN 10

MFRC522 mfrc522;

void setup() {
  while (!Serial);

  mfrc522.PCD_Init(SDA_PIN, RST_PIN);

void loop() {
  // Forward Uid to the Serial interface
  if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) {
    writeUidToSerial(mfrc522.uid.uidByte, mfrc522.uid.size);

void writeUidToSerial(byte *uid, byte size) {
  for (byte i = 0; i < size; i++) {
    if (uid[i] < 0x10) {
    Serial.print(uid[i], HEX);
class ButtonsLiveData : LiveData<Pair<DataLayerButton, Boolean>>() {

    companion object {
        private const val BUTTON_DEBOUNCE_DELAY_MS = 20L

    private val DataLayerButton.gpio: String
        get() = when (this) {
            DataLayerButton.RED -> "GPIO_37"
            DataLayerButton.GREEN -> "GPIO_32"
            DataLayerButton.BLUE -> "GPIO_39"
            DataLayerButton.YELLOW -> "GPIO_34"
            DataLayerButton.WHITE -> "GPIO_33"
            DataLayerButton.BLACK -> "GPIO_174"

    // This map is helpful to know which button is pressed
    private var buttons: Map<DriverLayerButton, DataLayerButton>? = null

    // When a button event is received, we emit the button and its state (pressed=true, release=false)
    private val listener = OnButtonEventListener { button: DriverLayerButton, pressed: Boolean ->
        buttons?.get(button)?.let {
            value = it to pressed

    // Here, we open and setup all buttons according to their GPIO names
    override fun onActive() {
        buttons = DataLayerButton.values()
                .map {
                    DriverLayerButton(it.gpio, DriverLayerButton.LogicState.PRESSED_WHEN_LOW).apply {
                    } to it

    // We close buttons when the LiveData is inactive
    override fun onInactive() {
        buttons?.let { buttons ->
            buttons.forEach { (button, _) ->
        }.also {
            buttons = null
Full project on GitHub
See the file for build information


NXP Pico i.MX7D I/O Pinout
Pinout pico7 wb0xrnmv5w
Schematics resized u0bvwns0el


Similar projects you might like

Android App-Based Home Automation System Using IOT

Project tutorial by Team Autoshack

  • 174 respects

Smart Home Automation And Security System Using 1Sheeld

Project tutorial by Team SADEE

  • 35 respects

Arduino Tutorial: JARVIS v1 | How to make a Home Automation

Project tutorial by Rahul Khanna D

  • 115 respects

Email Home Automation

Project tutorial by Chirila Radu

  • 17 respects

Home Automation Using Google Assistant

Project showcase by Pawan Kumar

  • 75 respects

Home Automation with Arduino MKR1000 and Windows 10

Project tutorial by Ioannis Kydonis

  • 1 comment
  • 38 respects
Add projectSign up / Login