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

jueves, 8 de febrero de 2018

Acceso directo una camara IP Dlink DCS-5000L.

Tenemos una cámara IP DCS-5000L que cumple todas las expectativas de un dispositivo de este tipo: interface web, acceso y control remoto (mediante un motor para girar el objetivo), grabación, detección y aviso de movimiento y/o sonido, visión nocturna....

Además de esto echaba en falta poder acceder desde fuera, con programas mas potentes y versátiles como motion (que ya usamos con OpenWrt anteriormente) o su estupendo frontend para videovigilancia motionEye.

Ya puestos en tarea, por su buena calidad de imagen veía interesante usarla poder usar para videoconferencias o emisiones de vídeo grupales, con Google Hangouts, Skype o similares.

Por todo ello vamos a tratar en este post como conectarnos a ella con aplicaciones diferentes al tradicional navegador e ir probando cosas a ver hasta donde llegamos.

1) Acceso directo al stream de vídeo/audio.

Lo primero es acceder a las imágenes y audios de forma directa, sin pasar por el interface web, el cual tiene este aspecto:


Como vemos la visualización de las imágenes está basada en tecnologías rabiosamente nuevas como Flash, Java y ActiveX. El interface permite ver, oír, mover la cámara y acceder a su configuración.

Normalmente en foros no oficiales aparecen las URL de acceso directo a los streams de audio y vídeo de las cámaras IP de Dlink, pero para esta webcam no había manera de encontrarlos. Afortunadamente mi buen compañero David usó sus oscuras artes de teleco para llegar a acceder y pasarme esto:

  • Foto: http://192.168.0.112:8080/image/jpeg.cgi. Descarga un jpg con una foto fija tomada de forma instántanea con la cámara. Podemos tomarla con :
    wget -O imagen.jpg http://192.168.0.112:8080/image/jpeg.cgi
  • Vídeo: http://192.168.0.112:8080/video.cgi. Emite un stream de vídeo en tiempo real con formato MJPEG y resolución de 640x480 píxeles. Podemos verlo con:
    vlc http://192.168.0.112:8080/video.cgi
  • Audio: http://192.168.0.112:8080/audio.cgi. Si hemos activado el audio en la cámara y subido el volumen del micro lo suficiente accederemos al stream de audio del micrófono. Nos llega como un wav en formato PCM de 16bits de frecuencia 11025Hz. Podemos oírlo en directo con:
    vlc http://192.168.0.112:8080/audio.cgi
De esta manera podríamos monitorizar la cámara con motion usando el parámetro netcam_url:
# cat /etc/motion/motion.conf:
.....
.....
netcam_url http://192.168.0.112:8080/video.cgi
.....
.....
Como vemos aparte de acceder a cámaras locales, motion permite controlar cámaras de red. Incluso podríamos hacer cosas mas interesantes, como activar la grabación de sonido ante un evento detección de movimiento.

2) Reproducción en ventana independiente y grabación.

El siguiente paso es ver si podemos reproducir el flujo de vídeo en una ventana independiente usando esa navaja suiza de los streams multimedia que es gst-launch.

Empecemos con:
gst-launch-1.0  souphttpsrc location=http://192.168.0.112:8080/video.cgi ! jpegdec ! autovideosink
Básicamente cogemos el stream remoto, lo pasamos por el plugin "jpegdec" que decodifica los fotogramas jpeg que forman la imagen y lo volcamos en el sink (un sink es un sumidero donde acaba el stream tras pasar por los plugins) autovideosink, que muestra el vídeo con una fluidez estupenda en una ventana independiente tal que así:


De esta manera logramos ver la cámara en directo prescindiendo de Flash, Java y demás puñetas anteriores al Holoceno.

Gstreamer tiene plugins y filtros de todo tipo, como por ejemplo este para girar la imagen 90º:
gst-launch-1.0  souphttpsrc location=http://192.168.0.112:8080/video.cgi ! jpegdec ! videoflip method=clockwise ! autovideosink
Aquí tenemos varios ejemplos más. Estos son todos los plugins y sinks aplicables.

