selfmade
(Achim)
November 16, 2025, 10:18am
1
Hello,
I’m just starting out with ESPhome programming.
I’m trying to pass a parameter to a script.
This script, “check_heaterLevel_upDown,” is supposed to compare the passed value “levelNow” with the global variable “heat_level_now” to see if the value is above or below the current level.
I was thinking of using on_value_range.
script:
- id: check_heaterLevel_upDown
parameters:
levelNow: int
then:
- on_value_range:
above: !lambda id(heat_level_now);
script.execute: calc_minRunTimeInHeatLevel
script.execute: heaterLevel_minus
below: !lambda id(heat_level_now);
script.execute: calc_minRunTimeInHeatLevel
script.execute: heaterLevel_plus
This code also seems to be incorrect.
script:
- id: check_heaterLevel_upDown
parameters:
levelNow: int
then:
- on_value_range:
above: !lambda id(heat_level_now);
- script.execute: calc_minRunTimeInHeatLevel
- script.execute: heaterLevel_minus
below: !lambda id(heat_level_now);
- script.execute: calc_minRunTimeInHeatLevel
- script.execute: heaterLevel_plus
But no matter what I do, I get an error message saying my syntax is incorrect.
mapping values are not allowed here
in "/config/esphome/test1.yaml", line 184, column 25
Can anyone help me with this?
zoogara
(Daryl)
November 16, 2025, 10:44am
2
Post your full yaml - that will help us diagnose the issue…
selfmade
(Achim)
November 16, 2025, 11:01am
3
---
substitutions:
devicename: esp32-s2-mini-saola
board: esp32-s2-saola-1
upper_devicename: ESP32_S2_TestBoard
device_location: Schreibtisch
device_description: Testboard using ESPhome firmware
ipaddress: !secret ESP32_S2_TESTBOX_IP
last_update: "2025-10-23 22:54:12"
esphome:
name: esp32-s2-mini-saola
comment: Testboard
includes: []
libraries: []
build_path: ESP32_S2_TestBoard
platformio_options: {}
esp32:
board: esp32-s2-saola-1
framework:
type: esp-idf
api:
encryption:
key: !secret ESPHOME_API_KEY
wifi:
power_save_mode: none # none (default for esp8266), light (default for esp32), high
ssid: !secret WLAN_ASUS_SSID
password: !secret WLAN_ASUS_PASSWORD
manual_ip:
static_ip: !secret ESP32_S2_TESTBOX_IP
gateway: !secret WLAN_ASUS_GATEWAY_IP
subnet: !secret WLAN_ASUS_SUBNET
dns1: !secret WLAN_ASUS_DNS1
ap:
ssid: "ESP32-S2-MINI-Testboard"
password: !secret WIFI_AP_PASSWORD
ota:
- platform: esphome
#safe_mode: true
password: !secret HA_OTA_PASSWORD
web_server:
port: 80
auth:
username: admin
password: admin
globals:
# global int variable
- id: heater_run
type: int
restore_value: no
initial_value: '0'
- id: heat_level
type: int
restore_value: no
initial_value: '10'
- id: heat_level_now
type: int
restore_value: no
initial_value: '0'
- id: set_heat_level_to
type: int
restore_value: no
initial_value: '0'
# global string variable
- id: string_heater_run_yes
type: std::string
restore_value: yes
max_restore_data_length: 24
initial_value: '"Heizung ist An"'
- id: string_heater_run_no
type: std::string
restore_value: yes
max_restore_data_length: 24
initial_value: '"Heizung ist Aus"'
- id: heater_minRunTimeInHeatLevel
type: int
restore_value: no
initial_value: '0'
- id: calc_startTime
type: int
restore_value: no
# initial_value: '0'
initial_value: '0'
- id: calc_endTime
type: int
restore_value: no
initial_value: '0'
remote_receiver:
pin: GPIO18
#dump: all # rc_switch
dump: # dump: all
- rc_switch
# Settings to optimize recognition of RF devices
tolerance: 50%
idle: 4ms
remote_transmitter:
pin: GPIO17
carrier_duty_percent: 100% # change from 100% to 50%
sensor:
- platform: dht
pin: GPIO11
model: AM2302
temperature:
name: "Garage Temperatur DHT_1"
id: TEMP_DHT_1
unit_of_measurement: "°C"
accuracy_decimals: 2
humidity:
name: "Garage Luftfeuchtigkeit DHT_1"
id: HUMIDITY_DHT_1
unit_of_measurement: "%"
accuracy_decimals: 2
update_interval: 10s
- platform: template
name: "Temp Garage delta"
id: tempGarage_delta
unit_of_measurement: "°C"
accuracy_decimals: 2
update_interval: 60s
lambda: |-
return id(TEMP_DHT_1).state - id(garage_thermostat).target_temperature;
on_value:
then:
- script.execute: update_vevor_heaster_power
# Example configuration entry
climate:
- platform: thermostat
name: "Garage Vevor Heizung"
id: garage_thermostat
sensor: TEMP_DHT_1
heat_deadband: 0.0
heat_overrun: 0.0
visual:
min_temperature: 15
max_temperature: 30
temperature_step: 0.1
min_heating_off_time: 2s
min_heating_run_time: 2s
min_idle_time: 2s
heat_action: []
idle_action: []
preset:
- name: Kodus
default_target_temperature_low: 20 °C
- name: Eemal
default_target_temperature_low: 18 °C
script:
- id: check_heaterLevel_upDown
parameters:
levelNow: int
then:
on_value_range:
above: !lambda id(heat_level_now);
- script.execute: calc_minRunTimeInHeatLevel
- script.execute: heaterLevel_minus
below: !lambda id(heat_level_now);
script.execute: calc_minRunTimeInHeatLevel
script.execute: heaterLevel_plus
- id: heaterLevel_plus
parameters:
heater: int
then:
- remote_transmitter.transmit_rc_switch_raw:
#code Plus
code: '00011100010111100000100011110000'
protocol:
pulse_length: 255
repeat:
times: 5
wait_time: 0s
- logger.log: Heizung Plus!
- id: heaterLevel_minus
parameters:
heater: int
then:
- remote_transmitter.transmit_rc_switch_raw:
#code Plus
code: '00011100010111100000001010001000'
protocol:
pulse_length: 255
repeat:
times: 5
wait_time: 0s
- logger.log: Heizung Minus!
- id: calc_minRunTimeInHeatLevel
parameters:
delta_degress: float
then:
- lambda: |-
// id(calc_startTime) = millis();
int tempStartTime = millis();
int tempCalc_startTime = calc_startTime;
int tempCalc_endTime = calc_endTime;
// heat_level
if (delta_degress < 0.5) {
id(tempCalc_endTime) = (id(calc_tempCalc_startTime) + (1 * 60000));
if (temp_calcStartTime > tempCalc_endTime) && (heat_level > set_heat_level_to){
id(calc_endTime) = (id(calc_startTime) + (1 * 60000));
}
}
if (delta_degress < 1) {
id(calc_endTime) = id(calc_startTime) + (2 * 600000);
}
if (delta_degress < 1.5) {
id(calc_endTime) = id(calc_startTime) + (3 * 600000);
}
if (delta_degress < 2) {
id(calc_endTime) = id(calc_startTime) + (4 * 600000);
}
if (delta_degress < 3) {
id(calc_endTime) = id(calc_startTime) + (6 * 600000);
}
if (delta_degress < 4) {
id(calc_endTime) = id(calc_startTime) + (8 * 600000);
}
if (delta_degress < 10) {
id(calc_endTime) = id(calc_startTime) + (10 * 600000);
}else{
id(calc_endTime) = id(calc_startTime) + (15 * 600000);
}
- id: update_vevor_heaster_power
mode: restart
then:
- if:
# Heizstufe 10
condition:
sensor.in_range:
id: tempGarage_delta
below: -3.0
then:
- script.execute:
id: heaterLevel_plus
heater: 3
- if:
# Heizstufe 9
condition:
sensor.in_range:
id: tempGarage_delta
below: -2.5
above: -3.0
then:
- script.execute:
id: heaterLevel_minus
heater: 5
- if:
# Heizstufe 8
condition:
sensor.in_range:
id: tempGarage_delta
below: -2.0
above: -2.49
then:
- lambda: |-
id(set_heat_level_to) = 5;
id(heat_level_now) = (id(heat_level) - id(set_heat_level_to));
- logger.log: Heizung 3 x Minus
- if:
# Heizstufe 7
condition:
sensor.in_range:
id: tempGarage_delta
below: -1.6
above: -1.99
then:
- lambda: |-
id(set_heat_level_to) = 5;
id(heat_level_now) = (id(heat_level) - id(set_heat_level_to));
- logger.log: Heizung 4 x Minus
- if:
# Heizstufe 6
condition:
sensor.in_range:
id: tempGarage_delta
below: -1.2
above: -1.59
then:
- lambda: |-
id(set_heat_level_to) = 5;
id(heat_level_now) = (id(heat_level) - id(set_heat_level_to));
- logger.log: Heizung 2 x Minus
- if:
# Heizstufe 5
condition:
sensor.in_range:
id: tempGarage_delta
below: -0.9
above: -1.19
then:
- lambda: |-
id(set_heat_level_to) = 5;
id(heat_level_now) = (id(heat_level) - id(set_heat_level_to));
- logger.log: Heizung 222 x Minus
- if:
# Heizstufe 4
condition:
sensor.in_range:
id: tempGarage_delta
below: -0.6
above: -0.89
then:
- lambda: |-
id(set_heat_level_to) = 5;
id(heat_level_now) = (id(heat_level) - id(set_heat_level_to));
- logger.log: Heizung 3333 x Minus
- if:
# Heizstufe 3
condition:
sensor.in_range:
id: tempGarage_delta
below: -0.4
above: -0.59
then:
- lambda: |-
id(set_heat_level_to) = 5;
id(heat_level_now) = (id(heat_level) - id(set_heat_level_to));
- logger.log: Heizung 2333 x Minus
- if:
# Heizstufe 2
condition:
sensor.in_range:
id: tempGarage_delta
below: -0.1
above: -0.39
then:
- lambda: |-
id(set_heat_level_to) = 5;
id(heat_level_now) = (id(heat_level) - id(set_heat_level_to));
- logger.log: Heizung 255555 x Minus
- if:
# Heizstufe 1
condition:
sensor.in_range:
id: tempGarage_delta
above: 0
then:
- lambda: |-
id(set_heat_level_to) = 5;
id(heat_level_now) = (id(heat_level) - id(set_heat_level_to));
- logger.log: Heizung 266666 x Minus
switch:
- platform: gpio
pin: GPIO10
name: "Heizung Strom An/Aus"
id: RelayHeater
button:
- platform: template
name: Heizung An
id: heaterOn
on_press:
- remote_transmitter.transmit_rc_switch_raw:
code: '00011100010111100001000110110000'
protocol:
pulse_length: 255
repeat:
times: 5
wait_time: 0s
- logger.log: Heizung ANgeschaltet!
- platform: template
name: Heizung Aus
id: heaterOff
on_press:
- remote_transmitter.transmit_rc_switch_raw:
code: '00011100010111100000010100001000'
protocol:
pulse_length: 255
repeat:
times: 5
wait_time: 0s
- logger.log: Heizung AUSgeschaltet!
- platform: template
name: Heizleistung Plus
id: heaterPlus
on_press:
- remote_transmitter.transmit_rc_switch_raw:
code: '00011100010111100000100011110000'
protocol:
pulse_length: 255
repeat:
times: 5
wait_time: 0s
- platform: template
name: Heizleistung Minus
id: heaterMinus
on_press:
#- script.call: heizleistung_1
- remote_transmitter.transmit_rc_switch_raw:
code: '00011100010111100000001010001000'
protocol:
pulse_length: 255
repeat:
times: 5
wait_time: 0s
improv_serial:
## Enable logging
logger:
level: DEBUG
baud_rate: 9600
Attempt at an explanation of the code:
What I want to achieve with the code:
It’s about controlling a slow-reacting diesel garage heater that often has a temperature difference of about 15°C between the actual and target temperatures when first switched on.
The heater has exactly 10 heating levels and starts at the highest level, 10, after every restart.
So, before I can regulate the heater using temperature measurements and try to maintain the target temperature, the heater first needs to run for a specific, predetermined time at a particular heating level.
If I don’t do this, the heater would just keep switching back and forth.
Therefore, I need temperature differences and switching times.
zoogara
(Daryl)
November 16, 2025, 11:35am
4
Actually - I didn’t need your yaml - Sunday arvo has fuzzed my brain and I didn’t notice that on_value_range: isn’t valid for scripts.
You need to test the parameter value in lambda - for example:
script:
- id: check_heaterLevel_upDown
parameters:
levelNow: int
then:
- if:
condition:
lambda: 'return levelNow >= id(heat_level_now);'
then:
script.execute: calc_minRunTimeInHeatLevel
script.execute: heaterLevel_minus
etc...
1 Like
selfmade
(Achim)
November 16, 2025, 2:48pm
5
Thank you,
yes,
i was just trying it with lambdas, and the code worked (better ).
I just wasn’t sure if I had the wrong syntax or if on_value_range simply doesn’t work in the script, since I’ve only ever seen on_value_range used in Sensor and, I think, Number functions as examples.
I’ve now solved it with lambdas and if statements.
However, the syntax and notation you have to use in ESPHome is really quite confusing at times.
For example, the compiler doesn’t throw an error during the initial code check when you call execute under lambda, but after it’s almost finished compiling, it finally throws the error that it doesn’t like the execute command.
code snipped:
script:
- id: check_heaterLevel_upDown
parameters:
levelNow: int
then:
lambda: |-
if(id(heat_level_now) > levelNow){
//id(calc_minRunTimeInHeatLevel).execute();
if(id(heat_level_now) > levelNow){
id(heaterLevel_minus).execute();
}
};
if(id(heat_level_now) < levelNow){
//id(calc_minRunTimeInHeatLevel).execute();
if(id(heat_level_now) > levelNow){
id(heaterLevel_plus).execute();
}
};
Compiling .pioenvs/esp32-s2-mini-saola/src/main.cpp.o
/config/esphome/test1.yaml: In lambda function:
/config/esphome/test1.yaml:192:37: error: no matching function for call to 'esphome::script::SingleScript<int>::execute()'
192 | id(heaterLevel_minus).execute();
| ~~~~~~~~~~~~~~~~~~~~~~~~^~
In file included from src/esphome.h:88,
from src/main.cpp:3:
src/esphome/components/script/script.h:68:8: note: candidate: 'void esphome::script::SingleScript<Ts>::execute(Ts ...) [with Ts = {int}]'
68 | void execute(Ts... x) override {
| ^~~~~~~
but i try and try and hope i find out my misstakes
edit:
i find now more and more the target
this code now run… looks now much better
step by step
script:
- id: check_heaterLevel_upDown
parameters:
levelNow: int
then:
lambda: |-
if(id(heat_level_now) > levelNow){
id(heaterLevel_minus)->execute(levelNow);
};
if(id(heat_level_now) < levelNow){
id(heaterLevel_plus)->execute(levelNow);
};