Note: This project is currently on hold. I’m restoring these notes from an older site draft and may come back to complete the build later.
I wanted to design and build my own weather station using a microcontroller.
Requirements
- Run on Arduino
- Use COTS hardware components
- Require minimal soldering
- Be battery operated
- Support solar charging
- Integrate with OpenHab
- Avoid destructive changes to major components
Hardware
| Item | Details |
|---|---|
| MCU | Arduino MKR WiFi 1010 |
| Environmental Sensors | MKR ENV Shield |
| Battery | LiPo 3.7V 3300mAh |
| 5V Regulator | Adafruit MiniBoost 5V @ 1A – TPS61023 |
| Solar Charger | Adafruit Universal USB / DC / Solar Lithium Ion/Polymer Charger (bq24074) |
| Solar Panel | 2W 6V small polysilicon solar panel |
Power
I knew I wanted the device to live outside and not be permanently plugged in, which meant battery power and a solar panel from the outset.
Sensors
Sensors for the MKR WiFi 1010 were easy enough to solve. I opted for an MKR ENV Shield that could simply sit on top.
The MKR ENV Shield includes three sensors: LPS22HB, HTS221, and TEMT6000.
LPS22HB
This is a compact absolute pressure sensor with a range between 260 hPa and 1260 hPa. Atmospheric pressure can be read using the readPressure() function.
One thing to watch is that the reading needs to be adjusted based on altitude. The sensor is calibrated to provide a reading at sea level, so if your location is above that you will need to apply an offset.
Find your altitude using GPS or an online source, then use a correction table such as:
https://novalynx.com/manuals/bp-elevation-correction-tables.pdf
In my case, I added the offset directly to the reading using a float.
float pressureAdjustment = 1.64; // kPa
pressure = ENV.readPressure() + pressureAdjustment;
As a sanity check, compare your readings with a trusted local weather service. In the UK, the Met Office is the obvious place to start. Local airport weather data can also be useful. In my case, the nearest weather station was roughly 250ft lower than my location, so I had to take that into account when comparing values.
HTS221
This sensor provides temperature and humidity readings. The main functions are:
readTemperature()readHumidity()
TEMT6000
The TEMT6000 is a phototransistor that changes behaviour depending on the amount of light falling on it. It is designed to align reasonably well with human eye sensitivity, so in practice it gives you a good sense of ambient light intensity.
Its opening angle is ±60°, and while it peaks at 570 nm, it detects light in the range from 440 nm to 800 nm.
Using the readIlluminance() command returns a value measured in lux.
When it came to designing an enclosure, I quickly realised that with the solar panel mounted on the top, the phototransistor would be of limited practical value. I still kept the readings, as it was interesting to see whether I could detect dawn, daylight, dusk, and night from within the enclosure.
Real-Time Clock
The MKR WiFi 1010 includes a Real-Time Clock (RTC), which I wanted to use partly so that I could track basic uptime behaviour.
The WiFiNINA library includes a getTime() function that polls the DHCP-advertised NTP server and returns the epoch value. Combined with the setEpoch() function from the RTCZero library, this makes it straightforward to set the internal clock correctly.
rtc.setEpoch(WiFi.getTime());
OpenHab
OpenHab, for all its quirks, is perfectly capable here — but it rewards reading the documentation first rather than charging in and hoping for the best.
MQTT
From experience, I knew I wanted each polling cycle to send as little data as possible. I also wanted a stateless, fire-and-forget protocol. MQTT was the obvious fit, and OpenHab already supports it well.
MQTT works by having clients connect to a broker and publish messages to topics that other clients can subscribe to. In this case, the weather station publishes data and OpenHab subscribes to it.

As I was already running OpenHab on Ubuntu, I chose Mosquitto as the broker:
http://www.mosquitto.org
Recent Mosquitto builds enforce authentication by default. I did not particularly want that complexity on my internal home network, but it is still the sensible default. If you are going down this route, generate credentials for:
- the IoT device
- OpenHab
- a spare admin/user account for yourself
Documentation for Mosquitto authentication is here:
https://mosquitto.org/documentation/authentication-methods
You may also want an MQTT client to inspect exactly what your device is publishing. I used MQTT Explorer:

You will want to think carefully about topic structure up front if you expect to add more IoT devices later.
Issues
Debugging
One of the more annoying practical issues during development was switching cleanly between debugging and normal runtime. Using Serial.print() and Serial.println() everywhere is fine for quick testing, but I wanted an easy way to turn debug output on and off.
A simple boolean flag worked well enough.
bool debugMode = false; // set to true for debug
...
if (debugMode) {
Serial.println("debug message here");
}
The same pattern can be used inside functions.
if (debugMode) {
Serial.print("Sensor A: ");
Serial.println(sensorAVal);
}
As noted under power management, I also needed a way to toggle low-power mode so that during debugging the Arduino would not go to sleep, while still waiting for the usual interval.
void powerManagement() {
switch (SystemState) {
case RUNNING:
if (lowPowerMode) {
WiFi.end();
SystemState = SLEEPING;
LowPower.sleep(interval);
} else {
SystemState = SLEEPING;
delay(interval);
}
break;
case SLEEPING:
updateWiFiStatus();
if (status != WL_CONNECTED) {
connectWiFi();
}
updateWiFiStatus();
SystemState = RUNNING;
break;
}
}
Power management
Power usage when running from battery turned out to be more of an issue than I expected. I was running out of power even after a full day of sun, which suggested I still had more optimisation to do around sleep states and overall power draw.
This is one of the areas I still intend to revisit if and when I pick the project back up.
