In this article I will talk about one of my amateur projects on the ESP8266 – a weather station on Arduino.
Yes! This is another weather station on Arduino 🙂
But don’t rush to close this article, this project has its own highlight, namely autonomous operation without the use of batteries in the harsh conditions of the Ural winter.
For professionals, this article will not be very interesting, but for those who like to make things with their own hands and learn something new, please read it.
In the article I will often talk about Arduino, despite the fact that the Arduino Uno itself (or another model) was not used in the project. But since the Arduino SDK and Arduino libraries were used, we will consider this project an Arduino project.
Idea
There are so many weather stations on Arduino that this is probably the most popular project after blinking an LED among beginners.
I wanted to have some kind of device outside my window on the balcony that collected weather data: temperature, humidity and pressure. The device will also measure the supply voltage so that you can understand how good/bad everything is with the power supply at night.
The device must operate 24/7 and require no maintenance.
Data must be transmitted in real time after each change (every half hour) via Wi-Fi to the home MQTT server. The measurement results can be viewed in the control panel with a primitive web face.
The most difficult thing is to decide on the power supply for the device. I immediately dismissed the idea of running wires onto the balcony as aesthetically incorrect. A lithium battery is also not suitable, especially in the Ural winter, it will quickly discharge and degrade. A lithium battery might be suitable, but not for powering the ESP and certainly not for connecting via Wi-Fi.
To power the weather station, it was decided to install a solar battery and an ionistor for energy storage. There were fears that at night the ESP would eat up the entire charge of the ionistor. But even if this happened, the ionistor is not afraid of complete discharge, unlike lithium batteries.
The ionistor for powering the ESP8266 is also good because it can deliver a very high current. But the ESP8266 has always had a problem with this; if there is insufficient current supply, the module can freeze. This happens, for example, if you connect the ESP8266 to a DC-DC power converter that does not provide the required current value.
Components
-
ESP-01S (ESP8266). Small and inexpensive module. It has one big drawback with getting out of deep sleep, but we’ll try to fix it with a file 😀
-
Harness for ESP-01S (0.1uF ceramic capacitor and 10K resistor).
-
INA226 (voltmeter/ammeter, I2C, 3.3V); We will measure the voltage on the ionistor and send the data to the server.
-
HTU31D (temperature and humidity sensor, I2C, 3.3V).
-
BMP280 (atmospheric pressure sensor, I2C, 3.3V). This sensor can also measure temperature, but we will not use this functionality;
-
Ionistor (D-type 3.8V Farah, 100F); The 100F capacity was chosen with a small margin. You can always adjust the measurement interval; the longer the device is in sleep mode, the less energy is wasted and vice versa.
-
Solar panels (8 pieces, 0.5W, 5V). Oh, I don’t know what the Chinese sent there, but I decided to order more panels. So that even in the cloudiest winter weather the weather station can work. Perhaps these panels could have been installed much less, for example 6 or even 4.
-
DC-DC converter (600mA, input 3-15V, output 3.3V). A pulse converter that will reduce the current from solar panels (5V) to 3.3V and charge the ionistor. The most important thing is not to apply a current higher than 3.8V to the ionistor, this will damage it.
-
Schottky diode. Without it, at night the ionistor will begin to discharge through the solar battery. That is, the current will flow backwards, but we don’t need that.
-
Universal PCB (in those years I didn’t know how to make boards with photoresist, so we’ll use collective farms).
-
Plastic case (regular ABS plastic box).
-
Neodymium magnets (for securely attaching the housing to the outside of the balcony).
-
MQTT server/web face For the MQTT server I used Mosquitto. The web application was written independently in React/Nest.JS. The web application listened to events on the MQTT server and, when they occurred, saved data in the database. After authorization, the web application led to a page where data was displayed in the form of graphs (temperature/humidity/voltage on the ionistor).
Assembling the device
ESP-01
As I wrote above, the ESP-01 has a problem with getting out of deep sleep. ESP-01 can be easily sent into deep sleep by triggering ESP.deepSleep(timeout, mode)
, but the module will never exit it. To solve this problem we have to connect the RESET and GPIO16 pins. This is quite difficult to do due to the small size of the contacts. When the deep sleep timeout expires, the GPIO16 pin will show a low voltage level (LOW), when connected to RESET, it will reboot the ESP-01.
We also need to add some wiring for the ESP-01 to work correctly:
-
0.1uF capacitor between RESET and GND. This capacitor provides a short circuit of the RESET pin to ground when power is turned on, which ensures reliable reset of the module.
-
10K resistor between RESET and VCC. This resistor pulls the RESET pin high when it is not grounded. This prevents the module from being accidentally reset due to noise or interference.
Nutrition
We connect the ionistor directly to the output contacts +/- DC-DC converter. We connect ESP-01 and sensors to the same contacts (to VCC and GND).
We will connect a solar battery to the input of the DC-DC converter. We will install a Schottky diode in front of the positive contact of the DC-DC converter so that at night the ionistor does not begin to discharge through the solar battery.
A few words about the ionistor. I used an ionistor or, as it is also called, a 100F, 3.8V supercapacitor. I liked it because of its low self-discharge. The ionistor provides good current to power the ESP-01, and the module has never frozen for me. Capacitors cost a lot; a 100F capacitor cost me 800 rubles. In appearance and weight, the ionistor resembles a conventional electrolytic capacitor. You also need to keep in mind that ionistors do not last forever; depending on operating conditions, it can last you from 5 to 10 years.
Solar panels
The solar cell blocks were connected in parallel and glued to a plastic board.
The finished panel with 8 solar panels was carefully placed on the balcony. Probably, it was possible to play with the angle of incidence of the sun’s rays and come up with a better solution for greater efficiency. But I decided not to bother with it.
I placed the solar panel close to the window on the street so that as much light as possible would fall on it. It would be even more effective to take it outside, but this would require sealing.
Sensor modules
We connect all sensor modules via I2C to ESP-01. The power supply for the sensors will be the same as for the ESP-01 (3.3V).
I used regular combs with contacts so that I could easily remove the modules (for other projects). I think that for a more correct version of the project, the contacts should be soldered with tin to ensure a reliable connection.
Device case
Magnets were securely glued to the body of the device for mounting on a windowsill. The body itself was treated with sealant.
The white wires protruding from the housing are connected by the solar panel wires.
A plastic cap is used to expose the ventilation holes. Under the outer cap there is another one that protects against moisture. The point is that air can reach the sensors, but for moisture this would be problematic.
If you have a 3D printer, I’m sure you can come up with something much better.
Module connection diagram
We write the firmware
For programming I used PlatformIO.
Firmware code:
// main.cpp
#include <Adafruit_BMP280.h>
#include <Adafruit_HTU31D.h>
#include <Arduino.h>
#include <ArduinoJson.h>
#include <ESP8266WiFi.h>
#include <INA226_WE.h>
#include <PubSubClient.h>
#include <Wire.h> // I2C
#define uS_TO_M_FACTOR 6e7 // Количество микросекунд в минуте
#define DEEP_SLEEP_TIMEOUT (int)(30 * uS_TO_M_FACTOR) // Продолжительность глубокого сна (в минутах)
#define RECONNECTION_LIMIT 3 // Число допустимых попыток переподключения
#define RECONNECTION_DELAY 500 // Задержка перед переподключением (в миллисекундах)
#define WIFI_SSID "ENTER WI-FI SSID"
#define WIFI_PASSWORD "ENTER WI-FI PASSWORD"
#define MQTT_SERVER "ENTER MQTT SERVER IP ADDRESS"
#define MQTT_PORT 1883
#define MQTT_CLIENT_ID "Weather Station"
#define MQTT_TOPIC "devices/weather-station/status"
#define BMP280_I2C 0x76
#define HTU31D_I2C 0x40
#define INA226_I2C 0x41
Adafruit_BMP280 bmp = Adafruit_BMP280();
Adafruit_Sensor *bmp_pressure = bmp.getPressureSensor();
Adafruit_HTU31D htu = Adafruit_HTU31D();
INA226_WE ina226 = INA226_WE(INA226_I2C);
WiFiClient espClient;
PubSubClient client(espClient);
struct sensors_data {
float temperature;
float humidity;
float pressure;
float voltage;
};
struct sensors_data sensors_data;
float convertHumidity(float hPa) {
float one_mmHg_in_Pa = 101325.0 / 760.0;
return (hPa * 100.0) / one_mmHg_in_Pa;
}
void bmpEnable(bool val) {
if (val) {
bmp.setSampling(Adafruit_BMP280::MODE_NORMAL, Adafruit_BMP280::SAMPLING_X16, Adafruit_BMP280::SAMPLING_X16,
Adafruit_BMP280::FILTER_X16, Adafruit_BMP280::STANDBY_MS_1);
} else {
bmp.setSampling(Adafruit_BMP280::MODE_SLEEP, Adafruit_BMP280::SAMPLING_NONE, Adafruit_BMP280::SAMPLING_NONE,
Adafruit_BMP280::FILTER_OFF, Adafruit_BMP280::STANDBY_MS_4000);
}
}
void update_sensors_data() {
// HTU sensor
htu.enableHeater(true); // Enable power
sensors_event_t humidity_event, temperature_event;
htu.getEvent(&humidity_event, &temperature_event);
htu.enableHeater(false); // Disable power
sensors_data.temperature = temperature_event.temperature;
sensors_data.humidity = humidity_event.relative_humidity;
// BMP sensor
bmpEnable(true);
sensors_event_t pressure_event;
bmp_pressure->getEvent(&pressure_event);
bmpEnable(false);
sensors_data.pressure = convertHumidity(pressure_event.pressure);
// INA sensor
ina226.powerUp();
ina226.readAndClearFlags();
sensors_data.voltage = ina226.getBusVoltage_V();
ina226.powerDown();
}
bool wifi_connect() {
if (WiFi.SSID() != "") {
WiFi.begin(); // Быстрое подключение к ранее запомненной Wi-Fi точке (обычно менее 1 сек).
} else {
WiFi.persistent(true); // Разрешить запись данных о последнем Wi-Fi подключении в память
WiFi.mode(WIFI_STA);
WiFi.setAutoConnect(true); // При включении подключаться к последней точке доступа
WiFi.setAutoReconnect(false); // Переподключаться при неудачном подключении
WiFi.begin(WIFI_SSID, WIFI_PASSWORD); // Долгое подключение (обычно около 5 сек).
}
int conn_result = WiFi.waitForConnectResult();
return conn_result == WL_CONNECTED;
}
void mqtt_subscribe_cb(char *topic, byte *payload, unsigned int length) {}
bool send_message(char *message) {
client.setServer(MQTT_SERVER, MQTT_PORT);
int count = 0;
while (!client.connect(MQTT_CLIENT_ID)) {
count += 1;
if (count == RECONNECTION_LIMIT) {
return false;
}
delay(RECONNECTION_DELAY);
}
client.publish(MQTT_TOPIC, message);
client.disconnect();
return true;
}
bool send_sensors_message() {
StaticJsonDocument<256> doc;
char message[256];
doc["temperature"] = sensors_data.temperature;
doc["humidity"] = sensors_data.humidity;
doc["pressure"] = sensors_data.pressure;
doc["voltage"] = sensors_data.voltage;
serializeJson(doc, message);
return send_message(message);
}
bool start_htu() {
int count = 0;
while (!htu.begin(HTU31D_I2C)) {
count += 1;
if (count == RECONNECTION_LIMIT) {
return false;
}
delay(RECONNECTION_DELAY);
};
htu.enableHeater(false);
return true;
}
bool start_bmp() {
int count = 0;
while (!bmp.begin(BMP280_I2C)) {
count += 1;
if (count == RECONNECTION_LIMIT) {
return false;
}
delay(RECONNECTION_DELAY);
}
bmpEnable(false);
return true;
}
bool start_ina() {
int count = 0;
while (!ina226.init()) {
count += 1;
if (count == RECONNECTION_LIMIT) {
return false;
}
delay(RECONNECTION_DELAY);
}
ina226.powerDown();
return true;
}
void setup() {
#if defined(BOARD_ESP_01S) || defined(BOARD_ESP_01)
Wire.begin(2, 0); // Настройка I2C (SDA, SCL)
#endif
#ifdef BOARD_ESP_01S
#define LED_BUILTIN 2 // Для ESP-01S
#endif
#ifdef BOARD_ESP_01
#define LED_BUILTIN 1 // Для ESP-01
#endif
pinMode(LED_BUILTIN, OUTPUT);
if (start_htu() && start_bmp() && start_ina()) {
update_sensors_data();
if (wifi_connect()) {
send_sensors_message();
}
}
// WAKE_RF_DEFAULT - проснуться с включенным модулем Wi-Fi
ESP.deepSleep(DEEP_SLEEP_TIMEOUT, WAKE_RF_DEFAULT);
}
void loop() {}
PlatformIO settings for ESP-01 and ESP-01S:
; platformio.ini
[env:esp_01]
platform = espressif8266
board = esp01_1m
framework = arduino
upload_speed = 3000000
monitor_speed = 74880
lib_deps =
knolleary/pubsubclient@^2.8
adafruit/Adafruit BMP280 Library@^2.3.0
adafruit/Adafruit HTU31D Library@^1.1.0
bblanchon/ArduinoJson@^6.18.3
wollewald/INA226_WE@^1.2.3
build_flags = -D PIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK3 -D BOARD_ESP_01
board_build.f_cpu = 80000000L
[env:esp_01s]
platform = espressif8266
board = esp01_1m
framework = arduino
upload_speed = 3000000
monitor_speed = 74880
lib_deps =
knolleary/pubsubclient@^2.8
adafruit/Adafruit BMP280 Library@^2.3.0
adafruit/Adafruit HTU31D Library@^1.1.0
bblanchon/ArduinoJson@^6.18.3
wollewald/INA226_WE@^1.2.3
build_flags = -D PIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK3 -D BOARD_ESP_01S
board_build.f_cpu = 80000000L
Problems
Leak test
After a couple of rainy days in September, my weather station showed very high humidity readings, around 90%. I didn’t believe these results, because there was no rain outside the window anymore. As it turned out, heavy rain was able to flood the station with water through the ventilation holes in the upper part of the body.
I had to disassemble the case, dry the board and all contents. Fortunately, there was a good gap below between the bottom and the board itself, so the filling of the station was not seriously damaged. I made an extra plastic cap on the inside of the vents to prevent water from getting in and sealed the case again.
This problem did not arise again. The humidity readings were approximately equal to those available online. If I had a 3D printer, the case could be made much better. It is important to ensure that if water enters from above, your housing does not allow it to flow down through the ventilation holes.
Frosty and cloudy days
At night, the weather station uses the energy stored in the ionistor during the day. In winter, sometimes there is not enough sun, but the station had enough of it. Apparently, the large solar battery managed to charge the ionistor to the required values.
Sometimes it was alarming when it was snowing heavily and it was already dark at 4 o’clock in the afternoon. It seemed to me that today there would definitely not be enough charge in the ionistor and the station would stop sending weather readings. But no, even on the darkest day everything worked out. According to my calculations, the ionistor always had a reserve of energy for 3-4 hours before dawn.
The winter cold also had an effect on the ionistor. The lower the temperature, the more energy would be spent on each measurement. I think in cold weather the self-discharge of the ionistor simply increased.
Despite everything, the station worked without interruption all winter; the charge in the ionistor was enough for the whole night with a reserve.
Let’s sum it up
An ionistor and a solar battery are a completely suitable solution for powering autonomous devices. Especially in environments where a lithium battery is not suitable (negative temperatures). Although the ionistor itself does not last forever, such devices can operate for years, and maybe even decades, without requiring maintenance.
The solar battery in this project looks very bulky. I think its size can be reduced by increasing the capacitance of the ionistor or choosing another more power-efficient module instead of ESP.
I would replace the ESP-01 module with something else. ESP is not suitable for low power projects. When using Wi-Fi in ESP-01, the power consumption is too high (70mA to 200mA). I just had it on hand at the time and its miniature size was perfect for the project. Now I would pick up some Bluetooth module from Nordic Semiconductor with low power consumption.
The device body needs to be better thought out. It should not heat up in the summer and get wet in the fall when it rains. The main ventilation openings should not allow water to penetrate into the device. The device board should not be flush against the bottom of the case. If moisture does get inside, this will prevent the board from getting wet.
It was an interesting experience; the device worked for almost a year without maintenance, transmitting data to the MQTT server every half hour. What I liked most was that the device required no maintenance. The autonomous operation of such devices is impressive. The ionistor is an amazing radio component, a “miniature battery” capable of delivering high currents, which may well be useful for storing energy for autonomous projects (automatic watering systems in the country, street lamps, etc.).
Thank you for reading this article to the end, happy DIY!
Acknowledgement and Usage Notice
The editorial team at TechBurst Magazine acknowledges the invaluable contribution of the author of the original article that forms the foundation of our publication. We sincerely appreciate the author’s work. All images in this publication are sourced directly from the original article, where a reference to the author’s profile is provided as well. This publication respects the author’s rights and enhances the visibility of their original work. If there are any concerns or the author wishes to discuss this matter further, we welcome an open dialogue to address potential issues and find an amicable resolution. Feel free to contact us through the ‘Contact Us’ section; the link is available in the website footer.