INDINexus¶
A modern, typed Python framework for INDI astronomical instrument control. Write drivers in clean async Python, watch them from a typed client, and put a polished React UI in front of your observatory - all on one shared, validated protocol model.
-
Drivers in Python
Subclass
Device, declare properties, poll with@every, handle writes with@on_new. The standard INDI lifecycle - connection, dispatch, supervision - is built in. -
React components & hooks
@indi-nexus/clientspeaks the wire;@indi-nexus/reactturns any INDI device into a live, themed UI with hooks likeusePropertyand components likeDevicePanel.
See it live¶
The real INDINexus panel, running against a simulated dome driver entirely in your browser - no server behind it. Connect the dome, open the shutter, send it to an azimuth, park it, and watch the INDI message log narrate.
The stack¶
Driver (Python) <-stdio XML-> indiserver:7624 <-TCP-> IndiClient (Python)
|
FastAPI bridge
| WebSocket (typed JSON)
React panel / your UI
- Keep C
indiserveras the hub - existing INDI drivers and clients interoperate; INDINexus modernizes the Python and browser layers. - Dual protocol - canonical INDI 1.7 XML on the wire, typed JSON to browsers, one Pydantic model as the shared contract.
- Fully typed -
mypy --strictPython, TypeScript end to end.
Quick taste¶
from indi_nexus.driver import Device, every, on_new
from indi_nexus.protocol import IPState, Number
class Mount(Device):
name = "Mount"
async def setup(self) -> None:
self.define_connection()
self.define_number(
"EQUATORIAL_EOD_COORD",
[Number(name="RA", format="%9.6m"), Number(name="DEC", format="%9.6m")],
)
@every(seconds=1, when_connected=True)
async def poll(self) -> None:
ra, dec = await self.read_mount()
self["EQUATORIAL_EOD_COORD"].set(RA=ra, DEC=dec, state=IPState.OK)
import { IndiProvider, useElement, DevicePanel } from "@indi-nexus/react";
import "@indi-nexus/react/styles.css";
export const App = () => (
<IndiProvider url="ws://localhost:8000/ws">
<DevicePanel device="Mount" />
</IndiProvider>
);