diff --git a/mytest/src/main.rs b/mytest/src/main.rs index 1743576..c30bd3d 100644 --- a/mytest/src/main.rs +++ b/mytest/src/main.rs @@ -1,6 +1,6 @@ use daikin_altherma::DaikinAlthermaClient; fn main() { - let mut a = DaikinAlthermaClient::new("192.168.11.100".to_string()); + let mut a = DaikinAlthermaClient::new("192.168.11.100".to_string()).unwrap(); // let am = a.get_adapter_model(); // println!("Adapter model: {am}"); // @@ -13,7 +13,7 @@ fn main() { let tp = a.get_tank_parameters().unwrap(); println!("Tank: {:?}", tp); - a.set_tank_powerful(true); + a.set_tank_powerful(false); let tp = a.get_tank_parameters().unwrap(); println!("Tank: {:?}", tp); diff --git a/src/lib.rs b/src/lib.rs index 2ee3260..4817701 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -use std::{fmt::Debug, net::TcpStream}; +use std::{error::Error, fmt::Debug, net::TcpStream}; use thiserror::Error; use uuid::Uuid; @@ -16,6 +16,12 @@ pub enum DAError { SetValueError(String), #[error("No such field")] NoSuchFieldError, + #[error("Value conversion error")] + ValueConversionError, + #[error("Url Parse error")] + UrlParseError, + #[error("WebSocket Error")] + WebSocketError, } pub struct DaikinAlthermaClient { @@ -62,80 +68,62 @@ trait FromJsonValue: Sized { // Implement the trait for i64 impl FromJsonValue for i64 { fn from_json_value(value: &Value) -> Result { - let v: Option = value.as_i64(); - match v { - Some(x) => Ok(x), - _ => Err(DAError::ConversionError), - } + value.as_i64().ok_or(DAError::ValueConversionError) } } // Implement the trait for f64 impl FromJsonValue for f64 { fn from_json_value(value: &Value) -> Result { - let v: Option = value.as_f64(); - match v { - Some(x) => Ok(x), - _ => Err(DAError::ConversionError), - } + value.as_f64().ok_or(DAError::ValueConversionError) } } // Implement the trait for String impl FromJsonValue for String { fn from_json_value(value: &Value) -> Result { - let v: Option<&str> = value.as_str(); - match v { - Some(x) => Ok(x.to_string()), - _ => Err(DAError::ConversionError), - } + let v = value.as_str().ok_or(DAError::ValueConversionError)?; + Ok(v.to_string()) } } // Implement the trait for bool impl FromJsonValue for bool { fn from_json_value(value: &Value) -> Result { - let v: Option = value.as_bool(); - match v { - Some(x) => Ok(x), - _ => Err(DAError::ConversionError), - } + value.as_bool().ok_or(DAError::ValueConversionError) } } impl DaikinAlthermaClient { /// Creates a new client to a Daikin Altherma LAN adapter. - pub fn new(adapter_hostname: String) -> Self { + pub fn new(adapter_hostname: String) -> Result { let url_str = format!("ws://{adapter_hostname}/mca"); - let url = Url::parse(&url_str).unwrap(); - let ws_client = connect(url).unwrap(); - DaikinAlthermaClient { + let url = Url::parse(&url_str).map_err(|_| DAError::UrlParseError)?; + let ws_client = connect(url).map_err(|_| DAError::WebSocketError)?; + + Ok(DaikinAlthermaClient { ws_client: ws_client.0, - } + }) } /// Returns the model of the LAN adapter. E.g. BRP069A61 - pub fn get_adapter_model(&mut self) -> String { - let v = self - .request_value("MNCSE-node/deviceInfo", None, "/m2m:rsp/pc/m2m:dvi/mod") - .unwrap(); + pub fn get_adapter_model(&mut self) -> Result { + let v = self.request_value("MNCSE-node/deviceInfo", None, "/m2m:rsp/pc/m2m:dvi/mod")?; - return v.as_str().unwrap().to_string(); + match v.as_str() { + Some(x) => Ok(x.to_string()), + None => Err(DAError::NoSuchFieldError), + } } pub fn get_tank_parameters(&mut self) -> Result { - let temperature: f64 = self - .request_value_hp_dft("2/Sensor/TankTemperature/la") - .unwrap(); + let temperature: f64 = self.request_value_hp_dft("2/Sensor/TankTemperature/la")?; - let setpoint_temperature: f64 = self - .request_value_hp_dft("2/Operation/TargetTemperature/la") - .unwrap(); + let setpoint_temperature: f64 = + self.request_value_hp_dft("2/Operation/TargetTemperature/la")?; - let enabled_str: String = self.request_value_hp_dft("2/Operation/Power/la").unwrap(); - let powerful_i: i64 = self - .request_value_hp_dft("2/Operation/Powerful/la") - .unwrap(); + let enabled_str: String = self.request_value_hp_dft("2/Operation/Power/la")?; + let powerful_i: i64 = self.request_value_hp_dft("2/Operation/Powerful/la")?; Ok(TankParameters { temperature, @@ -158,8 +146,6 @@ impl DaikinAlthermaClient { }); self.set_value_hp("2/Operation/Power", Some(payload), "/") - .unwrap(); - Ok(()) } /// Enables or disable the tank powerful mode @@ -175,32 +161,23 @@ impl DaikinAlthermaClient { }); self.set_value_hp("2/Operation/Powerful", Some(payload), "/") - .unwrap(); - Ok(()) } pub fn get_heating_parameters(&mut self) -> Result { - let indoor_temperature: f64 = self - .request_value_hp_dft("1/Sensor/IndoorTemperature/la") - .unwrap(); + let indoor_temperature: f64 = self.request_value_hp_dft("1/Sensor/IndoorTemperature/la")?; - let outdoor_temperature: f64 = self - .request_value_hp_dft("1/Sensor/OutdoorTemperature/la") - .unwrap(); + let outdoor_temperature: f64 = + self.request_value_hp_dft("1/Sensor/OutdoorTemperature/la")?; - let indoor_setpoint_temperature: f64 = self - .request_value_hp_dft("1/Operation/TargetTemperature/la") - .unwrap(); + let indoor_setpoint_temperature: f64 = + self.request_value_hp_dft("1/Operation/TargetTemperature/la")?; - let leaving_water_temperature: f64 = self - .request_value_hp_dft("1/Sensor/LeavingWaterTemperatureCurrent/la") - .unwrap(); + let leaving_water_temperature: f64 = + self.request_value_hp_dft("1/Sensor/LeavingWaterTemperatureCurrent/la")?; - let enabled_str: String = self.request_value_hp_dft("1/Operation/Power/la").unwrap(); + let enabled_str: String = self.request_value_hp_dft("1/Operation/Power/la")?; - let on_holiday: i64 = self - .request_value_hp_dft("1/Holiday/HolidayState/la") - .unwrap(); + let on_holiday: i64 = self.request_value_hp_dft("1/Holiday/HolidayState/la")?; Ok(HeatingParameters { indoor_temperature, @@ -224,8 +201,6 @@ impl DaikinAlthermaClient { }); self.set_value_hp("1/Holiday/HolidayState", Some(payload), "/") - .unwrap(); - Ok(()) } /// Sets the heating setpoint (target) temperature, in °C @@ -236,8 +211,6 @@ impl DaikinAlthermaClient { }); self.set_value_hp("1/Operation/TargetTemperature", Some(payload), "/") - .unwrap(); - Ok(()) } /// Enables or disables the heating @@ -253,15 +226,11 @@ impl DaikinAlthermaClient { }); self.set_value_hp("1/Operation/Power", Some(payload), "/") - .unwrap(); - Ok(()) } fn request_value_hp_dft>(&mut self, item: &str) -> Result { let hp_item = format!("MNAE/{item}"); - let json_val = self - .request_value(hp_item.as_str(), None, "/m2m:rsp/pc/m2m:cin/con") - .unwrap(); + let json_val = self.request_value(hp_item.as_str(), None, "/m2m:rsp/pc/m2m:cin/con")?; T::from_json_value(&json_val) } @@ -272,14 +241,8 @@ impl DaikinAlthermaClient { output_path: &str, ) -> Result<(), DAError> { let hp_item = format!("MNAE/{item}"); - self.request_value(hp_item.as_str(), payload, output_path); - /* - match result { - Ok(x) => Ok(()), - Err(x) => Err(x), - } - */ - Ok(()) + self.request_value(hp_item.as_str(), payload, output_path) + .map(|_| ()) } fn request_value( @@ -313,8 +276,6 @@ impl DaikinAlthermaClient { .extend(set_value_params.as_object().unwrap().clone()); } - println!(">>> {js_request}"); - self.ws_client .send(Message::Text(js_request.to_string())) .expect("Can't write message"); @@ -329,8 +290,7 @@ impl DaikinAlthermaClient { assert_eq!(result["m2m:rsp"]["rqi"], reqid); assert_eq!(result["m2m:rsp"]["to"], "hello"); //XXX - // - println!("<<< {result}"); + match result.pointer(output_path) { Some(v) => Ok(v.clone()), None => Err(DAError::NoSuchFieldError),