{ "cells": [ { "cell_type": "markdown", "id": "cb74fd38-1fa3-48a3-831e-9a12ca175ca6", "metadata": {}, "source": [ "# G: Programando clientes `INDI`\n", "\n", "En este `notebook` hacemos una introducción simple y burda a como podemos controlar dispositivos astronómicos con `INDI`. Para ello vamos a bajar bastante de nivel: abriremos un `socket` hacia nuestro servidor `INDI` e iremos leyendo / mandando los mensajes de XML que hacen falta para hacerlo funcionar. Algunos enlaces que pueden resultar de interés para seguir mejor estos ejemplos:\n", "\n", "+ [Socket Programming in Python (Guide)](https://realpython.com/python-sockets/)\n", "\n", "+ [Instalación de `INDI`](https://indilib.org/get-indi.html)\n", "\n", "+ [`INDI` whitepaper](http://www.clearskyinstitute.com/INDI/INDI.pdf)\n", "\n", "También te puede interesar ver esta [esta introducción a INDI (PDF)](./ficherosAuxiliares/controlDispositivosIndi.pdf)\n", "\n", "[![](./ficherosAuxiliares/portadaINDI.jpg)](./ficherosAuxiliares/controlDispositivosIndi.pdf)" ] }, { "cell_type": "markdown", "id": "73dd8c35-d7f7-4dec-8b3b-05644922c9e7", "metadata": {}, "source": [ "## Primer ejemplo: controlando un enfocador simulado\n", "\n", "Partimos de la base de que hemos instalado la biblioteca `INDI` y vamos a ejecutar el servidor de `INDI` con un único dispositivo: `indi_simulator_focus` (un simulador de enfocador. Como es un simulador no necesitamos *hardware* ninguno para ejecutar el ejemplo. Podemos abrir un cliente habitual de `INDI` (como el que está integrado en `KStars` para ir comprobando que los cambios que solicitamos al dispositivo efectivamente se llevan a cabo.\n", "\n", "```\n", "> indiserver indi_simulator_focus\n", "```" ] }, { "cell_type": "markdown", "id": "0f5a24ab-93c1-436b-9504-8da58b20bad9", "metadata": {}, "source": [ "Definimos unas cuantas funciones para simplificar el envio de mensajes y su recepción. No es un código muy elegante puesto que la recepción de mensajes debería hacerse en una hebra (hilo) diferente ([Threading: programación con hilos (I)](https://python-para-impacientes.blogspot.com/2016/12/threading-programacion-con-hilos-i.html)), pero esa es otra historia y debe ser contada en otra ocasión." ] }, { "cell_type": "code", "execution_count": null, "id": "16118687-e281-4403-a040-4c0d3660a79e", "metadata": {}, "outputs": [], "source": [ "#nombreEnfocador = \"MyFocuserPro2\"\n", "nombreEnfocador = \"Focuser Simulator\"" ] }, { "cell_type": "code", "execution_count": 1, "id": "dff4f110-3b92-485e-b9d5-69ed1063434d", "metadata": {}, "outputs": [], "source": [ "import socket\n", "import time\n", "from datetime import datetime" ] }, { "cell_type": "code", "execution_count": 2, "id": "54ca5852-d61a-4706-9fda-95185a8a651e", "metadata": {}, "outputs": [], "source": [ "def conectar(host, port):\n", " global s\n", " \n", " s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Creamos el socket y nos conectamos\n", " s.connect((host, port))\n", " s.settimeout(.01)\n", "\n", "def mandar(s, comando): # Manda al socket s un comando\n", " comando = comando.encode(\"ASCII\")\n", " \n", " print(comando)\n", " \n", " s.sendall(comando)\n", " \n", "def recibir(s, wait = 0.1, imprimir=True): # wait es el tiempo que vamos a esperar leyendo mensajes\n", " inicio = datetime.now()\n", "\n", " msg = \"\"\n", " \n", " try: \n", " msg = s.recv(500000).decode(\"UTF-8\")\n", " except socket.timeout:\n", " msg = \"\"\n", " \n", " horaActual = datetime.now()\n", "\n", " while (horaActual - inicio).total_seconds() < wait: # Espera activa... no es nada elegante :)\n", " try: \n", " msg = msg + s.recv(500000).decode(\"UTF-8\")\n", " except socket.timeout:\n", " # no hacemos nada\n", " msg = msg\n", " \n", " horaActual = datetime.now()\n", " \n", " time.sleep(0.05)\n", " \n", " if imprimir:\n", " print(msg)\n", " \n", " return msg" ] }, { "cell_type": "code", "execution_count": 3, "id": "7dcd1fb0-1f4d-4794-9c3b-1e31966181e4", "metadata": {}, "outputs": [], "source": [ "s=None # Nuestro socket\n", "\n", "host = \"127.0.0.1\" # Hostname o IP del servidor de INDI\n", "port = 7624 # Puerto por defecto de INDI\n", "\n", "\n", "conectar(host, port)" ] }, { "cell_type": "markdown", "id": "a1144807-6c5c-464a-9a6f-bbb8726fdacf", "metadata": {}, "source": [ "A estas alturas nos hemos conectado al servidor `INDI` pero no hemos recibido nada. Vamos a pedirle que nos envie toda la información sobre dispositivos y sus propiedades que tenga el servidor:" ] }, { "cell_type": "code", "execution_count": 4, "id": "6ba89d7f-1d62-400c-a3de-1e37467e22e5", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "b''\n" ] } ], "source": [ "mandar(s, '')" ] }, { "cell_type": "markdown", "id": "9f4851a2-d55a-429d-b8d7-cfad2062de82", "metadata": {}, "source": [ "Y recibimos información a ver que nos dice:" ] }, { "cell_type": "code", "execution_count": 5, "id": "5d221910-ea21-4a38-9c3d-03750b22b5d9", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Off\n", "Off\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Off\n", "Off\n", "\n", "\n", "On\n", "Off\n", "\n", "\n", "Unknown\n", "Unknown\n", "N/A\n", "\n", "\n", "0\n", "0\n", "0\n", "\n", "\n", "0\n", "\n", "\n", "On\n", "Off\n", "\n", "\n", "Off\n", "Off\n", "\n", "\n", "6\n", "90\n", "\n", "\n", "Off\n", "\n", "\n", "Off\n", "Off\n", "\n", "\n", "6\n", "90\n", "\n", "\n", "On\n", "Off\n", "Off\n", "Off\n", "\n", "\n", "Off\n", "Off\n", "\n", "\n", "Off\n", "Off\n", "\n", "\n", "On\n", "Off\n", "Off\n", "Off\n", "Off\n", "\n", "\n", "Off\n", "On\n", "\n", "\n", "50\n", "50\n", "\n", "\n", "On\n", "Off\n", "\n", "\n", "16.97615821\n", "90\n", "\n", "\n", "359.9654362\n", "-0.1245785888\n", "\n", "\n", "Off\n", "\n", "\n", "Off\n", "Off\n", "Off\n", "On\n", "\n", "\n", "2000\n", "\n", "\n", "\n", "\n", "\n", "\n", "On\n", "Off\n", "\n", "\n", "359.9654453\n", "-0.1245811091\n", "\n", "\n", "22.97643675\n", "\n", "\n", "16.97643675\n", "90\n", "\n", "\n", "359.9654544\n", "-0.1245836288\n", "\n", "\n", "22.9767153\n", "\n", "\n", "16.9767153\n", "90\n", "\n", "\n", "Off\n", "On\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Off\n", "On\n", "\n", "\n", "On\n", "Off\n", "\n", "\n", "Unknown\n", "Unknown\n", "N/A\n", "\n", "\n", "0\n", "0\n", "0\n", "\n", "\n", "22.9767153\n", "\n", "\n", "On\n", "Off\n", "\n", "\n", "Off\n", "Off\n", "\n", "\n", "6\n", "90\n", "\n", "\n", "Off\n", "\n", "\n", "Off\n", "Off\n", "\n", "\n", "6\n", "90\n", "\n", "\n", "On\n", "Off\n", "Off\n", "Off\n", "\n", "\n", "Off\n", "Off\n", "\n", "\n", "Off\n", "Off\n", "\n", "\n", "On\n", "Off\n", "Off\n", "Off\n", "Off\n", "\n", "\n", "Off\n", "On\n", "\n", "\n", "50\n", "50\n", "\n", "\n", "On\n", "Off\n", "\n", "\n", "16.97727237\n", "90\n", "\n", "\n", "359.9654726\n", "-0.124588666\n", "\n", "\n", "Off\n", "\n", "\n", "Off\n", "Off\n", "Off\n", "On\n", "\n", "\n", "2000\n", "\n", "\n", "\n", "\n", "\n", "\n", "On\n", "Off\n", "\n", "\n", "359.9654817\n", "-0.1245911836\n", "\n", "\n", "22.97755091\n", "\n", "\n", "16.97755091\n", "90\n", "\n", "\n", "Off\n", "On\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Off\n", "On\n", "\n", "\n", "On\n", "Off\n", "\n", "\n", "Unknown\n", "Unknown\n", "N/A\n", "\n", "\n", "0\n", "0\n", "0\n", "\n", "\n", "22.97755091\n", "\n", "\n", "On\n", "Off\n", "\n", "\n", "Off\n", "Off\n", "\n", "\n", "6\n", "90\n", "\n", "\n", "Off\n", "\n", "\n", "Off\n", "Off\n", "\n", "\n", "6\n", "90\n", "\n", "\n", "On\n", "Off\n", "Off\n", "Off\n", "\n", "\n", "Off\n", "Off\n", "\n", "\n", "Off\n", "Off\n", "\n", "\n", "On\n", "Off\n", "Off\n", "Off\n", "Off\n", "\n", "\n", "Off\n", "On\n", "\n", "\n", "50\n", "50\n", "\n", "\n", "On\n", "Off\n", "\n", "\n", "16.97782944\n", "90\n", "\n", "\n", "359.9654907\n", "-0.1245937005\n", "\n", "\n", "Off\n", "\n", "\n", "Off\n", "Off\n", "Off\n", "On\n", "\n", "\n", "2000\n", "\n", "\n", "\n", "\n", "\n", "\n", "On\n", "Off\n", "\n", "\n", "359.9654998\n", "-0.1245962168\n", "\n", "\n", "22.97810798\n", "\n", "\n", "16.97810798\n", "90\n", "\n", "\n", "359.9655089\n", "-0.1245987324\n", "\n", "\n", "22.97838652\n", "\n", "\n", "16.97838652\n", "90\n", "\n", "\n", "359.965518\n", "-0.1246012474\n", "\n", "\n", "22.97866505\n", "\n", "\n", "16.97866505\n", "90\n", "\n", "\n", "359.9655271\n", "-0.1246037617\n", "\n", "\n", "22.9789436\n", "\n", "\n", "16.9789436\n", "90\n", "\n", "\n", "359.9655362\n", "-0.1246062754\n", "\n", "\n", "22.97922214\n", "\n", "\n", "16.97922214\n", "90\n", "\n", "\n", "359.9655453\n", "-0.1246087883\n", "\n", "\n", "22.97950067\n", "\n", "\n", "16.97950067\n", "90\n", "\n", "\n", "359.9655543\n", "-0.1246113006\n", "\n", "\n", "22.97977921\n", "\n", "\n", "16.97977921\n", "90\n", "\n", "\n", "359.9655634\n", "-0.1246138123\n", "\n", "\n", "22.98005775\n", "\n", "\n", "16.98005775\n", "90\n", "\n", "\n", "359.9655725\n", "-0.1246163233\n", "\n", "\n", "22.98033629\n", "\n", "\n", "16.98033629\n", "90\n", "\n", "\n", "359.9655816\n", "-0.1246188336\n", "\n", "\n", "22.98061482\n", "\n", "\n", "16.98061482\n", "90\n", "\n", "\n", "359.9655907\n", "-0.1246213433\n", "\n", "\n", "22.98089337\n", "\n", "\n", "16.98089337\n", "90\n", "\n", "\n", "359.9655998\n", "-0.1246238523\n", "\n", "\n", "22.98117191\n", "\n", "\n", "16.98117191\n", "90\n", "\n", "\n", "359.9656089\n", "-0.1246263607\n", "\n", "\n", "22.98145044\n", "\n", "\n", "16.98145044\n", "90\n", "\n", "\n", "359.965618\n", "-0.1246288683\n", "\n", "\n", "22.98172898\n", "\n", "\n", "16.98172898\n", "90\n", "\n", "\n", "359.965627\n", "-0.1246313753\n", "\n", "\n", "22.98200752\n", "\n", "\n", "16.98200752\n", "90\n", "\n", "\n", "359.9656361\n", "-0.1246338817\n", "\n", "\n", "22.98228605\n", "\n", "\n", "16.98228605\n", "90\n", "\n", "\n", "359.9656452\n", "-0.1246363873\n", "\n", "\n", "22.98256459\n", "\n", "\n", "16.98256459\n", "90\n", "\n", "\n", "359.9656543\n", "-0.1246388924\n", "\n", "\n", "22.98284313\n", "\n", "\n", "16.98284313\n", "90\n", "\n", "\n", "359.9656634\n", "-0.1246413968\n", "\n", "\n", "22.98312168\n", "\n", "\n", "16.98312168\n", "90\n", "\n", "\n", "359.9656725\n", "-0.1246439005\n", "\n", "\n", "22.98340021\n", "\n", "\n", "16.98340021\n", "90\n", "\n", "\n", "359.9656816\n", "-0.1246464035\n", "\n", "\n", "22.98367875\n", "\n", "\n", "16.98367875\n", "90\n", "\n", "\n", "359.9656907\n", "-0.1246489059\n", "\n", "\n", "22.98395729\n", "\n", "\n", "16.98395729\n", "90\n", "\n", "\n", "359.9656998\n", "-0.1246514076\n", "\n", "\n", "22.98423582\n", "\n", "\n", "16.98423582\n", "90\n", "\n", "\n", "359.9657088\n", "-0.1246539086\n", "\n", "\n", "22.98451436\n", "\n", "\n", "16.98451436\n", "90\n", "\n", "\n", "359.9657179\n", "-0.124656409\n", "\n", "\n", "22.9847929\n", "\n", "\n", "16.9847929\n", "90\n", "\n", "\n", "359.965727\n", "-0.1246589088\n", "\n", "\n", "22.98507144\n", "\n", "\n", "16.98507144\n", "90\n", "\n", "\n", "359.9657361\n", "-0.1246614079\n", "\n", "\n", "22.98534998\n", "\n", "\n", "16.98534998\n", "90\n", "\n", "\n", "359.9657452\n", "-0.1246639063\n", "\n", "\n", "22.98562852\n", "\n", "\n", "16.98562852\n", "90\n", "\n", "\n", "359.9657543\n", "-0.124666404\n", "\n", "\n", "22.98590705\n", "\n", "\n", "16.98590705\n", "90\n", "\n", "\n", "359.9657634\n", "-0.124668901\n", "\n", "\n", "22.98618559\n", "\n", "\n", "16.98618559\n", "90\n", "\n", "\n", "359.9657725\n", "-0.1246713974\n", "\n", "\n", "22.98646413\n", "\n", "\n", "16.98646413\n", "90\n", "\n", "\n", "359.9657816\n", "-0.1246738932\n", "\n", "\n", "22.98674266\n", "\n", "\n", "16.98674266\n", "90\n", "\n", "\n", "359.9657907\n", "-0.1246763882\n", "\n", "\n", "22.9870212\n", "\n", "\n", "16.9870212\n", "90\n", "\n", "\n", "359.9657998\n", "-0.1246788828\n", "\n", "\n", "22.98729975\n", "\n", "\n", "16.98729975\n", "90\n", "\n", "\n", "359.9658088\n", "-0.1246813765\n", "\n", "\n", "22.98757829\n", "\n", "\n", "16.98757829\n", "90\n", "\n", "\n", "359.9658179\n", "-0.1246838696\n", "\n", "\n", "22.98785682\n", "\n", "\n", "16.98785682\n", "90\n", "\n", "\n", "359.965827\n", "-0.124686362\n", "\n", "\n", "22.98813536\n", "\n", "\n", "16.98813536\n", "90\n", "\n", "\n", "359.9658361\n", "-0.1246888538\n", "\n", "\n", "22.9884139\n", "\n", "\n", "16.9884139\n", "90\n", "\n", "\n", "359.9658452\n", "-0.1246913449\n", "\n", "\n", "22.98869243\n", "\n", "\n", "16.98869243\n", "90\n", "\n", "\n", "359.9658543\n", "-0.1246938353\n", "\n", "\n", "22.98897097\n", "\n", "\n", "16.98897097\n", "90\n", "\n", "\n", "359.9658634\n", "-0.1246963252\n", "\n", "\n", "22.98924952\n", "\n", "\n", "16.98924952\n", "90\n", "\n", "\n", "359.9658725\n", "-0.1246988143\n", "\n", "\n", "22.98952806\n", "\n", "\n", "16.98952806\n", "90\n", "\n", "\n", "359.9658816\n", "-0.1247013027\n", "\n", "\n", "22.98980659\n", "\n", "\n", "16.98980659\n", "90\n", "\n", "\n", "359.9658907\n", "-0.1247037905\n", "\n", "\n", "22.99008513\n", "\n", "\n", "16.99008513\n", "90\n", "\n", "\n", "Off\n", "On\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Off\n", "On\n", "\n", "\n", "On\n", "Off\n", "\n", "\n", "Unknown\n", "Unknown\n", "N/A\n", "\n", "\n", "0\n", "0\n", "0\n", "\n", "\n", "22.99008513\n", "\n", "\n", "On\n", "Off\n", "\n", "\n", "Off\n", "Off\n", "\n", "\n", "6\n", "90\n", "\n", "\n", "Off\n", "\n", "\n", "Off\n", "Off\n", "\n", "\n", "6\n", "90\n", "\n", "\n", "On\n", "Off\n", "Off\n", "Off\n", "\n", "\n", "Off\n", "Off\n", "\n", "\n", "Off\n", "Off\n", "\n", "\n", "On\n", "Off\n", "Off\n", "Off\n", "Off\n", "\n", "\n", "Off\n", "On\n", "\n", "\n", "50\n", "50\n", "\n", "\n", "On\n", "Off\n", "\n", "\n", "16.99119929\n", "90\n", "\n", "\n", "359.9659271\n", "-0.1247137351\n", "\n", "\n", "Off\n", "\n", "\n", "Off\n", "Off\n", "Off\n", "On\n", "\n", "\n", "2000\n", "\n", "\n", "\n", "\n", "\n", "\n", "On\n", "Off\n", "\n", "\n", "359.9659362\n", "-0.1247162195\n", "\n", "\n", "22.99147782\n", "\n", "\n", "16.99147782\n", "90\n", "\n", "\n", "359.9659452\n", "-0.1247187033\n", "\n", "\n", "22.99175636\n", "\n", "\n", "16.99175636\n", "90\n", "\n", "\n", "359.9659543\n", "-0.1247211865\n", "\n", "\n", "22.9920349\n", "\n", "\n", "16.9920349\n", "90\n", "\n", "\n", "359.9659634\n", "-0.1247236689\n", "\n", "\n", "22.99231343\n", "\n", "\n", "16.99231343\n", "90\n", "\n", "\n", "359.9659725\n", "-0.1247261507\n", "\n", "\n", "22.99259197\n", "\n", "\n", "16.99259197\n", "90\n", "\n", "\n", "359.9659816\n", "-0.1247286319\n", "\n", "\n", "22.99287051\n", "\n", "\n", "16.99287051\n", "90\n", "\n", "\n", "359.9659907\n", "-0.1247311124\n", "\n", "\n", "22.99314904\n", "\n", "\n", "16.99314904\n", "90\n", "\n", "\n", "359.9659998\n", "-0.1247335923\n", "\n", "\n", "22.99342759\n", "\n", "\n", "16.99342759\n", "90\n", "\n", "\n", "359.9660089\n", "-0.1247360715\n", "\n", "\n", "22.99370613\n", "\n", "\n", "16.99370613\n", "90\n", "\n", "\n", "359.966018\n", "-0.1247385499\n", "\n", "\n", "22.99398467\n", "\n", "\n", "16.99398467\n", "90\n", "\n", "\n", "359.9660271\n", "-0.1247410278\n", "\n", "\n", "22.9942632\n", "\n", "\n", "16.9942632\n", "90\n", "\n", "\n", "359.9660362\n", "-0.124743505\n", "\n", "\n", "22.99454174\n", "\n", "\n", "16.99454174\n", "90\n", "\n", "\n", "359.9660453\n", "-0.1247459815\n", "\n", "\n", "22.99482028\n", "\n", "\n", "16.99482028\n", "90\n", "\n", "\n", "359.9660544\n", "-0.1247484573\n", "\n", "\n", "22.99509881\n", "\n", "\n", "16.99509881\n", "90\n", "\n", "\n", "359.9660635\n", "-0.1247509326\n", "\n", "\n", "22.99537736\n", "\n", "\n", "16.99537736\n", "90\n", "\n", "\n", "359.9660726\n", "-0.1247534071\n", "\n", "\n", "22.9956559\n", "\n", "\n", "16.9956559\n", "90\n", "\n", "\n", "359.9660817\n", "-0.1247558809\n", "\n", "\n", "22.99593444\n", "\n", "\n", "16.99593444\n", "90\n", "\n", "\n", "359.9660908\n", "-0.1247583541\n", "\n", "\n", "22.99621297\n", "\n", "\n", "16.99621297\n", "90\n", "\n", "\n", "359.9660999\n", "-0.1247608266\n", "\n", "\n", "22.99649151\n", "\n", "\n", "16.99649151\n", "90\n", "\n", "\n", "359.966109\n", "-0.1247632985\n", "\n", "\n", "22.99677005\n", "\n", "\n", "16.99677005\n", "90\n", "\n", "\n", "359.9661181\n", "-0.1247657697\n", "\n", "\n", "22.99704858\n", "\n", "\n", "16.99704858\n", "90\n", "\n", "\n", "359.9661272\n", "-0.1247682402\n", "\n", "\n", "22.99732712\n", "\n", "\n", "16.99732712\n", "90\n", "\n", "\n", "359.9661363\n", "-0.1247707102\n", "\n", "\n", "22.99760567\n", "\n", "\n", "16.99760567\n", "90\n", "\n", "\n", "359.9661454\n", "-0.1247731794\n", "\n", "\n", "22.9978842\n", "\n", "\n", "16.9978842\n", "90\n", "\n", "\n", "359.9661545\n", "-0.124775648\n", "\n", "\n", "22.99816274\n", "\n", "\n", "16.99816274\n", "90\n", "\n", "\n", "359.9661636\n", "-0.1247781158\n", "\n", "\n", "22.99844128\n", "\n", "\n", "16.99844128\n", "90\n", "\n", "\n", "359.9661727\n", "-0.1247805831\n", "\n", "\n", "22.99871981\n", "\n", "\n", "16.99871981\n", "90\n", "\n", "\n", "359.9661818\n", "-0.1247830496\n", "\n", "\n", "22.99899835\n", "\n", "\n", "16.99899835\n", "90\n", "\n", "\n", "359.9661909\n", "-0.1247855155\n", "\n", "\n", "22.99927689\n", "\n", "\n", "16.99927689\n", "90\n", "\n", "\n", "359.9662\n", "-0.1247879808\n", "\n", "\n", "22.99955544\n", "\n", "\n", "16.99955544\n", "90\n", "\n", "\n", "359.9662091\n", "-0.1247904454\n", "\n", "\n", "22.99983397\n", "\n", "\n", "16.99983397\n", "90\n", "\n", "\n", "359.9662182\n", "-0.1247929093\n", "\n", "\n", "23.00011251\n", "\n", "\n", "17.00011251\n", "90\n", "\n", "\n", "359.9662273\n", "-0.1247953725\n", "\n", "\n", "23.00039105\n", "\n", "\n", "17.00039105\n", "90\n", "\n", "\n", "359.9662364\n", "-0.1247978351\n", "\n", "\n", "23.00066958\n", "\n", "\n", "17.00066958\n", "90\n", "\n", "\n", "359.9662455\n", "-0.124800297\n", "\n", "\n", "23.00094812\n", "\n", "\n", "17.00094812\n", "90\n", "\n", "\n", "359.9662546\n", "-0.1248027582\n", "\n", "\n", "23.00122666\n", "\n", "\n", "17.00122666\n", "90\n", "\n", "\n" ] } ], "source": [ "recv = recibir(s, 1)" ] }, { "cell_type": "markdown", "id": "4741f3b7-79fc-4fcc-89b2-0166e7a3c32f", "metadata": {}, "source": [ "Lo recibido son todas las propiedades que tiene definidas ese driver en ese momento. En este punto es interesante revisar dichas propiedades y compararlas con la información que nos enseña `KStars`:\n", "\n", "![](ficherosAuxiliares/INDI_kstars_01.jpg)\n", "\n", "Casi todos los dispositivos `INDI` tienen una propiedad llamada `CONNECTION` que hay que activar para que el dispositivo funcione correctamente. Vamos a pedirle al driver que encienda el enfocador:" ] }, { "cell_type": "code", "execution_count": null, "id": "4daa8d3f-3cfd-45a4-8f60-93ef7a1c121b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "b'On'\n" ] } ], "source": [ "mandar(s, f'On')" ] }, { "cell_type": "code", "execution_count": null, "id": "ba0d3527-b86c-46b5-a8d5-852345d75058", "metadata": {}, "outputs": [], "source": [ "recv = recibir(s, 1)" ] }, { "cell_type": "markdown", "id": "fbb76fc3-6e1c-4ed0-8d47-fd0a9c3a1729", "metadata": {}, "source": [ "Tras conectarse hemos recibido la confirmación de que se ha conectado (la propiedad `CONNECTION` tiene su campo `CONNECT` a `ON` (antes estaba a `OFF`) junto con otras muchas propiedades que tenemos disponibles:\n", "\n", "![](ficherosAuxiliares/INDI_kstars_02.jpg)" ] }, { "cell_type": "markdown", "id": "73338310-0375-410b-9fe4-ca80a919a143", "metadata": {}, "source": [ "Para finalizar este ejemplo vamos a pedirle al enfocador que vaya a la posición absoluta `2000` (la inicial es `50000`):" ] }, { "cell_type": "code", "execution_count": null, "id": "8cccd656-7d12-414c-80c7-1547db1e1a67", "metadata": {}, "outputs": [], "source": [ "mandar(s, f'100000')" ] }, { "cell_type": "markdown", "id": "971f0f5c-ae0f-4e8d-a531-3a9b4f2826f4", "metadata": {}, "source": [ "Recibimos los mensajes (dejamos 5 prudentes segundos para asegurarnos que el enfocador ha tenido tiempo de llegar a la posición deseada):" ] }, { "cell_type": "code", "execution_count": null, "id": "9db2eaab-f370-4d04-b21f-4ef1fbbb41e4", "metadata": {}, "outputs": [], "source": [ "recv = recibir(s, 5)" ] }, { "cell_type": "markdown", "id": "0c8403f9-5018-463a-8cbc-b64df31a160e", "metadata": {}, "source": [ "Efectivamente hemos recibido (además de otra información) una nueva posición absoluta de `100000`. Podemos comprobar que en `KStars` también se refleja dicho cambio:\n", "\n", "![](ficherosAuxiliares/INDI_kstars_03.jpg)\n", "\n", "Por último cerraremos el `socket` para desconectarnos del servidor `INDI`:" ] }, { "cell_type": "code", "execution_count": null, "id": "095d0b76-39ac-444f-8820-7fe53dece5bf", "metadata": {}, "outputs": [], "source": [ "s.close()" ] }, { "cell_type": "markdown", "id": "c8fcdfc2-2c05-4d4d-be18-d50199fc53eb", "metadata": {}, "source": [ "## Controlando una CCD simulada y una montura (también simulada)\n", "\n", "Vamos a hacer otro ejemplo para capturar una imagen (`FITS`) de una cámara virtual simulada. El simulador puede mostrar estrellas \"realistas\" si instalamos el `GSC` (*General Star Catalog*). En Linux:\n", "\n", "```\n", "> sudo apt install gsc \n", "```\n", "\n", "Para ello lanzaremos el servidor `INDI` con el driver `indi_simulator_ccd` y el driver `indi_simulator_telescope`:\n", "\n", "```\n", "> indiserver indi_simulator_ccd indi_simulator_telescope\n", "```" ] }, { "cell_type": "code", "execution_count": null, "id": "f535acdd-ac1a-44bc-95f6-579098bb523f", "metadata": {}, "outputs": [], "source": [ "import socket\n", "from pprint import pprint\n", "import time\n", "from datetime import datetime\n", "import regex as re" ] }, { "cell_type": "markdown", "id": "4aa0862e-c75a-4bde-9c23-6313947a3149", "metadata": {}, "source": [ "Conectamos al servidor `INDI`:" ] }, { "cell_type": "code", "execution_count": null, "id": "e7725bcc-cf78-4725-822f-a5067009fa63", "metadata": {}, "outputs": [], "source": [ "s = None\n", " \n", "conectar(\"127.0.0.1\", 7624)\n", "\n", "nombreCamara = \"CCD Simulator\"\n", "nombreMontura = \"Telescope Simulator\"" ] }, { "cell_type": "code", "execution_count": null, "id": "4243c3d8-5559-4b77-9c40-9232197bf333", "metadata": {}, "outputs": [], "source": [ "# mandar(s, '')" ] }, { "cell_type": "code", "execution_count": null, "id": "ccf82f94-660b-421c-9d9e-d6df106bb7f3", "metadata": {}, "outputs": [], "source": [ "# recv = recibir(s, 1)" ] }, { "cell_type": "markdown", "id": "67eb06b6-7ad2-4b5e-b611-715107e31384", "metadata": {}, "source": [ "Conectamos la cámara y la montura:" ] }, { "cell_type": "code", "execution_count": null, "id": "4e8507ba-27a8-49ae-93f5-64d121fa1a88", "metadata": {}, "outputs": [], "source": [ "mandar(s, f'On')\n", "\n", "mandar(s, f'On')" ] }, { "cell_type": "code", "execution_count": null, "id": "d94e7c69-b20f-4045-8240-c7ce9523f6ea", "metadata": {}, "outputs": [], "source": [ "# recv = recibir(s, 1)" ] }, { "cell_type": "markdown", "id": "510f87a6-5b91-44d0-8c19-3280825659c7", "metadata": {}, "source": [ "Activamos la recepción de `BLOBs` (objetos binarios, en este caso y casi siempre imágenes `FITS`:" ] }, { "cell_type": "code", "execution_count": null, "id": "5084c577-5017-4448-a101-316a4d6b3f9e", "metadata": {}, "outputs": [], "source": [ "mandar(s, f'Only\"')" ] }, { "cell_type": "code", "execution_count": null, "id": "c3da37b8-3415-43e5-9cdc-3bf8ddebe473", "metadata": {}, "outputs": [], "source": [ "# recv = recibir(s, 1)" ] }, { "cell_type": "markdown", "id": "fef51d20-3dc1-41d9-a122-15dd2acee826", "metadata": {}, "source": [ "Movemos la montura a Sirio:" ] }, { "cell_type": "code", "execution_count": null, "id": "413351d7-f9c7-4c55-b552-8df81d8a92df", "metadata": {}, "outputs": [], "source": [ "mandar(s, f'6.7685230037972683448-16.746465419192418267')" ] }, { "cell_type": "code", "execution_count": null, "id": "08423de7-f477-4bbb-acf5-6f1cbda13a2a", "metadata": {}, "outputs": [], "source": [ "# recv = recibir(s, 1)" ] }, { "cell_type": "markdown", "id": "0d342e93-0913-48fa-a8e0-b3511c6fef60", "metadata": {}, "source": [ "Tomamos una exposición de 2 segundos y esperamos a que mande los resultados. Cuidado si imprimimos que son varios megas y `Jupyter-Lab` se puede quejar:" ] }, { "cell_type": "code", "execution_count": null, "id": "d62c24dc-13df-4647-92eb-4e66d4331812", "metadata": {}, "outputs": [], "source": [ "mandar(s, f'2.0')\n", "recv = recibir(s, 3, imprimir=False)\n", "\n", "#print(recv[0:1000])\n", "#print(recv[-1000:])" ] }, { "cell_type": "markdown", "id": "28591355-53a7-44e3-b39d-ca6610886db1", "metadata": {}, "source": [ "Buscamos exactamente los datos de la imagen que vienen codificados como una cadena en BASE64 dentro de un elemento ` ... `:" ] }, { "cell_type": "code", "execution_count": null, "id": "9aea6832-8b3a-406f-849c-8b2190bb8ed8", "metadata": {}, "outputs": [], "source": [ "datosBLOB = re.search(r'.*(.*).*', recv, flags=re.DOTALL).group(2)\n", "\n", "#print(datosBLOB[0:1000])\n", "#print(len(datosBLOB))\n", "#print(datosBLOB[-10000:])" ] }, { "cell_type": "markdown", "id": "dc386f3d-85c2-4fa4-819f-c47fc2131167", "metadata": {}, "source": [ "Decodificamos los datos a binario y guardamos la imagen (directamente los datos binarios son los datos del fichero `FITS`):" ] }, { "cell_type": "code", "execution_count": null, "id": "7153f8d7-0195-4b53-a01b-c3a6b8a93d63", "metadata": {}, "outputs": [], "source": [ "import base64\n", "\n", "message_bytes = base64.b64decode(datosBLOB)\n", "\n", "f = open(\"salidas/capturaINDI.fit\", \"wb\")\n", "\n", "f.write(message_bytes)\n", "\n", "f.close()" ] }, { "cell_type": "markdown", "id": "a599fa92-3d62-4151-a39b-7aab9971b5ac", "metadata": {}, "source": [ "Cerramos el `socket`:" ] }, { "cell_type": "code", "execution_count": null, "id": "541372dd-0a0d-42ef-8931-2a7990dad448", "metadata": {}, "outputs": [], "source": [ "s.close()" ] }, { "cell_type": "markdown", "id": "19b482a0-ef1e-4f1d-a67e-739eec48a7c3", "metadata": {}, "source": [ "Mostramos la imagen:" ] }, { "cell_type": "code", "execution_count": null, "id": "81748851-dc9f-4090-9721-7916d75c4d7f", "metadata": {}, "outputs": [], "source": [ "%matplotlib widget\n", "\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "from astropy.io import fits\n", "import matplotlib.colors as colors\n", "\n", "hdul = fits.open(\"salidas/capturaINDI.fit\")\n", "data = hdul[0].data\n", "fig = plt.figure(\"matrix\", figsize=[10, 7])\n", "\n", "image = plt.imshow(data, norm=colors.PowerNorm(gamma=.1, vmin=np.min(data), vmax=np.max(data)/20), origin='lower')\n", "plt.colorbar(label='Counts')" ] }, { "cell_type": "markdown", "id": "2ca817c6-7a48-4f9d-a703-a4d7e8150b7a", "metadata": {}, "source": [ "## Capturando imágenes de una cámara real: ZWO ASI174MM-Cool\n", "\n", "Con casi el mismo código anterior (obviando el tema de la montura) podemos disparar una cámara real. Vamos a lanzar el servidor de `INDI` con el driver correspondiente:\n", "\n", "```\n", "> indiserver indi_asi_ccd\n", "```" ] }, { "cell_type": "code", "execution_count": null, "id": "55133db9-b7d5-4e27-bdaa-c54a29413796", "metadata": {}, "outputs": [], "source": [ "import socket\n", "from pprint import pprint\n", "import time\n", "from datetime import datetime\n", "import regex as re\n", "\n", "s = None\n", " \n", "conectar(\"127.0.0.1\", 7624)\n", "\n", "nombreCamara = \"ZWO CCD ASI174MM-Cool\"\n", "\n", "mandar(s, f'On')\n", "\n", "mandar(s, f'Only\"')\n", "\n", "mandar(s, f'2.0')\n", "\n", "recv = recibir(s, 4, imprimir=False)\n", "\n", "datosBLOB = re.search(r'.*(.*).*', recv, flags=re.DOTALL).group(2)\n", "\n", "import base64\n", "\n", "message_bytes = base64.b64decode(datosBLOB)\n", "\n", "f = open(\"salidas/capturaINDI_ZWO.fit\", \"wb\")\n", "\n", "f.write(message_bytes)\n", "\n", "f.close()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.15" } }, "nbformat": 4, "nbformat_minor": 5 }