Invert ledc at runtime

I’m using ledc to run a fan, can I set it inverted while its running or can that only be done at compilation?

I tried using a lambda doesnt seem to work.
I’m very new to esphome and yaml so im probably doing something wrong

output:
  - platform: ledc
    pin: GPIO21
    id: fan_pwm                                                                                                                                                                          
    frequency: 4882Hz
    inverted: true                                                                                                                                                                   

fan:
  - platform: speed
    output: fan_pwm
    name: Fan
    speed_count: 100
    id: fan 
    on_turn_on:
    - lambda: |-
        id(fan_pwm).set_inverted(false);
    - fan.turn_on:
        id: fan
        speed: 20
    - fan.turn_on: fan
    - logger.log: "Fan Turned On!"
    on_turn_off:
    - lambda: |-
        id(fan_pwm).set_inverted(true);

Why would you want to change it? You shouldnt need to if an inverted or not inverted gpio controls the fan, then thats your fan control and you shouldnt have other stuff wired to the same gpio, right?

Nothing else is wired to that gpio, I just want to know how to invert the pin.

You do know what ‘Inverted’ is for right? So if a GPIO needs to turn something on/off, you can send logic High or Logic Low because some things need one or the other.

To invert it, it tells you right there in the Docs. The other thing I just noticed is, You already have it Inverted…

What are you trying to accomplish by changing the pin to inverted/not inverted in your config? Are you trying to use that as an ON/OFF switch of some kind? It tells you in the Docs how to to turn the Fan/Output On/OFF. You gotta check that stuff out or else you’re gonna be lost here,. Read those Documentations!

The ‘Inverted’ configuration is talked about right at the very top of the Output page in the Docs. Have you looked at the documentation?

Yes I know what inverted means, in this case it needs high level to stay off but responds to pwm in the normal way while its running, which is why i need the ability to invert the direction when it gets turned on/off. I didnt sdesign the thing just trying to work with it

Well without knowing what “the thing” is, without being able to look up a data sheet or having a security clearence to know about any other details then this is as far as i can help you. What I can tell you though is you cant dynamically change the boolean and toggle the invert configuration on/off. Thats a fixed configuration and can only be changed by reflashing the board. There may may be other ways to do what you want or extra circuitry perhaps but, at this point id just be taking blind guesses and wasting mine and your time.

My fault, I forgot it was a fan. You got a brand and model number? Any details?

I guess im just confused why your fan is the only one ive ever seen that wont turn on/off by calling the fan.turn_on/turn_off or by manually setting the output level to 0.

Calling the fan.turn_on/off does exactly what you need. It. When you call fan.turn_off: does the fan keep spinning?

Which one of these services did you try snd what did it do or not do?

When you say “PWM in the normal way”, are you saying “high” is “off”, but 99% duty cycle (i.e. high for 99% of the time, low for 1%) would be almost full speed (which would be very odd)? Or is actually just inverted, so that 99% high, 1% low would be 1% speed, and 100% high is off? In which case, I don’t understand why just inverting the output pin wouldn’t just work.

You dont understand? I explained it to you. You cant change the pin schema without reflashing. These are not dynamic values that can be changed while the program is running.

You are overthinking this and making it more complicated than it is. It goes over all this in the documentation too. Reading that would clear up the confusion you’re having and you wouldnt be wasting your time trying to reinvent the wheel here.

I assume you didnt try the services like i told you? You wouldnt still be asking if you did. I told you, the service fan.turn_off is basically the same thing as inverting the pin back. It either takes the pwm down to 0% or up to 100% depending on how you configured the pin to begin with. It turns the gpio OFF for you and it knows which way to take it because its the opposite of however you set it up, thats it, its that simple, just go try it. Geeze

“Turns the Output with the given ID OFF when executed”
You have to read the documentation. You cant just go around calling “gpio.invert” functions that dont exist. They make these documents really simple for new people to learn but, you have to actually read them.

Did you get this inversion to work? Unfortunately all the other comments here aren’t helpful at all (as so often ignoring the original question completely and asking “why do you want to do that?”).
I’m checking the C3’s reference manual and there is a bit in the GPIO_FUNCn_OUT_SEL_CFG_REG configuration register (this register exists for every pin with “n” being the pin number) to invert the output logic:

GPIO_FUNCn_OUT_INV_SEL 0: Do not invert the output value; 1: Invert the output value. (R/W)

This is very likely the bit that esphome sets when using inverted: true on a pin. I just do not know how to set/unset it with esphome (or the Arduino framework, which esphome uses in the background) in a lambda.

In arduino code the syntax would be:
GPIO.func_out_sel_cfg[Your_GPIO_Number].inv_sel = 1;

Thank you! That’s even simpler than I thought.

Something to add, because I’ve been trying things out since my previous post (well, tried if they compile, not if they work :wink: ). In my case I need to invert a TX pin only. esphome allows inverting UART pins with the extended pin schema configuration. The problem is that the underlying Arduino framework apparently does not allow (or just hasn’t the functions for it) to invert RX and TX independently on initialization. To get around that I was searching for the “invert at runtime” which led me to this topic.

So slightly off-topic (because it concerns UART, not general IO), this is what I came up with.

uart:
  - id: bsb_uart
    baud_rate: 4800
    parity: even
    stop_bits: 1
    tx_pin:
      number: GPIO7
      inverted: true
    rx_pin:
      number: GPIO6
      inverted: true # will be "re-inverted" after boot; Arduino does not allow differing inv setting for UART on setup

I invert the pins right at the setup so TX never is enabled “non-inverted”. Then after boot:

on_boot:
  then:
    - lambda: |-
        // choose on of the following
        uart_set_line_inverse(id(bsb_uart).get_hw_serial_number(), UART_SIGNAL_TXD_INV);
        id(bsb_uart).get_hw_serial()->setRxInvert(false);

uart_set_line_inverse is from the ESP-IDF and more universal (has a bit pattern for all UART pins including flow control). setRxInvert is an Arduino function. There’s no equivalent for any of the other UART pins, not even TX. But it is enough for a “safe” initilization. If you need an inverted TX initialize the UART inverted, then un-invert RX.

And now I’m wondering what happens, if I set the above for the UART and also use GPIO.func_out_sel_cfg[UART_TX_PIN].inv_sel = 1;. Double inversion?

No idea, you need to try :wink:

And just for completeness I did. And it does indeed double invert. Setting up the UART inverted (as in the config above), and then adding

id(bsb_uart).get_hw_serial()->setRxInvert(false); // un-invert RX
GPIO.func_out_sel_cfg[7].inv_sel = 1; // invert TX pin

lets the UART talk to a normal USB-TTL-serial converter as expected.

Wouldn’t make sense if it inverted already inverted.