I have made a Solar Weather Station in a Birdhouse. This is based in this project. I ordered the components and some extra’s to measure lux and rain:
- The Wemos D1 Mini Pro (had this already)
- BME280 for Temperature, Humidity, Pressure (AliExpress)
- BH1750 for Light Luxsensor (AliExpress)
- SI1145 to measure UV Index, IR Light (raw), Visible Light (raw)
- FC-37 raindrop sensor with a LM393 converter (AliExpress) – please see edit at the bottom
- Dew Point calculation sensor
- Absolute Humidity calculation sensor
- 5V 250mA Solar panel (AliExpress) – changed it later to a bigger 840mA (AliExpress)
- TP4056 Charger module (AliExpress) – please see edit at the bottom
- The 3-Pin PCB switch (had this already)
- Screw terminal (had this already)
- 18650 Lithium 3400mAh Battery (AliExpress) – please see edit at the bottom
- Some header pins (AliExpress)
- The PCB board at PCBWay (PCBWay)
I didn’t wanted to make it with an Arduino sketch, but want to make it in ESPHome. So is used the following code in ESPHome for the Wemos:
substitutions:
display_name: SolarWeatherStation
esphome:
name: solar_weather
platform: ESP8266
# board: d1_mini_pro
board: d1_mini
includes:
- SI1145.h
libraries:
- "Adafruit SI1145 Library"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_pass
api:
# Enable logging
logger:
mqtt:
broker: !secret mqtt_broker
birth_message:
topic: solarsensor/birthdisable
payload: disable
will_message:
topic: solarsensor/willdisable
payload: disable
ota:
i2c:
- id: ic_1
sda: 4
scl: 5
scan: true
frequency: 100kHz
binary_sensor:
- platform: gpio
pin:
number: D5
inverted: True
name: ${display_name} Rain
device_class: moisture
filters:
- delayed_on_off: 10000ms
sensor:
- platform: wifi_signal
name: "WiFi Signal Sensor"
update_interval: 25s
- platform: bme280
address: 0x76
update_interval: 15s
temperature:
name: ${display_name} Temp
id: bme280_temperature
oversampling: 4x
filters:
- offset: -1.6
pressure:
name: ${display_name} Pres
id: bme280_pressure
oversampling: 4x
humidity:
name: ${display_name} Humi
id: bme280_humidity
oversampling: 4x
- platform: bh1750
name: ${display_name} Lux
address: 0x23
update_interval: 15s
- platform: template
name: ${display_name} Absolute Humidity
lambda: |-
const float mw = 18.01534; // molar mass of water g/mol
const float r = 8.31447215; // Universal gas constant J/mol/K
return (6.112 * powf(2.718281828, (17.67 * id(bme280_temperature).state) /
(id(bme280_temperature).state + 243.5)) * id(bme280_humidity).state * mw) /
((273.15 + id(bme280_temperature).state) * r); // in grams/m^3
accuracy_decimals: 2
update_interval: 25s
icon: 'mdi:water'
unit_of_measurement: 'g/m³'
- platform: template
name: ${display_name} Dew Point
lambda: return (243.5*(log(id(bme280_humidity).state/100)+((17.67*id(bme280_temperature).state)/(243.5+id(bme280_temperature).state)))/(17.67-log(id(bme280_humidity).state/100)-((17.67*id(bme280_temperature).state)/(243.5+id(bme280_temperature).state))));
unit_of_measurement: °C
update_interval: 25s
icon: 'mdi:thermometer-alert'
- platform: custom
lambda: |-
auto UV_sensor = new SI1145_sensor();
App.register_component(UV_sensor);
return {UV_sensor->visible_sensor, UV_sensor->ir_sensor, UV_sensor->uvindex_sensor};
sensors:
- name: ${display_name} Visible Light
- name: ${display_name} IR Light
- name: ${display_name} UV Index
unit_of_measurement: uvindex
accuracy_decimals: 2
- platform: adc
id: bat_vcc
pin: A0
name: ${display_name} Battery
update_interval: 15s
filters:
- multiply: 5.37
- platform: template
name: ${display_name} Battery Percentage
unit_of_measurement: '%'
update_interval: 15s
lambda: |-
return ((id(bat_vcc).state /4.25) * 100.00);
deep_sleep:
run_duration: 35s
sleep_duration: 5min
The above code does need some tuning. For example the ADC multiply. First of all disable the filter. Than a RealValue between 0-1V will be shown in the ESPHome log. Measure the real battery value with a multiple meter. Then BatteryMeasure / RealValue = Multplier.
Also the Battery Percentage needs some tuning, and the Deep Sleep needs tuning. The 35s is enough to drop some sensor readings and i feel ok with an 5 min sleep.
For the binary rain sensor there is a delayed_on_off so the sensor is not bouncing during the sensor reading.
To read an UV index i did use the SI1145, but the first try wasn’t successfully. I have stacked the sensor on the BH1750 sensor, this is possible because it is a different address.
This is not an integrated sensor so i needed the library for that. I tried it, but i was continously getting 0 values. After all it turned out that a manual library for a I2C and using the integrated I2C is not working together. So i stopped using it for a while. After a while someone posted on github that the I2C frequency wasn’t the same for this custom sensor and the built in I2C of esphome. I changed the code and added:frequency: 100kHz
within in the I2C section and all working now.
To get this working you need to upload the SI1145.h and the library code files to your esphome folder. Get the right SI1145.h here and the library here (upload the Adafruit_SI1145.cpp and Adafruit_SI1145.h file)
I also added the Dewpoint calculation sensor and the Absolute Humidity sensor calculator from the BME280.
To make the project more fun, i decided to create it in a bird house. Did some sawing and nailing, drilled some ventilation holes, made roof protection and divided the electronics part from the bird part. And made it waterproof.
The result:
For Home Assistant i used the following code, but you can also use MQTT Discovery to add the sensors.
# Weather Station
- platform: mqtt
name: Weather Station Temp
state_topic: "solar_weather/sensor/solarweatherstation_temp/state"
unit_of_measurement: "°C"
force_update: true
device_class: temperature
- platform: mqtt
name: Weather Station Humi
state_topic: "solar_weather/sensor/solarweatherstation_humi/state"
unit_of_measurement: "%"
force_update: true
device_class: humidity
- platform: mqtt
name: Weather Station Absolute Humidity
state_topic: "solar_weather/sensor/solarweatherstation_absolute_humidity/state"
icon: mdi:water-percent
unit_of_measurement: "g/m³"
force_update: true
- platform: mqtt
name: Weather Station Pres
state_topic: "solar_weather/sensor/solarweatherstation_pres/state"
unit_of_measurement: "hPa"
force_update: true
device_class: pressure
- platform: mqtt
name: Weather Station Lux
state_topic: "solar_weather/sensor/solarweatherstation_lux/state"
unit_of_measurement: "lux"
device_class: illuminance
force_update: true
- platform: mqtt
name: Weather Station Dewpoint
state_topic: "solar_weather/sensor/solarweatherstation_dew_point/state"
unit_of_measurement: "°C"
force_update: true
device_class: temperature
- platform: mqtt
name: Weather Station UV Index
state_topic: "solar_weather/sensor/solarweatherstation_uv_index/state"
force_update: true
icon: mdi:wall-sconce-round
- platform: mqtt
name: Weather Station Battery
state_topic: "solar_weather/sensor/solarweatherstation_battery/state"
unit_of_measurement: "V"
force_update: true
device_class: battery
- platform: mqtt
name: Weather Station Battery Percentage
state_topic: "solar_weather/sensor/solarweatherstation_battery_percentage/state"
unit_of_measurement: "%"
force_update: true
device_class: battery
- platform: mqtt
name: Weather Station Wifi Signal
state_topic: "solar_weather/sensor/wifi_signal_sensor/state"
unit_of_measurement: "dB"
force_update: true
device_class: signal_strength
At the end it is looking like this:
Edit: Because the sensors are in a Bird house, the temperature is higher compared to the ouside air. To fix this, you can play a little bit with the offset in esphome as i did. Also the light (lux) values aren’t correct. Therefore i create some ventilation holes in the bird house. You can also make your own Stevenson screen instead of a bird house. For the light intensity i created a hole with some plexiglass, behind the hole i glued the lux and light sensor.
Edit 2021:
Also the rain sensor turns out to be not as accurate, so i removed it. Perhaps in future i will try it again, but in the meantime i use a public sensor for this purpose.
As for the Solor panel, it turnes out it workes great, but is a little to less sometime to overcome the nights when there is very less UV on the day. So i changed it to a bigger 840mAh version, which is 165x165mm and covers almost the whole top of the birdhouse.
Edit 2022:
Athough the solar panel is working great, with the Rain sensor it is not a succes. As a deep sleep is needed for saving battery power, you are simple missing rain drops. I made some improvement in the code, as the new ESPHome 2021.12 and newer has some changes with Adafruit libraries. I also changed the rain sensor to a bucket MS-WH-SP-RG
As this is an digital sensor, you can use it with the pulse_counter and connect it to a GPIO.
At last make sure you have an updated version of SI1145.h (more info), i used the following code:
#include "esphome.h"
#include "Adafruit_SI1145.h"
using namespace esphome;
class SI1145_sensor : public PollingComponent {
public:
Adafruit_SI1145 uv;
Sensor *uvindex_sensor = new Sensor();
Sensor *ir_sensor = new Sensor();
Sensor *visible_sensor = new Sensor();
SI1145_sensor() : PollingComponent(60000) { }
void setup() override {
uv.begin();
}
void update() override {
float uvindex = uv.readUV();
uvindex_sensor->publish_state(uvindex / 100.0);
float irlight = uv.readIR();
ir_sensor->publish_state(irlight);
float visible = uv.readVisible();
visible_sensor->publish_state(visible);
}
};
Also i get rid of the solar panel and find a way to connect it constantly to main power (5v), so no battery needed any more. And also the TP4056 is not needed any more. The code is:
substitutions:
display_name: SolarWeatherStation
esphome:
name: solar_weather
platform: ESP8266
board: d1_mini
includes:
- SI1145.h
libraries:
- SPI
- Wire
- adafruit/Adafruit BusIO @ 1.9.6
- "Adafruit SI1145 Library"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_pass
api:
# Enable logging
logger:
mqtt:
broker: !secret mqtt_broker
birth_message:
topic: solarsensor/birthdisable
payload: disable
will_message:
topic: solarsensor/willdisable
payload: disable
ota:
i2c:
- id: ic_1
sda: 4
scl: 5
scan: true
frequency: 100kHz
sensor:
- platform: wifi_signal
name: WiFi Signal Sensor
update_interval: 180s
- platform: pulse_counter
name: ${display_name} Rain
pin:
number: D4
mode: INPUT_PULLUP
unit_of_measurement: 'mm'
icon: 'mdi:weather-rainy'
count_mode:
rising_edge: DISABLE
falling_edge: INCREMENT
internal_filter: 50us
filters:
- multiply: 0.2794
- platform: bme280
address: 0x76
update_interval: 50s
temperature:
name: ${display_name} Temp
id: bme280_temperature
oversampling: 4x
filters:
- offset: -1.6
pressure:
name: ${display_name} Pres
id: bme280_pressure
oversampling: 4x
humidity:
name: ${display_name} Humi
id: bme280_humidity
oversampling: 4x
- platform: bh1750
name: ${display_name} Lux
address: 0x23
update_interval: 50s
- platform: template
name: ${display_name} Absolute Humidity
lambda: |-
const float mw = 18.01534; // molar mass of water g/mol
const float r = 8.31447215; // Universal gas constant J/mol/K
return (6.112 * powf(2.718281828, (17.67 * id(bme280_temperature).state) /
(id(bme280_temperature).state + 243.5)) * id(bme280_humidity).state * mw) /
((273.15 + id(bme280_temperature).state) * r); // in grams/m^3
accuracy_decimals: 2
update_interval: 110s
icon: 'mdi:water'
unit_of_measurement: 'g/m³'
- platform: template
name: ${display_name} Dew Point
lambda: return (243.5*(log(id(bme280_humidity).state/100)+((17.67*id(bme280_temperature).state)/(243.5+id(bme280_temperature).state)))/(17.67-log(id(bme280_humidity).state/100)-((17.67*id(bme280_temperature).state)/(243.5+id(bme280_temperature).state))));
unit_of_measurement: °C
update_interval: 120s
icon: 'mdi:thermometer-alert'
- platform: custom
lambda: |-
auto UV_sensor = new SI1145_sensor();
App.register_component(UV_sensor);
return {UV_sensor->visible_sensor, UV_sensor->ir_sensor, UV_sensor->uvindex_sensor};
sensors:
- name: ${display_name} Visible Light
- name: ${display_name} IR Light
- name: ${display_name} UV Index
unit_of_measurement: uvindex
accuracy_decimals: 2
In this code i updated the interval also. You can remove the battery sensors in HA, as it is not in use anymore.
This looks like a fun project. However, I’d like to suggest something and please don’t take it personal.
You should read a little bit about how a safe birdhouse should be constructed. There are multiple flaws in your design which make it much easier for predators to harm unaware birds – e.g, walls thickness or presence of this stick just below entering hole (birds don’t need it at all, it just make things easier for predators….). And most importantly, hole should be drilled higher, or whole box should be deeper.
Hi Philip, i appreciatie your comment, but keep in mind, this is more a fun project and for purpose of the weather station.
Pingback: Community Highlights: 11th edition – Home Assistant – truvallu.com
Pingback: Community Highlights: 11th version » Define Smart Home
Hello,
I get this error when I try to compile the code:
src/main.cpp: In lambda function:
src/main.cpp:529:28: error: expected type-specifier before ‘SI1145_sensor’
auto UV_sensor = new SI1145_sensor();
^
src/main.cpp:531:89: error: could not convert ‘{, , }’ from ” to ‘std::vector’
return {UV_sensor->visible_sensor, UV_sensor->ir_sensor, UV_sensor->uvindex_sensor};
^
src/main.cpp:532:3: warning: control reaches end of non-void function [-Wreturn-type]
});
^
*** [/data/solarnimeteostanice/.pioenvs/solarnimeteostanice/src/main.cpp.o] Error 1
Hello,
I get this error message when I try to compile the code:
src/main.cpp: In lambda function:
src/main.cpp:525:28: error: expected type-specifier before 'SI1145_sensor'
auto UV_sensor = new SI1145_sensor();
^
src/main.cpp:527:89: error: could not convert '{, , }' from '' to 'std::vector'
return {UV_sensor->visible_sensor, UV_sensor->ir_sensor, UV_sensor->uvindex_sensor};
^
src/main.cpp:528:3: warning: control reaches end of non-void function [-Wreturn-type]
});
^
*** [/data/solarnimeteostanice/.pioenvs/solarnimeteostanice/src/main.cpp.o] Error 1
Did you load the adafruit files ?
Thank you,
but everything is fine now.
For the first time, I didn’t know what to do with the SI1145.h file, what it was supposed to contain. But I already understood that and I have successfully compiled the code.