Switch-Bot API integration

For those of you struggling with one of the buttons for the curtains being greyed out: I solved it. It has to do with the slider position. In Home Assistant a slide position of 100 means fully opened and a slide position of 0 is fully closed. In the SwitchBot API it’s the exact opposite: a slide position of 100 is fully closed and 0 is fully opened. The trick is quite simple: subtract the SlidePosition value you get with the API from 100. You have to do the same with setting the position: subtract the value from the slider in HA from 100 and pass the result as a parameter to the SwitchBot API.

As I noticed that the curtains do not always report 0 or 100 if they have been fully opened or closed, but e.g. 1 or 99, I also fixed that, by using an if-statement in the sensor template. Furthermore, I left out the stop_cover command, because the API doesn’t support that.

I used the templates from @gdeboos. This is what the SwitchBot part of my configuration.yaml looks like after my modifications:

# Switchbot setup
rest_command:
  switchbot_device_command:
    url: 'https://api.switch-bot.com/v1.0/devices/{{ deviceId }}/commands'
    method: post
    content_type: 'application/json'
    headers:
      Authorization: !secret switchbot_api
    payload: '{"command": "{{ command }}","parameter": "{{ parameter }}"}'

sensor:
  - platform: rest
    name: 'Positie gordijnen balkon'
    resource: !secret switchbot_balkon_status_url
    method: GET
    scan_interval: 600
    headers:
      Authorization: !secret switchbot_api
      Content-Type: 'application/json'
    value_template: >
      {% if value_json.body.slidePosition > 95 %} 0
      {% elif value_json.body.slidePosition < 5 %} 100
      {% else %} {{100-value_json.body.slidePosition}}
      {% endif %}
    json_attributes_path: "$.body"
    json_attributes:
      - deviceId
      - deviceType
      - hubDeviceId
      - calibrate
      - group
      - moving
      - slidePosition

cover:
  - platform: template
    covers:
      gordijnen_balkon:
        device_class: curtain
        friendly_name: "Gordijnen balkon"
        unique_id: curtain.balkon
        position_template: "{{states('sensor.positie_gordijnen_balkon')}}"
        open_cover:
          service: rest_command.switchbot_device_command
          data:
            deviceId: !secret switchbot_balkon_deviceId
            command: "turnOn"
        close_cover:
          service: rest_command.switchbot_device_command
          data:
            deviceId: !secret switchbot_balkon_deviceId
            command: "turnOff"
        set_cover_position:
          service: rest_command.switchbot_device_command
          data:
            deviceId: !secret switchbot_balkon_deviceId
            command: "setPosition"
            parameter: "0,ff,{{100-position}}"


As you can see HA reports the position of the curtain for the balcony as 100 (fully opened), while the sensor read-out via the API for SlidePosition is 0.

7 Likes

image
Curtain fully opened, so slider position in HA at 100 (corresponding with a SwitchBot slide position of 0).

1 Like

image
Curtains partially open (70 percent open), so both arrow buttons can be clicked/tapped upon. BTW: up is open, down is close. :slight_smile:

1 Like

Does anyone have a template for the Color Bulb?
Please

2 Likes

Everything i try, the curtains won’t react to the commands in home assistant. Even when i open/close the curtains with the switchbot app, it is not displayed in the history in Home assistant.

Also the meter isn’t working
afbeelding

don’t know what i’m doing wrong. out of idea’s.

But what i see at your pictures looks great.

Hello. I didn’t find sample codes/ automations for the Switchbot humidifier in this thread. Here is my setup if anyone is interested. I have used some of the codes here to call API and for the automations, helpers and sensors, I used @ tom_l lounge heating and cooling automations.

Paste these codes and adjust to your HA environment. Best to restart HA since there are quite a few of codes. Hope I didn’t missed anything.

configuration.yaml

rest_command:
  switchbot_device_command:
    url: "https://api.switch-bot.com/v1.0/devices/{{ deviceId }}/commands"
    method: post
    content_type: "application/json"
    headers:
      Authorization: !secret switchbot_api
    payload: '{ "command": "{{ command }}", "parameter": "{{ parameter }}" }'

