12 releases
Uses new Rust 2024
| new 1.0.0-beta.10 | Jan 13, 2026 |
|---|---|
| 1.0.0-beta.8 | Jan 11, 2026 |
| 1.0.0-beta.7 | Dec 28, 2025 |
| 1.0.0-beta.6 | Sep 9, 2025 |
| 1.0.0-beta.1 | May 27, 2023 |
#278 in Hardware support
1,040 downloads per month
Used in qhyccd-alpaca
280KB
5K
SLoC
ascom-alpaca-rs
This is a Rust implementation of the standard ASCOM Alpaca API for astronomy devices.
It implements main Alpaca API clients and servers, as well as transparent support for auto-discovery mechanism and ImageBytes encoding for camera images.
The usage documentation lives at docs.rs.
lib.rs:
This is a Rust implementation of the standard ASCOM Alpaca API for astronomy devices.
It implements main Alpaca API clients and servers, as well as transparent support for auto-discovery mechanism and ImageBytes encoding for camera images.
Compilation features
This crate defines two sets of compilation features that help to keep binary size & compilation speed in check by opting into only the features you need.
First set is along the client-server axis:
client: Enables client-side access to Alpaca-capable devices.server: Allows to expose your own devices as Alpaca servers.
The second set of features is based on the device type and enables the corresponding trait:
all-devices: Enables all of the below. Not recommended unless you're building a universal astronomy application.camera: Enables support for cameras via theCameratrait.cover_calibrator: Enables [...] theCoverCalibratortrait.dome: EnablesDome.filter_wheel: EnablesFilterWheel.focuser: EnablesFocuser.observing_conditions: EnablesObservingConditions.rotator: EnablesRotator.switch: EnablesSwitch.telescope: EnablesTelescope.
Once you decided on the features you need, you can add this crate to your Cargo.toml. For example, if I'm implementing an Alpaca camera driver, I'd add the following to my Cargo.toml:
[dependencies]
ascom-alpaca = { version = "0.1", features = ["client", "camera"] }
ascom-alpaca also provides a test feature that enables testing utilities for both clients and servers. See the corresponding section below for details.
Device methods
All the device type trait methods are async and correspond to the ASCOM Alpaca API. They all return ASCOMResult<...>.
The Device supertrait includes "ASCOM Methods Common To All Devices" from the Alpaca API, as well as a few custom metadata methods used for the device registration:
fn static_name(&self) -> &str: Returns the static device name.fn unique_id(&self) -> &str: Returns globally-unique device ID.
Implementing a device server
Since async traits are not yet natively supported on stable Rust, the traits are implemented using the async-trait crate. Other than that, you should implement trait with all the Alpaca methods as usual:
use ascom_alpaca::ASCOMResult;
use ascom_alpaca::api::{Device, Camera};
use async_trait::async_trait;
#[derive(Debug)]
struct MyCamera {
// ...
}
#[async_trait]
impl Device for MyCamera {
fn static_name(&self) -> &str {
"My Camera"
}
fn unique_id(&self) -> &str {
"insert GUID here"
}
// ...
}
#[async_trait]
impl Camera for MyCamera {
async fn bayer_offset_x(&self) -> ASCOMResult<i32> {
Ok(0)
}
async fn bayer_offset_y(&self) -> ASCOMResult<i32> {
Ok(0)
}
// ...
}
Any skipped methods will default to the following values:
can_*feature detection methods - tofalse.Device::name- to the result ofDevice::static_name().Device::supported_actions- to an empty list.- All other methods - to
Err(ASCOMError::NOT_IMPLEMENTED). It's your responsibility to consult documentation and implement mandatory methods.
Once traits are implemented, you can create a server, register your device(s), and start listening:
use ascom_alpaca::Server;
use ascom_alpaca::api::CargoServerInfo;
use std::convert::Infallible;
// ...implement MyCamera...
#
#[tokio::main]
async fn main() -> eyre::Result<Infallible> {
// create with the helper macro that populate server information from your own Cargo.toml
let mut server = Server::new(CargoServerInfo!());
// By default, the server will listen on dual-stack (IPv4 + IPv6) unspecified address with a randomly assigned port.
// You can change that by modifying the `listen_addr` field:
server.listen_addr.set_port(8000);
// Create and register your device(s).
server.devices.register(MyCamera { /* ...
Dependencies
~11–32MB
~358K SLoC