Compare commits
10 commits
585547b920
...
b298a7a16a
Author | SHA1 | Date | |
---|---|---|---|
b298a7a16a | |||
68f834a2cc | |||
e1eebd6971 | |||
db0036a2bc | |||
12efb33cf2 | |||
4f5ea343f3 | |||
4aaa22139b | |||
4486e9617c | |||
4013b2239a | |||
1dd1b17363 |
12 changed files with 318 additions and 152 deletions
19
.forgejo/workflows/publish.yml
Normal file
19
.forgejo/workflows/publish.yml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
name: publish crate
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- cicd
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: stable
|
||||||
|
override: true
|
||||||
|
- uses: katyo/publish-crates@v2
|
||||||
|
with:
|
||||||
|
registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -50,7 +50,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "daikin_altherma"
|
name = "daikin_altherma"
|
||||||
version = "0.1.0"
|
version = "0.0.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
@ -156,14 +156,6 @@ version = "0.4.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mytest"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"daikin_altherma",
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.3.1"
|
version = "2.3.1"
|
||||||
|
|
17
Cargo.toml
17
Cargo.toml
|
@ -1,8 +1,17 @@
|
||||||
workspace = { members = ["mytest"] }
|
|
||||||
[package]
|
[package]
|
||||||
name = "daikin_altherma"
|
name = "daikin_altherma"
|
||||||
version = "0.1.0"
|
version = "0.0.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
description = "A client for Daikin Altherma LAN adapters"
|
||||||
|
documentation = "https://docs.rs/daikin_altherma"
|
||||||
|
homepage = "https://github.com/Frankkkkk/daikin-altherma-rs"
|
||||||
|
repository = "https://github.com/Frankkkkk/daikin-altherma-rs"
|
||||||
|
keywords = ["daikin", "altherma", "BRP069A61", "BRP069A62"]
|
||||||
|
categories = ["API bindings"]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
@ -13,4 +22,8 @@ tungstenite = "0.21.0"
|
||||||
url = "2.5.0"
|
url = "2.5.0"
|
||||||
|
|
||||||
[dependencies.uuid]
|
[dependencies.uuid]
|
||||||
|
version = "1.7.0"
|
||||||
features = ["v4"]
|
features = ["v4"]
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"]
|
||||||
|
|
30
README.md
Normal file
30
README.md
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# Daikin Altherma Rust client
|
||||||
|
|
||||||
|
This project interfaces with Daikin Altherma LAN adapters (BRP069A61 BRP069A62).
|
||||||
|
|
||||||
|
This is a Rust port of the excellent [python-daikin-altherma](https://github.com/Frankkkkk/python-daikin-altherma)
|
||||||
|
|
||||||
|
<!-- cargo-rdme start -->
|
||||||
|
|
||||||
|
## API to Daikin Altherma LAN Adapters
|
||||||
|
|
||||||
|
This rust crate interfaces with Daikin Altherma LAN adapteros.
|
||||||
|
|
||||||
|
There are two firmware versions of the LAN adapters:
|
||||||
|
- Cloud connected
|
||||||
|
- LAN only
|
||||||
|
|
||||||
|
This library only supports the second one for the moment.
|
||||||
|
### Usage
|
||||||
|
Using this library is rather easy:
|
||||||
|
```rust
|
||||||
|
let mut client = DaikinAlthermaClient::new("192.168.11.100".to_string()).unwrap();
|
||||||
|
|
||||||
|
let hp = client.get_heating_parameters().unwrap();
|
||||||
|
println!("Heating: {:?}", hp);
|
||||||
|
|
||||||
|
client.set_heating_setpoint_temperature(20.0);
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- cargo-rdme end -->
|
||||||
|
|
15
examples/get_values.rs
Normal file
15
examples/get_values.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
use daikin_altherma::DaikinAlthermaClient;
|
||||||
|
fn main() {
|
||||||
|
let mut a = DaikinAlthermaClient::new("192.168.11.100".to_string()).unwrap();
|
||||||
|
|
||||||
|
let tp = a.get_tank_parameters().unwrap();
|
||||||
|
println!("Tank: {:?}", tp);
|
||||||
|
|
||||||
|
a.set_tank_powerful(false);
|
||||||
|
|
||||||
|
let tp = a.get_tank_parameters().unwrap();
|
||||||
|
println!("Tank: {:?}", tp);
|
||||||
|
|
||||||
|
let hp = a.get_heating_parameters().unwrap();
|
||||||
|
println!("Heating: {:?}", hp);
|
||||||
|
}
|
10
examples/temperature.rs
Normal file
10
examples/temperature.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
use daikin_altherma::DaikinAlthermaClient;
|
||||||
|
fn main() {
|
||||||
|
let mut a = DaikinAlthermaClient::new("192.168.11.100".to_string()).unwrap();
|
||||||
|
|
||||||
|
let hp = a.get_heating_parameters().unwrap();
|
||||||
|
println!("Heating: {:?}", hp);
|
||||||
|
a.set_heating_setpoint_temperature(20.0);
|
||||||
|
let hp = a.get_heating_parameters().unwrap();
|
||||||
|
println!("Heating: {:?}", hp);
|
||||||
|
}
|
|
@ -1,10 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "mytest"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
daikin_altherma = {path = "/home/frank/src/github.com/frankkkkk/daikin-altherma-rs/"}
|
|
||||||
thiserror = "1.0.57"
|
|
|
@ -1,15 +0,0 @@
|
||||||
use daikin_altherma::DaikinAlthermaClient;
|
|
||||||
fn main() {
|
|
||||||
let mut a = DaikinAlthermaClient::new("192.168.11.100".to_string());
|
|
||||||
// let am = a.get_adapter_model();
|
|
||||||
// println!("Adapter model: {am}");
|
|
||||||
//
|
|
||||||
|
|
||||||
//a.set_holiday_mode(false);
|
|
||||||
|
|
||||||
let hm = a.is_holiday_mode();
|
|
||||||
println!("Holiday mode: {hm}");
|
|
||||||
|
|
||||||
let tp = a.get_tank_parameters().unwrap();
|
|
||||||
println!("Tank: {:?}", tp);
|
|
||||||
}
|
|
19
src/errors.rs
Normal file
19
src/errors.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum DAError {
|
||||||
|
#[error("Communication error")]
|
||||||
|
CommunicationError,
|
||||||
|
#[error("Conversion error")]
|
||||||
|
ConversionError,
|
||||||
|
#[error("Set value error")]
|
||||||
|
SetValueError(String),
|
||||||
|
#[error("No such field")]
|
||||||
|
NoSuchFieldError,
|
||||||
|
#[error("Value conversion error")]
|
||||||
|
ValueConversionError,
|
||||||
|
#[error("Url Parse error")]
|
||||||
|
UrlParseError,
|
||||||
|
#[error("WebSocket Error")]
|
||||||
|
WebSocketError,
|
||||||
|
}
|
257
src/lib.rs
257
src/lib.rs
|
@ -1,108 +1,134 @@
|
||||||
use std::{fmt::Debug, net::TcpStream};
|
//! # API to Daikin Altherma LAN Adapters
|
||||||
use thiserror::Error;
|
//!
|
||||||
|
//! This rust crate interfaces with Daikin Altherma LAN adapteros.
|
||||||
|
//!
|
||||||
|
//! There are two firmware versions of the LAN adapters:
|
||||||
|
//! - Cloud connected
|
||||||
|
//! - LAN only
|
||||||
|
//!
|
||||||
|
//! This library only supports the second one for the moment.
|
||||||
|
//! ## Usage
|
||||||
|
//! Using this library is rather easy:
|
||||||
|
//! ```
|
||||||
|
//! let mut client = DaikinAlthermaClient::new("192.168.11.100".to_string()).unwrap();
|
||||||
|
//!
|
||||||
|
//! let hp = client.get_heating_parameters().unwrap();
|
||||||
|
//! println!("Heating: {:?}", hp);
|
||||||
|
//!
|
||||||
|
//! client.set_heating_setpoint_temperature(20.0);
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
use std::net::TcpStream;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use tungstenite::{connect, stream, Message, WebSocket};
|
use tungstenite::{connect, stream, Message, WebSocket};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
mod errors;
|
||||||
pub enum DAError {
|
mod params;
|
||||||
#[error("Communication error")]
|
mod traits;
|
||||||
CommunicationError,
|
pub use crate::errors::DAError;
|
||||||
#[error("Conversion error")]
|
pub use crate::params::HeatingParameters;
|
||||||
ConversionError,
|
pub use crate::params::TankParameters;
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DaikinAlthermaClient {
|
pub struct DaikinAlthermaClient {
|
||||||
//todo WS con
|
|
||||||
ws_client: WebSocket<stream::MaybeTlsStream<TcpStream>>,
|
ws_client: WebSocket<stream::MaybeTlsStream<TcpStream>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct TankParameters {
|
|
||||||
// The current temperature of the water tank
|
|
||||||
temperature: f64,
|
|
||||||
// The setpoint (wanted) temperature of the water tank
|
|
||||||
setpoint_temperature: f64,
|
|
||||||
// Is the tank heating enabled
|
|
||||||
enabled: bool,
|
|
||||||
// Is it on powerful (quick heating) mode
|
|
||||||
powerful: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
trait FromJsonValue<T>: Sized {
|
|
||||||
fn from_json_value(value: &Value) -> Result<T, DAError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implement the trait for i64
|
|
||||||
impl FromJsonValue<i64> for i64 {
|
|
||||||
fn from_json_value(value: &Value) -> Result<Self, DAError> {
|
|
||||||
let v: Option<i64> = value.as_i64();
|
|
||||||
match v {
|
|
||||||
Some(x) => Ok(x),
|
|
||||||
_ => Err(DAError::ConversionError),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implement the trait for f64
|
|
||||||
impl FromJsonValue<f64> for f64 {
|
|
||||||
fn from_json_value(value: &Value) -> Result<Self, DAError> {
|
|
||||||
let v: Option<f64> = value.as_f64();
|
|
||||||
match v {
|
|
||||||
Some(x) => Ok(x),
|
|
||||||
_ => Err(DAError::ConversionError),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implement the trait for String
|
|
||||||
impl FromJsonValue<String> for String {
|
|
||||||
fn from_json_value(value: &Value) -> Result<Self, DAError> {
|
|
||||||
let v: Option<&str> = value.as_str();
|
|
||||||
match v {
|
|
||||||
Some(x) => Ok(x.to_string()),
|
|
||||||
_ => Err(DAError::ConversionError),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implement the trait for bool
|
|
||||||
impl FromJsonValue<bool> for bool {
|
|
||||||
fn from_json_value(value: &Value) -> Result<Self, DAError> {
|
|
||||||
let v: Option<bool> = value.as_bool();
|
|
||||||
match v {
|
|
||||||
Some(x) => Ok(x),
|
|
||||||
_ => Err(DAError::ConversionError),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DaikinAlthermaClient {
|
impl DaikinAlthermaClient {
|
||||||
pub fn new(adapter_hostname: String) -> Self {
|
/// Creates a new client to a Daikin Altherma LAN adapter.
|
||||||
|
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
|
||||||
|
pub fn get_adapter_model(&mut self) -> Result<String, DAError> {
|
||||||
|
let v = self.request_value("MNCSE-node/deviceInfo", None, "/m2m:rsp/pc/m2m:dvi/mod")?;
|
||||||
|
|
||||||
|
match v.as_str() {
|
||||||
|
Some(x) => Ok(x.to_string()),
|
||||||
|
None => Err(DAError::NoSuchFieldError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_adapter_model(&mut self) -> String {
|
pub fn get_tank_parameters(&mut self) -> Result<TankParameters, DAError> {
|
||||||
let v = self
|
let temperature: f64 = self.request_value_hp_dft("2/Sensor/TankTemperature/la")?;
|
||||||
.request_value("MNCSE-node/deviceInfo", None, "/m2m:rsp/pc/m2m:dvi/mod")
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
return v.as_str().unwrap().to_string();
|
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")?;
|
||||||
|
let powerful_i: i64 = self.request_value_hp_dft("2/Operation/Powerful/la")?;
|
||||||
|
|
||||||
|
Ok(TankParameters {
|
||||||
|
temperature,
|
||||||
|
setpoint_temperature,
|
||||||
|
enabled: enabled_str == "on",
|
||||||
|
powerful: powerful_i == 1,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_holiday_mode(&mut self) -> bool {
|
/// Enables or disables the tank heating
|
||||||
let v: i64 = self
|
pub fn set_tank_enabled(&mut self, enabled: bool) -> Result<(), DAError> {
|
||||||
.request_value_hp_dft("1/Holiday/HolidayState/la")
|
let value = match enabled {
|
||||||
.unwrap();
|
true => "on",
|
||||||
|
false => "off",
|
||||||
|
};
|
||||||
|
|
||||||
return v == 1;
|
let payload = serde_json::json!({
|
||||||
|
"con": value,
|
||||||
|
"cnf": "text/plain:0"
|
||||||
|
});
|
||||||
|
|
||||||
|
self.set_value_hp("2/Operation/Power", Some(payload), "/")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enables or disable the tank powerful mode
|
||||||
|
pub fn set_tank_powerful(&mut self, powerful: bool) -> Result<(), DAError> {
|
||||||
|
let value = match powerful {
|
||||||
|
true => 1,
|
||||||
|
false => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let payload = serde_json::json!({
|
||||||
|
"con": value,
|
||||||
|
"cnf": "text/plain:0"
|
||||||
|
});
|
||||||
|
|
||||||
|
self.set_value_hp("2/Operation/Powerful", Some(payload), "/")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_heating_parameters(&mut self) -> Result<HeatingParameters, DAError> {
|
||||||
|
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")?;
|
||||||
|
|
||||||
|
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")?;
|
||||||
|
|
||||||
|
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")?;
|
||||||
|
|
||||||
|
Ok(HeatingParameters {
|
||||||
|
indoor_temperature,
|
||||||
|
outdoor_temperature,
|
||||||
|
indoor_setpoint_temperature,
|
||||||
|
leaving_water_temperature,
|
||||||
|
enabled: enabled_str == "on",
|
||||||
|
on_holiday: on_holiday == 1,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_holiday_mode(&mut self, holiday_mode: bool) -> Result<(), DAError> {
|
pub fn set_holiday_mode(&mut self, holiday_mode: bool) -> Result<(), DAError> {
|
||||||
|
@ -117,37 +143,39 @@ impl DaikinAlthermaClient {
|
||||||
});
|
});
|
||||||
|
|
||||||
self.set_value_hp("1/Holiday/HolidayState", Some(payload), "/")
|
self.set_value_hp("1/Holiday/HolidayState", Some(payload), "/")
|
||||||
.unwrap();
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_tank_parameters(&mut self) -> Result<TankParameters, DAError> {
|
/// Sets the heating setpoint (target) temperature, in °C
|
||||||
let temperature: f64 = self
|
pub fn set_heating_setpoint_temperature(&mut self, temperature: f64) -> Result<(), DAError> {
|
||||||
.request_value_hp_dft("2/Sensor/TankTemperature/la")
|
let payload = serde_json::json!({
|
||||||
.unwrap();
|
"con": temperature,
|
||||||
|
"cnf": "text/plain:0"
|
||||||
|
});
|
||||||
|
|
||||||
let setpoint_temperature: f64 = self
|
self.set_value_hp("1/Operation/TargetTemperature", Some(payload), "/")
|
||||||
.request_value_hp_dft("2/Operation/TargetTemperature/la")
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
Ok(TankParameters {
|
|
||||||
temperature,
|
|
||||||
setpoint_temperature,
|
|
||||||
enabled: enabled_str == "on",
|
|
||||||
powerful: powerful_i == 1,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn request_value_hp_dft<T: FromJsonValue<T>>(&mut self, item: &str) -> Result<T, DAError> {
|
/// Enables or disables the heating
|
||||||
|
pub fn set_heating_enabled(&mut self, is_enabled: bool) -> Result<(), DAError> {
|
||||||
|
let value = match is_enabled {
|
||||||
|
true => "on",
|
||||||
|
false => "standby",
|
||||||
|
};
|
||||||
|
|
||||||
|
let payload = serde_json::json!({
|
||||||
|
"con": value,
|
||||||
|
"cnf": "text/plain:0"
|
||||||
|
});
|
||||||
|
|
||||||
|
self.set_value_hp("1/Operation/Power", Some(payload), "/")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_value_hp_dft<T: traits::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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,8 +187,7 @@ impl DaikinAlthermaClient {
|
||||||
) -> 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)
|
||||||
.unwrap();
|
.map(|_| ())
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn request_value(
|
fn request_value(
|
||||||
|
@ -168,7 +195,7 @@ impl DaikinAlthermaClient {
|
||||||
item: &str,
|
item: &str,
|
||||||
payload: Option<Value>,
|
payload: Option<Value>,
|
||||||
output_path: &str,
|
output_path: &str,
|
||||||
) -> Result<Value, String> {
|
) -> Result<Value, DAError> {
|
||||||
let reqid = Uuid::new_v4().to_string();
|
let reqid = Uuid::new_v4().to_string();
|
||||||
|
|
||||||
let mut js_request = json!({
|
let mut js_request = json!({
|
||||||
|
@ -206,14 +233,12 @@ impl DaikinAlthermaClient {
|
||||||
|
|
||||||
let result: Value = serde_json::from_str(&msg).expect("Can't parse JSON");
|
let result: Value = serde_json::from_str(&msg).expect("Can't parse JSON");
|
||||||
|
|
||||||
//println!(">>> {result}");
|
|
||||||
|
|
||||||
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
|
||||||
//
|
|
||||||
match result.pointer(output_path) {
|
match result.pointer(output_path) {
|
||||||
Some(v) => Ok(v.clone()),
|
Some(v) => Ok(v.clone()),
|
||||||
None => Err("Todo".to_string()),
|
None => Err(DAError::NoSuchFieldError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
33
src/params.rs
Normal file
33
src/params.rs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TankParameters {
|
||||||
|
/// The current temperature of the water tank, in °C
|
||||||
|
pub temperature: f64,
|
||||||
|
/// The setpoint (wanted) temperature of the water tank, in °C
|
||||||
|
pub setpoint_temperature: f64,
|
||||||
|
/// Is the tank heating enabled
|
||||||
|
pub enabled: bool,
|
||||||
|
/// Is it on powerful (quick heating) mode
|
||||||
|
pub powerful: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct HeatingParameters {
|
||||||
|
/// The current indoor temperature, in °C
|
||||||
|
pub indoor_temperature: f64,
|
||||||
|
/// The current outdoor temperature, in °C
|
||||||
|
pub outdoor_temperature: f64,
|
||||||
|
/// The current indoor setpoint (target) temperature, in °C
|
||||||
|
pub indoor_setpoint_temperature: f64,
|
||||||
|
/// The leaving water temperature, in °C
|
||||||
|
pub leaving_water_temperature: f64,
|
||||||
|
|
||||||
|
/// Is the heating enabled
|
||||||
|
pub enabled: bool,
|
||||||
|
|
||||||
|
/// Is the heating on holiday (disabled)
|
||||||
|
pub on_holiday: bool,
|
||||||
|
// Is it on powerful (quick heating) mode
|
||||||
|
//mode: ,
|
||||||
|
}
|
35
src/traits.rs
Normal file
35
src/traits.rs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
use crate::errors::DAError;
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
|
pub trait FromJsonValue<T>: Sized {
|
||||||
|
fn from_json_value(value: &Value) -> Result<T, DAError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement the trait for i64
|
||||||
|
impl FromJsonValue<i64> for i64 {
|
||||||
|
fn from_json_value(value: &Value) -> Result<Self, DAError> {
|
||||||
|
value.as_i64().ok_or(DAError::ValueConversionError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement the trait for f64
|
||||||
|
impl FromJsonValue<f64> for f64 {
|
||||||
|
fn from_json_value(value: &Value) -> Result<Self, DAError> {
|
||||||
|
value.as_f64().ok_or(DAError::ValueConversionError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement the trait for String
|
||||||
|
impl FromJsonValue<String> for String {
|
||||||
|
fn from_json_value(value: &Value) -> Result<Self, DAError> {
|
||||||
|
let v = value.as_str().ok_or(DAError::ValueConversionError)?;
|
||||||
|
Ok(v.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement the trait for bool
|
||||||
|
impl FromJsonValue<bool> for bool {
|
||||||
|
fn from_json_value(value: &Value) -> Result<Self, DAError> {
|
||||||
|
value.as_bool().ok_or(DAError::ValueConversionError)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue