Si tienes un observatorio remoto con la montura AZ-GTi controlada desde una Raspberry Pi con KStars/INDI, es posible que en algún momento hayas querido usar la aplicación SynScan Pro —disponible para iOS y Android— para apuntar la montura manualmente, hacer un alineamiento rápido o simplemente ver el estado del firmware. El problema es que SynScan Pro solo está disponible para Mac o Windows, y si tu montura está conectada a un Linux, no hay opciones. La aplicación SynScan Pro se comunica con la montura a través del protocolo SynScan, y cuando la montura está conectada físicamente por cable USB a la Raspberry Pi, no hay ninguna forma directa de que la app del móvil o del Mac acceda a ese puerto serie.
Este artículo explica cómo solucionar exactamente eso: crear un puerto serie virtual en tu Mac que, de forma transparente, se comunica con el puerto USB físico de la Raspberry Pi a través de un túnel SSH. Sin drivers raros, sin hardware adicional, y con reconexión automática si se cae la red. La conexión aquí descrita vale para cualquier montura SkyWatcher que tenga conexión serie conectada a una Raspberry.
NOTA: he probado esta configuración correctamente con las monturas AZ-GTi y la Wave 150i. En el caso de la Wave 150i, mediante esta solución se puede realizar el Auto Home de forma remota, sin estar físicamente al lado de la montura.
El problema
La montura AZ-GTi en modo ecuatorial se puede manejar con KStars/EKOS a través de INDI, que se ejecuta en la Raspberry Pi y accede directamente al puerto serie (/dev/ttyUSB0 o similar). Hasta aquí todo bien.
El problema llega cuando quieres usar SynScan Pro en paralelo, por ejemplo para:
- Actualizar el firmware de la montura.
- Hacer un alineamiento en 2 o 3 estrellas con la app.
- Consultar la versión del firmware o la configuración actual.
SynScan Pro puede conectarse a la montura de dos formas: por Wi-Fi o por puerto serie. La montura en modo cable no ofrece Wi-Fi, así que la única opción sería el puerto serie… que está ocupado por la Raspberry Pi.
La solución pasa por exponer ese puerto serie remoto como si fuera un puerto serie local en tu Mac, usando socat y un túnel SSH. Tu Mac verá un fichero del tipo ~/virtual-serial que actúa exactamente igual que si tuvieras el cable USB de la montura enchufado directamente al Mac.
La arquitectura
El flujo de datos es el siguiente:
[ SynScan Pro / Mac app ]
│
[ ~/virtual-serial ] ← puerto serie virtual (symlink a un PTY)
│
(socat)
│
[ Puerto local 4000 ]
│
[ Túnel SSH cifrado ] ──→ [ Internet / Red 4G ] ──→ [ Raspberry Pi ]
│
[ Puerto TCP 6000 ]
│
(socat)
│
[ /dev/ttyUSB0 @ 115200 bps ]
│
[ Montura AZ-GTi ]
Para el Mac, ~/virtual-serial es un puerto serie como cualquier otro. Para la Raspberry Pi, es simplemente una conexión TCP en el puerto 6000. El túnel SSH en el medio cifra y enruta los datos entre los dos extremos. Todo completamente transparente.
Requisitos previos
En la Raspberry Pi:
socatinstalado (sudo apt install -y socat iproute2)- Acceso SSH con clave (sin contraseña), para que el túnel pueda reconectarse automáticamente
- El dispositivo serie accesible (comprueba con
ls -l /dev/serial/by-id/)
En el Mac:
socatinstalado (brew install socat)- SSH configurado para conectar a la Pi (ya sea con IP directa, reenvío de puertos en el router, o un hostname en
~/.ssh/config)
Nota sobre la velocidad: Las versiones antiguas de la montura AZ-GTi usaban 9600 bps. Las versiones modernas usan 115200 bps. Asegúrate de que la velocidad es la misma en los dos extremos.
Parte 1: El lado de la Raspberry Pi (pi_serial_proxy.sh)
En la Raspberry Pi hay que ejecutar un script que quede en segundo plano escuchando en el puerto TCP 6000 y conectando cada nueva conexión con el puerto serie físico.
El script pi_serial_proxy.sh hace exactamente eso, con un bucle de vigilancia que reinicia socat automáticamente si se cae:
#!/bin/bash
SERIAL_PORT="${SERIAL_PORT:-/dev/serial/by-id/usb-Prolific_Technology_Inc._USB-Serial_Controller_D-if00-port0}"
BAUD_RATE="${BAUD_RATE:-115200}"
TCP_PORT="${TCP_PORT:-6000}"
SCRIPT_NAME=$(basename "$0")
function start(){
while true; do
if ! ss -tuln | grep -q ":$TCP_PORT "; then
echo "Iniciando socat: $SERIAL_PORT a puerto TCP $TCP_PORT a $BAUD_RATE bps..."
socat TCP-LISTEN:$TCP_PORT,reuseaddr,fork "$SERIAL_PORT,b$BAUD_RATE,raw,echo=0" &
else
echo "Puerto TCP $TCP_PORT ya en uso"
fi
sleep 10
done
}
function stop(){
pkill -f "$SCRIPT_NAME start"
pkill -f "socat TCP-LISTEN:${TCP_PORT}"
echo "Proxy en la Pi terminado."
}
case $1 in
start) start ;;
stop) stop ;;
*) echo "Uso: $0 {start|stop}"; exit 1 ;;
esac
Para arrancarlo en segundo plano y que siga funcionando aunque cierres la sesión SSH:
nohup ./pi_serial_proxy.sh start > ~/pi_serial_proxy.log 2>&1 &
Con variables personalizadas, por si tu dispositivo serie tiene un path diferente:
SERIAL_PORT=/dev/ttyUSB0 BAUD_RATE=115200 TCP_PORT=6000 ./pi_serial_proxy.sh start
Para pararlo:
./pi_serial_proxy.sh stop
Parte 2: El lado del Mac (mac_serial_client.sh)
En el Mac, el script se encarga de dos cosas: abrir el túnel SSH y crear el puerto serie virtual. Además, incluye un bucle de reconexión para que si se cae la red 4G (cosa que pasa, especialmente en observatorios remotos), el sistema se recupere solo.
#!/bin/bash
REMOTE_SERVER="${REMOTE_SERVER:-astropi}"
REMOTE_PORT="${REMOTE_PORT:-6000}"
LOCAL_PORT="${LOCAL_PORT:-4000}"
BAUD_RATE="${BAUD_RATE:-115200}"
VIRTUAL_SERIAL="$HOME/virtual-serial"
SCRIPT_NAME=$(basename "$0")
function port_is_listening() {
ss -tuln 2>/dev/null | grep -q ":$LOCAL_PORT " || \
netstat -anp tcp 2>/dev/null | grep -q "\.$LOCAL_PORT .*LISTEN"
}
function start() {
killall socat 2>/dev/null
rm -f "$VIRTUAL_SERIAL"
SOCAT_PID=""
while true; do
if ! port_is_listening; then
echo "Túnel SSH caído. Reconectando..."
if [ -n "$SOCAT_PID" ] && kill -0 "$SOCAT_PID" 2>/dev/null; then
kill "$SOCAT_PID" 2>/dev/null
SOCAT_PID=""
rm -f "$VIRTUAL_SERIAL"
fi
ssh -4 -o ServerAliveInterval=15 -o ServerAliveCountMax=3 \
-L "$LOCAL_PORT:127.0.0.1:$REMOTE_PORT" "$REMOTE_SERVER" -N &
SSH_PID=$!
while ! port_is_listening; do
sleep 1
if ! kill -0 "$SSH_PID" 2>/dev/null; then break; fi
done
fi
if port_is_listening && { [ -z "$SOCAT_PID" ] || ! kill -0 "$SOCAT_PID" 2>/dev/null; }; then
echo "Creando puerto serie virtual $VIRTUAL_SERIAL a $BAUD_RATE bps..."
socat PTY,link="$VIRTUAL_SERIAL",raw,ispeed=$BAUD_RATE,ospeed=$BAUD_RATE,echo=0 \
TCP:127.0.0.1:$LOCAL_PORT &
SOCAT_PID=$!
fi
sleep 5
done
}
function stop(){
pkill -f "$SCRIPT_NAME start"
pkill -f "ssh -4 .*-L ${LOCAL_PORT}:127.0.0.1:${REMOTE_PORT}"
killall socat 2>/dev/null
rm -f "$VIRTUAL_SERIAL"
echo "Proxy serie en el Mac terminado."
}
case "$1" in
start) start ;;
stop) stop ;;
*) echo "Uso: $0 {start|stop}"; exit 1 ;;
esac
Para arrancarlo simplemente:
./mac_serial_client.sh start
Con variables personalizadas (si tu Pi no está en ~/.ssh/config como astropi):
REMOTE_SERVER=pi@raspberrypi.local REMOTE_PORT=6000 LOCAL_PORT=4000 BAUD_RATE=115200 \
./mac_serial_client.sh start
Para pararlo:
./mac_serial_client.sh stop
¿Cómo funciona el REMOTE_SERVER?
El script del Mac usa el valor de REMOTE_SERVER como destino SSH. Puede ser:
- Un hostname de
~/.ssh/config, por ejemploastropisi tienes una entrada así en tu fichero de configuración SSH. Esta es la opción más cómoda, especialmente si tu Pi está detrás de un router con reenvío de puertos en un puerto no estándar (como el2222). - Una dirección del tipo
usuario@ip-publicasi quieres pasarlo directamente.
Un ejemplo de entrada en ~/.ssh/config para un observatorio remoto detrás de un router 4G:
Host astropi
HostName ip-publica-del-router
User pi
Port 2222
IdentityFile ~/.ssh/id_ed25519
ServerAliveInterval 15
ServerAliveCountMax 3
Con esto, ssh astropi funciona directamente, y el script de Mac también.
Usando el puerto serie virtual
Una vez que el script del Mac está corriendo, tendrás disponible ~/virtual-serial como si fuera un puerto serie USB conectado físicamente. Puedes apuntarle cualquier aplicación que acepte un dispositivo serie.
Para verificar que todo funciona antes de abrir SynScan Pro:
screen $HOME/virtual-serial 115200
Si ves datos o puedes enviar comandos a la montura, el túnel está funcionando correctamente.
En SynScan Pro (versión Mac/iOS), configura la conexión serie apuntando a ~/virtual-serial con velocidad 115200. La app no notará ninguna diferencia respecto a tener el cable conectado localmente.
Prueba local antes de ir al observatorio
Antes de depender de este sistema en remoto, conviene validarlo todo en local usando un túnel SSH de loopback en el propio Mac. Así puedes comprobar el funcionamiento sin necesitar la red 4G ni la Pi. El procedimiento completo tiene cuatro pasos, cada uno en un terminal diferente:
Terminal 1 — El túnel SSH interno:
Abre un túnel IPv4 de loopback que reenvía el puerto local 4000 al 6000:
ssh -4 -L 4000:127.0.0.1:6000 127.0.0.1 -N
Nota: puede ser necesario activar el acceso en Configuración del Sistema → General → Compartir → Inicio de sesión remoto para que el loopback SSH funcione en macOS.
Terminal 2 — El puente de hardware:
Conecta el puerto TCP 6000 directamente al puerto serie físico. En macOS usa ispeed/ospeed:
socat TCP-LISTEN:6000,reuseaddr,fork /dev/cu.usbserial,ispeed=115200,ospeed=115200,raw,echo=0
Terminal 3 — El puerto serie virtual:
Crea el symlink ~/vsource que la aplicación verá como un puerto serie nativo:
socat PTY,link=$HOME/vsource,raw,echo=0 TCP:127.0.0.1:4000
Terminal 4 — Verificación:
Conecta un emulador de terminal al enlace virtual para comprobar que los datos fluyen correctamente:
screen $HOME/vsource 115200
Si ves respuesta de la montura, el pipeline completo funciona. Cuando lo valides así en local, puedes estar seguro de que en remoto, con la Pi en el otro extremo, también funcionará.
Prueba con SynScan Pro
Para esta prueba, debes tener conectada la montura en tu equipo local, mediante el puerto serie del Mac.
Ahora abre SynScan Pro en el Mac y ves a Configuración > Configuración de Conexion > Serie, y fija el Serial Port y la velocidad correspondiente.
A continuación pulsa el boton Conectar en la parte superior.
Notas finales
- Los scripts están diseñados para correr continuamente. Si cierras el terminal, usa
nohuposcreen/tmuxpara que sigan en segundo plano. - La velocidad (
BAUD_RATE) debe ser la misma en la Pi y en el Mac. Si no sabes qué velocidad usa tu montura, prueba con 115200 primero (versiones modernas) y si no funciona, con 9600 (versiones antiguas). - Si el SSH no conecta, prueba primero a mano:
ssh astropi. Si eso falla, el script tampoco funcionará. - El puerto 6000 se eligió deliberadamente para evitar conflictos con servicios del sistema de macOS (AirPlay, ControlCenter) que ocupan puertos más bajos como el 5000.
- Para encontrar el dispositivo serie correcto en la Pi:
ls -l /dev/serial/by-id/. Usar el path deby-iden lugar de/dev/ttyUSB0es más robusto, ya que no cambia si reinicias o reconectas el USB.
Con esto, SynScan Pro funciona a la perfección sobre la montura AZ-GTi conectada a la Raspberry Pi, sin necesidad de tener una versión nativa de la app para Linux ni ningún tipo de emulación. Todo el trabajo lo hace socat en los dos extremos y SSH en el medio.