PWM Servo control with ESPhome?

Hi

Is it possible to have 2 sg90 controlled by nodemcu ?
Only one works with my esphome config…

I did two. I put a delay so both weren’t pulling at the same time.
*Disclaimer: I had issues with connecting the servos to the blind shaft and haven’t had time to attempt to fix. These are not in production at the moment. One day my wife will kill me since those two blinds can’t be opened.
Also the level and open duration were me tweaking it so that it just opened the blinds enough because just a few milliseconds to many and it’d fall back closed the other way.
These were continuous rotation servos.

switch:
  - platform: gpio
    name: "Living Room Front Blinds Status Light"
    pin: 2
    inverted: True

servo:
  - id: my_servo
    output: pwm_output
    
  - id: my_servo2
    output: pwm_output2

# Example output platform
# On ESP32, use ledc output
output:
  - platform: esp8266_pwm
    id: pwm_output
    pin: D5
    frequency: 50 Hz

  - platform: esp8266_pwm
    id: pwm_output2
    pin: D6
    frequency: 50 Hz

cover:
  - platform: time_based
    name: "Living Room Front Blinds Left"
    id: cover1
    open_action:
#      then:
      - servo.write:
          id: my_servo
          level: -2.0%
    open_duration: 1.2sec

    close_action:
#      then:
      - servo.write:
          id: my_servo
          level: 20.0%
    close_duration: 2.3sec

    stop_action:
#      then:
      - servo.write:
          id: my_servo
          level: 0%
      - servo.detach: my_servo
###############################
  - platform: time_based
    name: "Living Room Front Blinds Right"
    id: cover2
    open_action:
#      then:
      - servo.write:
          id: my_servo2
          level: -2.0%
    open_duration: 3.5sec

    close_action:
#      then:
      - servo.write:
          id: my_servo2
          level: 20.0%
    close_duration: 1sec

    stop_action:
#      then:
      - servo.write:
          id: my_servo2
          level: 0%
      - servo.detach: my_servo2

HI thanks for your reply.

I tested that but sadly i have the same problem.

my esphome yaml :

# Example configuration entry
servo:
  - id: my_servo
    output: pwm_output
    transition_length: 1s
    auto_detach_time : 1s
  - id: my_servo2
    output: pwm_output2
    transition_length: 1s
    auto_detach_time: 1s
    
# Example output platform
# On ESP32, use ledc output
output:
  - platform: esp8266_pwm
    id: pwm_output
    pin: D5
    frequency: 50 Hz
  - platform: esp8266_pwm
    id: pwm_output2
    pin: D6
    frequency: 50 Hz
    
cover:
  - platform: time_based
    name: "Test1"
    id: cover1
    open_action:
#      then:
      - servo.write:
          id: my_servo
          level: -2.0%
    open_duration: 1.2sec

    close_action:
#      then:
      - servo.write:
          id: my_servo
          level: 20.0%
    close_duration: 2.3sec

    stop_action:
#      then:
      - servo.write:
          id: my_servo
          level: 0%
      - servo.detach: my_servo
###############################
  - platform: time_based
    name: "Test2"
    id: cover2
    open_action:
#      then:
      - servo.write:
          id: my_servo2
          level: -2.0%
    open_duration: 3.5sec

    close_action:
#      then:
      - servo.write:
          id: my_servo2
          level: 20.0%
    close_duration: 1sec

    stop_action:
#      then:
      - servo.write:
          id: my_servo2
          level: 0%
      - servo.detach: my_servo2    

and in debug logs :

