dcnielsen90 / python-bravia-tv

MIT License
13 stars 6 forks source link

TV doesn't respond to first command #15

Open hogi1200 opened 3 years ago

hogi1200 commented 3 years ago

I am using home assistant (2021.1.5) to control my Sony TV KJ-49X7500F. There is an issue, that the first command that is sent to the TV seems to be ignored by the TV. This affects basically any command, like volume set, switch off, play, pause, ... (for some reason 'switch on' works always).

"First command" means the first command after some time of inactivity. All subsequent commands are performed without problem if they are sent shortly after the first one. But after ~15min without any command by homeassistant, the problem occurs again.

I tried a local change as a workaround, see below. it works fine for me, but maybe is not the cleanest way to implement it. My solution is to make an additional call to send_req_ircc() with no parameter, before the actual call with my intended command is executed. I achieve this via a recursive call at the beginning of send_req_ircc.

Let me know if you need further information. Would be happy if this would be fixed in the offical release. Thanks.

def send_req_ircc(self, params, log_errors=True, timeout=TIMEOUT):

    #new:
    if not params == "":
        self.send_req_ircc("",False)

    #existing code:
    """Send an IRCC command via HTTP to Sony Bravia."""
    headers = {'SOAPACTION': '"urn:schemas-sony-com:service:IRCC:1#X_SendIRCC"'}
    ...
dcnielsen90 commented 3 years ago

Hmm that's really weird. I'm going to try to get some time to test this out this week.

Is it 15 minutes after the TV is off, or 15 minutes on or off?

I've found the is_connected isn't foolproof for me. Get commands will work but set commands will stop after a while. So is_connected will return true despite not being able to do set commands. I wonder if this is related? If so, I was tempted to test the connection with set-wol instead of get-wol. I haven't made the change though because I thought it might just be my tv.

hogi1200 commented 3 years ago

Great if you already have a suspicion.

The issue happens when TV is on or off.

dcnielsen90 commented 3 years ago

This should be resolved with: https://github.com/dcnielsen90/python-bravia-tv/commit/c9c0fe9e09e1d4f8c9207348b017e34047ac84d7

I have to make some changes in Home Assistant as well, but I plan to have it pushed this week

Drafteed commented 3 years ago

Issue not fixed. After some time of inactivity (eg. playing YouTube) TV still does not respond on first command (send_command).

dcnielsen90 commented 3 years ago

I think the only way to solve this is raise on any 400 code and have the caller handle it. Specifically after some time, I'm seeing a 403 return code. We will need to add more error handling in HA should we go this route.

Drafteed commented 3 years ago

We will need to add more error handling in HA should we go this route.

If I understood you correctly, I think it just needs to be fix in the library and not handle needed in the HA.

I think the only way to solve this is raise on any 400 code and have the caller handle it. Specifically after some time, I'm seeing a 403 return code.

If this is a problem on the API side, I suppose it would be normal to make a forced retry of the request in case of an error. I will try to test it deeper today.

Drafteed commented 3 years ago

Simplest way to fix (+2 lines):

    def send_req_ircc(self, params, log_errors=True, timeout=TIMEOUT):
        """Send an IRCC command via HTTP to Sony Bravia."""
        headers = {'SOAPACTION': '"urn:schemas-sony-com:service:IRCC:1#X_SendIRCC"'}
        data = ("<?xml version=\"1.0\"?><s:Envelope xmlns:s=\"http://schemas.xmlsoap.org" +
                "/soap/envelope/\" " +
                "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body>" +
                "<u:X_SendIRCC " +
                "xmlns:u=\"urn:schemas-sony-com:service:IRCC:1\"><IRCCCode>" +
                params+"</IRCCCode></u:X_SendIRCC></s:Body></s:Envelope>").encode("UTF-8")
        for _ in range(2):
            try:
                response = self._session.post(f'http://{self._host}/sony/IRCC',
                                         headers=headers,
                                         data=data,
                                         timeout=timeout)
            except requests.exceptions.HTTPError as exception_instance:
                if log_errors:
                    _LOGGER.error("HTTPError: " + str(exception_instance))

            except Exception as exception_instance:  # pylint: disable=broad-except
                if log_errors:
                    _LOGGER.error("Exception: " + str(exception_instance))
                break
            else:
                content = response.content
                return content
Drafteed commented 3 years ago

@dcnielsen90 ping