IP Anemometer


The latest version is available on the download page.


This article describes a wind speed measurement device – or anemometer, for short – built with the Raspberry Pi. A wind sensor is connected to the GPIO interface. The Pi collects measurements and uploads them to a web server, which stores them in a MySQL database.


The server shows wind speed over time, average, maximum and a histogram. Here’s a live example for the last 90 minutes (see the Wind @ GMC page for more charts). If this shows “no data available”, the system is currently down; select a known good date in the past, e.g. 2020-12-24.


Additional sensors can be used to measure temperature, humidity and voltage levels:

All the software is provided and free. Installation requires a little bit of familiarity with Linux and web servers. I’m happy to help if you get stuck :-) The hardware part is very simple and doesn’t even require soldering. The only complex step is wind sensor calibration, for which you’ll need a reference anemometer. Calibration is not needed if you get the exact same sensor that I use myself (which is available from Amazon Germany).

In my case the Pi is located at our RC model flying field, which is at a somewhat remote location (solar power, internet via 3G USB stick). Rain and temperature are easy to tell from the usual weather apps, but wind speed is very local and even specialized apps like Windfinder are often way off. The Pi, however, measures wind speed pretty accurately at exactly the spot I care about. So I can reliably tell if the weather is good for flying and what planes I should bring (some planes handle wind better than others).

For the RC airfiled use case the software includes some simple extra features:

  • Detect “shed door open” to see if anyone is there.
  • Count number of pilots by means of manual “punch in”/”punch out” buttons. This allows to display if/how many people are currently flying.


The project has the following software components:

  • Client code on the Pi (Python)
  • Server code (PHP 5.3+ and MySQL)
  • Two display options:

These hardware components are needed:

  • Raspberry Pi
  • Wind sensor
    • I use an Eltako from amazon.de. It is accurate and reliable, and can be used out of the box.
    • For other sensors the software must be calibrated, which requires a reference anemometer and a fan or some other device to generate constant wind.
  • Cable to connect the sensor to the GPIO pins (male to female, like this)
  • Optional:
    • DHT22/AM2302 sensor for temperature and humidity (can be connected directly, no additional components needed).
    • MCP3008 (SPI ADC) chip for measuring voltage levels (including some basic electronics, e.g. a voltage divider).

A wind sensor is a simple switch that goes open->close->open->close->… as it rotates. It can be connected directly to the Pi, no electronics are required. If you don’t use the Eltako sensor you will have to calibrate the software so it can compute the right wind speed from the rotation frequency. A reference anemometer is required for this step. Maybe some manufacturers even provide calibration information. If you have successfully calibrated your sensor and want to help others that have the same model, send me your calibration results so I can publish them here.

What it looks like

This is the hardware (except for the wind sensor): Raspberry Pi B+, Huawei E303 for 3G internet, 12V low voltage cutoff (red LED), brightness sensor (yellow LED) to turn the system off at night, and a 12V car USB adapter (left). One day I’ll put all the electronics in a real case…

IPA total

The Eltako wind sensor on a 3 meter slat, and our solar panels. The Pi doesn’t need this many panels; the primary consumers are our battery chargers, which draw about a hundred times more power. 12V car batteries are in the shed.

IPA outside


Raspbian OS

Install Raspbian OS using NOOBS, following the official instructions. If the SD Card Formatter cannot format your card, use this workaround.

After the installation you should upgrade all packages:

sudo apt-get update ; sudo apt-get dist-upgrade

DHT support

If you plan to connect a DHT22/AM2302 sensor, install Python support for it:

sudo apt-get install python-dev
git clone https://github.com/adafruit/Adafruit_Python_DHT
cd Adafruit_Python_DHT
sudo python setup.py install

PrivateEyePi explains how to connect the DHT22 sensor. This tutorial uses an additional resistor to connect the DHT sensor, but for me it works fine without.

SPI ADC support

To use the MCP3008 SPI ADC, install Python support for it:

sudo apt-get install python-dev
git clone git://github.com/doceme/py-spidev
cd py-spidev
sudo python setup.py install

Then run sudo raspi-config  and under Advanced Options, enable SPI.

