[JAVA] Enregistrez le téléviseur compatible DLNA dans l'inventaire SORACOM et utilisez la console Web

introduction

Voici Yasukawa de Soracom. Inventaire SORACOM publié en version bêta publique au SORACOM Technology Camp tenu en avril / 04/26 / inventaire-public-release /) Avez-vous essayé les gars?

Comme vous pouvez le voir dans le blog lié, lors de la création de la bêta publique, nous l'avons publié sous la forme d'ajout de nouvelles fonctions basées sur les commentaires des clients qui l'ont essayé avec la bêta privée et la prévisualisation limitée, mais l'une des nouvelles fonctions La première est qu'il prend en charge les modèles personnalisés. Cette fois, j'aimerais profiter de cette fonction pour faire une plongée approfondie.

Dans l'inventaire SORACOM, l'agent en cours d'exécution sur l'appareil et le serveur côté SORACOM suivent le protocole de gestion d'appareils standardisé appelé OMA DM LwM2M. Communiquer. Au début de la version, seule la Définition d'objet standard était prise en charge, donc les appareils à usage général tels que les capteurs de température et les capteurs d'accélération Même s'il était possible de mettre en œuvre selon la définition existante, il y avait un problème en ce qu'il ne pouvait pas être correctement exprimé dans l'inventaire lorsque vous tentiez de connecter des périphériques qui ne répondent pas à la norme.

Comme son nom l'indique, la prise en charge du modèle personnalisé publiée cette fois vous permet d'enregistrer une définition de modèle d'objet arbitraire et de l'utiliser pour l'interprétation des messages lorsque le serveur et le périphérique interagissent sur SORACOM Inventory, ou pour l'affichage sur la console Web. C'est une fonction qui peut être effectuée. En d'autres termes, si vous utilisez cette fonction, vous pouvez enregistrer vos propres définitions et les gérer dans l'inventaire même si les types d'appareils et les spécifications ne sont pas définis dans la norme.

Cela a été une longue introduction, mais j'ai toujours voulu le faire depuis que je développais cette fonctionnalité, et j'ai toujours voulu écrire un article qui l'essaie réellement. Comme le titre l'indique, il s'agit de faire fonctionner le téléviseur devant vous avec SORACOM Inventory!

