home-assistant-libs / pychromecast

Library for Python 3 to communicate with the Google Chromecast.
MIT License
2.51k stars 378 forks source link

How can I tell when an app stops casting? #84

Open rossdargan opened 8 years ago

rossdargan commented 8 years ago

I'm really new the python so sorry if this is obvious!

I'm using the code from here: https://www.reddit.com/r/homeautomation/comments/4fc01z/quick_question_for_openhab_users/d28vnc4 to hook up to openhab.

What I want to happen is when I cast something to a chromecast I want me speakers to turn on, and turn off when I stop casting.

The issue I'm having is that the following code:

` self.device.media_controller.register_status_listener(self)

    def new_media_status(self, status):
            self.sendDeviceStatus()

`

doesn't appear to execute when the app_id gets set to None. Is there another "event" I can hook up to so I know when the cast has stopped?

Sorry, I know this is a terrible way to reach out for help, but I didn't want to message you on reddit, and wasn't sure where else to ask!

noob-4-life commented 8 years ago

Not sure if this is what you're looking for, but you can register a listener for new 'cast' (receiver) status updates ??

In the code you linked to, you can add

def __init__(self, device):
    self.device = device
    self.thumbnail = ""
    self.sendDeviceStatus()
    self.device.media_controller.register_status_listener(self)
    self.device.register_status_listener(self)  # Register for receiver status updates.

def new_cast_status(self, new_status):
""" Called when a new status received from the Chromecast. """
    if new_status.app_id != "CC1AD845":
        pass  # Your code to turn off your speakers can go here.

Note that you may want to launch the app on the receiver BEFORE registering the cast/receiver status listener. Otherwise you might end up turning off your speakers before you've started playing anything due to the status being updated for whatever reason. Hope that helps.

P.s. There's also a listener for Network Connection Status updates as well:

def __init__(self, device)
    self.device.register_connection_listener(self)

def new_connection_status(self, new_status):
    # new_status.status will be one of the CONNECTION_STATUS_ constants defined in the
    # socket_client module.
    if new_status.status == CONNECTION_STATUS_DISCONNECTED:
        pass  # Your code to turn off your speakers here.
henfri commented 7 years ago

Hello,