Raspberry Pi Spy has an excellent tutorial on the MCP3008.

Anemometer application

The application consists of three components:

  • The client application. This is the Python code that runs on the Pi and measures the wind sensor rotation frequency, computes wind speed and other data, and uploads it to the server.
  • A server component that receives data from the Pi and shows it on a website. The server also provides the client application and configuration file for the client to download. This makes updates easy even when you have no SSH access to the Pi, because the Pi will pull updates itself.
  • A set of bash scripts for the client. These are typically started via cron at boot time. The main script downloads the client application and configuration file from the server and runs it. Other scripts perform helper tasks such as establishing a reverse SSH connection (if desired).


Upload the contents of the server/ directory to a directory on your web server. Let’s assume www.wind.foo/ipa/ for this example. The web server must run PHP 5.3 or higher and MySQL. Make sure the client/ and logs/ directories, as well as the file client/ipa-client.zip, are writable by the PHP user.

Create a new MySQL database, then copy or rename common/config-sample.php to common/config.php and fill in the credentials for that database. Navigate to www.wind.foo/ipa/admin. This will automatically create all database tables and a default configuration. Set server:log_level to debug, client:logging_level to DEBUG and client:upload_interval_seconds to a small value such as 5. This makes the initial setup easier because client and server log more and interact more frequently. Reset these values when everything is working. Server logs are stored in the logs/ directory and may be helpful when something doesn’t work.

Access control

The server/ directory contains several subdirectories, some of which you might eventually want to protect with a password using .htaccess and .htpasswd:

  • admin/ – The admin panel. This should be password protected. The admin password is only entered by you when visiting the admin panel.
  • client/ – Files for interacting with the Pi. This should be password protected if you want to prevent an attacker (or rather, a prankster) from uploading fake wind data or downloading your client binary and config file. The client/ password will be sent by the Pi for every server interaction. You will probably need to store it in your crontab, so don’t use any existing password. For illustration purposes we will assume the credentials for the client/ directory to be “clientUser” and “clientPassword”.
  • common/ – Common PHP files, no need to protect this.
  • logs/ – This already contains an .htaccess file that denies access for everyone.
  • view/ – This is for viewing wind data. You should protect this if you don’t want your data to be public. Wind data isn’t really critical, but the shed door status or the pilot count might be.

I recommend that you set up passwords after everything else is up and running, so if something doesn’t work you have one less thing to debug.

Client scripts

Create a directory on the Pi, e.g. /home/pi/ipa, and copy the contents of the client/ directory to it. Run chmod a+x * in this directory to make the scripts executable.

Client application

The client application and its configuration are downloaded from the server and run by the ipa_wrapper.sh script. This script will also automatically perform an update if you upload a new version to the server or change the client configuration. Run the script now to test if it’s working:

./ipa_wrapper.sh http://clientUser:clientPassword@www.wind.foo/ipa/client

Omit the user:password part if you haven’t set a password for the client/ directory yet. The script will run sudo (this is required for GPIO access), so the user account must be a sudoer and no root password must be set. This is the default setup for the user “pi”.

You should see no error messages on the client, and some data should appear on www.wind.foo/ipa/view. For now the wind data will be zero, but charts for CPU temperature and upload lag should appear.

Startup and shutdown

To kill the application run the kill_ipa.sh script.

To start the application automatically on boot add this line to your crontab:

@reboot ipa/ipa_wrapper.sh http://clientUser:clientPassword@www.wind.foo/ipa/client

Demo mode

The client can generate random data to populate the graphs. This allows to see what the visualization looks like, and to check whether the software part (i.e. everything after the sensor) works. This feature is enabled by setting the configuration key client:demo_mode_enabled to 1.


If something doesn’t work, check the log printed on the client (it is also stored in /home/pi/ipa/logs) and/or the server (in the logs/ directory).

Visualization on the server

The provided file view/index.php is very basic and will have to be edited manually to remove graphs you don’t use and make everything look nice.

The WordPress plugin is easy to use, can show only selected graphs and doesn’t require editing HTML.


NOTE: Previous versions used GPIO.BOARD notation. As of version 0.3.0 I’m using GPIO.BCM notation because it has become more popular.

