You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
942 lines
38 KiB
942 lines
38 KiB
<!DOCTYPE html>
|
|
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="generator" content="pandoc" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
|
|
<meta name="author" content="M.T. Konstapel" />
|
|
<meta name="dcterms.date" content="2024-05-02" />
|
|
<title>Weather station</title>
|
|
<link rel="stylesheet" href="./css/mvp.css" />
|
|
<style type="text/css">
|
|
:root {
|
|
--width-content: 1080px;
|
|
}
|
|
|
|
nav {
|
|
justify-content: space-around;
|
|
}
|
|
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<header id="title-block-header">
|
|
<nav id="TOC">
|
|
<ul>
|
|
<li>
|
|
<a href="#">Index</a>
|
|
<ul>
|
|
<li><a href="#why-do-you-need-a-weather-station"
|
|
id="toc-why-do-you-need-a-weather-station">Why do you need a
|
|
weather station?</a></li>
|
|
<li><a href="#what-should-a-weather-station-measure"
|
|
id="toc-what-should-a-weather-station-measure">What should a
|
|
weather station measure?</a></li>
|
|
<li><a href="#what-sensors-do-we-need"
|
|
id="toc-what-sensors-do-we-need">What sensors do we
|
|
need?</a></li>
|
|
<li><a
|
|
href="#what-to-use-for-communication-with-the-outside-world"
|
|
id="toc-what-to-use-for-communication-with-the-outside-world">What
|
|
to use for communication with the outside world?</a></li>
|
|
<li><a href="#what-else" id="toc-what-else">What
|
|
else?</a></li>
|
|
<li><a href="#theory-of-operation---hardware"
|
|
id="toc-theory-of-operation---hardware">Theory of operation
|
|
- Hardware</a></li>
|
|
<li><a href="#theory-of-operation---software"
|
|
id="toc-theory-of-operation---software">Theory of operation
|
|
- Software</a></li>
|
|
<li><a href="#prototype"
|
|
id="toc-prototype">Prototype</a></li>
|
|
<li><a href="#specifications"
|
|
id="toc-specifications">Specifications</a></li>
|
|
<li><a href="#schematic"
|
|
id="toc-schematic">Schematic</a></li>
|
|
<li><a href="#problems-i-encounter-after-four-months-of-use"
|
|
id="toc-problems-i-encounter-after-four-months-of-use">Problems
|
|
I encounter after four months of use</a></li>
|
|
<li><a href="#software-dependencies"
|
|
id="toc-software-dependencies">Software
|
|
dependencies</a></li>
|
|
<li><a href="#license" id="toc-license">License</a></li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<a href="./weather_station.pdf">PDF version</a>
|
|
</li>
|
|
<li>
|
|
<a href="https://git.meezenest.nl/marcel/weather_station">Git repo</a>
|
|
</li>
|
|
<li>
|
|
<a href="https://meezenest.nl/mees/weather_station.html">Back</a>
|
|
</li>
|
|
</ul>
|
|
|
|
<a href="https://www.meezenest.nl/mees/"><img alt="Logo" src="./images/mees_logo.svg" height="70"></a>
|
|
</nav>
|
|
<h1 class="title">Weather station</h1>
|
|
<p class="subtitle">with ModBus RTU interface</p>
|
|
<p class="author">M.T. Konstapel</p>
|
|
<p class="date">2024-05-02</p>
|
|
<p><a href="./weather_station.pdf"><i>PDF version</i></a></p>
|
|
</header>
|
|
<main>
|
|
<article>
|
|
<p><b>Abstract </b><p>A weather station build around a SparkFun Weather
|
|
Meter Kit (SEN-15901). The temperature, humidity and pressure are
|
|
measured with I2C sensors housed in an RS1 Passive Radiation Shield from
|
|
Garni. The data can be read via an RS485 ModBus RTU interface. The main
|
|
processor is an Arduino Pro Mini (ATmega328P 5V@16MHz)</p></p>
|
|
<h1 id="why-do-you-need-a-weather-station">Why do you need a weather
|
|
station?</h1>
|
|
<p>Well, you don’t…because if you want to know the weather, you look on
|
|
your phone. So why bother than? Because since the beginning of time,
|
|
people are obsessed with the weather. When I was a child, my grandmother
|
|
was measuring the temperature and rainfall on a daily basis. My
|
|
grandfather had an allotment, so he also was very interested in the
|
|
weather. The first thing my father read in the newspaper was the weather
|
|
report and the last thing he watched on the television was… the weather
|
|
report. And every hour he listed to the weather report on the radio. If
|
|
he talked to someone he always started the conversation by talking about
|
|
the weather. And when I open a new browser window, it automatically
|
|
opens the weather page.</p>
|
|
<p>So the weather is fascinating and taking your own measurements is a
|
|
lot of fun.</p>
|
|
<h1 id="what-should-a-weather-station-measure">What should a weather
|
|
station measure?</h1>
|
|
<p>As my grandmother already measured temperature and rainfall, these
|
|
ones are mandatory. And for the rest I looked at the website of the
|
|
Dutch meteorological institute. They measure wind direction, average
|
|
wind speed of the last 10 minutes, maximum wind gust of the last 10
|
|
minutes, rainfall of the last hour as well as the last 24 hours,
|
|
temperature, humidity and atmospheric pressure.</p>
|
|
<h3 id="measurements">Measurements</h3>
|
|
<ul>
|
|
<li>Wind direction</li>
|
|
<li>Wind speed (average of last 10 minutes)</li>
|
|
<li>Wind gust (last 10 minutes)</li>
|
|
<li>Rain fall (last hour)</li>
|
|
<li>Rain fall (last 24 hours)</li>
|
|
<li>Temperature</li>
|
|
<li>Humidity</li>
|
|
<li>Atmospheric pressure</li>
|
|
</ul>
|
|
<h1 id="what-sensors-do-we-need">What sensors do we need?</h1>
|
|
<h2 id="wind-and-rain">Wind and rain</h2>
|
|
<p>Measuring wind and rain is difficult. Well, not if you want to do it
|
|
by hand: place a beaker on the ground and wait a day. Than measure the
|
|
amount of water in it. Empty the beaker and start again. And for the
|
|
wind, you can stick a pole in the ground and attach a ribbon to it. The
|
|
direction of the wind can than be made visible. And even the wind speed
|
|
can be determent by measuring the angle between the ribbon and the
|
|
ground.</p>
|
|
<p>But how to do this automatically? Of course you can buy a fancy
|
|
commercial weather station. These are surprisingly cheap these days. But
|
|
that’s not a challenge. Besides, than you buy into a proprietary
|
|
ecosystem. And it probably only works when connected to the cloud. No
|
|
thanks!</p>
|
|
<p>Building from scratch is an option, but I am an electronic engineer,
|
|
not a mechanical one. I can imagine that won’t be a success. Besides
|
|
going the professional route, which is ridiculously expensive, there is
|
|
really only one option left: the SparkFun SEN-15901 Weather Meter.</p>
|
|
<figure>
|
|
<img src="./images/SparkFun-Weather_Meter.jpg"
|
|
title="SparkFun Weather Meter" alt="SparkFun Weather Meter" />
|
|
<figcaption aria-hidden="true">SparkFun Weather Meter</figcaption>
|
|
</figure>
|
|
<p>But this contraption does not come with any signal conditioning. We
|
|
have to make some kind of interface. Luckily, Sparkfun provides an
|
|
Arduino library, so we only have to connect the SEN-15901 to an Arduino
|
|
and run the code.</p>
|
|
<h2 id="temperature-humidity-and-air-pressure">Temperature, humidity and
|
|
air pressure</h2>
|
|
<p>These three are easy: there are a lot of I2C chips capable of
|
|
measuring these parameters. I choose the Silicon Labs Si7021 for
|
|
humidity and temperature and the Bosch BMP280 for pressure. Just hook
|
|
them up to the Arduino’s I2C bus, load the available libraries and Bob’s
|
|
your uncle.</p>
|
|
<p>To mount these sensors on the same mast as the SparkFun weather meter
|
|
I use the RS1 passive radiation shield from Garni.</p>
|
|
<figure>
|
|
<img src="./images/garni_rs1.jpg"
|
|
title="Garni RS1 Passive Radiation Shield"
|
|
alt="Garni RS1 Passive Radiation Shield" />
|
|
<figcaption aria-hidden="true">Garni RS1 Passive Radiation
|
|
Shield</figcaption>
|
|
</figure>
|
|
<h3 id="sensors">Sensors</h3>
|
|
<ul>
|
|
<li>SparkFun SEN-15901 Weather Station</li>
|
|
<li>Silicon Labs Si7021</li>
|
|
<li>Bosch BMP280</li>
|
|
</ul>
|
|
<h1 id="what-to-use-for-communication-with-the-outside-world">What to
|
|
use for communication with the outside world?</h1>
|
|
<p>Most consumer grade weather stations (and almost all other consumer
|
|
grade goods for that matter) use proprietary interfaces and protocols.
|
|
Probably to annoy the more technical skilled customer as you are not
|
|
able to interface these devices with other brands or self build systems.
|
|
I really hate that practice, so I won’t do that. Instead I will
|
|
implement a ModBus RTU interface. Dating back to 1979, this is the
|
|
industrial standard for communication between devices. And if the
|
|
professionals all use it, why not use it for this weather station?</p>
|
|
<h2 id="modbus">ModBus</h2>
|
|
<p>ModBus is a client/server data communications protocol in the
|
|
application layer of the OSI model. ModBus can work over several
|
|
different physical interfaces. For this application I will use an RS-485
|
|
interface. This interface is easy to implement and cables can be very
|
|
long, making it easy to locate the weather station. ModBus is a
|
|
lightweight protocol which can comfortably fit inside an under-powered
|
|
micro-controller like an Atmel ATmega328P. A simple RS-485 to USB dongle
|
|
connected to a PC is all you need to read the values from the weather
|
|
station.</p>
|
|
<h1 id="what-else">What else?</h1>
|
|
<p>Not much to be honest. Almost everything can be done in software. Of
|
|
course we need a power supply. And preferably a reverse polarity
|
|
protection. An input voltage of 12 Volt is convenient. 12 Volt power
|
|
bricks can be found in every charity shop and you can also use a 12 Volt
|
|
lead acid or lithium battery to power the weather station.</p>
|
|
<h1 id="theory-of-operation---hardware">Theory of operation -
|
|
Hardware</h1>
|
|
<figure>
|
|
<img src="./images/block_diagram.svg"
|
|
title="Block diagram of weather station"
|
|
alt="Block diagram of weather station" />
|
|
<figcaption aria-hidden="true">Block diagram of weather
|
|
station</figcaption>
|
|
</figure>
|
|
<h2 id="wind-speed">Wind speed</h2>
|
|
<p>Measuring the wind speed is done by a cup anemometer. It consisted of
|
|
three or four hemispherical cups on horizontal arms mounted on a
|
|
vertical shaft. The air flow past the cups in any horizontal direction
|
|
turned the shaft at a rate roughly proportional to the wind’s speed.
|
|
Every rotation, a magnet passes alongside a reed switch. The rate at
|
|
which the reed switch opens en closes is a measure of the wind
|
|
speed.</p>
|
|
<figure>
|
|
<img src="./images/sparkfun_cup_anemometer.jpg" title="Cup anemometer"
|
|
alt="Cup anemometer" />
|
|
<figcaption aria-hidden="true">Cup anemometer</figcaption>
|
|
</figure>
|
|
<p>By connecting one side of the reed switch to ground and the other via
|
|
a pull-up resistor to the supply voltage the mechanical switching action
|
|
is translated to an electrical pulse signal. This pulse can be read by a
|
|
micro-controller.</p>
|
|
<figure>
|
|
<img src="./images/diagram_cup_anemometer.svg"
|
|
title="Cup anemometer: theory of operation"
|
|
alt="Cup anemometer: theory of operation" />
|
|
<figcaption aria-hidden="true">Cup anemometer: theory of
|
|
operation</figcaption>
|
|
</figure>
|
|
<h2 id="wind-direction">Wind direction</h2>
|
|
<p>Measuring the wind direction is done by a wind vane. It consists of a
|
|
vertical blade mounted on a vertical shaft. Because the blade can turn,
|
|
it will always find the position of the least air resistance. The shape
|
|
of the blade is chosen so that it will always points directly to the
|
|
wind. A magnet mounted on the shaft rotates past several reed switches.
|
|
The switch that is closest to the magnet will close. If the magnet is
|
|
precisely between two reed switches both switches will close increasing
|
|
the resolution of the wind vane.</p>
|
|
<figure>
|
|
<img src="./images/sparkfun_wind_vane.jpg" title="Wind vane"
|
|
alt="Wind vane" />
|
|
<figcaption aria-hidden="true">Wind vane</figcaption>
|
|
</figure>
|
|
<p>Each reed switch is connected to a resistor and every resister has a
|
|
different value. The total resistance of the network will change
|
|
according to the wind direction. By connecting one side of the network
|
|
to ground and the other side via a resistor to VCC, a resisive divider
|
|
in made. This resistive divider converts the variable resistance to an
|
|
analog voltage which can be sampled by the A/D converter of a
|
|
micro-controller.</p>
|
|
<figure>
|
|
<img src="./images/diagram_wind_vane.svg"
|
|
title="Wind vane: theory of operation"
|
|
alt="Wind vane: theory of operation" />
|
|
<figcaption aria-hidden="true">Wind vane: theory of
|
|
operation</figcaption>
|
|
</figure>
|
|
<table>
|
|
<thead>
|
|
<tr class="header">
|
|
<th>Direction</th>
|
|
<th>Resistance</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr class="odd">
|
|
<td>0°</td>
|
|
<td>33kΩ</td>
|
|
</tr>
|
|
<tr class="even">
|
|
<td>22.5°</td>
|
|
<td>6.57kΩ</td>
|
|
</tr>
|
|
<tr class="odd">
|
|
<td>45°</td>
|
|
<td>8.2kΩ</td>
|
|
</tr>
|
|
<tr class="even">
|
|
<td>67.5°</td>
|
|
<td>891Ω</td>
|
|
</tr>
|
|
<tr class="odd">
|
|
<td>90°</td>
|
|
<td>1kΩ</td>
|
|
</tr>
|
|
<tr class="even">
|
|
<td>112.5°</td>
|
|
<td>688Ω</td>
|
|
</tr>
|
|
<tr class="odd">
|
|
<td>135°</td>
|
|
<td>2.2kΩ</td>
|
|
</tr>
|
|
<tr class="even">
|
|
<td>157.5°</td>
|
|
<td>1.41kΩ</td>
|
|
</tr>
|
|
<tr class="odd">
|
|
<td>180°</td>
|
|
<td>3.9kΩ</td>
|
|
</tr>
|
|
<tr class="even">
|
|
<td>202.5°</td>
|
|
<td>3.14kΩ</td>
|
|
</tr>
|
|
<tr class="odd">
|
|
<td>225°</td>
|
|
<td>16kΩ</td>
|
|
</tr>
|
|
<tr class="even">
|
|
<td>247.5°</td>
|
|
<td>14.12kΩ</td>
|
|
</tr>
|
|
<tr class="odd">
|
|
<td>270°</td>
|
|
<td>120kΩ</td>
|
|
</tr>
|
|
<tr class="even">
|
|
<td>292.5°</td>
|
|
<td>42.12kΩ</td>
|
|
</tr>
|
|
<tr class="odd">
|
|
<td>315°</td>
|
|
<td>64.9kΩ</td>
|
|
</tr>
|
|
<tr class="even">
|
|
<td>337.5°</td>
|
|
<td>21.88kΩ</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<h2 id="rain-fall">Rain fall</h2>
|
|
<p>Measuring the amount of rain fall is done by a self-emptying tipping
|
|
bucket. Rainwater is collected and funneled to a tipping bucket. The
|
|
bucket tips over when a certain amount of water is collected. The bucket
|
|
drains and a second bucket is automatically placed under the funnel.
|
|
When a certain amount of water is collected in this second bucket it
|
|
will tip over and the first bucket is raised again.</p>
|
|
<figure>
|
|
<img src="./images/sparkfun_rain_meter_inside.jpg" title="Rain meter"
|
|
alt="Rain meter" />
|
|
<figcaption aria-hidden="true">Rain meter</figcaption>
|
|
</figure>
|
|
<p>Every time the bucket tips over a magnet passes by a reed switch,
|
|
which closes and opens again. As with the cup anemometer this mechanical
|
|
movement can be translated to an electrical pulse by connecting one side
|
|
of the switch to ground and the other side via a pull-up resistor to
|
|
VCC. This pulse can than be read by a micro-controller.</p>
|
|
<p><sup>NOTE</sup> The rain meter is very sensitive: even a small amount
|
|
of movement and the bucket tips over. Mounting the rain meter in the
|
|
mast together with the wind meters can cause false triggers from the
|
|
rocking motion of the mast.</p>
|
|
<figure>
|
|
<img src="./images/diagram_rain_meter.svg"
|
|
title="Rain meter: theory of operation"
|
|
alt="Rain meter: theory of operation" />
|
|
<figcaption aria-hidden="true">Rain meter: theory of
|
|
operation</figcaption>
|
|
</figure>
|
|
<h2 id="humidity">Humidity</h2>
|
|
<p>Measuring the relative humidity is done by an electronic sensor based
|
|
on capacitive sensing using polymeric dielectrics. The humidity sensor
|
|
is a small capacitor consisting of a hygroscopic dielectric material
|
|
placed between a pair of electrodes. Absorption of moisture by the
|
|
sensor results in an increase in sensor capacitance. The opposite is
|
|
also true: when the moisture disappears, sensor capacitane decreases.
|
|
There is a direct relationship between relative humidity, the amount of
|
|
moisture present in the sensor, and the sensor capacitance. The relative
|
|
humidity is defined as the ratio of the amount of water vapor in the air
|
|
at a specific temperature to the maximum amount that the air could hold
|
|
at that temperature, expressed as a percentage. As the humidity sensor
|
|
has a build in temperature sensor, it can calculate the relative
|
|
humidity.</p>
|
|
<figure>
|
|
<img src="./images/capacitive_humidity_sensor.png"
|
|
title="Humidity sensor" alt="Humidity sensor" />
|
|
<figcaption aria-hidden="true">Humidity sensor</figcaption>
|
|
</figure>
|
|
<p>The Si7021 humidity sensor has an I²C bus for communication with a
|
|
micro-controller.</p>
|
|
<figure>
|
|
<img src="./images/Si7021_block_diagram.png"
|
|
title="Humidity sensor: block diagram"
|
|
alt="Humidity sensor: block diagram" />
|
|
<figcaption aria-hidden="true">Humidity sensor: block
|
|
diagram</figcaption>
|
|
</figure>
|
|
<h2 id="temperature">Temperature</h2>
|
|
<p>Measuring the temperature is done by the build in temperature sensor
|
|
of the humidity sensor. This sensor is used by the humidity sensor to
|
|
calculate the relative humidity. But as this sensor is very accurate it
|
|
can be used for ambient temperature measurments.</p>
|
|
<h2 id="atmospheric-pressure">Atmospheric pressure</h2>
|
|
<p>Measuring the atmospheric pressure is done by an electronic sensor
|
|
based on a piezo-resistive pressure sensing element. The piezo-resistive
|
|
effect is a change in the electrical resistivity of a semiconductor or
|
|
metal when mechanical strain is applied. In this case the strain comes
|
|
from the atmospheric pressure. The sensor measures the resistance which
|
|
is proportional to the atmospheric pressure.</p>
|
|
<figure>
|
|
<img src="./images/piezo_resistive_pressure_sensor.png"
|
|
title="Piezo-resistive pressure sensor"
|
|
alt="Piezo-resistive pressure sensor" />
|
|
<figcaption aria-hidden="true">Piezo-resistive pressure
|
|
sensor</figcaption>
|
|
</figure>
|
|
<p>The BMP280 pressure sensor has an on board temperature sensor which
|
|
can also be used to measure the ambient temperature. As this sensor is
|
|
less accurate compared to the sensor of the Si7021 humidity sensor, the
|
|
sensor is only used as a backup sensor. The BMP280 has an I²C bus for
|
|
communication with a micro-controller.</p>
|
|
<figure>
|
|
<img src="./images/BMP280_block_diagram.png"
|
|
title="Pressure sensor: block diagram"
|
|
alt="Pressure sensor: block diagram" />
|
|
<figcaption aria-hidden="true">Pressure sensor: block
|
|
diagram</figcaption>
|
|
</figure>
|
|
<h2 id="illumination">Illumination</h2>
|
|
<p>This sensor is still under development.</p>
|
|
<h2 id="modbus-interface">ModBus interface</h2>
|
|
<p>The RS-485 interface is build with a MAX485E driver chip from Maxim
|
|
Integrated. Nothing much to say as the implementation is pretty much
|
|
following the typical application from the datasheet.</p>
|
|
<figure>
|
|
<img src="./images/rs-485.svg" title="RS-485 interface"
|
|
alt="RS-485 interface" />
|
|
<figcaption aria-hidden="true">RS-485 interface</figcaption>
|
|
</figure>
|
|
<p>If the device is the first or last device on the RS-485 bus, a 120
|
|
Ohm termination resistor can be enabled by placing a jumper on header
|
|
J7.</p>
|
|
<p>The Arduino micro-controller can be programmed via an in circuit
|
|
programmer, which shares the serial port with the MAX485E. Resistor R5
|
|
isolates the output of the MAX485 from the signal of the programmer.</p>
|
|
<h2 id="i²c-bus">I²C bus</h2>
|
|
<p>The I²C bus is integrated in the micro-controller. But because the
|
|
micro-controller uses a power supply of 5 Volt and the I²C sensors use
|
|
3.3 Volt a bidirectional level shifter is needed. This way the sensors
|
|
can be used on the 5V I²C bus without the risk of damaging the
|
|
sensors.</p>
|
|
<figure>
|
|
<img src="./images/i2c_bus.svg" title="I²C bus level shifter"
|
|
alt="I²C bus level shifter" />
|
|
<figcaption aria-hidden="true">I²C bus level shifter</figcaption>
|
|
</figure>
|
|
<p>Let’s assume the I²C signal lines on either end of the MOSFETs are
|
|
either outputting a logic high or is configured as an input. Effectively
|
|
this means there is nothing pulling the signal levels down.</p>
|
|
<p>The voltage between the gate and source of both MOSFETs is at 0V
|
|
(both are at 3.3V) so the MOSFET is switched off. Therefore both sides
|
|
of the MOSFETs are logic high.</p>
|
|
<p>When either of the 3.3 Volt signal lines outputs a logic low the
|
|
corresponding drain is pulled to ground. Now the voltage between the
|
|
gate and the source is 3.3V and the MOSFET turns on causing the 5 Volt
|
|
side to go low as well.</p>
|
|
<p>When either of the 5 Volt signal lines outputs a logic low the body
|
|
diode of the corresponding MOSFET start conducting, causing the source
|
|
voltage to drop below the gate voltage. The MOSFET switches on and the
|
|
3.3 volt side goes low.</p>
|
|
<h2 id="power-supply">Power supply</h2>
|
|
<p>Typical, a 12 Volt power supply is used to power the device, but it
|
|
can be powered from a wide range of voltages, from 6.5 to 36 Volt. A
|
|
switching regulator (U3) supplies the 5 Volt power rail and a linear low
|
|
drop regulator (U4) supplies the 3.3 volt power rail.</p>
|
|
<figure>
|
|
<img src="./images/power_supply.svg" title="Power supply"
|
|
alt="Power supply" />
|
|
<figcaption aria-hidden="true">Power supply</figcaption>
|
|
</figure>
|
|
<h3 id="input-protection">Input protection</h3>
|
|
<p>C1 and C5 short out high frequency signals, protecting the input from
|
|
ESD. Bidirectional transient-voltage-suppression diodes D1 end D2 clamp
|
|
transient voltages, again protecting the input from ESD.</p>
|
|
<p>And than Q3 and its surrounding components: this is the reverse
|
|
polarity protection. Usually, a series diode is used, but due to the
|
|
voltage drop across such a diode it dissipates energy which is wasteful.
|
|
The circuit with Q3 on the other hand has a very low voltage drop
|
|
resulting in an almost zero loss solution.</p>
|
|
<p>If VCC is applied in the correct polarity, the source will
|
|
immediately rise to the about VCC because of the body diode
|
|
conducting.</p>
|
|
<p>The gate will charge towards -VCC with respect to the source through
|
|
R1. When the gate reaches the threshold voltage the MOSFET channel will
|
|
begin to conduct, and by the time the gate-source voltage reaches a few
|
|
volts the MOSFET channel will be conducting almost all the current, the
|
|
output voltage will be close to VCC. It continues to charge until it
|
|
reaches about -10V at which point the zener diode begins to shunt
|
|
significant current away from the gate.</p>
|
|
<p>In steady state with VCC on the drain the gate sits at -10V with
|
|
respect to the source, and the MOSFET happily conducts in the reverse
|
|
direction.</p>
|
|
<p>When VCC is applied in the reverse polarity, the body diode of the
|
|
MOSFET cannot conduct. Only a small leakage current can flow from the
|
|
source to the drain via resistor R1 and zener diode D3, which now acts
|
|
as a normal diode. The gate and the source are now at almost the same
|
|
potential and the MOSFET cannot conduct, protecting the device from
|
|
reverse polarity.</p>
|
|
<figure>
|
|
<img src="./images/reverse_polarity_protection.svg"
|
|
title="Reverse polarity protection" alt="Reverse polarity protection" />
|
|
<figcaption aria-hidden="true">Reverse polarity protection</figcaption>
|
|
</figure>
|
|
<h2 id="microcontroller">Microcontroller</h2>
|
|
<p>The heart of the circuit is an Arduino Pro Mini, which is basically
|
|
an Atmel ATmega328P with a special Arduino bootloader, making it an easy
|
|
platform for developing software.</p>
|
|
<figure>
|
|
<img src="./images/micro-controller.svg" title="Microcontroller"
|
|
alt="Microcontroller" />
|
|
<figcaption aria-hidden="true">Microcontroller</figcaption>
|
|
</figure>
|
|
<p>Both the signals from the rain meter and the cup anemometer are
|
|
connected to interrupt pins of the micro-controller. The signal from the
|
|
rain meter is lightly filtered by C8. The output of the wind vane is
|
|
connectd to an analog input of the micro-controller.</p>
|
|
<p>The ModBus address can be set by DIP switch J9.</p>
|
|
<h1 id="theory-of-operation---software">Theory of operation -
|
|
Software</h1>
|
|
<h2 id="wind-speed-1">Wind speed</h2>
|
|
<p>The pulse from the cup anemometer is connected to an interrupt input
|
|
of the micro-controller. Every time its logic level changes an interrupt
|
|
routine is called. This routine increments a counter and checks how many
|
|
time has passed since the previous interrupt call. If the previous call
|
|
was more than 6 seconds ago, the wind speed is (almost) zero. If the
|
|
previous call was just over 3 second ago the interrupt counter now holds
|
|
the amount of pulses in three seconds. This value is stored and from
|
|
that value the wind speed can be calculated. If the previous call was
|
|
less than 3 seconds ago the measurement is still in progress and no
|
|
further action is taken. A measurment period of three seconds is choosen
|
|
because it is the standard as used by the Dutch meteorological institute
|
|
(KNMI).</p>
|
|
<figure>
|
|
<img src="./images/wind_speed_diagram.svg" title="Wind speed interrupt"
|
|
alt="Wind speed interrupt" />
|
|
<figcaption aria-hidden="true">Wind speed interrupt</figcaption>
|
|
</figure>
|
|
<h2 id="wind-direction-1">Wind direction</h2>
|
|
<p>The analog signal from the wind vane is fed into the analog to
|
|
digital converter of the micro-controller. The software samples this
|
|
signal and determines which value from a lookup table is closest to the
|
|
value from the ADC. The lookup table now gives the wind direction in
|
|
degrees.</p>
|
|
<figure>
|
|
<img src="./images/wind_direction_diagram.svg"
|
|
title="Getting the wind direction" alt="Getting the wind direction" />
|
|
<figcaption aria-hidden="true">Getting the wind direction</figcaption>
|
|
</figure>
|
|
<p>As the tolerances between micro-controllers can be high, the wind
|
|
vane has to be calibrated in order to get a correct lookup table.</p>
|
|
<h2 id="rain-fall-1">Rain fall</h2>
|
|
<p>The pulse from the rain meter is connected to an interrupt input of
|
|
the micro-controller. Every time a rising edge is detected an interrupt
|
|
routine is called. This routine debounces the signal and increments the
|
|
rain counter. This counter can be used to calculate the rain fall.</p>
|
|
<h2 id="humidity-1">Humidity</h2>
|
|
<p>Via the I²C bus, the humidity value of the sensor is read. As the
|
|
sensor can become saturated with moisture it can get stuck at 100%. This
|
|
happens in particular with fog or other high humidity and condensing
|
|
weather types. The sensor has a build in heater to drive of moisture and
|
|
thus preventing this problem. Because the temperature of the sensor
|
|
rises when the heater is turned on, accurate ambient temperature and
|
|
humidity readings are no longer possible. But with a smart algorithm it
|
|
is possible to get the benefits of the build in heater while still being
|
|
able to use the sensor as an ambient thermometer.</p>
|
|
<p>When the humidity rises above 95% for more than an hour the current
|
|
temperature and humidity are stored and the heater is switched on for 5
|
|
minutes. Than the heater is switched off again. If after 15 minutes the
|
|
humidity is still above 95% the heater is turned on again for another 5
|
|
minutes. But not before the temperature and humidity are measured and
|
|
stored, as the sensor is now cooled off to ambient temperature. If the
|
|
humidity is below 95% the sensor is free from moisture and the process
|
|
is not repeated for another hour.</p>
|
|
<p>When the heater algorithm is active, the temperature and humidity
|
|
values are updated every 20 minutes instead of every 2 seconds. Statis
|
|
bit 0 (ModBus register 30014) indicated if the heater is on or off and
|
|
status bit 1 gives the update rate of the temperature and humidity
|
|
values.</p>
|
|
<p>This algorithm can be enabled by setting the HeaterCoil (see ModBus
|
|
secion).</p>
|
|
<figure>
|
|
<img src="./images/smart_heater.svg" title="Heater algorithm"
|
|
alt="Heater algorithm" />
|
|
<figcaption aria-hidden="true">Heater algorithm</figcaption>
|
|
</figure>
|
|
<h2 id="temperature-1">Temperature</h2>
|
|
<p>The temperature is read from the humidity sensor as this sensor gives
|
|
the most accurate temperature readings. When the heater is on (see
|
|
section humidity above) the temperature readings are temporary stopped
|
|
and only updated every 20 minutes. As a backup, the slightly less
|
|
accurate temperature readings from the pressure sensor can be used.</p>
|
|
<h2 id="atmospheric-pressure-1">Atmospheric pressure</h2>
|
|
<p>Via the I²C bus, the atmospheric pressure value of the sensor is
|
|
read. There is nothing further to say about this sensor: it is rather
|
|
boring.</p>
|
|
<h2 id="illumination-1">Illumination</h2>
|
|
<p>This sensor is still under development.</p>
|
|
<h2 id="modbus-interface-1">ModBus interface</h2>
|
|
<p>The weather station uses ModBus RTU over a simplex RS-485 line. For
|
|
now, the ModBus address is hard coded as 14 in the software. The values
|
|
are available in the input registers and can be read via function code
|
|
04.</p>
|
|
<p>Below an example of how to read the wind direction and enable the
|
|
heater algorithm in Python using the minimalmodbus library.</p>
|
|
<pre><code>#!/usr/bin/env python3
|
|
import minimalmodbus
|
|
|
|
# port name, slave address (in decimal)
|
|
instrument = minimalmodbus.Instrument('/dev/ttyUSB1', 14)
|
|
|
|
# register number, number of decimals, function code
|
|
wind_direction = instrument.read_register(1, 1, 4)
|
|
print(wind_direction)
|
|
|
|
# register address, value, function code
|
|
instrument.write_bit(0, 1, 5)</code></pre>
|
|
<h3 id="input-registers-read-only">Input registers (read only)</h3>
|
|
<p>Input registers are numbered 30001 to 39999 but have data addresses
|
|
0x000 to 0x270E. The measurements and order of the measurements are the
|
|
same as for APRS weather reports. But of course we use SI units.</p>
|
|
<table>
|
|
<colgroup>
|
|
<col style="width: 13%" />
|
|
<col style="width: 53%" />
|
|
<col style="width: 33%" />
|
|
</colgroup>
|
|
<thead>
|
|
<tr class="header">
|
|
<th>Address</th>
|
|
<th>Description</th>
|
|
<th>Units</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr class="odd">
|
|
<td>00</td>
|
|
<td>Device ID (0x5758)</td>
|
|
<td>NO UNIT</td>
|
|
</tr>
|
|
<tr class="even">
|
|
<td>01</td>
|
|
<td>Wind direction</td>
|
|
<td>degrees * 10</td>
|
|
</tr>
|
|
<tr class="odd">
|
|
<td>02</td>
|
|
<td>Wind speed (average of 10 minutes)</td>
|
|
<td>m/s * 100</td>
|
|
</tr>
|
|
<tr class="even">
|
|
<td>03</td>
|
|
<td>Wind gust (peak of last 10 minutes)</td>
|
|
<td>m/s * 100</td>
|
|
</tr>
|
|
<tr class="odd">
|
|
<td>04</td>
|
|
<td>Temperature (two’s complement)</td>
|
|
<td>degrees Celcius * 100</td>
|
|
</tr>
|
|
<tr class="even">
|
|
<td>05</td>
|
|
<td>Rain last hour</td>
|
|
<td>l/m2 * 100</td>
|
|
</tr>
|
|
<tr class="odd">
|
|
<td>06</td>
|
|
<td>Rain last 24 hours</td>
|
|
<td>l/m2 * 100</td>
|
|
</tr>
|
|
<tr class="even">
|
|
<td>07</td>
|
|
<td>Rain since midnight</td>
|
|
<td>NOT IMPLEMENTED</td>
|
|
</tr>
|
|
<tr class="odd">
|
|
<td>08</td>
|
|
<td>Humidity</td>
|
|
<td>percent * 100</td>
|
|
</tr>
|
|
<tr class="even">
|
|
<td>09</td>
|
|
<td>Barometric pressure</td>
|
|
<td>hPa * 10</td>
|
|
</tr>
|
|
<tr class="odd">
|
|
<td>10</td>
|
|
<td>Luminosity</td>
|
|
<td>W/m2</td>
|
|
</tr>
|
|
<tr class="even">
|
|
<td>11</td>
|
|
<td>Snow fall</td>
|
|
<td>NOT IMPLEMENTED</td>
|
|
</tr>
|
|
<tr class="odd">
|
|
<td>12</td>
|
|
<td>Raw rain counter</td>
|
|
<td>l/m2 * 100</td>
|
|
</tr>
|
|
<tr class="even">
|
|
<td>13</td>
|
|
<td>Temperature (two’s complement)</td>
|
|
<td>degrees Celcius * 100</td>
|
|
</tr>
|
|
<tr class="odd">
|
|
<td>14</td>
|
|
<td>Status bits</td>
|
|
<td>see table below</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<p><sup>NOTE</sup> Register 13 holds the backup temperature reading from
|
|
the pressure sensor.</p>
|
|
<table>
|
|
<colgroup>
|
|
<col style="width: 18%" />
|
|
<col style="width: 31%" />
|
|
<col style="width: 25%" />
|
|
<col style="width: 24%" />
|
|
</colgroup>
|
|
<thead>
|
|
<tr class="header">
|
|
<th>Status bits</th>
|
|
<th>Description</th>
|
|
<th>logic 0</th>
|
|
<th>logic 1</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr class="odd">
|
|
<td>0</td>
|
|
<td>Heater status</td>
|
|
<td>heater off</td>
|
|
<td>heater on</td>
|
|
</tr>
|
|
<tr class="even">
|
|
<td>1</td>
|
|
<td>Temp/humidity update</td>
|
|
<td>every 20 minutes</td>
|
|
<td>every 2 seconds</td>
|
|
</tr>
|
|
<tr class="odd">
|
|
<td>2</td>
|
|
<td>Heater algorithm</td>
|
|
<td>disabled</td>
|
|
<td>enabled</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<p>The ModBus registers are 16 bit wide. For better precision, some
|
|
units are scaled by a factor of 10 or 100. This way, values with up to
|
|
two decimal points can be stored as 16 bit integer values. Just divide
|
|
by 10 or 100 to get the floating point values.</p>
|
|
<h3 id="output-coils-write-only">Output coils (write only)</h3>
|
|
<p>Output coils registers are numbered 1 to 9999 but have data addresses
|
|
0x000 to 0x270E. The default value of a register is 0.</p>
|
|
<table>
|
|
<thead>
|
|
<tr class="header">
|
|
<th>Address</th>
|
|
<th>Description</th>
|
|
<th>logic 0</th>
|
|
<th>logic 1</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr class="odd">
|
|
<td>0</td>
|
|
<td>Heater algorithm</td>
|
|
<td>disabled</td>
|
|
<td>enabled</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<h1 id="prototype">Prototype</h1>
|
|
<p>I wanted to locate the weather station at about 100 meters from the
|
|
house. That meant that interfacing the weather station was not just a
|
|
matter of connecting a wire to it. And 100 meters is also a bit much for
|
|
a wifi connection. As I already had experience with LoRa I opted for
|
|
that. But not LoRaWAN, but LoRa APRS. This is a ham radio network that I
|
|
often use. I even run my own digipeater. So LoRa APRS it is.</p>
|
|
<figure>
|
|
<img src="./images/prototype_block_diagram.svg"
|
|
title="Block diagram of the prototype"
|
|
alt="Block diagram of the prototype" />
|
|
<figcaption aria-hidden="true">Block diagram of the
|
|
prototype</figcaption>
|
|
</figure>
|
|
<p>The weather station’s RS-485 interface is connected to a Raspberry Pi
|
|
Zero 2W running the aprx digipeater software, as well as some specially
|
|
written Python programs to interface the build in LoRa transceiver, the
|
|
GPS module and the weather station itself. Every 10 minutes the
|
|
digipeater will read the weather station’s registers and sends the data
|
|
as PE1RXF telemetry messages (see <a
|
|
href="https://www.meezenest.nl/mees-elektronica/projects/aprs_telemetry/APRS_protocol_nodes_PE1RXF.pdf">https://www.meezenest.nl/mees-elektronica/projects/aprs_telemetry/APRS_protocol_nodes_PE1RXF.pdf</a>)
|
|
over the APRS network to a server, which presents the data in a Grafana
|
|
dashboard. The digipeater can also send standardized APRS weather
|
|
reports over the APRS network. But more about this project can be found
|
|
here: <a
|
|
href="https://www.meezenest.nl/mees-elektronica/RPi_LoRa_shield.html">https://www.meezenest.nl/mees-elektronica/RPi_LoRa_shield.html</a></p>
|
|
<figure>
|
|
<img src="./images/prototype_overview_small.jpg"
|
|
title="The prototype in the garden" alt="The prototype in the garden" />
|
|
<figcaption aria-hidden="true">The prototype in the garden</figcaption>
|
|
</figure>
|
|
<p>As a housing for the prototype, I used an old beehive. These are
|
|
weatherproof and I had one laying around.</p>
|
|
<figure>
|
|
<img src="./images/prototype_sensors_small.jpg"
|
|
title="Closeup of the sensors" alt="Closeup of the sensors" />
|
|
<figcaption aria-hidden="true">Closeup of the sensors</figcaption>
|
|
</figure>
|
|
<figure>
|
|
<img src="./images/prototype_inside_annotations_small.jpg"
|
|
title="Inside the beehive" alt="Inside the beehive" />
|
|
<figcaption aria-hidden="true">Inside the beehive</figcaption>
|
|
</figure>
|
|
<h1 id="specifications">Specifications</h1>
|
|
<h2 id="wind">Wind</h2>
|
|
<ul>
|
|
<li><p>Wind speed is measured by taking 3 second averages from the cup
|
|
anemometer and using these samples to calculate the average over a 10
|
|
minute periode.</p></li>
|
|
<li><p>Wind gust is measured by taking 3 second averages from the cup
|
|
anemometer.</p></li>
|
|
<li><p>Wind vane has 8 main directions and another 8 directions in
|
|
between. But these last do not have the same weight, eg. these positions
|
|
are not as likely to be measured as the main directions. This is due to
|
|
the construction of the wind vane: it has eight reed switches for the
|
|
main directions and if the wind direction happens to sit exactly in
|
|
between two reed switches, both switches are closed giving the extra 8
|
|
sub directions. Not great, but it is what it is…</p></li>
|
|
</ul>
|
|
<h2 id="rain">Rain</h2>
|
|
<pre><code>Resolution: 0.2794 mm/impulse</code></pre>
|
|
<h2 id="humidity-2">Humidity</h2>
|
|
<pre><code>Operating range : 0 - 100 % RH
|
|
Recommended range : 20 - 80 % RH
|
|
Accuracy : +/- 3 % RH (0-80 % RH)
|
|
+/- 4.5 % (max when > 80 % RH)
|
|
|
|
Heater to drive of moisture (can be enabled via ModBus)</code></pre>
|
|
<h2 id="pressure">Pressure</h2>
|
|
<pre><code>Operating range : 300 - 1100 hPa
|
|
Accuracy : +/- 1.0 hPa (0 - 65 °C)
|
|
+/- 1.7 hPa (-20 - 0 °C)</code></pre>
|
|
<h2 id="temperature-2">Temperature</h2>
|
|
<pre><code>Main sensor
|
|
-----------
|
|
|
|
Operating range : -10 - 85 °C (typ)
|
|
-40 - 85 °C (max)
|
|
Accuracy : +/- 0.3 °C (typ)
|
|
+/- 0.4 °C (max)
|
|
+/- 0.5 °C (max when < -10°C)
|
|
|
|
Backup sensor
|
|
-------------
|
|
|
|
Operating range : 0 - 65 °C (typ)
|
|
-40 - 85 °C (max)
|
|
Accuracy : +/- 0.5 °C (25 °C)
|
|
+/- 1.0 °C (0 - 65 °C)</code></pre>
|
|
<h2 id="modbus-1">ModBus</h2>
|
|
<pre><code>Physical : RS-485 simplex RTU
|
|
Settings : 9600 bd 8N1
|
|
Address : 14</code></pre>
|
|
<h1 id="schematic">Schematic</h1>
|
|
<p><a href="./images/weather_station_schematic.pdf"><img
|
|
src="./images/weather_station_schematic.svg" alt="Schematic" /></a></p>
|
|
<h1 id="problems-i-encounter-after-four-months-of-use">Problems I
|
|
encounter after four months of use</h1>
|
|
<p>The Si7021 humidity sensor is not made for outdoor use. The datasheet
|
|
is clear about that. But a lot of people use this cheap sensor for
|
|
weather stations anyway. So I choose this sensor for my design. But that
|
|
was not smart. After an initial time without any problems, the sensor
|
|
started to saturate. This happened during a very wet and mild winter we
|
|
had. My first solution was to utilize the build in heater to drive of
|
|
the moisture. That worked, but only for a short period. The heater blew
|
|
up and the sensor started to report humidity levels above 100% and
|
|
because of a bug in the firmware of the sensor, the humidity register
|
|
wrapped around and the sensor reported humidity levels of 0-30%. I tried
|
|
to find a software solution, which worked for a while, but the sensor
|
|
deteriorated even more. To the point of being totally useless. So I
|
|
searched for another, better sensor. And I found the HYT-221 from
|
|
Innovative Sensor Technology. This sensor is designed to work outdoors
|
|
and can even be used in saunas, where the humidity levels are always
|
|
high and the air is condensating. The datasheet specifically mentions
|
|
outdoor weather stations as an application. The only downside is its
|
|
price: it is ten times more expensive than the Si7021.</p>
|
|
<p>The sensor can be controlled via the I2C bus, so implementing the new
|
|
sensor in the firmware was very easy. From version 0.3.0 onward, this
|
|
sensor is used. The Si7021 is removed from the code.</p>
|
|
<!---
|
|
# Bill of materials
|
|
|
|
# Component placement
|
|
|
|
# Cables and pinouts
|
|
-->
|
|
<h1 id="software-dependencies">Software dependencies</h1>
|
|
<ul>
|
|
<li>Arduino IDE</li>
|
|
</ul>
|
|
<h2 id="arduino-libraries">Arduino libraries</h2>
|
|
<ul>
|
|
<li>https://github.com/sparkfun/SparkFun_Weather_Meter_Kit_Arduino_Library</li>
|
|
<li>https://github.com/orgua/iLib</li>
|
|
<li>https://github.com/epsilonrt/modbus-arduino</li>
|
|
<li>https://github.com/epsilonrt/modbus-serial</li>
|
|
</ul>
|
|
<p>Libraries are included with the source code of this project</p>
|
|
<h1 id="license">License</h1>
|
|
<p>Copyright (C) 2023, 2024 M.T. Konstapel</p>
|
|
<p><a
|
|
href="https://meezenest.nl/mees/">https://meezenest.nl/mees/</a></p>
|
|
<p>The software is published as open-source software (GPL). The hardware
|
|
is published as open-source hardware (OSH).</p>
|
|
<h2 id="software">Software</h2>
|
|
<p>This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by the
|
|
Free Software Foundation, either version 3 of the License, or (at your
|
|
option) any later version.</p>
|
|
<h2 id="hardware-and-documentation">Hardware and documentation</h2>
|
|
<p>This work is licensed under a Creative Commons Attribution-ShareAlike
|
|
4.0 International License.</p>
|
|
<hr>
|
|
</article>
|
|
</main>
|
|
<footer>
|
|
<p>©
|
|
2024-05-02
|
|
M.T. Konstapel
|
|
<a href="https://meezenest.nl/mees/">https://meezenest.nl/mees/</a>
|
|
</p><p>This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">Creative Commons Attribution-ShareAlike 4.0 International License</a>.
|
|
</p>
|
|
</footer>
|
|
</body>
|
|
</html>
|
|
|