[17:02:17][C][time_based.cover:012]: Time Based Cover 'Test2'
[17:02:17][C][time_based.cover:012]:   Assumed State: YES
[17:02:17][C][time_based.cover:013]:   Open Duration: 3.5s
[17:02:17][C][time_based.cover:014]:   Close Duration: 1.0s
[17:02:17][C][captive_portal:169]: Captive Portal:
[17:02:17][C][ota:029]: Over-The-Air Updates:
[17:02:17][C][ota:030]:   Address: 192.168.3.143:8266
[17:02:17][C][ota:032]:   Using Password.
[17:02:17][C][api:095]: API Server:
[17:02:17][C][api:096]:   Address: 192.168.3.143:6053
[17:02:17][D][debug:023]: ESPHome version 1.16.1
[17:02:17][D][debug:025]: Free Heap Size: 29896 bytes
[17:02:17][D][debug:053]: Flash Chip: Size=4096kB Speed=40MHz Mode=DIO
[17:02:17][D][debug:190]: Chip ID: 0x00D61960
[17:02:17][D][debug:191]: SDK Version: 2.2.2-dev(38a443e)
[17:02:17][D][debug:192]: Core Version: 2_7_4
[17:02:17][D][debug:193]: Boot Version=6 Mode=1
[17:02:17][D][debug:194]: CPU Frequency: 80
[17:02:17][D][debug:195]: Flash Chip ID=0x0016405E
[17:02:17][D][debug:196]: Reset Reason: Software/System restart
[17:02:17][D][debug:197]: Reset Info: Software/System restart
[17:02:19][VV][api.service:220]: on_ping_request: PingRequest {}
[17:02:19][VV][api.service:032]: send_ping_response: PingResponse {}
[17:02:22][VV][api.service:220]: on_ping_request: PingRequest {}
[17:02:22][VV][api.service:032]: send_ping_response: PingResponse {}
[17:02:22][VV][api.service:333]: on_execute_service_request: ExecuteServiceRequest {
  key: 2387861054
  args: ExecuteServiceArgument {
  bool_: NO
  legacy_int: 0
  float_: -22
  string_: ''
  int_: 0
}
}
[17:02:22][D][servo:059]: Servo new target: -0.220000
[17:02:23][D][servo:049]: Servo reached target
[17:02:24][D][servo:027]: Servo detached on auto_detach_time
[17:02:27][VV][api.service:220]: on_ping_request: PingRequest {}
[17:02:27][VV][api.service:032]: send_ping_response: PingResponse {}
[17:02:28][VV][api.service:333]: on_execute_service_request: ExecuteServiceRequest {
  key: 1275517864
  args: ExecuteServiceArgument {
  bool_: NO
  legacy_int: 0
  float_: 19
  string_: ''
  int_: 0
}
}
[17:02:28][D][servo:059]: Servo new target: 0.190000
[17:02:28][D][servo:049]: Servo reached target
[17:02:29][D][servo:027]: Servo detached on auto_detach_time
[17:02:32][VV][api.service:220]: on_ping_request: PingRequest {}

The first SG90 works perfectly but nothing with my second … and no trace in logs for ESP everything is good, it sends the order to motor but nothing turn …

i test some different SG90 and Nodemcu always the same result the first servo is ok the second nothing…

Try forcing a log entry to see if that portion of your code is working?

- logger.log: "Hello World"

yes traces helps :slight_smile:

but not in my case :
my code :

api:
  password: "xxxxxx"
  services:
    - service: control_servo
      variables:
        level: float
      then:
        - logger.log: "Servo 1"
        - servo.write:
            id: my_servo
            level: !lambda 'return level / 100.0;'
    - service: control_servo2
      variables:
        level: float
      then:
        - logger.log: "Servo 2"
        - servo.write:
            id: my_servo2
            level: !lambda 'return level / 100.0;'          