Ahora vamos a por el stream de audio. Por ejemplo, veremos como grabar el audio a un fichero, primero con mplayer:
mplayer http://192.168.0.112:8080/audio.cgi  -ao pcm:file=/tmp/mystream.wav -vc dummy
Y ahora con gst-launch:
gst-launch-1.0 souphttpsrc location=http://192.168.0.112:8080/audio.cgi ! filesink location=/tmp/mystream.wav
Ahora oímos el sonido en directo (ojo, si estamos en la misma habitación el sonido acaba acoplándose con un chirrido irritante), como si fuese un micrófono espía :
gst-launch-1.0 souphttpsrc location=http://192.168.0.112:8080/audio.cgi ! wavparse ! autoaudiosink
Lo mismo, pero reproduciendo el sonido por pulseaudio:
gst-launch-1.0 souphttpsrc location=http://192.168.0.112:8080/audio.cgi ! wavparse ! pulsesink 
Ahora juntamos ambos streams (audio y vídeo) para reproducirlos a la vez:
gst-launch-1.0  souphttpsrc location=http://192.168.0.112:8080/video.cgi ! jpegdec ! autovideosink  souphttpsrc location=http://192.168.0.112:8080/audio.cgi ! wavparse ! autoaudiosink
Si hacemos pruebas veremos que el audio va con un retraso de varios segundos respecto al vídeo. Después de varias pruebas concluyo que es algo ineludible, tiene pinta de ser una feature de la cámara.

3) Vídeo remoto como local: dispositivo /dev/videoX y loopback.

Vamos un paso mas allá: ¿y si queremos usar la cámara para una aplicación de videoconferencia, tipo Skype o Hangouts? ¿Y si queremos hacer una captura del vídeo para algún tipo de procesado con cheese? Estas aplicaciones no trabajan con cámaras remotas, sino que lo hacen con dispositivos físicos /dev/videoX creados al conectar una fuente de vídeo USB o PCI.

¿Podemos hacer que la cámara IP sea accedida en /dev/videoX como una local? Pues sí, Linux es maravilloso. Todo pasa por crear un dispositivo de vídeo virtual, que hará aparecer un /dev/videoX y luego podremos conectar el stream de vídeo de la cámara a dicho dispositivo. Esto se consigue con el driver v4l2loopback.

Para Ubuntu 14.04 ésta es la versión ya compilada (para Manjaro/Arch sería ésta). Los pasos para descargarlo y cargar en memoria el módulo son:
# wget https://launchpad.net/ubuntu/+archive/primary/+files/v4l2loopback-dkms_0.10.0-1_all.deb
# apt-get install v4l-utils
# dpkg -i v4l2loopback-dkms_0.10.0-1_all.deb
# rmmod v4l2loopback
# modprobe v4l2loopback -r
# modprobe v4l2loopback devices=1 exclusive_caps=1 video_nr=1 card_label="virtualvideo1"
Con esto se carga el módulo v4l2loopback en memoria y se crea un dispositivo virtual /dev/video1. Podemos comprobarlo con:
# v4l2-ctl --list-devices
De momento este dispositivo está vacío. Si abrimos vlc o cheese leyendo de él no se muestra nada. Hay que conectar el stream remoto de la cámara con el módulo v4l2loopback, el cual a su vez lo hará emerger por /dev/video1.

Esto lo hacemos con gst-launch usando el sink "v4l2sink" para enviar los datos a /dev/video1:
gst-launch-1.0  souphttpsrc location=http://192.168.0.112:8080/video.cgi ! jpegdec ! tee ! v4l2sink device=/dev/video1 sync=false
O también podemos usar ffmpeg (en ubuntu se instala antes desde un PPA).
ffmpeg -re -f mjpeg -i http://192.168.0.112:8080/video.cgi  -f v4l2 -vcodec rawvideo -pix_fmt yuv420p /dev/video1
En las pruebas realizadas con Google Hangouts, usando ffmepg la transmisión de vídeo hacia el dispositivo virtual y al cliente remoto es más fiable, estable y fluida que con gst-launch. Recomendamos por tanto usar ffmpeg sobre gst-launch para enviar el stream de la cámara al dispositivo v4l2loopback.

Para ampliar, aquí tenemos documentados varios métodos de enviar fuentes de vídeo a v4l2loopback.

