ztalbot2000 / homebridge-cmd4

CMD4 Plugin for Homebridge - Supports ~All Accessory Types & now all Characteristics too
Apache License 2.0
149 stars 14 forks source link

TV Speaker Not Appearing in Home App #82

Closed Ramias1 closed 3 years ago

Ramias1 commented 3 years ago

Great pluign. I have my TV working with three input sources (actually on my Yamaha Receiver) as linked devices and they show fine in the official Apple Home app . I have a tv speaker as a linked device as well. It shows in the Homebridge UI-X (shows as a separate device) and I can control volume and mute, but there's no volume control for my TV in the Home App.

Any thoughts on this? Also, one other data point; not critical - the Home+ app does not even recognize the TV device from Cmd4. Provably an issue with that app.

and here's something else interesting: on the bottom of the About page for the TV, it shows Yamaha as the manufacturer (Defined for the linked speaker) not Samsung (defined for the tv).

I've removed it from my phone, removed it from homebridge etc. Any ideas how to get volume to show?

Config file below: { "platform": "Cmd4", "name": "Cmd4", "outputConstants": false, "accessories": [ { "type": "Television", "displayName": "TV", "manufacturer": "Samsung", "model": "55 Inch Something", "serialNumber": "Who Cares", "fetch": "Polled", "publishExternally": true, "category": "TELEVISION", "activeIdentifier": 1, "configuredName": "TV", "active": "ACTIVE", "sleepDiscoveryMode": "ALWAYS_DISCOVERABLE", "remoteKey": "SELECT", "polling": [ { "characteristic": "active", "interval": 50, "timeout": 5000 }, { "characteristic": "activeIdentifier", "interval": 50, "timeout": 5000 } ], "stateChangeResponseTime": 3, "state_cmd": "sh /homebridge/Cmd4Scripts/samsungtv.sh", "linkedTypes": [ { "type": "InputSource", "displayName": "TiVo", "configuredName": "TiVo", "currentVisibilityState": "SHOWN", "inputSourceType": "HDMI", "isConfigured": "CONFIGURED", "identifier": 0, "targetVisibilityState": "SHOWN", "name": "TiVo", "manufacturer": "TiVo", "model": "Mini", "serialNumber": "12345" }, { "type": "InputSource", "displayName": "AppleTV", "configuredName": "AppleTV", "currentVisibilityState": "SHOWN", "inputSourceType": "HDMI", "isConfigured": "CONFIGURED", "identifier": 1, "targetVisibilityState": "SHOWN", "name": "AppleTV", "manufacturer": "Apple", "model": "Anything", "serialNumber": "12345" }, { "type": "InputSource", "displayName": "Cameras", "configuredName": "Cameras", "currentVisibilityState": "SHOWN", "inputSourceType": "HDMI", "isConfigured": "CONFIGURED", "identifier": 2, "targetVisibilityState": "SHOWN", "name": "Cameras", "manufacturer": "Somebody", "model": "Anything", "serialNumber": "12345" }, { "type": "TelevisionSpeaker", "displayName": "TVSpeaker", "mute": "FALSE", "active": "ACTIVE", "volume": 40, "volumeControlType": "ABSOLUTE", "volumeSelector": "INCREMENT", "name": "TVSpeaker", "manufacturer": "Yamaha", "model": "Anything", "serialNumber": "12345" } ] } ] }

ztalbot2000 commented 3 years ago

Hi,

I'm not 100% sure how linked accessories work, I just define them exactly like Homebridge does. I have none myself. I could imagine you might need to define polling for the volume amd I wonder if you need to define it on both the TV and TV Speaker?

I might try your config when I get a chance. Just packed it in for the day.

For now as you familiarize yourself with the plugin and caching. Set restartRecover: false at the top so things act like you just started them the first time.

TTFN, John

My TV does show in The HomeApp.

On Tue, Jan 26, 2021 at 3:54 PM Ramias1 notifications@github.com wrote:

Great pluign. I have my TV working with three input sources (actually on my Yamaha Receiver) as linked devices and they show fine in the official Apple Home app . I have a tv speaker as a linked device as well. It shows in the Homebridge UI-X (shows as a separate device) and I can control volume and mute, but there's no volume control for my TV in the Home App.

