Esta será, en principio, la última entrada. En ella voy a describir el servidor/app que escribí para controlar mi aspiradora robot.
DISCLAIMER: no seré responsable si alguien decide seguir mis pasos y se carga su aspiradora. En principio todo lo que cuento debería ser seguro, pero por motivos obvios no me puedo responsabilizar de lo que hagan otras personas, sólo de lo que haga yo.
El código está escrito en python, está disponible en mi cuenta de Gitlab en servidor para robots Conga 1490, y se llama OpenDoñita. Esta descripción complementa a la del capítulo 5.
Para empezar, está cómo hacerlo funcionar. Yo lo he puesto en una Raspberry Pi 4 que tenía muerta de risa por casa (de momento OSMC no funciona en ella), la misma con la que configuré la red WiFi interna para analizar el tráfico. Sin embargo es posible ponerla en cualquier ordenador, siempre y cuando se configure un DNS adecuado. En efecto, si recordamos, la aspiradora se conectará siempre a dos dominios concretos, bl-app-eu.robotbona.com y bl-im-eu.robotbona.com, por lo que necesitamos engañarla de alguna manera para que se conecte a nuestro servidor. La manera más sencilla es entrar en la configuración de nuestro router Wifi y y configurar la IP de nuestra Raspberry Pi como la IP del servidor DNS de nuestra red. Luego, en dicha Raspberry instalamos dnsmasq, pero no configuramos la parte de DHCP, sólo el servidor DNS. Una vez hecho esto editamos el fichero /etc/hosts y añadimos estas dos entradas:
192.168.X.Y bl-app-eu.robotbona.com
192.168.X.Y bl-im-eu.robotbona.com
Siendo 192.168.X.Y la IP del equipo en donde vayamos a poner a correr el servidor (que, normalmente, será la misma Raspberry Pi).
Un detalle importante es que mi código necesita Python 3.6 o superior, lo que significa que funcionará en Raspbian, pero no en la versión actual de OSMC pues está basada en la versión stretch de Debian (lo he probado; quería meter todo en la misma Raspberry pero no ha podido ser). Hasta que actualicen el sistema base a buster (y me consta que están en ello) no se podrá hacer.
Una vez que está hecho reiniciamos dnsmasq para que refresque los valores, y ya podemos lanzar nuestro servidor. Para ello, desde un terminal, vamos al directorio donde esté el código y escribimos:
sudo screen ./congaserver
Es importante estar en el directorio correspondiente pues, por defecto, es ahí donde el servidor buscará el directorio html con las páginas de la aplicación web que se utiliza para controlar a las aspiradoras. Si lo lanzamos desde otro directorio lo más probable es que no funcione. Para más información sobre screen, recomiendo leer la documentación. Es necesario usarlo (o bien nohup en su lugar) para poder salir de la sesión SSH de la RPi y que el programa siga corriendo.
Podemos probar si funciona todo correctamente simplemente abriendo un navegador y escribiendo en un terminal
ping bl-app-eu.robotbona.com
Si todo está correcto, debería resolver a la IP de nuestra Raspberry Pi.
Y ahora que está todo listo y corriendo, ya podemos conectar la aspiradora. Para ello tenemos tres opciones:
- Apagar la WiFi y volverla a encender. En este caso, la aspiradora volverá a conectarse a ella, buscará el servidor de nuevo y se conectará al nuestro, pues recibirá la IP desde nuestro servidor DNS.
- Apagar la aspiradora y volverla a encender. Para ello es necesario retirarla de la base de carga y apagar el interruptor situado en el lado derecho, esperar unos segundos y volver a encenderlo.
- Volver a emparejar la aspiradora. Es el más lioso, pues con el DNS en marcha la app oficial no podrá conectarse al servidor (usa un puerto diferente) y se negará a arrancar, por lo que tendremos que utilizar el script configconga.py, que explicaré más adelante.
En cualquiera de los tres casos sabremos si hemos tenido éxito porque en la pantalla de nuestro servidor aparecerán mensajes que indican que se están haciendo peticiones.
Una vez conectada, ya está todo listo para empezar a trabajar. Si ahora abrimos un navegador y metemos la IP del equipo de nuestro servidor, nos aparecerá la siguiente pantalla:
En la parte blanca de la derecha es donde aparecerá el mapa, pero de momento estará en blanco. Por otro lado, en la parte superior izquierda tenemos un indicador de carga de la batería. Cuando esta completamente negra estará cargada, y si está blanca estará descargada. Ahí se ve que está casi cargada del todo.
El símbolo del rayo indica que está cargando. Cuando esté cargada del todo (o cuando no esté en la base) dicho símbolo desaparecerá.
A continuación vemos los cuatro botones que podemos utilizar. El primero, con forma de casa, ordena a la aspiradora volver a la base. Sin embargo, si ya está en la base aparecerá sólo en forma de líneas, sin relleno (tal y como se ve en la captura).
El siguiente botón, con forma de «play», le indica a la aspiradora que comience a trabajar. Al hacerlo cambiará a un cuadrado, o sea, «stop».
El tercer botón, con forma de altavoz, permite activar o desactivar el pitido de aviso de la aspiradora. Tal y como está en la captura, está desactivado. Al activarlo sonará un pitido de aviso y el icono pasará a estar relleno.
El último botón, el engranaje, muestra la pantalla de configuración de modo de limpieza. Al pulsarlo aparece esta imagen:
Los cuatro superiores, con forma de ventilador, representan las cuatro potencias de aspiración (nada, eco, normal y turbo). Las cuatro siguientes, con forma de gota de agua, la cantidad de líquido que se utiliza para humedecer la fregona (nada, poco, normal, mucho). Un detalle importante es que no es posible escoger a la vez los modos «nada» de aspiración y fregona. Por último, los siete inferiores representan los modos de aspirado y fregado disponibles, aunque lo normal es utilizar el modo auto y no complicarse.
Lo mejor de todo es que recuerda el modo escogido incluso si se apaga la aspiradora, pues la configuración se guarda en nuestro servidor.
Para cerrar esta ventana basta con pulsar la flecha situada abajo a la derecha.
Si ponemos a funcionar la aspiradora, se irá generando poco a poco el mapa, cuyo tamaño se irá ajustando poco a poco a medida que se va calculando. Por eso al principio estará formado por círculos gigantescos, pero luego irán haciéndose más pequeños a medida que la superficie descubierta aumente. Así, al principio veremos algo así:
El protocolo REST
Y tras esto, paso a describir el protocolo REST utilizado por el servidor. Porque, efectivamente, la nueva app es una aplicación web, por lo que se puede actualizar y tunear sin necesidad de parar el servidor y volver a lanzarlo (lo que, además, exigiría volver a hacer que la aspiradora se conectase a él usando uno de los tres métodos comentados antes).
Los comandos que acepta son los siguientes. Para empezar, están los tres específicos del emulador del servidor de Robot Bona, que son:
/baole-web/common/sumbitClearTime.do /baole-web/common/getToken.do /baole-web/common/*
Los dos primeros devuelven los datos necesarios para emparejar la aspiradora con el servidor, y el tercero devuelve simplemente un OK.
Ahora vienen los comandos específicos del servidor. Estos son comandos que no afectan a la aspiradora, sino que son útiles para implementar la app.
/robot/list /robot/XXXXX/getStatus /robot/XXXXX/setStatus /robot/XXXXX/getProperty?key=YYYYYY /robot/XXXXX/setProperty?key=YYYYYY&value=ZZZZZZ
El primero devuelve una lista con el identificador de cada robot que está conectado ahora mismo al servidor. Este identificador se puede utilizar para enviar comandos a un robot específico si tenemos varios en casa.
Los otros cuatro son comandos de servidor. El parámetro XXXXX sería un identificador del robot al que va dirigido (obtenido con list), o bien puede ser all si queremos dirigirnos a todos. De hecho, actualmente la app no soporta discernir entre robots, y siempre envía los comandos a all. Si en el futuro me compro otro robot puede que lo implemente.
getStatus devuelve el estado actual de la aspiradora. Se trata de un diccionario con los datos enviados por la aspiradora al servidor, tales como el mapa, el nivel de batería, el modo actual de trabajo… Cada vez que la aspiradora envía una actualización, el servidor la almacena internamente, y es esta caché la que se envía aquí. Eso significa, por ejemplo, que si no estamos aspirando, el mapa que recibamos será el último que se envió, aunque haya sido hace horas. También si hubo algún error aparecerá su código en el campo correspondiente, aunque haga mucho que no se produjeron más errores.
setStatus permite modificar alguno de los valores anteriores, pero sólo en la caché del servidor. No afecta a la aspiradora. Existe para poder resetear algunos campos que se activan en casos muy concretos, como por ejemplo el campo error, y así poder detectar cuando se ha producido uno nuevo. Actualmente no se utiliza para nada.
getProperty y setProperty se utilizan para almacenar datos personalizados en el servidor, referidos a una aspiradora concreta. Actualmente se utilizan para almacenar la configuración deseada (potencia de succión, cantidad de agua en modo fregado, y modo de limpieza), de manera que aunque se apague la aspiradora, el sistema recordará la configuración deseada por el usuario. La forma de almacenarlo es como pares clave/valor, y siempre son strings.
Por último, la lista de comandos que van a la aspiradora. Son:
/robot/XXXXX/clean /robot/XXXXX/stop /robot/XXXXX/return /robot/XXXXX/updateMap /robot/XXXXX/sound?status=0|1 /robot/XXXXX/fan?speed=0|1|2|3 /robot/XXXXX/watertank?speed=0|1|2|3 /robot/XXXXX/mode?type=auto|gyro|random|borders|area|x2|scrub /robot/XXXXX/notifyConnection /robot/XXXXX/askStatus
clean, stop y return controlan la operación básica de la aspiradora: comenzar un ciclo de limpieza, parar, y volver a la base. No tiene más complicación.
updateMap envía un comando 131, de manera que en torno a una décima de segundo después tendremos la variable map actualizada, y podremos obtener su nuevo valor con /robot/XXXXX/getStatus.
sound permite activar (1) o desactivar (0) el pitido de aviso de la aspiradora. Teniendo en cuenta que cada vez que termina de cargar emite un pitido, yo personalmente prefiero apagarlo.
fan y watertank permiten escoger la potencia de aspiración y la cantidad de agua que se utilizarán durante el ciclo de limpieza.
mode permite escoger entre los siete modos de limpieza, aunque lo normal es utilizar auto.
notifyConnection emite un comando 400. En la app actual se emite nada más cargar la página, para avisar de que hay una app abierta.
askStatus emite un comando 98, el cual hace que unos milisegundos más tarde la aspiradora envíe una actualización de su estado. El servidor, al recibirlo, actualizará su caché y podremos leer los cambios con robot/XXXXX/getStatus.
Por último, cualquier petición que no coincida con este formato se asumirá que está pidiendo un fichero, por lo que se buscará en la carpeta html. Es así como se sirven las páginas HTML y las imágenes de la app.
Emparejando la conga a una red WiFi
Una vez que hemos cambiado el DNS veremos que la app oficial, la del móvil, ya no funciona. Esto es porque intenta conectarse al servidor oficial, y al no poder por apuntar ahora al nuestro, se niega a abrirse siquiera. Eso significa que no podemos utilizarla si necesitamos emparejar nuestro aspirador con otra red WiFi.
Afortunadamente, para eso está configconga.py. Es un programita que permite realizar la operación de emparejado. Para ello necesitamos un ordenador con WiFi.
Lo primero es poner la aspiradora en modo emparejamiento. Para ello hay que mantener pulsado el botón de encendido hasta que el piloto de WiFi empiece a parpadear y suene un pitido.
En este momento la aspiradora se ha convertido en un punto de acceso WiFi, con un nombre CongaGyro_XXXXXX (siendo XXXXXX el identificador único de la aspiradora). Ahora tienes que conectarte desde tu ordenador a esa WiFi (no tiene contraseña), y ejecutar el programa anterior con:
./configconga.py WIFI_SSID WIFI_PASSWORD
Siendo SSID el identificador de la red WiFi a la que quieres conectar tu aspiradora, y PASSWORD la clave de dicha red WiFi. Una vez hecho esto la aspiradora dejará de ser un punto de acceso, y pasará a conectarse a la WiFi indicada.
¡Ahora, a disfrutarlo!
A ritmo de conga (8) por A cuadros está licenciado bajo una Licencia Creative Commons Atribución-CompartirIgual 4.0 Internacional.
Ole!
Te felicito, un trabajo buenísimo.
Muchas gracias