The Zambretti Forecaster, an alternative weather forecast

If you want to try a different approach for a weather forecast than my simple weather forecast, based on the barometric pressure history, then you could use the so called Zambretti Forecaster. The Zambretti Forecaster is a weather forecasting tool in the form of a circular slide rule that was introduced by the company Negretti and Zambra in 1920. A more detailed description about the functionality of the Zambretti Forecaster and how to put it into code can be found here.

Below, you can find my Python implementation of the Zambretti Forecaster algorithm. It uses the current barometric pressure, the trend of the barometric pressure (over the last six hours) and the current month of the year as an input. The output of the Zambretti Forecaster is one of 26 different weather conditions. I mapped these weather conditions to a set of four forecast icons (sun, cloud, rain and thunderstorm), to make it more simple. The forecast icon is then shown together with an icon (arrow) that represents the current trend of the barometric pressure. Of course, you could also use more than these four icons, to make the forecast better if you want.

#!/usr/bin/python
 
import os
import shutil
import rrdtool
 
# Filtering the pressure change by using the average from different periods should give better, more stable results
# Read the pressure values for now/t=0, t=-0.5h, t=-1.0h, t=-1.5h, t=-2.0h, t=-2.5h, t=-3.0h, t=-3.5h, t=-4.0h, t=-4.5h, t=-5.0h, t=-5.5h and t=-6.0h
press0 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 600', '-s -600')
press1 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -1800', '-e -1800')
press2 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -3600', '-e -3600')
press3 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -5400', '-e -5400')
press4 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -7200', '-e -7200')
press5 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -9000', '-e -9000')
press6 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -10800', '-e -10800')
press7 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -12600', '-e -12600')
press8 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -14400', '-e -14400')
press9 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -16200', '-e -16200')
press10 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -18000', '-e -18000')
press11 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -19800', '-e -19800')
press12 = rrdtool.fetch("./../pressure_info/pressure.rrd", 'AVERAGE', '-r 60', '-s -21600', '-e -21600')

# Calculate the single differences and normalize them to a change in pressure over 1h
pressurerdiff1 = (press0[2][0][1] - press1[2][0][1])*2
pressurerdiff2 = (press0[2][0][1] - press2[2][0][1])
pressurerdiff3 = (press0[2][0][1] - press3[2][0][1])/1.5
pressurerdiff4 = (press0[2][0][1] - press4[2][0][1])/2
pressurerdiff5 = (press0[2][0][1] - press5[2][0][1])/2.5
pressurerdiff6 = (press0[2][0][1] - press6[2][0][1])/3
pressurerdiff7 = (press0[2][0][1] - press7[2][0][1])/3.5
pressurerdiff8 = (press0[2][0][1] - press8[2][0][1])/4
pressurerdiff9 = (press0[2][0][1] - press9[2][0][1])/4.5
pressurerdiff10 = (press0[2][0][1] - press10[2][0][1])/5
pressurerdiff11 = (press0[2][0][1] - press11[2][0][1])/5.5
pressurerdiff12 = (press0[2][0][1] - press12[2][0][1])/6

# Calculate the average of the differences
pressurerdiff = (pressurerdiff1 + pressurerdiff2 + pressurerdiff3 + pressurerdiff4 + pressurerdiff5 + pressurerdiff6 + pressurerdiff7 + pressurerdiff8 + pressurerdiff9 + pressurerdiff10 + pressurerdiff11 + pressurerdiff12)/12

# Get the current pressure
currentpress = press0[2][0][1]

# Calculate the trend
if pressurerdiff < -0.25:
    trend = -1
elif pressurerdiff >= -0.25 and pressurerdiff <= 0.25:
    trend = 0
elif pressurerdiff > 0.25:
    trend = 1

# Get the current month
today = datetime.date.today()
date = datetime.datetime.strptime(str(today), "%Y-%m-%d")
month = int(date.month)