[18:44:41][VV][api.service:333]: on_execute_service_request: ExecuteServiceRequest {
  key: 2387861054
  args: ExecuteServiceArgument {
  bool_: NO
  legacy_int: 0
  float_: 8
  string_: ''
  int_: 0
}
}
[18:44:41][D][main:213]: Servo 1
[18:44:41][D][servo:059]: Servo new target: 0.080000
[18:44:41][D][servo:049]: Servo reached target
[18:44:42][D][servo:027]: Servo detached on auto_detach_time
[18:44:43][VV][api.service:220]: on_ping_request: PingRequest {}
[18:44:43][VV][api.service:032]: send_ping_response: PingResponse {}
[18:44:45][VV][api.service:333]: on_execute_service_request: ExecuteServiceRequest {
  key: 1275517864
  args: ExecuteServiceArgument {
  bool_: NO
  legacy_int: 0
  float_: 23
  string_: ''
  int_: 0
}
}
[18:44:45][D][main:381]: Servo 2
[18:44:45][D][servo:059]: Servo new target: 0.230000
[18:44:45][D][servo:049]: Servo reached target
[18:44:46][D][servo:027]: Servo detached on auto_detach_time
[18:44:48][VV][api.service:220]: on_ping_request: PingRequest {}
[18:44:48][VV][api.service:032]: send_ping_response: PingResponse {}
[18:44:49][VV][api.service:220]: on_ping_request: PingRequest {}
[18:44:49][VV][api.service:032]: send_ping_response: PingResponse {}
[18:44:53][VV][api.service:220]: on_ping_request: PingRequest {}
[18:44:53][VV][api.service:032]: send_ping_response: PingResponse {}
[18:44:54][VV][api.service:333]: on_execute_service_request: ExecuteServiceRequest {
  key: 1275517864
  args: ExecuteServiceArgument {
  bool_: NO
  legacy_int: 0
  float_: -32
  string_: ''
  int_: 0
}
}

So ESP call my control_servo2 but servo doesn’t react :confused:

I’ve tried to make it work with an ESP32-cam board.
Servo works perfect. Camera works perfect. But not together :face_with_symbols_over_mouth:
When I comment out the camera, the servo works, and when I comment out the servo, the camera works. When both settings are in - the servo and the camera wont work.
Maybe the camera needs all of the IO pins, or takes too much memory that the servo needs, which is weird because I’ve already made that board work with the built-in camera and a few other sensors (PIR sensor, light, TH)
Oh and I’ve tried almost all of the IO pins…

Anyway, here is my code for that board, maybe it will help someone, and maybe even someone has a solution for both to work - spent days on this S***… All I’ve ever wanted is a cheap camera with one cheap servo that connects to homeassistant and makes me some coffe and cookies. But I guess that’s too much to ask :wink:

esphome:
  name: office_camera
  platform: ESP32
  board: esp32cam
  
wifi:
  ssid: "****"
  password: "****"

captive_portal:

# Enable logging
logger:

# Enable Home Assistant API
api:
 services:
    - service: control_servo
      variables:
        level: float
      then:
        - servo.write:
            id: pwm_servoR
            level: !lambda 'return level / 100.0;'
ota:

# esp32_camera:
#   name: office camera
#   external_clock:
#     pin: GPIO0
#     frequency: 20MHz
#   i2c_pins:
#     sda: GPIO26
#     scl: GPIO27
#   data_pins: [GPIO5, GPIO18, GPIO19, GPIO21, GPIO36, GPIO39, GPIO34, GPIO35]
#   vsync_pin: GPIO25
#   href_pin: GPIO23
#   pixel_clock_pin: GPIO22
#   power_down_pin: GPIO32
#   vertical_flip: true
  
  
sensor:
  - platform: wifi_signal
    name: "WiFi Signal office cam"
    update_interval: 60s
    id: signalWgm

switch:
  - platform: restart
    name: "Restart office cam"
  
output:
  # Flashlight 
  - platform: gpio
    pin: GPIO4
    id: gpio_4
    
  # Servo Rotate : Using ledc output to control a standard 50Hz RC servo over the normal 1 to 2 mS pulse range
  - platform: ledc
    pin: GPIO14
    id: servoR
    frequency: 50 Hz
    
servo:
  - id: pwm_servoR
    output: servoR    
    
