{"id":2642,"date":"2020-08-31T20:42:52","date_gmt":"2020-08-31T20:42:52","guid":{"rendered":"http:\/\/blog.rastersoft.com\/?p=2642"},"modified":"2020-10-21T12:13:26","modified_gmt":"2020-10-21T12:13:26","slug":"a-ritmo-de-conga-13","status":"publish","type":"post","link":"https:\/\/blog.rastersoft.com\/?p=2642","title":{"rendered":"A ritmo de conga (13)"},"content":{"rendered":"\n<p>Una funcionalidad que echaba en falta es el control manual: poder controlar el robot para mandarlo de un lado a otro con el tel\u00e9fono, en lugar de tener que cogerlo f\u00edsicamente.<\/p>\n\n\n\n<figure class=\"wp-block-video aligncenter meme\"><video height=\"130\" style=\"aspect-ratio: 232 \/ 130;\" width=\"232\" controls src=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2020\/08\/manual-control.mp4\"><\/video><\/figure>\n\n\n\n<p>El problema es que, tras analizar el protocolo de control manual a partir de las capturas que hab\u00eda hecho, me encontr\u00e9 con que era ligeramente diferente del que ya estaba utilizando. Para empezar, los comandos no iban a trav\u00e9s del servidor, sino que se enviaban directamente desde el m\u00f3vil a la aspiradora (por fin ten\u00eda sentido el puerto 8888). Por otro lado, los \u00abvalores misteriosos\u00bb no segu\u00edan el mismo patr\u00f3n. Para empezar, es la tablet quien env\u00eda los PINGs, y siempre con el mismo n\u00famero de secuencia: 1a 27 00 00. Por otro lado, estas son varias cabeceras de comandos enviados desde la tablet a la aspiradora:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">d1 00 00 00 | fa 00 c8 00 | 00 00 29 27 | 28 27 00 00 | 00 00 00 00\nd1 00 00 00 | fa 00 c8 00 | 00 00 2c 27 | 2b 27 00 00 | 00 00 00 00\nd1 00 00 00 | fa 00 c8 00 | 00 00 2f 27 | 2e 27 00 00 | 00 00 00 00\nd1 00 00 00 | fa 00 c8 00 | 00 00 32 27 | 31 27 00 00 | 00 00 00 00\ndb 00 00 00 | fa 00 c8 00 | 00 00 35 27 | 34 27 00 00 | 00 00 00 00<\/pre>\n\n\n\n<p>Vemos que el primer campo sigue siendo el tama\u00f1o, el cuarto sigue siendo un n\u00famero de secuencia, y el segundo y el cuarto tienen los mismos valores que en el protocolo con el servidor; pero el tercer campo es diferente; de hecho es el valor del n\u00famero de secuencia pero con los bytes invertidos y sum\u00e1ndole uno al tercer byte.<\/p>\n\n\n\n<p>Esto ya plantea algunas dudas; por ejemplo \u00bfqu\u00e9 pasa si el n\u00famero de secuencia es mayor de 0xFFFF? \u00bfEst\u00e1 prohibido tal vez? Si est\u00e1 permitido \u00bfel campo tercero ser\u00e1 el cuarto m\u00e1s 256 y con los bytes en orden inverso? De hecho \u00bfrealmente el n\u00famero de secuencia es de cuatro bytes tambi\u00e9n en el protocolo original, o puede que sean s\u00f3lo dos bytes?<\/p>\n\n\n\n<p>De hecho, para probar esto \u00faltimo decid\u00ed ver hasta qu\u00e9 valor devolv\u00eda la aspiradora, y tras varias pruebas me encontr\u00e9 con que 10.000 es el n\u00famero de secuencia m\u00e1s grande que env\u00eda en el protocolo original, tras el cual vuelve al 1. Pero el servidor s\u00ed env\u00eda n\u00fameros m\u00e1s grandes de 10.000.<\/p>\n\n\n\n<figure class=\"wp-block-video aligncenter meme\"><video height=\"220\" style=\"aspect-ratio: 320 \/ 220;\" width=\"320\" controls src=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2020\/08\/misterio.mp4\"><\/video><\/figure>\n\n\n\n<p>Aparte de este problema, est\u00e1 la cuesti\u00f3n de que en el c\u00f3digo tendr\u00eda que a\u00f1adir un nuevo <em>socket<\/em> y gestionarlo&#8230; no es dif\u00edcil, pero s\u00ed un rollo. Sin embargo&#8230; \u00bfQu\u00e9 pasar\u00eda si se pudiese controlar desde la conexi\u00f3n original? \u00bfPuede el servidor enviar comandos de control manual?<\/p>\n\n\n\n<p>La pregunta es leg\u00edtima, pues cabe suponer que el control manual utiliza la conexi\u00f3n directa para reducir la latencia (a fin de cuentas, es un control interactivo), y adem\u00e1s, si estamos en el bar no tiene sentido querer controlar manualmente una aspiradora que no podemos ver. Pero a\u00fan as\u00ed hay casos en los que puede ser necesario, por ejemplo que tengamos varias WiFis en nuestra casa y que el tel\u00e9fono est\u00e9 conectada a una y la aspiradora a otra. As\u00ed que decid\u00ed probar justo eso y&#8230; \u00a1\u00a1\u00a1Funcion\u00f3!!! \u00a1\u00a1\u00a1Es posible enviar comandos de control manual a trav\u00e9s del socket del servidor!!! Eso simplifica la tarea enormemente.<\/p>\n\n\n\n<figure class=\"wp-block-video aligncenter meme\"><video height=\"288\" style=\"aspect-ratio: 288 \/ 288;\" width=\"288\" controls src=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2020\/06\/tadah.mp4\"><\/video><\/figure>\n\n\n\n<p>Ahora toca analizar el formato. Veamos un primer caso: ordenamos al aspirador ponerse a girar alrededor de s\u00ed mismo hacia la derecha durante tres segundos (las respuestas de la aspiradora son, simplemente, el estado actual, as\u00ed que he borrado casi todo el contenido y lo he reemplazado por unos puntos suspensivos para no alargar demasiado el bloque):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">1315.019054889679\ns-&gt;a e1 00 00 00 | fa 00 c8 00 | 00 00 f2 01 | 2d 27 00 00 | 00 00 00 00\n{\n  \"cmd\":0,\n  \"control\":{\n    \"authCode\":\"xxxxxx\",\n    \"deviceIp\":\"192.168.3.56\",\n    \"devicePort\":\"8888\",\n    \"targetId\":\"yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy\",\n    \"targetType\":\"3\"\n  },\n  \"seq\":0,\n  \"value\":{\n    \"direction\":\"4\",\n    \"transitCmd\":\"108\"\n  }\n}\\n\n\n1315.3824479579926\na-&gt;s f6 01 00 00 | fa 00 00 00 | 01 00 00 00 | 2d 27 00 00 | 00 00 00 00\n[...]\n\n\n\n1317.020054889679\ns-&gt;a e1 00 00 00 | fa 00 c8 00 | 00 00 f2 03 | 2d 27 00 00 | 00 00 00 00\n{\n  \"cmd\":0,\n  \"control\":{\n    \"authCode\":\"xxxxxx\",\n    \"deviceIp\":\"192.168.3.56\",\n    \"devicePort\":\"8888\",\n    \"targetId\":\"yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy\",\n    \"targetType\":\"3\"\n  },\n  \"seq\":0,\n  \"value\":{\n    \"direction\":\"4\",\n    \"transitCmd\":\"108\"\n  }\n}\\n\n\n1317.3924479579926\na-&gt;s f6 01 00 00 | fa 00 00 00 | 01 00 00 00 | 2d 27 00 00 | 00 00 00 00\n[...]\n\n\n\n1318.9394080638885\ns-&gt;a eb 00 00 00 | fa 00 c8 00 | 00 00 f2 01 | 2f 27 00 00 | 00 00 00 00\n{\n  \"cmd\":0,\n  \"control\":{\n    \"authCode\":\"xxxxxx\",\n    \"deviceIp\":\"192.168.3.56\",\n    \"devicePort\":\"8888\",\n    \"targetId\":\"yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy\",\n    \"targetType\":\"3\"\n  },\n  \"seq\":0,\n  \"value\":{\n    \"direction\":\"5\",\n    \"tag\":\"4\",\n    \"transitCmd\":\"108\"\n  }\n}\\n\n\n1319.4073688983917\na-&gt;s f6 01 00 00 | fa 00 00 00 | 01 00 00 00 | 2f 27 00 00 | 00 00 00 00\n[...]<\/pre>\n\n\n\n<p>Y ya vemos c\u00f3mo va: el comando es el 108 , y luego hay un campo <em>direction<\/em> que vale 4. \u00bfSer\u00e1 el comando 108 para girar a la derecha, y habr\u00e1 otros para el resto de direcciones, o ser\u00e1 un \u00fanico comando para todo y el campo <em>direction<\/em> indica cual de los cuatro posibles movimientos se desea? Adem\u00e1s, al cabo de dos segundos vemos que se vuelve a repetir el comando. \u00bfPor qu\u00e9?<\/p>\n\n\n\n<p>Finalmente, al cabo de tres segundos se emite el comando con la direcci\u00f3n 5, por lo que cabe suponer que eso significa <em>detente<\/em>. \u00bfPero qu\u00e9 significa el campo <em>tag<\/em>?<\/p>\n\n\n\n<p>Para resolver todas estas preguntas, veamos todos los comandos emitidos para los cuatro movimientos posibles (adelante, atr\u00e1s, izquierda y derecha):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">adelante:\n  \"value\":{\n    \"direction\":\"1\",\n    \"transitCmd\":\"108\"\n  }\n\n  \"value\":{\n    \"direction\":\"5\",\n    \"tag\": \"1\",\n    \"transitCmd\":\"108\"\n  }\n\n------------------------\natr\u00e1s:\n  \"value\":{\n    \"direction\":\"2\",\n    \"transitCmd\":\"108\"\n  }\n\n  \"value\":{\n    \"direction\":\"5\",\n    \"tag\": \"2\",\n    \"transitCmd\":\"108\"\n  }\n\n------------------------\nizquierda:\n  \"value\":{\n    \"direction\":\"3\",\n    \"transitCmd\":\"108\"\n  }\n\n  \"value\":{\n    \"direction\":\"5\",\n    \"tag\": \"3\",\n    \"transitCmd\":\"108\"\n  }\n\n------------------------\nderecha:\n  \"value\":{\n    \"direction\":\"4\",\n    \"transitCmd\":\"108\"\n  }\n\n  \"value\":{\n    \"direction\":\"5\",\n    \"tag\": \"4\",\n    \"transitCmd\":\"108\"\n  }<\/pre>\n\n\n\n<p>\u00a1Aj\u00e1! Ahora tiene sentido: se utiliza un \u00fanico comando, el 108, para los movimientos manuales, con 1, 2, 3 y 4 para moverse adelante, atr\u00e1s, izquierda y derecha respectivamente. Cuando se quiere parar se emite el mismo comando pero con la direcci\u00f3n 5, y el campo <em>tag<\/em> especifica qu\u00e9 movimiento es el que se cancela (probablemente por si los comandos llegan fuera de orden).<\/p>\n\n\n\n<p>Adem\u00e1s, si probamos con movimientos que duren m\u00e1s tiempo se ve que el servidor vuelve a enviar el comando de movimiento cada dos segundos. Todo apunta a que es una manera de asegurar que el servidor \u00absigue ah\u00ed\u00bb, y que si pasa mucho tiempo sin recibir un comando de <em>refresco<\/em>, la aspiradora dejar\u00e1 de ejecutar el \u00faltimo comando. Esto tiene sentido: si se pierde la conexi\u00f3n es importante que el robot no se quede ejecutando una orden de movimiento manual&#8230;<\/p>\n\n\n\n<figure class=\"wp-block-video aligncenter meme\"><video height=\"186\" style=\"aspect-ratio: 320 \/ 186;\" width=\"320\" controls src=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2020\/06\/tadah_harry_potter.mp4\"><\/video><\/figure>\n\n\n\n<p>Y con esto ya tenemos todo lo necesario para implementar el control manual, y as\u00ed de bonito se ve en la app:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><a href=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2020\/08\/Captura-de-pantalla-de-2020-08-31-22-39-36.png\" rel=\"lightbox-0\"><img loading=\"lazy\" decoding=\"async\" width=\"958\" height=\"991\" src=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2020\/08\/Captura-de-pantalla-de-2020-08-31-22-39-36.png\" alt=\"\" class=\"wp-image-2651\" srcset=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2020\/08\/Captura-de-pantalla-de-2020-08-31-22-39-36.png 958w, https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2020\/08\/Captura-de-pantalla-de-2020-08-31-22-39-36-290x300.png 290w, https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2020\/08\/Captura-de-pantalla-de-2020-08-31-22-39-36-768x794.png 768w\" sizes=\"auto, (max-width: 958px) 100vw, 958px\" \/><\/a><\/figure><\/div>\n\n\n\n<p>Como se ve, hay un nuevo icono que permite alternar entre <em>modo mapa<\/em> y <em>modo control manual<\/em>, y pulsando las flechas el robot se mover\u00e1. Eso s\u00ed, por desgracia la aspiradora no puede estar en la base para que este modo funcione, parece una limitaci\u00f3n del propio firmware del robot, no de la app original.<\/p>\n\n\n\n<p><a href=\"https:\/\/blog.rastersoft.com\/?p=2655\">Parte 14<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Una funcionalidad que echaba en falta es el control manual: poder controlar el robot para mandarlo de un lado a otro con el tel\u00e9fono, en lugar de tener que cogerlo f\u00edsicamente. El problema es que, tras analizar el protocolo de control manual a partir de las capturas que hab\u00eda hecho, me encontr\u00e9 con que era &hellip; <a href=\"https:\/\/blog.rastersoft.com\/?p=2642\" class=\"more-link\">Seguir leyendo <span class=\"screen-reader-text\">A ritmo de conga (13)<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,16,5,7],"tags":[],"class_list":["post-2642","post","type-post","status-publish","format-standard","hentry","category-cacharreo","category-opendonita","category-programacion","category-tutoriales"],"_links":{"self":[{"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/posts\/2642","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2642"}],"version-history":[{"count":11,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/posts\/2642\/revisions"}],"predecessor-version":[{"id":2690,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/posts\/2642\/revisions\/2690"}],"wp:attachment":[{"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2642"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2642"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2642"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}