Adding sensors to a RPi weather station

In the previous posts I set up a Raspberry Pi weather station using a USB radio reciever to pickup the data direct from the sensors. Unfortunately the pressure sensor is located in the base station rather than the outdoor sensors so I cant read it. As a work around I used a BME280 temperature/pressure sensor from Pimoroni.  Although Weewx is capable of running a service to poll the sensor, I found it simplest to grab a reading from the sensor into sdr.py as the recieved packets are processed. The patch is in /usr/share/weewx/user/sdr.py. First you will need to connect up the sensor and install the drivers. I found it useful to install drivers for both Python 2 and 3. You will also need to enable the i2c inteface for the pi. See the instructions on this page. You will need to run both sudo pip install ... and sudo pip3 install.... to get both versions.

Mods to sdr.py

Near the start of sdr.py, where the imports are defined, add code to import the smbus and bme280 libraries:

...
import time
## RWS - BME280 sensor with Pimoroni library
try:
from smbus2 import SMBus
except ImportError:
from smbus import SMBus
...

After the section where various constants are added, include code to initialise the sensor:

...
DRIVER_NAME = 'SDR'

DRIVER_VERSION = '0.77'

# Initialise the BME280 in 'forced' mode
bus = SMBus(1)
bme280 = BME280(i2c_dev=bus)
bme280.setup(mode="forced")
...

Finally, locate the class that handles processing the packets for your sensor (in my case the Bresser6in1Packet.parse_json), add a line to append the sensor reading to the packet:

 @staticmethod
def parse_json(obj):
pkt = dict()
pkt['dateTime'] = Packet.parse_time(obj.get('time'))
pkt['usUnits'] = weewx.METRICWX
pkt['station_id'] = obj.get('id')
pkt['battery'] = obj.get('battery_ok')
pkt['pressure'] = bme280.get_pressure()
......

You can of course add indoor temperature and humidity if you wish.

Oregon scientific and Bresser weather gauge

January 2021

Some notes on how I set up a weather station on a Raspberry Pi zero W using Weewxsoftware, SDR (a software defined radio USB dongle), an Oregon WMR89 and a Bresser 5in1 weather station. The Oregon unit transmits on 433Mhz and is fairly standard. The Bresser unit is newer and, as a result of recent charges in their protocol needs a bit more hacking to get it working.

Antenna lengths

The usb dongle is supplied with a short whip aerial. Its not very critical, but if you need max range, here is the theory.

1/4 wave dipole best when there is an earth plane. 1/2 wave is better when there is no earth plane. Figures below dont take account of speed of light in a wire is less than in a vacuum but none of it is critical.

433Mhz - 173mm for a 1/4 wave whip
868Mhz - 86.3mm

Installation

These notes cover both the Oregon WMR89 sensors and the new version Bresser 5-in-1 weather station.

Follow these instructions to install the modules on the RPi.

https://github.com/weewx/weewx/wiki/sdr-rpi-recipe
https://github.com/weewx/weewx/wiki/sdr-rpi-recipe.

If using the Bresser sensors, make sure you install rtl_433 version 20.11 or later. Earlier versions may not parse Bresser 5in1 correctly. Most recent will handle the Oregon.

Testing rtl_433

Check radio signals being recieved and parsed by rtl_433. For the Bresser station you will need to to specify the frequency on the command line as operates at 868.2Mhz rather than the default 433Mhz for the OregonScientific. Note not all packets include temperature and humidity so be sure to examine a few!

sudo rtl_433 -F json -f 868.2M -s 1M
.....{"time" : "2021-01-15 16:14:34", "model" : "Bresser-6in1", "id" : 541070586, "channel" : 0, "battery_ok" : 1, "sensor_type" : 1, "wind_max_m_s" : 0.000, "wind_avg_m_s" : 0.000, "wind_dir_deg" : 270, "rain_mm" : 6.400, "mic" : "CRC"}

{"time" : "2021-01-15 16:14:46", "model" : "Bresser-6in1", "id" : 541070586, "channel" : 0, "battery_ok" : 1, "temperature_C" : 1.300, "humidity" : 87, "sensor_type" : 1, "wind_max_m_s" : 0.000, "wind_avg_m_s" : 0.000, "wind_dir_deg" : 270, "mic" : "CRC"}

{"time" : "2021-01-15 16:14:58", "model" : "Bresser-6in1", "id" : 541070586, "channel" : 0, "battery_ok" : 1, "sensor_type" : 1, "wind_max_m_s" : 0.000, "wind_avg_m_s" : 0.000, "wind_dir_deg" : 270, "rain_mm" : 6.400, "mic" : "CRC"}

{"time" : "2021-01-15 16:15:10", "model" : "Bresser-6in1", "id" : 541070586, "channel" : 0, "battery_ok" : 1, "temperature_C" : 1.300, "humidity" : 87, "sensor_type" : 1, "wind_max_m_s" : 0.000, "wind_avg_m_s" : 0.000, "wind_dir_deg" : 270, "mic" : "CRC"}

Modify sdr.py for Bresser

The current version of /usr/share/weewx/user/sdr.py includes code to parse the Oregon WMR89 weather station, but not the current version of the Bresser n-in1. You need to add a class to parse the output and also add it to the list of data types in class PacketFactory(). Its very similar to the Bresser 5-in-1. If you cut and paste the code you will need to tidy up the tabs and indentation.

