lukasroegner / homebridge-apple-tv-remote

Plugin for controlling Apple TVs in homebridge.
MIT License
131 stars 13 forks source link

Stability issues #46

Open lukasroegner opened 4 years ago

lukasroegner commented 4 years ago

There are three main issues with the plugin in its current state:

Delayed messages For some users, messages from the Apple TV to the plugin are delayed (sometimes for minutes), resulting in switches that are out of sync. As the on/off switch emulates remote input, it also cannot execute the correct action if the plugin state is out of sync with the Apple TV state.

On/off detection The logic to detect whether an Apple TV is on or off is not correct, yet. Currently, three state variables are considered to check whether the Apple TV is on:

    /**
     * Tries to get the on/off state of the Apple TV
     * @param messagePayload The message payload that contains the information to check whether the Apple TV is on.
     * @returns Returns a value that determines whether the Apple TV is on.
     */
    private getIsOn(messagePayload: any): boolean {

        // If the Apple TV is not a proxy for AirPlay playback, the logicalDeviceCount determines the state
        if (messagePayload.logicalDeviceCount > 0 && !messagePayload.isProxyGroupPlayer) {
            return true;
        }

        // If the Apple TV is a proxy for AirPlay playback, the logicalDeviceCount and the AirPlay state determine the state
        if (messagePayload.logicalDeviceCount > 0 && messagePayload.isProxyGroupPlayer && messagePayload.isAirplayActive) {
            return true;
        }
        return false;
    }

Crashes of homebridge For some users, connections to the Apple TV are suddenly closed, resulting in an unhandled exception when the plugin tries to send a message through the closed channel. The PR for fixing the request has also been submitted, but not accepted, yet: https://github.com/stickpin/node-appletv-x/pull/3

try-and-error-and-repeat commented 3 years ago

@lukasroegner I had no problem until the update to tvOS 14. It worked fine and was 99% reliable.

I use a Raspberry Pi 3, connected via Ethernet (Gigabit on the same network switch as the Apple TV 4K) also plain homebridge, FRITZ!Box 7490 Router and homebridge with Version 1.2.2. Node.js with version 12.18.4 and npm 6.18.4. home hub is also the Apple TV 4K

brj5 commented 3 years ago

Plug-in is causing homebridge to give error sigterm command received and causing it to not be able to start, homebridge will not even start up with the plugin installed.

lukasroegner commented 3 years ago

@brj5 Can you please provide debug logs so that the cause of your issue can be investigated?

brj5 commented 3 years ago

INFO: Homebridge Version: 2.6 INFO: SmartThings-v2 Plugin Version: 2.3.8 INFO: Checking Package Version for Updates... [9/27/2020, 9:41:52 PM] [Alexa] Initializing Alexa platform... [9/27/2020, 9:41:52 PM] [Alexa] homebridge-alexa v0.4.74, node v12.18.4, homebridge v1.2.3 [9/27/2020, 9:41:52 PM] Initializing platform accessory 'Alexa'... [9/27/2020, 9:41:52 PM] [Apple TV Platform] Initializing AppleTvPlatform platform... [9/27/2020, 9:41:52 PM] [TplinkSmarthome] Configuring cached accessory: [Sylvia TP] 8006D708D3FB3181C5047D0F92AD1DCE1CC71E79 efea0c2a-deae-47c1-877d-713ba7beb6c3 [9/27/2020, 9:41:52 PM] [TplinkSmarthome] Configuring cached accessory: [George] 80063216504BED33259330D033C900271CC8DF9F d5471697-7289-4bed-9228-9d9b427dcae3 [9/27/2020, 9:41:52 PM] [SengledHub] configureAccessory: B0CE1814033A6325 [9/27/2020, 9:41:52 PM] [SengledHub] configureAccessory: B0CE18140320C9B5 [9/27/2020, 9:41:52 PM] [SengledHub] DeviceDiscovery invoked INFO: Fetching SmartThings-v2 Devices. NOTICE: This may take a moment if you have a large number of device data is being loaded! GOOD: Refreshing All Device Data | Source: (First Launch) [9/27/2020, 9:41:52 PM] [Apple TV Platform] Initialing platform... [9/27/2020, 9:41:52 PM] [Apple TV Platform] No devices configured. Setup Payload: X-HM://0023ISYWY9B5J Enter this code with your HomeKit app on your iOS device to pair with Homebridge:

┌────────────┐     
│ 031-45-154 │     
└────────────┘     

[9/27/2020, 9:41:52 PM] Homebridge v1.2.3 is running on port 52108. [9/27/2020, 9:41:52 PM] [TplinkSmarthome] New Device Online: [Sylvia TP] plug [8006D708D3FB3181C5047D0F92AD1DCE1CC71E79] 192.168.1.128 9999 [9/27/2020, 9:41:52 PM] [TplinkSmarthome] Adding: [Sylvia TP] plug [8006D708D3FB3181C5047D0F92AD1DCE1CC71E79] [9/27/2020, 9:41:52 PM] [TplinkSmarthome] New Device Online: [George] plug [80063216504BED33259330D033C900271CC8DF9F] 192.168.1.100 9999 [9/27/2020, 9:41:52 PM] [TplinkSmarthome] Adding: [George] plug [80063216504BED33259330D033C900271CC8DF9F] NOTICE: Temperature Unit is Now: (F) WARN: Devices to Remove: (0) [] INFO: Devices to Update: (3) GOOD: Devices to Create: (0) [] ALERT: Total Initialization Time: (1 seconds) NOTICE: Unknown Capabilities: [] INFO: SmartThings DeviceCache Size: (3) INFO: WebServer Initiated... INFO: Sending StartDirect Request to SmartThings | SendToLocalHub: (false) INFO: Direct Connect Active | Listening at 192.168.1.107:8000 Error: timeout of 2000ms exceeded at createError (/homebridge/node_modules/homebridge-sengled/node_modules/axios/lib/core/createError.js:16:15) at Timeout.handleRequestTimeout [as _onTimeout] (/homebridge/node_modules/homebridge-sengled/node_modules/axios/lib/adapters/http.js:207:16) at listOnTimeout (internal/timers.js:549:17) at processTimers (internal/timers.js:492:7) { config: { adapter: [Function: httpAdapter], transformRequest: { '0': [Function: transformRequest] }, transformResponse: { '0': [Function: transformResponse] }, timeout: 2000, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, headers: { Accept: 'application/json, text/plain, /', 'Content-Type': 'application/json;charset=utf-8', 'User-Agent': 'axios/0.17.1', 'Content-Length': 125 }, baseURL: 'https://us-elements.cloud.sengled.com:443/zigbee/', withCredentials: true, responseType: 'json', method: 'post', url: 'https://us-elements.cloud.sengled.com:443/zigbee/customer/remoteLogin.json', data: '{"uuid":"d0452dbd-f03d-094f-6c8d-e72fc36a7d8e","isRemote":true,"user":""pwd":","os_type":"ios"}', maxRedirects: 0, [Symbol(COOKIEJAR_SUPPORT_LOCAL)]: { backupOptions: [Object], jar: [CookieJar], redirectCount: 5 } }, code: 'ECONNABORTED', request: ClientRequest { _events: [Object: null prototype] { response: [Function], error: [Function: handleRequestError] }, _eventsCount: 2, _maxListeners: undefined, outputData: [], outputSize: 0, writable: true, _last: true, chunkedEncoding: false, shouldKeepAlive: false, useChunkedEncodingByDefault: true, sendDate: false, _removedConnection: false, _removedContLen: false, _removedTE: false, _contentLength: 125, _hasBody: true, _trailer: '', finished: true, _headerSent: true, socket: TLSSocket { _tlsOptions: [Object], _secureEstablished: true, _securePending: false, _newSessionPending: false, _controlReleased: true, secureConnecting: true, _SNICallback: null, servername: 'us-elements.cloud.sengled.com', alpnProtocol: false, authorized: true, authorizationError: null, encrypted: true, _events: [Object: null prototype], _eventsCount: 11, connecting: false, _hadError: false, _parent: null, _host: 'us-elements.cloud.sengled.com', _readableState: [ReadableState], readable: false, _maxListeners: undefined, _writableState: [WritableState], writable: false, allowHalfOpen: false, _sockname: null, _pendingData: null, _pendingEncoding: '', server: undefined, _server: null, ssl: null, _requestCert: true, _rejectUnauthorized: true, parser: [HTTPParser], _httpMessage: [Circular],

  [Symbol(verified)]: true,
  [Symbol(pendingSession)]: null,
  [Symbol(asyncId)]: 115,
  [Symbol(kHandle)]: null,
  [Symbol(kSetNoDelay)]: false,
  [Symbol(lastWriteQueueSize)]: 0,
  [Symbol(timeout)]: null,
  [Symbol(kBuffer)]: null,
  [Symbol(kBufferCb)]: null,
  [Symbol(kBufferGen)]: null,
  [Symbol(kCapture)]: false,
  [Symbol(kBytesRead)]: 0,
  [Symbol(kBytesWritten)]: 368,
  [Symbol(connect-options)]: [Object]
},
connection: TLSSocket {
  _tlsOptions: [Object],
  _secureEstablished: true,
  _securePending: false,
  _newSessionPending: false,
  _controlReleased: true,
  secureConnecting: true,
  _SNICallback: null,
  servername: 'us-elements.cloud.sengled.com',
  alpnProtocol: false,
  authorized: true,
  authorizationError: null,
  encrypted: true,
  _events: [Object: null prototype],
  _eventsCount: 11,
  connecting: false,
  _hadError: false,
  _parent: null,
  _host: 'us-elements.cloud.sengled.com',
  _readableState: [ReadableState],
  readable: false,
  _maxListeners: undefined,
  _writableState: [WritableState],
  writable: false,
  allowHalfOpen: false,
  _sockname: null,
  _pendingData: null,
  _pendingEncoding: '',
  server: undefined,
  _server: null,
  ssl: null,
  _requestCert: true,
  _rejectUnauthorized: true,
  parser: [HTTPParser],
  _httpMessage: [Circular],
  [Symbol(res)]: [TLSWrap],
  [Symbol(verified)]: true,
  [Symbol(pendingSession)]: null,
  [Symbol(asyncId)]: 115,
  [Symbol(kHandle)]: null,
  [Symbol(kSetNoDelay)]: false,
  [Symbol(lastWriteQueueSize)]: 0,
  [Symbol(timeout)]: null,
  [Symbol(kBuffer)]: null,
  [Symbol(kBufferCb)]: null,
  [Symbol(kBufferGen)]: null,
  [Symbol(kCapture)]: false,
  [Symbol(kBytesRead)]: 0,
  [Symbol(kBytesWritten)]: 368,
  [Symbol(connect-options)]: [Object]
},
_header: 'POST /zigbee/customer/remoteLogin.json HTTP/1.1\r\n' +
  'Accept: application/json, text/plain, */*\r\n' +
  'Content-Type: application/json;charset=utf-8\r\n' +
  'User-Agent: axios/0.17.1\r\n' +
  'Content-Length: 125\r\n' +
  'Host: us-elements.cloud.sengled.com\r\n' +
  'Connection: close\r\n' +
  '\r\n',
_onPendingData: [Function: noopPendingOutput],
agent: Agent {
  _events: [Object: null prototype],
  _eventsCount: 2,
  _maxListeners: undefined,
  defaultPort: 443,
  protocol: 'https:',
  options: [Object],
  requests: {},
  sockets: [Object],
  freeSockets: {},
  keepAliveMsecs: 1000,
  keepAlive: false,
  maxSockets: Infinity,
  maxFreeSockets: 256,
  maxCachedSessions: 100,
  _sessionCache: [Object],
  [Symbol(kCapture)]: false
},
socketPath: undefined,
method: 'POST',
insecureHTTPParser: undefined,
path: '/zigbee/customer/remoteLogin.json',
_ended: false,
res: null,
aborted: true,
timeoutCb: null,
upgradeOrConnect: false,
parser: HTTPParser {
  '0': [Function: parserOnHeaders],
  '1': [Function: parserOnHeadersComplete],
  '2': [Function: parserOnBody],
  '3': [Function: parserOnMessageComplete],
  '4': null,
  _headers: [],
  _url: '',
  socket: [TLSSocket],
  incoming: null,
  outgoing: [Circular],
  maxHeaderPairs: 2000,
  _consumed: false,
  onIncoming: [Function: parserOnIncomingClient],
  [Symbol(resource_symbol)]: [HTTPClientAsyncResource]
},
maxHeadersCount: null,
reusedSocket: false,
[Symbol(kCapture)]: false,
[Symbol(kNeedDrain)]: false,
[Symbol(corked)]: 0,
[Symbol(kOutHeaders)]: [Object: null prototype] {
  accept: [Array],
  'content-type': [Array],
  'user-agent': [Array],
  'content-length': [Array],
  host: [Array]
}

}, response: undefined } Error: timeout of 2000ms exceeded at createError (/homebridge/node_modules/homebridge-sengled/node_modules/axios/lib/core/createError.js:16:15) at Timeout.handleRequestTimeout [as _onTimeout] (/homebridge/node_modules/homebridge-sengled/node_modules/axios/lib/adapters/http.js:207:16) at listOnTimeout (internal/timers.js:549:17) at processTimers (internal/timers.js:492:7) { config: { adapter: [Function: httpAdapter], transformRequest: { '0': [Function: transformRequest] }, transformResponse: { '0': [Function: transformResponse] }, timeout: 2000, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, headers: { Accept: 'application/json, text/plain, /', 'Content-Type': 'application/json;charset=utf-8', 'User-Agent': 'axios/0.17.1', 'Content-Length': 125 }, baseURL: 'https://us-elements.cloud.sengled.com:443/zigbee/', withCredentials: true, responseType: 'json', method: 'post', url: 'https://us-elements.cloud.sengled.com:443/zigbee/customer/remoteLogin.json', data: '{"uuid":"d0452dbd-f03d-094f-6c8d-e72fc36a7d8e","isRemote":true,"user":"","os_type":"ios"}', maxRedirects: 0, [Symbol(COOKIEJAR_SUPPORT_LOCAL)]: { backupOptions: [Object], jar: [CookieJar], redirectCount: 5 } }, code: 'ECONNABORTED', request: ClientRequest { _events: [Object: null prototype] { response: [Function], error: [Function: handleRequestError] }, _eventsCount: 2, _maxListeners: undefined, outputData: [], outputSize: 0, writable: true, _last: true, chunkedEncoding: false, shouldKeepAlive: false, useChunkedEncodingByDefault: true, sendDate: false, _removedConnection: false, _removedContLen: false, _removedTE: false, _contentLength: 125, _hasBody: true, _trailer: '', finished: true, _headerSent: true, socket: TLSSocket { _tlsOptions: [Object], _secureEstablished: true, _securePending: false, _newSessionPending: false, _controlReleased: true, secureConnecting: true, _SNICallback: null, servername: 'us-elements.cloud.sengled.com', alpnProtocol: false, authorized: true, authorizationError: null, encrypted: true, _events: [Object: null prototype], _eventsCount: 11, connecting: false, _hadError: false, _parent: null, _host: 'us-elements.cloud.sengled.com', _readableState: [ReadableState], readable: false, _maxListeners: undefined, _writableState: [WritableState], writable: false, allowHalfOpen: false, _sockname: null, _pendingData: null, _pendingEncoding: '', server: undefined, _server: null, ssl: null, _requestCert: true, _rejectUnauthorized: true, parser: [HTTPParser], _httpMessage: [Circular],

  [Symbol(verified)]: true,
  [Symbol(pendingSession)]: null,
  [Symbol(asyncId)]: 115,
  [Symbol(kHandle)]: null,
  [Symbol(kSetNoDelay)]: false,
  [Symbol(lastWriteQueueSize)]: 0,
  [Symbol(timeout)]: null,
  [Symbol(kBuffer)]: null,
  [Symbol(kBufferCb)]: null,
  [Symbol(kBufferGen)]: null,
  [Symbol(kCapture)]: false,
  [Symbol(kBytesRead)]: 0,
  [Symbol(kBytesWritten)]: 368,
  [Symbol(connect-options)]: [Object]
},
connection: TLSSocket {
  _tlsOptions: [Object],
  _secureEstablished: true,
  _securePending: false,
  _newSessionPending: false,
  _controlReleased: true,
  secureConnecting: true,
  _SNICallback: null,
  servername: 'us-elements.cloud.sengled.com',
  alpnProtocol: false,
  authorized: true,
  authorizationError: null,
  encrypted: true,
  _events: [Object: null prototype],
  _eventsCount: 11,
  connecting: false,
  _hadError: false,
  _parent: null,
  _host: 'us-elements.cloud.sengled.com',
  _readableState: [ReadableState],
  readable: false,
  _maxListeners: undefined,
  _writableState: [WritableState],
  writable: false,
  allowHalfOpen: false,
  _sockname: null,
  _pendingData: null,
  _pendingEncoding: '',
  server: undefined,
  _server: null,
  ssl: null,
  _requestCert: true,
  _rejectUnauthorized: true,
  parser: [HTTPParser],
  _httpMessage: [Circular],
  [Symbol(res)]: [TLSWrap],
  [Symbol(verified)]: true,
  [Symbol(pendingSession)]: null,
  [Symbol(asyncId)]: 115,
  [Symbol(kHandle)]: null,
  [Symbol(kSetNoDelay)]: false,
  [Symbol(lastWriteQueueSize)]: 0,
  [Symbol(timeout)]: null,
  [Symbol(kBuffer)]: null,
  [Symbol(kBufferCb)]: null,
  [Symbol(kBufferGen)]: null,
  [Symbol(kCapture)]: false,
  [Symbol(kBytesRead)]: 0,
  [Symbol(kBytesWritten)]: 368,
  [Symbol(connect-options)]: [Object]
},
_header: 'POST /zigbee/customer/remoteLogin.json HTTP/1.1\r\n' +
  'Accept: application/json, text/plain, */*\r\n' +
  'Content-Type: application/json;charset=utf-8\r\n' +
  'User-Agent: axios/0.17.1\r\n' +
  'Content-Length: 125\r\n' +
  'Host: us-elements.cloud.sengled.com\r\n' +
  'Connection: close\r\n' +
  '\r\n',
_onPendingData: [Function: noopPendingOutput],
agent: Agent {
  _events: [Object: null prototype],
  _eventsCount: 2,
  _maxListeners: undefined,
  defaultPort: 443,
  protocol: 'https:',
  options: [Object],
  requests: {},
  sockets: [Object],
  freeSockets: {},
  keepAliveMsecs: 1000,
  keepAlive: false,
  maxSockets: Infinity,
  maxFreeSockets: 256,
  maxCachedSessions: 100,
  _sessionCache: [Object],
  [Symbol(kCapture)]: false
},
socketPath: undefined,
method: 'POST',
insecureHTTPParser: undefined,
path: '/zigbee/customer/remoteLogin.json',
_ended: false,
res: null,
aborted: true,
timeoutCb: null,
upgradeOrConnect: false,
parser: HTTPParser {
  '0': [Function: parserOnHeaders],
  '1': [Function: parserOnHeadersComplete],
  '2': [Function: parserOnBody],
  '3': [Function: parserOnMessageComplete],
  '4': null,
  _headers: [],
  _url: '',
  socket: [TLSSocket],
  incoming: null,
  outgoing: [Circular],
  maxHeaderPairs: 2000,
  _consumed: false,
  onIncoming: [Function: parserOnIncomingClient],
  [Symbol(resource_symbol)]: [HTTPClientAsyncResource]
},
maxHeadersCount: null,
reusedSocket: false,
[Symbol(kCapture)]: false,
[Symbol(kNeedDrain)]: false,
[Symbol(corked)]: 0,
[Symbol(kOutHeaders)]: [Object: null prototype] {
  accept: [Array],
  'content-type': [Array],
  'user-agent': [Array],
  'content-length': [Array],
  host: [Array]
}

}, response: undefined } ERROR: uncaughtException: abort(Error: timeout of 2000ms exceeded). Build with -s ASSERTIONS=1 for more info. No stack trace [9/27/2020, 9:41:54 PM] Got SIGTERM, shutting down Homebridge... [9/27/2020, 9:41:54 PM] [Apple TV Platform] Shutting down Apple TV clients... INFO: INFO: Your plugin version is up-to-date NOTICE: Sending Plugin Status to SmartThings | UpdateAvailable: false [9/27/2020, 9:41:59 PM] [HB Supervisor] Homebridge Process Ended. Code: 143, Signal: null

