Graphical front panel display

OK - that looks really interesting Matt. That would allow me to concatenate things like Channel Number and Chanel Name, Audio & Video Codecs and Resolution, Series and Episodes etc.

Exactly.

The earlier functionality is still present, too. So, one can make use of either prefix and suffix or specify a format_str.

1 Like

I just discovered this thread a few days ago and it is exactly what a wanted.
I have been using a usb attached hd44780 lcd for a few years and I am seriously thinking of “upgrading” it :grinning:

I have been playing a bit with the luma emulator to check how it work and it is very promising.

I just had one issue: I cannot get any thumb/artwork to display (I get stuck with the default thumb)
Maybe it is because I use an old version of kodi (14.2).
→ Have you an http request that I could send to Kodi to check if is an issue of my kodi config? (all info label work OK, and thumb is not working)

I have a few suggestions to make this project totally kickass :slight_smile:

Specific screen for each status of kodi eg:
screen when kodi is on home screen
screen when kodi is in screen saver
screen when music playing from library
screen when music playing from file
screen when video playing from movie library
screen when video playing from TVshow library
screen when video playing from file
screen for live TV
screen for PVR
screen for image playing
etc

I underestand that some of this is already ongoing.

Better codec handing:
You have a lookup table to change the displayed codec name (special treatment).
If a codec is unknown in the table (Eg: APE lossless), nothing is displayed, I think it would be better to send the raw value.
Also we could update the table with more codec, a list could be obtained from kodi skin:eg confluance skin

The “codec” name work only for with music.
You also created a “acodec” (line 1059 in kodi_panel_display.py) that work with the VideoPlayer.Codec info label that do not exist (at least in kodi 14.2)

I suggest using the VideoPlayer.AudioCodec to match this issue
When playing I have made some code modification to adress this issue and also created a “vcodec” to have the same thing for the video codec (eg x264, etc)

    # special treatment for audio codec, which gets a lookup
    if field_info["name"] == "acodec":
        if info['VideoPlayer.AudioCodec'] in codec_name.keys():            
           # render any label first
           if "label" in field_info: draw.text((field_info["lposx"], field_info["lposy"]), field_info["label"], fill=field_info["lfill"], font=field_info["lfont"])
           draw.text((field_info["posx"], field_info["posy"]), codec_name[info['VideoPlayer.AudioCodec']], fill=field_info["fill"], font=field_info["font"]) 
        else:
           # render any label first
           if "label" in field_info: draw.text((field_info["lposx"], field_info["lposy"]), field_info["label"], fill=field_info["lfill"], font=field_info["lfont"])
           draw.text((field_info["posx"], field_info["posy"]), info['VideoPlayer.AudioCodec'], fill=field_info["fill"], font=field_info["font"])  
                      
    # special treatment for video codec, which gets a lookup
    if field_info["name"] == "vcodec":
        if info['VideoPlayer.VideoCodec'] in codec_name.keys():            
           # render any label first
           if "label" in field_info: draw.text((field_info["lposx"], field_info["lposy"]), field_info["label"], fill=field_info["lfill"], font=field_info["lfont"])
           draw.text((field_info["posx"], field_info["posy"]), codec_name[info['VideoPlayer.VideoCodec']], fill=field_info["fill"], font=field_info["font"]) 
        else:
           # render any label first
           if "label" in field_info: draw.text((field_info["lposx"], field_info["lposy"]), field_info["label"], fill=field_info["lfill"], font=field_info["lfont"])
           draw.text((field_info["posx"], field_info["posy"]), info['VideoPlayer.VideoCodec'], fill=field_info["fill"], font=field_info["font"])   

Also a great addition for codec handling would be to display a thumbnail with the codec logo instead of just text. (codec logo thumbnail are available in kodi skin file)

Regarding other special treatment, I also created one to display channel number.
It is basically the same code as for codec lookup.
The feature to thumbnail logo image woul also be nice :slight_smile:

channel number lookup

ch_N = {
“1” : “1.0”,
“2” : “2.0”,
“3” : “2.1”,
“4” : “3.1”,
“5” : “4.1”,
“6” : “5.1”,
“7” : “6.1”,
“8” : “7.1”,
“10” : “9.1”,
}

and

            # special treatment for music channel number, which gets a lookup
    if field_info["name"] == "achannelnumber":
        if info['MusicPlayer.Channels'] in ch_N.keys():            
           # render any label first
           if "label" in field_info: draw.text((field_info["lposx"], field_info["lposy"]), field_info["label"], fill=field_info["lfill"], font=field_info["lfont"])
           draw.text((field_info["posx"], field_info["posy"]), ch_N[info['MusicPlayer.Channels']], fill=field_info["fill"], font=field_info["font"]) 
        else:
           # render any label first
           if "label" in field_info: draw.text((field_info["lposx"], field_info["lposy"]), field_info["label"], fill=field_info["lfill"], font=field_info["lfont"])
           draw.text((field_info["posx"], field_info["posy"]), info['MusicPlayer.Channels'], fill=field_info["fill"], font=field_info["font"])      
         # special treatment for video channel number, which gets a lookup
    if field_info["name"] == "vchannelnumber":
        if info['VideoPlayer.AudioChannels'] in ch_N.keys():            
           # render any label first
           if "label" in field_info: draw.text((field_info["lposx"], field_info["lposy"]), field_info["label"], fill=field_info["lfill"], font=field_info["lfont"])
           draw.text((field_info["posx"], field_info["posy"]), ch_N[info['VideoPlayer.AudioChannels']], fill=field_info["fill"], font=field_info["font"]) 
        else:
           # render any label first
           if "label" in field_info: draw.text((field_info["lposx"], field_info["lposy"]), field_info["label"], fill=field_info["lfill"], font=field_info["lfont"])
           draw.text((field_info["posx"], field_info["posy"]), info['VideoPlayer.AudioChannels'], fill=field_info["fill"], font=field_info["font"])                   

Also regarding info label retreive:
If I want to use new info label I need to update the setup.toml and also the Retrieve audio/video InfoLabels sections in kodi.

Is their a way to retreive all infolabels used on the active screen? (and only them?)

@nico1080 if you can think of ways of interrogating Kodi to work out which screen you are on - then you can implement different screens :slight_smile: - which are supported already.

I’ve got code that differentiates between video playing via PVR (Live/Recorded TV - check for channel number - which means you are in TV), TV Shows (from Library - check for TV Show Title - only exists for shows in TV Library), Movies and Video Files (Default if nothing else matches) etc.

My PVR screen shows TV Channel Number and Name labels for instance, my TV Show screen show both TVShow Title and Title (so you get the show and episode name). I’m about to add series and episodes to TV Show.

I’ve got VideoCodec, VideoResolution and AudioCodec displays on all my screens - but not using the look up table method (just showing raw at the moment).

@mblovell has implemented music from library as that was his original use case, as well as system settings.

@mblovell implemented touch as a means of switching between screens (info, full screen artwork, system info etc.). I don’t use touch displays so I just use static - though I’m kind of interested in a ‘dim after 30 seconds’ option as well as a ‘brighten when key pressed’ option (though these are quite radical changes potentially - as the display code needs to know when these have happened - and at the moment the display code polls Kodi rather than Kodi having a means of telling the display code what is going on - I think)

@noggin, Is it the code you mention in post 155 ?
I will try it (In fact and misread the topic and thought this change were already included in version 1.15 :blush:)

1.15 has only audio/video detection

For movie detection info label VideoPlayer.OriginalTitle seems to be populated on all my movie collection.

Do you have also idle status detection?

Regarding screen saver detection, I have no idea of how to do it, but on my old usb LCD witch used LCDproc addon from kodi 14.2 (openelec) it worrked, and it was was based on infolabel also.
So there should be a way :slight_smile:

Yes this code is what I have added as per @mblovell suggestion :

