DIY weather station and property monitoring (built for Raspberry Pi)
- Capturing of Temperature, Humidity, and Snow Depth - stored in MySQL instance
- Simple REST API for exposing captured values is great for exposing to tools like HomeAssistant (with docs about usage through VPN)
- Capture and API set up as two separate systemd services to run in the background on boot
- Github Actions Workflow for automatically publishing changes to weather station (leveraging Tailscale's Github Action to dynamically create nodes marked as ephemeral)
- Support for 4G modem for remote connectivity
- AMD based Linux Debian machine such as Raspberry Pi
- Temp/Humidity - DHT 11
- Snow Depth - Ultrasonic sensor (HC-SR04)
- Raspberry Pi Camera - Arducam IMX 477
- Flash linux machine planned for the weather-station (in my case Raspberry Pi) with a Debian version of linux (NOT Bookworm)
- SSH into the Pi (i.e.
ssh pi@raspberrypi.local
unless you changed defaults) - If you are using any hardware for remote connectivity such as the Sixfab LTE hat - I've found it best to install this before any other dependencies. Follow setup instructions provided by manufacturer - otherwise skip this step.
- Install dependencies including git, python, and maria db:
sudo apt-get install git build-essential python3 python3-pip libgpiod2 mariadb-server mariadb-client libmariadb-dev
- Clone repo
git clone https://github.com/prescottprue/weather-station
- Install python app dependencies:
pip3 install adafruit-blinka adafruit-circuitpython-dht adafruit-circuitpython-sht31d gpiozero mariadb fastapi "uvicorn[standard]" python-dotenv
- Setup MySQL instance:
-
Run
sudo mysql
all following steps will be sql commands -
Setup user with privileges:
create user pi IDENTIFIED by 'mydbpass'; grant all privileges on *.* to 'pi' with grant option;
-
Create
weather
database and measurements table:CREATE DATABASE weather; CREATE TABLE weather.measurements( id BIGINT NOT NULL AUTO_INCREMENT, temp DECIMAL(6,2) NOT NULL, humidity DECIMAL(6,2) NOT NULL, internal_temp DECIMAL(6,2) NOT NULL, internal_humidity DECIMAL(6,2) NOT NULL, snow_depth DECIMAL(6,2), created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY ( id ) );
-
Hit
ctrl + c
to exit mysql
-
- To test API, run:
MARIADB_PASS=mydbpass python3 ./weather-station/main.py
then visithttp://raspberrypi.local:8080
(or whatever the local name or local ip address of your Pi) - Setup and start services to run capture + API in background on boot:
- Write a file containing DB password you picked above (note
tee
is to prevent permission issues):echo "MARIADB_PASS=mydbpass" | sudo tee -a /etc/environment >/dev/null
- Copy service files into systemd folders:
sudo cp /home/pi/weather-station/services/weather-capture.service /etc/systemd/system/weather-capture.service && sudo cp /home/pi/weather-station/services/weather-api.service /etc/systemd/system/weather-api.service
- Reload the daemon:
sudo systemctl daemon-reload
- Enable services:
sudo systemctl enable weather-capture.service && sudo systemctl enable weather-api.service
- Start services:
sudo systemctl start weather-capture.service && sudo systemctl start weather-api.service
- Write a file containing DB password you picked above (note
To set up your weather-station code to update automatically when you push changes:
-
Fork this repo
-
Follow section below about setup of Tailscale
-
Add the following to Tailscale Access Controls:
{ // Define the tags which can be applied to devices and by which users. "tagOwners": { "tag:ci": [], "tag:prod": [], }, // Define users and devices that can use Tailscale SSH. "ssh": [ // Allow all users to SSH into their own devices in check mode. // Comment this section out if you want to define specific restrictions. { "action": "check", "src": ["autogroup:member"], "dst": ["autogroup:self"], "users": ["autogroup:nonroot", "root"], }, // Allow all users and machines with tag:ci to ssh into machines with tag:prod (tag:ci used for machines which deploy from Github Actions) { "action": "accept", "src": ["autogroup:member", "tag:ci"], "dst": ["tag:prod"], "users": ["autogroup:nonroot", "root", "pi"], }, ], }
-
Add a Tailscale oAuth client with
tag:ci
- client id and secret which appear will be saved in next step -
Set the following values within Github Actions Secrets (Settings tab of repo):
TS_OAUTH_CLIENT_ID - Tailscale oauth client id TS_OAUTH_SECRET - Tailscale oauth secert WEATHER_STATION_TAILNET_ADDRESS - address of weather-station machine on tailnet
If you plan to have your weather station on a different network (such as my situation which is a property which does not yet have internet planned to use 4G hat on PI) you can access weather-station data by setting up a VPN. I suggest Tailscale since it is so easy to set up
Make sure you are SSHed into your weather-station then do the following:
- Install tailscale:
curl -fsSL https://tailscale.com/install.sh | sh
- Start tailscale with ssh enabled
sudo tailscale up --ssh --advertise-tags tag:prod
- Approve machine in tailscale if needed and add the tag
prod
Weather station data is exposed in a REST API - this makes it easy for tools like HomeAssistant to connect and pull data.
Use the File Editor to modify your /homeassistant/configuration.yaml
file to add the following:
NOTE: $LOCAL_IP
is the local IP address of the weather station machine (raspberry pi) - this can be found by running ifconfig
within ssh. If you are running Tailscale VPN, this should instead be your device's tailnet URL or IP.
rest:
# Replace $LOCAL_IP with local IP address of weather-station machine - if using Tailscale, this is Tailnet DNS entry or IP
- resource: "http://$LOCAL_IP:8080/latest"
sensor:
- name: "Station Temperature"
unique_id: station-temperature
value_template: "{{ value_json.temp }}"
unit_of_measurement: "°F"
device_class: temperature
- name: "Station Humidity"
unique_id: station-humidity
value_template: "{{ value_json.humidity }}"
unit_of_measurement: "%"
device_class: humidity
- name: "Station Snow Depth"
unique_id: station-snow-depth
icon: mdi:snowflake
value_template: "{{ value_json.snow_depth }}"
unit_of_measurement: "in"
device_class: distance
- name: "Station Last Capture"
unique_id: station-last-capture
icon: mdi:clock
value_template: "{{ as_datetime(value_json.created).astimezone() }}"
device_class: timestamp
If you are running your weather station on a different network than you home assistant instance, you will need to setup Tailscale on your weather-station machine (super easy - see Remote Network section above) as well as install @tsujamin's Home Assistant Tailscale addon (Tailscale addon in store did allow rest connection to access Tailnet).
- Go to Add On Store
- Click "Add Repository"
- Add
https://github.com/tsujamin/hass-addons
repo url - Add "Tailscale" addon from under the
tsujamin's Add-ons
section - Create a new auth key in Tailscale UI
- Set auth key from Tailscale UI in configuration panel of Tailscale addon and disable
userspace_networking
(this is important!) - Save configuration then start Tailscale addon (and make sure
Start on boot
is enabled)
I'm currently using a Raspberry Pi 4 since I plan to add a 4G Hat, but the goal is to keep most of the project generalized to any AMD platform running Linux
- Wind speed/direction
- Rain Sensor
- Camera
- Motion sensor
- Publishing/sharing to weather authority
- Support Bookworm OS version by using python virtual env
- Pipenv or similar for dependency management
- Continue to capture data to machine's memory even if it is offline allowing for later review
- Data pulling can be optimized for network conditions (not necessarily all captures will go over the network)
- For 64bit support it is easiest to go with libcamera - Picam2 is an option, but bumped into some issues getting it working
- No in memory access to image is needed - we just render the most recent file
- Raspberry Pi Org Weather station project - main reference for organization and data storage. Doesn't include networking or extra sensors.
- Raspberry Pi Org Distance Sensor project
- DHT11 Interfacing with Raspberry Pi
- Setup Python script as a service through systemctl
- @tsujamin's Home Assistant Tailscale addon