Hello
Some time ago I made a project on a 3D printer for a weather station,
using the materials on https://github.com/nliaudat/weatherstation?tab=readme-ov-file
I based the station on the wroom 02 module, because it already uses a built-in socket for 18650, at that time it was one of the better choices for me,
after adding a voltage divider and LM393, QMC5883L, 5V 0.6A solar panel.
I set about adapting the Yaml code to my needs, everything in the test phase at home worked quite ok... 18650 cell according to the calculations should last about 30h plus the energy from the panel is known currently very low but in the summer days sufficient.
I put everything together I tested it works, although I must admit I had to make some corrections to the project from the network.... the biggest misfortune was connecting it by screwing it together like a bolt.... I broke a few cables and changed to L-type connector
ok to the point, the station worked about 5h after which it said it had enough and shut down at 3.7v :/ I want it to be wireless and support WiFi connectivity.... I can change to 433Mhz but my neighbour is a ham radio operator and he burnt my modules a couple of times already and I would prefer to avoid this
Please advise me whether to look for a solution with support for another cell, bugs in Yaml or forget about it and pull the wire to the station....
Some time ago I made a project on a 3D printer for a weather station,
using the materials on https://github.com/nliaudat/weatherstation?tab=readme-ov-file
I based the station on the wroom 02 module, because it already uses a built-in socket for 18650, at that time it was one of the better choices for me,
after adding a voltage divider and LM393, QMC5883L, 5V 0.6A solar panel.
I set about adapting the Yaml code to my needs, everything in the test phase at home worked quite ok... 18650 cell according to the calculations should last about 30h plus the energy from the panel is known currently very low but in the summer days sufficient.
I put everything together I tested it works, although I must admit I had to make some corrections to the project from the network.... the biggest misfortune was connecting it by screwing it together like a bolt.... I broke a few cables and changed to L-type connector
ok to the point, the station worked about 5h after which it said it had enough and shut down at 3.7v :/ I want it to be wireless and support WiFi connectivity.... I can change to 433Mhz but my neighbour is a ham radio operator and he burnt my modules a couple of times already and I would prefer to avoid this

Please advise me whether to look for a solution with support for another cell, bugs in Yaml or forget about it and pull the wire to the station....

