BirdNET-Pi to Monitor Bird Calls

From Sensors in Schools
Jump to navigation Jump to search

BirdNET-Pi Lesson

Lesson number Step by step instructions Dropbox Video link Teacher resources
Lesson 2a #The Importance of Using BirdNET-Pi to Monitor Bird Calls Alt text
Lesson 2b #BirdNET-Pi microSD Card Imaging link=https://www.dropbox.com/s/fq1ak4lqrg4hv5o/Installation%20Guide%20BirdNET-Pi.mp4?dl=0 BirdNET-Pi microSD Card Imaging GitHub BirdNET-Pi Installation Guide
Lesson 2c #BirdNET-Pi Software Installation link=https://www.dropbox.com/s/1x2lzk1n1koy1a5/BirdNET-Pi%20Software%20Installation.mp4?dl=0 BirdNET-Pi Software Installation using SSH BirdNET-Pi Software Installation using SSH
Lesson 2d #BirdNET-Pi Finalising the Installation link=https://www.dropbox.com/s/504yk7jwrszpgtm/BirdNET-Pi%20Finalising%20the%20Installation.mp4?dl=0 BirdNET-Pi Finalising the Installation BirdNET-Pi Finalising the Installation
Lesson 2e #Settings Configuration in BirdNET-Pi Web Portal

Overview

  • BirdNET-Pi uses a USB microphone connected to a Raspberry Pi to record and identify bird calls.
  • The system runs 24/7 and can upload data in real time to https://app.birdweather.com
  • Data can also be downloaded via an API so that you can do some additional data processing using Node-RED.

Hardware requirements

  • Raspberry Pi 4 or Pi 3 B+.
  • USB Microphone - (e.g. Gyvazla USB Microphone Lavalier Clip-on Omnidirectional Condenser Microphone for Computer) [1]
  • Heat sink and fan for Raspberry Pi. Optional, but highly recommended because it will keep the processor temperature less than 40degC to prevent throttling and prolong the life of your Raspberry Pi.

Learning Objectives

  • Learn about the important role of vegetation in supporting small birds
  • Learn how to install BirdNET-Pi on a Raspberry Pi 4
  • Learn how to interpret data from a local installation of BirdNET-Pi
  • Learn how to use an API to retrieve data from the BirdNET-Pi installed in Bundoora

Small Birds

  • Small birds need protection from thick scrubby vegetation so they can build nests and also hide from larger birds.
  • Examples of small birds include:
    • White-browed Scrubwrens
    • Brown Thornbills
    • Spotted Pardalotes
    • Willy Wagtails
    • Yellow Robins
    • Golden Whistlers
    • Eastern Spinebills
    • Grey Fantails
  • There is also a documentary you can watch on ABC iView called The Secret Lives of our Urban Birds. Start at the 41 minute mark to see the section on Noisy Minors [2]
  • Friends of Darebin Creek - Small Woodland Birds [3]

