Hi, I’m using a speed fan component to control dc motor shades. Maybe this isn’t the proper way to do it, but I got everything working as expected when controlling the LEDC speed pin directly, i.e.
I assume you did not find a solution to directly access the PWM’s current value?
ESP-IDF does offer a function ledc_get_duty, but it needs to know the channel that is used for your output’s PWM. And channel_ is a protected attribute of the ESPHome LEDCOutput class.
If one can assume a specific channel is used, which is true when only using a single PWM pin, then with:
// The actual PWM channel is stored in a protected attribute,
// so cannot be accessed. Assume the first channel is used:
auto channel = LEDC_CHANNEL_0;
// Only valid with high speed support; see SOC_LEDC_SUPPORT_HS_MODE in
// https://github.com/esphome/esphome/blob/f20aaf398162cf9c19cf99ad7a22343ff04bef5e/esphome/components/ledc/ledc_output.cpp
auto speed_mode = channel < 8 ? LEDC_HIGH_SPEED_MODE : LEDC_LOW_SPEED_MODE;
auto duty = ledc_get_duty(speed_mode, channel);
auto hpoint = ledc_get_hpoint(speed_mode, channel);
ESP_LOGI("my_app",
"LEDC status: channel=%d; speed_mode=%d; duty=%d; hpoint=%d",
channel,
speed_mode,
duty == LEDC_ERR_DUTY ? -1 : duty,
hpoint == LEDC_ERR_VAL ? -1 : hpoint
);
I only use the above for debugging. (Specifically for an issue with a display backlight that somehow does not adhere to id(my_ledc_output).set_level(my_brightness) if that code runs too early.) But I guess ESPHome expects us to keep the last known value in a sensor in Home Assistant, or in globals, or in a static variable in the lambda.
So, curious: is there a reason why you cannot use your id(motor_speed) to get the last known value? If you want to be truly sure the motor is running then you need a sensor that actually measures that, and not rely on the PWM’s internal housekeeping, I guess.
state : Retrieve the current state (on/off) of the fan.
// Within lambda, get the fan state and conditionally do something
if (id(my_fan).state) {
// Fan is ON, do something here
} else {
// Fan is OFF, do something else here
}
speed : Retrieve the current speed of the fan.
// Within lambda, get the fan speed and conditionally do something
if (id(my_fan).speed == 2) {
// Fan speed is 2, do something here
} else {
// Fan speed is not 2, do something else here
}
Nice!
@EvanVanVan, I guess you should not use id(speed_pin).set_level either. Instead, I think you need something like:
With the above, id(my_light_id).current_values.get_brightness() always seemed to yield 1.0, even after I changed the brightness. But I was setting the brightness in the wrong way, so the internal state of my Light was not updated.
Using id(my_light_id).turn_on().set_brightness(0.2).perform() as documented nicely changes the brightness. And makes get_brightness() work fine too.
But as I forgot to include .perform(), the call had no effect. Next, I found documentation that seems to suggest one can also use id(my_output_id).set_level(0.2). That indeed works as well. (Well, for me only if not executed in the first few runs of Display’s lambda.) But then get_brightness() always yields 1.0 as Light’s internal state does not know about the direct change I made.