Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Android Things Workshop - Building a Motion Sensing Camera

Android Things Workshop - Building a Motion Sensing Camera

In this workshop, attendees built an Android Things motion sensing camera using the Google Android Things libraries. The slides acted as a guide throughout the workshop.
The full hackster project can be found here - https://www.hackster.io/riggaroo/smart-motion-sensing-camera-with-intruder-notifications-b6c613
With the Github Repository for the workshop with the different steps: https://github.com/riggaroo/android-things-workshop-camera

2a37bf1e025cc1523124774c760df91a?s=128

Rebecca Franks

November 11, 2017
Tweet

Transcript

  1. None
  2. None
  3. None
  4. None
  5. None
  6. extension IoT embedded

  7. powerful intelligent secure

  8. Android SDK Play Services Firebase Android Studio Cloud Platform

  9. No Play Store Deploy OTAs Subset of APIs Custom Hardware

    Single Purpose Device
  10. None
  11. None
  12. None
  13. SoM Architecture Google Managed BSP

  14. Android Framework Hardware Libraries Linux Kernel Apps User Drivers

  15. • • • •

  16. None
  17. None
  18. None
  19. None
  20. None
  21. Button GPS PWM Servo RGB LED Strip Temperature Sensor Capacitive

    Touch Buttons GPIO PWM I2C SPI UART I2S
  22. None
  23. None
  24. None
  25. None
  26. None
  27. None
  28. Electronics Basics

  29. Components Breadboard - Construction base for prototyping electronics Jumper Wire

    - Used to interconnect the components of a breadboard
  30. LEDs - Emits visible light when an electric current passes

    through it Push Switches - Allows electricity to flow between its two contacts Components
  31. Resistor -Used to reduce current flow Source: http://www.electronicshub.org/resistor-color-code/ Components and

    many more...
  32. Ohm’s Law The current through a conductor between two points

    is directly proportional to the voltage across the two points. V = I * R V is Voltage (volts) I is Current (amps) R is Resistance (ohms) I = 0.023A V = 5V R = 5V / 0.023A R = ± 217 ohms
  33. None
  34. None
  35. Red, Red, Brown = 220 ohm Brown, Black, Orange =

    1k ohm
  36. None
  37. None
  38. None
  39. None
  40. None
  41. Pico Setup: bit.ly/pico-pro-setup

  42. None
  43. //Boot into fastboot mode $ adb reboot bootloader // Get

    list of fastboot devices $ fastboot devices 1b2f21d4e1fe0129 fastboot //Locate directory with factory image $ ./flash_all.sh //windows ./flash_all.bat // Get list of devices once flashed $ adb devices List of devices attached 1b2f21d4e1fe0129 device
  44. //Start internet $ adb shell am startservice -n com.google.wifisetup/.WifiSetupService -a

    WifiSetupService.Connect -e ssid "Jozihub Events" -e passphrase Jozihub#
  45. None
  46. None
  47. None
  48. None
  49. None
  50. //Automatically added in app level build.gradle compileOnly 'com.google.android.things:androidthings:...'

  51. //Automatically added in AndroidManifest.xml <application ...> <uses-library android:name="com.google.android.things"/> <activity ...>

    <!-- Launch activity automatically on boot --> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.IOT_LAUNCHER"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </activity> </application>
  52. //Automatically added in AndroidManifest.xml <application ...> <uses-library android:name="com.google.android.things"/> <activity ...>

    <!-- Launch activity automatically on boot --> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.IOT_LAUNCHER"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </activity> </application>
  53. None
  54. //Accessing Sensor Data private val buttonGpio: Gpio = PeripheralManagerService().openGpio(“GPIO_175”) fun

    start() { buttonGpio.setDirection(Gpio.DIRECTION_IN) buttonGpio.setActiveType(Gpio.ACTIVE_HIGH) buttonGpio.setEdgeTriggerType(Gpio.EDGE_BOTH) buttonGpio.registerGpioCallback(object : GpioCallback() { override fun onGpioEdge(gpio: Gpio): Boolean { if (gpio.value) { ledGpio.value = true } else { //do something else } return true } }) }
  55. //Accessing Sensor Data private val buttonGpio: Gpio = PeripheralManagerService().openGpio(“GPIO_175”) fun

    start() { buttonGpio.setDirection(Gpio.DIRECTION_IN) buttonGpio.setActiveType(Gpio.ACTIVE_HIGH) buttonGpio.setEdgeTriggerType(Gpio.EDGE_BOTH) buttonGpio.registerGpioCallback(object : GpioCallback() { override fun onGpioEdge(gpio: Gpio): Boolean { if (gpio.value) { ledGpio.value = true } else { //do something else } return true } }) }
  56. //Accessing Sensor Data private val buttonGpio: Gpio = PeripheralManagerService().openGpio(“GPIO_175”) fun

    start() { buttonGpio.setDirection(Gpio.DIRECTION_IN) buttonGpio.setActiveType(Gpio.ACTIVE_HIGH) buttonGpio.setEdgeTriggerType(Gpio.EDGE_BOTH) buttonGpio.registerGpioCallback(object : GpioCallback() { override fun onGpioEdge(gpio: Gpio): Boolean { if (gpio.value) { ledGpio.value = true } else { //do something else } return true } }) }
  57. None
  58. //Accessing Sensor Data private val motionSensorGpio: Gpio = PeripheralManagerService().openGpio(“GPIO_35”) fun

    start() { motionSensorGpio.setDirection(Gpio.DIRECTION_IN) motionSensorGpio.setActiveType(Gpio.ACTIVE_HIGH) motionSensorGpio.setEdgeTriggerType(Gpio.EDGE_BOTH) motionSensorGpio.registerGpioCallback(object : GpioCallback() { override fun onGpioEdge(gpio: Gpio): Boolean { if (gpio.value) { motionListener.onMotionDetected() } else { motionListener.onMotionStopped() } return true } }) }
  59. //Accessing Sensor Data private val motionSensorGpio: Gpio = PeripheralManagerService().openGpio(“GPIO_35”) fun

    start() { motionSensorGpio.setDirection(Gpio.DIRECTION_IN) motionSensorGpio.setActiveType(Gpio.ACTIVE_HIGH) motionSensorGpio.setEdgeTriggerType(Gpio.EDGE_BOTH) motionSensorGpio.registerGpioCallback(object : GpioCallback() { override fun onGpioEdge(gpio: Gpio): Boolean { if (gpio.value) { motionListener.onMotionDetected() } else { motionListener.onMotionStopped() } return true } }) }
  60. //Accessing Sensor Data private val motionSensorGpio: Gpio = PeripheralManagerService().openGpio(“GPIO_35”) fun

    start() { motionSensorGpio.setDirection(Gpio.DIRECTION_IN) motionSensorGpio.setActiveType(Gpio.ACTIVE_HIGH) motionSensorGpio.setEdgeTriggerType(Gpio.EDGE_BOTH) motionSensorGpio.registerGpioCallback(object : GpioCallback() { override fun onGpioEdge(gpio: Gpio): Boolean { if (gpio.value) { camera.takePhoto() } else { //do something else } return true } }) }
  61. None
  62. val peripheralManagerService = PeripheralManagerService() ledGpio = peripheralManagerService.openGpio(“GPIO_174”) ledGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW) ledGpio.value =

    true ledGpio.close()
  63. val peripheralManagerService = PeripheralManagerService() ledGpio = peripheralManagerService.openGpio(“GPIO_174”) ledGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW) ledGpio.value =

    true ledGpio.close()
  64. val peripheralManagerService = PeripheralManagerService() ledGpio = peripheralManagerService.openGpio(“GPIO_174”) ledGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW) ledGpio.value =

    true ledGpio.close()
  65. None
  66. None
  67. private fun setupCamera() { camera = CustomCamera.getInstance() camera.initializeCamera(this, Handler(), imageAvailableListener)

    } private val imageAvailableListener = object : CustomCamera.ImageCapturedListener { override fun onImageCaptured(bitmap: Bitmap) { motionImageView.setImageBitmap(bitmap) motionViewModel.uploadMotionImage(bitmap) } } camera.takePicture()
  68. private fun setupCamera() { camera = CustomCamera.getInstance() camera.initializeCamera(this, Handler(), imageAvailableListener)

    } private val imageAvailableListener = object : CustomCamera.ImageCapturedListener { override fun onImageCaptured(bitmap: Bitmap) { motionImageView.setImageBitmap(bitmap) motionViewModel.uploadMotionImage(bitmap) } } camera.takePicture()
  69. private fun setupCamera() { camera = CustomCamera.getInstance() camera.initializeCamera(this, Handler(), imageAvailableListener)

    } private val imageAvailableListener = object : CustomCamera.ImageCapturedListener { override fun onImageCaptured(bitmap: Bitmap) { motionImageView.setImageBitmap(bitmap) motionViewModel.uploadMotionImage(bitmap) } } camera.takePicture()
  70. None
  71. None
  72. None
  73. //data class for saving data class FirebaseImageLog(val timestamp: Long? =

    null, val imageRef: String? = null) //upload image val storageRef = FirebaseStorage.getInstance().getReference(FIREBASE_MOTION_REF) val imageStorageRef = storageRef.child(FIREBASE_IMAGE_PREFIX + System.currentTimeMillis() + ".jpg") val uploadTask = imageStorageRef.putBytes(imageStream.toByteArray()) uploadTask.addOnFailureListener { Log.d(TAG, "onFailure uploadMotionImage") }.addOnSuccessListener { // save image log to realtime db val downloadUrl = imageStorageRef.path val ref = FirebaseDatabase.getInstance().getReference(FIREBASE_MOTION_LOGS).push() ref.setValue(FirebaseImageLog(System.currentTimeMillis(), downloadUrl)) }
  74. //data class for saving data class FirebaseImageLog(val timestamp: Long? =

    null, val imageRef: String? = null) //upload image val storageRef = FirebaseStorage.getInstance().getReference(FIREBASE_MOTION_REF) val imageStorageRef = storageRef.child(FIREBASE_IMAGE_PREFIX + System.currentTimeMillis() + ".jpg") val uploadTask = imageStorageRef.putBytes(imageStream.toByteArray()) uploadTask.addOnFailureListener { Log.d(TAG, "onFailure uploadMotionImage") }.addOnSuccessListener { // save image log to realtime db val downloadUrl = imageStorageRef.path val ref = FirebaseDatabase.getInstance().getReference(FIREBASE_MOTION_LOGS).push() ref.setValue(FirebaseImageLog(System.currentTimeMillis(), downloadUrl)) }
  75. //data class for saving data class FirebaseImageLog(val timestamp: Long? =

    null, val imageRef: String? = null) //upload image val storageRef = FirebaseStorage.getInstance().getReference(FIREBASE_MOTION_REF) val imageStorageRef = storageRef.child(FIREBASE_IMAGE_PREFIX + System.currentTimeMillis() + ".jpg") val uploadTask = imageStorageRef.putBytes(imageStream.toByteArray()) uploadTask.addOnFailureListener { Log.d(TAG, "onFailure uploadMotionImage") }.addOnSuccessListener { // save image log to realtime db val downloadUrl = imageStorageRef.path val ref = FirebaseDatabase.getInstance().getReference(FIREBASE_MOTION_LOGS).push() ref.setValue(FirebaseImageLog(System.currentTimeMillis(), downloadUrl)) }
  76. //data class for saving data class FirebaseImageLog(val timestamp: Long? =

    null, val imageRef: String? = null) //upload image val storageRef = FirebaseStorage.getInstance().getReference(FIREBASE_MOTION_REF) val imageStorageRef = storageRef.child(FIREBASE_IMAGE_PREFIX + System.currentTimeMillis() + ".jpg") val uploadTask = imageStorageRef.putBytes(imageStream.toByteArray()) uploadTask.addOnFailureListener { Log.d(TAG, "onFailure uploadMotionImage") }.addOnSuccessListener { // save image log to realtime db val downloadUrl = imageStorageRef.path val ref = FirebaseDatabase.getInstance().getReference(FIREBASE_MOTION_LOGS).push() ref.setValue(FirebaseImageLog(System.currentTimeMillis(), downloadUrl)) }
  77. None
  78. None
  79. $ firebase login $ firebase init functions

  80. var functions = require('firebase-functions'); var admin = require('firebase-admin'); admin.initializeApp(functions.config().firebase); exports.annotateImage

    = functions.database.ref('/motion-logs/{id}') .onCreate(event => { const original = event.data.val(); var topic = "/topics/intruders"; var payload = { data: { title: "Intruder Alert!", body: "An intruder has been detected" } }; return admin.messaging().sendToTopic(topic, payload) .then(function (response) { console.log("Successfully sent message:", response); }).catch(function (error) { console.log("Error sending message:", error); }); } );
  81. var functions = require('firebase-functions'); var admin = require('firebase-admin'); admin.initializeApp(functions.config().firebase); exports.annotateImage

    = functions.database.ref('/motion-logs/{id}') .onCreate(event => { const original = event.data.val(); var topic = "/topics/intruders"; var payload = { data: { title: "Intruder Alert!", body: "An intruder has been detected" } }; return admin.messaging().sendToTopic(topic, payload) .then(function (response) { console.log("Successfully sent message:", response); }).catch(function (error) { console.log("Error sending message:", error); }); } );
  82. var functions = require('firebase-functions'); var admin = require('firebase-admin'); admin.initializeApp(functions.config().firebase); exports.annotateImage

    = functions.database.ref('/motion-logs/{id}') .onCreate(event => { const original = event.data.val(); var topic = "/topics/intruders"; var payload = { data: { title: "Intruder Alert!", body: "An intruder has been detected" } }; return admin.messaging().sendToTopic(topic, payload) .then(function (response) { console.log("Successfully sent message:", response); }).catch(function (error) { console.log("Error sending message:", error); }); } );
  83. $ firebase deploy --only functions

  84. None
  85. None
  86. //Use FirebaseUI dependency api "com.firebaseui:firebase-ui-database:3.0.0" // Get DB Reference val

    databaseRef = FirebaseDatabase.getInstance().getReference(MOTION_LOGS_FIREBASE_REF) // Create adapter that extends FirebaseRecyclerAdapter class LogsAdapter(ref: DatabaseReference) : FirebaseRecyclerAdapter<FirebaseImageLog, LogsViewHolder>(FirebaseImageLog::class.java, R.layout.list_item_log, LogsViewHolder::class.java, ref) { //.. Do adapter things } // Set adapter to use reference adapter = LogsAdapter(databaseRef.orderByChild(ORDER_BY_TIMESTAMP).ref)
  87. //Use FirebaseUI dependency api "com.firebaseui:firebase-ui-database:3.0.0" // Get DB Reference val

    databaseRef = FirebaseDatabase.getInstance().getReference(MOTION_LOGS_FIREBASE_REF) // Create adapter that extends FirebaseRecyclerAdapter class LogsAdapter(ref: DatabaseReference) : FirebaseRecyclerAdapter<FirebaseImageLog, LogsViewHolder>(FirebaseImageLog::class.java, R.layout.list_item_log, LogsViewHolder::class.java, ref) { //.. Do adapter things } // Set adapter to use reference adapter = LogsAdapter(databaseRef.orderByChild(ORDER_BY_TIMESTAMP).ref)
  88. //Use FirebaseUI dependency api "com.firebaseui:firebase-ui-database:3.0.0" // Get DB Reference val

    databaseRef = FirebaseDatabase.getInstance().getReference(MOTION_LOGS_FIREBASE_REF) // Create adapter that extends FirebaseRecyclerAdapter class LogsAdapter(ref: DatabaseReference) : FirebaseRecyclerAdapter<FirebaseImageLog, LogsViewHolder>(FirebaseImageLog::class.java, R.layout.list_item_log, LogsViewHolder::class.java, ref) { //.. Do adapter things } // Set adapter to use reference adapter = LogsAdapter(databaseRef.orderByChild(ORDER_BY_TIMESTAMP).ref)
  89. //Use FirebaseUI dependency api "com.firebaseui:firebase-ui-database:3.0.0" // Get DB Reference val

    databaseRef = FirebaseDatabase.getInstance().getReference(MOTION_LOGS_FIREBASE_REF) // Create adapter that extends FirebaseRecyclerAdapter class LogsAdapter(ref: DatabaseReference) : FirebaseRecyclerAdapter<FirebaseImageLog, LogsViewHolder>(FirebaseImageLog::class.java, R.layout.list_item_log, LogsViewHolder::class.java, ref) { //.. Do adapter things } // Set adapter to use reference adapter = LogsAdapter(databaseRef.orderByChild(ORDER_BY_TIMESTAMP).ref)
  90. None
  91. None
  92. None
  93. None
  94. Clear all Android Apps on device: https://gist.github.com/blundell/7c0c3bb17898b28fe8122b0dc230af50 Button Example :

    https://github.com/androidthings/sample-button Full MainActivity: https://gist.github.com/riggaroo/b4cad83be2f81d54fd854403af029b2d Github Project with Steps as branches: https://github.com/riggaroo/android-things-workshop-camera