# Flashlight    
light:
  - platform: binary
    output: gpio_4
    name: "Office camera light"

Is there an amperage issue?
I got lucky and was able to use the 5V out but I made sure that I turned off the first servo after it was done, then on the second one, did the action, then turned it off.

Can confirm. on ESP32-CAM either the camera works or the servos. But not both. Looks like I have to hook up an additional esp8266 only for the servos.
[EDIT]
Well, it seems I didn’t read the docs completely. My bad.

Note

Camera uses PWM timer #1. If you need PWM (via the ledc platform) you need to manually specify a channel there (with the channel: 2 parameter)

@keithcroshaw @Khalid_Abu_Hamza @Olivier974 @mr.sneezy @Drew.B

Hi All,

I’m hoping for some help - I’m trying to control a servo from an esp32 and have followed the guides, but I must be doing something wrong as the servo doesn’t move. I’ve setup esphome and tested with turning on an led via home assistant, which works, so I believe I’m okay for pin numbers etc. I’ve also previously tested controlling the servo directly from the esp32 via micropython and that worked, so I’m pretty happy with my wiring up etc.

I’m using AZDelivery ESP32 NodeMCU Dev Kit C WiFi WLAN CP2102 ESP32-WROOM-32D from Amazon UK. It isn’t listed in the board types. I’ve tried a few, including nodemcu with no luck.

Code in ESPHome - robogarage.yaml

esphome:
  name: robogarage
  platform: ESP32
  board: esp32dev

# Enable logging
logger:

# Enable Home Assistant API
api:
  services:
    - service: control_servo
      variables:
        level: float
      then:
        - servo.write:
            id: my_servo
            level: !lambda 'return level / 100.0;'

ota:
  password: "abcdefg"

wifi:
  ssid: "xxxxxxxx"
  password: "xxxxxxxx"

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Robogarage Fallback Hotspot"
    password: "xxxxxxx"

captive_portal:

servo:
  - id: my_servo
    output: pwm_output

output:
  - platform: ledc
    id: pwm_output
    pin: GPIO32
    frequency: 50 Hz

Then, in my configuration.yaml I have:

input_number:
  servo_control:
    name: Servo Control
    initial: 0
    min: -100
    max: 100
    step: 1
    mode: slider

automation:
  - alias: Write Servo Value to ESP
    trigger:
      platform: state
      entity_id: input_number.servo_control
    action:
      - service: esphome.robogarage_control_servo
        data_template:
          level: '{{ trigger.to_state.state | int }}'

and finally, the lovelace card:

type: entities
entities:
  - input_number.servo_control

If anyone can see ANYTHING obvious (or not so obvious) that I have done incorrectly or misunderstood, I would be incredibly grateful for your thoughts.

Maybe you’re still using the LED platform?
It might not matter but that might be a typo you forgot to change back.
I’ve only ever seen the pins be like D5 in my example, but I’ve only ever used the one board type.
And you don’t have an end device declared like the cover in my example.
Again that might not be necessary but I’m just looking what’s different between our esphome config files.

Steal mine and see if you can at least get it to twitch or something then work backwards from there?
ESPHome has been 100% trial and error for me.
Good luck!

Hello,

look at my last post : https://community.home-assistant.io/t/pwm-servo-control-with-esphome/111762/23

it only work for me with " " not ’ ’

try

@Olivier974 & @keithcroshaw
Thank you both so much for your time and input. I tried all your suggestions but didn’t have any luck. However, I have now identified my embarrassing mistake - I put the automation code in the config yaml and not the automations one. :flushed: I guess we live and learn!
Thanks again,

2 Likes

lol!

nice you find your mistake :wink:

1 Like

Solved! (My issue anyways)

For me there were two issues.

  1. Feather huzzah 32 simply did not want to servo… Just nope :person_shrugging:

  2. Since there were other pwm devices, there was interference or something. Took me forever to figure this out but I had to add channels. What’s important is that the servo needed to be non adjacent to the following channels. So servo on chanel 1 skip a channel then the next device on channel 3. In the esphome docs there’s a line that says two adjacent channels share the same timer.

