Monitoring Wireless Sensors

Monitoring Wireless Sensors

In this post we’ll cover how to monitor inexpensive wireless security sensors. There are two types of wireless sensors that we’ll be working with, door reed switches and passive infra red motion detectors. Each of these sensors transmit a broadcast radio message on the 433Mhz frequency. We’ll be expanding on earlier work with RTL_433. This post will cover how to identify a specific sensor and take appropriate action as needed, all that with a single bash script, let’s begin.

The first thing will be the command to run the RTL_433 command. The path to the command is included in the bash script. CRON might be able to know the path, but it’s better to include it just in case. If the path isn’t known, type “whereis ” in a terminal window and it will display the path. RTL_433 will only need to monitor protocol 86 (“Wireless Smoke and Heat Detector GS 558”). The sensors we’ll be working with use this protocol exclusively, so we don’t need to bother detecting other devices. The output of the results will be formated in JSON, which contains all of the data on a single line. This will make it easier to parse and process the results. Since RTL_433 will be running in a loop condition, we want to interrupt it when a device is detected. Here is the command we’ll be using.

/usr/local/bin/rtl_433 -R 86 -F json:"$JsonOutput" -E

Since the above command is saving its output to a variable, we will define all of the variables at the beginning of the script.

DoorSensorEmail="/home/local/Tasks/DoorSensorEmail.txt"
JsonOutput="/home/local/Tasks/A_JsonOutput.txt"
Message="/home/local/Tasks/A_Message.txt"
MessageOutside="/home/local/Tasks/A_MessageOutside.txt"

PIRCounter="/home/local/Tasks/BasementPIRCounter.txt"
Counter=$(cat "$PIRCounter")

CactiHost='cacti.host.local'
Mate1FTPUser=''
Mate1FTPPass=''

This script will be called from CRON on bootup. I like to add a 2 minute delay before staring the rest of the script. This is done with this command.

sleep 120

After this period of time, the variables will be loaded into memory and our main loop function will begin by starting RTL_433. It will continue running RTL_433 until one of a sensor transmits. When data is decoded by RTL_433, that process will end and we will enter into a series of if else conditions.

The first condition will check if the JSON output contains the identifier for a door sensor. If it doesn’t, it will continue on with the next check of another identifier and so on. However, if the JSON output does contain the identifier then a series of commands will execute.

# Door Sensor ID = #####
if grep -q ##### "$JsonOutput" ; then
  echo "Door Sensor Tripped" > $Message
  # Process paths need to be included for CRON, use whereis "command" to find path.
  cat "$JsonOutput" | /usr/bin/logger -n syslog.host.local
  rm "$JsonOutput"
  # Process paths need to be included for CRON, use whereis "command" to find path.
  /usr/sbin/ssmtp admin@email.local < "$DoorSensorEmail" >/dev/null 2>&1

The above if condition will log the results to a syslog server named “syslog.host.local”. It then removes the JSON file for housekeeping. Finally, it sends an email notifying admin@email.local with a pre-formatted email message. Certain sensors merit immediate attention, while others can simply be logged to the syslog server.

In the next if condition, we’ll log the JSON result to our syslog server. In addition to that, we’ll also tally a counter of the occurrence of the event. This value will then be uploaded to a FTP host that runs Cacti. I won’t cover the configuration of Cacti here, see earlier posts for that. If you have a number, Cacti will graph it.

# PIR Sensor ID = #####
elif grep -q ##### "$JsonOutput" ; then
  echo "PIR Tripped" > $Message
  # Process paths need to be included for CRON, use whereis "command" to find path.
  cat "$JsonOutput" | /usr/bin/logger -n syslog.host.local
  Counter=$((Counter+1))
  echo "$Counter" > "$PIRCounter"

  echo "
  verbose
  open $CactiHost
  user $Mate1FTPUser $Mate1FTPPass
  cd Tasks
  bin
  put "$PIRCounter"
  bye
  " | ftp -n 

  rm "$JsonOutput"

The last condition we’ll check is a catch all. If none of our devices were found in earlier conditions, then some unknown device transmitted data. This condition will take action based on that. Since I covered email, syslog, and cacti, we could use any or all of these in this catch all condition. At the conclusion of this, we return to the start of our loop and run the RTL_433 command again.

Using a single bash script and some inexpensive hardware, we can monitor security sensors and take action based on their activity. Here is the complete code for the script, names have been changed to protect the innocent.

#!/bin/sh
# /home/local/Tasks/DoorSensor.sh
# Version 6.0 (12312018)
# Purpose - Run SDR scan of Door and PIR Sensors, log readings to Syslog / Cacti, and send email alert
# Author - Patrick Gilfeather - CloudACM


# Delay the start of the script for 2 minutes so system has time to boot
sleep 120

# Set variables for work files
DoorSensorEmail="/home/local/Tasks/DoorSensorEmail.txt"
JsonOutput="/home/local/Tasks/A_JsonOutput.txt"
Message="/home/local/Tasks/A_Message.txt"
MessageOutside="/home/local/Tasks/A_MessageOutside.txt"

PIRCounter="/home/local/Tasks/BasementPIRCounter.txt"
Counter=$(cat "$PIRCounter")

CactiHost='**********'
Mate1FTPUser='**********'
Mate1FTPPass='**********'


# Run the process in a loop endlessly
while :
do

# Run RTL_433 process to detect door sensor with SDR and capture results to a JSON formatted file.
# Process paths need to be included for CRON, use whereis "command" to find path.
/usr/local/bin/rtl_433 -R 86 -F json:"$JsonOutput" -E 

# Door Sensor ID = **********
if grep -q ********** "$JsonOutput" ; then
  echo "********** Sensor Tripped" > $Message
  # Process paths need to be included for CRON, use whereis "command" to find path.
  cat "$JsonOutput" | /usr/bin/logger -n **********
  rm "$JsonOutput"
  # Process paths need to be included for CRON, use whereis "command" to find path.
  /usr/sbin/ssmtp ********** < "$DoorSensorEmail" >/dev/null 2>&1

# Door Sensor ID = **********
elif grep -q ********** "$JsonOutput" ; then
  echo "********** Sensor Tripped" > $Message
  # Process paths need to be included for CRON, use whereis "command" to find path.
  cat "$JsonOutput" | /usr/bin/logger -n **********
  rm "$JsonOutput"

# PIR Sensor ID = **********
elif grep -q ********** "$JsonOutput" ; then
  echo "********** Sensor Tripped" > $Message
  # Process paths need to be included for CRON, use whereis "command" to find path.
  cat "$JsonOutput" | /usr/bin/logger -n **********
  Counter=$((Counter+1))
  echo "$Counter" > "$PIRCounter"

  echo "
  verbose
  open $CactiHost
  user $Mate1FTPUser $Mate1FTPPass
  cd Tasks
  bin
  put "$PIRCounter"
  bye
  " | ftp -n 

  rm "$JsonOutput"

# Undefined Sensor
else
  echo "Foreign Sensor Tripped" >> $MessageOutside
  rm "$JsonOutput"
fi

done

exit
Comments are closed.