(En passant, ce blog est destiné à être un article que j'ai essayé sur Deep Dive, donc je suis proche de la date limite, mais je voudrais postuler pour Try SORACOM Challenge Campaign Je pense. "Cible: N'importe qui, quelle que soit l'entreprise ou l'individu, peut participer." Parce qu'il a été écrit, j'espère que ce sera une bonne nouveauté.)

Faire fonctionner un téléviseur compatible DLNA

De nos jours, la plupart des téléviseurs domestiques sont compatibles DLNA et sont connectés au réseau domestique via Ethernet ou WiFi. Je suis sûr que votre téléviseur à la maison communique également avec d'autres appareils via DLNA sur une base régulière. Si vous avez un tel environnement devant vous, vous pouvez réellement essayer ce qui est écrit dans ce blog.

Plus précisément, il s'agit de découvrir un téléviseur compatible DLNA avec UPnP, de se connecter au protocole OMA DM LwM2M SORACOM Inventory et de le faire fonctionner à partir de la console Web Inventory. (Désolé pour ceux qui sont allergiques à l'abréviation de l'alphabet, je pense qu'il y a une réaction de rejet, mais pour le moment, ce n'est pas grave si vous pensez que vous utilisez le téléviseur dans le désordre.)

Au moment du calendrier de l'Avent 2015, j'ai écrit un blog intitulé Discover Thing and Beam, mais à cette époque, j'ai découvert les téléviseurs compatibles DLNA avec UPnP Ensuite, c'était une histoire d'enregistrement et d'exploitation d'AWS IoT avec Beam MQTT. C'est facile à comprendre si vous pensez que MQTT, AWS IoT a été remplacé par LwM2M, SORACOM Inventory (facile à comprendre, n'est-ce pas?).

Au fait, à ce moment-là, j'ai créé quelque chose comme l'agent UPnP <-> MQTT avec node.js, mais dans le cas de SORACOM Inventory, la construction de l'agent à partir de la définition de modèle personnalisé est très fluide si vous utilisez la bibliothèque client Java, donc cette fois avec Java J'aimerais partir.

Comme pour la rédaction du blog précédent, j'aimerais mettre en œuvre cette fois-ci en me concentrant sur des cas d'utilisation tels que la lecture vidéo, l'augmentation / la diminution du volume et la reconnaissance de la mise sous / hors tension du téléviseur.

J'ai pris une vidéo du mouvement réel, alors jetez un œil ici pour avoir une idée de ce qu'il fait, et j'espère que vous comprenez que la procédure de mise en œuvre est décrite plus tard.

Contrôlez DLNA TV avec SORACOM Inventory

Je vais vraiment le faire

En tant que SDK pour l'inventaire SORACOM, la bibliothèque client Java de @ c9katayama est ouverte au public et le fichier Readme contient des Procédures détaillées de mise en œuvre de l'agent. /blob/master/README_ja.md) est écrit, donc ce sera facile si vous continuez en regardant cela.

Plus précisément, nous allons définir un modèle personnalisé pour DLNA TV, générer du code Java à partir du fichier de définition et le remplir.

1. Créez une définition de modèle personnalisée

La définition de modèle prend en charge XML et JSON. Cette fois, j'ai copié et édité l'exemple dans le Readme de la bibliothèque Java Client, donc c'est XML. Pour implémenter ce cas d'utilisation, le [Rendering Control Service] d'UPnP (http://upnp.org/specs/av/UPnP-av-RenderingControl-v1-Service.pdf) et le [AV Transport Service](http: / /www.upnp.org/specs/av/UPnP-av-AVTransport-v3-Service-20101231.pdf) est obligatoire, nous allons donc définir les paramètres d'action et les actions en se référant à chaque spécification.

Je m'inquiétais de la valeur de l'ID attaché à chaque ressource, mais pour le moment, j'ai décidé d'opter pour une option très grossière consistant à utiliser le numéro de section sur la spécification de chaque paramètre et action.

J'écrirai la définition des paramètres et des actions comme ceci.

resource-example.xml


  <Item ID="2216">
    <Name>Volume</Name>
    <Operations>R</Operations>
    <MultipleInstances>Single</MultipleInstances>
    <Mandatory>Mandatory</Mandatory>
    <Type>Integer</Type>
    <RangeEnumeration />
    <Units></Units>
    <Description>Current audio volume of the renderer</Description>
  </Item>

(J'en ai assez d'essayer de tout faire, je me suis donc concentré sur les cas d'utilisation que je voulais implémenter.)

Voici le fichier de définition d'objet terminé:

Si vous enregistrez ceci en tant que modèle personnalisé, les préparations du côté de l'inventaire SORACOM sont terminées et lorsque l'appareil sera en ligne après cela, l'élément correspondant apparaîtra automatiquement sur la console.

image.png

Pour plus de détails sur la définition du modèle d'objet personnalisé, reportez-vous à here.

2. Générez du code Java à partir du fichier de définition d'objet et implémentez la méthode

La bibliothèque cliente Inventory est excellente car elle prend également en charge la génération de fichiers de classe à partir de définitions d'objet, nous allons donc utiliser cette fonctionnalité.

Voici le code du générateur de source qui a été légèrement modifié pour générer un fichier de classe à partir du fichier créé dans la section précédente, faisant référence à l'exemple de code sur Github.

JavaSourceGenerator.java


package models;

import io.soracom.inventory.agent.core.util.TypedAnnotatedObjectTemplateClassGenerator;

import java.io.File;

public class JavaSourceGenerator {

    public static void main(String[] args) {
        String javaPackage = "models";
        File sourceFileDir = new File("src/main/java");
        TypedAnnotatedObjectTemplateClassGenerator generator = new TypedAnnotatedObjectTemplateClassGenerator(
                javaPackage, sourceFileDir);
        File[] modelFiles = new File("src/main/resources").listFiles();
        for (File modelFile : modelFiles) {
            generator.generateTemplateClassFromObjectModel(modelFile);
        }
        System.out.println("Finished generating Java source.");
        System.exit(0);
    }
}

Cela générera une classe correspondant au package models.

En regardant le contenu, cela ressemble à ceci.

UPnPRenderingControlServiceObject.java


package models;
import io.soracom.inventory.agent.core.lwm2m.*;
import java.util.Date;
import org.eclipse.leshan.core.node.ObjectLink;

/**
 * LwM2M device object model for UPnP Rendering Control service.
 **/
@LWM2MObject(objectId = 30001, name = "UPnP Rendering Control Service", multiple = true)
public class UPnPRenderingControlServiceObject extends AnnotatedLwM2mInstanceEnabler {

	/**
	 * Mute status of the renderer
	 **/
	@Resource(resourceId = 2215, operation = Operation.Read)
	public Boolean readMute()	{
		throw LwM2mInstanceResponseException.notFound();
	}

	/**
	 * Current audio volume of the renderer
	 **/
	@Resource(resourceId = 2216, operation = Operation.Read)
	public Integer readVolume()	{
		throw LwM2mInstanceResponseException.notFound();
	}

	/**
	 * Sets the renderer audio volume.
	 **/
	@Resource(resourceId = 2430, operation = Operation.Execute)
	public void executeSetVolume(String executeParameter)	{
		throw LwM2mInstanceResponseException.notFound();
	}
}

Après cela, vous pouvez l'implémenter pour qu'il appelle l'action UPnP correspondant à chaque méthode. On a l'impression de suivre le courant, donc c'est agréable de savoir quoi faire!

3. Implémentez chaque méthode correspondant à la ressource LwM2M

Cette fois, nous ciblons les appareils UPnP, nous allons donc l'implémenter ensuite à l'aide de la bibliothèque UPnP. J'ai décidé d'utiliser la bibliothèque de cling parce qu'elle semblait facile à utiliser.

Ajoutez ce qui suit à build.gradle et vous êtes prêt à partir.

build.gradle


apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'application'

repositories {
  mavenCentral()
  maven { url 'https://soracom.github.io/maven-repository/' }
  maven { url 'http://4thline.org/m2/' } // <-ajouter à
}

def INVENTORY_AGENT_VERSION="0.0.5"

dependencies {
    compile "io.soracom:soracom-inventory-agent-for-java-core:$INVENTORY_AGENT_VERSION"
    compile "org.fourthline.cling:cling-core:2.1.1" // <-ajouter à
    testCompile 'junit:junit:4.12'
}

jar {
    manifest {
        attributes "Main-Class": "App"
    }
}


mainClassName = 'App'

En regardant certaines des méthodes implémentées ʻUpnpRenderingControlServiceObject`, cela ressemble à ceci.

UpnpRenderingControlServiceObject.java


    /**
     * Current audio volume of the renderer
     **/
    @Resource(resourceId = 2216, operation = Operation.Read)
    public Long readVolume()	{
        ActionInvocation actionInvocation =
                new ActionInvocation(renderingControlService.getAction(ACTION_GET_VOLUME));
        actionInvocation.setInput(ARG_INSTANCE_ID, new UnsignedIntegerFourBytes(0));
        actionInvocation.setInput(ARG_CHANNEL, VALUE_CHANNEL_MASTER);
        Map<String, ActionArgumentValue> output = UpnpController.getInstance().executeUpnpAction(actionInvocation);
        return ((UnsignedIntegerTwoBytes)output.get(ARG_CURRENT_VOLUME).getValue()).getValue();
    }

    /**
     * Sets the renderer audio volume.
     **/
    @Resource(resourceId = 2430, operation = Operation.Execute)
    public void executeSetVolume(String executeParameter)	{

        ActionInvocation setVolumeInvocation =
                new ActionInvocation(renderingControlService.getAction(ACTION_SET_VOLUME));
        setVolumeInvocation.setInput(ARG_INSTANCE_ID, new UnsignedIntegerFourBytes(0));
        setVolumeInvocation.setInput(ARG_CHANNEL, VALUE_CHANNEL_MASTER);
        setVolumeInvocation.setInput(ARG_DESIRED_VOLUME, new UnsignedIntegerTwoBytes(executeParameter));
        UpnpController.getInstance().executeUpnpAction(setVolumeInvocation);
    }

En bref, cela ressemble à la conversion de la requête reçue par LwM2M en Action correspondante de UPnP. Les deux protocoles ont des concepts similaires sur la façon d'exprimer le périphérique, qui est la base, de sorte que la conversion était relativement facile.

Voici les deux fichiers qui ont été implémentés:

Si vous créez un agent qui implémente ces deux objets (et l'objet périphérique de base), vous pouvez l'enregistrer dans l'inventaire et le faire fonctionner avec l'API et la console utilisateur.

Cette fois, je l'ai fait avec le nom «MediaRendererAgent». Bien que non répertorié ici, si vous trouvez un périphérique UPnP, créez une classe distincte appelée ʻUpnpDeviceAgent` qui correspond à l'objet Device de LwM2M, et MediaRendererAgent en hérite et crée les deux objets définis cette fois. Il est fait pour être ajouté.

MediaRendererAgent.java


package org.yasukawa.inventory.upnp.media_renderer;

import org.fourthline.cling.model.meta.RemoteDevice;
import org.fourthline.cling.model.meta.Service;
import org.fourthline.cling.model.types.ServiceType;
import org.yasukawa.inventory.upnp.UpnpDeviceAgent;

public class MediaRendererAgent extends UpnpDeviceAgent {
    public static final String MEDIA_RENDERER_DEVICE_TYPE = "urn:schemas-upnp-org:device:MediaRenderer:1";
    public static final String RENDERING_CONTROL_SERVICE_TYPE = "urn:schemas-upnp-org:service:RenderingControl:1";
    public static final String AV_TRANSPORT_SERVICE_TYPE = "urn:schemas-upnp-org:service:AVTransport:1";
    public static final String ATTR_LAST_CHANGE = "LastChange";
    public static final String ATTR_INSTANCE_ID = "InstanceID";

    public MediaRendererAgent(RemoteDevice device){
        super(device);
        for ( Service service : device.getServices()){
            System.out.println(service.getServiceType());
            System.out.println(service.getServiceId());
        }
        super.initializer.addInstancesForObject(new UpnpRenderingControlServiceObject(
                device.findService(ServiceType.valueOf(RENDERING_CONTROL_SERVICE_TYPE)))
        );
        super.initializer.addInstancesForObject(new UpnpAvTransportServiceObject(
                device.findService(ServiceType.valueOf(AV_TRANSPORT_SERVICE_TYPE)))
        );
    }
}

4. Après avoir découvert le périphérique UPnP, créez un agent d'inventaire et enregistrez-le.

Si vous pouvez le faire jusqu'à présent, découvrez le périphérique UPnP, et si vous trouvez un Media Renderer tel qu'un téléviseur, créez une instance de Media Renderer Agent et enregistrez-la, et vous pourrez faire fonctionner le téléviseur avec l'API Inventory! chaud!

Avec cling utilisé cette fois, si vous démarrez Discovery après avoir enregistré une instance de la classe qui implémente l'interface appelée ʻUpnpRegistryListener` dans le point de contrôle UPnP, Il a été conçu pour que vous puissiez rappeler chaque fois que vous trouvez un appareil. Ainsi, après avoir reçu ce rappel, si le périphérique trouvé est Media Renderer, cela ressemble à une logique d'écriture pour créer une instance de Media Renderer Agent et la démarrer. Plus précisément, cela ressemble à ce qui suit.

InventoryUpnpRegistryListener.java


    @Override
    public void remoteDeviceAdded(Registry registry, RemoteDevice device) {
        logger.info("Device {} with type {} is added", device.getIdentity().toString(), device.getType().toString());
        if (MediaRendererAgent.MEDIA_RENDERER_DEVICE_TYPE.equals(device.getType().toString())){
            logger.info("Media renderer found: " + device.getDetails().getFriendlyName());
            MediaRendererAgent agent = new MediaRendererAgent(device);
            logger.info("Starting agent for {} and registering to SORACOM Inventory",
                    device.getIdentity().toString());
            agent.start();
            agentMap.put(device.getIdentity().toString(), agent);
        }
    }

    @Override
    public void remoteDeviceRemoved(Registry registry, RemoteDevice device) {
        logger.info("Device {} with type {} is removed", device.getIdentity().toString(), device.getType().toString());
        if (agentMap.containsKey(device.getIdentity().toString())){
            logger.info("Stopping agent for {} and deregistering from SORACOM Inventory",
                    device.getIdentity().toString());
            agentMap.remove(device.getIdentity().toString()).stop();
        }
    }

En passant, j'arrêterai l'agent lorsque surviendra l'événement de suppression de l'appareil. En faisant cela, si vous éteignez le téléviseur, même l'inventaire peut passer en mode hors ligne.

Enfin, enregistrez ce ʻUpnpRegistryListener` dans UPnP Control Point dans le fichier App.java principal et lancez Discovery, et vous avez terminé!

App.java


import org.fourthline.cling.UpnpService;
import org.fourthline.cling.UpnpServiceImpl;
import org.fourthline.cling.model.message.header.STAllHeader;
import org.yasukawa.inventory.upnp.InventoryUpnpRegistryListener;
import org.yasukawa.inventory.upnp.UpnpController;

public class App {

	public static void main(String[] args) throws Exception {

		UpnpService upnpService = new UpnpServiceImpl();
		UpnpController.initialize(upnpService);
		upnpService.getRegistry().addListener(new InventoryUpnpRegistryListener(upnpService));
		upnpService.getControlPoint().search(new STAllHeader());
	}
}

Je vais vraiment le déplacer

Le code créé cette fois-ci se trouve dans ce référentiel, et vous pouvez créer une archive zip pour distribution en suivant les étapes ci-dessous.

$ git clone https://github.com/kntyskw/inventory-upnp
$ cd inventory-upnp
$ gradle distZip

Si vous copiez le fichier . / Build / distributions / inventaire-upnp.zip créé avec ceci dans une tarte à la râpe, etc. ..

image.png

Après cela, déployez cette archive sur un appareil qui s'exécute en tant que passerelle UPnP telle que Raspeye et exécutez-la.

En passant, j'ai récemment utilisé resin.io, qui vous permet de déployer des conteneurs Docker sur des appareils IoT, comme moyen simple de déployer des logiciels sur Raspai. Pour plus de détails, veuillez consulter le site Web de la famille principale, mais si vous avez déjà configuré l'environnement de resin.io, vous pouvez déployer le conteneur mis à jour sur Raspai en suivant la procédure suivante.

$ git add inventory-upnp.zip
$ git commit -m "add/update inventory-upnp.zip"
$ git push resin master

De plus, vous pouvez SSH sur Rasppie à partir de la console Web de resin.io où que vous soyez, et redémarrer et mettre à jour les conteneurs à volonté. Veuillez l'essayer si vous le souhaitez.

Quelle que soit la procédure, après le déploiement et l'extraction de l'archive, exécutez la commande suivante dans le répertoire de destination.

$ ./bin/inventory-upnp

Ensuite, Raspai agira comme une passerelle UPnP, et si un téléviseur compatible DLNA est trouvé, il sera enregistré dans l'inventaire SORACOM et rendu opérationnel! À partir de là, vous pouvez opérer comme indiqué dans la vidéo au début.

image.png

en conclusion

Qu'as-tu pensé? Le concept de gestion des périphériques UPnP et LwM2M (plus précisément, OMA DM) est fondamentalement similaire, nous avons donc eu l'impression que nous étions en mesure d'enregistrer en douceur les périphériques UPnP dans l'inventaire SORACOM.

Cette fois, nous avons couvert UPnP, mais si le protocole dispose d'un mécanisme tel que la découverte, l'exécution de commandes et l'abonnement à l'événement, vous pouvez implémenter l'agent d'inventaire et le rendre disponible à partir de l'inventaire SORACOM. Par exemple, si vous utilisez Bonjour pour Apple TV, vous pouvez faire de même.

Cela signifie que si vous exécutez SORACOM Air SIM et Inventory Agent sur un appareil qui sera une passerelle de protocole, vous pouvez gérer tous les appareils environnants à partir d'Inventory. (Et avec la combinaison de SORACOM Air + Inventory, le partage des informations d'authentification vers la passerelle de protocole est automatique!) Pourquoi ne pas enregistrer vos appareils domestiques dans SORACOM Inventory afin de pouvoir les surveiller et les contrôler de n'importe où?

Au fait, comme je me souviens quand je me suis abonné à Discovery and Event, êtes-vous déjà abonné à l'événement SORACOM Discovery du 4 juillet? Si vous ne l'avez pas fait, le nombre de sièges restants diminue, mais je pense que ce sera à temps, alors veuillez postuler à partir de ce lien! Au fait, ce lien sera signalé comme mon introduction, alors veuillez ce lien ky) S'il vous plaît. (W persistant)

J'attends juste un vol de la Silicon Valley à Tokyo. Nous sommes impatients de discuter de sujets maniaques avec vous à nouveau cette année au SORACOM Discovery, y compris des choses comme UPnP et SORACOM Inventory!

Recommended Posts

Enregistrez le téléviseur compatible DLNA dans l'inventaire SORACOM et utilisez la console Web
21 Lire et exécuter le script à partir du fichier
Représentez graphiquement les informations du capteur de Raspberry Pi en Java et vérifiez-les avec un navigateur Web