I hope this helps someone!

2 Likes

GOT IT WORKING!

Ill leave this here though, hope it will help someone :slight_smile:

Hey all,

Trying to do this, but don’t have any context for what needs to go where on the HA side of things

Have worked out the following for anyone that’s stuck.

Config.yaml

input_number:
  servo_control:
    name: Servo Control
    initial: 0
    min: -100
    max: 100
    step: 1
    mode: slider

Place the below in your automation, sadly this yaml is not correct though and currently gives an error

Message malformed: required key not provided @ data[‘action’]

automation:
  - alias: Write Servo Value to ESP
    trigger:
      platform: state
      entity_id: input_number.servo_control
    action:
      - service: esphome.robogarage_control_servo
        data_template:
          level: '{{ trigger.to_state.state | int }}'

Id really love to know what the correct yaml is and, maybe more importantly, how this is working for you in the first place with this malformed yaml. Are you guys on super old versions and its been changed or?? I see this a lot, people seem to be often posting various things with the wrong syntax.

Thanks

EDIT

I managed to save the automation with this

alias: 'Flush Toilet '
description: ''
trigger:
  - platform: state
    entity_id: input_number.servo_control
condition: []
action:
  - data_template:
      level: '{{ trigger.to_state.state | int }}'
    service: esphome.robotarm_control_servo
mode: single

But its not working when I change the slider. No noise, no movement.

Here is my ESPHome.yaml

esphome:
  name: toilet
  platform: ESP32
  board: esp32dev

# Enable logging
logger:

# Enable Home Assistant API
api:
  services:
    - service: control_servo
      variables:
        level: float
      then:
        - servo.write:
            id: toilet
            level: !lambda 'return level / 100.0;'

ota:
  password: "XXXXXX"

wifi:
  ssid: "SSID"
  password: "password"
  
  manual_ip:
    static_ip: X.X.X.X
    gateway: X.X.X.X
    subnet: X.X.X.X

captive_portal:

output:
  - platform: ledc
    pin: GPIO04
    id: gpio_04_servo
    frequency: 50 Hz
    
servo:
  - id: toilet
    output: gpio_04_servo

I think I have this wired correctly, anything stick out?

GPIO 4

image

5V and GND

image

Servo pin colours

Servo

EDIT2

GOT IT WORKING

Make sure you name the service in your automation correctly esphome._control_servo .

alias: 'Flush Toilet '
description: ''
trigger:
  - platform: state
    entity_id: input_number.servo_control
condition: []
action:
  - data_template:
      level: '{{ trigger.to_state.state | int }}'
    service: esphome.toilet_control_servo
mode: single
1 Like

Just wondering about this set up. I have it all working and i’m able to use the ‘servo control’ slider to control the servo. But the ‘write servo value to ESP’ only disables the servo control slider. Has anyone been able to actually stop the servo running? If you listen to your servo it is constantly trying to turn, in time this will sure wear the servo out or if you use multiple servos you will hear the hum?

Im no expert but in the past i used 125 as a pulse length to turn the servo one way (not through home assist), 575 to turn the servo another and was also able to use 4096 to detach the servo which shut the power off and stopped the humming.

Anyone any thoughts on a way to incorporate that into the setup?

I think i may have jumped the gun with this one.

Noticed in the esphome info pages regarding servos, there’s some info on detaching. Will check that out now, if anyone else is interested the link is.

The link was posted earlier, but if anyone comes across my question, here’s the link again

This works perfect for me.
But my servo is vibrating?
Servo does not vibrating if i program with IDE…
Do you know a solution for this?

Hi, do you mind sharing how you connected 5v power supply to the esp32?
Pretty new to esphome

Hey,

I’m just using the USB connector for power

1 Like