v0.14.1
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
struct ConfigurationIds<'a> {
|
||||
devices: std::collections::HashSet<&'a str>,
|
||||
zones: std::collections::HashSet<&'a str>,
|
||||
device_groups: std::collections::HashSet<&'a str>,
|
||||
schedules: std::collections::HashSet<&'a str>,
|
||||
automations: std::collections::HashSet<&'a str>,
|
||||
flows: std::collections::HashSet<&'a str>,
|
||||
@@ -26,7 +27,7 @@ async fn export_configuration(
|
||||
|
||||
fn validate_configuration_header(export: &ConfigurationExport) -> Result<(), AppError> {
|
||||
if export.format_version != 3 {
|
||||
return Err(AppError::BadRequest("unsupported configuration export version; version 3 is required by GREE Controller 0.14.0".into()));
|
||||
return Err(AppError::BadRequest("unsupported configuration export version; version 3 is required by GREE Controller 0.14.1".into()));
|
||||
}
|
||||
if export.settings.control_strategy != "setpoint" {
|
||||
return Err(AppError::BadRequest(
|
||||
@@ -49,6 +50,7 @@ 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(),
|
||||
schedules: export
|
||||
.schedules
|
||||
.iter()
|
||||
@@ -63,11 +65,13 @@ fn collect_configuration_ids(
|
||||
};
|
||||
let duplicate_or_empty = ids.devices.len() != export.devices.len()
|
||||
|| ids.zones.len() != export.zones.len()
|
||||
|| ids.device_groups.len() != export.device_groups.len()
|
||||
|| ids.schedules.len() != export.schedules.len()
|
||||
|| ids.automations.len() != export.automations.len()
|
||||
|| ids.flows.len() != export.flows.len()
|
||||
|| ids.devices.contains("")
|
||||
|| ids.zones.contains("")
|
||||
|| ids.device_groups.contains("")
|
||||
|| ids.schedules.contains("")
|
||||
|| ids.automations.contains("")
|
||||
|| ids.flows.contains("");
|
||||
@@ -154,6 +158,71 @@ fn validate_configuration_devices_and_zones(
|
||||
));
|
||||
}
|
||||
}
|
||||
let mut installation_devices = std::collections::HashSet::new();
|
||||
for group in &export.device_groups {
|
||||
if group.name.trim().is_empty() || group.device_ids.is_empty() {
|
||||
return Err(AppError::BadRequest(
|
||||
"import contains an empty split/multisplit installation".into(),
|
||||
));
|
||||
}
|
||||
if group.kind == DeviceGroupKind::Split && group.device_ids.len() != 1 {
|
||||
return Err(AppError::BadRequest(
|
||||
"import contains a split installation with more than one unit".into(),
|
||||
));
|
||||
}
|
||||
for device_id in &group.device_ids {
|
||||
if !ids.devices.contains(device_id.as_str()) {
|
||||
return Err(AppError::BadRequest(
|
||||
"import contains an installation referencing a missing device".into(),
|
||||
));
|
||||
}
|
||||
if !installation_devices.insert(device_id.as_str()) {
|
||||
return Err(AppError::BadRequest(
|
||||
"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)) {
|
||||
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() {
|
||||
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()) {
|
||||
return Err(AppError::BadRequest(
|
||||
"import contains a Home Assistant installation without an energy entity".into(),
|
||||
));
|
||||
}
|
||||
if let Some(energy_device_id) = group.energy_device_id.as_deref() {
|
||||
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 {
|
||||
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_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"))
|
||||
{
|
||||
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)) {
|
||||
return Err(AppError::BadRequest(
|
||||
"import contains an installation outdoor-temperature source outside the installation".into(),
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user