Any thoughts on this? Also, one other data point; not critical - the Home+ app does not even recognize the TV device from Cmd4. Provably an issue with that app.

and here's something else interesting: on the bottom of the About page for the TV, it shows Yamaha as the manufacturer (Defined for the linked speaker) not Samsung (defined for the tv).

I've removed it from my phone, removed it from homebridge etc. Any ideas how to get volume to show?

Config file below: { "platform": "Cmd4", "name": "Cmd4", "outputConstants": false, "accessories": [ { "type": "Television", "displayName": "TV", "manufacturer": "Samsung", "model": "55 Inch Something", "serialNumber": "Who Cares", "fetch": "Polled", "publishExternally": true, "category": "TELEVISION", "activeIdentifier": 1, "configuredName": "TV", "active": "ACTIVE", "sleepDiscoveryMode": "ALWAYS_DISCOVERABLE", "remoteKey": "SELECT", "polling": [ { "characteristic": "active", "interval": 50, "timeout": 5000 }, { "characteristic": "activeIdentifier", "interval": 50, "timeout": 5000 } ], "stateChangeResponseTime": 3, "state_cmd": "sh /homebridge/Cmd4Scripts/samsungtv.sh", "linkedTypes": [ { "type": "InputSource", "displayName": "TiVo", "configuredName": "TiVo", "currentVisibilityState": "SHOWN", "inputSourceType": "HDMI", "isConfigured": "CONFIGURED", "identifier": 0, "targetVisibilityState": "SHOWN", "name": "TiVo", "manufacturer": "TiVo", "model": "Mini", "serialNumber": "12345" }, { "type": "InputSource", "displayName": "AppleTV", "configuredName": "AppleTV", "currentVisibilityState": "SHOWN", "inputSourceType": "HDMI", "isConfigured": "CONFIGURED", "identifier": 1, "targetVisibilityState": "SHOWN", "name": "AppleTV", "manufacturer": "Apple", "model": "Anything", "serialNumber": "12345" }, { "type": "InputSource", "displayName": "Cameras", "configuredName": "Cameras", "currentVisibilityState": "SHOWN", "inputSourceType": "HDMI", "isConfigured": "CONFIGURED", "identifier": 2, "targetVisibilityState": "SHOWN", "name": "Cameras", "manufacturer": "Somebody", "model": "Anything", "serialNumber": "12345" }, { "type": "TelevisionSpeaker", "displayName": "TVSpeaker", "mute": "FALSE", "active": "ACTIVE", "volume": 40, "volumeControlType": "ABSOLUTE", "volumeSelector": "INCREMENT", "name": "TVSpeaker", "manufacturer": "Yamaha", "model": "Anything", "serialNumber": "12345" } ] } ] }

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/ztalbot2000/homebridge-cmd4/issues/82, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABSBCX6HQIEIEUUFQT2S7VDS34TYDANCNFSM4WUDDJNQ .

Ramias1 commented 3 years ago

Thanks. My TV control looks like the far right photo here: https://www.macobserver.com/news/airplay-2-and-homekit-support-comes-to-2018-lg-tvs/

I may have it figured out thanks to the Google and Reddit... In the actual Remote app for Apple TVs (and where my TV shows up now) then use the phone volume buttons. It's calling a Set 'TVSpeaker' 'VolumeSelector' '1'. Will add this to my shell script and report back.

Ramias1 commented 3 years ago

That works. Con control volume with the iPhone volume controls from the Apple Remote app (not the Home app). Not sure how to invoke Mute though. Not a huge deal. Thanks again for the work on this plugin.

mitch7391 commented 3 years ago

@Ramias1 I am working on a shell script for my Hisense TV at the moment and currently have an issue with turning the TV on since adding linkedTypes in the mix. Assuming you have created a shell script and have no issues turning the TV on, can I please take a look at your shell script to see if there is any logic I may be missing for mine?

Ramias1 commented 3 years ago

Did it work before you added the linked types? My Samsung is a 2012. It was wired and wireless ethernet and I can turn it OFF via the network but not on. I need to invoke a scene on my Yamaha receiver (That I can do over the network when it is in 'sleep' mode) that then turns on the TV via HDMI CEC. To make it more interesting, I use IndigoDomotics and track on/off device states there so some of my script actually makes a rest call to Indigo to turn things on/off but I could just as well invoke the scene directly on the Yamaha (I do other things directly on the receiver for TVSpeaker), check TV on/off via ping etc.

