Skip to content

Instantly share code, notes, and snippets.

@JonTheNiceGuy
Last active October 20, 2024 00:11
Show Gist options
  • Save JonTheNiceGuy/294c5eadb3832c7bc6f90f472ca28242 to your computer and use it in GitHub Desktop.
Save JonTheNiceGuy/294c5eadb3832c7bc6f90f472ca28242 to your computer and use it in GitHub Desktop.
Use your Debian System as an iBeacon for Home Automation

Use your Debian System as an iBeacon for Home Automation

Introduction

I have been playing with using the https://Home-Assistant.io system at home to play with Home Automation.

One thing I've found is that the Raspberry Pi is perfect for quite a few of the monitoring things that I wanted it to do (see also https://github.com/JonTheNiceGuy/home-assistant-configs for more details of what I'm doing there!).

I'm using the http://OwnTracks.org application to talk to an MQTT server, but I could also do with it knowing where I am in the house, so I looked around for some details on iBeacons.

iBeacon is an Apple standard, but it's very easy to configure on Linux systems. I took some pointers from this article and wrote up this script. When I later went to deploy this on another system, I also needed a pointer from this PDF about getting at least a specific version of BlueZ.

Configuring the Script

When you first run it as root, it will pre-populate a config file in /etc/iBeacon.conf. Edit it and run the script again.

Running the script

This script needs to be run as root, so to test it, or to reconfigure the beacon, run sudo /root/iBeacon.sh (or wherever you put it!)