Post404 commented 3 years ago

I never had problems with the delay that people are talking about here, it always worked instantly for me. But since the updates from last weekend there is a big delay. Everything is updated to it's latest version. Nothing has changed in the network.

Post404 commented 3 years ago

I reinstalled the plugin and now the problem is only related to the play Pauze buttons, I added the application related buttons for Netflix and YouTube as well. But they behave the same way.

try-and-error-and-repeat commented 3 years ago

Same problem. Running it on a separate RPi 3 with just this plugin and homebridge UI X. So the Problem is not related to other plugins.

I can send debug logs if this would help.

uspino2 commented 3 years ago

I get this error every 7 seconds for 15 to 20 minutes every time I restart HomeBridge, until it finally connects to my Apple TV. I'm on a clean UniFi network. Anything I can do about it? Thanks!

[10/5/2020, 11:26:11 AM] [AppleTvPlatform] [ATV Projector] Error while connecting: Error: Apple TV not found while scanning.

shahrafique commented 3 years ago

Greetings to all. Not sure whether it is the right place to post my issue or not. Please help and advise. I have installed homebridge-apple-tv-remote in my RP Hoobs.

But stopped the server frequently. Any suggestion? Also, like to know if there is refresh option for the connection. please help. Thank you very much!

brj5 commented 3 years ago

