Monday, October 8, 2018

Picture Frame - gets PIR and saves energy


My RPiPF is doing good. So now the goal is to shut down the TV when nobody is watching.

This was done. Many times. Even here.

A simple PIR (passive infrared) connected to Rpi pin can be monitored and when no motion is detected for some time the TV gets turned off. This saves energy and potentially extends the TV life span.

The problem with (most) PIRs

The PIR devices are contain two main components: the actual sensor that converts light into electric signals and a very high-gain amplifier. And here the problem begins. The sensor gives a very weak signal that need to be amplified so it can be detected. The amplifier however will happily amplify anything on its input, including any interference. And RPI being a decently strong EM signal  emitter (WiFi radio) when placed close to the sensor will cause unwanted tripping.

I have tried the $5 sensors that worked great in the past, both with arduino and other laptops-picture-frames. These worked great as there was no interference source nearby.

The aluminium foil shield did not work. Neither did attempt to decouple power supply with capacitors (apparently it is an inducted interference rather than a noise conducted via supply/ground lines).

However, I found this particular mini PIR sensor resilient to the interference. The cost being the sensitivity - it's detecting motion only in less then 3-4 meters away, while the other sensors were  double this.

Bash the code

The complete code (bash script) is on github here:
https://github.com/michkrom/pictureframe

The main parts to make PIR work are:

  • script to read the GPIO pin state: gpiord  
  • scripts to turn TV on and off
  • main controller script monitoring the PIR and deciding when to turn the TV on or off: pf.sh

Bit and nuts of the script:

Keep time: these two lines store current time int the form of number of seconds since 'epoh'. This is convenient when comparing them later.

lastmotion=`date +%s`
...
nowts=`date +%s`

Here we read the pin #18, it's either 0 or 1.

pinstate=`gpiord 18`

And here we observe detected motion ($pinstate equal 1) and note when this happened.

  if [ $pinstate -eq 1 ]; then
    lastmotion=$nowts
  fi   

Then compute how long it was since last time something moved


  let lastmotionage=$nowts-$lastmotion

Then decide to show or not (by extending existing schedule condition)

  if [ $lastmotionage -lt 600 ] && [ "$timeok" = true ]; then
    show=true

  fi

That's it.