RasPi TV has a nice cheat sheet for the pinouts.

ADC voltage sensor

Set adc_enabled to 1 and specify the list of channels and reference voltages in adc_channels and adc_vrefs. When you have more than one channel, use a comma separated list with the same number of elements for both.

DHT temperature and humidity sensor

Set dht_enabled to 1 and dht_pin to the GPIO pin to which the sensor is connected. dht_sensor determines the sensor type (11 for DHT11, 22 for both DHT22 and AM2302). dht_retries controls the number of read retries in case the GPIO communication with the sensor fails.

Connecting the wind sensor

First connect a simple circuit tester (such as a multimeter) and slowly rotate the wind sensor 360 degrees. Take note of the number N of changes from open to close plus from close to open. N should be even, probably either 2 or 4. Go to www.wind.foo/ipa/admin and enter this number for edges_per_revolution. Example: If the sensor closes and opens twice per revolution, enter edges_per_revolution=4. Knowing the number of edges per revolution ensures accurate measurements even if the cycle duration within one rotation is uneven.

Now connect the sensor to the GPIO pins: One terminal (it doesn’t matter which one) goes to 3.3V (pin 1), the other to the wind_input_pin specified in the configuration (pin 4 by default). No resistor is needed since the Pi has buit-in pull up/down resistors.

Next we’ll start the calibration tool to check if the sensor is working:

cd ~/ipa/current ; sudo ./wind_calibrate.py

The actual client application must not be running at the same time because both require exclusive accesses to the GPIO pin.

Rotate the sensor by hand. The tool prints something like this:

16:09:28.356 0.268 11.615 1.565 14.721

These value are:

  1. time of day
  2. rotation duration in seconds
  3. current speed in km/h
  4. average speed over last 10 seconds
  5. maximum speed since startup

So if one rotation takes one second the second value should be approximately 1. It should also decrease with increasing rotation speed.

Congratulations, this was all the hardware work :-)

Calibrating the wind sensor

At low speeds mechanical friction will be significant and the relation between rotation speed and wind speed is nonlinear. At higher speeds friction will become negligible and the relation is approximately linear. I have used the following formula to describe this:

v [km/h] = LSF / (1 + rps) + HSF * rps

LSF and HSF stand for low and high speed factors, rps for rotations per second. LSF and HSF are the parameters we need to determine.

The default configuration contains the LSF and HSF values for the Eltako sensor that I use. If you use a different sensor you need to determine LSF and HSF for your particular model. This requires a reference anemometer. I like the Kaindl Windtronic 2 (called “Kaindl Windmaster 2” in Germany).

Set wind_low_speed_factor=0 and wind_high_speed_factor=1 in ipa.cfg. Note that this file will later be overwritten with the server side values when ipa_wrapper.sh is run, so the calibration results should also be entered in the admin panel.

Get a large and powerful fan, set it to maximum speed and point it at the sensor. Then start wind_calibrate.py. Note that the wind speed measured by the sensor may vary significantly depending on its position relative to the fan. Find an arrangement where the wind speed is stable. Make a copy of the readouts on the Pi, specifically the 10 second average since it reduces random fluctuations. Let’s call this value v_avg_pi. This isn’t the correct speed yet unless the correct value for HSF happens to be 1 for your sensor.

Now use the reference anemometer to measure the wind speed at exactly the same position; we’ll call this v_avg_ref.

Set wind_high_speed_factor in ipa.cfg to the quotient of v_avg_ref/v_avg_pi.

Next find out at wich wind speed, as measured by the reference anemometer, the Pi’s sensor starts turning at all, i.e. which wind speed is required to overcome friction in the sensor. Move the fan away from the sensor just before the sensor stops rotating. For the Eltako sensor this is around 1.8 km/h, for higher quality sensors it is probably lower, for cheaper ones it might be higher. Use this value for wind_low_speed_factor. Also, use the rotation duration measured at this speed, plus roughly one or two seconds, for wind_max_rotation_seconds. For example, if the slowest possible rotation takes 9.2 seconds, set wind_max_rotation_seconds=10.

wind_max_rotation_seconds is the cutoff threshold that allows v=0: If no rotation was observed within this time the wind speed is zero. Of course this means that all wind speeds below LSF are considered zero. This is not a theoretically optimal assumption, but in practice it would be confusing to show some magic non-zero estimate when the sensor is actually not rotating. Unless LSF is very high it probably doesn’t matter much. FWIW, my handheld reference anemometer does the same thing :-)

Restart wind_calibrate.py to pick up the config values and experiment with different wind speeds to verify that the calibration was successful. Remember to enter wind_low_speed_factor, wind_high_speed_factor and wind_max_rotation_seconds in the admin panel since ipa.cfg is overwritten when you update the configuration on the server.

Door sensor

When someone is at the flying field they always open the shed door to enter their name in the log book. Using a simple magnetic switch connected to a GPIO pin the Pi can detect this. The door_* values configure this feature. door_pud defines wether to use pull up or pull down on the input pin. door_open_state defines which state (switch open or closed) means the door is open.

Pilot count

Using two buttons connected to two GPIO pins, we can count the number of pilots at the field: When people check in they press the “plus” button, when they leave they press the “minus” button. This gives me a rough idea of how busy the field is. A third GPIO pin is connected to a LED that blinks N times after a button is pressed, where N is the current pilot count. At night (04:00 by default) the count is reset to 0, in case someone forgot to check out.

Electrical configuration is similar to the door sensor described above.

High temperature shutdown

I found that in the summer the CPU may get pretty hot with the Pi running in an unventilated small shed. To avoid damage from overheating you can configure a maximum CPU temperature, client:temperature_shutdown_at (degrees celsius). If this temperature is reached the system shuts down completely. I didn’t find much information on how hot the Pi’s CPU is allowed to get, so I’m not sure if the default of 75°C is good.


Over time the database and server logs grow. Especially at debug level the logs can take up several MB per day. You can use the prune button on the admin panel to delete old database records and log files.

This can also be automated: Enter the amount of days you want to keep, click the prune button, then copy the browser’s URL and configure a cron job to request this URL every day using curl or wget.


If you have any questions or suggestions, please feel free to contact me.