Una vez creado /dev/video1 estas son las pruebas que he hecho:
  • Con vlc leyendo de /dev/video1 ("vlc v4l2:///dev/video1") la imagen se ve sin problemas.
  • Con cheese no funciona a la primera, pero quitando "exclusive_caps=1" al cargar el módulo si funciona.


  • Con Google Hangouts: he tenido problemas (no detección de la cámara) según la versión de Google Chrome y Firefox. En Chromium si ha funciona correctamente.


  • Con Skype: no lo he probado por los problemas que da con Linux últimamente, pero debe funcionar según el enlace comentado anteriormente.

Resumiendo: podemos usar la cámara IP cómo si fuera una cámara local, tanto para programas de captura de vídeo tipo cheese como para una videoconferencia con Hangouts o Skype. Las ventajas son:
  • Tiene mejor calidad que una cámara USB normal.
  • Puede colocarse en sitios que permiten tomas panorámicas para videconferencias grupales.
  • Conectados al interfaz web estándar de la webcam podemos girar/mover la cámara remotamente durante la emisión.




4) Videoconferencia con sonido.

El módulo v4l2loopback transmite vídeo, pero no sonido. En el apartado 1 y 2 hemos oído el sonido remoto recogido por la cámara en el PC local, pero para videconferencias habría que tratar el sonido remoto como una fuente de sonido (vamos, que el sistema vea el stream entrante como un micrófono). Después de varias pruebas con pulsesink y distintas configuraciones de pulseaudio según este ejemplo se consigue conectar el audio remoto con ciertas aplicaciones:

gst-launch-1.0 souphttpsrc location=http://192.168.0.112:8080/audio.cgi ! wavparse ! pulsesink 

En este ejemplo anterior redirigimos el sonido del stream por la tarjeta HDMI y luego emerge en los Dispositivos de Salida, permitiendo realizar una grabación con un tercer programa (un grabador de audio en nuestro caso).

¿Esto podría usarse para videoconferencias? En teoría si, en la práctica no porque los programas de videoconferencia que he probado solo aceptan entrada de sonido de micrófonos reales, no de streams que provienen de una fuente remota o de un "monitor of ..." en pulseaudio.

Seguramente hay una manera de convertir el stream en un micrófono virtual (como hicimos con el vídeo y /dev/videoX) encadenando módulos loobpacks y null de pulseaudio, o como se comenta en diversos foros usando jackaudio , pero realmente no merece la pena. El sonido de la cámara llega con tanto retraso que desmerece el conjunto y hace vano el esfuerzo.

Mi conclusión es que es mucho más cómodo usar un micro local estándar conectado al PC desde donde hacemos la videoconferencia, de tal manera que el vídeo proviene de la cámara mediante v4l2loopback, pero el audio se recoge de forma directa por el PC, despreciando el stream de audio que genera la cámara.

Aquí una captura de pantalla de una videoconferencia de Google Hangouts mediante Chromium Browser. La imagen "ojo de pez" es la imagen de la cámara web y el sonido se recoge con un micro normal y corriente.


En la parte inferior derecha en pequeñito está la imagen tomada por el receptor, que es un móvil apuntando a la cámara web :-).

Otra imagen usando visión nocturna:


Recordemos, como dijimos en el anterior apartado, que para videoconferencias con Hangouts da mucho mejor resultado usar ffmpeg (y no gst-launch) para enviar el flujo de vídeo a v4l2loopback.

5) Emisión RTSP.

Por último, también puede ser interesante usar los streams de audio y vídeo para crear una emisión RTSP emitiendo por la red lo capturado por la cámara de forma que cualquier receptor pueda "sintonizarnos".

Esto son solo varias pinceladas para abrir las posibles vías de prueba:
  • Usando v4l2rtspserver: al parecer genera una emisión rtsp a partir de un dispositivo v4l2 (como v4l2loopback) y una fuente de sonido. Los paquetes .deb están aquí. Ademas necesita v4ltools, que hay que compilar a mano.
    El github de Michel Promonet, de donde viene esto, tiene varios proyectos muy interesantes para la emisión de vídeo.
  • Usando gstreamer: por desgracia gst-launch por si solo no es capaz de redigir el vídeo hacia rtsp. Existe una solución de pago en la que se usa un sink llamado gstrtspsink que es a su vez un servidor rtsp. Podemos pedirles una versión de evaluación.
  • Usando gstreamer para emisión rtp, mas sencilla que la de rtsp:
    # gst-launch-1.0 souphttpsrc location=http://192.168.0.112:8080/video.cgi !  jpegdec ! rndbuffersize max=1316 min=1316  ! udpsink host=127.0.0.1 port=5000  
    
    Para la recepción hace falta un fichero .sdp, pero no le he dedicado mucho tiempo a hacerlo funcionar.
  • Usando una utilidad específica para montar un rtsp server: el problema es que la mayoría son sistemas profesionales de pago (por poner un ejemplo: este o este otro). He encontrado algo sencillo y gratuito hecho en perl. Compilamos según las instrucciones y arrancamos el servidor:
    # /usr/local/share/perl/5.18.2/RTSP/rtsp-server.pl
    Arrancamos la fuente de vídeo/audio:
    # ffmpeg -re -f mjpeg -i http://192.168.0.112:8080/video.cgi -i http://192.168.0.112:8080/audio.cgi -f rtsp  -muxdelay 0.1 rtsp://127.0.0.1:5545/abc
    
    La recepción se haría:
    # vlc rtsp://127.0.0.1/abc
    En las pruebas realizadas la emisión se ve pixelada y el audio viene con retraso. Utilizando audio con micro local y jugando con parámetros de ffmpeg seguramente se pueda mejorar.
  • Usando ffserver, una herramienta más de la suite FFmpeg. Tomamos este texto como guía:
    # cat /etc/ffserver.conf
    
    Port 8090
    BindAddress 0.0.0.0
    MaxClients 1000
    MaxBandwidth 10000         
    
    <feed feed1.ffm>
    File /tmp/feed1.ffm
    FileMaxSize 5M
    </Feed>
    
    <stream camara1.avi>
    Feed feed1.ffm
    Format mpjpeg
    VideoFrameRate 25
    VideoIntraOnly
    VideoSize 640x480
    NoAudio
    Strict -1
    </Stream>
    
    <stream stat.html>
    Format status
    </Stream>
    
    Arrancamos el servidor:
    # ffmpeg -re -f mjpeg -i http://192.168.0.112:8080/video.cgi  http://localhost:8090/feed1.ffm
    
    La recepción se haría en la URL:
    http://localhost:8090/camara1.avi
    Esto es sin sonido, para añadir audio debemos emitir en formato .webm.
    # cat /etc/ffserver.conf
    
    Port 8090
    BindAddress 0.0.0.0
    MaxClients 1000
    MaxBandwidth 10000         
    
    <feed feed1.ffm>
    File /tmp/feed1.ffm
    FileMaxSize 5M
    </Feed>
    
    <stream camara1.flv>
    Feed feed1.ffm
    Format webm
    
    # Audio settings
    AudioCodec vorbis
    AudioBitRate 64          # Audio bitrate
    
    # Video settings
    VideoCodec libvpx
    VideoSize 640x480        # Video resolution
    VideoFrameRate 25        # Video FPS
    AVOptionVideo flags +global_header  # Parameters passed to encoder
    # (same as ffmpeg command-line parameters)
    cpu-used 0
    AVOptionVideo qmin 10
    AVOptionVideo qmax 42
    AVOptionVideo quality good
    AVOptionAudio flags +global_header
    PreRoll 15
    StartSendOnKey
    VideoBitRate 400         # Video bitrate
    
    </Stream>         
    
    <stream stat.html>
    Format status
    </Stream>
    
    Empezamos emisión:
    # ffmpeg -re -f mjpeg -i http://192.168.0.112:8080/video.cgi -i  http://192.168.0.112:8080/audio.cgi
    
    Y conectamos con el navegador:
    http://localhost:8090/feed1.ffm
    Como antes, se ve pixelado y con el audio retrasado. La solución sería la planteada en su momento: audio local con micrófono y ajuste de opciones de ffmpeg.

Hasta aquí todo por ahora, creo que le hemos sacado a la cámara todo el jugo que le podíamos sacar.

No puedo evitar despedirme con una de las imágenes mas emocionantes de los últimos años: los dos side boosters del Falcon Heavy de SpaceX aterrizando al unísono:


Gracias Elon y buen viaje a Starman en su Tesla hacia la órbita de Marte.



martes, 30 de enero de 2018

Instalación de una aplicación mediante wine para todos los usuarios.

Hace poco me pidieron instalar la aplicación PhotoFiltre en Ubuntu ya que necesitaban usar una aplicación sencilla de retoque fotográfico. Solo tiene versión Windows, pero tras descargar el instalador y lanzarlo con wine confirmé que era totalmente funcional.

El problema que tiene wine es que la instalación de las aplicaciones va asociada al usuario, lo cual me obligaría a instalar la misma aplicación una y otra vez en todas las cuentas necesarias. En este caso la única molestia es el tiempo perdido apretando una y otra vez la misma tuerca, pero en aplicaciones que ocupan mucho espacio tenemos además el problema del disco desperdiciado con instalaciones idénticas en el home de cada alumno/profesor.

Según recuerdo con Codeweavers Crossover podías hacer una sola instalación de una aplicación Windows en una bottle (wine->bottle, son unos cachondos) y reusar luego esa bottle en distintas cuentas de usuario. Pero Crossover es de pago y yo tengo que usar wine de forma gratuita.

Así que buscando una manera de hacer una única instalación por máquina encuentro ésto y pruebo a ponerlo en práctica:

Creamos un usuario "windows" local con home en /var/home (para no interferir con nuestro /home en NFS):
# adduser --home /var/home/windows windows
Hago login con el nuevo usuario, descargo el PhotoFiltre y los ficheros de idioma español y los instalo con:
$ wine pf7-setup-en-7.2.1.exe
Después instalo el idioma español copiando el fichero según comentan en la página del programa.

El programa se ha instalado como es normal en wine, en la ruta:
/var/home/windows/.wine/drive_c/Program\ Files\ \(x86\)/PhotoFiltre\ 7/
habiéndose creado un acceso directo en el escritorio del usuario "windows". Si lo lanzamos desde dicho acceso directo se abre y funciona sin problema.

El reto está en hacer que funcione para los otros usuarios de la máquina sin tener que volver a instalarlo. Para ellos vamos a hacer uso de "sudo", que nos permitirá adoptar la identidad del usuario "windows" y ejecutar el programa desde otras sesiones de usuario. Empezamos tocando en el fichero sudoers:
# cat /etc/sudoers
..........
..........
# Configuracion Wine:
User_Alias WINDOWS_USERS = %teachers
Cmnd_Alias WINDOWS = /usr/bin/wine,/usr/bin/winecfg,/var/home/windows/pf7

Defaults:WINDOWS_USERS env_reset
Defaults:WINDOWS_USERS env_keep += DISPLAY
Defaults:WINDOWS_USERS env_keep += XAUTHORITY

WINDOWS_USERS ALL = (windows) NOPASSWD: WINDOWS

En este sudoers damos permisos a todos los usuarios del grupo "teachers" (aquí especificaremos los usuarios o grupo de usuario que queramos) a ejecutar wine, winecfg y el script /var/home/windows/pf7 con la identidad del usuario "windows". El contenido del script pf7 sería:
# cat /var/home/windows/pf7
#!/bin/bash
env WINEPREFIX="/var/home/windows/.wine" wine C:\\Program\ Files\ \(x86\)\\PhotoFiltre\ 7\\PhotoFiltre7.exe
exit 0
Lo que hace es fijar un WINEPREFIX en el directorio donde está wine y lanzar el ejecutable. Esta ruta está sacada del interior archivo .desktop que comentamoss anteriormente, creado por la aplicación en el escritorio durante su instalación con wine.

Ahora tenemos que establecer el medio para que los otros usuarios arranquen el script /var/home/windows/pf7 con la identidad del usuario "windows". Para ello definimos un nuevo script en una carpeta accesible para todo el mundo:
# cat /usr/bin/pf7
#!/bin/bash
xhost +
sudo -u windows -H /var/home/windows/pf7
exit 0
En él ponemos "xhost +" para permitir al usuario "windows" abrir aplicaciones dentro de nuestra sesión Xorg y hacemos el "sudo .../var/home/windows/pf7" para ejecutar el programa con la identidad "windows" sin que nos pida contraseña alguna.

