Calibrating a Humidity Sensor with Saturated Salt Solution — ASTM E104 Method
Why Calibrate?
The music room contains a pair of B&W Matrix 800 loudspeakers — the original flagship model from 1987. At 110kg each, with crossovers, drive units, and cabinet materials that are no longer manufactured, they are effectively irreplaceable. Keeping them in good condition over decades requires stable humidity. Too dry and surrounds crack, spiders stiffen, and wooden cabinet joints open. Too damp and cones absorb moisture, crossover components corrode, ferrofluid in the tweeters degrades. And most importantly with this pair, the nickel plated magnet assemblies oxidise, binding the voice coils in the coil gap. This has already killed one of the very rare drivers.
The humidity monitoring in this house — the import risk automation, the absolute humidity calculations, the window-opening decisions — exists primarily to protect these speakers. That means the sensors doing the measuring need to be accurate. A 6% error in relative humidity is not a minor calibration footnote, it is the difference between correct and incorrect humidity management decisions.
Most humidity sensors ship with a stated accuracy — the Sensirion SHT45, for example, specifies ±1.8% RH typical. But “typical” means the population average. Any individual sensor may sit anywhere within that band, and without calibration you do not know where yours sits.
For casual temperature monitoring that does not matter. For tracking absolute humidity differences between rooms, calculating moisture import risk, or using a sensor as a reference standard to calibrate others, it matters considerably.
The method described here — the saturated salt solution technique — is the same one used by Vaisala, the Met Office, and professional calibration laboratories. It costs almost nothing and requires no specialist equipment.
The Physics
When sodium chloride (table salt, NaCl) is dissolved in water to saturation — meaning excess undissolved crystals are present — the air immediately above the solution reaches a fixed equilibrium relative humidity determined only by temperature. This is a consequence of the thermodynamic water activity of the saturated solution.
At 15°C the equilibrium RH above saturated NaCl is 75.61%. This value is well established and tabulated in scientific literature going back to Greenspan (1977), which remains the reference cited by ASTM E104 and by Vaisala’s calibration documentation.
The temperature coefficient is small — approximately 0.047% RH per °C — which means the target shifts by less than 0.5% across the typical indoor temperature range of 10-20°C. This is why NaCl is particularly useful as a calibration reference: it is stable, cheap, and not strongly temperature-sensitive.
A sealed container with saturated NaCl paste on the bottom will equilibrate to 75.61% (at 15°C) and hold that humidity indefinitely as long as excess undissolved salt remains present.
The Failed Attempt

The first attempt used a 2-litre plastic Tupperware container, standard supermarket table salt, and the wires fed through a gap in the side sealed loosely with blu-tack.
It failed for two reasons. Table salt contains sodium ferrocyanide as an anti-caking agent — this changes the water activity of the solution and shifts the equilibrium RH away from the theoretical value. Plastic is also slightly porous and can absorb or release moisture, and the large volume took much longer to equilibrate. After several hours the sensor was reading 72.10% at 14.5°C against a theoretical target of 75.64% — a 3.54% discrepancy that was still drifting.
The Correct Setup

The working setup addresses each failure point:
- 500ml glass jar — non-porous, does not absorb or release moisture, seals well
- 99.9% pure NaCl — no anti-caking agent, no additives
- Distilled water — no dissolved minerals
- Dupont wires through a hole in the lid, sealed with hot glue — airtight
- SHT45 sensor suspended ~4cm above the salt surface — not touching walls or paste
- ESP32-C6 board outside the jar — board heat cannot warm the chamber air
Salt paste preparation: 20g pure NaCl mixed with approximately 7ml distilled water. The correct consistency is wet sand with visible undissolved crystals throughout — if it looks clear and fully dissolved, add more dry salt. Excess undissolved salt is essential; the equilibrium only holds as long as the solution remains saturated.
ESPHome Wiring
The SHT45 connects to the ESP32-C6 via I2C:
SHT45 VCC → 3V3
SHT45 GND → GND
SHT45 SDA → GPIO4
SHT45 SCL → GPIO5
Basic ESPHome yaml for the SHT45:
i2c:
sda: GPIO4
scl: GPIO5
sensor:
- platform: sht4x
temperature:
name: "Temperature SHT45"
humidity:
name: "Humidity SHT45"
update_interval: 60s
For calibration work, temporarily increase update_interval to 60s or more to minimise self-heating from the sensor element. Self-heating is the enemy in a sealed chamber — even a fraction of a degree of sensor-induced warming shifts the equilibrium target and skews the result.
The Calibration Run
With the chamber sealed, the sensor climbs rapidly toward the equilibrium value then slows as it approaches it — a classic asymptotic curve. At 15°C the target is 75.61%.
The curve takes several hours to fully flatten. The ESP32 board outside the jar matters — if the board is inside, its heat warms the chamber air, raises the temperature, and lowers the equilibrium target, giving a false reading. With the board outside, the chamber temperature tracks the room.
After full equilibration at 14.70°C (NaCl equilibrium: 75.63%), the SHT45 stabilised at approximately 74.5%, giving an offset of +1.1%. This is well within the sensor’s ±1.8% specified tolerance and confirms the SHT45 is performing correctly — it simply sits near the low end of its accuracy band.
Applying the Offset
The offset is applied as an ESPHome filter, correcting the value at source before Home Assistant sees it:
sensor:
- platform: sht4x
temperature:
name: "Temperature SHT45"
humidity:
name: "Humidity SHT45"
filters:
- offset: 1.1
update_interval: 60s
Flash and the sensor now reports calibrated values. The AirGradient I-9PSL indoor unit (which uses a Sensirion SHT40) was subsequently compared against the calibrated SHT45 and found to read approximately 6% high — a significant error that would meaningfully affect any humidity-based calculations such as absolute humidity or import risk.
The Deviance Template Sensor
To monitor calibration stability over time, a template sensor in configuration.yaml tracks how far the SHT45 reads from the theoretical NaCl equilibrium, with live temperature compensation:
template:
- sensor:
- name: "SHT45 RH Deviance"
unit_of_measurement: "%"
state: >
{% set t = states('sensor.esp32_c6_zero_1_sht45_temperature_sht45') | float(0) %}
{% set target = 75.61 + (15.0 - t) * 0.047 %}
{{ (target - states('sensor.esp32_c6_zero_1_sht45_humidity_sht45') | float(0)) | round(2) }}
When the sensor is placed back in the chamber, this should read near zero if calibration is holding. When deployed in normal room air it will show a large positive value — which is expected and correct, since room humidity is well below 75%.
The Calibration Chain
This setup establishes a three-tier calibration chain:
- Primary reference — saturated NaCl solution (ASTM E104 method), traceable to established thermodynamic constants
- Transfer standard — SHT45 #1, calibrated against the primary reference, stored sealed when not in use
- Working sensors — two additional SHT45s on order, to be calibrated against the transfer standard
The transfer standard should only be used for calibrating other sensors — not deployed permanently. Store it in a sealed glass jar at moderate humidity (40-60% RH) with a small silica gel packet. Label the jar with the sensor ID, offset, calibration date, and method.
This is precisely the chain used by professional calibration laboratories, scaled to a kitchen table.