Turning your Raspberry Pi (3 or Zero W) into a Bluetooth beacon

The idea behind a Bluetooth beacon is that things around you are allowed to interact with you in a certain way.  For example, they can give you the address of a website or provide information by using a special app that you have installed for that particular purpose.

In this article, I want to focus on the possibility of broadcasting the URL of a website, since this is a very easy and universal way to provide location based information to someone. My aim for using a Bluetooth beacon at my home was to broadcast the URL of the Weather Underground page of my weather station, using the Eddystone URL format by Google, so that others around can easily access these information with the help of their Android smartphones.

Although, Bluetooth beacons may not be very poplar in daily life up to now, the idea behind it is very fascinating and since it is very easy to create one with a Rasberry Pi (3 or Zero W), it is well worth doing.

There is already a very good description over here, of how to use a Raspberry Pi 3 as an Eddystone URL beacon.  All in all, there are just three easy steps necessary:

1. Enableing the Bluetooth device

2. Setting the Bluetooth device to “advertise and not-connectable”

3. Entering the Beacon Advertising Data

The third step includes encoding the URL which is the most difficult part, but luckily, there is already an Eddystone URL command calculator online available who does the encoding for you.

It is to mention that the lenght of the URL within the broadcast frame is limited, which means that, if you want to broadcast a longer URL, you have to use a service that shortens the URL for you. I am using https://goo.gl for that. Actually, I recommend to do that, even if the URL you want to broadcast fits into the Eddystone broadcast message, because you will be able to see the number of clicks within the statistics of the Google URL Shortener service, which is really nice. The commands for all three steps together are shown below (using some example URL).

sudo hciconfig hci0 up
sudo hciconfig hci0 leadv 3
sudo hcitool -i hci0 cmd 0x08 0x0008 17 02 01 06 03 03 aa fe 0f 16 aa fe 10 00 03 77 65 62 67 61 7a 65 72 08 00 00 00 00 00 00 00 00

This is already enough to turn your Raspberry Pi into a bluetooth beacon. After executing the commands, you should see a notification on your Android Smartphone, if Bluetooth is turned on. Normally, the notifications for Nearby are turned on by default. If you don’t see a notification, you should go to the Google settings and check the Nearby configuration.

Nearby

Even if your Bluetooth beacon is alredy working and broadcasting the URL correctely now, there is one more additional thing that you should do. The Eddystone format also transmits the TX power (the value between 10 and 03), so that a receiver can use that information to determine the distance to the beacon. For making that work correctely, you have to make a calibration, which simply means that you have to adjust the value for TX power within the Eddystone message. I have done that with the help of the APP Beacon Scanner. The rule for calibration is that you measure The TX power of the beacon at a distance of 1m (using Beacon Scanner), add 41 dBm and then use the result as the value for TX power. For me, that gave a good starting point for the calibration, but I had to play around a bit more with the value for TX power, so that the real distance to the beacon and the one shown by Beacon Scanner were a good match.

scanner

If you want to start the beacon automatically when you power up your Raspberry Pi, you can easily create a script with the three command lines and put it in the crontab with @reboot. But you have to take in account that Bluetooth may not available when the script is executed, so a delay (sleep command) at the beginning of the script  is necessary to make the beacon work. I use a delay of ten seconds for that, which works just fine.

With the help of your new Raspberry Pi Bluetooth beacon, you can now just tell your visitors to check the notifications of their Android Smartphone and to follow the link (bad luck for iPhone users 😉 ), if they are curious about the current weather condition details at your home location.

Solving Lighttpd hang issues

Although, everything was running fine on my Raspberry Pi 3, there was one thing that bothered me and took me quite a while to find a solution for it. Every now and then, Lighttpd started to hang for many seconds. After just waiting, or impatiently restarting Lighttpd, everything worked fine again for some time. Unnecessary to say that this situation was not very pleasing and a solution had to be found.

After looking around the internet, I got the strong feeling that the FastCGI configuration is causing the problem. In particular, PHP_FCGI_MAX_REQUESTS seems to be the one to blame.

I have PHP7 on my Raspberry Pi 3 and the parameters we are looking for are accessible with the following commands (including a backup of the original configuration). This can vary, depending on which version of PHP you are using.


cd /etc/lighttpd/conf-available/

sudo cp 15-fastcgi-php.conf 15-fastcgi-php.conf.bak

sudo nano 15-fastcgi-php.conf

Within the configuration, the following part is of special interest for us. This was what my default installation looked like.


...

"max-procs" => 1,

