Aqara Magic Cube ZHA (51 actions)

Blueprint to support the Xiaomi Cube Controller using ZHA.
Thanks to @bergstrom for this inspiration.

All has been tested.

Supported actions

  • Slide
  • Knock
  • Flip 90 degress
  • Flip 180 degress
  • Shake
  • Drop
  • Wake
  • Rotate clockwise
  • Rotate counter-clockwise

Blueprint

Click the badge to import this Blueprint: (needs Home Assistant Core 2021.3 or higher)

Open your Home Assistant instance and show the blueprint import dialog with a specific blueprint pre-filled.

blueprint:

  name: Aqara Magic Cube

  description: Control anything using Aqara Magic Cube.

  domain: automation

  input:

    remote:

      name: Magic Cube

      description: Select the Aqara Magic Cube device

      selector:

        device:

          integration: zha

          manufacturer: LUMI

    flip_90:

      name: Flip 90 degrees

      description: Actions to run when cube flips 90 degrees.

        This cancels all specific 90 degrees functions.

        e.g From side 1 to side 2 will be the same as from side 6 to side 2

      default: false

      selector:

        boolean: {}

    cube_flip_90:

      name: Flip cube 90 degrees

      description: Action to run when cube flips 90 degrees. This only works if 'Flip 90 degrees' is toggled

      default: []

      selector:

        action: {}

    flip_180:

      name: Flip 180 degrees

      description: Actions to run when cube flips 180 degrees.

        This cancels all specific 180 degrees functions

        e.g From side 1 to side 4 will be the same as from side 5 to side 2

      default: false

      selector:

        boolean: {}

    cube_flip_180:

      name: Flip cube 180 degrees

      description: Action to run when cube flips 180 degrees. This only works if 'Flip 180 degrees' is toggled

      default: []

      selector:

        action: {}

    slide_any_side:

      name: Slide any side

      description: Actions to run when cube slides on any side.

        This cancels all specific 'slide' functions

        e.g Slide on side 1 will be the same as slide on side 2

      default: false

      selector:

        boolean: {}

    cube_slide_any:

      name: Slide cube on any side

      description: Action to run when cube slides on any slide. This only works if 'Slide any side' is toggled

      default: []

      selector:

        action: {}

    knock_any_side:

      name: Knock on any side

      description: Actions to run when knocking cube regardless of the side.

        This cancels all specific 'knock' functions

        e.g Knock on side 1 will be the same as knocking side 2

      default: false

      selector:

        boolean: {}

    cube_knock_any:

      name: Knock cube on any side

      description: Action to run when knocking cube on any side. This only works if 'Knock on any side' is toggled

      default: []

      selector:

        action: {}

    one_to_two:

      name: From side 1 to side 2

      description: Action to run when cube goes from side 1 to side 2

      default: []

      selector:

        action: {}

    one_to_three:

      name: From side 1 to side 3

      description: Action to run when cube goes from side 1 to side 3

      default: []

      selector:

        action: {}

    one_to_four:

      name: From side 1 to side 4

      description: Action to run when cube goes from side 1 to side 4

      default: []

      selector:

        action: {}

    one_to_five:

      name: From side 1 to side 5

      description: Action to run when cube goes from side 1 to side 5

      default: []

      selector:

        action: {}

    one_to_six:

      name: From side 1 to side 6

      description: Action to run when cube goes from side 1 to side 6

      default: []

      selector:

        action: {}

    two_to_one:

      name: From side 2 to side 1

      description: Action to run when cube goes from side 2 to side 1

      default: []

      selector:

        action: {}

    two_to_three:

      name: From side 2 to side 3

      description: Action to run when cube goes from side 2 to side 3

      default: []

      selector:

        action: {}

    two_to_four:

      name: From side 2 to side 4

      description: Action to run when cube goes from side 2 to side 4

      default: []

      selector:

        action: {}

    two_to_five:

      name: From side 2 to side 5

      description: Action to run when cube goes from side 2 to side 5

      default: []

      selector:

        action: {}

    two_to_six:

      name: From side 2 to side 6

      description: Action to run when cube goes from side 2 to side 6

      default: []

      selector:

        action: {}

    three_to_one:

      name: From side 3 to side 1

      description: Action to run when cube goes from side 3 to side 1

      default: []

      selector:

        action: {}

    three_to_two:

      name: From side 3 to side 2

      description: Action to run when cube goes from side 3 to side 2

      default: []

      selector:

        action: {}

    three_to_four:

      name: From side 3 to side 4

      description: Action to run when cube goes from side 3 to side 4

      default: []

      selector:

        action: {}

    three_to_five:

      name: From side 3 to side 5

      description: Action to run when cube goes from side 3 to side 5

      default: []

      selector:

        action: {}

    three_to_six:

      name: From side 3 to side 6

      description: Action to run when cube goes from side 3 to side 6

      default: []

      selector:

        action: {}

    four_to_one:

      name: From side 4 to side 1

      description: Action to run when cube goes from side 4 to side 1

      default: []

      selector:

        action: {}

    four_to_two:

      name: From side 4 to side 2

      description: Action to run when cube goes from side 4 to side 2

      default: []

      selector:

        action: {}

    four_to_three:

      name: From side 4 to side 3

      description: Action to run when cube goes from side 4 to side 3

      default: []

      selector:

        action: {}

    four_to_five:

      name: From side 4 to side 5

      description: Action to run when cube goes from side 4 to side 5

      default: []

      selector:

        action: {}

    four_to_six:

      name: From side 4 to side 6

      description: Action to run when cube goes from side 4 to side 6

      default: []

      selector:

        action: {}

    five_to_one:

      name: From side 5 to side 1

      description: Action to run when cube goes from side 5 to side 1

      default: []

      selector:

        action: {}

    five_to_two:

      name: From side 5 to side 2

      description: Action to run when cube goes from side 5 to side 2

      default: []

      selector:

        action: {}

    five_to_three:

      name: From side 5 to side 3

      description: Action to run when cube goes from side 5 to side 3

      default: []

      selector:

        action: {}

    five_to_four:

      name: From side 5 to side 4

      description: Action to run when cube goes from side 5 to side 4

      default: []

      selector:

        action: {}

    five_to_six:

      name: From side 5 to side 6

      description: Action to run when cube goes from side 5 to side 6

      default: []

      selector:

        action: {}

    six_to_one:

      name: From side 6 to side 1

      description: Action to run when cube goes from side 6 to side 1

      default: []

      selector:

        action: {}

    six_to_two:

      name: From side 6 to side 2

      description: Action to run when cube goes from side 6 to side 2

      default: []

      selector:

        action: {}

    six_to_three:

      name: From side 6 to side 3

      description: Action to run when cube goes from side 6 to side 3

      default: []

      selector:

        action: {}

    six_to_four:

      name: From side 6 to side 4

      description: Action to run when cube goes from side 6 to side 4

      default: []

      selector:

        action: {}

    six_to_five:

      name: From side 6 to side 5

      description: Action to run when cube goes from side 6 to side 5

      default: []

      selector:

        action: {}

    one_to_one:

      name: Knock - Side 1

      description: Action to run when knocking on side 1

      default: []

      selector:

        action: {}

    two_to_two:

      name: Knock - Side 2

      description: Action to run when knocking on side 2

      default: []

      selector:

        action: {}

    three_to_three:

      name: Knock - Side 3

      description: Action to run when knocking on side 3

      default: []

      selector:

        action: {}

    four_to_four:

      name: Knock - Side 4

      description: Action to run when knocking on side 4

      default: []

      selector:

        action: {}

    five_to_five:

      name: Knock - Side 5

      description: Action to run when knocking on side 5

      default: []

      selector:

        action: {}

    six_to_six:

      name: Knock - Side 6

      description: Action to run when knocking on side 6

      default: []

      selector:

        action: {}

    slide_on_one:

      name: Slide - Side 1 up

      description: Action to run when slides with Side 1 up

      default: []

      selector:

        action: {}

    slide_on_two:

      name: Slide - Side 2 up

      description: Action to run when slides with Side 2 up

      default: []

      selector:

        action: {}

    slide_on_three:

      name: Slide - Side 3 up

      description: Action to run when slides with Side 3 up

      default: []

      selector:

        action: {}

    slide_on_four:

      name: Slide - Side 4 up

      description: Action to run when slides with Side 4 up

      default: []

      selector:

        action: {}

    slide_on_five:

      name: Slide - Side 5 up

      description: Action to run when slides with Side 5 up

      default: []

      selector:

        action: {}

    slide_on_six:

      name: Slide - Side 6 up

      description: Action to run when slides with Side 6 up

      default: []

      selector:

        action: {}

    cube_wake:

      name: Wake up the cube

      description: Action to run when cube wakes up

      default: []

      selector:

        action: {}

    cube_drop:

      name: Cube drops

      description: Action to run when cube drops

      default: []

      selector:

        action: {}

    cube_shake:

      name: Shake cube

      description: Action to run when you shake the cube

      default: []

      selector:

        action: {}

    rotate_right:

      name: Rotate right

      description: Action to run when cube rotates right

      default: []

      selector:

        action: {}

    rotate_left:

      name: Rotate left

      description: Action to run when cube rotates left

      default: []

      selector:

        action: {}

mode: restart

max_exceeded: silent

trigger:

  - platform: event

    event_type: zha_event

    event_data:

      device_id: !input "remote"

action:

  - variables:

      command: "{{ trigger.event.data.command }}"

      value: "{{ trigger.event.data.args.value }}"

      flip_degrees: "{{ trigger.event.data.args.flip_degrees }}"

      relative_degrees: "{{ trigger.event.data.args.relative_degrees }}"

      flip_90: !input "flip_90"

      flip_180: !input "flip_180"

      slide_any_side: !input "slide_any_side"

      knock_any_side: !input "knock_any_side"

      flip90: 64

      flip180: 128

      slide: 256

      knock: 512

      shake: 0

      drop: 3

      activated_face: >

        {% if command == "slide" or command == "knock" %}

          {% if trigger.event.data.args.activated_face == 1 %} 1

          {% elif trigger.event.data.args.activated_face == 2 %} 5

          {% elif trigger.event.data.args.activated_face == 3 %} 6

          {% elif trigger.event.data.args.activated_face == 4 %} 4

          {% elif trigger.event.data.args.activated_face == 5 %} 2

          {% elif trigger.event.data.args.activated_face == 6 %} 3

          {% endif %}

        {% elif command == 'flip' %}

          {{ trigger.event.data.args.activated_face | int }}

        {% endif %}

      from_face: >

        {% if command == "flip" and flip_degrees == 90 %}

          {{ ((value - flip90 - (trigger.event.data.args.activated_face - 1)) / 8) + 1 | int }}

        {% endif %}

  - choose:

      # ---------------------------- Rotate Right ----------------------------

      - conditions:

          - "{{ command == 'rotate_right' }}"

        sequence: !input "rotate_right"

      # ---------------------------- Rotate Left ----------------------------

      - conditions:

          - "{{ command ==  'rotate_left' }}"

        sequence: !input "rotate_left"

      # ---------------------------- Wake ----------------------------

      - conditions:

          - "{{ command == 'checkin' }}"

        sequence: !input "cube_wake"

      # ---------------------------- Shake ----------------------------

      - conditions:

          - "{{ value == shake }}"

        sequence: !input "cube_shake"

      # ---------------------------- Drop ----------------------------

      - conditions:

          - "{{ value == drop }}"

        sequence: !input "cube_drop"

      # ---------------------------- Knock any side ----------------------------

      - conditions:

          - "{{ command == 'knock' and knock_any_side }}"

        sequence: !input "cube_knock_any"

      # ---------------------------- Slide any side ----------------------------

      - conditions:

          - "{{ command == 'slide' and slide_any_side }}"

        sequence: !input "cube_slide_any"

      # ---------------------------- Flip 90 to any side ----------------------------

      - conditions:

          - "{{ flip_degrees == 90 and flip_90 }}"

        sequence: !input "cube_flip_90"

      # ---------------------------- Flip 180 to any side ----------------------------

      - conditions:

          - "{{ flip_degrees == 180 and flip_180 }}"

        sequence: !input "cube_flip_180"

      # ---------------------------- Flip 90 to side 1 ----------------------------

      - conditions:

          - "{{ flip_degrees == 90 and activated_face == 1 }}"

        sequence:

          - choose:

              - conditions: "{{ from_face == 2 }}"

                sequence: !input "two_to_one"

              - conditions: "{{ from_face == 3 }}"

                sequence: !input "three_to_one"

              - conditions: "{{ from_face == 5 }}"

                sequence: !input "five_to_one"

              - conditions: "{{ from_face == 6 }}"

                sequence: !input "six_to_one"

      # ---------------------------- Flip 90 to side 2 ----------------------------

      - conditions:

          - "{{ flip_degrees == 90 and activated_face == 2 }}"

        sequence:

          - choose:

              - conditions: "{{ from_face == 1 }}"

                sequence: !input "one_to_two"

              - conditions: "{{ from_face == 3 }}"

                sequence: !input "three_to_two"

              - conditions: "{{ from_face == 4 }}"

                sequence: !input "four_to_two"

              - conditions: "{{ from_face == 6 }}"

                sequence: !input "six_to_two"

      # ---------------------------- Flip 90 to side 3 ----------------------------

      - conditions:

          - "{{ flip_degrees == 90 and activated_face == 3 }}"

        sequence:

          - choose:

              - conditions: "{{ from_face == 1 }}"

                sequence: !input "one_to_three"

              - conditions: "{{ from_face == 2 }}"

                sequence: !input "two_to_three"

              - conditions: "{{ from_face == 4 }}"

                sequence: !input "four_to_three"

              - conditions: "{{ from_face == 5 }}"

                sequence: !input "five_to_three"

      # ---------------------------- Flip 90 to side 4 ----------------------------

      - conditions:

          - "{{ flip_degrees == 90 and activated_face == 4 }}"

        sequence:

          - choose:

              - conditions: "{{ from_face == 2 }}"

                sequence: !input "two_to_four"

              - conditions: "{{ from_face == 3 }}"

                sequence: !input "three_to_four"

              - conditions: "{{ from_face == 5 }}"

                sequence: !input "five_to_four"

              - conditions: "{{ from_face == 6 }}"

                sequence: !input "six_to_four"

      # ---------------------------- Flip 90 to side 5 ----------------------------

      - conditions:

          - "{{ flip_degrees == 90 and activated_face == 5 }}"

        sequence:

          - choose:

              - conditions: "{{ from_face == 1 }}"

                sequence: !input "one_to_five"

              - conditions: "{{ from_face == 3 }}"

                sequence: !input "three_to_five"

              - conditions: "{{ from_face == 4 }}"

                sequence: !input "four_to_five"

              - conditions: "{{ from_face == 6 }}"

                sequence: !input "six_to_five"

      # ---------------------------- Flip 90 to side 6 ----------------------------

      - conditions:

          - "{{ flip_degrees == 90 and activated_face == 6 }}"

        sequence:

          - choose:

              - conditions: "{{ from_face == 1 }}"

                sequence: !input "one_to_six"

              - conditions: "{{ from_face == 2 }}"

                sequence: !input "two_to_six"

              - conditions: "{{ from_face == 4 }}"

                sequence: !input "four_to_six"

              - conditions: "{{ from_face == 5 }}"

                sequence: !input "five_to_six"

      # ---------------------------- Flip 180 to side x ----------------------------

      - conditions:

          - "{{ value == flip180 + activated_face - 1 }}"

        sequence:

          - choose:

              - conditions: "{{ activated_face == 1 }}"

                sequence: !input "four_to_one"

              - conditions: "{{ activated_face == 2 }}"

                sequence: !input "five_to_two"

              - conditions: "{{ activated_face == 3 }}"

                sequence: !input "six_to_three"

              - conditions: "{{ activated_face == 4 }}"

                sequence: !input "one_to_four"

              - conditions: "{{ activated_face == 5 }}"

                sequence: !input "two_to_five"

              - conditions: "{{ activated_face == 6 }}"

                sequence: !input "three_to_six"

        # ---------------------------- Knock side x ----------------------------

      - conditions:

          - "{{ value == knock + activated_face - 1 }}"

        sequence:

          - choose:

              - conditions: "{{ activated_face == 1 }}"

                sequence: !input "one_to_one"

              - conditions: "{{ activated_face == 2 }}"

                sequence: !input "two_to_two"

              - conditions: "{{ activated_face == 3 }}"

                sequence: !input "three_to_three"

              - conditions: "{{ activated_face == 4 }}"

                sequence: !input "four_to_four"

              - conditions: "{{ activated_face == 5 }}"

                sequence: !input "five_to_five"

              - conditions: "{{ activated_face == 6 }}"

                sequence: !input "six_to_six"

      # ---------------------------- Slide side x ----------------------------

      - conditions:

          - "{{ value == slide + activated_face - 1 }}"

        sequence:

          - choose:

              - conditions: "{{ activated_face == 1 }}"

                sequence: !input "slide_on_one"

              - conditions: "{{ activated_face == 2 }}"

                sequence: !input "slide_on_two"

              - conditions: "{{ activated_face == 3 }}"

                sequence: !input "slide_on_three"

              - conditions: "{{ activated_face == 4 }}"

                sequence: !input "slide_on_four"

              - conditions: "{{ activated_face == 5 }}"

                sequence: !input "slide_on_five"

              - conditions: "{{ activated_face == 6 }}"

                sequence: !input "slide_on_six"
25 Likes

Looking good. Home Assistant shows no supported devices found at the blueprint page.

Is it possible to add a wildcard to detecting the model?

My model is HA is lumi.sensor_cube.aqgl01

Are you using Deconz integration? This only works with ZHA. Anyways - the name must be “lumi.sensor_cube”, without the “aqgl01”.

Br

Same here;
Device info
lumi.sensor_cube.aqgl01
by LUMI
:frowning:

1 Like

@Mr_Thomasz @Getverderrie

Hey Guys, Just edit the blueprint config and remove the model: lumi.sensor_cube Line and then save it and reload Automations then the Cube will show up :smiley:

@Mikkelmoeller Might be good to edit the model line out so others don’t have the same issue.

Thanks for the blueprint though

@Getverderrie, @Mr_Thomasz. Please try again.
Thanks to @AlexGreenUK for the comment.

Tnx! Works like a charm :slight_smile:

This is awesome, saves us a lot of work! Thank you!

Is it possible to add “from any” actions, i.e. six actions depending on which side is turned up regardless of which other side was up before?

I don’t have the time to do it, but if anyone has please do.

Thanks for the reply!

I’m pretty new to Home Assistant, but I’ll see if I can make sense of your blueprint and go from there.

Has anyone managed to get 2 cube to show up as options, as I have 2 at home one upstairs and one downstairs, but the blueprint only sees the first one that I have added?

I managed to do what I wanted thanks to your clean code. I hope my solution isn’t unnecessarily complicated.

I’m not sure what to do with it now. @Mikkelmoeller Do you want to (and have the time to) look at it (it’s on github for now) and maybe integrate it here, or should I post it as a new integration crediting you and linking here?

1 Like

I don’t quite understand: Are you trying to use both cubes in the same automation, or does the second one not show up as an option at all?

Nice, this is the most wholesome blueprint that I was able to find with the cube. Works fine for me.

1 Like

Hi, no the second cube doesn’t show up on the options to use

Oh OK, that’s weird. Mine shows both. Do they both show up as devices on the devices screen? Have you tried removing the second one and pairing again?

Hi @memorandomz ,

I imported your config but couldn’t find any differences. Maybe I am missing something. In which area is your code different from the one provided by Mikkelmoeller?

I am really happy with this blueprint, it made my Cube’s automation really easy.

If we can make the “rotate right” and “rotate left” actions to be side specific it will be really awesome.

For example with side 1 up you can dim and brighten the lights, side 2 up can control the TV volume, side 3 up can control your amplifier volume, etc.

I’ll give it a try too!

Hi @HawkMan,

I introduced this section into the blueprint:


I didn’t change any of the existing code, just added to it (well, basically copy-pasted from it).

Ooh, that sounds interesting. I don’t know if it’s possible, but it might be. Maybe I’ll play around with it a little tomorrow.

I don’t know if it is just my Cube but for the rotate right and left movements there is no zha_event about which side it is on. It just registers the rotate_right or rotate_left command and the relative degrees.

So it think it is pointless to try and assign different rotate actions according to the face the cube is on as I posted in my previous.

Can anyone else confirm the same?

My zha_event data
{
    "event_type": "zha_event",
    "data": {
        "device_ieee": "00:15:8d:00:05:cf:9a:3d",
        "unique_id": "00:15:8d:00:05:cf:9a:3d:3:0x000c",
        "device_id": "ef000d94d7b85f1c1f873315860e16af",
        "endpoint_id": 3,
        "cluster_id": 12,
        "command": "rotate_right",
        "args": {
            "relative_degrees": 11.560001373291016
        }
    },
    "origin": "LOCAL",
    "time_fired": "2021-02-06T21:30:36.181945+00:00",
    "context": {
        "id": "9dfc7cc994cae4410d2984393553bda2",
        "parent_id": null,
        "user_id": null
    }
}

Yes, same here. :frowning_face:

If you really want that functionality, you could probably define an input_number that keeps track of which side is turned up and then react to the rotate left and right events accordingly.