BirdNET-Pi microSD Card Imaging

  • Insert a microSD card in the computer with the Raspberry Pi Imaging software.
  • The size of the microSD card needs to be 16 GB.
  • Open the Raspberry Pi Imager and click CHOOSE OS to select the operating system for BirdNET-Pi.
  • Click Raspberry Pi OS (other) Other Raspberry Pi OS based images

  • Scroll down the list and select "Raspberry Pi OS Lite (64-bit)"

  • Next, click "CHOOSE STORAGE" to select the SD card the BirdNET-Pi will use

  • Choose the SD card onto which we will write the RaspiOS-Lite (64-bit) operating system

  • Now, click the gear icon in the bottom right to open the "Advanced options" menu

  • Answer Yes - to fill in WiFi details

  • Set the hostname you would like this BirdNET-Pi to use to be reached.
  • For example, to have multiple BirdNET-Pis on the same network, you might want to give them each a different hostname.
  • In this example, the installation will be reachable at "http://birdnetpi1.local", since that is the hostname that is set during this step.
  • You should also "Enable SSH" and select to "Use password authentication"
  • When you scroll down, you will set the option to "Set username and password."
  • This example creates a new user called pi.

  • You will also configure the system's connection to your WiFi by entering the network's name (SSID) and the password used to connect to that WiFi.
  • Adjust the locale settings for your Time zone and Keyboard layout.
  • Save the settings

  • Click "WRITE" to write the image to the SD card

  • Select "YES" and enter to allow your host system (the computer you're on now) to write the SD card.
  • Wait while the image is written to the card and the checksums verified

  • You may need to give permission for your computer to make changes to the SD card.
  • Enter your password (if requested) and click OK.

  • The writing and verification process takes approx 5-10 minutes.

  • When the SD card is ready, you'll be notified that is ok to remove it from your computer

  • At this point, you will put the SD card into the Raspberry Pi and will allow it a few minutes to boot up.
  • After a few minutes, you can move on to the next step.

BirdNET-Pi Software Installation

  • At this point, you will put the SD card into the Raspberry Pi and will allow it a few minutes to boot up.
  • After a few minutes, you can move on to the next step.
  • Using a terminal emulator of your choosing (macOS and Linux users can use the terminals that come with the OS -- Windows users can use PowerShell or PuTTY).

  • Use the username and hostname from step 8 to SSH into the Raspberry Pi.
  • In this example, we created the birder user on the birdnetpi1.local host, so the command would be ssh pi@birdnetpi1.local

  • When warned that you are connecting to a new machine, type yes to proceed

  • You will be prompted for the password that you set for user pi

  • After entering the password for your user, you will be able to begin the installation of the BirdNET-Pi software.

  • The installation process will take approximately 5 to 10 minutes.

  • When the installation is finished, the system will automatically reboot. When it is booted back up,

you will be able to reach your BirdNET-Pi using the hostname you set in step 8. In this installation example, it is http://birdnetpi1.local. The default (if you did not set a specific hostname in step 8) will be http://birdnetpi.local. It can also be reached at the Pi's IP address.

BirdNET-Pi Finalising the Installation

  • Open a Browser on a computer on the local network.
  • Enter the following address in the search bar http://birdnetpi1.local

  • BirdNET-Pi Dashboard will open up.

Settings Configuration in BirdNET-Pi Web Portal

  • The BirdNET-Pi web portal has additional configuration options.
  • Click on the Tools dropdown menu.
  • A Log into birdnetpi1.local:80 window will appear.
  • The username is birdnet
  • There is no password.
  • Click on Log in

  • A new series of administration buttons will appear under the main menu.
  • Click on Settings

  • Wait a few seconds for the Settings page to load.
  • BirdNET-Pi needs to know the latitude and longitude location up to 4 decimal places.

  • Use Google Maps to pinpoint the location of the BirdNET-Pi sensor.
  • Enter the GPS coordinates to 4 decimal places.

  • BirdNET-Pi will keep your data localised unless you upload data to BirdWeather.com.
  • If you would like to share data contact Tim (tim@birdweather.com) to request a BirdWeather ID.
  • Sending data to BirdWeather.com will is important for this project because we can then access the data using an API (more on this later).

  • Update the Time and Date settings.
  • To commit (save) all setting click on the Update Settings button.

  • To check that the Settings have been updated successfully wait for the Settings page to reload.
  • Then scroll down to the bottom of the page.
  • A Success message should be displayed.

Advanced Settings

Swap file expansion

[Expanding the swap file on the Raspberry Pi]


WiFi Antenna Extenders

  • BirdNet-Pi (Raspberry Pi) may end up in a location that has poor WiFi receiption.
  • External WiFi antennas can be plugged into the USB port on the Raspberry Pi that will boost reception.

USB WiFi Module

  • A small Mini USB WiFi Module - RTL8188eu - 802.11b/g/n can be added to the Raspberry Pi (Core Electronics).
  • This is suitable for indoor spaces where Wifi reception is poor.
  • Often, a metal case enclosing the Raspberry Pi will reduce WiFi signal strength. Metal cases are ofter used to enclose a Raspberry Pi to help remove excess heat.

Wifi High Gain Antenna

  • A larger High Gain external antenna may be required especially if the Raspberry Pi is located outside a house or in a garden shed.
  • This antenna will significantly extend the useful range of the existing WiFi network.
  • Panda Wireless® PAU0D AC1200 Wireless AC USB Adapter with High Gain Antennas - Windows XP/Vista/7/8/10/11, Mint, Ubuntu, openSUSE, Fedora, Centos, Kali Linux and Raspbian (Amazon)

BirdNET-Pi Maintenance

  • Restart BirdNET-Pi Raspberry Pi once per week.
  • Monitor temperature of Raspberry Pi to check to see if it has been throttled due to exceeding 60degC.
  • Check to see if the Micro SSD card is full.
  • Complete any updates.
  • Accessing BirdNET-Pi computer using Secure Shell (ssh)
  • Accessing BirdNET-Pi specific hostname http://birdnetpi1.local/

BirdNET-Pi Monitoring

  • It may be necessary to establish a regular monitoring program for the Raspberry Pi to monitor disk usage.
  • In the example below, the Raspberry Pi running BirdNET-Pi was found to be unresponsive.
  • Even after rebooting the system could not be fully recovered (disconnecting power and powering up again).
  • The system could be accessed using secure shell using the command ssh pi@192.168.1.133
  • Using the command df -h the hard drive was found to be full.

  • To monitor the Raspberry Pi system two python libraries were installed.
  • vcgencmd is a command line utility that can get various pieces of information from the VideoCore GPU on the Raspberry Pi such as temperature and determine if the processor has been throttled due to over temperature.
  • It is installed with the command sudo pip3 install vcgencmd [4]

  • Dweet can be used to send data from the Raspberry Pi every 15 minutes.
  • To use Dweet the requests python library needs to be installed.
  • Enter the command python3 -m pip install requests

  • The bird_monitor.py python file was created in the /home/pi directory.

  • The python code is reproduced below.

  • A typical output is presented below.
  • If the python script /home/pi/bird_monitor.py is now working, then rebooting the BirdNET-Pi computer may fix the error.


Python code to monitor BirdNET-Pi has been collapsed by default. Click here to expand:

import os
import requests
from datetime import datetime
from vcgencmd import Vcgencmd

now_unformatted = datetime.utcnow().isoformat()
now = f"{now_unformatted[:-7]}Z"

df_output_lines = [s.split() for s in os.popen("df -Ph").read().splitlines()]
disk_space = str(df_output_lines[1][4])

vcgm = Vcgencmd()
temp = vcgm.measure_temp()
throttled = vcgm.get_throttled()

dweet_dict = {}
dweet_dict.update({"latest_update": now})
dweet_dict.update({"disk_space": disk_space})
dweet_dict.update({"temp": temp})
dweet_dict.update({"throttled": throttled})
url = "https://dweet.io/dweet/for/birdNET-pi-273-bundoora-monitor?"
x = requests.post(url, json=dweet_dict)
print(f"x data {x.text}")

Scheduling tasks using crontab

  • Cron can be used to schedule monitoring tasks.
  • BirdNET-Pi requires disk space and processor temperature to be monitored using the bird_monitor.py file.
  • Cron can be edited in the Terminal with the command crontab -e
  • Cron tasks can be viewed with the command ctrontab -l
  • In the listing below the bird_monitor.py file is run at 5, 20, 35 and 50 minute intervals every hour.

Managing Disk Space on the BirdNET-Pi computer

  • To keep disk space free on the BirdNET-Pi computer the clear_all_data.sh script is scheduled to run every day at 4:05am
  • The update_birdnet.sh is also scheduled daily at 4:10am.
  • BirdNET-Pi parameters are monitored every 15 minutes and stored in a text file on a separate computer.
  • The screen shot of the text file shows the following data:
    • disk utilisation (%)
    • CPU temperature (degC)
    • CPU throttled (0x0 - indicates no throttling)

BirdNET-Pi in-built Scripts

  • BirdNET-Pi has a several in-built scripts that are used to help administer BirdNET-Pi.
  • clear_all_data.sh clears all bird recordings from the computer and frees up disk space.
  • disk_usage.sh provides a human readable output for free disk space on the computer.
  • update_birdnet.sh updates the BirdNET-Pi software.

  • These same scripts are executed from the BirdNET-Pi web portal dashboard.
  • Open a Browser on a computer on the local network.
  • Enter the following address in the search bar http://birdnetpi1.local
  • This will bring up the BirdNET-Pi web portal.
  • Click on the Tools tab.
  • Then click on the System Controls tab.

  • Clicking on Update executes the update_birdnet.sh script.
  • Clicking on Clear ALL Data executes the clear_all_data.sh script.

  • The output of the command update_birdnet.sh can be seen here.


Running Shell Script cleanup.sh Daily

  • If there are issues processing data during the day this can lead to a reduction in storage space on the BirdNET-Pi.
  • Running the shell scrip cleanup.sh daily can help.
  • If the in-built cleanup.sh script doesn't work then the Pi can also be rebooted daily or when memory is low.
  • These scripts can be run using cron

  • However after running this script for several days the solid state MicroSD card started to fill up to 90%.

Daily reboot

  • In this trial the BirdNET-Pi was rebooted each day at 5 minutes after midnight to see if this could reduce space on the micro SD card.
  • However even reboot did not seem to clear the microSD memory card.
  • The best approach seems to be to clear_all_data.sh once per week using cron. An example will be provided.

Running clear_all_data.sh script once per week (Sunday)

  • Using crontab the amount of memory usage on the Raspberry Pi microSD card can be managed.
  • The following scripts are run.
    • cleanup.sh - daily at 5 minutes past midnight
    • update_birdnet.sh - daily at 15 minutes past midnight
    • clear_all_data.sh - weekly on Sundays at 10 minutes past midnight. This will clear all data and free up space on the microSD card. This script is the most effective. Running weekly is sufficient to prevent the microSD card from becoming too full.

Node-RED code to analyse bird_monitor.py data via Dweet

  • Node-RED running on a separate Raspberry Pi computer was used to monitor the disk space and the CPU temperature on the BirdNET-Pi computer.
  • The data was made available to another computer using Dweet.

Installing Node-RED

  • The Node-RED code is reproduced below.

Node-RED code has been collapsed by default. Click here to expand:

[
    {
        "id": "99bda892.ebb298",
        "type": "tab",
        "label": "BirdWeather",
        "disabled": false,
        "info": ""
    },
    {
        "id": "ec6d79ff.a14128",
        "type": "debug",
        "z": "99bda892.ebb298",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 650,
        "y": 120,
        "wires": []
    },
    {
        "id": "c534dd12.19d5f",
        "type": "exec",
        "z": "99bda892.ebb298",
        "command": "python3 /home/pi/BirdWeather/birdWeather1.py",
        "addpay": "",
        "append": "",
        "useSpawn": "false",
        "timer": "",
        "winHide": false,
        "oldrc": false,
        "name": "",
        "x": 390,
        "y": 200,
        "wires": [
            [
                "ec6d79ff.a14128"
            ],
            [],
            []
        ]
    },
    {
        "id": "63e49c383d07eb36",
        "type": "cronplus",
        "z": "99bda892.ebb298",
        "name": "23:45 every day",
        "outputField": "payload",
        "timeZone": "",
        "persistDynamic": false,
        "commandResponseMsgOutput": "output1",
        "outputs": 1,
        "options": [
            {
                "name": "schedule1",
                "topic": "topic1",
                "payloadType": "default",
                "payload": "",
                "expressionType": "cron",
                "expression": "0 45 23 * * *",
                "location": "",
                "offset": "0",
                "solarType": "all",
                "solarEvents": "sunrise,sunset"
            }
        ],
        "x": 120,
        "y": 60,
        "wires": [
            [
                "c534dd12.19d5f"
            ]
        ]
    },
    {
        "id": "85745ab65dbe7307",
        "type": "function",
        "z": "99bda892.ebb298",
        "name": "Save data function",
        "func": "var latest_update; \nvar disk_space;\nvar temp;\nvar throttled;\n\n\nlatest_update = msg.payload.with[0].content.latest_update;\ndisk_space = msg.payload.with[0].content.disk_space;\ntemp = msg.payload.with[0].content.temp;\nthrottled = msg.payload.with[0].content.throttled.raw_data;\n\ndatetime = msg.payload.with[0].content.latest_update;\n\nmsg.payload = String(msg.myepoch) + \",\" + String(msg.mydate) + \",\"\n            + String(msg.mytimes) + \",\" \n            + String(latest_update) + \",\" + String(disk_space) + \",\" \n            + String(temp) + \",\" \n            + String(throttled) + \",\"\n            + String(datetime);\nreturn [msg];",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 130,
        "y": 460,
        "wires": [
            [
                "ebb8a5963b97cfd6"
            ]
        ]
    },
    {
        "id": "9d59914e52e7c4a1",
        "type": "http request",
        "z": "99bda892.ebb298",
        "name": "",
        "method": "GET",
        "ret": "obj",
        "paytoqs": "ignore",
        "url": "https://dweet.io/get/latest/dweet/for/birdNET-pi-dweet-project-name",
        "tls": "",
        "persist": false,
        "proxy": "",
        "authType": "",
        "senderr": false,
        "x": 570,
        "y": 340,
        "wires": [
            [
                "0eb9fa1b01114ab1",
                "85745ab65dbe7307"
            ]
        ]
    },
    {
        "id": "922d3407be181bd0",
        "type": "debug",
        "z": "99bda892.ebb298",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 590,
        "y": 460,
        "wires": []
    },
    {
        "id": "900ef8f1cd64965c",
        "type": "cronplus",
        "z": "99bda892.ebb298",
        "name": "10,25,40,55 hourly",
        "outputField": "payload",
        "timeZone": "",
        "persistDynamic": false,
        "commandResponseMsgOutput": "output1",
        "outputs": 1,
        "options": [
            {
                "name": "schedule1",
                "topic": "topic1",
                "payloadType": "default",
                "payload": "",
                "expressionType": "cron",
                "expression": "10,25,40,55 * * * * ",
                "location": "",
                "offset": "0",
                "solarType": "all",
                "solarEvents": "sunrise,sunset"
            }
        ],
        "x": 130,
        "y": 340,
        "wires": [
            [
                "195359b5ede1fae4"
            ]
        ]
    },
    {
        "id": "195359b5ede1fae4",
        "type": "simpletime",
        "z": "99bda892.ebb298",
        "name": "",
        "mydate": true,
        "myymd": true,
        "myyear": true,
        "mymonth": true,
        "mymonthn": true,
        "mydom": true,
        "mydoy": true,
        "myday": true,
        "myhourpm": true,
        "myhour": true,
        "mytime": true,
        "mytimes": true,
        "myminute": true,
        "myminutes": true,
        "mysecond": true,
        "mymillis": true,
        "myepoch": true,
        "myrawdate": true,
        "mypm": true,
        "x": 350,
        "y": 340,
        "wires": [
            [
                "9d59914e52e7c4a1"
            ]
        ]
    },
    {
        "id": "ebb8a5963b97cfd6",
        "type": "file",
        "z": "99bda892.ebb298",
        "name": "bird_monitor-data",
        "filename": "/home/pi/BirdWeather/bird_monitor_data.txt",
        "appendNewline": true,
        "createDir": false,
        "overwriteFile": "false",
        "encoding": "none",
        "x": 370,
        "y": 460,
        "wires": [
            [
                "922d3407be181bd0"
            ]
        ]
    },
    {
        "id": "0eb9fa1b01114ab1",
        "type": "debug",
        "z": "99bda892.ebb298",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 610,
        "y": 260,
        "wires": []
    }
]


  • Cronplus node in Node-RED
  • The cron job will run every 10, 25, 40 and 55 minutes, every hour, every day as given by the term 10,25,40,55 * * * *

  • HTTP Request Node
  • Note that the actual Dweet address has been modified.
  • Add your own Dweet project name.

  • Function node in Node-RED

  • Write file node in Node-RED

BirdNET-Pi API

Example Python code

  • This is a simple python program that will return some BirdWeather results from station 273 (my station in Bundoora, Victoria Australia)

  • Here is the Python code that can be copied.
import requests
import json

query = """query{ 
  station(id: "273")  {
    id
    location
    name
    topSpecies {
        averageProbability
        species {
            id
            commonName
            scientificName
        }
     } 
  }
}"""

url = 'https://app.birdweather.com/graphql'

r = requests.post(url, json={'query': query})
#print(r.status_code)
#print(r.json())

data_json = json.dumps(r.json())
print(data_json)
  • The output is shown in the Python Shell.
  • The data is in JSON format

  • Copy this output and paste it in JSONviewer to make the data human readable https://jsonviewer.com
  • The data should be similar to the screen shot below.

BirdWeather online GraphiQL tool

  • Use the online documentation to modify your query https://app.birdweather.com/api/index.html.
  • This will help you understand how the API work.
  • In this example below the wikipediaSummary has been added to the query.


API to monitor Bird species and Count

  • API query to extract data from BirdWeather.com

  • Python code breakdown:
    • Analyse data from top 30 bird species. Data saved in text file named dailyBirdCount'txt
    • Dweeting data to make available to others
    • Saving BirdWeather data as a JSON file (JSON data)

  • Output of Python file birdWeather1.py


Bird Weather Hourly Data Collection - birdWeatherHourly.py

  • Will collect data from midnight to the current hour each day.
  • Two different data plots are created from the python file named birdWeatherHourly.py.
  • This first plot shows how the total tally of bird recordings increases every hour.
  • The Total bird count is reset to zero at midnight each day.

  • This plot shows the number of unique (different) bird species recorded each day.
  • The data is plotted each hour.
  • The graph shows that in a typical day between 15 and 20 different species of bird are detected.


# file name - birdWeatherHourly.py
import requests
import json
import datetime
import plotly
import plotly.graph_objects as go
import pandas

now = datetime.datetime.now()
date_stamp = now.strftime("%Y-%b-%d %H:%M")

hour_str = now.strftime("%H")
hour_int = int(hour_str)
print(f'The currently hour is {hour_int}')

# Will collect data from midnight to the current hour each day

query = """query{ 
  station(id: "273")  {
    id
    location
    name
    topSpecies (limit: 60, period: {count: %s, unit: "hour"}) {
        count
        species {
            id
            commonName
            scientificName
            ebirdUrl
            imageUrl
            wikipediaSummary
        }
     } 
  }
}""" % (hour_int)

print(f'QUERY = {query}')

total_count = 0
different_bird_species = 0

# Requesting data from BirdWeather.com using API
url = 'https://app.birdweather.com/graphql'
r = requests.post(url, json={'query': query})

try:
    data_dict = r.json()["data"]["station"]
    #print(data_dict["id"])
    topSpecies = data_dict["topSpecies"]
    bird_dict = {"last_updated": date_stamp}  # dictionary

    # Analysing data for top 60 species and saving in file named dailyBirdCount.txt

    for species in topSpecies:
        count = species["count"]
        total_count += count
        species = species["species"]
        print(f"species = {species['commonName']}, count = {count}")
        data = str(different_bird_species) + "," + date_stamp + "," + str(species['commonName']) + "," + str(count) + "\n"
        #print(f"data = {data}")

        different_bird_species += 1
        bird_dict.update({str(species['commonName']): count})
        ebird_url = str(species['ebirdUrl'])
        image_url = str(species['imageUrl'])
        summary = str(species['wikipediaSummary'])

    
    print()
    print(f"dictionary = {bird_dict}\n")
    print(f"ebird_url = {ebird_url}")
    print(f"Summary = {summary}")
    
except:
    # no detections from BirdWeather API
    print("No data")
    ebird_url = "https://ebird.org/species/railor5"
    image_url = "https://birdweather.s3.amazonaws.com/species/301/RainbowLorikeet-standard-239eeed3a59c681ef12fa644ebc8e2d6.jpg"
    summary = ""


# Total count of all birds detected per day
data_count = date_stamp + "," + hour_str + "," + str(total_count) + "," + str(different_bird_species) + "\n"
f = open('/home/pi/BirdWeather/dailyBirdTotalCount.txt','a')
f.write(data_count)
f.close()

# Bird URL to display to viewers - most recent new bird species from past hour
f = open('/home/pi/BirdWeather/mostRecentUniqueBirdUrl.txt','w')
f.write(str(ebird_url))
f.close()

# Save most recent bird image from internet. wb = write binary
url = image_url
myfile = requests.get(url)
open('/home/pi/BirdWeather/BirdImage.png', 'wb').write(myfile.content)


# import and plot data text file
# date_stamp,total_count,different_bird_species
df = pandas.read_csv('/home/pi/BirdWeather/dailyBirdTotalCount.txt')

fig = go.Figure(data = go.Scatter(mode='markers',
                                    x=df.date_stamp,
                                    y=df.total_count,
                                    marker=dict(
                                        color="LightSkyBlue",
                                        size=20)
                                    )
                )
fig.update_layout(title="Total Count of Birds in the Day",
                    xaxis_title = 'Time',
                    yaxis_title = 'Bird Count',
                    font=dict(
                        size=20,
                        color="RebeccaPurple"
                        )
                    )

plotly.offline.plot(fig,
                    filename="/home/pi/BirdWeather/daily_bird_count.html",
                    auto_open=False)

print("Daily Bird Count data plotted")

# Different Bird Species Plot

fig = go.Figure(data = go.Scatter(mode='markers',
                                    x=df.date_stamp,
                                    y=df.different_bird_species,
                                    marker=dict(
                                        color="LightSkyBlue",
                                        size=20)
                                    )
                )
fig.update_layout(title="Total Count of Birds in the Day",
                    xaxis_title = 'Time',
                    yaxis_title = 'Different Bird Species',
                    font=dict(
                        size=20,
                        color="RebeccaPurple"
                        )
                    )

plotly.offline.plot(fig,
                    filename="/home/pi/BirdWeather/different_bird_species.html",
                    auto_open=False)

print("Different Bird Species Count data plotted")

Bird Weather Specific Species - birdWeatherSpecificSpecies.py

  • The query only retrieves data generated in the past 1 hour (count: 1).
  • This python code names birdWeatherSpecificSpecies.py keeps separate text files for individual bird species and tracks the number of recordings per hour.
  • Both common (Rainbow lorikeet) and rare birds (Powerful owl) can be recorded separately.
  • In the future this data can also be plotted using plotly.

* file name - birdWeatherSpecificSpecies.py
import requests
import json
import datetime
import plotly
import plotly.graph_objects as go
import pandas

now = datetime.datetime.now()
date_stamp = now.strftime("%Y-%b-%d %H:%M")

# The query only retrieves data generated in the past 1 hour (count: 1)

query = """query{ 
  station(id: "273")  {
    id
    location
    name
    topSpecies (limit: 60, period: {count: 1, unit: "hour"}) {
        count
        species {
            id
            commonName
            scientificName
            ebirdUrl
            imageUrl
            wikipediaSummary
        }
     } 
  }
}"""

# Requesting data from BirdWeather.com using API
url = 'https://app.birdweather.com/graphql'
r = requests.post(url, json={'query': query})

try:
    data_dict = r.json()["data"]["station"]
    #print(data_dict["id"])
    topSpecies = data_dict["topSpecies"]
    bird_dict = {"last_updated": date_stamp}  # dictionary

    total_count = 0

    # Analysing data for top 60 species and saving in file named dailyBirdCount.txt

    for species in topSpecies:
        count = species["count"]
        #total_count += count
        species = species["species"]
        print(f"species = {species['commonName']}, count = {count}")

        # Powerful Owl detection (Powerful Owl id = 4249)
        if species['id'] == "4249":
            bird_data = date_stamp + "," + species['id'] + "," + species['commonName'] + "," + str(count) + "\n"
            f = open('/home/pi/BirdWeather/powerfulOwlDetected.txt','a')
            f.write(bird_data)
            f.close()

        # Rainbow Lorikeet detection (Rainbow Lorikeet id = 301)
        if species['id'] == "301":
            bird_data = date_stamp + "," + species['id'] + "," + species['commonName'] + "," + str(count) + "\n"
            f = open('/home/pi/BirdWeather/rainbowLorikeetDetected.txt','a')
            f.write(bird_data)
            f.close()
except:
    # no data
    print("no detections in the last hour")

Bird Weather Once Daily - birdWeatherOnceDaily.py

  • This code will record all topSpecies recorded during the day and the number of detections of each species.
  • Just before midnight the birdWeatherOnceDaily.py script is run.
  • It collates the top 60 bird species recorded during the entire day.
  • Total recordings for each bird species are recorded.
  • This should give researcher long term data on the number and population of bird species recorded in an area.

# file name - birdWeatherOnceDaily.py
import requests
import json
import datetime
import plotly
import plotly.graph_objects as go
import pandas

now = datetime.datetime.now()
date_stamp = now.strftime("%Y-%b-%d %H:%M")

query = """query{ 
  station(id: "273")  {
    id
    location
    name
    topSpecies (limit: 60) {
        count
        species {
            id
            commonName
            scientificName
            ebirdUrl
            imageUrl
            wikipediaSummary
        }
     } 
  }
}"""

# Requesting data from BirdWeather.com using API
url = 'https://app.birdweather.com/graphql'
r = requests.post(url, json={'query': query})
data_dict = r.json()["data"]["station"]
#print(data_dict["id"])
topSpecies = data_dict["topSpecies"]
bird_dict = {"last_updated": date_stamp}  # dictionary

total_count = 0
different_bird_species = 0

# Analysing data for top 60 species and saving in file named dailyBirdCount.txt

for species in topSpecies:
    count = species["count"]
    total_count += count
    species = species["species"]
    print(f"species = {species['commonName']}, count = {count}")
    data = str(different_bird_species) + "," + date_stamp + "," + str(species['commonName']) + "," + str(count) + "\n"
    print(f"data = {data}")
    f = open('/home/pi/BirdWeather/dailyBirdCount.txt','a')
    f.write(data)
    f.close()
    different_bird_species += 1
    bird_dict.update({str(species['commonName']): count})

    
print()
print(f"dictionary = {bird_dict}\n")


# Saving BirdWeather.com data in a JSON file
with open("Bird_data.json", "w") as file: 
#Using json.dump() to write the data into a JSON file.    
    json.dump(topSpecies, file)