Contrôler XBMC avec un Yocto-Display

Contrôler XBMC avec un Yocto-Display

Nous vous avons montré par le passé comment utiliser un écran Yoctopuce pour afficher des informations venant d'Internet, comme un flux RSS ou les événements d'un calendrier Google. Aujourd'hui nous allons voir comment un Yocto-Display peut être utilisé pour faire un panneau de contrôle actif pour le media center XBMC.



Pour fabriquer le panneau de contrôle, nous avons besoin d'un Yocto-Display et de six boutons pour les actions haut,bas, gauche, droite, ok, retour.

Le Yocto-Display et le Yocto-MaxiDisplay ne sont pas que des écrans: ils embarquent l'équivalent d'un Yocto-Knob. En plus de la fonction display (qui permet de d’interagir avec l'écran) et de la fonction files (qui permet d'uploader des images ou des fonts), ils disposent aussi de 6 fonctions anButton qui permettent de mesurer l'état de composant résistifs (interrupteurs, boutons poussoir, potentiomètres, etc.). Ces 6 fonctions peuvent être utilisées avec les mini boutons présents sur le board. Il est aussi possible de souder ses propres boutons sur les pads prévus.

Le Yocto-Display avec 6 boutons externes
Le Yocto-Display avec 6 boutons externes



Pour réaliser ce panneau de contrôle, nous allons écrire un petit script Python qui récupère le titre du film en lecture, l'affiche sur le Yocto-Display, et qui transmet à XBMC les commandes de navigation quand un bouton est pressé.

L'API de XBMC


Pour interagir avec XBMC, nous allons utiliser l'API JSON-RPC qui est installée automatiquement. Cette API permet de simuler n'importe quel bouton d'une télécommande, mais aussi de récupérer des informations sur le film (ou mp3) qui est diffusé. Cette API suit le protocole JSON-RPC, et est documenté sur la page web du projet (http://kodi.wiki/view/JSON-RPC_API). Par défaut cette API est désactivée, pour l'utiliser il faut activer l'option "Allow control of XBMC via HTTP" dans le menu "Webserver" (disponible dans la section "Service" des paramètres).

Pour utiliser l'API JSON-RPC il faut activer l'option Allow control of XBMC via HTTP
Pour utiliser l'API JSON-RPC il faut activer l'option Allow control of XBMC via HTTP



Il existe plusieurs librairies Python qui implémentent uniquement ce protocole, mais nous avons décidé d'utiliser la librairie requests qui permet d'écrire n'importe quelle requête basée sur le protocole HTTP.

Une requête JSON-RPC n'est rien de plus qu'une requête HTTP POST avec une structure JSON qui contient le nom de la fonction à appeler (champ "method") et les paramètres de cette fonction (champ "params").

Pour communiquer avec XBMC, on implémente une classe SimpleXMBC qui contient une méthode json_rpc_request qui prend en argument le nom de la fonction XBMC et ses paramètres, et qui retourne le résultat de la requête. Cette classe contient les méthodes up(), down(), right(), left(), ok(), back() et get_player_info() qui appellent la méthode json_rpc_request avec les bons paramètres.

class SimpleXMBC(object):
        def __init__(self, host, port, user, password):
        self._url = 'http://%s:%d/jsonrpc' % (host, port)

        def json_rpc_request(self, method, params):
        headers = {'content-type': 'application/json'}
        payload = {
            "method": method,
            "params": params,
            "jsonrpc": "2.0",
            "id": 0,
        }
        response = requests.post(
            self._url, data=json.dumps(payload), headers=headers).json()
        if 'error' in response:
            print(response['error'])
        return response

        def up(self):
        self.json_rpc_request('Input.Up', {})


    ....

xbmc_interface = SimpleXMBC('localhost', 80, 'xbmc', 'password')
xbmc_interface.up()



Le script Python


Le reste du script est assez semblable à l'exemple Prog-EventBased qui est fournit avec la librairie Python Yoctopuce. On enregistre les fonctions de callback qui sont appelées chaque fois qu'un module est branché et à chaque changement de valeur d'une fonction. Si vous n'avez jamais utilisé les fonctions RegisterDeviceArrivalCallback() ou registerValueCallback(), il est fortement conseillé lire l'article suivant qui décrit l'utilisation de callack de l'API Yoctopuce.

