chore(home-assistant): implement the revised light protocol

This commit is contained in:
2025-05-03 21:07:08 -04:00
parent 50e9ee43f7
commit 089e96b99f
3 changed files with 70 additions and 84 deletions

View File

@@ -26,7 +26,7 @@ pyo3-async-runtimes = { workspace = true, features = ["tokio-runtime"] }
python-utils = { path = "../python-utils" } python-utils = { path = "../python-utils" }
smol_str = "0.3.2" smol_str = "0.3.2"
snafu = { workspace = true } snafu = { workspace = true }
strum = { version = "0.27.1", features = ["derive"] } strum = { workspace = true, features = ["derive"] }
tokio = { workspace = true } tokio = { workspace = true }
tracing = { optional = true, workspace = true } tracing = { optional = true, workspace = true }
ulid = "1.2.0" ulid = "1.2.0"

View File

@@ -4,85 +4,49 @@ use crate::{
event::context::context::Context, event::context::context::Context,
state::{ErrorState, HomeAssistantState, UnexpectedState}, state::{ErrorState, HomeAssistantState, UnexpectedState},
}; };
use arbitrary_value::arbitrary::Arbitrary; use protocol::light::{GetState, SetState};
use protocol::light::Light;
use pyo3::prelude::*; use pyo3::prelude::*;
use python_utils::IsNone;
use snafu::{ResultExt, Snafu}; use snafu::{ResultExt, Snafu};
#[derive(Debug, Snafu)] #[derive(Debug, Snafu)]
pub enum IsStateError { pub enum GetStateError {
GetStateObjectError { source: GetStateObjectError }, GetStateObjectError { source: GetStateObjectError },
Error { state: ErrorState }, Error { state: ErrorState },
UnexpectedError { state: UnexpectedState }, UnexpectedError { state: UnexpectedState },
} }
impl Light for HomeAssistantLight { impl GetState for HomeAssistantLight {
type IsOnError = IsStateError; type Error = GetStateError;
async fn is_on(&self) -> Result<bool, Self::IsOnError> { async fn get_state(&self) -> Result<protocol::light::State, Self::Error> {
let state_object = self.get_state_object().context(GetStateObjectSnafu)?; let state_object = self.get_state_object().context(GetStateObjectSnafu)?;
let state = state_object.state; let state = state_object.state;
match state { match state {
HomeAssistantState::Ok(light_state) => Ok(matches!(light_state, LightState::On)), HomeAssistantState::Ok(light_state) => Ok(light_state.into()),
HomeAssistantState::Err(state) => Err(IsStateError::Error { state }), HomeAssistantState::Err(error_state) => {
Err(GetStateError::Error { state: error_state })
}
HomeAssistantState::UnexpectedErr(state) => { HomeAssistantState::UnexpectedErr(state) => {
Err(IsStateError::UnexpectedError { state }) Err(GetStateError::UnexpectedError { state })
}
} }
} }
} }
type IsOffError = IsStateError; impl SetState for HomeAssistantLight {
type Error = PyErr;
async fn is_off(&self) -> Result<bool, Self::IsOffError> { async fn set_state(&mut self, state: protocol::light::State) -> Result<(), Self::Error> {
let state_object = self.get_state_object().context(GetStateObjectSnafu)?;
let state = state_object.state;
match state {
HomeAssistantState::Ok(light_state) => Ok(matches!(light_state, LightState::Off)),
HomeAssistantState::Err(state) => Err(IsStateError::Error { state }),
HomeAssistantState::UnexpectedErr(state) => {
Err(IsStateError::UnexpectedError { state })
}
}
}
type TurnOnError = PyErr;
async fn turn_on(&mut self) -> Result<(), Self::TurnOnError> {
let context: Option<Context<()>> = None; let context: Option<Context<()>> = None;
let target: Option<()> = None; let target: Option<()> = None;
let services = Python::with_gil(|py| self.home_assistant.services(py))?; let services = Python::with_gil(|py| self.home_assistant.services(py))?;
// TODO
let service_response: Arbitrary = services
.call_service(
TurnOn {
entity_id: self.entity_id(),
},
context,
target,
false,
)
.await?;
// TODO let _: IsNone = match state {
#[cfg(feature = "tracing")] protocol::light::State::Off => {
tracing::info!(?service_response); services
Ok(())
}
type TurnOffError = PyErr;
async fn turn_off(&mut self) -> Result<(), Self::TurnOffError> {
let context: Option<Context<()>> = None;
let target: Option<()> = None;
let services = Python::with_gil(|py| self.home_assistant.services(py))?;
// TODO
let service_response: Arbitrary // TODO: a type that validates as None
= services
.call_service( .call_service(
TurnOff { TurnOff {
entity_id: self.entity_id(), entity_id: self.entity_id(),
@@ -91,18 +55,22 @@ impl Light for HomeAssistantLight {
target, target,
false, false,
) )
.await?; .await
}
// TODO protocol::light::State::On => {
#[cfg(feature = "tracing")] services
tracing::info!(?service_response); .call_service(
TurnOn {
entity_id: self.entity_id(),
},
context,
target,
false,
)
.await
}
}?;
Ok(()) Ok(())
} }
type ToggleError = PyErr;
async fn toggle(&mut self) -> Result<(), Self::ToggleError> {
todo!()
}
} }

View File

@@ -20,3 +20,21 @@ impl<'py> FromPyObject<'py> for LightState {
Ok(state) Ok(state)
} }
} }
impl From<LightState> for protocol::light::State {
fn from(light_state: LightState) -> Self {
match light_state {
LightState::On => protocol::light::State::On,
LightState::Off => protocol::light::State::Off,
}
}
}
impl From<protocol::light::State> for LightState {
fn from(state: protocol::light::State) -> Self {
match state {
protocol::light::State::On => LightState::On,
protocol::light::State::Off => LightState::Off,
}
}
}