Problem with PWM

Hello everyone. I need help, I’m trying my hand at HA. I created a simple code to control the PWM module. however, after uploading to Wemos Dmini, the display does not show me the current status in numerical form. I only get PWM:0.0%. what am I doing wrong. This is my code:

  name: pid-mini
  friendly_name: PID MINI

esp8266:
  board: d1_mini

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "LPfvDZQ39grzmeVEPtp2tX0S144rNmTa6mjWN6NA/4s="

ota:
  password: "2561d3fd6170948cba84ee811d6 b1bb1"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Pid-Mini Fallback Hotspot"
    password: "atDIjPiDofhY"

captive_portal:

dallas:
  - pin: D6

sensor:
  - platform: dallas
    address: 0x280008037073a910  # Zastąp to adresem swojego czujnika DS18B20
    name: "DS18B20 Sensor"
    id: ds18b20_sensor

  - platform: wifi_signal
    name: "WiFi Signal"
    id: wifi_signal_strength
    update_interval: 10s

  - platform: uptime
    name: "Uptime"
    update_interval: 10s

  - platform: template
    name: "PWM Percentage"
    id: pwm_percentage
    update_interval: 10s
    lambda: |-
      auto pwm_value = id(pwm_percentage).state;
      return (pwm_value / 255.0) * 100.0;

switch:
  - platform: template
    name: "Setpoint Updated"
    id: setpoint_updated
    turn_on_action:
      - sensor.template.publish:
          id: pwm_percentage
          state: !lambda |-
            auto setpoint = id(pwm_percentage).state;
            return setpoint + 1;
    turn_off_action:
      - sensor.template.publish:
          id: pwm_percentage
          state: !lambda |-
            auto setpoint = id(pwm_percentage).state;
            return setpoint;

binary_sensor:
  - platform: gpio
    pin:
      number: D5
      mode:
        input: True
      inverted: False
    name: "Increase Button"
    on_press:
      then:
        - lambda: |-
            id(console_fan_thermostat).target_temperature += 1;
            id(console_fan_thermostat).publish_state();
    
  - platform: gpio
    pin:
      number: D8
      mode:
        input: True
      inverted: False
    name: "Decrease Button"
    on_press:
      then:
        - lambda: |-
            id(console_fan_thermostat).target_temperature -= 1;
            id(console_fan_thermostat).publish_state();

output:
  - platform: esp8266_pwm
    id: pwm_output
    pin: D7

climate:
  - platform: pid
    name: "Console Fan Thermostat"
    id: console_fan_thermostat
    sensor: ds18b20_sensor
    default_target_temperature: 30.0 °C
    heat_output: pwm_output

    control_parameters:
      kp: 0.3
      ki: 0.001
      kd: 6
      max_integral: 0.0
      output_averaging_samples: 5
      derivative_averaging_samples: 5

    deadband_parameters:
      threshold_high: 0.4 °C
      threshold_low: -1.0 °C
      kp_multiplier: 0.0
      ki_multiplier: 0.0
      kd_multiplier: 0.0
      deadband_output_averaging_samples: 15

i2c:
  sda: GPIO5
  scl: GPIO4
  scan: true

font:
  - file: "arial.ttf"
    id: font_10
    size: 10
  - file: "arial.ttf"
    id: font_12
    size: 12
  - file: "arial.ttf"
    id: font_14
    size: 14
  - file: "arial.ttf"
    id: font_24
    size: 24

display:
  - platform: ssd1306_i2c
    model: SH1106_128X64
    address: 0x3c
    id: my_display
    pages:
      - id: page1
        lambda: |-
          it.printf(30, 11, id(font_24), " %.1f°C", id(ds18b20_sensor).state);
          it.printf(0, 0, id(font_10), "T: %.1f°C", id(console_fan_thermostat).target_temperature);
          it.printf(0, 41, id(font_10), "S: %.1f°C", id(pwm_percentage).state);
          it.printf(0, 51, id(font_10), "PWM: %.1f%%", id(pwm_percentage).state);
          it.printf(75, 0, id(font_10), "WiFI: %.1f dBm", id(wifi_signal_strength).state);

Hi - before anyone has a look at this they will probably ask you to post your yaml with the correct indenting.

As per item 11 in this list:

1 Like

And your issue is with your lambda code. isnan returns a boolean, which will be zero (false) if the value is a number.

