How to setup ESPHome to control my Bluetooth controlled (Octocontrol) bed

I’m working on controlling my bed (Bluetooth Octocontrol, which is supplied with remotes and an App).
My primary goal was to control the under-bed light as also part of my setup.
I got that part working with an ESP32, ESPHome resulting in an on/off switch in Home Assistant (my first time analyzing bluetooth traffic :sunglasses:).

I used wireshark to analyze the bluetooth commands to control the bed (as send from the app on my Android phone). I got all commands logged and all are working.

My challenge… I also want to control bed movement and when I send the bed-head-up command it moves the bed-head up for a fraction of a second and then stops. In the wireshark logging I see a continuous (every +/-300ms) repeat of this command which results in a continuous move.

I wonder what the best approach to create similar behaviour in ESPHome would be and home somebody can help me. I looked into a first button to start movement (start while loop) and a second button to stop movement (stop the running while loop). Or possibly use the cover component (time based?).

What would be the best approach? And how could I set this up?

To also share my work so-far:

All controls (head / feet / head/feet combined / lamp) all use:
[Service UUID: 0xffe0]
[UUID: 0xffe1]

Specific commands:
Head up	  : 40 02 70 00 01 0b 02 40
Head down : 40 02 71 00 01 0a 02 40
Both up	  : 40 02 70 00 01 07 06 40
Both down : 40 02 71 00 01 06 06 40
Foot up   : 40 02 70 00 01 09 04 40
Foot down : 40 02 71 00 01 08 04 40

When logging I see repeating the commands above, for as long as the button 
is pressed. After that I see the following command: 40 02 73 00 00 0b 40 
(which does stop movement I guess, even in shorter than 300ms period?)

Lamp control
ON   40 20 72 00 08 de 00 01 02 01 01 01 01 01 40
OFF: 40 20 72 00 08 df 00 01 02 01 01 01 01 00 40

And in addition my existing ESPHome control for the lamp

ble_client:
  - mac_address: AA:11:AA:11:AA:11
    id: rc2bed
    on_connect:
      then:
        - lambda: |-
            ESP_LOGD("ble_client_lambda", "Connected to BLE device");
    on_disconnect:
      then:
        - lambda: |-
            ESP_LOGD("ble_client_lambda", "Disconnected from BLE device");

switch:
  - platform: template
    name: "Bed verlichting"
    id: bed_verlichting
    icon: "mdi:lightbulb-outline"
    optimistic: true
    turn_on_action:
      - ble_client.ble_write:
          id: rc2bed
          service_uuid: ffe0
          characteristic_uuid: ffe1
          # List of bytes to write.
          value: [0x40, 0x20, 0x72, 0x00, 0x08, 0xde, 0x00, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40]
    turn_off_action:
      - ble_client.ble_write:
          id: rc2bed
          service_uuid: ffe0
          characteristic_uuid: ffe1
          # List of bytes to write.
          value: [0x40, 0x20, 0x72, 0x00, 0x08, 0xdf, 0x00, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x00, 0x40]
1 Like

I think the approaches you’ve suggested are reasonable (buttons, cover, while loop).

You could put the up/down loops in scripts, as you can do a lot with scripts. Then call them from elsewhere (buttons, covers etc).

You can also do some nice single press logic with buttons. Like…
On press…
If stationary, move in the opposite direction as last time.
If moving, stop.

Thanks, this helped me. Working on scripts now to get more generic re-usable blocks.
After that I’ll check upon covering this in a ‘cover’ type (possibly not, I do not have feedback on current state) or ‘pushbutton’ type.
I do plan to have one button to set the bed to my preferences (based flat base position)

Hi Peter,I also own a Octo bed controller. Is there an easy way to get the MAC address of the unit?

Hello Bouke,
Are you on Android? You can use for example the “BLE Scanner (Connect & Notify)” app by “Bluepixel technologies”. (no affiliate)
and… welcome to HA community!

Thanks for the quick reply and warm welcome! I’m on iOS, but the app is available on iOS as well. Problem is the many many devices it is discovering and the ones nearby won’t connect. Is it simply waiting for the right advertisement or did you do something else (like connecting in the app)?

Yes only waiting for the device to show-up with name “RC2”, You’ll probably see 2 (left/right side of bed).
Testing or powering of 1 of the 2 will help determining which is for left/right side of bed.
Connecting in this app is not required to retrieve the MAC address (format xx:xx:xx:xx:xx:xx).

Thank you very much. I’ try to be patient.

Should anyone ever see this post, here are te codes for the Octo remote star2. This is the system shown in the screenshot.

service_uuid: aa5c
characteristic_uuid: 5a55

Head up: 0x68, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x36, 0x31, 0x38, 0x16
Head down: 0x68, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x39, 0x31, 0x3b, 0x16
Feet up: 0x68, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x34, 0x31, 0x36, 0x16
Feet down: 0x68, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x37, 0x31, 0x39, 0x16
Both up: 0x68, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x32, 0x37, 0x31, 0x3b, 0x16
Both down: 0x68, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x32, 0x38, 0x31, 0x3c, 0x16

ESPHome code:

esp32_ble_tracker:
  on_ble_advertise:
    - mac_address:
        - 11:22:33:44:55:66
      then:
        - lambda: |-
            ESP_LOGD("ble_adv", "New BLE device");
            ESP_LOGD("ble_adv", "  address: %s", x.address_str().c_str());
            ESP_LOGD("ble_adv", "  name: %s", x.get_name().c_str());
            ESP_LOGD("ble_adv", "  Advertised service UUIDs:");
            for (auto uuid : x.get_service_uuids()) {
                ESP_LOGD("ble_adv", "    - %s", uuid.to_string().c_str());
            }
            ESP_LOGD("ble_adv", "  Advertised service data:");
            for (auto data : x.get_service_datas()) {
                ESP_LOGD("ble_adv", "    - %s: (length %i)", data.uuid.to_string().c_str(), data.data.size());
            }
            ESP_LOGD("ble_adv", "  Advertised manufacturer data:");
            for (auto data : x.get_manufacturer_datas()) {
                ESP_LOGD("ble_adv", "    - %s: (length %i)", data.uuid.to_string().c_str(), data.data.size());
            }

ble_client:
  - mac_address: 11:22:33:44:55:66
    id: bed
    on_connect:
      then:
        - lambda: |-
            ESP_LOGD("ble_client_lambda", "Connected to BLE device");
    on_disconnect:
      then:
        - lambda: |-
            ESP_LOGD("ble_client_lambda", "Disconnected from BLE device");

button:
  - platform: template
    name: "Head up"
    id: head_up
    icon: "mdi:bed"
    on_press:
      - ble_client.ble_write:
          id: bed
          service_uuid: aa5c
          characteristic_uuid: 5a55
          value: [0x68, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x36, 0x31, 0x38, 0x16]

  - platform: template
    name: "Head down"
    id: head_down
    icon: "mdi:bed"
    on_press:
      - ble_client.ble_write:
          id: bed
          service_uuid: aa5c
          characteristic_uuid: 5a55
          value: [0x68, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x39, 0x31, 0x3b, 0x16]

  - platform: template
    name: "Feet up"
    id: feet_up
    icon: "mdi:bed"
    on_press:
      - ble_client.ble_write:
          id: bed
          service_uuid: aa5c
          characteristic_uuid: 5a55
          value: [0x68, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x34, 0x31, 0x36, 0x16]

  - platform: template
    name: "Feet down"
    id: feet_down
    icon: "mdi:bed"
    on_press:
      - ble_client.ble_write:
          id: bed
          service_uuid: aa5c
          characteristic_uuid: 5a55
          value: [0x68, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x37, 0x31, 0x39, 0x16]

  - platform: template
    name: "Both up"
    id: both_up
    icon: "mdi:bed"
    on_press:
      - ble_client.ble_write:
          id: bed
          service_uuid: aa5c
          characteristic_uuid: 5a55
          value: [0x68, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x32, 0x37, 0x31, 0x3b, 0x16]

  - platform: template
    name: "Both down"
    id: both_down
    icon: "mdi:bed"
    on_press:
      - ble_client.ble_write:
          id: bed
          service_uuid: aa5c
          characteristic_uuid: 5a55
          value: [0x68, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x32, 0x38, 0x31, 0x3c, 0x16]
2 Likes

Nice result!! :+1:t2:

Hi :slight_smile: im trying to control my Linak motorized bed . I have the values to control it but the stupid thing is that I need to press release the button in ha multiple times to get the bed up or down - one press just execute a short move :frowning: is it the same with yours ?

Yes it works the same for me, I use the repeat function Automations and Templates — ESPHome

And in that way repeat the command as long as needed

can you show me your code? Another guy have counted the commands for the bed to reach all the way to the top and back to the bottom. From flat to top requires 58 commands, and to bottom 68 commands. BUT - esphome crashes when setting so many counts. How many repeats do you use for your settings?

This is part of my code, I repeat with a delay between commands (I measured this delay from the logging of the original remote inside the wireshark logging)

      - repeat:
          count: 100
          then:
            - ble_client.ble_write:
                id: rc2bedpeter
                service_uuid: ffe0
                characteristic_uuid: ffe1
                # List of bytes to write.
                value: [0x40, 0x02, 0x70, 0x00, 0x01, 0x0b, 0x02, 0x40]
            - delay: 300ms
            - logger.log: "repeat head UP"

Nice - could you paste your whole code here?

esp32_ble_tracker:
  scan_parameters:
    duration: 30s
#  on_ble_advertise:
#    - mac_address: ED:9B:FD:1E:12:86
#      then:
#        - lambda: |-
#            ESP_LOGD("ble_adv", "New BLE device");
#            ESP_LOGD("ble_adv", "  address: %s", x.address_str().c_str());
#            ESP_LOGD("ble_adv", "  name: %s", x.get_name().c_str());
#            ESP_LOGD("ble_adv", "  Advertised service UUIDs:");
#            for (auto uuid : x.get_service_uuids()) {
#                ESP_LOGD("ble_adv", "    - %s", uuid.to_string().c_str());
#            }
#            ESP_LOGD("ble_adv", "  Advertised service data:");
#            for (auto data : x.get_service_datas()) {
#                ESP_LOGD("ble_adv", "    - %s: (length %i)", data.uuid.to_string().c_str(), data.data.size());
#            }
#            ESP_LOGD("ble_adv", "  Advertised manufacturer data:");
#            for (auto data : x.get_manufacturer_datas()) {
#                ESP_LOGD("ble_adv", "    - %s: (length %i)", data.uuid.to_string().c_str(), data.data.size());
#            }
#  on_ble_manufacturer_data_advertise:
#    - mac_address: ED:9B:FD:1E:12:86
#      manufacturer_id: 0590
#      then:
#        - lambda: |-
#            if (x[0] != 0x7b || x[1] != 0x61) return;
#            int value = x[2] + (x[3] << 8);
#            id(ble_sensor).publish_state(value);
#  on_ble_service_data_advertise:
#    - mac_address: 11:22:33:44:55:66
#      service_uuid: 181A
#      then:
#        - lambda: 'id(ble_sensor).publish_state(x[0]);'
#  on_scan_end:
#    - then:
#        - lambda: |-
#             ESP_LOGD("ble_auto", "The scan has ended!");
#
#sensor:
#  - platform: template
#    name: "BLE Sensor"
#    id: ble_sensor

binary_sensor:
  - platform: template
    name: "Bed remote connection status"
    id: bed_remote_connection_status

ble_client:
  - mac_address: ED:9B:FD:1E:12:86
    id: rc2bedpeter
    on_connect:
      then:
        - lambda: |-
            ESP_LOGD("ble_client_lambda", "Connected to BLE device");
        - binary_sensor.template.publish:
            id: bed_remote_connection_status
            state: True
    on_disconnect:
      then:
        - lambda: |-
            ESP_LOGD("ble_client_lambda", "Disconnected from BLE device");
        - binary_sensor.template.publish:
            id: bed_remote_connection_status
            state: False

switch:
  - platform: template
    name: "Bed verlichting Peter"
    id: bed_verlichting_peter
    icon: "mdi:lightbulb-outline"
    optimistic: true
    turn_on_action:
      - ble_client.ble_write:
          id: rc2bedpeter
          service_uuid: ffe0
          characteristic_uuid: ffe1
          # List of bytes to write.
          value: [0x40, 0x20, 0x72, 0x00, 0x08, 0xde, 0x00, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40]
    turn_off_action:
      - ble_client.ble_write:
          id: rc2bedpeter
          service_uuid: ffe0
          characteristic_uuid: ffe1
          # List of bytes to write.
          value: [0x40, 0x20, 0x72, 0x00, 0x08, 0xdf, 0x00, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x00, 0x40]

button:
  - platform: template
    name: "Bed Peter head up"
    icon: "mdi:bed"
    on_press:
      # Calling a script with parameters
      - script.execute:
          id: control_bed
          section: 1 #head
          direction: 1 #up
  - platform: template
    name: "Bed Peter head down"
    icon: "mdi:bed"
    on_press:
      # Calling a script with parameters
      - script.execute:
          id: control_bed
          section: 1 #head
          direction: 0 #down
  - platform: template
    name: "Bed Peter head/feet up"
    icon: "mdi:bed"
    on_press:
      - ble_client.ble_write:
          id: rc2bedpeter
          service_uuid: ffe0
          characteristic_uuid: ffe1
          # List of bytes to write.
          value: [0x40, 0x02, 0x70, 0x00, 0x01, 0x07, 0x06, 0x40]
  - platform: template
    name: "Bed Peter head/feet down"
    icon: "mdi:bed"
    on_press:
      - ble_client.ble_write:
          id: rc2bedpeter
          service_uuid: ffe0
          characteristic_uuid: ffe1
          # List of bytes to write.
          value: [0x40, 0x02, 0x71, 0x00, 0x01, 0x06, 0x06, 0x40]
  - platform: template
    name: "Bed Peter feet up"
    icon: "mdi:bed"
    on_press:
      - ble_client.ble_write:
          id: rc2bedpeter
          service_uuid: ffe0
          characteristic_uuid: ffe1
          # List of bytes to write.
          value: [0x40, 0x02, 0x70, 0x00, 0x01, 0x09, 0x04, 0x40]
  - platform: template
    name: "Bed Peter feet down"
    icon: "mdi:bed"
    on_press:
      - ble_client.ble_write:
          id: rc2bedpeter
          service_uuid: ffe0
          characteristic_uuid: ffe1
          # List of bytes to write.
          value: [0x40, 0x02, 0x71, 0x00, 0x01, 0x08, 0x04, 0x40]
  - platform: template
    name: "Bed Peter end move"
    id: bed_peter_end_move
    icon: "mdi:stop-circle-outline"
    on_press:
      - ble_client.ble_write:
          id: rc2bedpeter
          service_uuid: ffe0
          characteristic_uuid: ffe1
          # List of bytes to write.
          value: [0x40, 0x02, 0x73, 0x00, 0x00, 0x0b, 0x40]

script:
  - id: control_bed
    mode: restart #Makes sure only 1 execution in parallel and running is cancelled # IMPROVEIMPROVEIMPROVE SENT THE COMMAND VALUE AS PARAMETER! check wat het verwachte type is en wat ik voor type als parameter mee kan sturen
    parameters:
      section: int #1 head, 2 feet, 3 both
      direction: int # 1 up, 0 down
      #percentage? voor later
    then:
      - ble_client.ble_write: #send stop command
          id: rc2bedpeter
          service_uuid: ffe0
          characteristic_uuid: ffe1
          # List of bytes to write.
          value: [0x40, 0x02, 0x73, 0x00, 0x00, 0x0b, 0x40]
      # Check what task to perform
      - lambda: |-
          switch (section) {
            case 1: if (direction == 1) { 
              id(control_bed_head_up).execute();
              return;
            } else {
              id(control_bed_head_down).execute();
              return;
            };
            case 2: if (direction == 1){ 
              id(control_bed_feet_up).execute();
              return;
            } else {
              id(control_bed_feet_down).execute();
              return;
            };
            case 3: if (direction == 1){ 
              id(control_bed_both_up).execute();
              return;
            } else {
              id(control_bed_both_down).execute();
              return;
            };
            default: {      
              id(control_bed_stop_cmd).execute();
              return;
            }
          }
  - id: control_bed_head_up
    mode: restart #Makes sure only 1 execution in parallel and running is cancelled
    then:
      - repeat:
          count: 100
          then:
            - ble_client.ble_write:
                id: rc2bedpeter
                service_uuid: ffe0
                characteristic_uuid: ffe1
                # List of bytes to write.
                value: [0x40, 0x02, 0x70, 0x00, 0x01, 0x0b, 0x02, 0x40]
            - delay: 300ms
            - logger.log: "repeat head UP"
  - id: control_bed_head_down
    mode: restart #Makes sure only 1 execution in parallel and running is cancelled
    then:
      - repeat:
          count: 100
          then:
            - ble_client.ble_write:
                id: rc2bedpeter
                service_uuid: ffe0
                characteristic_uuid: ffe1
                # List of bytes to write.
                value: [0x40, 0x02, 0x71, 0x00, 0x01, 0x0a, 0x02, 0x40]
            - delay: 300ms
            - logger.log: "repeat head DOWN"
  - id: control_bed_feet_up
    mode: restart #Makes sure only 1 execution in parallel and running is cancelled
    then:
      - repeat:
          count: 100
          then:
            - ble_client.ble_write:
                id: rc2bedpeter
                service_uuid: ffe0
                characteristic_uuid: ffe1
                # List of bytes to write.
                value: [0x40, 0x02, 0x70, 0x00, 0x01, 0x09, 0x04, 0x40]
            - delay: 300ms
            - logger.log: "repeat feet up"
  - id: control_bed_feet_down
    mode: restart #Makes sure only 1 execution in parallel and running is cancelled
    then:
      - repeat:
          count: 100
          then:
            - ble_client.ble_write:
                id: rc2bedpeter
                service_uuid: ffe0
                characteristic_uuid: ffe1
                # List of bytes to write.
                value: [0x40, 0x02, 0x71, 0x00, 0x01, 0x08, 0x04, 0x40]
            - delay: 300ms
            - logger.log: "repeat feet down"
  - id: control_bed_both_up
    mode: restart #Makes sure only 1 execution in parallel and running is cancelled
    then:
      - repeat:
          count: 100
          then:
            - ble_client.ble_write:
                id: rc2bedpeter
                service_uuid: ffe0
                characteristic_uuid: ffe1
                # List of bytes to write.
                value: [0x40, 0x02, 0x70, 0x00, 0x01, 0x07, 0x06, 0x40]
            - delay: 300ms
            - logger.log: "repeat both up"
  - id: control_bed_both_down
    mode: restart #Makes sure only 1 execution in parallel and running is cancelled
    then:
      - repeat:
          count: 100
          then:
            - ble_client.ble_write:
                id: rc2bedpeter
                service_uuid: ffe0
                characteristic_uuid: ffe1
                # List of bytes to write.
                value: [0x40, 0x02, 0x71, 0x00, 0x01, 0x06, 0x06, 0x40]
            - delay: 300ms
            - logger.log: "repeat both down"
  - id: control_bed_stop_cmd
    mode: restart #Makes sure only 1 execution in parallel and running is cancelled
    then:
      - ble_client.ble_write:
          id: rc2bedpeter
          service_uuid: ffe0
          characteristic_uuid: ffe1
          # List of bytes to write.
          value: [0x40, 0x02, 0x73, 0x00, 0x00, 0x0b, 0x40]

Cool - thanks:) For your inspiration here is my code using a cover component instead.

substitutions:
  device_name: 'linak-jacob-seng'
  friendly_name: 'Jacob Seng'
  device_description: "Bluetooth kontrol af elevationsseng"
  project_version: "1.0.0"
  log_level: DEBUG
  mac_address: "D2:3E:FE:30:27:F9" ## Change this to your beds unique mac-addresse 

packages:
  device_base: !include common/base.yaml

esphome:
  name: ${device_name}
  friendly_name: ${friendly_name}

esp32:
  board: esp32dev
  framework:
    type: esp-idf 

globals:
  # To store the Linak Bed Connection Status
  - id: ble_client_connected
    type: bool
    initial_value: 'false'

esp32_ble_tracker:

ble_client:
  - mac_address: ${mac_address}
    id: seng_1
    on_connect:
      then:
        # Update the Linak Bed Connection Status
        - lambda: |-
            id(ble_client_connected) = true;
            ESP_LOGD("ble_client_lambda", "${friendly_name}");
        - delay: 5s
       # Update Linak Bed height sensors after bluetooth is connected
        - lambda: |-
            id(jacob_head_height).update();
            id(jacob_feet_height).update();             
    on_disconnect:
      then:
        - lambda: |-
            id(ble_client_connected) = false;
            ESP_LOGD("ble_client_lambda", "${friendly_name}");     
        
binary_sensor:
  # Presence based on MAC address
  - platform: ble_presence
    mac_address: ${mac_address}
    name: "${friendly_name} BLE Status"

  # Bed Bluetooth Connection Status
  - platform: template
    name: '${friendly_name} Connection'
    id: desk_connection
    lambda: 'return id(ble_client_connected);'    

sensor:
  # RSSI based on MAC address
  - platform: ble_rssi
    mac_address: ${mac_address} 
    name: "${friendly_name} BLE RSSI" 

  # Jacob Head Height Sensor
  - platform: ble_client
    type: characteristic
    ble_client_id: seng_1
    id: jacob_head_height
    name: '${friendly_name} hoved højde'
    service_uuid: '99fa0020-338a-1024-8a49-009c0215f78a'
    characteristic_uuid: '99fa0028-338a-1024-8a49-009c0215f78a'
    icon: 'mdi:arrow-up-down'
    unit_of_measurement: 'cm'
    accuracy_decimals: 1
    update_interval: never
    notify: true
    lambda: |-
      uint16_t raw_height = ((uint16_t)x[1] << 8) | x[0];
      unsigned short height_mm = raw_height /5;
 
      return (float) height_mm /5;
 
  # Jacob Feet Height Sensor
  - platform: ble_client
    type: characteristic
    ble_client_id: seng_1
    id: jacob_feet_height
    name: '${friendly_name} fod højde'
    service_uuid: '99fa0020-338a-1024-8a49-009c0215f78a'
    characteristic_uuid: '99fa0027-338a-1024-8a49-009c0215f78a'
    icon: 'mdi:arrow-up-down'
    unit_of_measurement: 'cm'
    accuracy_decimals: 1
    update_interval: never
    notify: true
    lambda: |-
      uint16_t raw_height = ((uint16_t)x[1] << 8) | x[0];
      unsigned short height_mm = raw_height / 6;
 
      return (float) height_mm / 5;  

  # Desk Speed Sensor
  - platform: ble_client
    type: characteristic
    ble_client_id: seng_1
    id: bed_speed
    name: 'Jacob seng Speed'
    service_uuid: '99fa0020-338a-1024-8a49-009c0215f78a'
    characteristic_uuid: '99fa0028-338a-1024-8a49-009c0215f78a'
    icon: 'mdi:speedometer'
    unit_of_measurement: 'cm/min' # I'm not sure this unit is correct
    accuracy_decimals: 0
    update_interval: never
    notify: true
    lambda: |-
      uint16_t raw_speed = ((uint16_t)x[3] << 8) | x[2];
      return raw_speed / 100;


### Lys under seng ####

switch:
  - platform: template
    name: "${friendly_name} Lys"
    id: light_bed
    optimistic: true
    turn_on_action: 
    - delay: 1s  
    - ble_client.ble_write:
        id: seng_1
        service_uuid: 99fa0001-338a-1024-8a49-009c0215f78a
        characteristic_uuid: 99fa0002-338a-1024-8a49-009c0215f78a
        value: [0x92, 0x00]
    turn_off_action: 
    - delay: 1s  
    - ble_client.ble_write:
        id: seng_1
        service_uuid: 99fa0001-338a-1024-8a49-009c0215f78a
        characteristic_uuid: 99fa0002-338a-1024-8a49-009c0215f78a
        value: [0x93, 0x00] 

### Lys under seng #### 

  - platform: ble_client
    ble_client_id: seng_1
    name: "${friendly_name} BLE" 

cover:

### Hoved + ben 

  - platform: template
    name: "${friendly_name} Both"
    id: both_actuators
    assumed_state: true
    icon: "mdi:bed"
    open_action:
      - script.execute: jacob_op
      - logger.log: "Repeat both actuators UP"
    stop_action:
      - script.execute: jacob_stop
      - logger.log: "Action stopped"     
    close_action:
      - script.execute: jacob_ned
      - logger.log: "Repeat both actuators DOWN"

### Hoved  

  - platform: template
    name: "${friendly_name} Head"
    id: head_actuator
    assumed_state: true
    icon: "mdi:bed"
    open_action:
      - script.execute: jacob_hoved_op
      - logger.log: "Repeat head actuator UP"
    stop_action:
      - script.execute: jacob_stop
      - logger.log: "Action stopped"      
    close_action:
      - script.execute: jacob_hoved_ned
      - logger.log: "Repeat head actuator DOWN"    

### Ben 

  - platform: template
    name: "${friendly_name} Legs"
    id: leg_actuator
    assumed_state: true
    icon: "mdi:bed"
    open_action:
      - script.execute: jacob_ben_op
      - logger.log: "Repeat legs actuator UP"
    stop_action:
      - script.execute: jacob_stop
      - logger.log: "Action stopped"      
    close_action:
      - script.execute: jacob_ben_ned
      - logger.log: "Repeat leg actuator DOWN"      
                                                            

button:

### Presets mv.   

  - platform: template
    name: "${friendly_name} Store Preset 1"
    id: store_preset_1
    icon: "mdi:file-account"
    on_press:
      then:
        - ble_client.ble_write:
            id: seng_1
            service_uuid: 99fa0001-338a-1024-8a49-009c0215f78a
            characteristic_uuid: 99fa0002-338a-1024-8a49-009c0215f78a
            value: [0x38, 0x00] 
        - logger.log: "Preset 1 Saved"             

  - platform: template
    name: "${friendly_name} Store Preset 2"
    id: store_preset_2
    icon: "mdi:file-account"
    on_press:
      then:
        - ble_client.ble_write:
            id: seng_1
            service_uuid: 99fa0001-338a-1024-8a49-009c0215f78a
            characteristic_uuid: 99fa0002-338a-1024-8a49-009c0215f78a
            value: [0x39, 0x00]
        - logger.log: "Preset 2 Saved"              

  - platform: template
    name: "${friendly_name} Store Preset 3"
    id: store_preset_3
    icon: "mdi:file-account"
    on_press:
      then:
        - ble_client.ble_write:
            id: seng_1
            service_uuid: 99fa0001-338a-1024-8a49-009c0215f78a
            characteristic_uuid: 99fa0002-338a-1024-8a49-009c0215f78a
            value: [0x3A, 0x00] 
        - logger.log: "Preset 3 Saved"      

  - platform: template
    name: "${friendly_name} Store Preset 4"
    id: store_preset_4
    icon: "mdi:file-account"
    on_press:
      then:
        - ble_client.ble_write:
            id: seng_1
            service_uuid: 99fa0001-338a-1024-8a49-009c0215f78a
            characteristic_uuid: 99fa0002-338a-1024-8a49-009c0215f78a
            value: [0x45, 0x00] 
        - logger.log: "Preset 4 Saved"                  

  - platform: template
    name: "${friendly_name} Run Preset 1"
    id: preset_1
    icon: "mdi:head-question-outline"
    on_press:
      - repeat:
          count: 100
          then:
            - ble_client.ble_write:
                id: seng_1
                service_uuid: 99fa0001-338a-1024-8a49-009c0215f78a
                characteristic_uuid: 99fa0002-338a-1024-8a49-009c0215f78a
                value: [0x0E, 0x00] 
            - delay: 300ms
            - logger.log: "Run preset 1"     

  - platform: template
    name: "${friendly_name} Run Preset 2"
    id: preset_2
    icon: "mdi:head-question-outline"
    on_press:
      - repeat:
          count: 100
          then:
            - ble_client.ble_write:
                id: seng_1
                service_uuid: 99fa0001-338a-1024-8a49-009c0215f78a
                characteristic_uuid: 99fa0002-338a-1024-8a49-009c0215f78a
                value: [0x0F, 0x00] 
            - delay: 300ms
            - logger.log: "Run preset 2"

  - platform: template
    name: "${friendly_name} Run Preset 3"
    id: preset_3
    icon: "mdi:head-question-outline"
    on_press:
      - repeat:
          count: 100
          then:
            - ble_client.ble_write:
                id: seng_1
                service_uuid: 99fa0001-338a-1024-8a49-009c0215f78a
                characteristic_uuid: 99fa0002-338a-1024-8a49-009c0215f78a
                value: [0x0C, 0x00] 
            - delay: 300ms
            - logger.log: "Run preset 3" 

  - platform: template
    name: "${friendly_name} Run Preset 4"
    id: preset_4
    icon: "mdi:head-question-outline"
    on_press:
      - repeat:
          count: 100
          then:
            - ble_client.ble_write:
                id: seng_1
                service_uuid: 99fa0001-338a-1024-8a49-009c0215f78a
                characteristic_uuid: 99fa0002-338a-1024-8a49-009c0215f78a
                value: [0x44, 0x00] 
            - delay: 300ms
            - logger.log: "Run preset 4" 

script:
  # Turn Head up and down (standalone)
  - id: jacob_hoved_op
    then:
      - ble_client.ble_write:
          id: seng_1
          service_uuid: 99fa0001-338a-1024-8a49-009c0215f78a
          characteristic_uuid: 99fa0002-338a-1024-8a49-009c0215f78a
          value: [0x0b, 0x00]
      - delay: 0.05s  

  - id: jacob_hoved_ned
    then:
      - ble_client.ble_write:
          id: seng_1
          service_uuid: 99fa0001-338a-1024-8a49-009c0215f78a
          characteristic_uuid: 99fa0002-338a-1024-8a49-009c0215f78a
          value: [0x0a, 0x00]
      - delay: 0.05s    

  # Turn legs up and down (standalone)
  - id: jacob_ben_op
    then:
      - ble_client.ble_write:
          id: seng_1
          service_uuid: 99fa0001-338a-1024-8a49-009c0215f78a
          characteristic_uuid: 99fa0002-338a-1024-8a49-009c0215f78a
          value: [0x09, 0x00]
      - delay: 0.05s  

  - id: jacob_ben_ned
    then:
      - ble_client.ble_write:
          id: seng_1
          service_uuid: 99fa0001-338a-1024-8a49-009c0215f78a
          characteristic_uuid: 99fa0002-338a-1024-8a49-009c0215f78a
          value: [0x08, 0x00]
      - delay: 0.05s

  # Turn legs and head up and down (both actuators)
  - id: jacob_op
    then:
      - ble_client.ble_write:
          id: seng_1
          service_uuid: 99fa0001-338a-1024-8a49-009c0215f78a
          characteristic_uuid: 99fa0002-338a-1024-8a49-009c0215f78a
          value: [0x01, 0x00]
      - delay: 0.05s  

  - id: jacob_ned
    then:
      - ble_client.ble_write:
          id: seng_1
          service_uuid: 99fa0001-338a-1024-8a49-009c0215f78a
          characteristic_uuid: 99fa0002-338a-1024-8a49-009c0215f78a
          value: [0x00, 0x00]
      - delay: 0.05s            
                 
  # Stop movement
  - id: jacob_stop
    then:
      - ble_client.ble_write:
          id: seng_1
          service_uuid: 99fa0001-338a-1024-8a49-009c0215f78a
          characteristic_uuid: 99fa0002-338a-1024-8a49-009c0215f78a
          value: [0xFF, 0x00] 
      - delay: 0.05s  

       



1 Like

In my case I mounted gyro’s on the head and foot of the bed that report back the angle. I created a button for each end of the bed (head up, head down, feet up and feet down). The command is repeated until a switch is pressed which breaks the loop. The switch is pressed by an automation that monitors the degrees. That way with a number slider I can set the angle of both the head and feet.

Some code snippets:
Buttons:

button:
  - platform: template
    name: "Head up"
    id: head up
    icon: "mdi:bed"
    on_press:
      while:
        condition:
          switch.is_off: head_stop
        then:
          - ble_client.ble_write: 
              id: bed
              service_uuid: aa5c
              characteristic_uuid: 5a55
              value: [0x68, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x36, 0x31, 0x38, 0x16]
          - delay: 200ms

Switch:

switch:
  - platform: template
    name: "Head stop"
    id: head_stop
    icon: mdi:close-octagon
    optimistic: true
    on_turn_on:
      then:
        - delay: 1s
        - switch.turn_off: head_stop

Wow nice setup, which gyro are you using? Do you plan to use a cover setup with these?

I use the MPU-6050 gyros on a separate ESP for monitoring the angle. It is a double bed, so 4 gyros in total. With pressure mats is detected if someone is in the bed and when the tv is switched on, the bed that has someone in it automatically goes up to a preset angle. When the second person gets into bed, the pressure mat detects it and that bed goes up as well. When the tv is switched off, the beds go down automatically. So there is manual control and a preset angle. Voice control is also possible with a scene in HomeKit.

What do you mean with a cover setup?