You may need to install Bluez 5 (I did on the Ubuntu Trusty for Joggler image I'm using at home) by running apt install software-properties-common && sudo add-apt-repository ppa:tigerite/bluez5 && sudo apt update && sudo apt install bluez

Making it persistent

To be honest, at this point, I'd probably just stick this into my root Crontab file by adding this line:

@reboot /root/iBeacon.sh | logger

Again, replace /root/iBeacon.sh with wherever you put it!

#! /bin/bash
# Based on http://www.wadewegner.com/2014/05/create-an-ibeacon-transmitter-with-the-raspberry-pi/
# This snip thanks to https://www.cyberciti.biz/tips/shell-root-user-check-script.html
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root" 1>&2
exit 1
fi
######################################################################################
## Read Config Or Die
######################################################################################
if [ -f /etc/iBeacon.conf ]; then
. /etc/iBeacon.conf
else
echo "An /etc/iBeacon.conf file has been created for you with the following values:"
echo "###################################"
echo "# Config File"
echo "###################################"
echo " "
echo "Beacon_Name=NameOfBeacon" > /etc/iBeacon.conf
echo " " >> /etc/iBeacon.conf
echo "# A UUID has been generated for you, using the following command. Feel free" >> /etc/iBeacon.conf
echo "# to replace this with your own value, or run it again for your own values." >> /etc/iBeacon.conf
echo "# " >> /etc/iBeacon.conf
echo "# python -c 'import sys,uuid;sys.stdout.write(uuid.uuid4().hex)'" >> /etc/iBeacon.conf
echo " " >> /etc/iBeacon.conf
echo "Beacon_UUID=`python -c 'import sys,uuid;sys.stdout.write(uuid.uuid4().hex)'`" >> /etc/iBeacon.conf
echo " " >> /etc/iBeacon.conf
echo "# Major and minor can be 0-65534, set as two octets (01-FF)" >> /etc/iBeacon.conf
echo "# 1 = 00 01" >> /etc/iBeacon.conf
echo "# 255 = 00 ff" >> /etc/iBeacon.conf
echo "# 256 = 01 00" >> /etc/iBeacon.conf
echo "# 65535 = ff ff" >> /etc/iBeacon.conf
echo " " >> /etc/iBeacon.conf
echo "# Major represents new \"site\" or building. The default value here is \"1\"" >> /etc/iBeacon.conf
echo "major0=00" >> /etc/iBeacon.conf
echo "major1=01" >> /etc/iBeacon.conf
echo "# Minor is a specific place in that site. Again the default value here is \"1\"" >> /etc/iBeacon.conf
echo "minor0=00" >> /etc/iBeacon.conf
echo "minor1=01" >> /etc/iBeacon.conf
echo " " >> /etc/iBeacon.conf
echo "# RSSI is what the power should be seen as by the receiver at 1m from transmitter" >> /etc/iBeacon.conf
echo "# However, this is more-or-less a magic number until calibrated, and I have found" >> /etc/iBeacon.conf
echo "# no concrete details on how to calculate this. Run your own tests! The Locate app" >> /etc/iBeacon.conf
echo "# from https://play.google.com/store/apps/details?id=com.radiusnetworks.locate" >> /etc/iBeacon.conf
echo "# has a calibration feature. The value found in the script this code was derived from" >> /etc/iBeacon.conf
echo "# specifies this value, and it appears accurate for my RPi3." >> /etc/iBeacon.conf
echo " " >> /etc/iBeacon.conf
echo "rssi=c8" >> /etc/iBeacon.conf
echo " " >> /etc/iBeacon.conf
echo "## If you want to publish a \"waypoints\" file, please populate the following values" >> /etc/iBeacon.conf
echo "# Your Location Lat/Long" >> /etc/iBeacon.conf
echo "latitude=0.000000" >> /etc/iBeacon.conf
echo "longditude=0.000000" >> /etc/iBeacon.conf
echo "# The radius that this beacon is considered to be valid for" >> /etc/iBeacon.conf
echo "radius=2" >> /etc/iBeacon.conf
echo "# The timestamp this file was *FIRST* published" >> /etc/iBeacon.conf
echo "timestamp=`date +%s`" >> /etc/iBeacon.conf
echo " " >> /etc/iBeacon.conf
echo "# Where to output the result of this" >> /etc/iBeacon.conf
echo "OutputForIPhone=0" >> /etc/iBeacon.conf
echo "OutputWaypointsFile=1" >> /etc/iBeacon.conf
echo "OutputWaypointsFilePath=`find / -name www_static 2>/dev/null`" >> /etc/iBeacon.conf
cat /etc/iBeacon.conf
echo " "
echo "###################################"
echo "# End Config File"
echo "###################################"
echo "Please edit this file (/etc/iBeacon.conf) and run this script again."
exit 1
fi
######################################################################################
## Convert config to usable values
######################################################################################
# Explode the uuid into component parts
# based losely on http://stackoverflow.com/a/23664252
if [[ $Beacon_UUID =~ (..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..) ]]; then
H0=${BASH_REMATCH[1]}
H1=${BASH_REMATCH[2]}
H2=${BASH_REMATCH[3]}
H3=${BASH_REMATCH[4]}
H4=${BASH_REMATCH[5]}
H5=${BASH_REMATCH[6]}
H6=${BASH_REMATCH[7]}
H7=${BASH_REMATCH[8]}
H8=${BASH_REMATCH[9]}
H9=${BASH_REMATCH[10]}
HA=${BASH_REMATCH[11]}
HB=${BASH_REMATCH[12]}
HC=${BASH_REMATCH[13]}
HD=${BASH_REMATCH[14]}
HE=${BASH_REMATCH[15]}
HF=${BASH_REMATCH[16]}
fi
######################################################################################
## Render for output later
######################################################################################
strUUID="${H0}${H1}${H2}${H3}-${H4}${H5}-${H6}${H7}-${H8}${H9}-${HA}${HB}${HC}${HD}${HE}${HF}"
# thanks to http://stackoverflow.com/a/22863296
strMajor=$((0x${major0}${major1}))
strMinor=$((0x${minor0}${minor1}))
strConfigUrl="owntracks:///beacon?name=${Beacon_Name}&uuid=${strUUID}&major=${strMajor}&minor=${strMinor}"
######################################################################################
## Configure the HCI device
######################################################################################
hciconfig hci0 up > /dev/null
hciconfig hci0 leadv3 > /dev/null 2> /dev/null
hciconfig hci0 noscan > /dev/null
hcitool -i hci0 cmd 0x08 0x0008 1E 02 01 1A 1A FF 4C 00 02 15 $H0 $H1 $H2 $H3 $H4 $H5 $H6 $H7 $H8 $H9 $HA $HB $HC $HD $HE $HF $major0 $major1 $minor0 $minor1 $rssi > /dev/null
######################################################################################
## Produce Output
######################################################################################
NOOUTPUT=true
# Report
if [ "$OutputForIPhone" == "1" ]; then
echo "$strConfigUrl"
NOOUTPUT=false
if which qrencode >/dev/null; then
# thanks to http://www.linux-magazine.com/Online/Features/Generating-QR-Codes-in-Linux
qrencode -t ANSI256 "$strConfigUrl"
fi
fi
if [ "$OutputWaypointFile" == "1" ]; then
NOOUTPUT=true
# THIS ISN'T DONE YET!!
#
# Save this blob as waypoint.otrw
# according to http://owntracks.org/booklet/tech/json/#_typewaypoints
#{
# "_type": "waypoints",
# "_creator": "OTwpDraw",
# "waypoints": [
# {
# "_type": "waypoint",
# "tst": epochtime,
# "lat": x.xx,
# "lon": y.yy,
# "rad": zzz,
# "desc": "desc",
# "uuid": "",
# "major": xx,
# "minor": xx
# }
# ]
#}
fi
if [ "$NOOUTPUT" == "true" ]; then
echo "Beacon Name : ${Beacon_Name}"
echo "Beacon UUID : ${strUUID}"
echo "Beacon Major: ${strMajor}"
echo "Beacon Minir: ${strMinor}"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment