Henry Negretti and Joseph Zambra, renowned scientific instrument makers to Queen Victoria, invented the 'Zambretti Forecaster'.
This weird contraption used a series of overlaid discs and operated much like a slide rule. With just wind and barometer readings, the 'Zambretti' could produce 90% accurate 12 hour weather forecasts.
This fun little project attempts to squeeze this old 'Zambretti Forecaster' into an 8K ATtiny.
The AlgorithmMy attempt of the Zambretti algorithm is based on https://github.com/sassoftware/iot-zambretti-weather-forcasting and, mostly, this Javascript implementation http://www.beteljuice.co.uk/zambretti/forecast.html
The original algorithm requires a number of readings:
current pressure - Taken from the BMP280 sensor. Converted to sea level adjusted pressure
trend - whether the pressure is rising, falling or steady, compared to a reading 3 hours earlier
season - is it Spring/Summer?
wind direction - Used in the original, I've removed the wind direction from my project - probably losing the famed 90% accuracy, oh well.
These readings are used to calculate an index into one of 3 tables (one for each trend) which in turn point to one of 26 possible forecasts:
"Settled fine"
"Fine weather"
"Becoming fine"
"Fine, becoming less settled"
"Fine, possible showers"
"Fairly fine, improving"
"Fairly fine, possible showers early"
"Fairly fine, showery later"
"Showery early, improving"
"Changeable, mending"
"Fairly fine, showers likely"
"Rather unsettled clearing later"
"Unsettled, probably improving"
"Showery, bright intervals"
"Showery, becoming less settled"
"Changeable, some rain"
"Unsettled, short fine intervals"
"Unsettled, rain later"
"Unsettled, some rain"
"Mostly very unsettled"
"Occasional rain, worsening"
"Rain at times, very unsettled"
"Rain at frequent intervals"
"Rain, very unsettled"
"Stormy, may improve"
"Stormy, much rain"
Instead of keeping track of the seasons or the current month with an RTC, I've added a physical "It's Summer!" toggle switch.
Ideally the Zambretti works best for the northern hemisphere and apparently best used at 9am. Let's see how it goes.
Connecting everythingFor the display I chose a 128x32 SSD1306 OLED, a pretty cheap 5V I2C display. I2C is important here, that's just two wires which can be shared with the pressure sensor. I2C's SDA and SCL are connected to the ATtiny's pins 5 & 7.
For the pressure sensor I used a BMP280 (I couldn't find any BMP180s) again it's 5V and I2C, so again, that's pins 5 & 7 on the ATtiny.
A toggle switch - used to indicate the season - is connected to the ATtiny's pin 2 and 5V and pulled down with a suitable resistor. And, not shown on the schematic, it's always a good idea to throw in a 100nf decoupling capacitor.
This should be fairly straightforward (Zambretti calculations aside). It needs to:
- take a pressure reading
- compare with a previous reading to determine the trend
- convert to sea level adjusted pressure
- read the status of a toggle switch to determine the season
- calculate the forecast (the Zambretti magic)
- show the forecast on the display
To read the sensor and use the display I'll use the following libraries:
OLED display libraryAs space is a premium on the ATtiny I needed a barebones cut back OLED library. I went with TinyOzOLED, originally by Oscar Liang modified for ATtiny and TinyWire by Andreas Spiess (the guy with the Swiss accent).
I made some slight modifications to the TinyOzOLED library. I altered it for my smaller 128x32 display. I added a larger font and added support for long text scrolling. My variation can be found here : https://github.com/limpfish/TinyOzOledlimpfish and here's an example of the scrolling : https://github.com/limpfish/attiny_scroll/
Pressure sensor libraryAgain, I wanted something minimal that used TinyWire. I decided to use Forced-BME280 by Jochem van Kranenburg. It's a small and efficient library https://github.com/JVKran/Forced-BME280
Pressure at sea levelThe Zambretti code expects the pressure reading to be 'equivalent sea level pressure'.
The formula I used to to convert BMP280 output to sea level pressure is:
seaLevelPressure = (((pressure * 100.0)/pow((1-((float)(ELEVATION))/44330), 5.255))/100.0)
Determining the trendTo get the pressure trend (rising, falling or steady). I need to compare a reading with one of 3 hours ago. I could just take a reading every 3 hours and compare but that would make for a slow weather update. Instead I decided take a reading every 30 minutes and log it in a circular array of 7 elements. I can compare the newest reading with the first in the list which would be 3 hours old.... Fingers crossed, as I'm not sure of the accuracy of millis() on an ATtiny. I'm sure if you were doing this properly you would use something more accurate.
Final buildSqueezing everything into 8K became a challenge. With liberal use of PROGMEM and a greatly reduced font set it compiles fine. I'm sure there are lots of optimisations that can be made, the pressure to sea-level conversion for one, removal of floats in the Zambretti calculation perhaps but as it stands it just about fits.
Without wind direction there's a chunk of the Zambretti code unused - I've commented out the wind direction stuff - and I'm unsure as to whether the full range of forecasts will be shown without it. But never mind, this project is just a bit of fun, primarily an exercise in cramming as much as I can a little ATtiny.
Finally, I went full 'brass rod freeform' on it and mounted it in a 3d printed 'weather cloud' on a piece of wood.
Overall, it seems to work well, and just about matches the current weather, which, being in the North West of England, tends to be a near constant "UNSETTLED RAIN LATER".
Comments