My code's a bit messy, but it works for me. And actually sending commands to my Samsung, I also do that via Indigo. Could not find simple curl commands for the non-Tizen Samsung from 2012. There are Python libraries, so it can be done with bash as well, but for me it was just as easy to invoke the Samsung commands from Indigo.

PS - I ran in to some strange issues with certain "sed" and other bash commands working fine on my Mac but failing in the Alpine Linux container I run homebridge under, thus some of the mess in the code.

#!/bin/sh

#
# This Cmd4 example demonstrates how you can test if an accessory is on the network using ping.
#
# Your Cmd4 .homebridge/.config.json file would have a state_cmd like:
# state_cmd: ".homebridge/Cmd4Scripts/Examples/ping.sh"
#
#
# Testing from the shell prompt:
#    ./basic_ping.sh Get My_TV On
#    or
#    ./basic_ping.sh Set My_TV On 1

# Exit immediately if a command exits with a non-zero status
set -e

# Define the accessories IP you wish to test
indigo_ip="192.168.0.30"
yamahaIp="192.168.0.94"
indigo_creds="user:password"
# Check if the first parameter to this script was "Get" for getting an accessory's
# specific attribute.
if [ "$1" = "Get" ]; then

   # Normally we would exit immediately if a command fails with a non-zero status.
   # In this case ping can fail and we would rely on the failing exit status to
   # tell Cmd4 that the accessory is not on the network. That would be the prefered
   # thing to do. However for this example we are going to output '0' (false) so
   # that you can see the '0' on the console telling us that the accessory is not
   # on the network.
   set +e

   # $2 would be the name of the accessory
   # $3 would be the accessory's charactersistic 'On'
   # On OSX the string is returned differently than on linux.
   # ping -c 2 -W 1 "${ip}" | sed -E 's/2 packets received/2 received/g' | grep -i '2 received' >> /dev/null
   if [ "$2" = "TV" ]; then
      if [ "$3" = "On" ] || [ "$3" = "Active" ]; then
         curl -X GET -d isOn -u ${indigo_creds} --digest http://${indigo_ip}:8176/devices/TV.txt | grep 'isOn : True' >> /dev/null
         rc=$?

         # Exit immediately if a command exits with a non-zero status
         set -e

         # Check if we got the message '2 packets recieved' meaning the accessory is
         # on the network by seeing if the return code of the above command passed or
         # failed.
         if [ "$rc" = "0" ]; then
            # The message was recieved so the target is up, sending a '1' (true), like
            # a binary number is, back to Cmd4.
            echo "1"

            # Exit this script positivitely.
            exit 0
         else
            # The message was not recieved so the target must be down, sending a '0' (false), like
            # a binary number is, back to Cmd4.
            echo "0"

            # Exit this script positivitely, even though ping failed.
            exit 0
         fi
      fi

      if [ "$3" = "ActiveIdentifier" ]; then
         input=$(curl http://192.168.0.94/YamahaExtendedControl/v1/main/getStatus | sed -e 's/.*input\":\"\(.*\)\",\"input.*/\1/')
         case $input in
            "hdmi1") echo 0 ;;
            "hdmi2") echo 1 ;;
            "hdmi3") echo 2 ;;
            "audio4") echo 3 ;;
         esac
         exit 0
      fi
   fi

   if [ "$2" = "TiVo" ]; then
      if [ "$3" = "Identifier" ]; then
         echo 0
         exit 0
      fi
   fi

   if [ "$2" = "AppleTV" ]; then
      if [ "$3" = "Identifier" ]; then
         echo 1
         exit 0
      fi
   fi

   if [ "$2" = "Cameras" ]; then
      if [ "$3" = "Identifier" ]; then
         echo 2
         exit 0
      fi
   fi

      if [ "$2" = "Sonos" ]; then
      if [ "$3" = "Identifier" ]; then
         echo 3
         exit 0
      fi
   fi

   if [ "$3" = "TargetVisibilityState" ]; then
      echo 0
      exit 0
   fi
   if [ "$3" = "CurrentVisibilityState" ]; then
      echo 0
      exit 0
   fi
   if [ "$3" = "IsConfigured" ]; then
      echo 1
      exit 0
   fi
   if [ "$3" = "InputSourceType" ]; then
      echo 3
      exit 0
   fi
   if [ "$3" = "ConfiguredName" ]; then
      echo $2
      exit 0
   fi

   if [ "$2" = "TVSpeaker" ]; then
      if [ "$3" = "Mute" ]; then
         curl -s http://${yamahaIp}/YamahaExtendedControl/v1/main/getStatus | grep '"mute":true' >> /dev/null
         rc=$?
         set -e
         if [ "$rc" = "0" ]; then
            echo "1"
            exit 0
         else
            echo "0"
            exit 0
         fi
      fi

      #Do Something 'VolumeControlType', 'Volume', 'Active'

      if [ "$3" = "Volume" ]; then
         response=$(curl -s http://${yamahaIp}/YamahaExtendedControl/v1/main/getStatus | sed -rn 's/.*,"value":([0-9]*).*/\1/p')
         rc=$?
         set -e
         if [ "$rc" = "0" ]; then
            echo "$response"
            exit 0
         else
            exit 1
         fi
      fi
      exit 0
   fi
fi

# Check if the first parameter to this script was "Set" for setting an accessory's
# specific attribute.
if [ "$1" = "Set" ]; then

   # $2 would be the name of the accessory.
   # $3 would be the accessory's charactersistic 'On'.
   # $4 would be '1' for 'On' and '0' for 'Off', like a binary number is.
   # $4 would be 'true' for 'On' and 'false' for 'Off' with
   # outputConstants=true in your .homebridge/.config.json file.

   # Cmd4 will pass the IP in the config.json defined by state_cmd_suffix as the fifth
   # parameter to a Set command.

   # Cmd4 will pass the MAC Address in the config.json defined by state_cmd_suffix as the sixth
   # parameter to a Set command.
   if [ "$2" = "TV" ]; then
      if [ "$3" = "Active" ] || [ "$3" = "On" ]; then
         if [ "$4" = "1" ]; then
            curl -X PUT -d isOn=1 -u ${indigo_creds} --digest http://${indigo_ip}:8176/devices/TV >> /dev/null 2>&1
            rc=$?
         else
            curl -X PUT -d isOn=0 -u ${indigo_creds} --digest http://${indigo_ip}:8176/devices/TV >> /dev/null 2>&1
            rc=$?
         fi

         if [ "$rc" = "0" ]; then
            exit 0
         else
            exit $rc
         fi

      elif [ "$3" = "RemoteKey" ]; then
         case "$4" in
            "0") indigo_dev="Samsung%20REWIND" ;;
            "1") indigo_dev="Samsung%20FAST_FORWARD" ;;
            "2") indigo_dev="Samsung%20NEXT_TRACK" ;;
            "3") indigo_dev="Samsung%20PREVIOUS_TRACK" ;;
            "4") indigo_dev="Samsung%20ARROW_UP" ;;
            "5") indigo_dev="Samsung%20ARROW_DOWN" ;;
            "6") indigo_dev="Samsung%20ARROW_LEFT" ;;
            "7") indigo_dev="Samsung%20ARROW_RIGHT" ;;
            "8") indigo_dev="Samsung%20Enter%20Button" ;;
            "9") indigo_dev="Samsung%20BACK" ;;
            "10") indigo_dev="Samsung%20EXIT" ;;
            "11") indigo_dev="Samsung%20PLAY_PAUSE" ;;
            "12") indigo_dev="Samsung%20INFORMATION" ;;
         esac
         curl -X EXECUTE -u ${indigo_creds} --digest http://${indigo_ip}:8176/actions/${indigo_dev} >> /dev/null 2>&1
         rc=$?
         if [ "$rc" = "0" ]; then
            exit 0
         fi
      elif [ "$3" = "ActiveIdentifier" ]; then
         if [ "$4" = "0" ]; then
            curl -s http://${yamahaIp}/YamahaExtendedControl/v1/main/setInput?input=hdmi1
         elif [ "$4" = "1" ]; then
            curl -s http://${yamahaIp}/YamahaExtendedControl/v1/main/setInput?input=hdmi2
         elif [ "$4" = "2" ]; then
            curl -s http://${yamahaIp}/YamahaExtendedControl/v1/main/setInput?input=hdmi3
         elif [ "$4" = "3" ]; then
            curl -s http://${yamahaIp}/YamahaExtendedControl/v1/main/setInput?input=audio4
         fi
         rc=$?
         if [ "$rc" = "0" ]; then
            exit 0
         fi
      fi
   fi

   if [ "$3" = "ConfiguredName" ]; then
      echo $2
      exit 0
   fi

   if [ "$2" = "TVSpeaker" ]; then
      if [ "$3" = "Mute" ]; then
         if [ "$4" = "1" ]; then
            curl -s http://${yamahaIp}/YamahaExtendedControl/v1/main/setMute?enable=true
            rc=$?
            if [ "$rc" = "0" ]; then
               exit 0
            fi
         else
            curl -s http://${yamahaIp}/YamahaExtendedControl/v1/main/setMute?enable=false
            rc=$?
            if [ "$rc" = "0" ]; then
               exit 0
            fi
         fi
      elif [ "$3" = "VolumeSelector" ]; then
         if [ "$4" = "0" ]; then # Increment
            curl -s http://${yamahaIp}/YamahaExtendedControl/v1/main/setVolume?volume=up\&step=2
            rc=$?
            if [ "$rc" = "0" ]; then
               exit 0
            fi
         else
            curl -s http://${yamahaIp}/YamahaExtendedControl/v1/main/setVolume?volume=down\&step=2
            rc=$?
            if [ "$rc" = "0" ]; then
               exit 0
            fi
         fi

      elif [ "$3" = "Volume" ]; then
         targetVol=$(($4*2))
         if [ "$targetVol" -gt "161" ]; then
            targetVol=161
         fi
         curl -s http://${yamahaIp}/YamahaExtendedControl/v1/main/setVolume?volume=${targetVol}
         rc=$?
         if [ "$rc" = "0" ]; then
            exit 0
         fi
      fi
   fi

