Setting the position of a template cover and getting open/closed status from sensor

I have a motorised curtain controlled by an ESP board running ESPhome.
The setup is simple, the ESP board is wired to 3 relays which connect a dry contact to a common contact for triggering, one each for the command of open, close, and stop. Each command is in Home Assistant as a switch and then I use those switches to create a template cover for the curtain.

There are two more things I am trying to achieve with this curtain.

1: Read the state of a reed switch to determine if the curtain is either fully closed or open (even partially open should read as open).
The following is my code for my template cover for this curtain and the “value_template” part is what I “think” the code should look like for updating the open/closed status from a sensor, I haven’t installed the sensor yet but want to soon so any tips on whether my code will be able to update its state from the sensor would be hugely appreciated.

  - platform: template
        device_class: curtain
        friendly_name: "Bedroom Curtains"
        value_template: >-
          {% if is_state('binary_sensor.bedroom_curtain_status', 'on') %}
          {% else %}
          {% endif %}
          service: switch.turn_on
          entity_id: switch.bedroom_curtains_open
          service: switch.turn_on
          entity_id: switch.bedroom_curtains_close
          service: switch.turn_on
          entity_id: switch.bedroom_curtains_stop

2: I would like to be able to issue a command to tell the curtain to open to a set position. For example; 50% open.
I have found there is a “set_cover_position” variable but I’m a little stuck on how to use it.
The example used on the template cover page is like this:

          service: script.cover_group_position
            position: "{{position}}"

What I don’t get is:

  • Where does it get the data for “{{position}}” to use in the script?
  • What should the script look like for accomplishing this?

I can create a script to issue the command, delay the correct amount of seconds and then issue the cover.stop command and then I can create a bunch of template switches each triggering a script for say each 10% increment so I can activate one switch to open 10% and another for 20% and so on but this seems like an inelegant and inefficient solution so I’m trying to learn the right way to accomplish this.

Seriously, any and all help for this amateur is really appreciated.

for #1 the code you have looks correct as far as I can tell.

For #2 I think that the code is kind of hard to understand.

the “{{ position }}” should be a value (either hard coded or derived from some kind of entity or passed thru an automation) then that value will get passed to the script using the “position” variable used in the script.

I the case of the example the automation at the very bottom is passing the “position” to the cover template for the “set_cover_position” service, which in turn sends that “position” variable along to the script.

At least I think that’s how it works…

But as far as you general question about setting a position…

How would your code know that the position has been reached?

For example say you want to set the position to 65%. How would your system know that the curtains are at 65% and to stop the curtain motion? I don’t see anywhere that you have any analog(ish) actual position feedback. You only have open/closed/somewhere in between.

Thank you so much for your reply.

#1 - As soon as I get my sensor installed I’ll try it out and report back so others searching later can see if and how it worked.

#2 - That is an extremely helpful answer, thank you.
I think I have a little better understanding of it now, but some I still don’t quite understand.
Please let me know if my understanding is right, wrong, or somewhere between.
In the cover template setup code I can set an action for setting the cover position, specifically that action will call a script to execute.
My thought about how to control the position is to use a delay. For example, if my curtain takes exactly 10 seconds to fully open and I want to set it to 50% open I could script it as

- cover.bedroom_curtains
- delay: 5
- cover.stop: cover.bedroom_curtains

It wouldn’t be totally accurate but it’s good enough for my purposes. I use a script like this to slowly open my curtains at a set time each morning, it works well.

Here is where I still get lost.
Say I use a voice command or let’s say I use the home app on iPhone to tell the curtains to open to 50%. Does the system then take this “50%” from my voice or Home app command and pass that through as the variable? Or does that variable have to be set in some other place/way?
I guess there is a way to use that passed through variable to change the amount of time of the “delay” step of my script but I’m not sure how to do that.

You could do it like that for a predefined setting but lets say you want to open the curtain to 60% or 20%. How would you do that using the cover template? I could think of a way to do it but it’s going to get kind of complicated using a counter for the “actual” position and an input_number for the position setpoint. But then you would need an automation to increment/decrement the counter to simulate the position feedback to the cover.

And if you operate the curtain outside of HA then everything will be out of synch until you resynch it. Then the position template gets even more complex.

I think once you figure out how to set up the position control in HA that a voice assistant would be able to work with that just like it would with a standard variable position cover. But there’s no way to really know until you try it out. But again you’ll have to figure out how to work out the position feedback simulation based on time and/or the real open/closed sensors first.