{
"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/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",
"\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",
""
]
},
{
"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",
"\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
}