28 thoughts on “IP Anemometer

  1. Hey!

    Thank you very much for this post regarding this specific wind speed sensor for anemometer because of its digital output nature to be plugged in directly with a Raspberry Pi, I was really looking for a sensor as this long back to build my weather station as yours. However, I would like to know, how much power does the wind speed sensor from Eltako uses which you have implemented in your system, I mean the voltage requirements, does it require more than 5V as required by the Raspberry Pi, then finding a common power supply for the Raspberry Pi and wind speed sensor might be difficult for me.


    1. The sensor is connected directly to 3.3V and a GPIO pin (using software pull down). No special electronics are required at all, provided you don’t need to extend the cable that the sensor comes with. If you’re using a long cable you’ll have to deal with the noise this cable picks up. One user was successful with a long ethernet cable, due to the shielding it provides.

      1. Hello,

        So I have the Eltako Wind speed sensor as used by your weather station, however even if the post explains about the connection of the two wired wind speed sensor to the Raspberry Pi 3.3V power and GPIO pin (default pin 4), I have doubt in identifying which wire of the two from the sensor is to be connected to the 3.3V and which one (as the sensor output) to the GPIO of Raspberry Pi, there is no information manual or instruction to identify the same, I can see only one white colored insulated wire and the other brown colored insulated wire, so I am unable to identify the correct wires among the two for a successful connection. I fear damaging the sensor with the wrong connection as in swapping of wire connection to Raspberry Pi. I request you to kindly help with your suggestion.

        Best Regards,

        1. It doesn’t matter which wire is connected to 3.3V and which to the GPIO pin. The sensor is just a switch, so it doesn’t have polarity. I’ve updated the text to mention this.


          1. Hello Jörg,

            Thank you very much for your quick response, I have made the necessary hardware connection of the Eltako wind sensor to the Pi already, however when I try to execute the wind_calibrate.py code from the required path after downloading the ip anemometer master folder shared by you on to my Pi desktop, the Pi is not giving any response output but giving out IOError: No such file or directory: ‘ipa.cfg’. I am unable to debug the source of this error to check the operation of the wind sensor if it works or not. As you mentioned in the post, I believe any further calibration to this sensor is not needed.

            Could you please help with this and also in identifying the main python code for the operation of the wind speed sensor, there are files named wind.py in the ipa folder and the wind_test.py in the test folder of ipa, I am confused of which one to be used for code execution to observe the wind speed output on console if I had to check.

            Also do I have to upload and install any library exclusively from “github” or other source onto the Pi for the wind sensor operation to be provided with a relevant output from Pi and after executing the python code in client ipa folder successfully?

            Best Regards,

  2. Hello Jörg,

    The earlier IOError is resolved but I’m having an encounter of a new error, i.e. KeyError: ‘logging_level’ while trying to execute the wind_calibrate.py when it is calling the get_logger, exactly in line 34 of logger.py and then calling LOGGING_LEVEL, exactly in line 113 of config.py .

    Could you please help resolve this?

    Best Regards,

    1. The client code depends on an ipa.cfg config file that the server generates. Did you set up the server and have ipa_wrapper.sh pull the actual client code (with the config) from the server? This is described in the installation steps above (sections “Server” through “Cient Application”).

      You don’t need to download anything from github, all you need is the .zip archive from the download page.

      1. Hello Jörge,

        Thank you for your last response.
        I have set up the server (LAMP – LinuxApacheMySQLPHP) and wordpress installation, with my site (after WordPress installation) and database created already and started following your described installation steps from the section “Server”, I’ve provided the write access to the PHP user for “…./client” and “…./logs”. However, after renaming the config-sample.php to config.php inside “…./common”, I have stumbled across one step where I find “…../client/ipa-client.zip” this .zip file missing as the message on my browser when I am trying to navigate to “localhost/ipa/admin” to create database table and default configuration .

        I cannot find this exact .zip folder/filename as mentioned inside the “…./client” directory. Is it one of the .zip folders with a different name which are available in your “download page” or something else specifically, could you please help me locate this “…../client/ipa-client.zip” somewhere ? Without which I am unable to successfully navigate/proceed for creating table and configuration under “localhost/ipa/admin” address.

        Best Regards,

        1. The file is right there in .\server\client\ipa-client.zip (I just verified ip-anemometer-0.3.2.zip on the download page). Just a wild guess: Did you use a tool that unzips recursively?

          1. Hello Jörg,

            I have also the same problem that I can’t find the file “ipa-client.zip”. Do I have to create this file myself?
            In the Folder “.\server\client\” is only the file “ul.php”.
            I’ve already searched all releases on git, but I did not find anything and I’m stuck with that point.

          2. I found the Problem by myself. The file ist lost in git. But I found it on the archiv on your website.

          3. The file is not in the repository to avoid duplicate data. Generally the repository doesn’t map 1:1 to the installation package. I figured that everyone would download the package from the download page on zieren.de. It seems that was incorrect, and I have to say the “Releases” page on Github does look like the right place to download for end users. I’ve added some notes on Github to point here. Thanks for letting me know.

        1. Hi Marcus, what is the error you’re getting? ipa.cfg not found? That should be unrelated to port 8080. Did you visit the admin page on the web server? It will create the ipa.cfg file so the client can retrieve it.


  3. Hello Jörg,

    Thank you for this information. I have got this ipa-client.zip file after downloading from the ip-anemometer-0.3.2.zip, earlier I was using another source of .zip called “ip-anemometer-master.zip” which is why I could not find it. So, now the problem is when I am trying to navigate through “localhost/ipa/admin”, I believe the installation is still not happening for database table and default configuration, I am seeing “Failed: Internal server error 500” even after having the necessary .zip file in the location “…\client\ipa-client.zip”. I have not been able to resolve this error since long. Could you please provide an idea or help?

    Also, I could not follow your steps after this one as in to “Set server:log_level to debug, client:logging_level to DEBUG and client:upload_interval_seconds to a small value such as 5”, where can I do these changes/modifications?

    Thank you!

    Best Regards,

  4. Hi,
    your project is fantastic! I try to understand and reproduce some part of it, but lacking an instrument to do the calibration
    myself, I’d love to use your values for LSF, HSF and the debounce time (but myself teh Eltrako Windsensor WS as well).
    I think these values should be in a file called “config.ipa”, but I cannot find it, sorry. Would you mind sharing these values
    (knowing that of course my Windsensor is probably a bit different then yours).
    Best regards

    1. If you have the Eltako sensor you don’t need to do anything. The Eltako values for LSF and HSF are mentioned above (section “Calibrating the wind sensor”), but they will be used automatically by default. The client will download a config file from the server that contains them. If you want to take a look, the file is at ./server/admin/default.cfg.

      Let me know if it works.

  5. Hi,

    if i call ‘./ipa_wrapper.sh http://(…)’ i get the following error(s):
    File “main.py”, line 16, in
    from config import C
    File “/home/pi/ipa/sh/ipa-20181229-140032/config.py”, line 123, in
    C = Config()
    File “/home/pi/ipa/sh/ipa-20181229-140032/config.py”, line 23, in __init__
    File “/home/pi/ipa/sh/ipa-20181229-140032/config.py”, line 26, in _readFile
    for line in open(K.CONFIG_FILENAME, ‘r’):
    IOError: [Errno 2] No such file or directory: ‘ipa.cfg’
    20181229-155259 client returned exit code 1
    20181229-155259 restarting client
    20181229-155259 starting client

    May you can help?
    Package rpi.gpio is install too, i use Debian v9.6

    Best regards, Thomas

    1. Hi Thomas,

      Did you set up the server and have ipa_wrapper.sh pull the actual client code (with the config) from the server? This is described in the installation steps above (sections “Server” through “Cient Application”). LMK if it still doesn’t work.


      1. Hi Jörg!

        Yes, my server is running (WordPress is running too on it) and i got the actual client code. But it isn’t still work. :-(

        What i’ve done?!
        – A subdirectory {myurl}/ipa/ was created
        – Uploaded the server contents in it done
        – {myurl}/ipa/admin worked, all tables in a database were created
        – still not .htaccess and .htpasswd in the subdirectories
        – section ‘Client scripts’ done
        – section ‘Client application’ i get the error(s) when i call ./ipa_wrapper.sh http://{myurl}/ipa/client

        BR Thomas

        1. Supplement:
          The ‘ipa-client.zip’ archive i found in your direct download file, not on GitHub

          1. So I tried a lot of things but only got that:

            20181230-192855 IP anemometer wrapper 0.4.0 – (c) 2017 Jörg Zieren – http://zieren.de – GNU GPL v3
            20181230-192855 waiting for clock to sync (stratum must be <= 8)
            20181230-192855 stratum now: 2
            20181230-192855 clock is synced
            20181230-192855 starting client
            Traceback (most recent call last):
            File "main.py", line 16, in
            from config import C
            File “/home/pi/ipa/sh/ipa-20181229-140032/config.py”, line 123, in
            C = Config()
            File “/home/pi/ipa/sh/ipa-20181229-140032/config.py”, line 23, in __init__
            File “/home/pi/ipa/sh/ipa-20181229-140032/config.py”, line 26, in _readFile
            for line in open(K.CONFIG_FILENAME, ‘r’):
            IOError: [Errno 2] No such file or directory: ‘ipa.cfg’
            20181230-192855 client returned exit code 1
            20181230-192855 restarting client

            I use Python 2.7.13(-2)

  6. Hello,

    i tried to follow this tutorial, but I am a bit confused.

    I found an other tutorial about the Elkato Windsensor, where the Sensor is connect to a Ground and a GPIO instead of a 3,3V and a GPIO.
    Can someone explain this to me?

    Thank you

    1. Both are possible, it’s just a matter of the software to configure the GPIO pin accordingly (pull up or down).

  7. Hi !

    Thanks for that nice Project.

    Is there any chance to get a Sensor for Wind-Direction running ?
    Oure Air-Field is South-Wind-Sensitive, so we need this.


    1. A wind direction sensor would be great, but right now I don’t have the time to do this (it’s not trivial). If anyone wants to contribute the hardware part though, I think I might be able to do the software support.


Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.