chore+feat(home-assistant): update to pyo3 0.27 and update extraction errors, switch out SmolStr for Arc<str>, tighten up light service calls and implement some for notify, start implementing units of measurement like for power
This commit is contained in:
@@ -3,7 +3,9 @@ use pyo3::prelude::*;
|
||||
use snafu::{ResultExt, Snafu};
|
||||
use state::LightState;
|
||||
|
||||
use crate::state::HomeAssistantState;
|
||||
use crate::{
|
||||
home_assistant::GetStatesError, state::HomeAssistantState, state_machine::GetStateError,
|
||||
};
|
||||
|
||||
use super::{
|
||||
domain::Domain, entity_id::EntityId, home_assistant::HomeAssistant, object_id::ObjectId,
|
||||
@@ -29,7 +31,15 @@ impl HomeAssistantLight {
|
||||
|
||||
#[derive(Debug, Snafu)]
|
||||
pub enum GetStateObjectError {
|
||||
PythonError { source: PyErr },
|
||||
/// couldn't get the state machine registry
|
||||
GetStatesError { source: GetStatesError },
|
||||
|
||||
/// this state object exists in the state machine registry, but it couldn't be extracted as a light state object
|
||||
GetStateError { source: GetStateError<
|
||||
<StateObject<HomeAssistantState<LightState>, LightAttributes, Py<PyAny>> as FromPyObject<'static, 'static>>::Error
|
||||
> },
|
||||
|
||||
/// this entity does not have a state object in the registry
|
||||
EntityMissing,
|
||||
}
|
||||
|
||||
@@ -40,12 +50,12 @@ impl HomeAssistantLight {
|
||||
StateObject<HomeAssistantState<LightState>, LightAttributes, Py<PyAny>>,
|
||||
GetStateObjectError,
|
||||
> {
|
||||
Python::with_gil(|py| {
|
||||
let states = self.home_assistant.states(py).context(PythonSnafu)?;
|
||||
Python::attach(|py| {
|
||||
let states = self.home_assistant.states(py).context(GetStatesSnafu)?;
|
||||
let entity_id = self.entity_id();
|
||||
let state_object = states
|
||||
.get(py, entity_id)
|
||||
.context(PythonSnafu)?
|
||||
.context(GetStateSnafu)?
|
||||
.ok_or(GetStateObjectError::EntityMissing)?;
|
||||
|
||||
Ok(state_object)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use super::service::{turn_off::TurnOff, turn_on::TurnOn};
|
||||
use super::{state::LightState, GetStateObjectError, HomeAssistantLight};
|
||||
use super::{GetStateObjectError, HomeAssistantLight};
|
||||
use crate::home_assistant::GetServicesError;
|
||||
use crate::service_registry::CallServiceError;
|
||||
use crate::{
|
||||
event::context::context::Context,
|
||||
state::{ErrorState, HomeAssistantState, UnexpectedState},
|
||||
@@ -35,21 +37,31 @@ impl GetState for HomeAssistantLight {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Snafu)]
|
||||
pub enum SetStateError {
|
||||
/// couldn't get the service registry
|
||||
GetServicesError { source: GetServicesError },
|
||||
|
||||
/// couldn't call the service
|
||||
CallServiceError { source: CallServiceError },
|
||||
}
|
||||
|
||||
impl SetState for HomeAssistantLight {
|
||||
type Error = PyErr;
|
||||
type Error = SetStateError;
|
||||
|
||||
async fn set_state(&mut self, state: protocol::light::State) -> Result<(), Self::Error> {
|
||||
let context: Option<Context<()>> = None;
|
||||
let target: Option<()> = None;
|
||||
|
||||
let services = Python::with_gil(|py| self.home_assistant.services(py))?;
|
||||
let services =
|
||||
Python::attach(|py| self.home_assistant.services(py)).context(GetServicesSnafu)?;
|
||||
|
||||
let _: IsNone = match state {
|
||||
protocol::light::State::Off => {
|
||||
services
|
||||
.call_service(
|
||||
TurnOff {
|
||||
entity_id: self.entity_id(),
|
||||
object_id: self.object_id.clone(),
|
||||
},
|
||||
context,
|
||||
target,
|
||||
@@ -61,7 +73,7 @@ impl SetState for HomeAssistantLight {
|
||||
services
|
||||
.call_service(
|
||||
TurnOn {
|
||||
entity_id: self.entity_id(),
|
||||
object_id: self.object_id.clone(),
|
||||
},
|
||||
context,
|
||||
target,
|
||||
@@ -69,7 +81,8 @@ impl SetState for HomeAssistantLight {
|
||||
)
|
||||
.await
|
||||
}
|
||||
}?;
|
||||
}
|
||||
.context(CallServiceSnafu)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -3,13 +3,12 @@ use std::str::FromStr;
|
||||
use pyo3::IntoPyObject;
|
||||
|
||||
use crate::{
|
||||
entity_id::EntityId,
|
||||
service::{service_domain::ServiceDomain, service_id::ServiceId, IntoServiceCall},
|
||||
domain::Domain, entity_id::EntityId, object_id::ObjectId, service::{IntoServiceCall, service_domain::ServiceDomain, service_id::ServiceId}
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TurnOff {
|
||||
pub entity_id: EntityId,
|
||||
pub object_id: ObjectId,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, IntoPyObject)]
|
||||
@@ -24,7 +23,8 @@ impl IntoServiceCall for TurnOff {
|
||||
let service_domain = ServiceDomain::from_str("light").expect("statically written and known to be a valid slug; hoping to get compiler checks instead in the future");
|
||||
let service_id = ServiceId::from_str("turn_off").expect("statically written and known to be a valid slug; hoping to get compiler checks instead in the future");
|
||||
|
||||
let Self { entity_id } = self;
|
||||
let Self { object_id } = self;
|
||||
let entity_id = EntityId(Domain::Light, object_id);
|
||||
|
||||
let service_data = TurnOffServiceData { entity_id };
|
||||
|
||||
|
||||
@@ -3,13 +3,12 @@ use std::str::FromStr;
|
||||
use pyo3::IntoPyObject;
|
||||
|
||||
use crate::{
|
||||
entity_id::EntityId,
|
||||
service::{service_domain::ServiceDomain, service_id::ServiceId, IntoServiceCall},
|
||||
domain::Domain, entity_id::EntityId, object_id::ObjectId, service::{IntoServiceCall, service_domain::ServiceDomain, service_id::ServiceId}
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TurnOn {
|
||||
pub entity_id: EntityId,
|
||||
pub object_id: ObjectId,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, IntoPyObject)]
|
||||
@@ -24,7 +23,9 @@ impl IntoServiceCall for TurnOn {
|
||||
let service_domain = ServiceDomain::from_str("light").expect("statically written and known to be a valid slug; hoping to get compiler checks instead in the future");
|
||||
let service_id = ServiceId::from_str("turn_on").expect("statically written and known to be a valid slug; hoping to get compiler checks instead in the future");
|
||||
|
||||
let Self { entity_id } = self;
|
||||
let Self { object_id } = self;
|
||||
let entity_id = EntityId(Domain::Light, object_id);
|
||||
|
||||
let service_data = TurnOnServiceData { entity_id };
|
||||
|
||||
(service_domain, service_id, service_data)
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use pyo3::{exceptions::PyValueError, prelude::*};
|
||||
use pyo3::{
|
||||
exceptions::{PyException, PyValueError},
|
||||
prelude::*,
|
||||
};
|
||||
use snafu::{ResultExt, Snafu};
|
||||
use strum::EnumString;
|
||||
|
||||
#[derive(Debug, Clone, EnumString, strum::Display)]
|
||||
@@ -10,12 +14,36 @@ pub enum LightState {
|
||||
Off,
|
||||
}
|
||||
|
||||
impl<'py> FromPyObject<'py> for LightState {
|
||||
fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
|
||||
let s = ob.extract::<String>()?;
|
||||
#[derive(Debug, Snafu)]
|
||||
pub enum ExtractLightStateError {
|
||||
/// couldn't extract the object as a string
|
||||
ExtractStringError { source: PyErr },
|
||||
|
||||
let state =
|
||||
LightState::from_str(&s).map_err(|err| PyValueError::new_err(err.to_string()))?;
|
||||
/// couldn't parse the string as a [`LightState`]
|
||||
ParseError {
|
||||
source: <LightState as FromStr>::Err,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<ExtractLightStateError> for PyErr {
|
||||
fn from(error: ExtractLightStateError) -> Self {
|
||||
match &error {
|
||||
ExtractLightStateError::ExtractStringError { .. } => {
|
||||
PyException::new_err(error.to_string())
|
||||
}
|
||||
ExtractLightStateError::ParseError { .. } => PyValueError::new_err(error.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: replace with a derive(PyFromStr) (analogous to serde_with::DeserializeFromStr) once I make one
|
||||
impl<'a, 'py> FromPyObject<'a, 'py> for LightState {
|
||||
type Error = ExtractLightStateError;
|
||||
|
||||
fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result<Self, Self::Error> {
|
||||
let s = ob.extract::<&str>().context(ExtractStringSnafu)?;
|
||||
|
||||
let state = LightState::from_str(&s).context(ParseSnafu)?;
|
||||
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user