home-assistant-libs / aioslimproto

SLIMProto implementation in async python allows you to control squeezebox players (and compatibles)
Apache License 2.0
7 stars 5 forks source link

Attempting to play media on Squeezelite-ESP32 with Display throws "image index out of range" #359

Open JamiePhonic opened 3 weeks ago

JamiePhonic commented 3 weeks ago

I appear to have encountered an issue attempting to play media to a Squeezelite-ESP32 device with a display attached which causes both Home Assistant (through the SlimProto integration) and MusicAssistant (Through its own SlimProto provider) to throw an IndexError: image index out of range exception

In Home Assistant this causes the media playback to fail entierly. In Music Assistant, (Assuming "Enable Display Support" is enabled in the advanced settings of the player configuration) the media will still play, but the device volume will consistently reset to 20%. Also, if a Visualiser is enabled, this displays correctly.

The display i'm currently using is a 160x128 Adafruit ST7735 TFT, though i have ordered a Waveshare ST7789 2" 240×320 display to try to rule out the issue being the current display simply being too small.

The Exception trace from Home Assistant is below. I have had a skim though the code in display.py and can't immediatley see anything that jumps out as a potential culprit but sadly i dont think i'm familiar enough with Python to be able to debug this myself.

Logger: homeassistant.components.websocket_api.http.connection
Source: components/websocket_api/commands.py:241
integration: Home Assistant WebSocket API (documentation, issues)
First occurred: 01:40:46 (4 occurrences)
Last logged: 01:42:20

[140457385637584] Unexpected exception
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/websocket_api/commands.py", line 241, in handle_call_service
    response = await hass.services.async_call(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/core.py", line 2763, in async_call
    response_data = await coro
                    ^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/core.py", line 2806, in _execute_service
    return await target(service_call)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 999, in entity_service_call
    single_response = await _handle_entity_call(
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 1071, in _handle_entity_call
    result = await task
             ^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/slimproto/media_player.py", line 213, in async_play_media
    await self.player.play_url(media_id, mime_type=to_send_media_type)
  File "/usr/local/lib/python3.12/site-packages/aioslimproto/client.py", line 413, in play_url
    await self.power(powered=True)
  File "/usr/local/lib/python3.12/site-packages/aioslimproto/client.py", line 299, in power
    await self._render_display()
  File "/usr/local/lib/python3.12/site-packages/aioslimproto/client.py", line 549, in _render_display
    await self.display_control.set_lines(fullscreen=time_str)
  File "/usr/local/lib/python3.12/site-packages/aioslimproto/display.py", line 162, in set_lines
    await self._render_display()
  File "/usr/local/lib/python3.12/site-packages/aioslimproto/display.py", line 185, in _render_display
    data = await asyncio.get_running_loop().run_in_executor(None, pack)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/aioslimproto/display.py", line 179, in pack
    to_set = 1 if pixmap[col, 31 - bit] else 0
                  ~~~~~~^^^^^^^^^^^^^^^
IndexError: image index out of range
JamiePhonic commented 3 weeks ago

Okay, so i cloned the repo and took a crack at debugging it myself. It took most of the day but i think the issue is in display.py and might be related to this on line 174: pixmap = self.image.load()

It seems that self.image has a resolution of 128x32. I assume that since my display is bigger than that, it's causing the "image index out of range" exception as it tries to index outside of that range (in my case, 160x128)

I can see self.image being instantiated on line 115: self.image = Image.new("1", (width, 32)) I noticed the comment specifying that "Height can only be 32". Is there a specific reason for that?

I added self.logger.debug("Called _render_display with resolution %s x %s", self.width, self.height) directly above def pack() (plus the required supporting code) and it outputs Called _render_display with resolution 160 x 128 which would suggest the player is correctly reporting its display resolution?

Unfortunatley i don't really know how i'd go about trying to fix this but i'm willing to give it a shot