@brj5 Can you please provide debug logs so that the cause of your issue can be investigated?

I provided the logs in a post above, I retried this again and got the same error, I really want this to work so I can use Alexa with my tv.

njuart commented 3 years ago

Hi, looks like I also have a delay issue, at least it’s related to Play / Pause button. So when I press Play / Pause on AW, remote, AirPods I see that in Home app it changes state only after 30-40 seconds. Problem is that I have some automations in which this switch is involved and those are also being executed with the same delay which is quite annoying =( Besides that, if I press Play / Pause when it’s out of sync (during these 30-40 seconds) playback starts (or stops) and at the time it is synced it might be already in wrong state, meaning if playback is on, switch shows Pause state. Thx for any help in advance @lukasroegner

My setup is: RPi 3+ with native HB 1.2.3 Node.JS 12.19.0 NPM 6.14.18

kevinjohncutler commented 3 years ago

I'm also experiencing the same delay issue as @njuart, same setup as well. Strange thing is that it worked flawlessly for the first hour.

JDBem commented 3 years ago

@lukasroegner Thanks so much for this plugin, it's a great plugin!

I'm experiencing this same delay/out of sync play/pause button issue as @njuart has mentioned.

MacOS Node.js Version | v14.15.0 Npm Version | v6.14.8

try-and-error-and-repeat commented 3 years ago

Today I tried to connect my second Apple TV and did not gave him a unique Name for the Play Pause and the On Off Switch and it worked. So I tried the same with my first Apple TV with the "Out-Of-Sync-Problem" and it worked also. I'll take a closer look to that in the next few days but maybe it helps others also. My Config looks like this right now: { "name": "Apple TV 4K", "credentials": "4....a0e5", "isOnOffSwitchEnabled": true, "isPlayPauseSwitchEnabled": true }

iogitio commented 3 years ago

has anyone gotten on/off detection to work super reliably? It's not perfect on my end but hoping to figure this out so I can layer automation on top :)

Luke2kk commented 3 years ago

I do also experience a delay with the atv turn on/off switch. Is there a know reason behind?

linkx2252 commented 3 years ago

Today I tried to connect my second Apple TV and did not gave him a unique Name for the Play Pause and the On Off Switch and it worked. So I tried the same with my first Apple TV with the "Out-Of-Sync-Problem" and it worked also. I'll take a closer look to that in the next few days but maybe it helps others also. My Config looks like this right now: { "name": "Apple TV 4K", "credentials": "4....a0e5", "isOnOffSwitchEnabled": true, "isPlayPauseSwitchEnabled": true }

Just wanted to give this more visibility. I was having problems, I removed the unique name and it fixed it!

EvoSems commented 2 years ago

No Apple TVs found on the network. Try again. latest TVOS any work around? TIA

meltinsands commented 2 years ago

Like many others I have the connection problem since OS15: Apple has dropped the direct Media Remote Protocol support with iOS15 #114

Will you get your plugin working again?