Por último nos hace falta un fichero .desktop para poner en el escritorio de los usuario que vayan a ejecutar la aplicación:
# cat PhotoFiltre7.desktop
[Desktop Entry]
Name=PhotoFiltre 7
Exec=/usr/bin/pf7
Type=Application
StartupNotify=true
Path=/usr/bin
Icon=/usr/share/icons/hicolor/pf7.png
El icono /usr/share/icons/hicolor/pf7.png lo he extraido del .EXE con la aplicacion wrestool:
# wrestool -x fichero.exe -o .
Ultimando las cosas hemos creado una carpeta /wine con propietario "windows" y mapeado z: y "Mis Documentos" sobre ella usando winecfg con la cuenta "windows". De esta manera la aplicación podrá guardar sus datos en una carpeta accesible y fácil de encontrar.



Para finalizar, bloqueamos el login en la cuenta "windows", para que nadie trastee con ella y solo esté accesible a través de sudo:
# passwd -l windows
Y con esto ya tenemos hecha la tarea. A modo de recapitulación las ventajas son:
  • Realizamos una sola instalación y configuración por máquina, ahorrando espacio y trabajo.
  • Si la aplicación se estropea o deja de funcionar (en aplicaciones wine no es infrecuente, ya que el usuario tiene acceso total a la carpeta Archivos de Programa) no tenemos nada más que hacer una copia previa del directorio .wine con tar.gz y descomprimirla para dejar todo otra vez funcionando para todos los usuarios.
Y los inconvenientes:
  • Todos los usuarios de un mismo PC comparten la misma aplicación y carpeta de datos en /wine.
  • La aplicación va vinculada a la máquina y no al usuario. Si se mueve a otro PC no tiene acceso a sus datos o incluso puede no tener acceso a la aplicación
Por tanto, corresponde a cada cual valorar si merece o no la pena hacerlo así o de la forma tradicional.

Vamos que nos vamos.



lunes, 15 de enero de 2018

Poner las aplicaciones de Manjaro en español después una instalación fresca.

Después de instalar nuestro Manjaro XFCE en el primer arranque nos pide que instalemos los paquetes de idioma. Con las ansias de empezar a enredar lo dejamos para mas tarde y cerramos la ventana...de tal forma que luego no lo vuelve a pedir más veces y nos encontramos con que Firefox, Libreoffice y otras cosas están en inglis.

¿Cómo instalamos los paquetes de idiomas perdidos? Podemos ir al Gestor de Paquetes y buscarlos uno a uno, pero Manjaro nos tiene un sistema mejor para hacerlo de forma centralizada y ordenada.

Nos vamos al Gestor de Configuración de Manjaro en el menú:


Ahí elegimos "Configuración de idioma":


En esta ventana podemos ver los paquetes de idiomas instalados y los disponibles:


Con el botón de "Instalar paquetes" podemos elegir nuevos paquetes para añadir a las distintas aplicaciones:


Y ya está. Sencillo e indoloro, como todo en Manjaro.

domingo, 14 de enero de 2018

Como meter un recovery en Android desde linea de comandos.


Un dispositivo android tiene varios modos de arranque, desde un modo "mayormente muerto" (como el Pirata Roberts de La princesa prometida) hasta el modo completamente funcional.


Un modo muy usado si queremos trastear con el móvil es el "modo recovery", pero para sacarle toda su potencialidad normalmente nos vemos obligados a sustituir el recovery que trae por defecto el terminal por otro con más opciones. Aquí describiremos como meter un recovery nuevo mas potente a un dispositivo android.

Antes de entrar en faena y a modo de repaso para que no se me olvide, voy a enumerar los modos de los cuales tenemos noticia:

1. Modo normal/system.

Es el modo usual, con el dispositivo arrancado y funcional. Podemos interactuar con el mediante la pantalla táctil o mediante adb, conectándolo a un PC con el cable USB y enviando comandos hacia él.

El adb es además la vía mas sencilla y universal para reiniciar el móvil en los otros modos.

2. Modo recovery.:

En este modo el dispositivo arranca en un entorno restringido, que permite hacer varias tareas de mantenimiento que nos facilitan enredar con el dispositivo. Aquí el móvil se maneja con la pantalla táctil y/o los botones laterales y no es funcional en el sentido usual, ya que no se llega a cargar el sistema android.

Muchos móviles traen un stock recovery por defecto muy limitado, pero afortunadamente la comunidad ha creado recoverys sustitutos bastante avanzados, como CWM o TWRP.