fi

# The proper arguments to this script were not passed to it so end with a failure exit status.
exit 66
mitch7391 commented 3 years ago

I started with a simple switch accessory for my TV and the on/off worked there, but the moment I made it into a TV accessory it will only accept the off command and won't accept the on command (exact same MQTT command but now using Active instead of On characteristic). I was suspecting with cmd4 and not my shell script after some investigating; so hearing if it does or doesn't work for others would help me cement this thought.

if [ "$3" = "On" ] || [ "$3" = "Active" ]; then

A quick read over your script and I notice you are using both On and Active; is this due to your particular setup or is it required? This could be what I am missing then...

Ramias1 commented 3 years ago

Using both On and Active is due to my "hunt and peck" method of getting this to work :). Like I said, my code is fragile; basically wrote it based on the ping sample and then adding fixes for every error message I saw in the logs.

mitch7391 commented 3 years ago

That is interesting, I wonder if I should try defining the On characteristic in my shell script as well as the Active... I know what you mean about you method, it has been the same for me! Haha

mitch7391 commented 3 years ago

Well it appears adding the On to my config and polling, changing Active ) to 'On )' in my 'Set' section and changing my 'Get' as follows On | Active ) to pipe the value of On into Active has worked for me. I can now turn my TV accessory on via Homekit. Thanks for providing your script and prompting that line of testing! :)

ztalbot2000 commented 3 years ago

As it turns out the TV speaker would not be a linked accessory, but an added accessory. Either way it still does not show in HomeKit. This is not a fault of Cmd4. It may be of Homebridge or it is not even possible in HomeKit as we do not own their GUI. If you can show me an example of anything that has one this way, please let me know and I will pursue further.

That being said, I can prove why it is not a Cmd4 issue. Homebridge has an exact example of a Television with HDMI inputs and an added speaker. You can find it here: https://developers.homebridge.io/#/service/Television

You will see that the Television Speaker is not a linked accessory but an added accessory. You can literally copy and paste this code into an index.js file of its own with a package.json wrapper around it and load this plugin with an entry in your config.json as "platforms" : [ { "platform": "HomebridgeExampleTv" } ]

Going to HomeKit you will not find this TV Speaker either. How HomeKit displays which accessories are part of their GUI is not something I can fix. Now I also checked Eve and it did not show anything either. Sadly the ExampleTV does not show up at all as does the one by Cmd4 too.

What I can tell you is that you can define the Speaker as shown in the Homebridge tv example in Cmd4. I use this config.json to duplicate the ExampleTV plugin in Cmd4. The Television Speaker is not within LinkedTypes, but an "accessories" section of the Television platform. If you then run Homebridge in debug mode, Cmd4 will output the same step as the ExampleTV plugin where the Speaker is an added service to the Television and not a linked service of the Television. { "platform": "Cmd4", "outputConstants": false, "restartRecover": true, "fetch": "Polled", "accessories" : [ { "type": "Television", "category": "TELEVISION", "publishExternally": false, "name": "Example TV", "active": "ACTIVE", "activeIdentifier": 1, "configuredName": "Example TV", "manufacturer": "Example TV Mfg.", "model": "Example TV Model", "serialNumber": "Example TV Sn.", "sleepDiscoveryMode": "ALWAYS_DISCOVERABLE", "accessories": [ { "type": "televisionSpeaker", "displayName": "My TvSpeaker", "name": "My TVSpeaker", "active": "ENABLED", "mute": "FALSE", "volumeSelector": 10, "volume": 10, "volumeControlType": "ABSOLUTE", "state_cmd": "node .homebridge/anyDevice.js", "polling": [ { "characteristic": "active", "interval": 50, "timeout": 5000}, { "characteristic": "volume", "interval": 50, "timeout": 5000}, { "characteristic": "volumeSelector", "interval": 50, "timeout": 5000} ] } ], "linkedTypes": [ { "type": "InputSource", "displayName": "HDMI1", "configuredName": "HDMI 1", "currentVisibilityState": "SHOWN", "inputSourceType": "HDMI", "isConfigured": "CONFIGURED", "identifier": 1, "targetVisibilityState": "SHOWN", "name": "HDMI 1" }, { "type": "InputSource", "displayName": "HDMI 2", "configuredName": "HDMI 2", "currentVisibilityState": "SHOWN", "inputSourceType": "HDMI", "isConfigured": "CONFIGURED", "identifier": 2, "targetVisibilityState": "SHOWN", "name": "HDMI 2" }, { "type": "InputSource", "displayName": "Netflix", "configuredName": "Netflix", "currentVisibilityState": "SHOWN", "inputSourceType": "HDMI", "isConfigured": "CONFIGURED", "identifier": 3, "targetVisibilityState": "SHOWN", "name": "Netflix" } ], "displayOrder": 0, "currentMediaState": "STOP", "targetMediaState": "STOP", "pictureMode": "STANDARD", "remoteKey": "SELECT", "polling": [ { "characteristic": "active", "interval": 50, "timeout": 5000}, { "characteristic": "activeIdentifier", "interval": 50, "timeout": 5000}, { "characteristic": "currentMediaState", "interval": 540, "timeout": 5000} ], "stateChangeResponseTime": 3, "state_cmd": "node .homebridge/anyDevice.js" } ] } ]

I do not know what benefit of doing it this way is to HomeKit if it does not display it anyway.

I am going to close this because this is not a Cmd4 issue as previously explained. It seems your only recourse is to define the Speaker separately and wait until the GUI's catch up.

mitch7391 commented 3 years ago

Just as an FYI on the topic of HomeKit not showing the Television Speaker as its own accessory; I am pretty sure that config-ui-x shows it as a separate accessory on the web-UI under the accessories tab.

ztalbot2000 commented 3 years ago

Oooh, I'm going to check that out. Thanks !!!!!

I've noticed that even the homebridge example plugin does not show even a TV in "Eve". I wonder if they are having issues.?

On Mon, Feb 1, 2021 at 7:02 PM Mitch Williams notifications@github.com wrote:

Just as an FYI on the topic of HomeKit not showing the Television Speaker as its own accessory; I am pretty sure that config-ui-x shows it as a separate accessory on the web-UI under the accessories tab.

— You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHub https://github.com/ztalbot2000/homebridge-cmd4/issues/82#issuecomment-771245789, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABSBCX7U77GHP5NBFARF65DS446IVANCNFSM4WUDDJNQ .