# Use the Zambretti-algorithm to finally make the forecast
# --------------------------------------------------------
# Falling Conditions
# ------------------
if trend == -1:
    shutil.copyfile('/home/pi/pressure_info/DownRight.png', '/var/www/html/Arrow.png')
    zambretti = 0.0009746*currentpress*currentpress-2.1068*currentpress+1138.7019
    if month < 4 | month > 9:
        zambretti = zambretti + 1
    zambretti = int(round(zambretti))
    if zambretti == 1:
        forecast = 'Settled Fine'
        shutil.copyfile('/home/pi/pressure_info/Sun.png', '/var/www/html/Forecast.png')
    elif zambretti == 2:
        forecast = 'Fine Weather'
        shutil.copyfile('/home/pi/pressure_info/Sun.png', '/var/www/html/Forecast.png')
    elif zambretti == 3:
        forecast = 'Fine Becoming Less Settled'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 4:
        forecast = 'Fairly Fine Showers Later'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 5:
        forecast = 'Showery Becoming unsettled'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 6:
        forecast = 'Unsettled, Rain later'
        shutil.copyfile('/home/pi/pressure_info/Rain.png', '/var/www/html/Forecast.png')
    elif zambretti == 7:
        forecast = 'Rain at times, worse later'
        shutil.copyfile('/home/pi/pressure_info/Rain.png', '/var/www/html/Forecast.png')
    elif zambretti == 8:
        forecast = 'Rain at times, becoming very unsettled'
        shutil.copyfile('/home/pi/pressure_info/Rain.png', '/var/www/html/Forecast.png')
    elif zambretti == 9:
        forecast = 'Very Unsettled, Rain'
        shutil.copyfile('/home/pi/pressure_info/Rain.png', '/var/www/html/Forecast.png')
# Steady Conditions
# -----------------
elif trend == 0:
    shutil.copyfile('/home/pi/pressure_info/Right.png', '/var/www/html/Arrow.png')
    zambretti = 138.24-0.133*currentpress
    zambretti = int(round(zambretti))
    if zambretti == 1:
        forecast = 'Settled Fine'
        shutil.copyfile('/home/pi/pressure_info/Sun.png', '/var/www/html/Forecast.png')
    elif zambretti == 2:
        forecast = 'Fine Weather'
        shutil.copyfile('/home/pi/pressure_info/Sun.png', '/var/www/html/Forecast.png')
    elif zambretti == 3:
        forecast = 'Fine, Possibly showers'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 4:
        forecast = 'Fairly Fine, Showers likely'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 5:
        forecast = 'Showery Bright Intervals'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 6:
        forecast = 'Changeable some rain'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 7:
        forecast = 'Unsettled, rain at times'
        shutil.copyfile('/home/pi/pressure_info/Rain.png', '/var/www/html/Forecast.png')
    elif zambretti == 8:
        forecast = 'Rain at Frequent Intervals'
        shutil.copyfile('/home/pi/pressure_info/Rain.png', '/var/www/html/Forecast.png')
    elif zambretti == 9:
        forecast = 'Very Unsettled, Rain'
        shutil.copyfile('/home/pi/pressure_info/Rain.png', '/var/www/html/Forecast.png')
    elif zambretti == 10:
        forecast = 'Stormy, much rain'
        shutil.copyfile('/home/pi/pressure_info/Storm.png', '/var/www/html/Forecast.png')