Stock recovery, como vemos bastante insulso:


Recovery CWM, aquí hay mas opciones:


Recovery TWRP, con un GUI bonito y encima táctil:


Algunas de las funcionalidades que traen estos recoverys vitaminados son:

  • Cargar nuevas ROMs.
  • Hacer un reset de las distintas particiones y datos.
  • Instalar aplicaciones especiales, tipo SuperSU (para rootear) o Xposed (para añadir funcionalidades variadas).
  • Formateo, borrado, creación y montaje de particiones de la memoria SD interna del móvil.

Aquí y acá viene mejor explicado.

Para arrancar el móvil en recoverý suele haber una combinación especial de teclas de encendido o bien usando adb, como podemos ver aquí.

3. Modo fastboot/bootloader.

En este modo el móvil no puede ser manejado por su pantalla o botones, pero si podemos interactuar con él usando un cable USB y la utilidad fastboot.

Muchas veces tenemos un móvil brickeado (se queda congelando arrancando) o en bootloop (reinicia continuamente sin cargar el sistema). En estos casos si conseguimos ponerlo en modo fastboot tendremos una vía para restaurar o arreglar el sistema.

Normalmente se entra desde adb con el comando "adb reboot bootloader", aunque algunos dispositivos tienen combinaciones de teclas para arrancar en este modo. Es algo que tendremos que investigar en cada caso concreto.

Desde este modo se puede desbloquear el bootloader (en algunos móviles viene bloqueado para impedir instalar otras ROMs o recoverys) y trabajar con las particiones: borrar, formatear, sobreescribir imágenes nuevas. Es el modo que vamos a usar para meter un recovery más adelante.

4. Más abajo: modos cercanos al Amenti.

Aquí llegamos a terreno envuelto en brumas. Cada fabricante puede tener modos más profundos para arrancar el móvil, según estas normas básicas:
  • La nomenclatura depende del fabricante: download mode (aunque en algunos fabricantes es equivalente al fastboot), emergency mode, QDL mode, y seguro que hay muchos más.
  • En cada caso se usa herramientas especializadas, como Odin, SPFlashTool, MTKDroidTools, KDZ Firmware Update, MiFlash,...
  • Desde estos modos normalmente sólo se consigue flashear el móvil cargando una Stock ROM (ROM Oficial)
Cuando uno llega aquí es que tiene el móvil tan brickeado que no podemos conectar con él mediante fastboot y ya estamos en modo pánico. Mis tribulaciones con los malditos Xiami Redmi 1S son una prueba de ello.


Vamos al lío.

Yo he venido aquí a hablar de mi recovery, así que vamos a ello. Mi problema es que cada vez que tengo que meter un recovery me lanzo una y otra vez por el camino mas pedregoso: bajarme los drivers USB el teléfono, instalar una utilidad de flasheo, conseguir el fichero con el recovery para mi modelo de móvil (no vale cualquiera, hay que buscar el correcto en htcmania/xda-developers o generarlo nosotros) y realizar el flasheo de la partición que lo aloja.

Esa es la teoría. En la práctica, como la mayoría de estas utilidades solo funcionan bien en Windows no queda otra que arrancar dicho sistema, sortear los problemas con los drivers no firmados (la mayoría de los drivers de móviles están sin firmar), ver si detecta o no el dispositivo USB, ver si hay comunicación estable... y un sinfín de contratiempos más. Después de un par de horas infructuosas recuerdo que hay un método mucho más sencillo usando la línea de comandos de linux:

  1. Localizar y descargar el recovery. Suele ser un fichero .img que contiene dentro imagen de una partición con un mini-sistema Linux
  2. Conectar por adb y arrancar en modo fastboot.
  3. Desbloquear el bootloader, cargar el recovery y reiniciar.

Veamos la secuencia de comandos. Antes de nada debemos instalar las android-tools-adb y android-tools-fastboot en nuestro Linux, a veces vienen por separado o a veces en un único paquete android-tools. No hace falta ningún driver. También hay que habilitar el modo depuración USB en el menú de desarrollo del móvil.

