{"id":17922601,"url":"https://github.com/rreverser/ascom-alpaca-rs","last_synced_at":"2025-07-27T18:12:32.591Z","repository":{"id":170056916,"uuid":"615855635","full_name":"RReverser/ascom-alpaca-rs","owner":"RReverser","description":"Cross-platform Rust library for the ASCOM Alpaca API for astronomy devices","archived":false,"fork":false,"pushed_at":"2024-12-20T18:22:45.000Z","size":1225,"stargazers_count":20,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-07-15T05:10:45.027Z","etag":null,"topics":["ascom","ascom-alpaca","ascom-alpaca-api","astronomy","devices","drivers","rust","rust-lang"],"latest_commit_sha":null,"homepage":"https://docs.rs/ascom-alpaca","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RReverser.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE-APACHE-2.0","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"RReverser","patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":null}},"created_at":"2023-03-18T21:47:25.000Z","updated_at":"2025-05-21T20:10:58.000Z","dependencies_parsed_at":"2024-01-14T20:13:49.637Z","dependency_job_id":"9b388cf6-679c-4ab6-b4db-a29021ed59e4","html_url":"https://github.com/RReverser/ascom-alpaca-rs","commit_stats":null,"previous_names":["rreverser/ascom-alpaca-rs"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/RReverser/ascom-alpaca-rs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RReverser%2Fascom-alpaca-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RReverser%2Fascom-alpaca-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RReverser%2Fascom-alpaca-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RReverser%2Fascom-alpaca-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RReverser","download_url":"https://codeload.github.com/RReverser/ascom-alpaca-rs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RReverser%2Fascom-alpaca-rs/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267400520,"owners_count":24081183,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-27T02:00:11.917Z","response_time":82,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ascom","ascom-alpaca","ascom-alpaca-api","astronomy","devices","drivers","rust","rust-lang"],"created_at":"2024-10-28T20:39:56.631Z","updated_at":"2025-07-27T18:12:32.565Z","avatar_url":"https://github.com/RReverser.png","language":"Rust","funding_links":["https://github.com/sponsors/RReverser"],"categories":[],"sub_categories":[],"readme":"# ascom-alpaca-rs\n\n\u003c!-- DO NOT EDIT: the rest of this file is autogenerated from `src/lib.rs` by `cargo rdme`. --\u003e\n\u003c!-- cargo-rdme start --\u003e\n\nThis is a Rust implementation of the standard [ASCOM Alpaca API](https://ascom-standards.org/api/) for astronomy devices.\n\nIt implements main Alpaca API clients and servers, as well as transparent support for auto-discovery mechanism and `ImageBytes` encoding for camera images.\n\n## Usage\n\n### Compilation features\n\nThis crate defines two sets of compilation features that help to keep binary size \u0026 compilation speed in check by opting into only the features you need.\n\nFirst set is along the client-server axis:\n\n- `client`: Enables client-side access to Alpaca-capable devices.\n- `server`: Allows to expose your own devices as Alpaca servers.\n\nThe second set of features is based on the device type and enables the corresponding trait:\n\n- `all-devices`: Enables all of the below. Not recommended unless you're building a universal astronomy application.\n- `camera`: Enables support for cameras via the [`Camera`](https://docs.rs/ascom-alpaca/latest/ascom_alpaca/api/trait.Camera.html) trait.\n- `covercalibrator`: Enables [...] the [`CoverCalibrator`](https://docs.rs/ascom-alpaca/latest/ascom_alpaca/api/trait.CoverCalibrator.html) trait.\n- `dome`: Enables [`Dome`](https://docs.rs/ascom-alpaca/latest/ascom_alpaca/api/trait.Dome.html).\n- `filterwheel`: Enables [`FilterWheel`](https://docs.rs/ascom-alpaca/latest/ascom_alpaca/api/trait.FilterWheel.html).\n- `focuser`: Enables [`Focuser`](https://docs.rs/ascom-alpaca/latest/ascom_alpaca/api/trait.Focuser.html).\n- `observingconditions`: Enables [`ObservingConditions`](https://docs.rs/ascom-alpaca/latest/ascom_alpaca/api/trait.ObservingConditions.html).\n- `rotator`: Enables [`Rotator`](https://docs.rs/ascom-alpaca/latest/ascom_alpaca/api/trait.Rotator.html).\n- `switch`: Enables [`Switch`](https://docs.rs/ascom-alpaca/latest/ascom_alpaca/api/trait.Switch.html).\n- `telescope`: Enables [`Telescope`](https://docs.rs/ascom-alpaca/latest/ascom_alpaca/api/trait.Telescope.html).\n\nOnce 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`:\n\n```toml\n[dependencies]\nascom-alpaca = { version = \"0.1\", features = [\"client\", \"camera\"] }\n```\n\n### Device methods\n\nAll the device type trait methods are async and correspond to the [ASCOM Alpaca API](https://ascom-standards.org/api/). They all return `ASCOMResult\u003c...\u003e`.\n\nThe [`Device`](https://docs.rs/ascom-alpaca/latest/ascom_alpaca/api/trait.Device.html) 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:\n\n- `fn static_name(\u0026self) -\u003e \u0026str`: Returns the static device name.\n- `fn unique_id(\u0026self) -\u003e \u0026str`: Returns globally-unique device ID.\n\n### Implementing a device server\n\nSince async traits are not yet natively supported on stable Rust, the traits are implemented using the [async-trait](https://crates.io/crates/async-trait) crate. Other than that, you should implement trait with all the Alpaca methods as usual:\n\n```rust\nuse ascom_alpaca::ASCOMResult;\nuse ascom_alpaca::api::{Device, Camera};\nuse async_trait::async_trait;\n\n#[derive(Debug)]\nstruct MyCamera {\n    // ...\n}\n\n#[async_trait]\nimpl Device for MyCamera {\n    fn static_name(\u0026self) -\u003e \u0026str {\n        \"My Camera\"\n    }\n\n    fn unique_id(\u0026self) -\u003e \u0026str {\n        \"insert GUID here\"\n    }\n\n    // ...\n}\n\n#[async_trait]\nimpl Camera for MyCamera {\n    async fn bayer_offset_x(\u0026self) -\u003e ASCOMResult\u003ci32\u003e {\n        Ok(0)\n    }\n\n    async fn bayer_offset_y(\u0026self) -\u003e ASCOMResult\u003ci32\u003e {\n        Ok(0)\n    }\n\n    // ...\n}\n```\n\nAny skipped methods will default to the following values:\n\n- `can_*` feature detection methods - to `false`.\n- `Device::name` - to the result of `Device::static_name()`.\n- `Device::interface_version` - to `3` (latest ASCOM interface version implemented by this crate).\n- `Device::supported_actions` - to an empty list.\n- All other methods - to `Err(ASCOMError::NOT_IMPLEMENTED)`. It's your responsibility to consult documentation and implement mandatory methods.\n\nOnce traits are implemented, you can create a server, register your device(s), and start listening:\n\n```rust\nuse ascom_alpaca::Server;\nuse ascom_alpaca::api::CargoServerInfo;\nuse std::convert::Infallible;\n\n// ...implement MyCamera...\n\n#[tokio::main]\nasync fn main() -\u003e eyre::Result\u003cInfallible\u003e {\n    let mut server = Server {\n        // helper macro to populate server information from your own Cargo.toml\n        info: CargoServerInfo!(),\n        ..Default::default()\n    };\n\n    // By default, the server will listen on dual-stack (IPv4 + IPv6) unspecified address with a randomly assigned port.\n    // You can change that by modifying the `listen_addr` field:\n    server.listen_addr.set_port(8000);\n\n    // Create and register your device(s).\n    server.devices.register(MyCamera { /* ... */ });\n\n    // Start the infinite server loop.\n    server.start().await\n}\n```\n\nThis will start both the main Alpaca server as well as an auto-discovery responder.\n\n**Examples:**\n\n- [`examples/camera-server.rs`](https://github.com/RReverser/ascom-alpaca-rs/blob/main/examples/camera-server.rs):\n  A cross-platform example exposing your connected webcam(s) as Alpaca `Camera`s.\n\n  ```log\n  \u003e env RUST_LOG=debug { cargo run --example camera-server --release }\n        Finished release [optimized] target(s) in 0.60s\n         Running `target\\release\\examples\\camera-server.exe`\n    2023-05-27T15:21:43.336191Z DEBUG camera_server: Registering webcam webcam=Webcam { unique_id: \"150ddacb-7ad9-4754-b289-ae56210693e8::0\", name: \"Integrated Camera\", description: \"MediaFoundation Camera\", max_format: CameraFormat { resolution: Resolution { width_x: 1280, height_y: 720 }, format: MJPEG, frame_rate: 30 }, subframe: RwLock { data: Subframe { bin: Size { x: 1, y: 1 }, offset: Point { x: 0, y: 0 }, size: Size { x: 1280, y: 720 } } }, last_exposure_start_time: RwLock { data: None }, last_exposure_duration: RwLock { data: None }, valid_bins: [1, 2, 4] }\n    2023-05-27T15:21:43.339433Z DEBUG ascom_alpaca::server: Binding Alpaca server addr=[::]:8000\n    2023-05-27T15:21:43.342897Z  INFO ascom_alpaca::server: Bound Alpaca server bound_addr=[::]:8000\n    2023-05-27T15:21:43.369040Z  WARN join_multicast_groups{listen_addr=::}: ascom_alpaca::server::discovery: err=An unknown,\n    invalid, or unsupported option or level was specified in a getsockopt or setsockopt call. (os error 10042)\n    2023-05-27T15:21:43.370932Z DEBUG join_multicast_groups{listen_addr=::}: ascom_alpaca::server::discovery: return=()\n    2023-05-27T15:21:43.371861Z DEBUG ascom_alpaca::server: Bound Alpaca discovery server\n    ```\n\n  Binning is implemented by switching the webcam to other supported resolutions which are proportional to the original.\n\n  Long exposures are simulated by stacking up individual frames up to the total duration.\n  This approach can't provide precise requested exposure, but works well enough otherwise.\n\n- [`star-adventurer-alpaca`](https://github.com/jsorrell/star-adventurer-alpaca): An implentation of the Alpaca protocol for Star Adventurer trackers.\n- [`qhyccd-alpaca`](https://github.com/ivonnyssen/qhyccd-alpaca): Alpaca driver for QHYCCD cameras and filter wheels written in Rust.\n\n### Accessing devices from a client\n\nIf you know address of the device server you want to access, you can access it directly via `Client` struct:\n\n```rust\nuse ascom_alpaca::Client;\n\nlet client = Client::new(\"http://localhost:8000\")?;\n\n// `get_server_info` returns high-level metadata of the server.\nprintln!(\"Server info: {:#?}\", client.get_server_info().await?);\n\n// `get_devices` returns an iterator over all the devices registered on the server.\n// Each is represented as a `TypedDevice` tagged enum encompassing all the device types as corresponding trait objects.\n// You can either match on them to select the devices you're interested in, or, say, just print all of them:\nprintln!(\"Devices: {:#?}\", client.get_devices().await?.collect::\u003cVec\u003c_\u003e\u003e());\n```\n\nIf you want to discover device servers on the local network, you can do that via the `discovery::DiscoveryClient` struct:\n\n```rust\nuse ascom_alpaca::discovery::DiscoveryClient;\nuse ascom_alpaca::Client;\nuse futures::prelude::*;\n\n// This holds configuration for the discovery client.\n// You can customize prior to binding if you want.\nlet discovery_client = DiscoveryClient::new();\n// This results in a discovery client bound to a local socket.\n// It's intentionally split out into a separate API step to encourage reuse,\n// for example so that user could click \"Refresh devices\" button in the UI\n// and the application wouldn't have to re-bind the socket every time.\nlet mut bound_client = discovery_client.bind().await?;\n// Now you can discover devices on the local networks.\nbound_client.discover_addrs()\n    // create a `Client` for each discovered address\n    .map(|addr| Ok(Client::new_from_addr(addr)))\n    .try_for_each(|client| async move {\n        /* ...do something with devices via each client... */\n        Ok::\u003c_, eyre::Error\u003e(())\n    })\n    .await?;\n```\n\nOr, if you just want to list all available devices and don't care about per-server information or errors:\n\n```rust\nbound_client.discover_devices()\n    .for_each(|device| async move {\n        /* ...do something with each device... */\n    })\n    .await;\n```\n\nKeep in mind that discovery is a UDP-based protocol, so it's not guaranteed to be reliable.\n\nAlso, same device server can be discovered multiple times if it's available on multiple network interfaces.\nWhile it's not possible to reliably deduplicate servers, you can deduplicate devices by storing them in something like `HashSet`\nor in the same `Devices` struct that is used for registering arbitrary devices on the server:\n\n```rust\nuse ascom_alpaca::api::{Camera, Devices};\nuse ascom_alpaca::discovery::DiscoveryClient;\nuse ascom_alpaca::Client;\nuse futures::prelude::*;\n\nlet devices =\n    DiscoveryClient::new()\n    .bind()\n    .await?\n    .discover_devices()\n    .collect::\u003cDevices\u003e()\n    .await;\n\n// Now you can iterate over all the discovered devices via `iter_all`:\nfor (typed_device, index_within_category) in devices.iter_all() {\n    println!(\"Discovered device: {typed_device:#?} (index: {index_within_category})\");\n}\n\n// ...or over devices in a specific category via `iter\u003cdyn Trait\u003e`:\nfor camera in devices.iter::\u003cdyn Camera\u003e() {\n    println!(\"Discovered camera: {camera:#?}\");\n}\n```\n\n**Examples:**\n\n- [`examples/discover.rs`](https://github.com/RReverser/ascom-alpaca-rs/blob/main/examples/discover.rs):\n  A simple discovery example listing all the found servers and devices.\n\n- [`examples/camera-client.rs`](https://github.com/RReverser/ascom-alpaca-rs/blob/main/examples/camera-client.rs):\n  A cross-platform GUI example showing a live preview stream from discovered Alpaca cameras.\n\n  Includes support for colour, monochrome and Bayer sensors with automatic colour conversion for the preview.\n\n  \u003cimg alt=\"Screenshot of a live view from the simulator camera\" src=\"https://github.com/RReverser/ascom-alpaca-rs/assets/557590/faecb549-dc0c-4f07-902f-7d49429b6458\" width=\"50%\" /\u003e\n\n### Logging and tracing\n\nThis crate uses [`tracing`](https://crates.io/crates/tracing) framework for logging spans and events, integrating with the Alpaca `ClientID`, `ClientTransactionID` and `ServerTransactionID` fields.\n\nYou can enable logging in your app by using any of the [subscriber crates](https://crates.io/crates/tracing#ecosystem).\n\nFor example, [`tracing_subscriber::fmt`](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/fmt/index.html) will log all the events to stderr depending on the `RUST_LOG` environment variable:\n\n```rust\ntracing_subscriber::fmt::init();\n```\n\n## Testing\n\nSince this is a library for communicating to networked devices, it should be tested against real devices at a higher level.\n\nIn particular, if you're implementing an Alpaca device, make sure to run [ConformU](https://github.com/ASCOMInitiative/ConformU) - ASCOM's official conformance checker - against your device server.\n\n## License\n\nLicensed under either of\n\n- Apache License, Version 2.0 ([LICENSE-APACHE-2.0](LICENSE-APACHE-2.0))\n- MIT license ([LICENSE-MIT](LICENSE-MIT))\n\n\u003c!-- cargo-rdme end --\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frreverser%2Fascom-alpaca-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frreverser%2Fascom-alpaca-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frreverser%2Fascom-alpaca-rs/lists"}