"Después del juego es antes del juego"
Sepp Herberger

martes, 5 de diciembre de 2017

Instalar un panel informativo en el IES.

A los centros eScholarium se enviaron unos paneles informativos para poner en sitios visibles y poder publicar contenidos de interés para la comunidad educativa. Por desgracia, mi centro no estaba entonces en ese programa y no nos llegó nada.

Pero por fortuna teníamos una antigua TV plana (en realidad relativamente plana, es de las primeras que salieron y tiene un grosor de mas de 10cm) que estaba ociosa después de instalar cañones de vídeo en casi todas las aulas, y pensamos en rescatarla para hacer nuestro propio panel informativo. Como no es una Smart TV, para darle la parte smart hace falta un elemento externo, que ha sido un sencillo PC con una modesta CPU Intel Atom (aunque bien podría servir un miniportátil de alumno, una Raspberry Pi, una Android TVBox o incluso un móvil antiguo o tablet con salida HDMI). Una vez montada quedará así:


Mi idea es instalar un Xubuntu pelado con un usuario local que haga autologin y abra un navegador que reproduzca el contenido de una página web a pantalla completa, en modo "kiosco". La página web en mi caso está en el mismo PC desde donde se reproduce todo, pero igualmente podría estar en un servidor del centro (lo cual sería imperativo en el caso de usar una SmartTV o un dispositivo Android).

Para ello tenemos un script panel.sh que hace:
#!/bin/bash
firefox http://localhost/intranet/panel.html?tipo=slide & # Tipo video, flow, slide, panel
sleep 10
xdotool search --sync --onlyvisible --class "Firefox" windowactivate key F11
Este script se ejecuta al iniciar sesión desde un fichero /etc/xdg/autostart/panel.desktop usual. El comando xdotool envia a Firefox una pulsación simulada de la tecla F11, con lo cual se pone a pantalla completa, sin decoración de barras de ningún tipo.

Lo que usamos es un fichero .html lo mas versátil posible, con la siguiente estructura:

  • En la parte izquierda tenemos una zona donde se proyecta la información, luego lo veremos pero la idea es poder proyectar presentaciones de Google Slides, vídeos y otras fuentes de información.
  • En la parte superior derecha pondremos un widget meteorológico, con la predicción del tiempo en Cáceres. El usado es el generado en la página tiempo.es
  • En la parte inferior derecha pondremos un reloj-calendario hecho en Javascript a partir de este ejemplo con algunos retoques estéticos y de idioma .
  • Debajo del reloj nos sobra un pequeño espacio y ponemos allí el logotipo del IES.

Como la idea es que la parte de proyección pueda mostrar varios contenido incluimos un parámetro "tipo" que pasaremos en la URL y que puede tomar 4 valores (en el script panel.sh anterior se ve como se pasa dicho parámetro al hacer la petición, por ejemplo: http://localhost/intranet/panel.html?tipo=slide):

  • video: para proyectar vídeos en formato mp4. Normalmente actividades del IES. Permite reproducir un array de vídeos en bucle continuo. Los vídeos tienen un tamaño de 1280x720 y un bitrate de aproximadamente 1000kbps, dando una calidad suficiente y sin necesitar mucha potencia para reproducirlos. Si no lo tenemos en ese formato lo podremos convertir con la utilidad avconv (avconv -i input.mp4 -s 1280x720 output.mp4).
  • flow: para proyectar vídeos en el viejuno formato flv, usa el widget flowplayer, basado en Flash. Tienen menor calidad y gasta mas recursos de cpu que los mp4, pero ya tenía contenidos previos en dicho formato de otros años y no quería perder la posibilidad de proyectarlos.
  • slide: para proyectar presentaciones de Google Slides compartidas de forma pública por su creador (explicado en Embed a document, spreadsheet, or presentation).
  • panel: para mostrar el contenido de la URL http://panelinformativo.educarex.es, que es el sistema de gestión de los paneles oficiales de la Consejería. Los usuarios autorizados de cada centro pueden entrar a través de http://panelinformativo.educarex.es/login y dar de alta noticias y/o mensajes (con fechas configurables de activación y caducidad), que serán mostradas en la URL antes citada de forma automática en formato "carrusel" (filtrando lo mostrado en centro en función de la IP peticionaria, claro está). Este es el sistema que tienen los paneles enviados por la Consejería .

Cada vez que queremos cambiar los vídeos o la presentación debemos editar el fichero panel.html. Ya sé que eso es hard coding pero no me he puesto a automatizar la configuración mediante ficheros externos. Dentro del código HTML que pongo a continuación marco en rojo las partes que habría que cambiar para adaptar a las circunstancias de cada cual. También he cambiado la IP del pc donde están los contenidos web poniendo 172.X.Y.Z.

La página está calculada para una resolución de 1360x768, siendo todas las anchuras expresadas en pixeles para cuadrar perfectamente. La parte del vídeo/presentación tiene un ancho de 1000px aproximadamente y la de los widgets unos 330px. En caso de usar otras resoluciones habría que ir probando hasta que cuadrase.

Empezamos viendo la parte HEAD de panel.html. En ella definimos los CSS de los widget tiempo y reloj, así como todo el javascript necesario:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html style="height: 100%;">
<head>
  
  <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">
  <title>panel.html</title>

  <!-- ======================================================================================================================================================= -->
  <!--Importante: poner la IP fija definitiva. Si no se pone, no funciona. Nada de localhost.-->
  <!-- ======================================================================================================================================================= -->

  <!-- ======================================================================================================================================================= -->
  <!-- Antiguo Widget Flowplayer basado en flash para videos .flv --->
  <!-- ======================================================================================================================================================= -->
  <script src="http://172.X.Y.Z/intranet/javascript/flowplayer-3.2.8.min.js"></script>
  <script src="http://172.X.Y.Z/intranet/javascript/jquery.js" type="text/javascript" charset="utf-8"></script>
  <script src="http://172.X.Y.Z/intranet/javascript/flowplayer.playlist-3.2.8.min.js" type="text/javascript" charset="utf-8"></script>

  <style type="text/css">
        a.player {
            display: block;
            width: 560px;
            height: 420px;
            text-align: center;
            text-decoration: none;
            cursor: pointer;
            background: #333333;
        }

        a.player img {
            margin-top: 110px;
            border: 0;
            opacity: 0.8;
            filter: alpha(opacity=80);
        }

        a.player img:hover {
            opacity: 1;
            filter: alpha(opacity=100);
        }


        a.player {
            margin-top: 0px;
            width: 500px;
        }
  </style>  

  <!-- ======================================================================================================================================================= -->
  <!-- CSS Reloj -->
  <!-- ======================================================================================================================================================= -->

  <style type="text/css">
 body{
   font:bold 12px Arial, Helvetica, sans-serif;
   margin:0;
   padding:0;
   color:#bbbbbb; 
 }

 a { 
  text-decoration:none; 
  color:#00c6ff;
 }

 h1 {
  font: 4em normal Arial, Helvetica, sans-serif;
  padding: 20px; margin: 0;
  text-align:center;
 }

 h1 small{
  font: 0.2em normal  Arial, Helvetica, sans-serif;
  text-transform:uppercase; letter-spacing: 0.2em; line-height: 5em;
  display: block;
 }

 h2 {
     font-weight:700;
     color:#bbb;
     font-size:50px;
 }

 h2, p {
  margin-bottom:10px;
 }

 @font-face {
     font-family: 'BebasNeueRegular';
     src: url('fonts/BebasNeue-webfont.eot');
     src: url('fonts/BebasNeue-webfont.eot?#iefix') format('embedded-opentype'),
   url('fonts/BebasNeue-webfont.woff') format('woff'),
   url('fonts/BebasNeue-webfont.ttf') format('truetype'),
   url('fonts/BebasNeue-webfont.svg#BebasNeueRegular') format('svg');
     font-weight: normal;
     font-style: normal;

 }

 .container {width: 300px; margin: 0 auto; overflow: hidden;}

 .clock {width:280px; margin:0 auto; padding:5px; border:1px solid #333; color:#fff; }

 #Date { font-family: Arial, 'BebasNeueRegular', Helvetica, sans-serif; font-size:20px; text-align:center;  }

 ul { width:280px; margin:0 auto; padding:0px; list-style:none; text-align:center; }
 ul li { display:inline; font-size:50px; text-align:center; font-family: Arial, 'BebasNeueRegular', Helvetica, sans-serif; }

 #point { position:relative; -moz-animation:mymove 1s ease infinite; -webkit-animation:mymove 1s ease infinite; padding-left:10px; padding-right:10px; }

 @-webkit-keyframes mymove 
 {
 0% {opacity:1.0; text-shadow:0 0 20px #00c6ff;}
 50% {opacity:0; text-shadow:none; }
 100% {opacity:1.0; text-shadow:0 0 20px #00c6ff; } 
 }


 @-moz-keyframes mymove 
 {
 0% {opacity:1.0; text-shadow:0 0 20px #00c6ff;}
 50% {opacity:0; text-shadow:none; }
 100% {opacity:1.0; text-shadow:0 0 20px #00c6ff; } 
 }

  </style>
  <script type="text/javascript" src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
  <script type="text/javascript">
 $(document).ready(function() {
 // Create two variable with the names of the months and days in an array
 var monthNames = [ "Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre" ]; 
 var dayNames= ["Domingo","Lunes","Martes","Miércoles","Jueves","Viernes","Sábado"];

 // Create a newDate() object
 var newDate = new Date();
 // Extract the current date from Date object
 newDate.setDate(newDate.getDate());
 // Output the day, date, month and year    
 $('#Date').html(dayNames[newDate.getDay()] + " " + newDate.getDate() + ' ' + monthNames[newDate.getMonth()] + ' ' + newDate.getFullYear());

 setInterval( function() {
  // Create a newDate() object and extract the seconds of the current time on the visitor's
  var seconds = new Date().getSeconds();
  // Add a leading zero to seconds value
  $("#sec").html(( seconds < 10 ? "0" : "" ) + seconds);
  },1000);
 
 setInterval( function() {
  // Create a newDate() object and extract the minutes of the current time on the visitor's
  var minutes = new Date().getMinutes();
  // Add a leading zero to the minutes value
  $("#min").html(( minutes < 10 ? "0" : "" ) + minutes);
     },1000);
 
 setInterval( function() {
  // Create a newDate() object and extract the hours of the current time on the visitor's
  var hours = new Date().getHours();
  // Add a leading zero to the hours value
  $("#hours").html(( hours < 10 ? "0" : "" ) + hours);
     }, 1000);
 
 }); 
  </script>

  <!-- ======================================================================================================================================================= -->
  <!-- Codigo Javascript para poner carrusel de Videos modernos: mp4 y webm. -->
  <!-- ======================================================================================================================================================= -->
  <script type="text/javascript">

      var videoSources = ["videos/terror.mp4"]; //Array con la lista de videos a reproducir
      var currentIndex = 0;

      //listener function changes src
      function myNewSrc() {
           var myVideo = document.getElementsByTagName('video')[0];
           myVideo.src = videoSources[currentIndex];
           myVideo.load();
      }
      // add a listener function to the ended event
      function myAddListener(){
           var myVideo = document.getElementsByTagName('video')[0];
           currentIndex = (currentIndex+1) % videoSources.length;
           myVideo.src = videoSources[currentIndex];
           myVideo.addEventListener('ended', myNewSrc, false);
      }
  </script>


  <!-- ======================================================================================================================================================= -->
  <!-- Codigo Javascript para ver que tipo de objeto se muestra (video normal, presentacion google o video flv en función del parametro get de la url tipo=XXX -->
  <!-- ======================================================================================================================================================= -->

  <script type="text/javascript">

      // analiza el queryString buscando el parametro tipo=XXX en la URL para decidir que mostrar.
      function muestraDiv() {

        var params = {};
        params.tipo="video"; // video, slide, flow, panel, ... Por defecto, video
        if (location.search) {
            var parts = location.search.substring(1).split('&');

            for (var i = 0; i < parts.length; i++) {
                var nv = parts[i].split('=');
                if (!nv[0]) continue;
                params[nv[0]] = nv[1] || true;
            }
        }
        divVideo=document.getElementById("div-video");
        divSlide=document.getElementById("div-slide");
        divFlow=document.getElementById("div-flow");
        divPanel=document.getElementById("div-panel");
        switch (params.tipo) {
                  case "video": 
                        purgaElemento(divSlide);
                        purgaElemento(divFlow);
                        purgaElemento(divPanel);
                        divVideo.style.display = 'block';     
                        myNewSrc(); //Carga el primer video
                        break;
                  case "slide":
                        divSlide.style.display = 'block';  
                        purgaElemento(divFlow);
                        purgaElemento(divVideo);
                        purgaElemento(divPanel);
                        break;
                  case "flow":
                        divFlow.style.display = 'block';  
                        purgaElemento(divSlide);
                        purgaElemento(divVideo);
                        purgaElemento(divPanel);
                        break;
                  case "panel":
                        divPanel.style.display = 'block';  
                        purgaElemento(divSlide);
                        purgaElemento(divVideo);
                        purgaElemento(divFlow);
                        break;
        }
      }
      
      function purgaElemento(oDiv) {
            oDiv.style.display = 'none';     
            oDiv.outerHTML = "";
            delete oDiv;
      }

  </script>
    
</head>
En la parte BODY definimos una tabla para formatear las partes la página (lo siento, aprendí HTML en los años 90 y sigo formateando con tablas en lugar de con DIV+CSS) y llamamos a la funcion javascript muestraDiv, que analiza el parámetro tipo y decide cual de los cuatro div (div-video, div-slide, div-flow o div-panel) mostrar, ocultando y destruyendo los otros tres.

Para el reloj y el widget tiempo pongo el código html que se generaba en las respectivas páginas de donde los he sacado:

<body style="height: 90%;" bgcolor="#000815"  onload="muestraDiv();">  <!--  muestraDiv-> decide que div aparece -->
   <table width="100%" style="height: 100%;" >
        <tr valign="middle">
           <td rowspan="2">

                <!-- ======================================================================================================================================================= -->
                <!-- UN DIV PARA CADA TIPO DE CONTENIDO MOSTRADO. SOLO UNO ES VISIBLE, LOS OTROS SE OCULTAN Y DESTRUYEN                                                      -->
                <!-- ======================================================================================================================================================= -->
               
                <!-- ======================================================================================================================================================= -->
                <!-- VIDEO MP4/WEBM                                                                                                                                          -->
                <!-- ======================================================================================================================================================= -->
                <div id="div-video" style="display: none">
                        <video width="990" poster="logo.png" height="740" autoplay preload="auto" controls id="miVideo" onended="myAddListener()" >
                          <source src="" type="video/mp4" />
                          Your browser does not support the video tag.
                        </video>
                </div>
                <!-- ======================================================================================================================================================= -->
                <!-- SLIDE                                                                                                                                                   -->
                <!-- ======================================================================================================================================================= -->
                <div id="div-slide" style="display: block"> <!-- si lo intentamos ocultar da error en la carga inicial -->
                        <div style="width:1000px;height:720px;overflow:hidden;" >  <!-- esto es para ocultar la barra de controles -->
                                  <iframe src="https://docs.google.com/presentation/d/e/2PACX-1vQ4WA8UkpxrJeeDdQOI-wIQ7S9kEpNoHZYpXxUvorCir-gTVoo2fWVyLN8VShiDivdbvtHZy4w1VRD1/embed?start=true&loop=true&delayms=5000" 
                                        frameborder="0" width="1000" height="750" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true">
                                </iframe>
                        </div>
                </div>
                <!-- ======================================================================================================================================================= -->
                <!-- PANEL                                                                                                                                                   -->
                <!-- ======================================================================================================================================================= -->
                <div id="div-panel" style="display: none">
                        <div style="width:1000px;height:750px;overflow:hidden;" >  <!-- esto es para ocultar la barra de controles -->
                                  <iframe src="http://panelinformativo.educarex.es" 
                                        frameborder="0" width="1000" height="750" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true">
                                </iframe>
                        </div>
                </div>
                <!-- ======================================================================================================================================================= -->
                <!-- VIDEO FLASH                                                                                                                                             -->
                <!-- ======================================================================================================================================================= -->
                <div id="div-flow" style="display: none">
                        <script>
                                $(function() {
                                    // set up player without "internal" playlists
                                    $f("player", "http://172.X.Y.Z/intranet/javascript/flowplayer-3.2.9.swf", {
                                        clip: { baseUrl: 'http://172.X.Y.Z/intranet/videos/antiguos' }
                                    // use playlist plugin. again loop is true
                                    }).playlist("#myplaylist", {loop:true});
                        });
                        </script>
                        <div style="float:left" id="myplaylist">
                             <a href="LipDub2016.flv"></a>
                             <a href="video-estetica.flv"></a>
                        </div>
                        <!-- player container without nested content -->
                        <a class="player" id="player"  style="width:1000px;height:750px;float:left"  href="videos/antiguos/bachillerato.flv"></a>
                </div>
                <!-- ======================================================================================================================================================= -->
                <!-- FIN DIVs                                                                                                                                                -->
                <!-- ======================================================================================================================================================= -->
           </td>
           <td width="330px" height="200px">        
             <!-- ======================================================================================================================================================= -->
             <!-- WIDGET TIEMPO                                                                                                                                           -->
             <!-- ======================================================================================================================================================= -->
             <div style="height:390px; width:330px; overflow-x:hidden; " valign="center">                               
                   <div id="tiempo_033974258b5fb50f89ccd5071c8f4f8c"> 
                   <div></div>
                   <div> 
                       <img src="//www.tiempo.es/build/img/logo/tiempo133.png" width="80" height="18" alt="tiempo.es"> </div> 
                       <script type="text/javascript" src="//www.tiempo.es/widload/es/ver/320/340/010/es0ca0037/033974258b5fb50f89ccd5071c8f4f8c.js">
                       </script> 
                   </div>
             </div>
           </td>
        </tr>
        <tr valign="top" align="middle">
           <td>
              <!-- ======================================================================================================================================================= -->
              <!-- WIDGET RELOJ                                                                                                                                           -->
              <!-- ======================================================================================================================================================= -->
              <div class="container">
                <div class="clock">
                <div id="Date"></div>
                        <ul>
                            <li id="hours"> </li>
                            <li id="point">:</li>
                            <li id="min"> </li>
                            <li id="point">:</li>
                            <li id="sec"> </li>
                        </ul>
                </div>
              </div>
              <br/>
              <img src="logo.png" width="290px" height="210px"/>
           </td>
        </tr>
   </table>

</body></html>
El código html completo de panel.html y varias cosas más podemos descargarlo de aquí. No olvidemos adaptar las IP y los nombres de los vídeos, ficheros de imagen, enlaces a presentaciones y el widget del tiempo a nuestro caso particular.

El resultado final que aparece en la pantalla es:



Bueno, pues con todo esto ya tenemos nuestra pantalla hecha con materiales de derribo.

viernes, 1 de diciembre de 2017

Desactivando la red wifi de 5Ghz en DLink DIR-860L con dd-wrt

Nuestros puntos de acceso DLink traen de serie 2 wifis: la de 2.4Ghz y la de 5Ghz, cada una con SSID y gestión de contraseñas independiente. La mayoría de los portátiles de los que disponemos en los centros solo ven la red de 2.4Ghz y los programas de gestión (SiaticControl y ControlWifi) que tenemos solo manejan esa frecuencia.

Como consecuencia de ello la red de 5Ghz estará ociosa a no ser que la configuremos a mano via ssh o interfaz web. Como algunos de nosotros queremos dejarla apagada en tanto en cuanto no la necesitemos estuve investigando como hacerlo entrando por ssh al DLink.

Lo que hacemos cambiar el SSID y contraseña que trae por defecto dicha red e indicar que el comando "ifconfig ba0 down" se ejecute en el arranque del sistema dd-wrt. El interface "ba0" es el correspondiente a la red de 5Ghz (en el caso de la de 2.4Ghz es "ra0"):
nvram set wl1_ssid=NUEVO_SSID_5GHZ
nvram set wl1_wpa_psk=NUEVA_PASSWORD_5GHZ
nvram set rc_startup="ifconfig ba0 down"
nvram commit
reboot
Y con esto nos despedimos hasta una nueva pildorita sobre nuestros DLink.