class Bresser6in1Packet(Packet):
# Includes newer versions of 5 in 1 as well as 6 in 1 and 7 in 1.
#{"time" : "2021-01-15 16:14:58", "model" : "Bresser-6in1", "id" : 541070586, "channel" : 0, "battery_ok" : 1, "sensor_type" : 1, "wind_max_m_s" : 0.000, "wind_avg_m_s" : 0.000, "wind_dir_deg" : 270, "rain_mm" : 6.400, "mic" : "CRC"}
#{"time" : "2021-01-15 16:15:10", "model" : "Bresser-6in1", "id" : 541070586, "channel" : 0, "battery_ok" : 1, "temperature_C" : 1.300, "humidity" : 87, "sensor_type" : 1, "wind_max_m_s" : 0.000, "wind_avg_m_s" : 0.000, "wind_dir_deg" : 270, "mic" : "CRC"}

IDENTIFIER = "Bresser-6in1"
@staticmethod
def parse_json(obj):
pkt = dict()
pkt['dateTime'] = Packet.parse_time(obj.get('time'))
pkt['usUnits'] = weewx.METRICWX
pkt['station_id'] = obj.get('id')
pkt['channel'] = obj.get('channel')
pkt['battery'] = obj.get('battery_ok')
pkt['sensor_type'] = obj.get('sensor_type')
# deal with different labels from rtl_433
for dst, src in [('temperature_C', 'temperature_C'),
('humidity','humidity'),
('moisture','moisture'),
('wind_speed', 'wind_avg_m_s'),
('gust_speed', 'wind_max_m_s'),
('wind_dir_deg','wind_dir_deg'),
('rain_total', 'rainfall_mm'),
('rain_total', 'rain_mm'),
('uv','uv')]:
if src in obj:
pkt[dst] = Packet.get_float(obj,src)
return Bresser6in1Packet.insert_ids(pkt)

@staticmethod
def insert_ids(pkt):
station_id = pkt.pop('station_id', '0000')
pkt = Packet.add_identifiers(pkt, station_id, Bresser6in1Packet.__name__)
return pkt
class PacketFactory(object):
KNOWN_PACKETS = [
AcuriteAtlasPacket,
...
Bresser6in1Packet,
...

Testing sdr.py

Your command line to test sdr.py with the Bresser station at the will look like:
sudo PYTHONPATH=/usr/share/weewx python3 /usr/share/weewx/user/sdr.py --cmd="rtl_433 -M utc -F json -f 868M"
The output will look something like this:

out:['{
"time" : "2021-01-17 11:48:15",
"model" : "Bresser-6in1",
"id" : 541070586,
"channel" : 0,
"battery_ok" : 1,
"temperature_C" : 7.100,
"humidity" : 69,
"sensor_type" : 1,
"wind_max_m_s" : 3.000,
"wind_avg_m_s" : 2.900,
"wind_dir_deg" : 270,
"mic" : "CRC"
}\n']

parsed: {
'dateTime': 1610884095, 'usUnits': 17,
'battery.541070586.Bresser6in1Packet': 1,
'temperature_C.541070586.Bresser6in1Packet': 7.1,
'humidity.541070586.Bresser6in1Packet': 69.0,
'wind_speed.541070586.Bresser6in1Packet': 2.9,
'gust_speed.541070586.Bresser6in1Packet': 3.0,
'wind_dir_deg.541070586.Bresser6in1Packet': 270.0
}

You can now edit weewx.conf to suit. Its located in

/etc/weewx/weewx.conf

Here is my section for SDR. Commands for the Oregon WMR89 are commented out.

[SDR]
# This section is for the software-defined radio driver.

# The driver to use
driver = user.sdr
#cmd = rtl_433 -M utc -F json
cmd = rtl_433 -M utc -F json -f868.2M
path = /usr/local/bin/
log_unknown_sensors = True
log_unmapped_sensors = True

[[sensor_map]]
# Oregon WMR89
# windSpeed = wind_speed.0:215.OSWGR800Packet
# windGust = wind_gust.0:215.OSWGR800Packet
# windDir = wind_dir.0:215.OSWGR800Packet
# windBatteryStatus = battery.0:215.OSWGR800Packet
# outTemp = temperature.1:246.OSTHGR810Packet
# outHumidity = humidity.1:246.OSTHGR810Packet
# outTempBatteryStatus = battery.1:246.OSTHGR810Packet
# pressure = pressure.1:246.OSTHGR810Packet
# rainBatteryStatus = battery.0:122.OSPCR800Packet
# rainRate = rain_rate.0:122.OSPCR800Packet
# rain_total = rain.0:122.OSPCR800Packet

# Bresser 5in1 (new format)
windSpeed = wind_speed.541070586.Bresser6in1Packet
windGust = gust_speed.541070586.Bresser6in1Packet
windDir = wind_dir_deg.541070586.Bresser6in1Packet
outTemp = temperature_C.541070586.Bresser6in1Packet
outHumidity = humidity.541070586.Bresser6in1Packet
pressure = pressure.541070586.Bresser6in1Packet

[[deltas]]
rain = rain_total

Finishing Up

Finally, the default web page does not autorefresh. To make it easier to reload the page I made the station name in the masthead into a link to auto refresh script. Its like old school tapping a barometer to see if the pressure is falling. Although a lot can be configured through weewx.conf, this change has to be made in the skin. The default is located in /etc/weewx/skins/Seasons. The page index.html.tmpl calls  titlebar.inc to build the masthead. Wrapping a <a> element with some javascript around the relevant div gives the wanted effect:

....
<div id="title_bar">

<a HREF="javascript:history.go(0)">
<div id="title">
<h1 class="page_title">$station.location</h1>
<p class="lastupdate">$current.dateTime</p>
</div>
</a>
....