Kid’s Eye and Energy Safe Smart and Green TV — Internet of Things

Abhijit Ghosh
5 min readJul 9, 2020

Sometimes I feel, kids do this just to irritate us. Or may be, we always have a prioritized list of problems in our subconscious mind. When we solve the top one, the next one pops up and gets highlighted. It is indeed never ending.

Few extra hours of running TV will hardly make any difference in monthly bill. But it bothers me a lot. Conservation of energy is really important to me. Especially when I know, I am not using renewable energy.

In my last project ( Kid’s Eye Safe Smart TV — Part 1), I was successful in addressing my topmost concern. Reinforcement learning worked very well for them. But nowadays, I am noticing that TV continues to run for hours without any viewers. No one bothers to switch off the TV before going outdoor or moving to another room to play. May be that’s why they are called Kids.

Let them be kids. Let’s do something to trade off with this situation.

Project Concept

This is enhancement of my last project ( Kid’s Eye Safe Smart TV — Part 1). I have added one more sensor called PIR motion sensor (HC-SR501).

Dual Technology Occupancy Sensor (Ultrasonic sensor & Motion sensor) yields a very responsive and reliable solution to detect occupancy. PIR sensor detects the change of infrared radiations emitted by the subject in motion in its field of view. Perfect for my project to detect audience in front of TV.

Circuit built using ESP32 will read Ultrasonic Distance Sensor (HC-SR04) and PIR Motion Sensor (HC-SR501). Based on that reading, Micropython logic will decide when to pause or resume or switch off the TV by calling smart TV API (e.g. in my case Roku TV API to toggle Play/Pause http://$ROKU_DEV_TARGET:8060/keypress/play).

In this PoC, if viewer goes very close (within preconfigured threshold — 1 meter) to the TV or no viewer (no motion) detected for certain period of time (say 15 seconds), TV will be paused ( switch off may be the preferable option in real life) automatically.

Tools,Technologies and Components used in this article

  1. Ultrasonic sensor HC-SR04 driver
  2. SSD1306 128x64 OLED display driver
  3. WiFi Manager
  • Hardware Components:
  1. ESP-WROOM-32 Dev Kit
  2. HC-SR04 Ultrasonic Sensor
  3. HC-SR501 PIR Motion Sensor
  4. OLED display 128x64 — Optional
  5. Breadboard
  6. 3.3v & 5v Breadboard Power Supply
  7. Breadboard Jumper Wires
  8. 1kΩ & 470Ω Resistors
  9. Less Smart TV (Roku)

Build the Circuit

Connect all the components as shown in the diagram below.

Schematic Diagram:

Note: In case if you are wondering, why I have used “H” pin (3.3v) instead of VCC (+5v), please refer the following nice hack — Cheap Pyroelectric Infrared PIR Motion Sensor on 3.3v.Circuit Design:


  1. Connect ESP32 development board to your computer.
  2. Open Thonny Python IDE.
  3. Select RunSelect interpreter…
  4. Choose MicroPython (ESP32) as device and corresponding port.

5. Upload following python libraries

6. Upload the below “” (pre-alpha version). For my Roku TV, Rest endpoint to simulate “Play/Pause” remote button is

import wifimgr
from hcsr04 import HCSR04
from machine import Pin,I2C
import ssd1306,time
import urequests
def init():
i2c = I2C(scl=Pin(19), sda=Pin(18))
oled = ssd1306.SSD1306_I2C(128, 64, i2c, 0x3c)
hcsr04 = HCSR04(trigger_pin=32, echo_pin=35, echo_timeout_us=1000000)
hcsr501Pin = Pin(26, Pin.IN)
hcsr501Pin.irq(trigger=Pin.IRQ_FALLING, handler=interruptCallbackHandler)
return oled, hcsr04def interruptCallbackHandler(p):
global motionDetected
motionDetected = True
global lastTimeMotionDetected
lastTimeMotionDetected = time.time()
print("$$$$Motion detected at %s" % lastTimeMotionDetected)
def log(msg, x, y):
oled.text(msg, x, y)
def clearDisplay():
def toggleTvPlayPause():
response ="")
print("API Response %s" % response.status_code)
return response.status_code == 200
print("Error !!!")
log("Error !!!", 0, 30)
return False
def anyoneWatching():
global motionDetected
if motionDetected:
# If no motion detected in next 15 secs
if ((time.time() - lastTimeMotionDetected) > 15):
motionDetected = False
print("Not Watching at %s" % time.time())
return False
print("Watching at %s" % time.time())
return True
print(">>>Not Watching at %s" % time.time())
return False
def play():
global isPaused
if isPaused and toggleTvPlayPause():
isPaused = False
def pause():
global isPaused
if not isPaused and toggleTvPlayPause():
isPaused = True
# Initialize OLED display, Distance & Motion sensor
oled, distanceSensor = init()
# Connect to WIfi
log("Connecting...", 0, 0)
wlan = wifimgr.get_connection()
if wlan is None:
log("No wifi !!!", 0, 20)
print("Unable to connect to Wifi")
log("Connected :-)", 0, 20)
print("Deactivated AP mode.")
time.sleep_ms(1000)prevDistance = -1
isPaused = False
motionDetected = True
lastTimeMotionDetected = time.time()
while True:
currDistance = int(distanceSensor.distance_cm())
if currDistance != prevDistance and motionDetected:
print("Distance: %s cm" % currDistance)
log("Dist: %s cm" % currDistance,0, 0)
prevDistance = currDistanceif anyoneWatching():
if currDistance < 100:
print("TV -> %s" % ("Pause" if isPaused else "Play"))
log("TV -> %s" % ("Pause" if isPaused else "Play"), 0, 30)
print("Motion -> %s" % ("Y" if motionDetected else "N"))
log("Motion -> %s" % ("Y" if motionDetected else "N"), 0, 40)

Use the following method to configure interrupt for a Pin Pin.irq(handler=None, trigger=(Pin.IRQ_FALLING | Pin.IRQ_RISING), \*, priority=1, wake=None, hard=False)

I have added lots of print statements to capture the flow in console log for better understanding of demo video. Try to minimize the use of print statements. Specifically for interruptCallbackHandler (External Interrupt Handler), DO NOT use anything extra. It has to be simple and short as much as possible. Please refer Tips and recommended practices for writing interrupt handlers.


Now, I am feeling responsible towards mother planet The Earth.

Circuit In Action

Video Demo:

Possible Extension

If you have pet, then you can include ESP32-CAM to detect the type of audience (pet or human) and use that input to drive the logic accordingly.

Download SrcCodes

All codes used in this post are available on Github: srccodes/smart-tv-occupancy-sensor.


Originally published at on July 9, 2020.



Abhijit Ghosh

A Joyful developer… :) Love to share learning experiences on different technologies/frameworks.