Home Assistant Integration
My terrarium tracks the live weather of the Solomon Islands, the skinks' own range, then learns how to hold that climate on its own, and logs every reading.
Instead of picking fixed numbers, I let the terrarium follow the skinks' native climate in real time. Home Assistant pulls the current Solomon Islands sunrise, sunset and humidity and uses them as live targets: the lights rise and set with the island sun, and a self-learning controller keeps humidity tracking the island's own value. Everything is logged, which is as useful for the behaviour notes and the paper I'm writing as it is for day-to-day welfare.
This page is the whole thing, start to finish: the idea, the diagrams that explain each part, a browsable record of every day the system has run, and the full parts list if you want to build the same. Nothing below is illustrative. Every number comes out of the enclosure.
Island sync, the core idea
A weather source for the Solomon Islands feeds three live reference values into Home Assistant: sunrise, sunset and humidity. The photoperiod and the humidity target then follow the real island rather than a static schedule, so the animals experience something close to their wild day, drifting naturally across the seasons.
Lighting: following the island sun
- Basking light follows the Solomon sunrise/sunset cycle for its timing (when it's on), but its temperature is held by a separate Habistat dimming thermostat, not by Home Assistant (see below).
- ESP32 LED bar (ESPHome, "lumenize") provides the bright daylight the species needs and ramps with the same cycle, sunrise, full day, sunset.
- The result is a consistent, natural photoperiod without me touching a timer.
Three zones, not one number
Temperature and humidity are measured in three zones, top, ambient and center, so the controller sees the gradient, not one number. From each it also computes dew point and VPD (vapour-pressure deficit), the same figures a good hygrometer app shows, which are a better guide to how "drying" the air really feels to the animal than raw humidity alone.
This matters more than I expected when I built it. A tall enclosure heated from the top is stably stratified: warm air sitting above cool air does not convect, so the layers genuinely do not mix on their own. On a still afternoon the canopy of my enclosure can hold ten degrees more dew point than the middle, which means the box is simultaneously too wet at the top and too dry where the animals actually sit. One sensor in the middle would have told me everything was fine.
The controller: a self-learning climate brain
The humidity and ventilation are run by a custom controller (an AppDaemon app) rather than simple on/off rules. Reacting to the current reading is the easy half. The rest is learning my specific enclosure and working out where it is heading. Every few minutes the controller:
- Learns how much each second of misting raises humidity, and how much each second of fan lowers it, separately per zone and per temperature, and remembers it across restarts.
- Predicts when humidity will fall below target from the measured drying rate, and mists early instead of waiting.
- Ventilates against fungus, if two of three zones sit too high, it runs a measured fan burst.
- Helps with heat, heating itself is held by the Habistat thermostat (below), but on a hot spell the controller adds evaporative cooling by misting or venting.
- Guards against over-misting, caps a spray if a zone is already near saturation.
- Fails safe: if all sensors drop out it enters a "safe mode" and mists on a learned schedule so the animals are never left dry; a "refill mode" pauses everything while I top up the water tank.
What happens every five minutes
The controller wakes on a five-minute tick and works down a fixed priority list, stopping at the first rule that applies. Nothing runs in parallel, so no two rules can ever be pulling against each other. Months later, when I am trying to work out why a particular afternoon went the way it did, there is only one rule to find.
Why the humidity target has a ceiling
Chasing the island's humidity number directly would be a mistake, for two reasons. The first is that the islands have wind and my living room does not. Air moves constantly through a forest canopy, so 90% out there is 90% of air that is being replaced all day and never sits against a surface. In a closed glass box the same air just stands there, and stagnant wet air is a different thing entirely from moving wet air.
The second is condensation. Warm air holds far more water than cool air. If I fill a 35 °C enclosure to the island's 90% and then let the night fall to 22 °C, all of that extra water has to go somewhere, and it goes onto the glass, the cork and the leaves. Wet surfaces overnight are how you grow mould and how a healthy enclosure turns into a sick one.
So the controller computes the dew point of each zone and caps the humidity target below the coldest temperature the enclosure has actually reached in the last 24 hours. Not an assumed night temperature, a measured one. The target is allowed to follow the island right up until following it would guarantee water on the glass by morning.
How it learns
Every actuator run is an experiment. The controller records the humidity before a misting, waits for the air to settle, and records it again, then folds the difference into a running estimate of how much this enclosure responds to one second of water. The same happens for the fan, and for the rate at which the box dries out on its own. All of it is kept per zone and per temperature band, because a spray on a 36 °C afternoon behaves nothing like the same spray at 25 °C.
The practical effect is that the enclosure gets better at being itself. I did not measure any of these numbers by hand and I could not have: they change with the season, the planting and how much water is in the substrate.
Browse every day
Every day the system has run, drawn entirely from the log, nothing smoothed and nothing drawn by hand. Each one shows the island line, the target the controller derived from it, the humidity it actually achieved, the temperature underneath driving all of it, and every misting and fan run along the bottom.
Step through with the arrow keys or the strip, switch on the three zones to see the stratification, put the Groningen outdoor temperature underneath to see what the box was working against, and use compare to put any two days on top of each other. Pick a hot one and you can watch the heat ladder work: fan first, then a cooling misting, then cutting the basking lamp if neither is enough.
Humidity, target, trigger, temperature and every misting come from the controller's own append-only log. Fan runs come from Home Assistant's recorder, which keeps about ten days, so older days show no fan trace. The Solomon Islands lines are reconstructed from the Open-Meteo archive using the same lookup the live sensor performs, which reproduces the recorded sensor values with a median error of 0.00% over the period where both exist. The Groningen line is the same archive read for this city on the local clock, so it lines up hour for hour with the mistings underneath it.
Making a rainy season
If you step through the days above you will notice something change on 20 August: the green target stops tracking the islands and sits flat on 70% for about twelve hours a day. Nothing went wrong there, I raised the humidity floor by hand.
Emerald tree skinks come into breeding condition on the wet season, when humidity stays high and food is suddenly everywhere. So I am running both levers at once: I raised the humidity floor to hold the enclosure wet through the day, and I increased how much and how often the animals are fed. Together those two signals are the closest I can get to telling them the rains have arrived, which is what I want if they are going to pair up.
The cost is visible in the same chart. Holding a floor that high overrides the dew-point ceiling on warm afternoons, which is exactly the protection I described above, so more water ends up on the glass overnight. That is a trade I am making deliberately and watching closely, not one the system made for me. Before the 20th the floor was 60%, and before the 17th it was 50%, which is why the earlier days in the browser look so different.
Temperature is hardware-controlled
I would recommend this split to anyone. A crashed server, a failed update or a bug in my own code cannot cook the enclosure, because the thing that decides how hot the basking spot gets is a dumb analogue thermostat with no opinion about any of it. Everything Home Assistant does is a refinement on top of a safe baseline.
Behaviour log
A quick form in Home Assistant lets me log what each skink, Loki, Naga and Ron, is doing: activity, appetite, shedding status and a note. Each entry saves a full snapshot of the moment: temperature, humidity, dew point and VPD for all three zones, plus the outdoor weather. Weeks later I can scan for patterns, a dip in activity or appetite lined up against a change in the terrarium, which is exactly the kind of data that feeds the scientific side of this project.
The camera doing the watching is a Wyze Pan v4, and mounting it took no bracket at all: the foot is magnetic, so the camera hangs inside the enclosure off a magnet laid on top of the mesh lid. Nothing drilled, nothing glued, and I can lift it out one-handed when I need to.

Monitoring & alerts
- Sensor watchdog, I get a phone alert the moment a sensor goes offline, and again when it recovers.
- Safe-mode & action alerts: entering safe mode, and each spray or fan run, are pushed to my phone.
- Live dashboard: learned drying rate, time-to-threshold, spray gain and the current targets are all shown so I can see the brain's reasoning at a glance.
Every decision: spray, fan, learned value, sensor drop-out, is written to a permanent append-only log, so I have a full record of what the terrarium did and why. That log is what the day browser above reads.
What I would change
Two things, and I would rather write them down than pretend the build is finished.
The fan is the wrong tool for mixing. Mine exhausts to the room, so every time it breaks up the stratified canopy it also dries the whole enclosure. A small internal circulation fan, moving air inside the box without exchanging it with the room, is the physically correct answer to a thermal inversion, and would let the exhaust fan go back to being used only for genuine humidity removal.
The humidity floor and the dew-point ceiling have no idea about each other. Right now I am holding a high floor on purpose, for the reasons in the rainy-season section, and the consequence is that the ceiling is overridden for half of every warm day. I am fine with that because I chose it. What I would change is that the controller has no way of knowing the difference between a floor I raised deliberately and a floor that is silently cancelling a safety rule. A seasonal mode that said "wet season, accept the condensation risk, and tell me about it" would be more honest than two rules quietly fighting.
What it takes to build
Here's what it takes to build the same thing.
Hardware
| Part | Role | Count |
|---|---|---|
| Home Assistant server (HA Green/Yellow, Pi 4/5, or mini-PC) | Runs everything | 1 |
| Temp/humidity sensors (e.g. Inkbird IBS-TH) | One per zone, top, ambient, center | 3 |
| Bluetooth adapter/proxy + a Matter hub | Connects the sensors & the plugs to HA | 1 |
| Tuya Wi-Fi mister (AliExpress) | Humidity, self-contained reservoir + nozzle, controlled over Tuya | 1 |
| IKEA Matter smart plug(s), e.g. the fan | Controlled airflow & other switched devices | 1+ |
| Basking heat lamp + Habistat dimming thermostat | Daytime hot spot, temperature held in hardware, not HA | 1 |
| ESP32 + addressable LED bar (ESPHome) | Daylight / photoperiod | 1 |
| Camera (I use a Wyze Pan v4) | Behaviour watching, magnetic foot on a magnet on the mesh lid, no bracket | 1 |
| Phone running the HA app | Alerts & dashboard | 1 |
Home Assistant software & plugins
| Component | What it's for |
|---|---|
| Home Assistant OS / Core | The platform itself |
| AppDaemon add-on | Runs the self-learning terrarium controller (Python) |
| ESPHome add-on | Firmware for the ESP32 LED bar |
| Tuya / LocalTuya integration | Controls the Wi-Fi mister |
| Matter integration | IKEA smart plugs (fan & other switched devices) |
| Bluetooth / Inkbird integration | Reads the BLE temp/humidity sensors |
| A weather source for the Solomon Islands (I use Open-Meteo) | Live sunrise, sunset & humidity reference |
| Template sensors | Compute dew point & VPD from temp + humidity |
| Helpers (input_boolean / input_number / input_select / input_text) | Refill mode, live spray/fan duration, behaviour-log fields |
| Scripts & Logbook | Behaviour logging with condition snapshots |
| HACS + custom Lovelace cards | The dashboard |
| HA Companion app | Push notifications |
Another keeper-built tool worth knowing
Automating a terrarium is one way to take the guesswork out of it. Simulating one before you build it is another. Light My Reptile, built by Nathan Burton, models UVB, heat and visible light inside a specific enclosure and draws UV Index contours across a cross-section, so you can see where the basking branch should sit before you spend anything. The emerald tree skink is not in its species list, so the settings to enter for this species are written up on the terrarium page.