{"id":2494,"date":"2020-07-13T22:31:16","date_gmt":"2020-07-13T22:31:16","guid":{"rendered":"http:\/\/blog.rastersoft.com\/?p=2494"},"modified":"2020-10-21T12:15:15","modified_gmt":"2020-10-21T12:15:15","slug":"a-ritmo-de-conga-y-6","status":"publish","type":"post","link":"https:\/\/blog.rastersoft.com\/?p=2494","title":{"rendered":"A ritmo de conga (6)"},"content":{"rendered":"\n<p><strong>Actualizado<\/strong>: a\u00f1adidos dos comandos extra.<\/p>\n\n\n\n<p><strong>DISCLAIMER:<\/strong> no ser\u00e9 responsable si alguien decide seguir mis pasos y se carga su aspiradora. En principio todo lo que cuento deber\u00eda ser seguro, pero por motivos obvios no me puedo responsabilizar de lo que hagan otras personas, s\u00f3lo de lo que haga yo.<\/p>\n\n\n\n<p>Ahora que ya tengo un servidor en marcha capaz de enviar comandos, lleg\u00f3 el momento de analizar todas las posibles opciones. Para ello puse otra vez el <a href=\"https:\/\/en.wikipedia.org\/wiki\/Tcpdump\">tcpdump<\/a> a capturar y, desde la aplicaci\u00f3n oficial, fui enviando todos los posibles comandos, anotando a la vez la hora a la que lo hac\u00eda para poder luego identificarlos. Tambi\u00e9n modifiqu\u00e9 mi analizador de paquetes para que mostrase el instante de tiempo en que se emit\u00eda o recib\u00eda cada paquete.<\/p>\n\n\n\n<figure class=\"wp-block-video aligncenter meme\"><video height=\"180\" style=\"aspect-ratio: 320 \/ 180;\" width=\"320\" controls src=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2020\/07\/mando.mp4\"><\/video><\/figure>\n\n\n\n<p>La primera conclusi\u00f3n es que todos los comandos (a excepci\u00f3n, de momento, de los de mover la aspiradora manualmente, que <em>en principio<\/em> hay que enviarlos a trav\u00e9s del puerto 8888 de la aspiradora; a\u00fan no prob\u00e9 qu\u00e9 pasa si lo env\u00edo por la conexi\u00f3n <em>normal<\/em>) se pueden ejecutar con este paquete (con un par de excepciones):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">d1 00 00 00 | fa 00 c8 00 | 00 00 09 01 | 1a 27 00 00 | 00 00 00 00\n{\n  \"cmd\":0,\n  \"control\":{\n    \"authCode\":\"yyyyyy\",\n    \"deviceIp\":\"192.168.18.3\",\n    \"devicePort\":\"8888\",\n    \"targetId\":\"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz\",\n    \"targetType\":\"3\"\n  },\n  \"seq\":0,\n  \"value\":{\"transitCmd\":\"ID_COMANDO\"}\n}\\n<\/pre>\n\n\n\n<p>Siendo <strong>ID_COMANDO<\/strong> un n\u00famero que identifica la operaci\u00f3n. En casi todos los casos, la aspiradora devolver\u00e1 una respuesta, con la excepci\u00f3n de un par de ellos.<\/p>\n\n\n\n<p>Los posibles comandos que ya tengo identificados son:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>98<\/strong>: pide una actualizaci\u00f3n del estado de la aspiradora. El aspirador no env\u00eda asentimiento. S\u00f3lo funciona mientras la aspiradora est\u00e1 en marcha.<\/li><li><strong>100<\/strong>: comienza a limpiar<\/li><li><strong>102<\/strong>: deja de limpiar<\/li><li><strong>104<\/strong>: vuelve a la base<\/li><li><strong>106<\/strong>: establece el modo de limpieza. Incluye el par\u00e1metro <em>mode<\/em> antes de <em>transitCmd<\/em> con uno de los siguientes valores:<ul><li><em>11<\/em>: modo <em>auto<\/em><\/li><li><em>1<\/em>: modo <em>giro<\/em><\/li><li><em>3<\/em>: modo <em>random<\/em><\/li><li><em>4<\/em>: modo <em>edges<\/em><\/li><li><em>6<\/em>: modo <em>area<\/em><\/li><li><em>8<\/em>: modo <em>deep cleaning<\/em><\/li><li><em>10<\/em>: modo <em>scrubbing<\/em><\/li><\/ul><\/li><li><strong>110<\/strong>: establece la potencia del aspirador. Incluye el par\u00e1metro <em>fan<\/em> antes de <em>transitCmd<\/em> con uno de los siguientes valores:<ul><li><em>1<\/em>: detenido<\/li><li><em>2<\/em>: normal<\/li><li><em>3<\/em>: turbo<\/li><li><em>4<\/em>: eco<\/li><\/ul><\/li><li><strong>123<\/strong>: activa los sonidos de la aspiradora. Emitir\u00e1 un pitido al ponerse en marcha, terminar de cargar, etc.<\/li><li><strong>125<\/strong>: desactiva los sonidos de la aspiradora.<\/li><li><strong>131<\/strong>: pide una actualizaci\u00f3n del mapa generado. S\u00f3lo funciona mientras la aspiradora est\u00e1 en marcha.<\/li><li><strong>145<\/strong>: establece la cantidad de agua en modo fregado. Incluye el par\u00e1metro <em>waterTank<\/em> depu\u00e9s de <em>transitCmd<\/em> con uno de los siguientes valores:<ul><li><em>255<\/em>: no emitir agua<\/li><li><em>60<\/em>: flujo de agua bajo<\/li><li><em>40<\/em>: flujo de agua normal<\/li><li><em>20<\/em>: flujo de agua alto<\/li><\/ul><\/li><li><strong>400<\/strong>: notifica que la aplicaci\u00f3n se acaba de conectar. El aspirador no env\u00eda asentimiento.<\/li><\/ul>\n\n\n\n<figure class=\"wp-block-video aligncenter meme\"><video height=\"180\" style=\"aspect-ratio: 302 \/ 180;\" width=\"302\" controls src=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2020\/07\/lista.mp4\"><\/video><\/figure>\n\n\n\n<p>A mayores hay al menos dos comandos m\u00e1s:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>139<\/strong>: sirve para poner la fecha y la hora y que debe ir acompa\u00f1ado del par\u00e1metro <strong>set_time<\/strong>, con formato <em>AAAAMMDDhhmm000x<\/em>, siendo AAAA en a\u00f1o (cuatro cifras), MM el mes, DD el d\u00eda, hh la hora, mm el minuto (todos con dos cifras), y luego est\u00e1 esa <em>x<\/em>, que en algunos sitios es 0, en otros 1 y en otros 2, pero a\u00fan no encontr\u00e9 una regla para determinar su valor.<\/li><li><strong>127<\/strong>: sirve para actualizar el firmware, as\u00ed que mi consejo: <a href=\"https:\/\/www.youtube.com\/watch?v=9s22RkxCC-U\" target=\"_blank\" rel=\"noreferrer noopener lightbox-video-0\">no se toca<\/a>.<\/li><\/ul>\n\n\n\n<p>Cada vez que enviemos un comando, la aspiradora nos devolver\u00e1 un asentimiento (con la excepci\u00f3n de los comandos 98 y 400). \u00c9ste ser\u00e1 un paquete como \u00e9ste:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">db 01 00 00 | fa 00 00 00 | 01 00 00 00 | 1a 27 00 00 | 00 00 00 00<br>{<br>  \"version\":\"1.0\",<br>  \"control\":{<br>    \"targetId\":\"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz\",<br>    \"targetType\":\"3\",<br>    \"broadcast\":\"0\"<br>  },\"value\":{<br>    \"noteCmd\":\"102\",<br>    \"workState\":\"5\",<br>    \"workMode\":\"0\",<br>    \"fan\":\"2\",<br>    \"direction\":\"0\",<br>    \"brush\":\"2\",<br>    \"battery\":\"100\",<br>    \"voice\":\"2\",<br>    \"error\":\"0\",<br>    \"standbyMode\":\"1\",<br>    \"waterTank\":\"40\",<br>    \"clearComponent\":\"0\",<br>    \"waterMark\":\"0\",<br>    \"version\":\"3.11.416(513)\",<br>    \"attract\":\"0\",<br>    \"deviceIp\":\"192.168.18.3\",<br>    \"devicePort\":\"8888\",<br>    \"cleanGoon\":\"2\",<br>    \"extParam\":\"{\\\"cleanModule\\\":\\\"3\\\"}\"<br>  }<br>}<\/pre>\n\n\n\n<p>pero con el importante detalle de que el estado que devuelve es el anterior a la ejecuci\u00f3n del comando. Esto es: si tenemos el sonido activado (que en el JSON con el estado de la aspiradora viene indicado con <em>voice<\/em> valiendo 2), y enviamos el comando 125, el estado que nos llegue en el ACK del comando tendr\u00e1 todav\u00eda <em>voice=2<\/em>. Ser\u00e1 justo despu\u00e9s cuando la aspiradora nos enviar\u00e1 un paquete <em>status<\/em>, con el siguiente formato:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">bc 01 00 00 | 18 00 00 00 | 01 00 00 00 | 1a 00 00 00 | 00 00 00 00\n{\n  \"version\":\"1.0\",\n  \"control\":{\n    \"targetId\":\"0\",\n    \"targetType\":\"6\",\n    \"broadcast\":\"0\"\n  },\"value\":{\n    \"noteCmd\":\"102\",\n    \"workState\":\"5\",\n    \"workMode\":\"0\",\n    \"fan\":\"2\",\n    \"direction\":\"0\",\n    \"brush\":\"2\",\n    \"battery\":\"100\",\n    \"voice\":\"1\",\n    \"error\":\"0\",\n    \"standbyMode\":\"1\",\n    \"waterTank\":\"40\",\n    \"clearComponent\":\"0\",\n    \"waterMark\":\"0\",\n    \"version\":\"3.11.416(513)\",\n    \"attract\":\"0\",\n    \"deviceIp\":\"192.168.18.3\",\n    \"devicePort\":\"8888\",\n    \"cleanGoon\":\"2\",\n    \"extParam\":\"{\\\"cleanModule\\\":\\\"3\\\"}\"\n  }\n}<\/pre>\n\n\n\n<p>donde esta vez s\u00ed vemos que <em>voice<\/em> vale 1. Este paquete debemos asentirlo con un ACK como \u00e9ste, con el mismo n\u00famero de secuencia (el cuarto entero de los cinco que forman la cabecera):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">3c 00 00 00 | 19 00 c8 00 | 01 00 00 00 | 1a 00 00 00 | 01 00 00 00\n{\n  \"msg\":\"OK\",\n  \"result\":0,\n  \"version\":\"1.0\"\n}\\n<\/pre>\n\n\n\n<figure class=\"wp-block-video aligncenter meme\"><video height=\"172\" style=\"aspect-ratio: 220 \/ 172;\" width=\"220\" controls src=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2020\/07\/ok.mp4\"><\/video><\/figure>\n\n\n\n<p>En el JSON del estado de la aspiradora tenemos los siguientes campos interesantes:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>workstate: indica el modo actual en el que est\u00e1 la aspiradora, que puede ser:<ul><li>1: limpiando<\/li><li>2: parada<\/li><li>4: regresando a la base<\/li><li>5: cargando la bater\u00eda<\/li><li>6: bater\u00eda cargada<\/li><\/ul><\/li><li>battery: un valor de 0 a 100 indicando el nivel de carga de la bater\u00eda<\/li><li>voice: si vale 1, el pitido de aviso est\u00e1 desactivado; si vale 2, est\u00e1 activado<\/li><\/ul>\n\n\n\n<p><a href=\"https:\/\/blog.rastersoft.com\/?p=2513\">Parte 7<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Actualizado: a\u00f1adidos dos comandos extra. DISCLAIMER: no ser\u00e9 responsable si alguien decide seguir mis pasos y se carga su aspiradora. En principio todo lo que cuento deber\u00eda ser seguro, pero por motivos obvios no me puedo responsabilizar de lo que hagan otras personas, s\u00f3lo de lo que haga yo. Ahora que ya tengo un servidor &hellip; <a href=\"https:\/\/blog.rastersoft.com\/?p=2494\" class=\"more-link\">Seguir leyendo <span class=\"screen-reader-text\">A ritmo de conga (6)<\/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-2494","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\/2494","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=2494"}],"version-history":[{"count":15,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/posts\/2494\/revisions"}],"predecessor-version":[{"id":2598,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/posts\/2494\/revisions\/2598"}],"wp:attachment":[{"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2494"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2494"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2494"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}