if VIDEO_LAYOUT_AUTOSELECT:
    if info["VideoPlayer.ChannelName"] != '':
        layout = VIDEO_LAYOUT["V_PVR"]
    elif info["VideoPlayer.TVShowTitle"] != '':
        layout = VIDEO_LAYOUT["V_TV_SHOW"]
    else:
        pass  # leave as-is

Then in setup.toml I have separate display configs for V_LAYOUT.V_DEFAULT and V_LAYOUT.V_PVR and V_LAYOUT.V_TV_SHOW

(I misremembered - we check for channel name not number to see if we are in PVR Live/Recorded TV)

I just had one issue: I cannot get any thumb/artwork to display (I get stuck with the default thumb)
Maybe it is because I use an old version of kodi (14.2).
–> Have you an http request that I could send to Kodi to check if is an issue of my kodi config? (all info label work OK, and thumb is not working)

Hard to say what’s at fault. Online documentation for Kodi’s JSON-RPC only goes back to Version 17. Any upgrade planned in your near future?

The process for cover art retrieval is essentially the following:

  1. Include MusicPlayer.Cover or VideoPlayer.Cover in the XBMC.GetInfoLabels JSON-RPC call that is performed after determining which player is active. That code is in the update_display() function.

  2. Within get_artwork(), invoke the JSON-RPC Files.PrepareDownload method. (See https://kodi.wiki/view/JSON-RPC_API#Redirected_file_download and nearby sections in the Kodi wiki.)

  3. Still in get_artwork(), use the URL returned from Step 2 to retrieve the file. The cover then gets resized to whatever the layout has specified. If get_artwork() fails to obtain a usable URL by the end of the function, it then falls back to default files.

I believe changes in previous versions of Kodi did occur in this area. The whole “prepare” step is new-ish and part of trying to make Kodi more secure.

Post #27 above has my earliest working JSON-RPC calls in Python. You can use that as a starting point. It should also be possible to play with command-line programs like curl or wget and Kodi’s web server – it’s just a pain to construct some of the longer calls by hand.

Specific screen for each status of kodi eg:
screen when kodi is on home screen
screen when kodi is in screen saver
screen when music playing from library
screen when music playing from file
screen when video playing from movie library
screen when video playing from TVshow library

Sound like you want a remote skin! :slight_smile:

Some of the above is indeed already implemented, but other aspects may be more difficult. I would recommend reading through what Kodi’s InfoLabels and JSON-RPC interface make available.

Do you have also idle status detection?

The update_display() function starts out by using a Player.GetActivePlayers call. If no players are active, Kodi is idle. The present implementation then leaves the display blank and the backlight (if it has that control) off. A touch interrupt while idle causes the status layout to be displayed momentarily. One could instead have the display constantly on and render something.

I don’t know at the moment whether Kodi’s screensaver state is available via JSON-RPC. Kodi may or may not make that state easily available – we are effectively running remotely, after all, not as a plugin.

You can always try some experiments, knowing you can get back to a previous version of kodi_panel_display.py from github. My usage of Kodi isn’t particularly broad, so I don’t have a direct means of testing much outside of music playback. Even with music, playback of local files, versus UPnP/DLNA, versus AirPlay all have slightly different behavior. It took some experimentation to figure out how things work.

If others develop solid code for their use cases, and it doesn’t collide with anything, the code can always be expanded!

Matt

1 Like

Kodi 18’s JSON-RPC does have

I think those fall into the “Notifications” category though. I suspect that Notifications only work when using WebSocket as the transport, rather than the HTTP that kodi_panel currently uses.

There are WebSocket modules for Python. I briefly experimented a little with it in posts above. Making use of notifications / callbacks would likely require using asyncio. That may be more than I want to bite off at this point!

For the thumb retrevial, I tried and http request on the MusicPlayer.Cover info label while play some music that have artwork --> empty result

I will try with a newer version of kodi, it will probably be a reason to update

Any luck, @nico1080?

Not yet, I have a spare android box, I will install latest kodi to check it, but it will probably be next weekend. :slight_smile:

I tried the code for videoscreen autoselection, it work good except for pvr recording (live TV OK)

I also added detection for movie using VideoPlayer.OriginalTitle

movie detection
if VIDEO_LAYOUT_AUTOSELECT:
    if info["VideoPlayer.ChannelName"] != '':
        layout = VIDEO_LAYOUT["V_PVR"]     # PVR TV shows
    elif info["VideoPlayer.TVShowTitle"] != '':
        layout = VIDEO_LAYOUT["V_TV_SHOW"] # Library TV shows
    elif info["VideoPlayer.OriginalTitle"] != '':
        layout = VIDEO_LAYOUT["V_movie"] # movie
    else:
        pass  # leave as-is, assumed good for video file

Slideshow.Path should also work for picture detection (I do not use it a lot) but image can also be viewed when music is playing

@noggin what version of pvr backend/kodi are you using?
I use tvheadend 4.2.8 with kodi 14.2 and for recorded TV i do not get channel number or name–> it get detected as video file

Maybe using the infolabel Player.Filenameandpath or Player.Folderpath will get better result.
For live TV I get response: {“Player.Filenameandpath”:“pvr://channels/tv/All channels/1.pvr”}}
For recorded TV I get response: {“Player.Filenameandpath”:"pvr://recordings///xxxxxxxxxxx
So basically:

  • if path start with pvr://channels–>liveTV
  • if path start with pvr://recordings–>recorded TV

Any ideas of How to do that? (I am not absolutely not a coder :blush:)

I also activated the status screen when idle by changing/commenting in this code section:

status screen deactivation

if ((not ‘result’ in response.keys()) or
len(response[‘result’]) == 0 or
response[‘result’][0][‘type’] == ‘picture’ or
(response[‘result’][0][‘type’] == ‘video’ and not VIDEO_ENABLED) or
(response[‘result’][0][‘type’] == ‘audio’ and not AUDIO_ENABLED)):
# Nothing is playing or something for which no display screen
# is available.
_kodi_playing = False

    # Check for screen press before proceeding.  A press when idle
    # generates the status screen.
    _last_image_path = None
    _last_image_time = None
    _last_thumb = None
    _static_image = None
    **_screen_active = True #to force status screen**

** #if _screen_press or touched:**
** # _screen_press = False**
** # _screen_active = True**
** # _screen_offtime = datetime.now() + timedelta(seconds=_screen_wake)**

    if _screen_active:
        # Idle status screen
        if len(response['result']) == 0:
            summary = "Idle"
        elif response['result'][0]['type'] == 'video':
            summary = "Video playing"
        elif response['result'][0]['type'] == 'picture':
            summary = "Photo viewing"

@nico1080 Are you playing recordings via the Recordings section of the TV Headend PVR add-on (and are thus playing them via the TV menu), or have you separately added the folder you are recording to as a Videos->Files location (and playing them via the Videos menu)? The behaviour will be different between the two.

When I play via the TV Route I get both channel name and channel number for my recordings, as well as TV Show title, Title and Plot. If I play them via the Videos route - then I don’t think any metadata is available other than filename and codecs etc. Please see attached screen grab of me playing a recording of BBC News from BBC One HD - Channel 115. (I’ve not had time to sort codec / resolution etc. code yet - this is a week old build still)

I’m running TV Headend build 4.3-1909 (which I compiled myself I think) and the TV Headend PVR version 4.4.21.1 which I downloaded from the CoreElec repo.

Hi Folks

Following along with great interest!

Wondering if it’s possible to use the 7" official Pi screen instead of these smaller options?

We’ve got a big-ish lounge room and I’ve tried various small screen options for things like this before, only to find them a bit difficult to read from 4 or 5m away. Apparently I’m getting older… :frowning:

The 7" screen should mean legible text on one side and good size cover art on the the other (almost CD size)…but the luma.lcd docs aren’t all that up to date with the LCD additions and I can’t find what controller the official 7" screen uses?

I’m not too fussed about cost and the 7" screen, in a case, with a Pi3B backing it, with this, seems like it would make a lovely second panel display.

(I’m a complete novice with electronics but fairly handy with Kodi and Python as I make & maintain several addons…)

Hi, @bossanova808. Yes, I think it should be possible, provided that display is driven from software via a framebuffer (e.g., /dev/fb0). If you have it up and running and have booted to a console (rather than X), you can check to see if that file exists. One “test” you can also try is whether executing

cat /dev/urandom > /dev/fb0

fills your display with white noise (even if slowly, since evidently /dev/urandom just slows down if it has insufficient entropy to ensure randomness).

The framebuffer support in luma.core should then be sufficient. I don’t think there’s any direct support in luma.core for DSI – or DPI – itself. With a framebuffer available, though, some other device driver is handling that lower-level aspect of the display.

You would make use of kodi_panel_display.fb.

Cheers,
Matt

Pimoroni seems to be maintaining a FAQ (well FAQ-ish thread) on that 7-inch display:

Pimoroni: Official 7" Raspberry Pi Touch Screen FAQ

I don’t have that particular display, so handling the touch interrupt and managing the backlight (if either feature is desired) may take a little hacking. It seems like there is backlight control via a

/sys/class/backlight/rpi_backlight/brightness

sysfs file, though. So, the PWM approach currently in kodi_panel_fb.py can be adapted to that.

@bossanova808 you shouldn’t need to use the luma.lcd stuff as that’s more for SPI LCD displays which aren’t supported directly at OS level (so luma.lcd adds output support for them).

For DSI, DPI, HDMI and Composite which already have OS level support, you should be able to go in at framebuffer level (which is what I’m doing with my DPI display) using kodi_panel_fb.py as @mblovell suggests.

I’d expect the DSI display to work fine - though if you are using a Pi 4B you may need to switch back to the older display driver framework (I had to for my DPI screen because of bit depth and rotation issues) - but I wouldn’t be surprised if you didn’t have to for the DSI screens.

@mblovell I tried with an android box with kodi 18.8. Image retreiving work good.
I just has an issue with some file for whitch the image adress started witth https
I just modified “http” instead of"http://" line 545 to allow both http and https

else:
_last_image_path = image_path
if image_path.startswith(“http”):
image_url = image_path

And it worked.

@noggin with new kodi I also get recorded tv detected as PVR. I don’t now if it is kodi or pvr addon issue.
Anyway, I still think that using the infolabel Player.Filenameandpath or Player.Folderpath will get better result as it will aloow to differentiate between live and recorded tv.

PVR/Live Tv detection

For live TV I get response: {“Player.Filenameandpath”:“pvr://channels/tv/All channels/1.pvr”}}
For recorded TV I get response: {“Player.Filenameandpath”:"pvr://recordings///xxxxxxxxxxx
So basically:

if path start with pvr://channels–>liveTV
if path start with pvr://recordings–>recorded TV

I tried with an android box with kodi 18.8. Image retreiving work good.
I just has an issue with some file for whitch the image adress started witth https
I just modified “http” instead of"http://" line 545 to allow both http and https

Thanks for the suggestion. Similar update pushed to github.

You are welcome :slight_smile:

One other suggestion for the setup.toml file would be to add a font size for each text field that override the size defined in the font setting.

It would avoid to create many font when you just want to make the text a bit bigger or smaller

One other suggestion for the setup.toml file would be to add a font size for each text field that override the size defined in the font setting.

It would avoid to create many font when you just want to make the text a bit bigger or smaller

Unfortunately, there is no “size” argument to the Pillow call that renders text. The font argument to the that text() function

ImageDraw.text() documentation

is an ImageFont instance. That ImageFont instance has to be created ahead of time, thus the loop to go through all user-specified fonts during startup.

Cheers,
Matt