"bin-environment" => (

    "PHP_FCGI_CHILDREN" => "4",

    "PHP_FCGI_MAX_REQUESTS" => "10000"

...

I changed the values for max-procs and PHP_FCGI_MAX_REQUESTS like shown below. For more detailed information about the function of the parameters, you should read the article Optimizing FastCGI performance.


...

"max-procs" => 3,

"bin-environment" => (

    "PHP_FCGI_CHILDREN" => "4",

    "PHP_FCGI_MAX_REQUESTS" => "500"

...

After changing the values, you have to restart Lighttpd, so that the changes will take effect.


sudo /etc/init.d/lighttpd restart

Right after restarting the web server, you can see the RAM consumption of the system increasing, due to the increase of max-procs. I am not 100% sure, if the values that I have chosen are the best ones for the Raspberry Pi 3, but up to now, Lighttpd is running just fine, without any hangs, delays or hiccups and the RAM consumption also seems to be fine.

Overview of my weather station website

The website of my weather station includes contents from most of the articles here in the blog, so I finally want to give you an overview, of how the website that I mentioned several times before looks like.

Because I included all the information on one single page, I put a navigation bar at the top of the page. If you click on one of the links, the page scrolls automatically to the correspondent area. By clicking on one of the graphs, you will get back to the top of the page, so that there is actually no excessively scrolling necessary, despite the fact that the page is actually rather long. If you stay on the website for a longer period of time, it will automatically reload itself after five minutes, so that it always shows you the latest values.

website

PHP scripts for your Raspberry Pi weather station

On the website of my Raspberry Pi weathers station, I show various graphs that illustrate the development of different weather and also system values. But there are also a few other interesting information to include that don’t need graphs.

Besides general information, like the current date and time, I also wanted to display the overall run time of the system, the current clock speed, the installed Kernel version, and the number of currently running processes. To get all of these information, I am using small PHP scripts.  Below, you can see the representation of these information, followed by the sources of the used scripts.

system

Current time and date:

<?php
	date_default_timezone_set("Europe/Berlin");
	setlocale(LC_TIME, "de_DE.utf8");
	$timestamp = time();
	$datum = date("d.m.Y",$timestamp);
	$uhrzeit = date("H:i",$timestamp);
	echo strftime("%A, ");
	echo $datum," – ",$uhrzeit," Uhr";
?>

Uptime:

<?php
	$ut = strtok(@exec("cat /proc/uptime"), ".");
	$days = sprintf("%2d", ($ut / (3600 * 24)));
	$hours = sprintf("%2d", (($ut % (3600 * 24))) / 3600);
	$min = sprintf("%2d", ($ut % (3600 * 24) % 3600) / 60);
	$sec = sprintf("%2d", ($ut % (3600 * 24) % 3600) % 60); 
	$uptime = array($days, $hours, $min, $sec); 

	echo ("Laufzeit: ");
	
	if ($uptime[0] == 1) {  
							echo ($uptime[0] . " Tag, "); 
						 }
	else {  
			echo ($uptime[0] . " Tage, "); 
		 }
		
	if ($uptime[1] == 1) {
							echo ($uptime[1] . " Stunde und ");
						 }
	else {  
			echo ($uptime[1] . " Stunden und "); 
		 }
	
	if ($uptime[2] == 1) {
							echo ($uptime[2] . " Minute");
						 }
	else {  
			echo ($uptime[2] . " Minuten"); 
		 }					 
?>

Clock, Kernel version and number of processes:

<?php
	$freq = @exec("echo $(($(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq)/1000))");
	$proc = @exec("ps aux | wc -l");
	$vers = @exec("uname -r");
	
	echo ("Taktfrequenz: " . $freq . " MHz &nbsp;•&nbsp; Kernel Version: " . $vers . " &nbsp;•&nbsp; Prozesse: " . $proc ); 
?>

Just like for the system information, there are also a few weather and environment related information that do not need to use graphs, e.g the before described warning status of the lightning detector, the air quality, and the weather forecast. Furthermore, the current season, the times for sunrise and sunset and the lunar phase would be a useful addition on the weather station website. To calculate these times and states, of course, you can use PHP scripts again. To get the sunrise and sunset times of your desired location, you just have to adapt the coordinates in the scripts. When you are using the scripts for season and lunar phase, you can directly use the resulting string (followed by the file extension) to load an icon of the same name.

Version 1:

Hechingen

Version2 :

Benningen

Lunar phase:

<?php
function mondphase()
{
	date_default_timezone_set("Europe/Berlin");
	$timestamp = time();
	$day = date("j",$timestamp);
	$month = date("n",$timestamp);
	$year = date("Y",$timestamp);
		
	$c = $e = $jd = $b = 0;
	if ($month < 3)
	{
		$year = $year - 1;
		$month = $month + 12;
	}
	$month = $month + 1;
	$c = 365.25 * $year;
	$e = 30.6 * $month;
	$jd = $c + $e + $day - 694039.09;
	$jd = $jd / 29.5305882;
	$b = (int) $jd;
	$jd = $jd - $b;
	$b = round($jd * 8);
	if ($b >= 8 )
	{
		$b = 0;
	}
	
	switch ($b)
	{
		case 0:
			return 'NewMoon';
			break;
		case 1:
			return 'WaxingCrescent';
			break;
		case 2:
			return 'FirstQuarter';
			break;
		case 3:
			return 'WaxingGibbous';
			break;
		case 4:
			return 'FullMoon';
			break;
		case 5:
			return 'WaningGibbous';
			break;
		case 6:
			return 'ThirdQuarter';
			break;
		case 7:
			return 'WaningCrescent';
			break;
		default:
			return 'Unknown';
	}
}
?>

Current season:

<?php 
function season($theday) {
	if($theday >= "79" && $theday <= "171") {
	$season = "Spring";
	} elseif($theday >= "172" && $theday <= "264") {
	$season = "Summer";
	} elseif($theday >= "265" && $theday <= "355") {
	$season = "Autumn";
	} else {
	$season = "Winter";
	}
	   return $season;
}
?>

Sunrise time:

<?php
	$zenith = 90+50/60; 
	echo date_sunrise(time(), SUNFUNCS_RET_STRING,
	49.xx, 9.xx, $zenith, date("O")/100) . " Uhr"; 
?>

Sunset time:

<?php
	$zenith = 90+50/60;
	echo date_sunset(time(), SUNFUNCS_RET_STRING,
	49.xx, 9.xx, $zenith, date("O")/100) . " Uhr";
?>

Getting various Linux system information

There are already countless tools and scripts out there to gather and display Linux system information, but there are also numerous reasons why you may want to do this on your own. For example, you don’t like the way it is displayed, the time between the measurements is to short or to long for you, or something that you really need is simply missing or even wrong.

For me, the main reason to do it on my own was, because I want to display the system information together with the data from my weather station, for which I already use RRDtool graphs, and I want all the graphs to have the same appearance.

Below are some little scripts with which you are able to get the most interesting information about your system in a format that allows you to display it, or to store it in a database for further usage.

Overall CPU load of all four cores of the Raspberry Pi:

# Read the current CPU load
CPULOAD=`top -bn 1 | awk 'NR>7{s+=$9} END {print s/4}'`

cpuload

CPU temperature:

# Read the current CPU temperature and format it (e.g.: 59234 to 59.234)
TEMPERATURE=`cat /sys/class/thermal/thermal_zone0/temp`
TEMPERATURE=`echo -n ${TEMPERATURE:0:2}; echo -n .; echo -n ${TEMPERATURE:2}`

cputemp

RAM usage:

# Read the current RAM usage
RAMTOTAL=`free | grep Mem | awk '{print $2}'`
RAMUSED=`free | grep buffers/cache | awk '{print $3}'`
RAM=$(awk "BEGIN {print int($RAMUSED/$RAMTOTAL*100)}")

ramusage

Throughput of the microSD card:

# Read the current values from the diskstats and convert it to kB/s
READ=$(cat /proc/diskstats | grep 'mmcblk0 ' | awk '{print $6}')
READ=$(($READ/2))
READ=`echo $READ`
WRITE=$(cat /proc/diskstats | grep 'mmcblk0 ' | awk '{print $10}')
WRITE=$(($WRITE/2))
WRITE=`echo $WRITE`

card

Network throughput:

# Read the current values from ifconfig and convert it to kB/s
RECEIVED=$(grep wlan0 /proc/net/dev | awk '{print $2}')
RECEIVED=$(($RECEIVED/1024))
RECEIVED=`echo $RECEIVED`
SENT=$(grep wlan0 /proc/net/dev | awk '{print $10}')
SENT=$(($SENT/1024))
SENT=`echo $SENT`

traffic

WI-Fi information:

# Read the current WI-FI information
QUALITY=$(/sbin/iwconfig wlan0 | /bin/sed -n "s/.*Link Quality=\([0-9]*\).*/\1/p")
LEVEL=$(/sbin/iwconfig wlan0 | /bin/sed -n "s/.*Signal level=\([0-9]*\).*/\1/p")

wifiinfo