Need some help with code/ how to... (show input slider as a percentage rather than the actual number)

Hello all,

Could someone help me with coding or give me an example of how to code this:

Essentially I have 2 input sliders that control a set of blinds (the tilt portion of the blind). One goes from 0-460 and one goes from 0-700 (these numbers are essentially steps on the motor). How can I show those on a 100 percent scale though? 0 is fully closed in the down positions, 700 is in the middle of the blind positions which is 100% open (i.e. letting the most light in)

input_number:
  stepper_control_right_test_blind:
    name: Stepper Control Right Test Blind
    min: 0
    max: 460
    step: 1
    mode: slider
  stepper_control_left_test_blind:
    name: Stepper Control Left Test Blind
    min: 0
    max: 700
    step: 1
    mode: slider

I currently have these controlled by the standard cover (up/ stop/ down) lovelace card but I would like to also be able to control these by position (i.e. percent open). Can someone help me with this? (I’m not a programmer sadly).

Below is my current code for the first example 0-460 (so 920 would be closed in the up position)

I’m not sure that you all will even need the below but I have provided for others that may want to use it. (I didn’t develop it, I am a monkey when it comes to coding :frowning: )

Thank you all for any help/ guidance you can provide

esphome:
  name: "dining-room-blinds"
  platform: ESP32
  board: nodemcu-32s

  on_boot:
    - priority: -200.0
      then:
      - stepper.report_position: # Set stepper to global variable
          id: stepper_motor
          position: !lambda return id(stepper_motor_global);
      - stepper.set_target: # Set stepper to global variable
          id: stepper_motor
          target: !lambda return id(stepper_motor_global);
      - if: # If blind is Closed
          condition:
            - lambda: 'return id(stepper_motor_global) == 0;'
          then: # Publish state etc.
            - cover.template.publish:
                id: dining_room_blinds
                state: CLOSED
                current_operation: IDLE
      - if: # If blind is Open
          condition:
            - lambda: 'return id(stepper_motor_global) == id(endstop);'
          then: # Publish state etc.
            - cover.template.publish:
                id: dining_room_blinds
                state: OPEN
                current_operation: IDLE
      - if: # If blind is Neither
          condition:
            - lambda: 'return (id(stepper_motor_global) != 0) && (id(stepper_motor_global) != id(endstop));'
          then: #  # Publish state etc.
            - cover.template.publish:
                id: dining_room_blinds
                position: !lambda 'return (float(float(id(stepper_motor).current_position) / float(id(endstop))));' 
                current_operation: IDLE
# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "NkblotNz0QL9TwPbE1tGMAcayC41bZqSRavwCtduSP4="
  services:
    - service: control_stepper
      variables:
        target: int
      then:
        - stepper.set_target:
            id: stepper_motor
            target: !lambda 'return target;'

ota:
  password: "1c32e35ea8e90d369b8feb7f8b204aef"

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

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "DR-Blinds Fallback Hotspot"
    password: "Fhm0gqd5qfc3"

captive_portal:

web_server:
  port: 80
###################################################################
################################################################### STEPPER CHANGE (ENDSTOP)
###################################################################
globals:
  - id: stepper_motor_global # Integer for storing the stepper position in case of reboot
    type: int
    restore_value: True
    initial_value: '0'

  - id: openclosed # Boolean to store OPEN/CLOSED state
    type: bool
    restore_value: True
    initial_value: '0'

  - id: endstop # Variable for storing ENDSTOP (how far to move stepper)
    type: int
    restore_value: True
    initial_value: '460'   # this is the max value # this is the max value

stepper:
  - platform: a4988
    id: stepper_motor
    step_pin: GPIO2
    dir_pin: 
      number: GPIO4
      inverted: true   
    sleep_pin: 
      number: GPIO5
      inverted: true  # inverted since using enable pin
    max_speed: 250
###################################################################
################################################################### STEPPER CHANGE (TARGET)
###################################################################
cover:
  - platform: template
    name: Dining Room Blinds
    id: dining_room_blinds
    open_action:
      then:
        - logger.log: "Opening"
        - stepper.set_target: 
            id: stepper_motor
            target: 460
        - while:
            condition:
              lambda: 'return id(stepper_motor).current_position < id(endstop);'
            then:
              - cover.template.publish:
                  id: dining_room_blinds
                  position: !lambda 'return (float(float(id(stepper_motor).current_position) / float(id(endstop))));' 
                  current_operation: OPENING
              - delay: 1000 ms
        - globals.set: # Set global to current position
            id: stepper_motor_global
            value: !lambda return id(stepper_motor).current_position; 
        - globals.set: # Set toggle to OPEN (No need for 'optimistic mode')
            id: openclosed
            value: '1'
        - cover.template.publish:
            id: dining_room_blinds
            state: OPEN 
            current_operation: IDLE
    close_action:
      then:
        - logger.log: "Closing"
        - stepper.set_target: # Send stepper to 0
            id: stepper_motor
            target: '0'
        - while:
            condition:
              lambda: 'return id(stepper_motor).current_position > 0;'
            then:
              - cover.template.publish:
                  id: dining_room_blinds
                  position: !lambda 'return (float(float(id(stepper_motor).current_position) / float(id(endstop))));' 
                  current_operation: CLOSING
              - delay: 1000 ms
        - globals.set: # Set global to current position
            id: stepper_motor_global
            value: !lambda return id(stepper_motor).current_position; 
        - globals.set: # Set toggle to CLOSED (No need for 'optimistic mode')
            id: openclosed
            value: '0'
        - cover.template.publish:
            id: dining_room_blinds
            state: CLOSED
            current_operation: IDLE
    position_action:
      then:
        - stepper.set_target:
            id: stepper_motor
            target: !lambda return int(id(endstop) * pos);
        - while:
            condition:
              lambda: 'return id(stepper_motor).current_position != int(id(endstop) * pos);'
            then:
              - cover.template.publish:
                  id: dining_room_blinds
                  position: !lambda 'return (float(float(id(stepper_motor).current_position) / float(id(endstop))));' 
              - delay: 1000 ms
        - globals.set: # Set global to current position
            id: stepper_motor_global
            value: !lambda return id(stepper_motor).current_position; 
        - cover.template.publish:
            id: dining_room_blinds
            position: !lambda 'return (float(float(id(stepper_motor).current_position) / float(id(endstop))));' 
            current_operation: IDLE
    stop_action:
      then:
        - stepper.set_target:
            id: stepper_motor
            target: !lambda return id(stepper_motor).current_position;
        - globals.set: # Set global to current position
            id: stepper_motor_global
            value: !lambda return id(stepper_motor).current_position;
        - cover.template.publish:
            id: dining_room_blinds
            position: !lambda 'return (float(float(id(stepper_motor).current_position) / float(id(endstop))));' 
            current_operation: IDLE
    has_position: true
    device_class: blind

###################################################################
################################################################### STEPPER CHANGE (TARGET)
###################################################################

switch:
  - platform: template
    name: Reset Dining Room Blinds
    id: reset
    turn_on_action:
      - stepper.set_target:
          id: stepper_motor
          target: '920'
      - wait_until: 
          lambda: 'return id(stepper_motor).current_position == 1500;'
      - delay: 1s
      - stepper.set_target:
          id: stepper_motor
          target: '0'
      - globals.set: # Set global to current position
          id: stepper_motor_global
          value: !lambda return id(stepper_motor).current_position; 
      - globals.set: # Set toggle to CLOSED (No need for 'optimistic mode')
          id: openclosed
          value: '0'
      - cover.template.publish:
          id: dining_room_blinds
          state: CLOSED
          current_operation: IDLE
      - switch.turn_off: reset
  - platform: restart
    name: "Dining Room Blinds Reboot"
    
###################################################################
###################################################################
###################################################################

# Text sensors with general information.
text_sensor:
  # Expose WiFi information as sensors.
  - platform: wifi_info
    ip_address:
      name: Dining Room Blinds IP
    ssid:
      name: Dining Room Blinds SSID

# Sensors with general information.
sensor:
  # WiFi Signal sensor.
  - platform: wifi_signal
    name: Dining Room Blinds WiFi Signal
    update_interval: 60s
    

Should this still be relevant;
I had something similar and I’ve asked ChatGPT :wink:
Its useless for most things, but asking for formulas goes really well.

I had min=15, max=50 and an input_number 0-100%

So I asked: how do i calculate values between 0 - 100% from a range between 15-50
It came back with Value=(Percentage/100)×(MaxValue−MinValue)+MinValue, which did the job for me.

Hope this helps.