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