forked from danrusei/hass-rs
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
110 additions
and
86 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,14 @@ | ||
[package] | ||
name = "hass-rs" | ||
version = "0.2.0" | ||
version = "0.3.0" | ||
description = "An async websocket client for Home Assistant" | ||
keywords = ["hass", "homeassistant", "tokio", "async-std"] | ||
authors = ["Dan Rusei <[email protected]>"] | ||
repository = "https://github.com/danrusei/hass-rs" | ||
documentation = "https://docs.rs/hass-rs" | ||
readme = "README.md" | ||
license = "MIT" | ||
edition = "2018" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,106 +1,128 @@ | ||
# Hass-Rs | ||
|
||
A simple async Rust client library for interacting with Home Assistant websocket API. | ||
A simple async Rust client library for interacting with Home Assistant **websocket** API. | ||
|
||
## Configure: | ||
|
||
hass-rs supports tokio and async-std runtimes, by default it uses async-std, to use tokio change the feature flags in Cargo.toml | ||
## Test environment | ||
|
||
with [async-std](https://async.rs/) support | ||
Connect to your Home Assistant server, or follow the instructions from the [Instalation Guide](https://www.home-assistant.io/installation/). | ||
For development, [docker](https://www.home-assistant.io/installation/linux#install-home-assistant-container) can be used to easily bootstrap a test environment. | ||
|
||
```toml | ||
[dependencies] | ||
hass-rs = { version = "0.2", features = ["async-std-runtime"] } | ||
``` | ||
Steps to run the provided Examples: | ||
|
||
with [tokio](https://tokio.rs/) support | ||
* clone the hass_rs github repository | ||
* run the homeassistant server in a docker container | ||
|
||
```toml | ||
[dependencies] | ||
hass-rs = { version = "0.2", features = ["tokio-runtime"] } | ||
```bash | ||
docker run -d --name="home-assistant" -v /PATH_TO_YOUR_CONFIG:/config -v /etc/localtime:/etc/localtime:ro --net=host homeassistant/home-assistant:stable | ||
``` | ||
|
||
* login to Home Assistant web interface: <http://localhost:8123/> | ||
* go to `Profile` --> `Long-Lived Access Tokens` and create a token to be used by hass_rs client | ||
* set the environment variable ***export HASS_TOKEN=<YOUR_TOKEN_HERE>*** | ||
* run the example scripts: `cargo run --example get_cmds` or `cargo run --example call_service` or `cargo run --example subscribe_event` | ||
|
||
## Example usage | ||
|
||
Check the [Example folder](https://github.com/danrusei/hass-rs/tree/master/examples) for additional details on how to use various hass-rs functions. | ||
|
||
```rust | ||
use env_logger; | ||
use hass_rs::client; | ||
use hass_rs::client::HassClient; | ||
|
||
use async_tungstenite::tungstenite::{Error, Message}; | ||
use futures_util::{ | ||
stream::{SplitSink, SplitStream}, | ||
SinkExt, StreamExt, | ||
}; | ||
use lazy_static::lazy_static; | ||
use std::env::var; | ||
use tokio::io::{AsyncRead, AsyncWrite}; | ||
use tokio::sync::{mpsc, mpsc::Receiver, mpsc::Sender}; | ||
use tokio_tungstenite::{connect_async, WebSocketStream}; | ||
|
||
lazy_static! { | ||
static ref TOKEN: String = | ||
var("HASS_TOKEN").expect("please set up the HASS_TOKEN env variable before running this"); | ||
} | ||
|
||
#[cfg_attr(feature = "async-std-runtime", async_std::main)] | ||
async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||
env_logger::init(); | ||
|
||
println!("Creating the Websocket Client and Authenticate the session"); | ||
let mut client = client::connect("localhost", 8123).await?; | ||
|
||
client.auth_with_longlivedtoken(&*TOKEN).await?; | ||
println!("WebSocket connection and authethication works"); | ||
async fn ws_incoming_messages( | ||
mut stream: SplitStream<WebSocketStream<impl AsyncRead + AsyncWrite + Unpin>>, | ||
to_user: Sender<Result<Message, Error>>, | ||
) { | ||
loop { | ||
while let Some(message) = stream.next().await { | ||
let _ = to_user.send(message).await; | ||
} | ||
} | ||
} | ||
|
||
println!("Get Hass Config"); | ||
match client.get_config().await { | ||
Ok(v) => println!("{:?}", v), | ||
Err(err) => println!("Oh no, an error: {}", err), | ||
async fn ws_outgoing_messages( | ||
mut sink: SplitSink<WebSocketStream<impl AsyncRead + AsyncWrite + Unpin>, Message>, | ||
mut from_user: Receiver<Message>, | ||
) { | ||
loop { | ||
match from_user.recv().await { | ||
Some(msg) => sink.send(msg).await.expect("Failed to send message"), | ||
None => continue, | ||
} | ||
} | ||
Ok(()) | ||
} | ||
``` | ||
|
||
## Test environment | ||
#[tokio::main] | ||
async fn main() { | ||
let url = "ws://localhost:8123/api/websocket"; | ||
|
||
Use docker to easily bootstrap a test environment. | ||
println!("Connecting to - {}", url); | ||
let (wsclient, _) = connect_async(url).await.expect("Failed to connect"); | ||
let (sink, stream) = wsclient.split(); | ||
|
||
Steps: | ||
//Channels to recieve the Client Command and send it over to Websocket server | ||
let (to_gateway, from_user) = mpsc::channel::<Message>(20); | ||
//Channels to receive the Response from the Websocket server and send it over to Client | ||
let (to_user, from_gateway) = mpsc::channel::<Result<Message, Error>>(20); | ||
|
||
* clone the hass_rs github repository | ||
* execute the below command, which runs the docker homeassistant container in background | ||
// Handle incoming messages in a separate task | ||
let read_handle = tokio::spawn(ws_incoming_messages(stream, to_user)); | ||
|
||
```bash | ||
$ docker run -d --name="home-assistant" -v /PATH_TO_YOUR_CONFIG:/config -v /etc/localtime:/etc/localtime:ro --net=host homeassistant/home-assistant:stable | ||
``` | ||
// Read from command line and send messages | ||
let write_handle = tokio::spawn(ws_outgoing_messages(sink, from_user)); | ||
|
||
* login to Home Assistant web interface: http://localhost:8123/ | ||
* go to `Profile` --> `Long-Lived Access Tokens` and create a token to be used by hass_rs client | ||
* set the environment variable ***export HASS_TOKEN=<YOUR_TOKEN_HERE>*** | ||
* run the tests with `cargo test` | ||
* run the example scripts: `cargo run --example ping` or `cargo run --example fetch_items` or `cargo run --example subscribe_event` | ||
|
||
## API reference | ||
|
||
* **client::connect(host, port)** - establish the websocket connection to Home Assistant server. | ||
* **client::connect_to_url(url)** - connect using a given URL (use this if you are using a WSS connection) | ||
* **client.auth_with_longlivedtoken(token)** - authenticate the session using a long-lived access token. | ||
* **client.ping()** - can serve as a heartbeat, to ensure the connection is still alive. | ||
* **client.subscribe_event(event_name, callback)** - subscribe the client to the event bus. the callback is a closure, of type Fn(WSEvent), which is executed every time when a specific event is received. | ||
* **client.unsubscribe_event(subscription_id)** - unsubscribe the client from the event bus. | ||
* **client.get_config()** - it gets a dump of the current config in Home Assistant. | ||
* **client.get_states()** - it gets a dump of all the current states in Home Assistant. | ||
* **client.get_services()** - it gets a dump of the current services in Home Assistant. | ||
* **client.call_service(domain, service, service_data)** - it calls call a service in Home Assistant. | ||
let mut client = HassClient::new(to_gateway, from_gateway); | ||
|
||
## Development status | ||
client | ||
.auth_with_longlivedtoken(&*TOKEN) | ||
.await | ||
.expect("Not able to autheticate"); | ||
|
||
- [x] Create the client | ||
- [ ] Automatic reconnection (TBD) | ||
- [x] Authenticate using long-lived access tokens | ||
- [ ] Authenticate using OAuth2 (TBD) | ||
- [x] Call a service | ||
- [x] Subscribe | ||
- [x] Events | ||
- [ ] Config (you need this?, raise an Issue) | ||
- [ ] Services (you need this?, raise an Issue) | ||
- [x] UnSubscribe | ||
- [x] Fetch Commands | ||
- [x] Fetching states | ||
- [x] Fetching config | ||
- [x] Fetching services | ||
- [x] Fetching panels | ||
- [ ] Fetching media player thumbnails (you need this?, raise an Issue) | ||
- [x] Ping - Pong | ||
println!("WebSocket connection and authethication works\n"); | ||
|
||
println!("Getting the Config:\n"); | ||
let cmd2 = client | ||
.get_config() | ||
.await | ||
.expect("Unable to retrieve the Config"); | ||
println!("config: {}\n", cmd2); | ||
|
||
// Await both tasks (optional, depending on your use case) | ||
let _ = tokio::try_join!(read_handle, write_handle); | ||
} | ||
``` | ||
|
||
## Development status | ||
|
||
* [x] Create the client | ||
* [ ] Automatic reconnection (TBD) | ||
* [x] Authenticate using long-lived access tokens | ||
* [ ] Authenticate using OAuth2 (TBD) | ||
* [x] Call a service | ||
* [x] Subscribe | ||
* [x] Events | ||
* [ ] Config (you need this?, raise an Issue) | ||
* [ ] Services (you need this?, raise an Issue) | ||
* [x] UnSubscribe | ||
* [x] Fetch Commands | ||
* [x] Fetching states | ||
* [x] Fetching config | ||
* [x] Fetching services | ||
* [x] Fetching panels | ||
* [ ] Fetching media player thumbnails (you need this?, raise an Issue) | ||
* [ ] Ping - Pong |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters