v0.14.21
This commit is contained in:
+68
-20
@@ -50,7 +50,11 @@ fn collect_configuration_ids(
|
||||
let ids = ConfigurationIds {
|
||||
devices: export.devices.iter().map(|item| item.id.as_str()).collect(),
|
||||
zones: export.zones.iter().map(|item| item.id.as_str()).collect(),
|
||||
device_groups: export.device_groups.iter().map(|item| item.id.as_str()).collect(),
|
||||
device_groups: export
|
||||
.device_groups
|
||||
.iter()
|
||||
.map(|item| item.id.as_str())
|
||||
.collect(),
|
||||
schedules: export
|
||||
.schedules
|
||||
.iter()
|
||||
@@ -190,21 +194,33 @@ fn validate_configuration_devices_and_zones(
|
||||
}
|
||||
if !installation_devices.insert(device_id.as_str()) {
|
||||
return Err(AppError::BadRequest(
|
||||
"import assigns one device to more than one split/multisplit installation".into(),
|
||||
"import assigns one device to more than one split/multisplit installation"
|
||||
.into(),
|
||||
));
|
||||
}
|
||||
}
|
||||
if group.energy_device_id.as_deref().is_some_and(|id| !group.device_ids.iter().any(|member| member == id)) {
|
||||
if group
|
||||
.energy_device_id
|
||||
.as_deref()
|
||||
.is_some_and(|id| !group.device_ids.iter().any(|member| member == id))
|
||||
{
|
||||
return Err(AppError::BadRequest(
|
||||
"import contains an installation energy source outside the installation".into(),
|
||||
));
|
||||
}
|
||||
if group.energy_source == EnergySourcePreference::GreeCloud && group.energy_device_id.is_none() {
|
||||
if group.energy_source == EnergySourcePreference::GreeCloud
|
||||
&& group.energy_device_id.is_none()
|
||||
{
|
||||
return Err(AppError::BadRequest(
|
||||
"import contains a GREE Cloud installation without an energy source device".into(),
|
||||
));
|
||||
}
|
||||
if group.energy_source == EnergySourcePreference::HomeAssistant && group.ha_energy_entity_id.as_deref().map_or(true, |value| value.trim().is_empty()) {
|
||||
if group.energy_source == EnergySourcePreference::HomeAssistant
|
||||
&& group
|
||||
.ha_energy_entity_id
|
||||
.as_deref()
|
||||
.map_or(true, |value| value.trim().is_empty())
|
||||
{
|
||||
return Err(AppError::BadRequest(
|
||||
"import contains a Home Assistant installation without an energy entity".into(),
|
||||
));
|
||||
@@ -213,23 +229,43 @@ fn validate_configuration_devices_and_zones(
|
||||
let energy_device = export.devices.iter().find(|device| device.id == energy_device_id).ok_or_else(|| {
|
||||
AppError::BadRequest("import contains an installation energy source referencing a missing device".into())
|
||||
})?;
|
||||
if energy_device.connection_type != ConnectionType::GreeCloud || !energy_device.capabilities.energy_meter {
|
||||
if energy_device.connection_type != ConnectionType::GreeCloud
|
||||
|| !energy_device.capabilities.energy_meter
|
||||
{
|
||||
return Err(AppError::BadRequest(
|
||||
"import contains an installation energy source without a GREE Cloud energy meter".into(),
|
||||
));
|
||||
}
|
||||
}
|
||||
if group.ha_energy_entity_id.as_deref().is_some_and(|value| !value.trim().is_empty()) {
|
||||
if group
|
||||
.ha_energy_entity_id
|
||||
.as_deref()
|
||||
.is_some_and(|value| !value.trim().is_empty())
|
||||
{
|
||||
if group.ha_energy_device_class.as_deref() != Some("energy")
|
||||
|| !matches!(group.ha_energy_state_class.as_deref(), Some("total" | "total_increasing"))
|
||||
|| !matches!(group.ha_energy_unit.as_deref().map(str::to_ascii_lowercase).as_deref(), Some("wh" | "kwh"))
|
||||
|| !matches!(
|
||||
group.ha_energy_state_class.as_deref(),
|
||||
Some("total" | "total_increasing")
|
||||
)
|
||||
|| !matches!(
|
||||
group
|
||||
.ha_energy_unit
|
||||
.as_deref()
|
||||
.map(str::to_ascii_lowercase)
|
||||
.as_deref(),
|
||||
Some("wh" | "kwh")
|
||||
)
|
||||
{
|
||||
return Err(AppError::BadRequest(
|
||||
"import contains an invalid Home Assistant cumulative energy entity".into(),
|
||||
));
|
||||
}
|
||||
}
|
||||
if group.outdoor_temperature_device_id.as_deref().is_some_and(|id| !group.device_ids.iter().any(|member| member == id)) {
|
||||
if group
|
||||
.outdoor_temperature_device_id
|
||||
.as_deref()
|
||||
.is_some_and(|id| !group.device_ids.iter().any(|member| member == id))
|
||||
{
|
||||
return Err(AppError::BadRequest(
|
||||
"import contains an installation outdoor-temperature source outside the installation".into(),
|
||||
));
|
||||
@@ -652,10 +688,14 @@ fn normalize_imported_runtime_settings(settings: &mut RuntimeSettings) -> Result
|
||||
}
|
||||
settings.gree_cloud.polling_interval_seconds =
|
||||
settings.gree_cloud.polling_interval_seconds.clamp(30, 3600);
|
||||
settings.gree_cloud.connectivity_metrics_interval_seconds =
|
||||
settings.gree_cloud.connectivity_metrics_interval_seconds.clamp(30, 3600);
|
||||
settings.gree_cloud.connectivity_metrics_sample_count =
|
||||
settings.gree_cloud.connectivity_metrics_sample_count.clamp(1, 10);
|
||||
settings.gree_cloud.connectivity_metrics_interval_seconds = settings
|
||||
.gree_cloud
|
||||
.connectivity_metrics_interval_seconds
|
||||
.clamp(30, 3600);
|
||||
settings.gree_cloud.connectivity_metrics_sample_count = settings
|
||||
.gree_cloud
|
||||
.connectivity_metrics_sample_count
|
||||
.clamp(1, 10);
|
||||
if settings.gree_cloud.account_id.trim().is_empty() {
|
||||
settings.gree_cloud.account_id = "default".into();
|
||||
}
|
||||
@@ -710,8 +750,12 @@ async fn hydrate_imported_cloud_device_keys(
|
||||
) -> Result<(), AppError> {
|
||||
if export.settings.gree_cloud.password.trim().is_empty() {
|
||||
let current = state.settings.read().await.gree_cloud.clone();
|
||||
if current.region.eq_ignore_ascii_case(&export.settings.gree_cloud.region)
|
||||
&& current.username.eq_ignore_ascii_case(&export.settings.gree_cloud.username)
|
||||
if current
|
||||
.region
|
||||
.eq_ignore_ascii_case(&export.settings.gree_cloud.region)
|
||||
&& current
|
||||
.username
|
||||
.eq_ignore_ascii_case(&export.settings.gree_cloud.username)
|
||||
&& !current.password.trim().is_empty()
|
||||
{
|
||||
export.settings.gree_cloud.password = current.password;
|
||||
@@ -732,9 +776,11 @@ async fn hydrate_imported_cloud_device_keys(
|
||||
&settings.username,
|
||||
&settings.password,
|
||||
)
|
||||
.map_err(|err| AppError::BadRequest(format!(
|
||||
"cannot restore GREE Cloud device secrets from account: {err}"
|
||||
)))?;
|
||||
.map_err(|err| {
|
||||
AppError::BadRequest(format!(
|
||||
"cannot restore GREE Cloud device secrets from account: {err}"
|
||||
))
|
||||
})?;
|
||||
api.login().await.map_err(|err| {
|
||||
AppError::BadRequest(format!(
|
||||
"cannot restore GREE Cloud device secrets: account login failed: {err}"
|
||||
@@ -767,7 +813,9 @@ async fn hydrate_imported_cloud_device_keys(
|
||||
device.key = Some(found.key.clone());
|
||||
let normalized_cloud_mac = found.mac.replace([':', '-'], "").to_ascii_uppercase();
|
||||
device.cloud_device_id = Some(normalized_cloud_mac.clone());
|
||||
device.cloud_parent_mac = Some(crate::protocol::gree_cloud::parent_mac(&normalized_cloud_mac));
|
||||
device.cloud_parent_mac = Some(crate::protocol::gree_cloud::parent_mac(
|
||||
&normalized_cloud_mac,
|
||||
));
|
||||
device.cloud_account_id = Some(settings.account_id.clone());
|
||||
if device.model.trim().is_empty() {
|
||||
device.model = found.model.clone().unwrap_or_default();
|
||||
|
||||
Reference in New Issue
Block a user