ControllerX. Bring full functionality to light and media player controllers

You are completely right.
This is no a good option if you had more than two lights but it’s a good alternative to manage just two.

Thank you very much for this rutine! It works great!

1 Like

Hi,
I have another problem. I’m using the Aqara wireless remote switch to control a few lights. I want the right_long to dim one of the lights, so I mapped it as hold_brightness_down. Both_double restores 100% brightness. Dimming works for the first time. Unfortunately, after restoring brightness, pressing right_long again no longer works, the lamp remains at 100%.

  module: controllerx
  class: CustomLightController
  controller: sensor.0x00158d0002334d6a_click
  integration: z2m
  light: light.kitchen_main
  mapping:
    right: toggle
    right_long: hold_brightness_down
    both_double: on_full_brightness

The same thing happened with hold_brightness_toggle

I think all “hold” actions need to be “released” and you don’t have release command mapped to anything. Since your controller does not support sending release command after you release the button after holding, I think it never stops dimming and other commands fail. I think you shouldn’t use any hold actions. You can use click_brightness_down or on_min_brightness

2 Likes

Hi @Jan_D,

As @peca89 said, you are using a “hood” action without a “release” one. Hold action activate a loop that sends HA requests to change the brightness (or any value) to a light. This loop is stopped if it reaches the end or it is stopped by a release action. This is why “hold” action should be together with a “release” one.

I am guessing by your mapping that you are using this device, which does not support release action, so no action is fired when a button is released. You could use “click” action as @peca89 recommended or use the hold as you are using and a click action as release for example. The only limitation you have now is your device since no action is fired when a button is released.

Let me know if you have any more questions.

Xavi M.

1 Like

Thank’s guys. Solution with click_brightness_down limited by manual_steps: 4 works perfect for me.

1 Like

Hi, I am having issues trying to use Controller X for controlling my hue lights with the hue dimmer switch.

I am running Hassio through Docker on Raspberry OS, and I am using ZHA integration through the Conbee II.

These are the steps I took:

  1. Installed newest AppDaemon 4 through Supervisor
  2. Installed newest HACS in the custom_components folder
  3. Installed newest Controller X through HACS
  4. Added the following code to /config/appdaemon/apps/apps.yaml
hall_controller:
  module: controllerx
  class: HueDimmerController
  controller: sensor.hall_switch_power
  integration: zha
  light: light.hall_pendel

And the AppDaemon logs says the following:

2020-07-20 21:46:18.296280 INFO AppDaemon: Initializing app hall_controller using class HueDimmerController from module controllerx
2020-07-20 21:46:18.313856 INFO hall_controller: 🎮 ControllerX v3.3.0

But when I press the dimmer, nothing happens. Is it because the entity showing under the remote device, is actually concerning the battery level? Because no other entities are showing, and I am unsure if I can use that.

I am able to setup simple automations through automations.yaml that triggers when I hit the buttons, but those points at the device, and not the underlying entity.

Edit: I definitely got the ID wrong, but when looking at Developer Tools, and what Device ID to use, this is what shows when pressing buttons:

{
    "event_type": "zha_event",
    "data": {
        "device_ieee": "00:17:88:01:04:e5:33:4a",
        "unique_id": "00:17:88:01:04:e5:33:4a:1:0x0006",
        "endpoint_id": 1,
        "cluster_id": 6,
        "command": "on",
        "args": []
    },
    "origin": "LOCAL",
    "time_fired": "2020-07-20T21:17:14.111489+00:00",
    "context": {
        "id": "564ebab53ed048b1b64289bf84c413aa",
        "parent_id": null,
        "user_id": null
    }
}

Any ideas?

Edit 2: device_ieee was the answer!

Sorry for my stupidity, I will leave this in place if it can help others.

1 Like

can i ask how you made a group which automatically changes with the media player that is playing?

I have two google cast speakers ‘kitchen’ and ‘dining room’. I would love it if my Symfonisk controller would control which ever is operating at the time (or both if they were both playing as a cast group?)

I have made a group in in group.yaml, which is called ‘group.downstairsaudio’ but am unsure how to make this switch based on the entity playing.

apologies, I’ve found the post from @Sennevds earlier in the thread re. using automations to select the entities in a group. I’ll give that a try!

Hi @bjorn.sivertsen,

Sorry for the late reply, however, you can find how to extract the controller attribute depending on the integration in here.

1 Like

So, I have been trying to work out how to use one Symfonisk sound controller to control two chromecast media players depending on which is playing, i.e:

  • media player 1 is playing, Symfonisk controls media player 1 only
  • media player 2 is playing, Symfonisk controls media player 2 only
  • media player 1 and 2 are playing as a group, Symfonisk controls media player 1 and 2 together (volume and play/pause)

Initially I used the method @Sennevds posted earlier in the thread using an automation to assign the controller to whichever of the two media players was currently in the ‘playing’ state. This worked well for controlling the volume on the devices when they were playing individually, however after pausing the music with the Symfonisk controller I was not able to restart the music as the the device was no longer ‘playing’ and so was no longer linked to the controller. Also, when two media players were playing as a group I was only able to control the volume of one media player.

My solution has been to use the constrain callback method suggested by @xaviml using the code below. This seems to achieve 90% of what I wanted - the Symfonisk will control whichever media player is playing, allowing volume and pause/resume, and also has the bonus of controlling both devices at the same time when they are playing as a synchronised group.

The only issue I now have is if each media player has been playing separate sources at some point in the day (i.e. Spotify from two separate accounts) and are both in the ‘paused’ state with different sources, then using the Symfonisk controller to play/pause will cause both media player to play the two different sources at the same time - which is a little annoying!

I can’t think how to solve this last issue and so will just need to make sure one of the chromecast media players is disconnected from casting if they have been playing different sources before using the Symfonisk!

Anyway, the code below works well based on initial testing:

diningroom_volume_controller:
  module: controllerx
  class: E1744MediaPlayerController
  controller: symfonisk_sound_controller
  integration: deconz
  media_player: media_player.dining_room
  constrain_input_select: media_player.dining_room,playing,paused
  volume_steps: 30
  delay: 200
  
kitchen_volume_controller:
  module: controllerx
  class: E1744MediaPlayerController
  controller: symfonisk_sound_controller
  integration: deconz
  media_player: media_player.kitchen
  constrain_input_select: media_player.kitchen,playing,paused
  volume_steps: 30
  delay: 200

Hi @colincliff,

That is awesome! Thanks for sharing this, this reduces the code to achieve what you wanted since no HA config is needed. However, thinking about the issue it raised and this is my question first: what is the behaviour you are expecting when the 2 media players are playing different sources and the button to resume is pressed?

Hi @xaviml

I think the ideal behaviour would be that the controller ‘remembers’ the last device that was playing and controls that (volume, pause/resume) even if both are paused. If the second player is then put into the ‘play’ state the controller would switch to the second player. The two media players are in separate open plan rooms so would never be playing separate sources at the same time, but could have been used individually in the day and so remain in ‘pause’ state with different sources.

For example the kind of behaviour I am trying to achieve is:
Scenario 1

  1. Media player 1 plays source 1 in the morning and is paused.
  2. Media player 2 plays source 2 in the afternoon and is paused.
  3. Symfonisk is pressed to resume Media Player 2 (last played), and only controls Media Player 2.

Currently doing this would resume media player 2 but also resume media player 1 in the same action which is undesirable.

Scenario 2

  1. Media player 1 plays source 1 in the morning and is paused.
  2. Medial player 2 plays source 2 in the afternoon and is playing.
  3. Symfonisk is pressed to pause Media Player 2 (currently playing) and only controls Media Player 2

Currently doing this would pause media player 2 but would also resume media player 1 in the same action which is undesirable.

Scenario 3: (this currently works with the code in the previous post)

  1. Both players are playing the same source as a group
  2. Symfonisk controls both devices playing/pausing and changing volume simultaneously

What would be better in the scenarios above is that Symfonisk somehow remains ‘attached’ only to the last Symfonisk that was playing, unless both are playing at the same time in which case it would control both.

The issues is that the constrain command is currently looking for both the ‘playing’ and ‘pause’ states for both media players - which is needed to make sure resume works - but this then confuses things if different sources had been used.

Apologies that this is not explained very well! I appreciate that the above may well not be possible as I’m trying to manage too many variables, and also my HA and coding skills are poor to say the least!

edit: perhaps one way to achieve this would be to have HA ‘disconnect’ the last player from casting when a new player starts playing. No idea if that is possible within HA as i am unclear on google cast controls, but that would mean that there is only ever one player in the ‘play’ / ‘pause’ state unless both are playing as a group?

Just to follow up - I think I have solved this with an automation that turns off the media player which is not being used when the other changes state to ‘playing’. This seems to work for my specific situation and ensures that the Symfonisk controller only controls the current playing media player and not the paused one. This also works for the two media players when grouped so the symfonisk can control both simultaneously.

It seems to work without fault in normal use - the only way i’ve managed to confuse it is to deliberately play different sources from the two players at the same time, but in reality this wouldn’t happen as both media players are in joined open plan rooms and so one would always be paused before using the other.

I’ve added the code below in case it helps anyone with a similar setup:

- id: '1595524338276'
  alias: turn dining room off when kitchen plays
  description: ''
  trigger:
  - entity_id: media_player.kitchen
    from: paused
    platform: state
    to: playing
  condition:
  - condition: state
    entity_id: media_player.dining_room
    state: paused
  action:
  - data: {}
    entity_id: media_player.dining_room
    service: media_player.turn_off
- id: '5595524338276'
  alias: turn kitchen off when dining room plays
  description: ''
  trigger:
  - entity_id: media_player.dining_room
    from: paused
    platform: state
    to: playing
  condition:
  - condition: state
    entity_id: media_player.kitchen
    state: paused
  action:
  - data: {}
    entity_id: media_player.kitchen
    service: media_player.turn_off
1 Like

Xiaomi magic cube example doesn’t work for me, my other Ikea remote works well.

apps.yaml:

---
cube_controller:
  module: controllerx
  class: MFKZQ01LMLightController
  controller: mi_magic_cube
  integration: deconz
  light: light.yeelight_lights_2 
  
livingroom_controller:
  module: controllerx
  class: E1810Controller
  controller: tradfri_remote_control
  integration: deconz
  light: light.yeelight_lights_1

In Appdaemon log I see that the cube_controller was initialized:

2020-07-25 20:00:06.680652 INFO AppDaemon: Reading config
2020-07-25 20:00:06.691191 INFO AppDaemon: /config/appdaemon/apps/apps.yaml added or modified
2020-07-25 20:00:06.691968 INFO AppDaemon: App 'cube_controller' added
2020-07-25 20:00:06.692824 INFO AppDaemon: Found 2 total apps
2020-07-25 20:00:06.693842 INFO AppDaemon: Adding thread 1
2020-07-25 20:00:06.737955 INFO AppDaemon: Initializing app cube_controller using class MFKZQ01LMLightController from module controllerx

In dev tools/events I see that it’s working:

{
    "event_type": "deconz_event",
    "data": {
        "id": "mi_magic_cube",
        "unique_id": "00:15:8d:00:02:7d:8e:39",
        "event": 3005,
        "gesture": 3
    },
    "origin": "LOCAL",
    "time_fired": "2020-07-25T18:21:45.071657+00:00",
    "context": {
        "id": "5ebe744925204970986ef92d82482a2d",
        "parent_id": null,
        "user_id": null
    }
}

When I try to rotate magic cube it doesn’t show anything in Appdaemon log, only in Events.

Hi @xaviml, first of all: kudos to you for a no doubt VERY well designed app and for the superb support you never seem to be tiring off !
I myself have started using your app over the last couple of days, replacing some rather intricate automations and scripts I concocted previously. On the whole, it has been a pleasant exercise with a positive outcome, meaning my remotes mostly do what I want them to do. There is however one thing I’m struggling with: your app seems to not recognize subsequent button presses after the first one. By which I mean: suppose I press e.g. the On button, then the corresponding action gets duly carried out, but a second press of the same button does nothing anymore (the log shows no action triggered). Pressing another button then does what’s requested, after which pressing the On button again works perfectly again - but only the first time after pressing this other button. So it seems like pressing buttons that do not result in ‘state’ changes go unnoticed ? It’s hard to believe this is a ‘feature’ by design, or a bug throughout the whole app …
Could it be it is an unlucky characteristic of the CallServiceController, which is what I’m using ?

ControllerX has been working since installed and I am using the basic setup for the E1524 remote.

I also have the E1743 on/off Switch and would like to set it up a little differently. Is it possible to have a single light bulb flash on/off continuously when the on button is depress and stop flashing when the off button is depressed?

Hi @madrian,

The Xiaomi Cube is an special one. In the documentation says:

deCONZ integration should be added with type gesture.

This means that the default behaviour for the cube (although you can change it) needs to be used with gesture type from deconz integration. The configuration will look like this:

cube_controller:
  module: controllerx
  class: MFKZQ01LMLightController
  controller: mi_magic_cube
  integration:
    name: deconz
    type: gesture
  light: light.yeelight_lights_2 

Let me know if this worked as expected. You can change the behaviour with custom controllers. This is an example for the example page:

example_app:
  module: controllerx
  class: CustomMediaPlayerController
  controller: my_magic_cube_id
  integration:
    name: deconz
    type: gesture
  media_player: media_player.livingroom_speaker
  mapping:
    1: play_pause # Shake
    8: click_volume_down # Rotate left
    7: click_volume_up # Rotate right
    3: next_track # Flip90
    4: previous_track # Flip180

Cheers

Hi @pav,

First off, hank you for your appreciation :slight_smile: Secondly, I would love to see first the configuration you have currently in place. Does this happen for all configurations?

Here is a background on the design. Some time ago, to avoid request overload, I added a delay where a button event is ignore. This delay is by default 300ms, this means that if you double press a button that sends 2 individual clicks within 300ms, ControllerX will just process the first one. This was done for the Symfonisk controller since it used to send a lot of data through z2m. Having said this, this parameter is called action_delta and it can be changed to 0 if needed. Documentation says this about action_delta:

This is the threshold time between the previous action and the next one (being the same action). If the time difference between the two actions is less than this attribute, then the action won’t be called. I recommend changing this if you see the same action being called twice.

Can be found in here. This is the only reason I could give to the problem you are mentioning. You haven’t mentioned, but the second time to press the button is like instantly or after a second or 2?

Cheers

Hi @duceduc,

For the use you are looking for, I will recommend you using CallServiceController. This controller allows you to map button events with HA call services. You will need to figure out how to make a light bulb flash from “Developer Tools > Services” (don’t know how to do that, but you might need a script for it). On a side note, when you say “depress”, do you mean the release action of the button? If so, z2m just sends “brightness_stop” when either button is released, so there is no way for you to know which button was released, so I will assume you meant press, then the configuration will look like the following:

example_app:
  module: controllerx
  class: CallServiceController
  controller: sensor.my_sensor
  integration: z2m
  mapping:
    on:
      service: <The service to flassh>
      data:
        arg1: <any needed argument>
    off:
      service: <The service to stop flashing>
      data:
        arg1: <any needed argument>

Cheers

I missed this information, but now it works. Thank you. :slight_smile:

Another idea: It would be great if it would be possible to define multiple lights and switch between them.

livingroom_controller:
  module: controllerx
  class: E1810Controller
  controller: tradfri_remote_control
  integration: deconz
  light: 
    - light.yeelight_lights_1
    - light.yeelight_lights_2

And add a shortcut to switch between them (double click maybe?).

1 Like

Hi @xaviml, my praise is well-deserved, so no thanks necessary :wink:
My use case consists of a couple of Hue dimmers, one I use as a light controller, one as a media controller. In both cases I use the CallServiceController, as I want to address more complex activities than just a simple on/off or similar (involving templating and such).
I hope my description of the problem I’m facing is clear enough, to which I can add that the time between subsequent presses of the same button is certainly more than the built-in cooldown delay. As a matter of fact, even waiting like 10 secs makes no difference whatsoever I’m afraid.
FYI : tailing appdaemon’s log shows the correct activation being launched after the first button press, but nada after the 2nd and following presses. And as I explained before, pressing any other button then works perfectly - meaning: once, and then no more when pressing this same other button again. And so on, and so further with every single button. The phenomenon can simply be summarized by saying: everything, every button works - but only once, without intermittently pressing another button.
Finally, please note that watching the controller’s state in HASS, I can see it updates with every button press. The only difference being that on a 2nd or following press of the same button its state remains the same (obviously) and only some attributes change - which leads me to think that one way or another you fail to detect these button presses because of the unchanged state.
Oh, and this is my config for one of the controllers:

music_remote:
  module: controllerx
  class: CallServiceController
  controller: sensor.music_remote_action
  integration: z2m
  mapping:
    on-press:
      service: script.music_remote_radio
      data:
        function: play_station
    on-hold-release:
      service: script.music_remote_mopidy
      data:
        function: play_mopidy_playlist
    up-press:
      service: script.music_remote_volume
      data:
        function: volume_up
    up-hold-release:
      service: script.music_remote_radio
      data:
        function: cycle_station
    down-press:
      service: script.music_remote_volume
      data:
        function: volume_down
    down-hold-release:
      service: script.music_remote_speaker
      data:
        function: cycle_speaker
    off-press:
      service: script.music_remote_misc
      data:
        function: media_play_pause
    off-hold-release:
      service: script.music_remote_misc
      data:
        function: turn_off

Please advise if you need other and/or more info, and many thanks for looking into it.

1 Like