Project tutorial

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.

  • 4,236 views
  • 0 comments
  • 17 respects

Components and supplies

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

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:

Prototype

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 https://www.googleapis.com/auth/assistant-sdk-prototype \
  --save

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.

Schematics

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

Code

Rc522LiveDataJava
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.read(buffer, UART_BUFFER_SIZE)

            if (read > 0) {
                postValue(buffer)
            }

            return true
        }

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

    override fun onActive() {
        openUart()
    }

    override fun onInactive() {
        closeUart()
    }

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

        uartDevice = PeripheralManagerService().openUartDevice(UART_NAME).apply {
            setBaudrate(9600)
            setDataSize(8)
            setParity(UartDevice.PARITY_NONE)
            setStopBits(1)

            registerUartDeviceCallback(callback, handler)
        }
    }

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

        uartDevice?.let {
            it.unregisterUartDeviceCallback(callback)
            it.close()
        }.also { uartDevice = null }
    }
}
Arduino SketchArduino
#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN 9
#define SDA_PIN 10

MFRC522 mfrc522;

void setup() {
  Serial.begin(9600);
  while (!Serial);

  SPI.begin();
  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);
    mfrc522.PICC_HaltA();
  }
}

void writeUidToSerial(byte *uid, byte size) {
  for (byte i = 0; i < size; i++) {
    if (uid[i] < 0x10) {
      Serial.print("0");
    }
    Serial.print(uid[i], HEX);
  }
  Serial.println();
}
ButtonsLiveDataJava
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 {
                        setDebounceDelay(BUTTON_DEBOUNCE_DELAY_MS)
                        setOnButtonEventListener(listener)
                    } to it
                }
                .toMap()
    }

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

Comments

Similar projects you might like

Pac-Man LED Pixel Panel Costume

Project tutorial by Ben Muller

  • 4,641 views
  • 3 comments
  • 82 respects

LoRa Gateway for DeviceHive

Project tutorial by DeviceHive IoT team

  • 1,194 views
  • 2 comments
  • 16 respects

IoT Bird Feeder with Sigfox and Tweeter

Project showcase by Gaël Porté

  • 347 views
  • 0 comments
  • 7 respects

Raspberry Pi and Arduino Laptop

Project tutorial by Dante Roumega

  • 17,682 views
  • 6 comments
  • 44 respects

Arduino-Based Automatic Guitar Tuner

Project tutorial by Ben Overzat

  • 3,278 views
  • 0 comments
  • 10 respects

Really Smart Box

Project tutorial by Stephen Harrison

  • 3,237 views
  • 0 comments
  • 9 respects
Add projectSign up / Login