Quote:.esphome:
name: weather-station
friendly_name: WEATHER STATION
esp8266:
board: esp_wroom_02
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: !!!!!!!!!!!!!!!!!!!!
ota:
password: !!!!!!!!!!!!!!
wifi:
networks:
- ssid: "!!!!!!!!!!
password: !!!!!!!!!!
priority : 1
- ssid: "!!!!!!!!!!!
password: !!!!!!!!!!!!
priority : 2
- ssid: 1!!!!!!!!!!!!!
password: "!!!!!!!!!!!
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "WEATHER STATION"
password: !!!!!!!!!!!!!!!
captive_portal:
# sun:
# latitude: !secret latitude
# longitude: !secret longitude
globals:
- id: enable_magnetometer_serial_output
type: bool
restore_value: no
initial_value: 'false'
i2c:
- id: bus_a
sda: GPIO5
scl: GPIO4
scan: True #True only if hmc5883l not detected at address 0x1E
#frequency: 100kHz (max 400 kHz for hmc5883l)
sensor:
- platform: wifi_signal
name: "${friendly_name} WiFi Signal"
- platform: adc
pin: A0
name: "BATERRY"
id: BATERRY
unit_of_measurement: "%"
accuracy_decimals: 0
update_interval: 20s
filters:
- multiply: 12.2
- calibrate_linear:
- 4.25 -> 100
- 4.13 -> 90
- 4.06 -> 80
- 3.99 -> 70
- 3.92 -> 60
- 3.85 -> 50
- 3.78 -> 40
- 3.71 -> 30
- 3.64 -> 20
- 3.57 -> 10
- 3.48 -> 0
- 3.39 -> -10
- platform: uptime
name: "${friendly_name} Uptime"
id: uptime_sensor
update_interval: 60s
internal: true
on_raw_value:
then:
- text_sensor.template.publish:
id: uptime_human
state: !"lambda |-
int seconds = round(id(uptime_sensor).raw_state);
int days = seconds / (24 * 3600);
seconds = seconds % (24 * 3600);
int hours = seconds / 3600;
seconds = seconds % 3600;
int minutes = seconds / 60;
seconds = seconds % 60;
return (
(days ? String(days) + "d " : "") +
(hours ? String(hours) + "h " : "") +
(minutes ? String(minutes) + "m " : "") +
(String(seconds) + "s")
).c_str();
#https://esphome.io/components/sensor/hmc5883l.html?highlight=hmc5883
#I2C connected : SDA (GPIO21) and SCL (GPIO22)
- platform: qmc5883l
address: 0x0D
field_strength_x:
name: "HMC5883L Field Strength X"
internal: true
id: hmc5883l_x
field_strength_y:
name: "HMC5883L Field Strength Y"
internal: true
id: hmc5883l_y
field_strength_z:
name: "HMC5883L Field Strength Z"
internal: true
id: hmc5883l_z
heading:
name: "${friendly_name} wind heading"
id: hmc5883l_heading
internal: true
filters:
- lambda: |-
if(x < 0){ return x +360;}
else{return x;}
oversampling: 256x
range: 800µT #Supported values are 88µT, 130µT, 190µT, 250µT, 400µT, 470µT, 560µT, 810µT. Default range is ±130µT.
update_interval: 1s #max 160Hz=6.25ms but that component cannot be under 1s
id: meteo_station_HMC5883L_magnetometer
- platform: pulse_meter
pin:
number: GPIO13
unit_of_measurement: 'km/h' #'m/s'
name: '${friendly_name} wind speed'
icon: 'mdi:weather-windy'
internal_filter: 13us
accuracy_decimals: 1
#internal: true
timeout: 1s
# https://fr.wikipedia.org/wiki/An%C3%A9mom%C3%...m%C3%A8tre_%C3%A0_coupelles_(dit_de_Robinson)
# [Wind speed in m/s] = 2PI * [anemometer mid cup to axle lenght in m] * [revolution per seconds] * [unknown correction factor]
# anemometer mid cup to axle lenght = 72.5 mm => 72.5/1000 = 0.0725 m for R
# rotary encoder pulse per revolution : 36
# revolution per seconds = pulses /36 /60
# S = 2PI * 0.0725 * pulses /36 /60 = 0.00021089395
# Speed m/s => Km/h : *3.6 => 0.00075921822
# [unknown correction factor or friction] = ~5 => 0.00075921822 *5
filters:
- multiply: 0.0037960911 #start at ~2km/h
# - calibrate_polynomial:
# degree: 2
# datapoints: # Map 0.0 (from sensor) to 0.0 (true value)
# - 5.0 -> 7.5
# - 10.0 -> x.0
# - 20.0 -> x.0
# - 30.0 -> x.0
# - 40.0 -> 40.0
# - 50.0 -> 50.0
# - 60.0 -> 60.0
id: meteo_station_wind_speed
- platform: template
name: '${friendly_name} Wind speed avg 1s'
unit_of_measurement: 'km/h' #'m/s'
update_interval: 300ms #60s
lambda: |-
return id(meteo_station_wind_speed).state;
filters:
- sliding_window_moving_average:
window_size: 3
send_every: 3
send_first_at: 3
id: meteo_station_wind_speed_avg_1s
- platform: template
name: '${friendly_name} Wind speed avg 3s'
unit_of_measurement: 'km/h' #'m/s'
update_interval: 1s #60s
lambda: |-
return id(meteo_station_wind_speed).state;
filters:
- sliding_window_moving_average:
window_size: 3
send_every: 3
send_first_at: 3
id: meteo_station_wind_speed_avg_3s
- platform: template
name: '${friendly_name} Wind speed avg 60s'
unit_of_measurement: 'km/h' #'m/s'
update_interval: 1s
lambda: |-
return id(meteo_station_wind_speed).state;
filters:
- sliding_window_moving_average:
window_size: 60
send_every: 60
send_first_at: 60
id: meteo_station_wind_speed_avg_60s
- platform: template
name: '${friendly_name} Wind speed max'
unit_of_measurement: 'km/h' #'m/s'
update_interval: 60s
lambda: |-
return id(meteo_station_wind_speed).state;
filters:
- max:
window_size: 5
send_every: 5
send_first_at: 2
id: meteo_station_wind_speed_max
# - platform: pulse_counter
# pin:
# number: GPIO38
# mode: INPUT_PULLUP
# unit_of_measurement: 'mm'
# name: "${friendly_name} rain gauge"
# icon: 'mdi:weather-rainy'
# id: rain_gauge
# internal: true
# count_mode:
# rising_edge: DISABLE
# falling_edge: INCREMENT
# internal_filter: 13us
# update_interval: 60s
# filters:
# Each 0.011" (0.2794mm) of rain causes one momentary contact closure
# - multiply: 0.2794
# accuracy_decimals: 4
# - platform: integration
# name: '${friendly_name} rainfall per min'
# id: rain_per_min
# time_unit: min
# unit_of_measurement: 'mm'
# icon: 'mdi:weather-rainy'
# sensor: rain_gauge
# - platform: total_daily_energy
# name: "${friendly_name} total daily rain"
# power_id: rain_gauge
# unit_of_measurement: 'mm'
# icon: 'mdi:weather-rainy'
# x60 To convert to aggregated rain amount
# filters:
# - multiply: 60
# - platform: bme280
# address: 0x76
# update_interval: 60s
# iir_filter: 16x
# temperature:
# name: '${friendly_name} temperature'
# id: bme280_temperature
# oversampling: 16x
# humidity:
# name: "${friendly_name} humidity"
# id: bme280_humidity
# oversampling: 16x
# pressure:
# name: "${friendly_name} pressure"
# id: bme280_pressure
# oversampling: 16x
# - platform: tsl2561
# name: "${friendly_name} ambient Light"
# address: 0x39
# update_interval: 60s
# integration_time: 14ms
# gain: 1x
# - platform: adc
# pin: GPIO35
# name: "${friendly_name} input voltage"
# icon: mdi:car-battery
# attenuation: 11db
# accuracy_decimals: 2
# filters:
# - calibrate_linear:
# - 3.24 -> 12.01
# - 2.80 -> 10.78
# - platform: ina219
# address: 0x40
# shunt_resistance: 0.1 ohm
# current:
# name: "${friendly_name} solar current"
# power:
# name: "${friendly_name} solar power"
# id: solar_power
# bus_voltage:
# name: "${friendly_name} solar voltage"
# icon: mdi:car-battery
# shunt_voltage:
# name: "${friendly_name} solar shunt voltage"
# max_voltage: 26V
# max_current: 3.2A
# update_interval: 60s
# - platform: total_daily_energy
# name: "${friendly_name} total daily solar energy"
# power_id: solar_power
# unit_of_measurement: "Wh"
# accuracy_decimals: 2
# - platform: sun
# name: "${friendly_name} sun elevation"
# type: elevation
# update_interval: 120s
# - platform: sun
# name: "${friendly_name} Sun azimuth"
# type: azimuth
# update_interval: 120s
- platform: template
name: "${friendly_name} true heading"
unit_of_measurement: '°'
lambda: |-
// Taken from calibrate.py or magcal
float hard_iron_bias_x = 41.45884154873271 ;
float hard_iron_bias_y = -87.79628696573607 ;
float hard_iron_bias_z = 569.4171225039286 ;
double soft_iron_bias_xx = 0.5823136909144911 ;
double soft_iron_bias_xy = 0.007124620314368133 ;
double soft_iron_bias_xz = -0.024442807568982334 ;
double soft_iron_bias_yx = 0.00712462031436818 ;
double soft_iron_bias_y = 0.5906868599676302 ;
double soft_iron_bias_yz = 0.005356720947343228 ;
double soft_iron_bias_zx = -0.024442807568982372 ;
double soft_iron_bias_zy = 0.005356720947343263 ;
double soft_iron_bias_zz = 0.7210550285247264 ;
// get values x,y,z and subtract the hard iron offset
float xm_off = id(hmc5883l_x).state - hard_iron_bias_x;
float ym_off = id(hmc5883l_y).state - hard_iron_bias_y;
float zm_off = id(hmc5883l_z).state - hard_iron_bias_z;
// multiply by the inverse soft iron offset
float xm_cal = xm_off * soft_iron_bias_xx + ym_off * soft_iron_bias_yx + zm_off * soft_iron_bias_zx;
float ym_cal = xm_off * soft_iron_bias_xy + ym_off * soft_iron_bias_y + zm_off * soft_iron_bias_zy;
//not needed : float zm_cal = xm_off * soft_iron_bias_xz + ym_off * soft_iron_bias_yz + zm_off * soft_iron_bias_zz;
//float heading = atan2(ym_cal, xm_cal);
float heading = atan2(0 - xm_cal, ym_cal);
//heading += id(magnetic_declination);
if(id(enable_magnetometer_serial_output) == true){
ESP_LOGD("main", "%.1f,%.1f,%.1f", id(hmc5883l_x).state, id(hmc5883l_y).state, id(hmc5883l_z).state);
}
// Correct for when signs are reversed.
if (heading < 0) {
heading += 2*PI;
}
// Check for wrap due to addition of declination.
if (heading > 2*PI) {
//heading -= 2*PI;
}
float headingDegrees = heading * 180/M_PI; // Convert radians to degrees.
return headingDegrees;
update_interval: 1s
id: meteo_station_wind_true_heading
text_sensor:
# - platform: template
# name: "${friendly_name} wind cardinal direction" #16 cardinals points
# lambda: |-
# float deg = id(meteo_station_wind_true_heading).state;
# if(deg < 0){ deg= 360+deg;}
# if ((deg >= 11.25) and (deg < 33.75)) {return {"NNE"} ;}
# else if ((deg >= 33.75) and (deg < 56.25)) {return {"NE"} ;}
# else if ((deg >= 56.25) and (deg < 78.75)) { return {"ENE"} ;}
# else if ((deg >= 78.75) and (deg < 101.25)) {return {"E"} ;}
# else if ((deg >= 101.25) and (deg < 123.75)) {return {"ESE"} ;}
# else if ((deg >= 123.75) and (deg < 146.25)) {return {"SE"} ;}
# else if ((deg >= 146.25) and (deg < 168.75)) {return {"SSE"} ;}
# else if ((deg >= 168.75) and (deg < 191.25)) {return {"S"} ;}
# else if ((deg >= 191.25) and (deg < 213.75)) {return {"SSW"} ;}
# else if ((deg >= 213.75) and (deg < 236.25)) {return {"SW"} ;}
# else if ((deg >= 236.25) and (deg < 258.75)) {return {"WSW"} ;}
# else if ((deg >= 258.75) and (deg < 281.25)) {return {"W"} ;}
# else if ((deg >= 281.25) and (deg < 303.75)) {return {"WNW"} ;}
# else if ((deg >= 303.75) and (deg < 326.25)) {return {"NW"} ;}
# else if ((deg >= 326.25) and (deg < 348.75)) {return {"NNW"} ;}
# else {return {"N"} ;}
# update_interval: 1s
# id: meteo_station_wind_direction
- platform: template
name: "${friendly_name} wind cardinal direction" #8 cardinals points
lambda: |-
float deg = id(meteo_station_wind_true_heading).state;
if(deg < 0){ deg= 360+deg;}
if ((deg >= 0) and (deg < 22.5)) {return {"N"} ;}
else if ((deg >= 22.5) and (deg < 56.25)) { return {"NE"} ;}
else if ((deg >= 56.25) and (deg < 123.75)) { return {"E"} ;}
else if ((deg >= 123.75) and (deg < 168.75)) {return {"SE"} ;}
else if ((deg >= 168.75) and (deg < 213.75)) {return {"S"} ;}
else if ((deg >= 213.75) and (deg < 258.75)) {return {"SW"} ;}
else if ((deg >= 258.75) and (deg < 303.75)) {return {"W"} ;}
else if ((deg >= 303.75) and (deg < 348.75)) {return {"NW"} ;}
else {return {"N"} ;}
update_interval: 1s
id: meteo_station_wind_direction
- platform: template
name: "${friendly_name} uptime"
id: uptime_human
icon: mdi:clock-start
# - platform: sun
# name: "${friendly_name} next sunrise"
# type: sunrise
# update_interval: 4h
# - platform: sun
# name: "${friendly_name} next sunset"
# type: sunset
# update_interval: 4h
time:
- platform: sntp
timezone : Europe/Zurich
#timezone: UTC+1
servers: [0.pool.ntp.org, 1.pool.ntp.org , 2.pool.ntp.org]
on_time:
- seconds: 0
minutes: 0
hours: 6
days_of_week: MON
then:
- switch.toggle: switch_meteo_station_reboot
id: meteo_station_time
# interval:
# - interval: 60s
# then:
# - sensor.integration.reset: rain_per_min
web_server:
port: 80
switch:
- platform: restart
name: "${friendly_name} reboot"
id: switch_meteo_station_reboot
- platform: template
name: "Toogle magnetometer serial output"
turn_on_action:
- script.execute: toogle_magnetometer_serial_output
script:
- id: toogle_magnetometer_serial_output
then:
- lambda: |-
ESP_LOGD("main", "toogle magnetometer calibration output");
id(enable_magnetometer_serial_output) = !id(enable_magnetometer_serial_output) ;
deep_sleep:
run_duration: 1min
sleep_duration: 15min