I am trying the same. I am not sure, I implemented your suggestion correctly: `#!/usr/bin/python

source https://www.reddit.com/r/homeautomation/comments/4fc01z/quick_question_for_openhab_users/d28vnc4/

from future import print_function import pychromecast import os

def getDeviceNamed(name): for myDevice in myDevices: if myDevice.device.name == name: return myDevice return None;

def on_mqtt_connect(client, userdata, flags, rc): for device in devices: client.subscribe("chromecast/{0}/command".format(device.name))

def on_message(command,device):

try:

            if command[0] == "play":
                    getDeviceNamed(device).device.media_controller.play()
                    getDeviceNamed(device).forceUpdate()
            if command[0] == "pause":
                    getDeviceNamed(device).device.media_controller.pause()
                    getDeviceNamed(device).forceUpdate()
            if command[0] == "stop":
                    getDeviceNamed(device).device.quit_app()
                    getDeviceNamed(device).forceUpdate()
            if command[0] == "volume_up":
                    getDeviceNamed(device).device.volume_up()
                    getDeviceNamed(device).forceUpdate()
            if command[0] == "volume_down":
                    getDeviceNamed(device).device.volume_down()
                    getDeviceNamed(device).forceUpdate()

            if command[0] == "set_volume":
                    print("vol: " + str(command[1]))
                    getDeviceNamed(device).device.set_volume(float(str(command[1])) / 100)
                    getDeviceNamed(device).forceUpdate()

            if command[0] == "replay":
                    getDeviceNamed(device).device.media_controller.seek(getDeviceNamed(device).media_controller.status.current_time - float(str(command[1])))
                    getDeviceNamed(device).forceUpdate()
            if command[0] == "skip":
                    getDeviceNamed(device).device.media_controller.seek(getDeviceNamed(device).media_controller.status.current_time + float(str(command[1])))
                    getDeviceNamed(device).forceUpdate()

            if command[0] == "reboot":
                    getDeviceNamed(device).device.reboot()

            if command[0] == "update":
                    getDeviceNamed(device).forceUpdate()

except:

pass

class DeviceStatusUpdater: def init(self, device): self.device = device self.thumbnail = "" self.sendDeviceStatus() self.device.media_controller.register_status_listener(self)

    def new_media_status(self, status):
            self.sendDeviceStatus()

    def forceUpdate(self):
            self.device.socket_client._force_recon=True

    def addDeviceInfo(self, topic, payload):
            return {"topic":"chromecast/{0}/{1}".format(str(self.device.name), topic), "payload":payload}

    def __init__(self, device):
        self.device = device
        self.thumbnail = ""
        self.sendDeviceStatus()
        self.device.media_controller.register_status_listener(self)
        self.device.register_status_listener(self)  # Register for receiver status updates.
        self.device.register_connection_listener(self)

    def new_cast_status(self, new_status):
        #""" Called when a new status received from the Chromecast. """
        print(new_status.app_id)
        if new_status.app_id != "CC1AD845":
            print("NewStatus")
            pass  # Your code to turn off your speakers can go here.

    def new_connection_status(self, new_status):
        # new_status.status will be one of the CONNECTION_STATUS_ constants defined in the
        # socket_client module.
        if new_status.status == CONNECTION_STATUS_DISCONNECTED:
            pass  # Your code to turn off your speakers here.

    def sendDeviceStatus(self):
            #global publish
            deviceInfo = []

            deviceInfo.append(self.addDeviceInfo("name", self.device.name))
            deviceInfo.append(self.addDeviceInfo("host", self.device.host))
            deviceInfo.append(self.addDeviceInfo("app",  self.device.app_display_name))

            if self.device.media_controller is not None:
                    if self.device.media_controller.status is not None:
                            deviceInfo.append(self.addDeviceInfo("state", self.device.media_controller.status.player_state))

                            if self.device.media_controller.status.player_state == pychromecast.controllers.media.MEDIA_PLAYER_STATE_PLAYING:
                                    deviceInfo.append(self.addDeviceInfo("is_playing", "ON"))
                            else:
                                    deviceInfo.append(self.addDeviceInfo("is_playing", "OFF"))

                            deviceInfo.append(self.addDeviceInfo("title",                   self.device.media_controller.status.title))
                            deviceInfo.append(self.addDeviceInfo("series_title",            self.device.media_controller.status.series_title))
                            deviceInfo.append(self.addDeviceInfo("artist",                  self.device.media_controller.status.artist))
                            deviceInfo.append(self.addDeviceInfo("album",                   self.device.media_controller.status.album_name))
                            deviceInfo.append(self.addDeviceInfo("mediatype",               self.device.media_controller.status.metadata_type))
                            deviceInfo.append(self.addDeviceInfo("thumbnail",               self.device.media_controller.thumbnail))
                            deviceInfo.append(self.addDeviceInfo("volume",                  str(float(self.device.status.volume_level) * 100)))
                            deviceInfo.append(self.addDeviceInfo("current",                 self.device.media_controller.status.current_time))

                            duration = self.device.media_controller.status.duration
                            if duration is None:
                                    duration = -1
                            deviceInfo.append(self.addDeviceInfo("duration",                duration))

                            if self.thumbnail is not self.device.media_controller.thumbnail:
                  #                  os.system("wget {1} -O /usr/share/openhab/webapps/images/{0}.png".format(self.device.name, self.device.media_controller.thumbnail))
                                    #os.system("/usr/bin/convert /usr/share/openhab/webapps/images/{0}.png -resize 128x128 /usr/share/openhab/webapps/images/{0}.png".format(self.device.name))
                                    self.thumbnail = self.device.media_controller.thumbnail

                            print(deviceInfo)

print ("Device discovery...") devices = pychromecast.get_chromecasts() global myDevices myDevices = [] for device in devices:

Wait for cast device to be ready

    device.wait()
    print(str(device))
    myDevices.append(DeviceStatusUpdater(device))

myDevices is a list of Chromecast devices (class DeviceStatusUpdater)

we can now send a message

cmd=['set_volume', '33'] on_message(cmd,"ChromecastSchlafzimmer")

or get the Title

print(myDevices[0].sendDeviceStatus)

from time import sleep

while True: sleep(1)`

What happens is, that I get this output: vol: 33 <bound method DeviceStatusUpdater.sendDeviceStatus of <main.DeviceStatusUpdater object at 0x7f97736875f8>> Error communicating with socket, resetting connection 233637DE NewStatus

Followed by the output of sendDeviceStatus()

But when changing the status of the chromecast (play, pause, ...) only sendDeviceStatus is called, whereas new_cast_status is not called.

new_cast_status is only called upon launch of the script.

Also: What could be the error of the message "Error communicating with socket, resetting connection"

Regards, Hendrik