Pour transmettre les commandes ("up", "down", etc) à XBMC chaque fois qu'un bouton est pressé, il faut appeler la méthode correspondante de notre objet xbmc_interface depuis la fonction an_button_callback().

La fonction principale est composé d'une boucle sans fin qui appel YAPI.UpdateDeviceList() et YAPI.Sleep(). Dans cette boucle sans fin, on récupère le titre à l'aide de l'appel xbmc_interface.get_info_to_display(), et on rafraîchit l'écran avec ces informations. La fonction principale va donc effectuer les tâches suivantes en boucle:

  1. afficher sur l'écran le titre du film
  2. vérifier si il faut appeler les callbacks de connexion/déconnexion
  3. vérifier pendant 1 seconde si il faut appeler les callbacks de changement de valeurs.

L'écran n'est rafraîchi qu'une fois par seconde, mais pour ce genre d’application c'est amplement suffisant.

Ce script fonctionne donc à la fois en "polling" et en "callback". La gestion des boutons est traité en "callback", alors que l'écran est mit à jour en "polling".

def an_button_callback(anbutton, value):
    if (anbutton.get_isPressed() == YAnButton.ISPRESSED_TRUE):
        last = anbutton.get_userData()
        if last == YAnButton.ISPRESSED_FALSE:
            funcid = anbutton.get_functionId()
            if funcid == 'anButton1':
                xbmc_interface.up()
            elif funcid == 'anButton2':
                xbmc_interface.down()
            elif funcid == 'anButton3':
                xbmc_interface.left()
            elif funcid == 'anButton4':
                xbmc_interface.right()
            elif funcid == 'anButton5':
                xbmc_interface.ok()
            elif funcid == 'anButton6':
                xbmc_interface.back()
    anbutton.set_userData(anbutton.get_isPressed())

....

def main():
    errmsg = YRefParam()
    YAPI.RegisterDeviceArrivalCallback(device_arrival)
    YAPI.RegisterDeviceRemovalCallback(device_removal)
    if YAPI.RegisterHub("usb", errmsg) < 0:
        print("Unable register usb :" + str(errmsg))
        return -1

    while True:
           progress, title = xbmc_interface.get_info_to_display()
        for display in display_list:
            w = display.get_displayWidth()
            h = display.get_displayHeight()
            layer0 = display.get_displayLayer(0)
            layer0.selectGrayPen(0)
            layer0.drawBar(0, 0, w - 1, h - 1)
            layer0.selectGrayPen(255)
            layer0.drawText(w / 2, h / 2, YDisplayLayer.ALIGN.CENTER, title)
            if progress > 0:
                layer0.drawBar(0, h - 1, int(progress * w / 100), h - 1)
            display.swapLayerContent(0, 1)
        YAPI.UpdateDeviceList()
        YAPI.Sleep(1000)



Le code complet est disponible sur GitHub à l'adresse http://github.com/yoctopuce-examples/xbmc_remote.

Conclusion


  
Et voilà la preuve que ça marche :-)



En moins de 200 lignes, nous avons implémenté un panneau de contrôle pour XBMC. Et comme la librairie Yoctopuce n'a pas besoin de driver, il fonctionne d'emblée sur n'importe quel OS (Windows, Linux et OSX). Trop facile :-)

Commenter 2 commentaires Retour au blog



1 - eti.que Dimanche 11 septembre 2016 9H15

Bonjour,

Petite question, auriez vous des pistes pour faire contrôler l'écran MaxiDisplay par LCDProc ?

Merci !

2 - martinm (Yocto-Team)Lundi 12 septembre 2016 10H15

@eti.que: a priori, le plus simple serait de contacter l'équipe de LCDProc, mais comme leur site n'a pas été mis à jour depuis 4 ans, ça risque d'être un peu compliqué. La meilleur piste serait de:

1.Télécharger les sources
2.Vérifier que vous arrivez à les compiler correctement
3.Comprendre comment marche le support pour les écrans graphiques ( contrôleurs SED1330, SED1520 et T6963)
4.Ajouter le support pour les Yocto-MaxiDisplay de manière similaire

Mais c'est un gros boulot. Il serait peut-être plus facile de repartir à zéro.


Yoctopuce, get your stuff connected.