ESP Devices

Home Assistant & ESPHome Servo Example (Step-by-Step guide)

Looking to integrate a servo with Home Assistant? This step-by-step tutorial will guide you through the process of building a wireless servo and integrating it with Home Assistant!

For the example we will be using a readily available Wemos D1 Mini and RC servo, however you can use any compatible ESP device and servo. By utilizing an ESP device and the ESPHome platform, adding a servo to your smart home is a piece of cake!

Bitmoji Image

Prerequisite

For this tutorial we will assume that you have Home Assistant up and running already. A very basic knowledge of configuration.yaml would also be advantageous, but we will cover as much detail as possible.

If you are completely new to Home Assistant then you should probably first check out my beginners guide to YAML, as well as my tutorials on automation and scripts.

You will also need to configure the ESPHome add-on in Home Assistant and have a compatible ESP device such as the Wemos D1 Mini. If you haven’t installed the ESP Home add-on yet, go ahead and check out my tutorial on how to add ESPHome to Home Assistant.

Wiring

A standard analogue RC servo usually has three wires and operates from 5 volts. The red and black wire should be connected to +5V and ground respectively. The third lead is the control signal and is usually yellow or orange.

Servos are usually shipped with some variant of a standard pin header style connection with 2.54mm pin spacing. For testing you can connect the servo to the ESP device using jumper wires.

The red positive lead is usually connected to the middle pin of the connector to prevent damage occurring if the connecter is inserted backwards. As we are not connecting our RC servo to a standard RC receive, we need to take care that the connections are correct.

On our ESP device we need to connect the orange signal lead to one of the GPIOs. For this example I will connect the signal lead to D3 on the Wemos D1 Mini. If you are using a different device and/or choose a different pin, don’t forget to amend the example code as necessary.

The black lead needs to be connected to ground, labelled as ‘G’ on the Wemos D1 Mini. The red lead needs to be connected to 5 volts, labeled as ‘5V’ on the Wemos D1 Mini.

Note that larger servos and/or servos under a lot of load may draw more current than the USB port can supply. If in doubt you should use an external 5 volt power supply.

If you are using an external power supply, the +5V connection should be made to the power supply and the ground terminals should be tied together. The signal lead should be connected as normal, between the ESP device and servo.

Configure ESPHome

So now hopefully you have a servo connected to an ESP device as we are ready to start the configuration! As previously mentioned you will need to have the ESPHome add-on installed in Home Assistant. Alternatively you can write your configurations with a text editor and upload them manually.

Create a device

First you should add a new device in ESPHome if you have not done so already. When your new device is available in the user interface, go ahead and click edit and you should be presented with something like the following template. Note that the parameters will reflect your device configuration.

esphome:
  name: little_wemos
  platform: ESP8266
  board: d1_mini

wifi:
  ssid: "MyWiFiRouter"
  password: "************"

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

captive_portal:

# Enable logging
logger:

api:

ota:

Add the PWM output

First we will add an output component that tells ESPHome to send data to our servo. As our servo requires a PWM signal for control we will use the esp8266_pwm platform. Note that you should change this if you are using an ESP32 board.

We need to specify the output pin that the servo’s signal lead is connected to. I am using pin D4 (GPIO02) but you should change this accordingly if you are using a different pin or device. We also need to specify a PWM frequency of 50 Hz. We will give this output the ID pwm_output, which will be used to receive the data.

esphome:
  name: little_wemos
  platform: ESP8266
  board: d1_mini

wifi:
  ssid: "MyWiFiRouter"
  password: "************"

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

captive_portal:

# Enable logging
logger:

api:

ota:

output:
  - platform: esp8266_pwm
    id: pwm_output
    pin: D3
    frequency: 50 Hz

Add the servo component

Next we will add the servo component. This will act as the link between the output component that we just created and the incoming data from Home Assistant.

We will specify the output attribute as pwm_output in order to pass the data to the output. We will also assign the ID attribute my_servo, which will be used to receive the data from Home Assistant.

esphome:
  name: little_wemos
  platform: ESP8266
  board: d1_mini

wifi:
  ssid: "MyWiFiRouter"
  password: "************"

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

captive_portal:

# Enable logging
logger:

api:

ota:

output:
  - platform: esp8266_pwm
    id: pwm_output
    pin: D3
    frequency: 50 Hz

servo:
  - id: my_servo
    output: pwm_output

Add the native API component

At the time of writing Home Assistant does not yet support the servo component directly (version 0.108). Therefore in order to communicate with Home Assistant we must set up the native API component in ESPHome.

The native API component is used to directly receive data from Home Assistant and it will allow us to create a custom service. We will then be able to reference the custom service in the Home Assistant setup.

Data will be passed from the custom service in Home Assistant to the native API component. It will then be passed from the native API to the output pin via the servo component.

First we will add a service under the api component and name it control_servo. We will also create a new float variable to store the value for the servo named level.

esphome:
  name: little_wemos
  platform: ESP8266
  board: d1_mini

wifi:
  ssid: "MyWiFiRouter"
  password: "************"

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

captive_portal:

# Enable logging
logger:

api:
  services:
    - service: control_servo
      variables:
        level: float

ota:

output:
  - platform: esp8266_pwm
    id: pwm_output
    pin: D3
    frequency: 50 Hz

servo:
  - id: my_servo
    output: pwm_output

Home Assistant will create a custom service named esphome.<your-device>_control_servo and the data will be passed from this service to the variable level within the ESPHome device.

Next we will write the value level to the servo component that we created earlier, named my_servo.

esphome:
  name: little_wemos
  platform: ESP8266
  board: d1_mini

wifi:
  ssid: "MyWiFiRouter"
  password: "************"

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

captive_portal:

# Enable logging
logger:

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

ota:

output:
  - platform: esp8266_pwm
    id: pwm_output
    pin: D3
    frequency: 50 Hz

servo:
  - id: my_servo
    output: pwm_output

That completes the ESPHome configuration! Now you can go ahead and upload the code to your device.

Configure Home Assistant

Next we will configure Home Assistant by adding an automation to control to servo. For this example we will link the automation to a slider on the user interface, but you can adapt the code to something more suited to your own application.

Add an input

Firstly we need to create a way to input a value in Home Assistant to send to our servo. We will do this by adding a simple slider that will control the movement of the servo.

In order to add a slider we will create a new instance of input_number in the configuration.yaml file called servo_control. We will give it minimum and maximum values of -100 and 100 respectively. We will also set the initial value to 0 and step value to 1.

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

Add automation

In order to link our slider to the ESPHome device we need to create a new automation instance in the configuration.yaml file.

The entity for the trigger should be set to the slider entity that we just created. The action will then be fired whenever the slider changes value.

In the action section we will set the service to our ESPHome custom service created by the native API. You will find this in your list of services as esphome.<your-device>_control_servo.

In order to push the value from the slider to the native API via the service, we will use a data template. This template fetches the value of the slider and puts it into our level variable within ESPHome.

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

Add to the UI and Test the servo

Now we are ready to give the servo a test! Go ahead and add input_number.servo_control to the user interface. You can add the switch for the automation too, if you would like the option to disable the servo movement.

Adding multiple servos

If multiple servos are needed, we can simply replicate each stage of the code using a unique name. Let’s add a second servo and call it servo2, first we will add it to ESPHome.

Second servo in ESPHome

First we can add a second instance to the api communication. We must differentiate the new servo by giving it a unique name. In this example I have simply called it servo2.

esphome:
  name: little_wemos
  platform: ESP8266
  board: d1_mini

wifi:
  ssid: "MyWiFiRouter"
  password: "************"

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

captive_portal:

# Enable logging
logger:

api:
  services:
    - service: control_servo
      variables:
        level: float
      then:
        - servo.write:
            id: my_servo
            level: !lambda 'return level / 100.0;'
    - service: control_servo2
      variables:
        level: float
      then:
        - servo.write:
            id: my_servo2
            level: !lambda 'return level / 100.0;'

ota:

output:
  - platform: esp8266_pwm
    id: pwm_output
    pin: D3
    frequency: 50 Hz

servo:
  - id: my_servo
    output: pwm_output

Next we need to add a second PWM output. Here we can specify the pin that we wish to use for the second servo.

esphome:
  name: little_wemos
  platform: ESP8266
  board: d1_mini

wifi:
  ssid: "MyWiFiRouter"
  password: "************"

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

captive_portal:

# Enable logging
logger:

api:
  services:
    - service: control_servo
      variables:
        level: float
      then:
        - servo.write:
            id: my_servo
            level: !lambda 'return level / 100.0;'
    - service: control_servo2
      variables:
        level: float
      then:
        - servo.write:
            id: my_servo2
            level: !lambda 'return level / 100.0;'

ota:

output:
  - platform: esp8266_pwm
    id: pwm_output
    pin: D3
    frequency: 50 Hz
  - platform: esp8266_pwm
    id: pwm_output2
    pin: D2
    frequency: 50 Hz

servo:
  - id: my_servo
    output: pwm_output

Finally we will add an instance for the second servo to tie the incoming data from the servo2 Home Assistant service to the physical PWM output.

esphome:
  name: little_wemos
  platform: ESP8266
  board: d1_mini

wifi:
  ssid: "MyWiFiRouter"
  password: "************"

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

captive_portal:

# Enable logging
logger:

api:
  services:
    - service: control_servo
      variables:
        level: float
      then:
        - servo.write:
            id: my_servo
            level: !lambda 'return level / 100.0;'
    - service: control_servo2
      variables:
        level: float
      then:
        - servo.write:
            id: my_servo2
            level: !lambda 'return level / 100.0;'

ota:

output:
  - platform: esp8266_pwm
    id: pwm_output
    pin: D3
    frequency: 50 Hz
  - platform: esp8266_pwm
    id: pwm_output2
    pin: D2
    frequency: 50 Hz

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

Second servo in Home Assistant

Now we can add the second servo to our Home Assistant user interface. First let’s add a second input_number slider for controlling our second servo. Again in this example I am simply naming it with a numerical sequence.

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

Now we can add a second automation. If you have configured ESPHome correctly, you should find a second service available in Home Assistant called esphome.<your-device-name>_control_servo2.

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

  - alias: Write Servo2 Value to ESP
    trigger:
      platform: state
      entity_id: input_number.servo_control2
    action:
      - service: esphome.wemos_d1_mini_control_servo2
        data_template:
          level: '{{ trigger.to_state.state | int }}'

Finally we can add the slider and automation to the user interface in order to control the second servo. You can repeat this process in order to add even more servos. Awesome!

Conclusion

In this tutorial we learnt how to harness the power of ESPHome to make a bespoke integration within Home Assistant.

The ability to control servos adds many possibilities to the smart home ideas repertoire and could be further adapted for devices larger than an RC servo.

Why not go check out some of my other awesome Home Assistant tutorials to get some inspiration for your next ESPHome device!

back to top