I'm sorry, but due to the rush and the very poor network, I didn't have time to look at my post. Now ihope it's better. Thank you very much for your interest, and I appreciate the fact that you do it as enthusiasts, but I'm just starting out in "Your World", so I'm asking for patience. You write that the problem is in the lambda code, which I need to change or add so that the values ​​on the display take on a real state. Now the lambda expression calculates and returns the pwm_percentage percentage based on its state. This value is used to display the PWM duty cycle percentage on the display. but it doesn't display it. I'm probably too stupid or too old for programming. I need help

Ok - not sure where you got this code but there are still some errors. In the template sensor for pwm_percentage you are referring to itself to perform a calculation - this is not good practice and will give unexpected results:

  - platform: template
    name: "PWM Percentage"
    id: pwm_percentage
    update_interval: 10s
    lambda: |-
      auto pwm_value = id(pwm_percentage).state; # why this??
      return (pwm_value / 255.0) * 100.0;

Also in your lambda for your display - you use pwm_percentage twice - once for your SET temperature and once for PWM percentage:

          it.printf(0, 41, id(font_10), "S: %.1f°C", id(pwm_percentage).state);
          it.printf(0, 51, id(font_10), "PWM: %.1f%%", id(pwm_percentage).state);

Lastly - does this work? I admit I haven’t played with the Climate component, so I am just asking as it seems pretty good if it does. Where is this documented?

        - lambda: |-
            id(console_fan_thermostat).target_temperature += 1;
            id(console_fan_thermostat).publish_state();

Hello. Thank you for your interest. Maybe I can explain why I need an autonomous controller. I have a Heat Pump to control which (compressor power) requires a voltage of -10V. The system I created is intended to use the PID function to act as a thermostat with intelligent power reduction as it gets closer to achieving and maintaining the set temperature. The system based on Wemods D1 is already running, just like ESP Home. PWM output behavior is promising. I don’t know if this is the correct encoding, it works for now. The only thing I miss is the unfortunate display of the PWM output indicator on the display.


What do the ESPHome logs show as the value of pwm_percentage?

[22:54:46][C][wifi:546]: WiFi:
[22:54:46][C][wifi:382]:   Local MAC: xxxxxxxxxxxx
[22:54:46][C][wifi:383]:   SSID: [redacted]
[22:54:46][C][wifi:384]:   IP Address: 192.168.1.79
[22:54:46][C][wifi:385]:   BSSID: [redacted]
[22:54:46][C][wifi:387]:   Hostname: 'pid-mini'
[22:54:46][C][wifi:389]:   Signal strength: -75 dB ▂▄▆█
[22:54:46][C][wifi:393]:   Channel: 1
[22:54:46][C][wifi:394]:   Subnet: 255.255.255.0
[22:54:46][C][wifi:395]:   Gateway: 192.168.1.1
[22:54:46][C][wifi:396]:   DNS1: 192.168.1.1
[22:54:46][C][wifi:397]:   DNS2: 0.0.0.0
[22:54:46][W][component:214]: Component ssd1306_base took a long time for an operation (0.31 s).
[22:54:46][W][component:215]: Components should block for at most 20-30ms.
[22:54:46][C][logger:416]: Logger:
[22:54:46][C][logger:417]:   Level: DEBUG
[22:54:46][C][logger:418]:   Log Baud Rate: 115200
[22:54:46][C][logger:420]:   Hardware UART: UART0
[22:54:46][C][i2c.arduino:053]: I2C Bus:
[22:54:46][C][i2c.arduino:054]:   SDA Pin: GPIO5
[22:54:46][C][i2c.arduino:055]:   SCL Pin: GPIO4
[22:54:46][C][i2c.arduino:056]:   Frequency: 50000 Hz
[22:54:46][C][i2c.arduino:059]:   Recovery: bus successfully recovered
[22:54:46][I][i2c.arduino:069]: Results from i2c bus scan:
[22:54:46][I][i2c.arduino:075]: Found i2c device at address 0x3C
[22:54:46][C][uptime.sensor:031]: Uptime Sensor 'Uptime'
[22:54:46][C][uptime.sensor:031]:   Device Class: 'duration'
[22:54:46][C][uptime.sensor:031]:   State Class: 'total_increasing'
[22:54:46][C][uptime.sensor:031]:   Unit of Measurement: 's'
[22:54:46][C][uptime.sensor:031]:   Accuracy Decimals: 0
[22:54:46][C][uptime.sensor:031]:   Icon: 'mdi:timer-outline'
[22:54:47][C][template.sensor:022]: Template Sensor 'PWM Percentage'
[22:54:47][C][template.sensor:022]:   State Class: ''
[22:54:47][C][template.sensor:022]:   Unit of Measurement: ''
[22:54:47][C][template.sensor:022]:   Accuracy Decimals: 1
[22:54:47][C][template.sensor:023]:   Update Interval: 10.0s
[22:54:47][C][esp8266_pwm:022]: ESP8266 PWM:
[22:54:47][C][esp8266_pwm:023]:   Pin: GPIO13
[22:54:47][C][esp8266_pwm:024]:   Frequency: 1000.0 Hz
[22:54:47][C][gpio.binary_sensor:015]: GPIO Binary Sensor 'Increase Button'
[22:54:47][C][gpio.binary_sensor:016]:   Pin: GPIO14
[22:54:47][C][gpio.binary_sensor:015]: GPIO Binary Sensor 'Decrease Button'
[22:54:47][C][gpio.binary_sensor:016]:   Pin: GPIO15
[22:54:47][C][template.switch:068]: Template Switch 'Setpoint Updated'
[22:54:47][C][template.switch:090]:   Restore Mode: always OFF
[22:54:47][C][template.switch:057]:   Optimistic: NO
[22:54:47][C][dallas.sensor:075]: DallasComponent:
[22:54:47][C][dallas.sensor:076]:   Pin: GPIO12
[22:54:47][C][dallas.sensor:077]:   Update Interval: 60.0s
[22:54:47][D][dallas.sensor:082]:   Found sensors:
[22:54:47][D][dallas.sensor:084]:     0x280008037073a910
[22:54:47][C][dallas.sensor:089]:   Device 'DS18B20 Sensor'
[22:54:47][C][dallas.sensor:089]:     Device Class: 'temperature'
[22:54:47][C][dallas.sensor:089]:     State Class: 'measurement'
[22:54:47][C][dallas.sensor:089]:     Unit of Measurement: '°C'
[22:54:47][C][dallas.sensor:089]:     Accuracy Decimals: 1
[22:54:47][C][dallas.sensor:097]:     Address: 0x280008037073a910
[22:54:47][C][dallas.sensor:098]:     Resolution: 12
[22:54:47][C][pid.climate:062]: PID Climate 'Console Fan Thermostat'
[22:54:47][C][pid.climate:063]:   Control Parameters:
[22:54:47][C][pid.climate:064]:     kp: 0.30000, ki: 0.00100, kd: 6.00000, output samples: 5
[22:54:47][C][pid.climate:070]:   Deadband Parameters:
[22:54:47][C][pid.climate:071]:     threshold: -1.00000 to 0.40000, multipliers(kp: 0.00000, ki: 0.00000, kd: 0.00000), output samples: 15
[22:54:47][C][ssd1306_i2c:023]: I2C SSD1306
[22:54:47][C][ssd1306_i2c:023]:   Rotations: 0 °
[22:54:47][C][ssd1306_i2c:023]:   Dimensions: 128px x 64px
[22:54:47][C][ssd1306_i2c:024]:   Address: 0x3C
[22:54:47][C][ssd1306_i2c:025]:   Model: SH1106 128x64
[22:54:47][C][ssd1306_i2c:027]:   External VCC: NO
[22:54:47][C][ssd1306_i2c:028]:   Flip X: YES
[22:54:47][C][ssd1306_i2c:029]:   Flip Y: YES
[22:54:47][C][ssd1306_i2c:030]:   Offset X: 0
[22:54:47][C][ssd1306_i2c:031]:   Offset Y: 0
[22:54:47][C][ssd1306_i2c:032]:   Inverted Color: NO
[22:54:47][C][ssd1306_i2c:033]:   Update Interval: 1.0s
[22:54:47][C][captive_portal:088]: Captive Portal:
[22:54:47][C][mdns:115]: mDNS:
[22:54:47][C][mdns:116]:   Hostname: pid-mini
[22:54:47][C][ota:097]: Over-The-Air Updates:
[22:54:47][C][ota:098]:   Address: pid-mini.local:8266
[22:54:47][C][ota:101]:   Using Password.
[22:54:47][C][api:139]: API Server:
[22:54:47][C][api:140]:   Address: pid-mini.local:6053
[22:54:47][C][api:142]:   Using noise encryption: YES
[22:54:47][D][sensor:093]: 'PWM Percentage': Sending state nan  with 1 decimals of accuracy
[22:54:47][C][wifi_signal.sensor:009]: WiFi Signal 'WiFi Signal'
[22:54:47][C][wifi_signal.sensor:009]:   Device Class: 'signal_strength'
[22:54:47][C][wifi_signal.sensor:009]:   State Class: 'measurement'
[22:54:47][C][wifi_signal.sensor:009]:   Unit of Measurement: 'dBm'
[22:54:47][C][wifi_signal.sensor:009]:   Accuracy Decimals: 0

1: This is what the log looks like:

2: The PWM output status can be as a status bar, percentage or even in numerical form, just to let me know that the system is working and at what power.

Well that shows me that your display is not the issue. The calculation of the sensor you are displaying as pwm_percentage is the issue. Which brings me back to the questions I asked above.

Lastly, the Climate PID does what you stated without any reference to that value you calculate so I am not sure what you are trying to do by displaying it…

I think what you need here is to know what the output of the PID is doing, correct? I am learning more about the climate component than I really wanted to know. :slight_smile:

You don’t need any of the template sensors that calculate pwm_percentage, what you want is a sensor that shows you the level of the HEAT output of the PID. Something like:

sensor:
  - platform: pid
    name: "Heat Output Level"
    id: heat_output_level
    climate_id: console_fan_thermostat
    type: HEAT

I don’t know how that value is presented - you may need to do some calculations to turn it into a percentage. For starters just add the above and show what the value is presented as in the logs, for a few cycles of your PID.

1 Like

Hello.Daryl - You are my Guru!!! Finally, thanks to your interest, the display started showing what I wanted. Thank you very much, of course I will have to make some calculations. I cleaned up the code a bit (as much as I can) and tried to add an on-screen notification about receiving an alarm on pin D0 and activating an additional pump on pin D2 (for the duration of the alarm). everything would be ok but… FileEditor does not show incorrect syntax but I get this error during compilation. I would be very grateful if you would look at what I am trying to create with a professional eye. Thank you in advance for all your suggestions and help with code changes.

  name: pid-mini
  friendly_name: PID MINI

esp8266:
  board: d1_mini

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "xxxxxxxxxxxxxxxxxxxxxxxxxx"

ota:
  password: "xxxxxxxxxxxxxxxxxxxx"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Pid-Mini Fallback Hotspot"
    password: "xxxxx"

captive_portal:

dallas:
  - pin: D6

sensor:
  - platform: dallas
    address: 0x280008037073a910
    name: "DS18B20 Sensor"
    id: ds18b20_sensor

  - platform: dallas
    address: 0x7f000803707e6610
    name: "Gas.In"
    id: Gas_In
  - platform: dallas
    address: 0xcc00080370970510
    name: "Gas.Out"
    id: Gas_Out
  - platform: dallas
    address: 0xb500080370468510
    name: "Water.In"
    id: Water_In
  - platform: dallas
    address: 0x7f00080370836b10
    name: "Water.Out"
    id: Water_Out

  - platform: wifi_signal
    name: "WiFi Signal"
    id: wifi_signal_strength
    update_interval: 10s

  - platform: uptime
    name: "Uptime"
    update_interval: 10s

  - platform: pid
    name: "Heat Output Level"
    id: heat_output_level
    climate_id: console_fan_thermostat
    type: HEAT

text_sensor:
  - platform: template
    name: "Alarm"
    id: "alarm_condition"    

switch:
  - platform: template
    name: "Pump Switch"
    id: pump_switch1
    turn_on_action:
      - switch.turn_on: pump_switch1
    turn_off_action:
      - switch.turn_off: pump_switch1

  - platform: gpio
    pin: D4
    id: pump_switch

    

binary_sensor:

  - platform: gpio
    pin:
      number: D5
      mode:
        input: True
      inverted: False
    name: "Increase Button"
    on_press:
      then:
        - lambda: |-
            id(console_fan_thermostat).target_temperature += 1;
            id(console_fan_thermostat).publish_state();

  - platform: gpio
    pin:
      number: D8
      mode:
        input: True
      inverted: False
    name: "Decrease Button"
    on_press:
      then:
        - lambda: |-
            id(console_fan_thermostat).target_temperature -= 1;
            id(console_fan_thermostat).publish_state();

  - platform: gpio
    pin:
      number: D0
      mode:
        input: True
      inverted: False
    name: "Defrost Sensor"
    on_state:
      then:
        - switch.turn_on: pump_switch
        - lambda: it.printf(70, 52, id(font_12), "ALARM");
        

output:

  - platform: esp8266_pwm
    id: pwm_output
    pin: D7

climate:
  - platform: pid
    name: "Console Fan Thermostat"
    id: console_fan_thermostat
    sensor: ds18b20_sensor
    default_target_temperature: 30.0 °C
    heat_output: pwm_output

    control_parameters:
      kp: 0.3
      ki: 0.001
      kd: 6
      max_integral: 0.0
      output_averaging_samples: 5
      derivative_averaging_samples: 5

    deadband_parameters:
      threshold_high: 0.4 °C
      threshold_low: -1.0 °C
      kp_multiplier: 0.0
      ki_multiplier: 0.0
      kd_multiplier: 0.0
      deadband_output_averaging_samples: 15

i2c:
  sda: GPIO5
  scl: GPIO4
  scan: true

font:
  - file: "arial.ttf"
    id: font_10
    size: 10
  - file: "arial.ttf"
    id: font_12
    size: 12
  - file: "arial.ttf"
    id: font_14
    size: 14
  - file: "arial.ttf"
    id: font_30
    size: 30

display:
  - platform: ssd1306_i2c
    model: SH1106_128X64
    address: 0x3c
    id: my_display
    contrast: 70%
    pages:
      - id: page1
        lambda: |-
          it.printf(16, 11, id(font_30), " %.1f°C", id(ds18b20_sensor).state);
          it.printf(0, 0, id(font_12), "T: %.1f°C", id(console_fan_thermostat).target_temperature);
          it.printf(0, 52, id(font_12), "PWM: %.1f%%", id(heat_output_level).state);
          it.printf(70, 0, id(font_10), "WiFI: %.1f dBm", id(wifi_signal_strength).state);
          it.printf(70, 52, id(font_12), "ALARM", id(alarm_condition));

      - id: page2
        lambda: |-
          it.printf(0, 0, id(font_12), "Gas.In: %.1f°C", id(Gas_In).state);
          it.printf(0, 15, id(font_12), "Gas.Out: %.1f°C", id(Gas_Out).state);
          it.printf(0, 30, id(font_12), "Water.In: %.1f°C", id(Water_Out).state);
          it.printf(0, 45, id(font_12), "Water.Out: %.1f°C", id(Water_Out).state);
interval:
  - interval: 5s
    then:
      - display.page.show_next: my_display
      - component.update: my_display
      
button:
  - platform: template
    name: "PID Climate Autotune"
    on_press:
      - climate.pid.autotune: console_fan_thermostat

I posted the compilation errors here

INFO ESPHome 2023.10.6
INFO Reading configuration /config/esphome/pid-mini.yaml…
INFO Generating C++ source…
INFO Compiling app…
Processing pid-mini (board: d1_mini; framework: arduino; platform: platformio/[email protected])
--------------------------------------------------------------------------------
HARDWARE: ESP8266 80MHz, 80KB RAM, 4MB Flash
Dependency Graph
|-- ESPAsyncTCP-esphome @ 2.0.0
|-- ESPAsyncWebServer-esphome @ 3.1.0
|-- DNSServer @ 1.1.1
|-- ESP8266WiFi @ 1.0
|-- ESP8266mDNS @ 1.2
|-- noise-c @ 0.1.4
|-- Wire @ 1.0
Compiling .pioenvs/pid-mini/src/main.cpp.o
/config/esphome/pid-mini.yaml: In lambda function:
/config/esphome/pid-mini.yaml:129:7: error: ‘it’ was not declared in this scope; did you mean ‘bit’?
** 129 | - lambda: it.printf(70, 52, id(font_12), “ALARM”);**
** | ^ **
** | bit**
/config/esphome/pid-mini.yaml: In lambda function:
/config/esphome/pid-mini.yaml:194:34: warning: too many arguments for format [-Wformat-extra-args]
** 194 | it.printf(70, 52, id(font_12), “ALARM”, id(alarm_condition));**
** | ^~~~~~~**
***** [.pioenvs/pid-mini/src/main.cpp.o] Error 1**
========================= [FAILED] Took 19.28 seconds =========================

1 Like

It still a sensor - so you still need to use .state, you also need to specify it’s a string.

          it.printf(70, 52, id(font_12), "ALARM: %s", id(alarm_condition).state);