Rotary dimmer as volume control SOLVED

If it can help, I use this appDaemon script:

import appdaemon.plugins.hass.hassapi as hass

#

# App which set the symfonisk remote

#

# Args:

#   [event] {string} -- Event name that will be fired (ex: deconz_event)

#   [remotes] {list} -- List of the symfonisk remote id in DeconZ (ex: - symfonisk_sound_controller)

#   [sonos] {list} -- List of the sonos media player to control (ex: - media_player.sonos_bathroom)

#   [sources] {list} -- Name of the source to play when double clicking (ex: - 'Sonos favoris name')

#   [play_shuffle] {boolean} -- Shuffle play the playlist

#

# Release Notes

#

# Version 1.2:

#   Bug fixes

#

# Version 1.1:

#   Handling volume

#

# Version 1.0:

#   Initial Version

# Define the max time when the volume can change

# There to avoid an unlimited change when

# not receiveing stop event

CHANGE_VOLUME_TIME_MAX = 10

# Define the interval between

# each call to change volume, smaller = faster

CHANGE_VOLUME_INTERVAL = 1

class DeconzSymfoniskRemote(hass.Hass):

    """ [summary]

        [event] {string} -- Event name that will be fired (ex: deconz_event)

        [remotes] {list} -- List of the symfonisk remote id in DeconZ (ex: - symfonisk_sound_controller)

        [sonos] {list} -- List of the sonos media player to control (ex: - media_player.sonos_bathroom)

        [sources] {list} -- Name of the source to play when double clicking (ex: - 'Sonos favoris name')

        [play_shuffle] {boolean} -- Shuffle play the playlist

    """

    def initialize(self):

        self.handle_params()

        if 'event' in self.args:

            self.listen_event(self.handle_event, self.args['event'])

    def handle_params(self):

        self.log(self.args)

        self.event_name = "app_daemon_symfonisk"

        self.sonos = self.args.get('sonos')

        self.sources = self.args.get('sources')

        self.remotes = self.args.get('remotes')

        self.play_shuffle = self.args.get('play_shuffle', False)

        self.initial_source = 0

        self.volume_change = False

    def handle_source(self):

        selected_source = self.sources[self.initial_source]

        self.initial_source += 1

        if self.initial_source >= len(self.sources):

            self.initial_source = 0

        return selected_source

    

    def disable_volume_change(self, kwargs):

        self.log("Change volume disabled by " + kwargs["emit"])

        self.volume_change = False

    def handle_volume(self, kwargs):

        self.log("Change volume loop " + kwargs["way"])

        if self.volume_change:

            self.call_service("media_player/volume_" + kwargs["way"], entity_id = self.sonos)

            self.run_in(self.handle_volume, CHANGE_VOLUME_INTERVAL, way = kwargs["way"])

    def handle_event(self, event_name, data, kwargs):

        remote_id = data['id']

        if remote_id in self.remotes:

            if data['event'] == 1002:

                self.log('Button simple click - toggle')

                self.call_service("media_player/media_play_pause", entity_id = self.sonos)

                self.fire_event(self.event_name, entity_id = self.sonos, state="click1")

            elif data['event'] == 1004:

                self.log('Button double click - next track')

                self.call_service("media_player/media_next_track", entity_id = self.sonos)

                self.fire_event(self.event_name, entity_id = self.sonos, state="click2")

            elif data['event'] == 1005:

                self.log('Button triple click - choose source')

                if len(self.sonos) > 1:

                    self.call_service("sonos/join", entity_id = self.sonos, master = self.sonos[0])

                self.call_service("media_player/shuffle_set", entity_id = self.sonos, shuffle = self.play_shuffle)

                self.call_service("media_player/select_source", entity_id = self.sonos, source = self.handle_source())

                self.fire_event(self.event_name, entity_id = self.sonos, state="click3")

            elif data['event'] == 2001:

                self.log('Button volume up')

                self.volume_change = True

                self.handle_volume({'way': 'up'})

                self.run_in(self.disable_volume_change, CHANGE_VOLUME_TIME_MAX, emit = "auto vol up")

                self.fire_event(self.event_name, entity_id = self.sonos, state="volup")

            elif data['event'] == 3001:

                self.log('Button volume down')

                self.volume_change = True

                self.handle_volume({'way': 'down'})

                self.run_in(self.disable_volume_change, CHANGE_VOLUME_TIME_MAX, emit = "auto vol down")

                self.fire_event(self.event_name, entity_id = self.sonos, state="voldown")

            elif data['event'] in [2003, 3003]:

                self.log('Button volume stop')

                self.disable_volume_change({'emit': 'event'})

                self.fire_event(self.event_name, entity_id = self.sonos, state="volstop")

            else:

                self.log('Unkown action: ' + data['event'])

Iā€™m trying to change the volume of my AVR Amplifier via an IKEA Tradfri Dimmer (ICTC-G-1) and Zigbee2MQTT. The amp accepts only IR and CEC so instead forking out for an IR blaster I decided to use the Kodi box connected to the amp via HDMI CEC. As there is no volume scale known by Kodi (HDMI Passthrough) Iā€™m unable to use media_player.volume_set. At the moment I have implemented this very hacky script and automation. It works just about but the delay in changing volume quickly isnā€™t great. Any suggestions on an improvement would be great!

- id: bedroom_amp_volume_up
  alias: "Bedrooom Amplifier Volume Up"
  trigger:
  - platform: state
    entity_id: sensor.0x000b57fffe208e8f_action
    to: rotate_right
  condition:
    condition: state
    entity_id: switch.bedroom_amp
    state: 'on'
  action:
    service: media_player.volume_up
    entity_id: media_player.pi_bedroom

- id: bedroom_amp_volume_down
  alias: "Bedrooom Amplifier Volume Down"
  trigger:
  - platform: state
    entity_id: sensor.0x000b57fffe208e8f_action
    to: rotate_left
  condition:
    condition: state
    entity_id: switch.bedroom_amp
    state: 'on'
  action:
    service: media_player.volume_down
    entity_id: media_player.pi_bedroom

- id: bedroom_amp_volume_up_quick
  alias: "Bedrooom Amplifier Volume Up Quick"
  trigger:
  - platform: state
    entity_id: sensor.0x000b57fffe208e8f_action
    to: rotate_right_quick
  condition:
    condition: state
    entity_id: switch.bedroom_amp
    state: 'on'
  action:
    service: script.turn_on
    entity_id: script.bedroom_volume_up

- id: bedroom_amp_volume_down_quick
  alias: "Bedrooom Amplifier Volume Down Quick"
  trigger:
  - platform: state
    entity_id: sensor.0x000b57fffe208e8f_action
    to: rotate_left_quick
  condition:
    condition: state
    entity_id: switch.bedroom_amp
    state: 'on'
  action:
    service: script.turn_on
    entity_id: script.bedroom_volume_down

Scripts:

bedroom_volume_up:
  alias: Bedroom Volume Up Quick
  sequence:
  - service: media_player.volume_up
    entity_id: media_player.pi_bedroom
  - delay:
      milliseconds: 2
  - service: media_player.volume_up
    entity_id: media_player.pi_bedroom
  - delay:
      milliseconds: 2
  - service: media_player.volume_up
    entity_id: media_player.pi_bedroom
  - delay:
      milliseconds: 2
  - service: media_player.volume_up
    entity_id: media_player.pi_bedroom
  - delay:
      milliseconds: 2
  - service: media_player.volume_up
    entity_id: media_player.pi_bedroom

bedroom_volume_down:
  alias: Bedroom Volume Down Quick
  sequence:
  - service: media_player.volume_down
    entity_id: media_player.pi_bedroom
  - delay:
      milliseconds: 2
  - service: media_player.volume_down
    entity_id: media_player.pi_bedroom
  - delay:
      milliseconds: 2
  - service: media_player.volume_down
    entity_id: media_player.pi_bedroom
  - delay:
      milliseconds: 2
  - service: media_player.volume_down
    entity_id: media_player.pi_bedroom
  - delay:
      milliseconds: 2
  - service: media_player.volume_down
    entity_id: media_player.pi_bedroom

Hi,

many thanks for you efforts to write this script. Im totally new to appdaemon (never heard from it until i saw your script).
I set it up as im using a bose sound system and not a sonos i replaced all occurrences of ā€œsonosā€ in your script with ā€œboseā€

this is in my apps.yaml

symfonisk:
module: symfonisk
class: DeconzSymfoniskRemote
bose: media_player.bose_buiten
remotes: SYMFONISK_controller
event: deconz_event

When i turn the controller i can see event callbacks in appdaemon but the volume doesnā€™t go up or down. Do you have any idea what I am doing wrong?

You can add a delay node so it only allows 1event per second. This is what i did. Here is my node-red config for symfonisk that uses it to control volume (but you can easily modify it to control lights)

[{"id":"2b73df72.7a5ef","type":"switch","z":"8d71d601.17bd38","name":"TV Light","property":"payload.state.buttonevent","propertyType":"msg","rules":[{"t":"eq","v":"1005","vt":"str"},{"t":"eq","v":"1004","vt":"str"},{"t":"eq","v":"1002","vt":"str"},{"t":"eq","v":"2001","vt":"str"},{"t":"eq","v":"2003","vt":"str"},{"t":"eq","v":"3001","vt":"str"},{"t":"eq","v":"3003","vt":"str"}],"checkall":"true","repair":false,"outputs":7,"x":920,"y":1840,"wires":[["413e4ee9.4de178"],[],["94a40bd9.309258"],["506d4c6d.088e64"],["77566777.2851f"],["b0f22e28.3cdba8"],["77566777.2851f"]],"outputLabels":["Tripple","Double","Single","Left Spin start","left stop","Right spin start","right stop"]},{"id":"77566777.2851f","type":"function","z":"8d71d601.17bd38","name":"Stop","func":"var newMsg = { payload: \"stop\" };\nreturn newMsg;\n","outputs":1,"noerr":0,"x":1210,"y":1900,"wires":[["4226d4c9.270e4c","82f67842.33573"]]},{"id":"82f67842.33573","type":"looptimer","z":"8d71d601.17bd38","duration":"1","units":"Second","maxloops":"30","maxtimeout":"1","maxtimeoutunits":"Minute","name":"","x":1460,"y":1880,"wires":[["3851a70f.2b4c88"],[]]},{"id":"4226d4c9.270e4c","type":"looptimer","z":"8d71d601.17bd38","duration":"1","units":"Second","maxloops":"30","maxtimeout":"1","maxtimeoutunits":"Minute","name":"","x":1460,"y":1940,"wires":[["a8aa3509.4b6a"],[]]},{"id":"1f744871.cc3228","type":"api-call-service","z":"8d71d601.17bd38","name":"Toggle","server":"8a745406.799e98","version":1,"debugenabled":false,"service_domain":"light","service":"toggle","entityId":"light.livingroom_balls","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1270,"y":1820,"wires":[[]]},{"id":"3851a70f.2b4c88","type":"api-call-service","z":"8d71d601.17bd38","name":"Light Up","server":"8a745406.799e98","version":1,"debugenabled":false,"service_domain":"light","service":"turn_on","entityId":"light.livingroom_balls","data":"{\"brightness_step_pct\":10}","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1640,"y":1880,"wires":[[]]},{"id":"506d4c6d.088e64","type":"delay","z":"8d71d601.17bd38","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"2","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"x":1190,"y":1880,"wires":[["82f67842.33573"]]},{"id":"b0f22e28.3cdba8","type":"delay","z":"8d71d601.17bd38","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"2","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"x":1190,"y":1940,"wires":[["4226d4c9.270e4c"]]},{"id":"a8aa3509.4b6a","type":"api-call-service","z":"8d71d601.17bd38","name":"Light Down","server":"8a745406.799e98","version":1,"debugenabled":false,"service_domain":"light","service":"turn_on","entityId":"light.livingroom_balls","data":"{\"brightness_step_pct\":\"-10\"}","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1630,"y":1940,"wires":[[]]},{"id":"94a40bd9.309258","type":"delay","z":"8d71d601.17bd38","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"2","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"x":1120,"y":1820,"wires":[["1f744871.cc3228"]]},{"id":"413e4ee9.4de178","type":"function","z":"8d71d601.17bd38","name":"Light mode=false","func":"var light = global.set('light',\"false\") || \"false\";\n\n\n\n","outputs":1,"noerr":0,"x":1170,"y":1780,"wires":[[]]},{"id":"7edb1a80.15ae24","type":"deconz-input","z":"8d71d601.17bd38","name":"Black Knob","server":"5fd4e4ff.662abc","device":"14:b4:57:ff:fe:6e:23:f1-01-1000","device_name":"Black knob : ZHASwitch","topic":"","state":"buttonevent","output":"always","outputAtStartup":false,"x":690,"y":1840,"wires":[["2b73df72.7a5ef"],[]]},{"id":"8a745406.799e98","type":"server","z":"","name":"Skynet Home Assistant - Local","legacy":false,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true},{"id":"5fd4e4ff.662abc","type":"deconz-server","z":"","name":"HA-Zigbee","ip":"core-deconz","port":"40850","apikey":"C29F29E46B","ws_port":"8081","secure":false,"polling":"15"}]

For me it suddenly stopped working. I can pair it but it does not shows any values when I do any actions. I am using Zigbee2Mqtt

Same here, I donā€™t get any messages for any actions. Iā€™m currently applying the ota update to the device, hopefully this will help.

No luck, the OTA update took 2 hours to complete, and still no publish messages when i click or rotate to left and right.
All i see is an entry at about every 5 minutes that the ikea sound controller sends out to show itā€™s online. I started noticing this after i updated zigbee2mqtt to 1.14.2

Yep, I did the FW update some time ago. Seems that the bug is in the addon. Thanks for confirmation.

ok, just got another volume controller, and out of the box, it straight connects to z2m and publishes commands. I have no idea what went wrong with the first one

So the new one is working and the old one not?
I reported a bug based on we are two. You are free to leave a comment there: https://github.com/Koenkk/zigbee2mqtt/issues/4036

Exactly, the new one works and the old one doesnā€™t. I have no idea why. It just stopped after upgrading z2m. So I just replaced it with the same friendly name in the z2m configuration.yaml and everything works normal

I tried to also use the Symfonisk controller for changing the volume. However, I could not find a way yet to change the volume smoothly. My current automation looks like this:

- alias: "Speaker: Select sonos office volume with cube rotation"
  initial_state: "on"
  trigger:
    platform: mqtt
    topic: "zigbee2mqtt/volume_controller"
  condition:
    condition: and
    conditions:
      - condition: template
        value_template: "{{ trigger.payload_json.action in ['rotate_right', 'rotate_left', 'rotate_stop'] }}"
      - condition: state
        entity_id: switch.speaker_2
        state: "on"
  action:
    - service: media_player.volume_set
      data_template:
        entity_id: media_player.office
        volume_level: >
          {{ trigger.payload_json.brightness / 2000 | float }}

However, the volume control is not as smooth as I expected it to be. I wonder if this is the case because of a delay of the media_player.volume_set service or if it because of a delay in triggering this automation. Any ideas on how to improve this?

I use 2000 instead of 255, since I want to limit the maximum volume.

what specifically was the issue you had. I have the same issue but canā€™t find the problem in the script