Conectamos el móvil al PC por usb y tecleamos:
# adb devices
Si todo va bien saldrán numeritos y el nombre del teléfono. Ojo: quizá el móvil nos pregunte ahora o más adelante en su pantalla si damos permisos para aceptar la conexión desde el PC.

Reiniciamos el móvil en modo fastboot:
# adb reboot bootloader
En ese modo la pantalla no muestra nada interesante, la única manera de interactuar es a través del comando fastboot en el PC. Vemos si hay comunicación con dicho modo desde el ordenador tecleando:
# fastboot devices
Antes de nada, puede que el terminal tenga el bootloader bloqueado. Eso quiere decir que viene de fábrica configurado para impedir cambiar el recovery y/u otras partes del sistema. En ese caso lo que haremos será desloquearlo con uno de estos 2 comandos:
# fastboot oem unlock
o
# fastboot oem unlock-go
Podemos ver el estado del bootloader con:
# fastboot oem device-info
y/o
# fastboot getvar all
Debe aparecer algo así como: "Device Unlocked: true".

Una vez confirmamos que el móvil está desbloqueado, procedemos a sustituir el revovery por uno nuevo descargado de Internet (recordemos: el recovery debe ser compatible con nuestro terminal, no se pueden hacer mezclas a riesgo de brickear el movil).
# fastboot flash recovery twrp.img
También es posible hacer una prueba del recovery en dique seco, sin reescribir el original. Así confirmamos su buen funcionamiento/compatibilidad o bien lo ejecutamos para algo puntual sin sustituir el recovery que hay instalado:
# fastboot boot twrp.img
Una vez sobreescrito el nuevo recovery, reiniciamos:
# fastboot reboot
El móvil debe reiniciar bien y una vez arrancado, desde el adb podemos reiniciar en el recovery para operar con él:
# adb devices
# adb reboot recovery
Y ya está, espero que la próxima vez no tenga que perder el tiempo con Windows cuando quiera hacer esto.

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.

martes, 28 de noviembre de 2017

Reinicio periódico en DLink DIR-860L con dd-wrt

Es muy conveniente reiniciar algunos sistemas de forma periódica. En el caso de nuestros puntos de acceso DLink DIR-860L es casi obligatorio ya que cuanto mas tiempo pasan en funcionamiento mas empiezan a fallar ciertos aspectos, lo cual nos obliga al final a hacer un reset manual.

Mis compañeros Paco y Noemí me descubrieron que el propio dd-wrt incorpora un mecanismo de reinicio periódico, sin necesidad de configurar a mano crontab. Aunque se puede definir usando el interface web, buscando la opción "Administracion->Keep alive" entre sus pestañas nosotros lo vamos a hacer por comando. Consiste en entrar por ssh y ejecutar en cada punto de acceso los siguientes comandos:
nvram set schedule_enable=1
nvram set schedule_hour_time=2
nvram set schedule_weekdays=*
nvram set schedule_hours=7
nvram set schedule_minutes=0
nvram set schedule_time=3600
nvram set ntp_enable=1
nvram set ntp_server=..ip servidor centro..
nvram set ntp_mode=auto
nvram commit
reboot
Comentemos:
  • schedule_enable: puesto a 1 habilita el reinicio programado.
  • schedule_hour_time: puesto a 1 activa el reinicio cada X segundos, puesto a 2 el reinicio a dias/horas determinados.
  • schedule_weekdays, schedule_hours, schedule_minutes: días y hora donde se realiza el reinicio. En mi caso, todos los dias a las 7:00 de la mañana.
  • schedule_time: segundos entre reinicio si schedule_hour_time=1.
  • ntp_enable: puesto a 1 habilita la sincronización de hora por ntp.
  • ntp_mode: con valor auto se realiza una sincronización automática.
  • ntp_server: IP del servidor ntp de nuestra red. Normalmente es el servidor principal del centro.
El servidor ntp se configura para que el punto de acceso se ponga en hora y haga los reinicios en el momento correcto, ya que si no se piensa que estamos en 1970 y a una hora intempestiva del día. Una vez arrancado el punto de acceso tarda un rato en sincronizar la hora, parece ser que no le corre prisa eso, pero si somos pacientes al final coge la hora y fecha correcta.

Gracias a estos reinicios nuestros puntos de acceso serán mucho mas estables y se portarán mejor. Nada como un buen reinicio para limpiar un sistema.