I’ve always wanted to get back to my technical roots and work on electronics projects, however, life somehow always seems to get in the way. The Nationwide/Worldwide lockdown has been in full swing for months now which means lately I’ve had a lot more time to work on various projects such as a podcast, and fooling around with solar power for my garden shed.

After I finished working on my solar project I needed something else to do and had the idea of building a weather station. I scoured the internet looking for examples and parts. To my surprise, there were lots of options available, from buying each individual component separately all the way up to completely built. I was looking for something in the middle, ultimately I settled on Sparkfun weatherbit. It has a temperature sensor, humidity sensor, soil temperature, moisture sensors, more traditional weather-related sensors like wind speed and direction sensors as well as a few other sensors such as an accelerometer.

All controlled by a microcontroller, the BBC Microbit. Now this in itself is awesome, however, there was no built-in method for exporting that data in realtime since the supported methods of communication are extremely limited, Bluetooth, serial, and writing to a micro SD card. I knew I wanted to do more than store the weather data on an SD card so I decided to use a Raspberry Pi Zero W and some programming to scrape the serial port and then ship that data to a database for realtime weather data. I also had the thought of possibly uploading that data to Weather Underground or perhaps even make a small website that would display the latest data to anyone that came across it.

let humid = 0
let tempF = 0
let preasure = 0
let temp = 0
let current_WindDirection_List = ""
let current_WindSpeed = 0
let rain = 0
let item = false
let itemT = 0
let rainData = " "
serial.redirectToUSB()
weatherbit.startWindMonitoring()
weatherbit.startWeatherMonitoring()
weatherbit.startRainMonitoring()
basic.forever(function () {
    current_WindSpeed = Math.trunc(weatherbit.windSpeed())
    current_WindDirection_List = weatherbit.windDirection()
    temp = Math.idiv(weatherbit.temperature(), 100)
    preasure = Math.idiv(weatherbit.pressure(), 25600)
    tempF = temp * 9 / 5 + 32
    humid = Math.idiv(weatherbit.humidity(), 1024)
    rain = weatherbit.rain()
    if (rain > 1) {
        rainData = rain.toString()
    } else {
        rainData = null
    }
    serial.writeLine("" + current_WindSpeed + "," + current_WindDirection_List + "," + temp + "," + tempF + "," + humid + "," + preasure + "," + rainData)
    basic.pause(1 * 3000)
})

Above is the Javascript that I use for the Microbit. It has some bugs, especially around the rain sensor, But the plan is to keep working on this for the foreseeable future and I welcome pull requests.

def start():
    ser = serial.Serial(serial_port, serial_rate, timeout=2)
    ser.reset_input_buffer()
    ser.reset_output_buffer()

The code above starts collecting the data over the serial port. In Linux I ran into a serial buffer issue hence the reset calls.

while True:
        json_data = {}
        data = ser.readlines()
        try:
            goodData = data[0].decode("utf-8").rstrip().split(',')
            json_data = {"timestamp": time.time(),
                         "wind_Speed": mak_num(goodData[0]),
                         "wind_dir": goodData[1],
                         "temp_c": mak_num(goodData[2]),
                         "temp_f": mak_num(goodData[3]),
                         "humidity": mak_num(goodData[4]),
                         "baro": mak_num(goodData[5]),
                         "rain": mak_num(goodData[6])
                         }


        except:
            ser.reset_input_buffer()
            ser.reset_output_buffer()
            time.sleep(5)
        rabbit = RabbitMq()
        rabbit.publish(json_data)

    ser.close()

That bit of code is where the magic begins. It’s basically a forever While loop that scrapes the serial port. Again occasionally I hit the serial buffer issue so I have some error handling that resets the buffers, waits five seconds then starts the loop over. On each successful iteration of the While loop, the data is sent to Rabbitmq.

class RabbitMq(object):
    def __init__(self, queue=pika_queue):
        self._connection = pika.BlockingConnection(pika.ConnectionParameters(host=pika_server, credentials=creds))
        self._channel = self._connection.channel()
        self.queue = queue
        self._channel.queue_declare(queue=self.queue, durable=True)
        self._channel.exchange_declare(exchange=pika_exchange, exchange_type='direct', passive=False, durable=True,
                                       auto_delete=False, internal=False)

    def publish(self, payload={}):
        try:
            self._channel.basic_publish(exchange=pika_exchange, routing_key=pika_queue, body=json.dumps(payload))
            self._connection.close()
        except (UnroutableError, NackError) as e:
            print('Rabbit MQ Error', e)

That short bit of code takes in the weather data and sends it to RabbitMq where it is stored until consumed buy a telegraf. Telegraf then stores the data in an Influxdb database where I can finally retrieve the data. I use Grafana to make a dashboard of current atmosphere data.

My Grafana Weather Dashboard

Overall this has been a fun and somewhat challenging project. But I highly recommend it especially if you’re trying to expose your children to programming and or electronics.