# Rising Conditions
# -----------------
elif trend == 1:
    shutil.copyfile('/home/pi/pressure_info/UpRight.png', '/var/www/html/Arrow.png')
    zambretti = 142.57-0.1376*currentpress
    if month < 4 | month > 9:
        zambretti = zambretti + 1
    zambretti = int(round(zambretti))
    if zambretti == 1:
        forecast = 'Settled Fine'
        shutil.copyfile('/home/pi/pressure_info/Sun.png', '/var/www/html/Forecast.png')
    elif zambretti == 2:
        forecast = 'Fine Weather'
        shutil.copyfile('/home/pi/pressure_info/Sun.png', '/var/www/html/Forecast.png')
    elif zambretti == 3:
        forecast = 'Becoming Fine'
        shutil.copyfile('/home/pi/pressure_info/Sun.png', '/var/www/html/Forecast.png')
    elif zambretti == 4:
        forecast = 'Fairly Fine, Improving'
        shutil.copyfile('/home/pi/pressure_info/Sun.png', '/var/www/html/Forecast.png')
    elif zambretti == 5:
        forecast = 'Fairly Fine, Possibly showers, early'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 6:
        forecast = 'Showery Early, Improving'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 7:
        forecast = 'Changeable, Improving'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 8:
        forecast = 'Rather Unsettled Clearing Later'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 9:
        forecast = 'Unsettled, Probably Improving'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 10:
        forecast = 'Unsettled, short fine Intervals'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 11:
        forecast = 'Very Unsettled, Finer at times'
        shutil.copyfile('/home/pi/pressure_info/SunCloud.png', '/var/www/html/Forecast.png')
    elif zambretti == 12:
        forecast = 'Stormy, possibly improving'
        shutil.copyfile('/home/pi/pressure_info/Storm.png', '/var/www/html/Forecast.png')
    elif zambretti == 13:
        shutil.copyfile('/home/pi/pressure_info/Storm.png', '/var/www/html/Forecast.png')
        forecast = 'Stormy, much rain'

 

Moving from Weather Underground to OpenWeatherMap

Since Weather Underground has announced the End of Service for their API by the end of 2018, I stopped uploading data from my weather station to Weather Underground and started to look for an alternative API in order to still being able to display the current weather conditions on my Pimoroni Scroll pHAT HD display and the current air pressure on my GUI for rtl_433, along with the received temperature and humidity.

With OpenWeatherMap, I found a good substitute for that. They also provide an API that can be used for free for a limited amount of calls. For the average hobbyist, the limitations of the API does not matter. Like for Weather Underground in the past, you also have to get an API-Key, before you will be able to use the API.

In the following picture, you can see a small Windows program (similar to my rtl_433-GUI) that I wrote for learning about the OpenWeatherMap-API. It displays the name of the city where the data is coming from, an icon that represents the current weather conditions and the values for temperature, humidity and air pressure. A complete description of the weather conditions and the weather icons used by OpenweatherMap can be found here.

Wetterstation_OWM

I will leave all the Weather Underground related articles here unchanged for reference, but additionally, I will provide a working example on how to use the Openweathermap-API in this article, so that you will be able to adapt the code that uses the Weather Underground-API, to now use the OpenWeatherMap-API.

Using the OpenWeatherMap-API is straightforward and very similar to using the one from Weather Underground. Anyway, there is one thing that I’ve noticed when testing the API. It sometimes delivers the air pressure using one of two different ways. I pay attention to this in my example code so that it should work, either if the API delivers the normalized pressure at sea level via ‘pressure’, or via ‘sea_level’. Below, you can see the code that I use within the program that I’ve shown above. Only thing you have to do before you can use the code, is to replace YOURCITYID with the id of the city you want to get the data for and YOURAPPID with your personal API-Key. How to determine the City-Id is described here.

import requests
import json

try:
    OWM_str = 'http://api.openweathermap.org/data/2.5/weather?id=YOURCITYID&appid=YOURAPPID'
    response = requests.get(OWM_str)
    x = response.json() 

    if x['cod'] != '404':
        y = x['main']
        temp = y['temp']
        temp_float = float(temp)
        temp_float = temp_float-273.15
        temp_float = round(temp_float, 1)
        temp = str(temp_float)
        humi = y['humidity']
        temp_humi = float(humi)
        temp_humi = round(temp_humi, 1)
        humi = str(temp_humi)
        if 'sea_level' not in y:
            press = y['pressure']
            press_float = float(press)
            press_float = round(press_float, 1)
            press = str(press_float)
        else:
            press = y['sea_level']
            press_float = float(press)
            press_float = round(press_float, 1)
            press = str(press_float)
        z = x['weather']
        icon = z[0]['icon']
        icon = icon + '.png'
        city = x['name']
    else:
        temp = "--.-"
        humi = "--.-"
        press = '---.-'
        icon = '-'
        city = '-'
except:
    temp = "--.-"
    humi = "--.-"
    press = "---.-"
    icon = '-'
    city = '-'

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.

Finding an UPS for the Raspberry Pi

Even if the infrastructure in Germany is very good, occasional power outages for a few seconds, or even for minutes can happen once or twice a year. Every time this happens, I feel really afraid for my Raspberry Pi. Although, up to now, it was never a real problem and the Raspberry Pi just booted fine after the power came back, the uneasy feeling remains.

After the last power outage that lasted for about 15 minutes, I started to look for a way to keep my Raspberry Pi running during a power outage. If you search the Internet for an UPS for the Raspberry Pi, you basically will find three different solutions  for it.

A ‘real’ UPS with a built in lead acid battery

Solutions including a backup battery that connect to the Pi’s HAT

A power bank that can be charged and discharged at the same time

But all of these solutions have at least one big disadvantage that makes it unusable for me. A big UPS which is normally used for desktop PCs would be an overkill. It is just to big and expensive and also uses usually at least 10W during standby.

Also, I want to continue using the original case and don’t want to connect anything big to the Raspberry Pi directly, so this also excludes the second solution.  A software that shuts down the Raspberry Pi, if a power outage is detected is also unnecessary for my purpose. For me, it is only important to keep it running independently for as long as possible.

What I don’t like about the idea with the power bank is, that it is hard to find a power bank that can be charged and discharged at the same time and also, the power bank is not really designed in the way a UPS should work. I would rather have a battery that is constantly kept full than a battery that is charged and discharged all the time.

Finally, I found the PowerWalker DC SecureAdapter 12V. A small and lightweight DC UPS, especially designed for routers, security cameras and similar devices. This power supply contains a rechargeable 18650 Li-Ion battery as a backup. Only downside is that it outputs 12V and the Raspberry Pi needs 5V. So, one more step is necessary, if you want to use this nice little UPS together with your Raspberry Pi, you have to convert the output voltage. For that, I use a 15W DC-DC converter that can output 5V/3A maximum, just like the original Raspberry Pi power supply can do. You can find various DC/DC converters all around on Amazon, eBay, AliExpress and so on. Luckily, there are ones available that directly have a Micro USB connector on the output, so all you have to do is to connect the output of the UPS with the input of the DC/DC converter. For that, I use an adapter that has a screw terminal on one side and a 5.5mm/2.5mm DC socket on the other side, so finally not even soldering was required for putting it all together.

Below, you can see everything connected together and also a table from the box of the PowerWalker DC SecureAdapter that gives you an idea about the approximate backup times. If you assume that the DC/DC converter has an efficiency of about 90%, the Raspberry Pi  can run about 150 minutes with a power consumption of 10.8W (2.16A)!

USV

Another advantage of the PowerWalker DC SecureAdapter is, that the rechargeable 18650 Li-Ion battery is a very common rechargeable battery which can easily be found, and that it can be replaced on your own.

Although, there is always one voltage conversion more present than it would ideally need (230V to 12V to 5V, instead of 230V to 5V and 3.7V to 12V to 5V, instead of 3.7V to 5V), I think this solution is the closest one to what the perfect solution for me would be at the moment. Maybe some day, there will be a device like the PowerWalker DC SecureAdapter available that directly outputs 5V…

 

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" =&gt; 1,

"bin-environment" =&gt; (

&nbsp;&nbsp;&nbsp; "PHP_FCGI_CHILDREN" =&gt; "4",

&nbsp;&nbsp;&nbsp; "PHP_FCGI_MAX_REQUESTS" =&gt; "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" =&gt; 3,

"bin-environment" =&gt; (

&nbsp;&nbsp;&nbsp; "PHP_FCGI_CHILDREN" =&gt; "4",

&nbsp;&nbsp;&nbsp; "PHP_FCGI_MAX_REQUESTS" =&gt; "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.

Using the Steak Champ thermometer to make the perfect steak

If you like to make yourself a good steak every now and then, just like I do, you can go and take a Raspberry Pi and build yourself a full option steak thermometer that has eight temperature sensors, a touchscreen, a web server, Email notification and a fan cotroller for your barbecue, or instead, you can go and buy a steak thermometer that looks a bit simpler, but also has a lot of high-tech inside. 😉

Steak01

In the past, I used to use the ‘Perfect Steaks and Roasts’ app when frying a steak. Using this app works well, if your steak keeps it’s size during frying, but if it raises while you are frying it (some haunch steaks e.g. just like to do), the recommended frying time from the app will get totally useless. To avoid this problem, you have to look for a more sophisticated tool that helps you to get the best result.

In general, using a thermometer and monitoring the core temperature of the meat is a good and well-known idea. But of course, it does not have to be an ordinary thermometer, it has to be a high-tech one like the Steak Champ steak thermometer. 🙂 This thermometer does not have a normal display/gauge to show you the temperature, it has a multi-color LED that shows you the degree of the doneness of the steak. After activating the thermometer, the LED slowly flashes in green color. If it reaches ‘medium rare’, it starts to rapidly flash in green color. Same for ‘medium’ (yellow) and ‘medium well’ (red). If your desired degree of the donenes is reached, you have to get the steak out of the pan (or barbecue) and give it a rest until the rapid flashing of the LED stops. Then the making of the steak has finished and it’s ready to eat.

The battery inside the thermometer is promised to last for about 1000 steaks, then the thermometer will get useless. Changing the battery is not possible. If this is true, the price for the thermometer (about 45€) is quite OK. This, time will tell. But for now, it’s time for a test…

A dry-aged steak from the local butcher:

Steak02

Ready to be fried:

Steak03

Time to turn it around:

Steak04

It says ‘medium’, so give it a little rest and a portion of good steak pepper:

Steak05

Yummy! 😀

Steak06

Getting the stats out of Pi-Hole

If you want to be informed about your Pi-Hole statistics, but don’t want to visit the Pi-Hole dashboard all the time, then there is also an alternative way to get the statistics out of Pi-Hole, and use the numbers to present it in any other way that meets your demands. This could be e.g. showing it on a display (like the Scroll pHAT HD), uploading it to ThingSpeak, or whatever else you can think of.

Pi-Hole already provides you the opportunity to make a request for getting some statistic data right out of the box.  You just have to put the following line in the address bar of your browser and replace IPOFYOURPIRUNNINGPIHOLE with the IP address of your Raspberry Pi, on which Pi-Hole is running, and you will get a list with various numbers and the description for them.

http://IPOFYOURPIRUNNINGPIHOLE/admin/api.php

The result is given to you in the JSON data format and can easily be processed with Python, just like shown in previous scripts here in the blog before.

PiHoleStats

The following small Python script gets the data, extracts some interesting information,  formats it, and then outputs the final text on the command line.

#!/usr/bin/env python

import json
import urllib2

try:
    f = urllib2.urlopen('http://IPOFYOURPIRUNNINGPIHOLE/admin/api.php')
    json_string = f.read()
    parsed_json = json.loads(json_string)
    queries = parsed_json['dns_queries_today']
    adsblocked = parsed_json['ads_blocked_today']
    clients = parsed_json['unique_clients']
    f.close()
except:
    queries = '-'
    adsblocked = '-'
    clients = '-'

pihole = 'DNS-Queries: ' + str(queries) + ' - ' + 'Ads blocked: ' + str(adsblocked) + ' - ' + 'Devices: ' + str(clients)
print pihole