# humidifier sensors
rest:
  - resource: !secret switchbot_wohumi_waterlevel_url
    method: GET
    headers:
      Authorization: !secret switchbot_api
      Content-Type: 'application/json'
    scan_interval: 600 # adjust this to suite your need. There is api limit of 10,000 /per day.
    sensor:
      - name: SB Humidifier Lack Water
        value_template: "{{ value_json.body.lackWater }}"
        device_class: carbon_dioxide
      - name: SB Humidifier Nebulization Efficiency
        value_template: "{{ value_json.body.nebulizationEfficiency }}"
        device_class: ozone 
      - name: SB Humidifier Temperature
        value_template: "{{ value_json.body.temperature }}"
        device_class: temperature 
      - name: SB Humidifier Humidity
        value_template: "{{ value_json.body.humidity }}"
        device_class: humidity

secret.yaml

switchbot_api: '2ac4f4dxxxxxxxx6a0718ec'
switchbot_wohumi_waterlevel_url: 'https://api.switch-bot.com/v1.0/devices/<devicID>/status'
switchbot_wohumi_id: '<deviceID>'

input_select.yaml

  sb_humidifier_mode:
    name: SB Humidifier Mode
    icon: mdi:air-humidifier
    options:
      - 'Off'
      - Auto
      - Low
      - Med
      - High

input_number.yaml

  lrh_humidity_low_set:
    name: Humidity Low Set Point
    icon: mdi:thermometer
    initial: 30
    min: 0
    max: 100
    step: 1

  lrh_humidity_high_set:
    name: Humidity High Set Point
    icon: mdi:thermometer
    initial: 50
    min: 0
    max: 100
    step: 1

  lrh_humidity_intensity_set:
    name: Humidifier Intensity
    icon: mdi:water-plus
    min: 34
    max: 100
    step: 1

input_datetime.yaml

  lrh_ac_am_on_time:
    name: Humidifier AM On Time
    has_time: true
    initial: '05:00'
  lrh_ac_am_off_time:
    name: Humidifier AM Off Time
    has_time: true
    initial: '06:00'
  lrh_ac_pm_on_time:
    name: Humidifier PM On Time
    has_time: true
    initial: '18:30'
  lrh_ac_pm_off_time:
    name: Humidifier PM Off Time
    has_time: true
    initial: '19:00'

input_boolean.yaml

  lrh_humidifier_automation_enable:
    name: Humidifier Automation
    icon: mdi:av-timer
    initial: off

binary_sensor.yaml

      lrh_humidifier_am_automation_time_active:
        friendly_name: "LRH Humidifier AM Automation Time Active"
        value_template: >-
          {% set d = now().strftime("%Y-%m-%dT") %}
          {% set tz = as_timestamp(now()) | timestamp_custom('%z') %}
          {% set t = now().timestamp() %}
          {% set am_start = as_timestamp(d ~ states('input_datetime.lrh_ac_am_on_time') ~ tz) %}
          {% set am_end = as_timestamp(d ~ states('input_datetime.lrh_ac_am_off_time') ~ tz) %}
          {{ am_start <= t <= am_end }}

      lrh_humidifier_pm_automation_time_active:
        friendly_name: "LRH Humidifier PM Automation Time Active"
        value_template: >-
          {% set d = now().strftime("%Y-%m-%dT") %}
          {% set tz = as_timestamp(now()) | timestamp_custom('%z') %}
          {% set t = now().timestamp() %}
          {% set am_start = as_timestamp(d ~ states('input_datetime.lrh_ac_pm_on_time') ~ tz) %}
          {% set am_end = as_timestamp(d ~ states('input_datetime.lrh_ac_pm_off_time') ~ tz) %}
          {{ am_start <= t <= am_end }}

script.yaml

  humidifier_low:
    sequence:
      - service: rest_command.switchbot_device_command
        data:
          deviceId: !secret switchbot_wohumi_id
          command: 'setMode'
          parameter: 101
        
  humidifier_med:
    sequence:
      - service: rest_command.switchbot_device_command
        data:
          deviceId: !secret switchbot_wohumi_id
          command: 'setMode'
          parameter: 102

  humidifier_high:
    sequence:
      - service: rest_command.switchbot_device_command
        data:
          deviceId: !secret switchbot_wohumi_id
          command: 'setMode'
          parameter: 103

  humidifier_auto:
    sequence:
      - service: rest_command.switchbot_device_command
        data:
          deviceId: !secret switchbot_wohumi_id
          command: 'setMode'
          parameter: auto
          
  humidifier_off:
    sequence:
      - service: rest_command.switchbot_device_command
        data:
          deviceId: !secret switchbot_wohumi_id
          command: 'turnOff'
          parameter: default

  lrh_humidity_intensity_set:
    sequence:
      - service: rest_command.switchbot_device_command
        data:
          deviceId: !secret switchbot_wohumi_id
          command: 'setMode'
          parameter: "{{ states('input_number.lrh_humidity_intensity_set') }}"

automation.yaml

- alias: 'SB Humidifier'
  initial_state: true
  trigger:
    platform: state
    entity_id: input_select.sb_humidifier_mode
  action:
  - service_template: >
      {% if is_state('input_select.sb_humidifier_mode', 'Low') %} script.humidifier_low
      {% elif is_state('input_select.sb_humidifier_mode', 'Med') %} script.humidifier_med
      {% elif is_state('input_select.sb_humidifier_mode', 'High') %} script.humidifier_high
      {% elif is_state('input_select.sb_humidifier_mode', 'Auto') %} script.humidifier_auto
      {% elif is_state('input_select.sb_humidifier_mode', 'Off') %} script.humidifier_off
      {% endif %}


- alias: 'SB Humidifier Intensity'
  initial_state: true
  trigger:
    platform: state
    entity_id: input_number.lrh_humidity_intensity_set
  condition:
  - condition: template # Only if currently On
    value_template: "{{ is_state('input_boolean.sb_humidifier', 'on') }}"
  action:
  - service: script.lrh_humidity_intensity_set


- alias: 'SB Humidifier AM Schedule'
  trigger:
    - platform: state
      entity_id: binary_sensor.lrh_humidifier_am_automation_time_active
      to: 'on'
      for:
        seconds: 10
  condition:
    - condition: template # Only if automation is enabled
      value_template: "{{ is_state('input_boolean.lrh_humidifier_automation_enable', 'on') }}"
    - condition: template # Only if currently Off
      value_template: "{{ is_state('input_select.sb_humidifier_mode', 'Off') }}"
    - condition: numeric_state 
      entity_id: sensor.sb_humidifier_humidity
      above: input_number.lrh_humidity_low_set
      below: input_number.lrh_humidity_high_set
    - condition: template # Water tank not empty
      value_template: "{{ is_state('sensor.sb_humidifier_lack_water', 'False') }}"
    - condition: template # Someone is home
      value_template: "{{ is_state('input_select.home_mode', 'Home') }}"
  action:
    service: input_select.select_option
    data_template:
      entity_id: input_select.sb_humidifier_mode
      option: High


- alias: 'SB Humidifier PM Schedule'
  trigger:
    - platform: state
      entity_id: binary_sensor.lrh_humidifier_pm_automation_time_active
      to: 'on'
      for:
        seconds: 10      
  condition:
    - condition: template # Only if automation is enabled
      value_template: "{{ is_state('input_boolean.lrh_humidifier_automation_enable', 'on') }}"
    - condition: template # Only if currently Off
      value_template: "{{ is_state('input_select.sb_humidifier_mode', 'Off') }}"
    - condition: numeric_state 
      entity_id: sensor.sb_humidifier_humidity
      above: input_number.lrh_humidity_low_set
      below: input_number.lrh_humidity_high_set
    - condition: template # Water tank not empty
      value_template: "{{ is_state('sensor.sb_humidifier_lack_water', 'False') }}"
    - condition: template # Someone is home
      value_template: "{{ is_state('input_select.home_mode', 'Home') }}"
  action:
    service: input_select.select_option
    data_template:
      entity_id: input_select.sb_humidifier_mode
      option: High


- alias: 'SB Humidifier AM Off'
  trigger:
    - platform: state
      entity_id: binary_sensor.lrh_humidifier_am_automation_time_active
      to: 'off'
  condition:
    - condition: state # Only if AM automation is enabled
      entity_id: automation.sb_humidifier_am_schedule
      state: 'on'
    - condition: template # And only if humidifier is on
      value_template: '{{ states("input_select.sb_humidifier_mode") != "Off" }}'
  action:
    service: input_select.select_option
    data_template:
      entity_id: input_select.sb_humidifier_mode
      option: 'Off'

- alias: 'SB Humidifier PM Off'
  trigger:
    - platform: state
      entity_id: binary_sensor.lrh_humidifier_pm_automation_time_active
      to: 'off'
  condition:
    - condition: state # Only if PM automation is enabled
      entity_id: automation.sb_humidifier_pm_schedule
      state: 'on'
    - condition: template # And only if humidifier is on
      value_template: '{{ states("input_select.sb_humidifier_mode") != "Off" }}'
  action:
    service: input_select.select_option
    data_template:
      entity_id: input_select.sb_humidifier_mode
      option: 'Off'

This is how my lovelace looks like. Manual controls and automations are here. This is also taken from @ tom_l. I used decluttering-card. Make sure you have this installed and setup. You can do it without it, just follow what is in ui-lovelace.yaml and input the entities in lovelace.yaml below. The Humidifier Auotmation switch is what will turn on your am/pm automations. Make sure it is in the on position.

ui-lovelace.yaml

  humidifier_tpl:
    card:
      type: 'custom:vertical-stack-in-card'
      cards:
        - type: glance
          title: '[[title]]'
          state_color: false
          show_name: false
          entities:
            - entity: '[[entity_1]]'
              name: Humidifier
            - entity: '[[entity_2]]'
              name: Temperature
            - entity: '[[entity_3]]'
              name: Humidity
            - entity: '[[entity_4]]'
              name: Efficiency
        - entities:
            - head:
                label: Automation
                type: section
              items:
                - input_boolean.[[room]]_humidifier_automation_enable                                              
                - input_datetime.[[room]]_ac_am_on_time
                - input_datetime.[[room]]_ac_am_off_time
                - input_datetime.[[room]]_ac_pm_on_time
                - input_datetime.[[room]]_ac_pm_off_time
                - input_number.[[room]]_humidity_low_set                
                - input_number.[[room]]_humidity_high_set              
                - input_number.[[room]]_humidity_intensity_set
              type: 'custom:fold-entity-row'
          show_header_toggle: false
          type: entities

lovelace.yaml (file inside of lovelace folder)

  - type: custom:decluttering-card
    template: humidifier_tpl
    variables:
      - title: Humidifier Controls
      - room: lrh
      - entity_1: input_select.sb_humidifier_mode
      - entity_2: sensor.sb_humidifier_temperature
      - entity_3: sensor.sb_humidifier_humidity
      - entity_4: sensor.sb_humidifier_nebulization_efficiency
1 Like

Works perfect @gvandenhil Thanks.

Thanks for the great work all. My curtains and IR hub are all working great. I actually really like the way they handled their api too. Super simple. Get a token, get your device id’s, make rest calls. Wish every company did this.

Only final issue I have is that even though I’m using device class curtain, it’s showing me the icon for shade (like roller shades, rather than curtains like gvandenhill’s pics showed. Happening to any one else? Otherwise, perfect.

Disregard this message. Turns out my phone is too ancient and it ended up cropping out half the switchbot api token for some reason. Wasted a couple hours to figure that out :joy:

So I’m trying to set up my switchbot devices, but I keep getting {“message”:“Unauthorized”} with the command:

curl -H "Authorization: API_KEY_HERE" https://api.switch-bot.com/v1.0/devices

I tried resetting my token a couple times, making sure I copied it correctly every time. Hub is connected to wifi. Switchbot app is updated. Unfortunately I get the same unauthorized message whether using windows command prompt or home assistant terminal

Based on the SwitchBotApi github, {“message”:“Unauthorized”} means: Http 401 Error. User permission is denied due to invalid token.

I’ve tried your method, but the close button is still greyed out, regardless of the position of the curtains. I copied your YAML, so I have no idea what’s wrong. Do you?

sensor:
  - platform: rest
    name: 'Gordijnen positie'
    resource: !secret switchbot_gordijnen_status_url
    method: GET
    scan_interval: 60
    headers:
      Authorization: !secret switchbot_api
      Content-Type: 'application/json'
    value_template: >
      {% if value_json.body.slidePosition > 90 %} 0
      {% elif value_json.body.slidePosition < 10 %} 100
      {% else %} {{100-value_json.body.slidePosition}}
      {% endif %}
    json_attributes_path: "$.body"
    json_attributes:
      - deviceId
      - deviceType
      - hubDeviceId
      - calibrate
      - group
      - moving
      - slidePosition

rest_command:
  switchbot_device_command:
    url: 'https://api.switch-bot.com/v1.0/devices/{{ deviceId }}/commands'
    method: post
    content_type: 'application/json'
    headers:
      Authorization: !secret switchbot_api
    payload: '{"command": "{{ command }}","parameter": "{{ parameter }}"}'

cover:
  - platform: template
    covers:
      gordijnen:
        device_class: curtain
        friendly_name: "Gordijnen"
        unique_id: curtain.gordijnen
        position_template: "{{states('sensor.positie_gordijnen')}}"
        open_cover:
          service: rest_command.switchbot_device_command
          data:
            deviceId: !secret switchbot_gordijnen_deviceId
            command: "turnOn"
        close_cover:
          service: rest_command.switchbot_device_command
          data:
            deviceId: !secret switchbot_gordijnen_deviceId
            command: "turnOff"
        set_cover_position:
          service: rest_command.switchbot_device_command
          data:
            deviceId: !secret switchbot_gordijnen_deviceId
            command: "setPosition"
            parameter: "0,ff,{{100-position}}"

stop command not available in API as mentioned already by @gvandenhil, you can put back turnOff command = copy of close cover command

        stop_cover:
          service: rest_command.switchbot_device_command
          data:
            deviceId: !secret switchbot_gordijnen_deviceId
            command: "turnOff"

I’ve been using this with my switchbot curtains and I was just wondering if there is a way to integrate the battery status into the solution? I couldn’t see it on a quick scan of the API but would be really helpful to integrate the battery status into my Home Assistant monitoring…

Hi there,

thanks for the great work. I put my meters and my hub (as IR-Controller) in ha. Most things are fine, but it would be nice, if the IR-Buttons work as ha-buttons and not like switches. Could you give me a hint, how i can use the HA-Buttons?

Hi all,

I was constantly struggling with the calibration of my curtains. It only happened with Home Assistant, so I knew it had to be specifically that. I’ve been messing around with the code for a little bit and now my curtains are completely closing again. It seems that turnOn and turnOff are not working properly.

I also saw the remarks about the greyed out close arrow. Since the API only asks for every 10 minutes, the arrow will be white/clickable after 10 minutes (in my experience). That’s where the stop button comes in handy. That one will always close your curtain.

Below the code for what I’m using (based on the different templates that I got here)

# Switchbot
rest_command:
  switchbot_device_command:
    url: 'https://api.switch-bot.com/v1.0/devices/{{ deviceId }}/commands'
    method: post
    content_type: 'application/json'
    headers:
      Authorization: !secret switchbot_api
    payload: '{"command": "{{ command }}","parameter": "{{ parameter }}"}'

sensor:
  - platform: rest
    name: 'Positie Woonkamer Gordijn'
    resource: !secret switchbot_woonkamergordijn_status_url
    method: GET
    scan_interval: 600
    headers:
      Authorization: !secret switchbot_api
      Content-Type: 'application/json'
    value_template: '{{ value_json.body.slidePosition }}'
    json_attributes_path: "$.body"
    json_attributes:
      - deviceId
      - deviceType
      - hubDeviceId
      - calibrate
      - group
      - moving
      - slidePosition

cover:
  - platform: template
    covers:
      bedroom_curtains:
        device_class: curtain
        friendly_name: "Woonkamergordijn"
        position_template: "{{ states('sensor.positie_woonkamer_gordijn') }}"
        open_cover:
          service: rest_command.switchbot_device_command
          data:
            deviceId: !secret switchbot_woonkamergordijn_deviceId
            command: "setPosition"
            parameter: "0,ff,0"
        close_cover:
          service: rest_command.switchbot_device_command
          data:
            deviceId: !secret switchbot_woonkamergordijn_deviceId
            command: "setPosition"
            parameter: "0,ff,100"
        stop_cover:
          service: rest_command.switchbot_device_command
          data:
            deviceId: !secret switchbot_woonkamergordijn_deviceId
            command: "setPosition"
            parameter: "0,ff,100"
        set_cover_position:
          service: rest_command.switchbot_device_command
          data:
            deviceId: !secret switchbot_woonkamergordijn_deviceId
            command: "setPosition"
            parameter: "0,ff,{{position}}"

With warm regards,

Dennis

Can you please explain where meter1_json in states.sensor.meter1_json.attributes comes from?

For example, you have a name Meter1 JSON. Would everything still work if you were to name that SomethingRandom?

The name is automatically slugified ( → lower case, and spaces → underscores ) by the integration and used as the entity object id. e.g.

name: 'Any Name Here'

is converted to:

sensor.any_name_here

Where, sensor is the domain, and any_name_here is the object_id of the entity_id

entity_id: domain.object_id

As long as you realise that changing the name changes the entity_id you can change it to pretty much anything you want. Be careful with symbols (slugified to underscores), and try not to start your name with numbers. object_ids beginning with numbers require special treatment in some circumstances.

When i use rest command to open my curtains my switchbot open more than it should ( More than my Calibration) and wheels trying to spin even when it max on the rail :frowning: WHY? XD

I have 4 SwitchBot switches I use on some light switches that I’m having some difficulty properly integrating into HA and I’m hoping someone can help.

I got the device IDs by running this in in Terminal in macOS…

curl -H "Authorization: my_api_key" https://api.switch-bot.com/v1.0/devices

I then added this to secrets.yaml…

switchbot_api: "my_api_key"
switchbot_deviceId: "my_device_id"
switchbot_ryans_office_status_url: "https://api.switch-bot.com/v1.0/devices/my_device_id/status"

I then added this to configuration.yaml…

rest_command:
  switchbot_device_command:
    url: "https://api.switch-bot.com/v1.0/devices/{{ deviceId }}/commands"
    method: post
    content_type: "application/json"
    headers:
      Authorization: !secret switchbot_api
    payload: '{"command": "{{ command }}"}'

switch:
  - platform: template
    switches:
      ki_switchbot:
        friendly_name: Switchbot
        turn_on:
          service: rest_command.switchbot_device_command
          data:
            deviceId: !secret switchbot_deviceId
            command: "turnOn"
        turn_off:
          service: rest_command.switchbot_device_command
          data:
            deviceId: !secret switchbot_deviceId
            command: "turnOff"

I then added this to lovelace…

type: entities
entities:
  - entity: switch.ki_switchbot
    name: My Office
    secondary_info: last-changed
title: Switchbot Lights

… and it’s actually working!

1

However, I quickly realized that it’s not polling for updates so if I control it anywhere outside of HA it becomes out of sync and I’ve scanned through the dozens of posts above and see some sample code on how to poll for updates but I’m a bit unsure of how to actually apply it to configuration.yaml. Also as I have 4 different switches it seems a bit clunky to paste all the stuff above over and over again for each switch and I’m sure there is an easier way I’m just getting a bit twisted up trying to make it all work and looking for some help.

2 Likes

Anyone knows how to set 2 or more curtains?
I was able to follow the guide for only 1 pair of curtains. But what if I wanted to add another pair? If I type the same code twice, the first valid for the first pair and the second valid for the second pair, Home Assistant gives me an error.

The problem is the curtain position number. Home assistant is expecting position 0 to be closed and 100 to be open, where as switchbot reports it the opposite way round.
Refer to Template Cover - Home Assistant

position_template:
Defines a template to get the position of the cover. Legal values are numbers between “0” (closed) and “100” (open).

Switchbot reports 0 as open and 100 as closed.

The fix is to use the following in the position_template.

cover:
  - platform: template
    covers:
      bedroom_curtains:
      device_class: curtain
        friendly_name: "Bedroom Curtains"
        #position_template: "{{ states('sensor.bedroom_curtain_position') }}" # original
        position_template:  "{% if  (states('sensor.bedroom_curtain_position') | round | int) == 0 %}
                             100
                             {% else %}
                             {{  100 % (states('sensor.bedroom_curtain_position') | round | int) }}
                             {% endif %}" # my change using % (mod) to convert the value. if value is 0 it throws error in log about using mod on a value of 0. so place in the static value instead.
        open_cover:
          service: rest_command.switchbot_device_command
          data:
            deviceId: !secret switchbot_bedroom_deviceId
            command: "turnOn"
        close_cover:
          service: rest_command.switchbot_device_command
          data:
            deviceId: !secret switchbot_bedroom_deviceId
            command: "turnOff"
        stop_cover:
          service: rest_command.switchbot_device_command
          data:
            deviceId: !secret switchbot_bedroom_deviceId
            command: "turnOff"
        set_cover_position:
          service: rest_command.switchbot_device_command

The mod (%) math function provides the remainder value. You can google the mod math function but effectively it does the following.

{{ 100 % (states(‘sensor.bedroom_curtain_position’) | round | int) }}

100 % 99 = 1
100 % 98 = 2
100 % 90 = 10
100 % 50 = 50
100 % 30 = 70
100 % 5 = 95
100 % 2 = 98
100 % 0 = 100

It effectively converts/switches the slider position to one compliant with home assistant. It works great on my curtains using the api.

Really Hope people find this helpful. I know this bothered my when interacting with curtains on my lovelace dashboard. This resolve it completely.