first commit
This commit is contained in:
+317
@@ -0,0 +1,317 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
fn default_true() -> bool { true }
|
||||
fn default_port() -> u16 { 7000 }
|
||||
fn default_protocol() -> u8 { 1 }
|
||||
fn default_mode() -> String { "cool".into() }
|
||||
fn default_fan() -> u8 { 0 }
|
||||
fn default_target() -> f64 { 24.0 }
|
||||
fn default_hysteresis() -> f64 { 0.6 }
|
||||
fn default_external_sensor_weight() -> f64 { 0.4 }
|
||||
fn default_max_sensor_difference() -> f64 { 3.0 }
|
||||
fn default_control_temperature_source() -> String { "device".into() }
|
||||
fn default_min_cycle() -> u64 { 180 }
|
||||
fn default_cooldown() -> u64 { 300 }
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Device {
|
||||
pub id: String,
|
||||
pub mac: String,
|
||||
pub name: String,
|
||||
pub ip: String,
|
||||
#[serde(default = "default_port")]
|
||||
pub port: u16,
|
||||
#[serde(default = "default_protocol")]
|
||||
pub protocol_version: u8,
|
||||
#[serde(default)]
|
||||
pub model: String,
|
||||
#[serde(default)]
|
||||
pub firmware: String,
|
||||
#[serde(default)]
|
||||
pub key: Option<String>,
|
||||
#[serde(default)]
|
||||
pub cid: Option<String>,
|
||||
#[serde(default = "default_true")]
|
||||
pub enabled: bool,
|
||||
#[serde(default)]
|
||||
pub simulated: bool,
|
||||
#[serde(default)]
|
||||
pub power: bool,
|
||||
#[serde(default = "default_mode")]
|
||||
pub mode: String,
|
||||
#[serde(default = "default_target")]
|
||||
pub target_temperature: f64,
|
||||
#[serde(default = "default_fan")]
|
||||
pub fan_speed: u8,
|
||||
#[serde(default)]
|
||||
pub swing_vertical: bool,
|
||||
#[serde(default)]
|
||||
pub swing_horizontal: bool,
|
||||
#[serde(default)]
|
||||
pub quiet: bool,
|
||||
#[serde(default)]
|
||||
pub turbo: bool,
|
||||
#[serde(default)]
|
||||
pub light: bool,
|
||||
#[serde(default)]
|
||||
pub current_temperature: Option<f64>,
|
||||
#[serde(default)]
|
||||
pub outdoor_temperature: Option<f64>,
|
||||
#[serde(default)]
|
||||
pub online: bool,
|
||||
#[serde(default)]
|
||||
pub last_seen: Option<DateTime<Utc>>,
|
||||
#[serde(default)]
|
||||
pub last_error: Option<String>,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
impl Device {
|
||||
pub fn simulated_default() -> Self {
|
||||
let now = Utc::now();
|
||||
Self {
|
||||
id: "sim-salon".into(),
|
||||
mac: "SIM000000001".into(),
|
||||
name: "Living Room (simulator)".into(),
|
||||
ip: "127.0.0.1".into(),
|
||||
port: 7000,
|
||||
protocol_version: 1,
|
||||
model: "GREE-SIM".into(),
|
||||
firmware: "sim-1.0".into(),
|
||||
key: None,
|
||||
cid: Some("gree-controller".into()),
|
||||
enabled: true,
|
||||
simulated: true,
|
||||
power: false,
|
||||
mode: "cool".into(),
|
||||
target_temperature: 23.0,
|
||||
fan_speed: 0,
|
||||
swing_vertical: false,
|
||||
swing_horizontal: false,
|
||||
quiet: false,
|
||||
turbo: false,
|
||||
light: true,
|
||||
current_temperature: Some(26.0),
|
||||
outdoor_temperature: Some(30.0),
|
||||
online: true,
|
||||
last_seen: Some(now),
|
||||
last_error: None,
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct DevicePatch {
|
||||
pub name: Option<String>,
|
||||
pub ip: Option<String>,
|
||||
pub port: Option<u16>,
|
||||
pub protocol_version: Option<u8>,
|
||||
pub key: Option<Option<String>>,
|
||||
pub enabled: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct DeviceCommand {
|
||||
pub power: Option<bool>,
|
||||
pub mode: Option<String>,
|
||||
pub target_temperature: Option<f64>,
|
||||
pub fan_speed: Option<u8>,
|
||||
pub swing_vertical: Option<bool>,
|
||||
pub swing_horizontal: Option<bool>,
|
||||
pub quiet: Option<bool>,
|
||||
pub turbo: Option<bool>,
|
||||
pub light: Option<bool>,
|
||||
}
|
||||
|
||||
impl DeviceCommand {
|
||||
pub fn apply(&self, device: &mut Device) {
|
||||
if let Some(v) = self.power { device.power = v; }
|
||||
if let Some(v) = &self.mode { device.mode = v.clone(); }
|
||||
if let Some(v) = self.target_temperature { device.target_temperature = v.clamp(8.0, 32.0); }
|
||||
if let Some(v) = self.fan_speed { device.fan_speed = v.min(5); }
|
||||
if let Some(v) = self.swing_vertical { device.swing_vertical = v; }
|
||||
if let Some(v) = self.swing_horizontal { device.swing_horizontal = v; }
|
||||
if let Some(v) = self.quiet { device.quiet = v; }
|
||||
if let Some(v) = self.turbo { device.turbo = v; }
|
||||
if let Some(v) = self.light { device.light = v; }
|
||||
device.updated_at = Utc::now();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Zone {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub device_id: String,
|
||||
#[serde(default = "default_true")]
|
||||
pub enabled: bool,
|
||||
#[serde(default = "default_mode")]
|
||||
pub mode: String,
|
||||
#[serde(default = "default_target")]
|
||||
pub setpoint: f64,
|
||||
#[serde(default = "default_hysteresis")]
|
||||
pub hysteresis: f64,
|
||||
#[serde(default = "default_min_cycle")]
|
||||
pub min_on_seconds: u64,
|
||||
#[serde(default = "default_min_cycle")]
|
||||
pub min_off_seconds: u64,
|
||||
#[serde(default = "default_sensor_source")]
|
||||
pub sensor_source: String,
|
||||
#[serde(default)]
|
||||
pub ha_entity_id: Option<String>,
|
||||
/// Weight of the optional room sensor when sensor_source is `combined`.
|
||||
#[serde(default = "default_external_sensor_weight")]
|
||||
pub external_sensor_weight: f64,
|
||||
/// If GREE and external sensor differ more than this, the controller falls back to GREE.
|
||||
#[serde(default = "default_max_sensor_difference")]
|
||||
pub max_sensor_difference: f64,
|
||||
/// Temperature reported by the GREE indoor sensor during the last zone cycle.
|
||||
#[serde(default)]
|
||||
pub device_temperature: Option<f64>,
|
||||
/// Temperature reported by the per-zone external Home Assistant sensor.
|
||||
#[serde(default)]
|
||||
pub external_temperature: Option<f64>,
|
||||
/// Temperature actually used by the zone controller.
|
||||
#[serde(default)]
|
||||
pub current_temperature: Option<f64>,
|
||||
/// `device`, `external`, `combined`, `device_fallback`, or `device_discrepancy_fallback`.
|
||||
#[serde(default = "default_control_temperature_source")]
|
||||
pub control_temperature_source: String,
|
||||
#[serde(default)]
|
||||
pub demand: bool,
|
||||
#[serde(default)]
|
||||
pub last_action_at: Option<DateTime<Utc>>,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
fn default_sensor_source() -> String { "device".into() }
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Schedule {
|
||||
pub id: String,
|
||||
pub zone_id: String,
|
||||
pub name: String,
|
||||
#[serde(default = "default_true")]
|
||||
pub enabled: bool,
|
||||
/// ISO weekday numbers, Monday=1, Sunday=7.
|
||||
pub weekdays: Vec<u32>,
|
||||
/// Local time HH:MM.
|
||||
pub start_time: String,
|
||||
/// Local time HH:MM. Ranges crossing midnight are supported.
|
||||
pub end_time: String,
|
||||
pub setpoint: f64,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Automation {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
#[serde(default = "default_true")]
|
||||
pub enabled: bool,
|
||||
/// temperature_above, temperature_below, time
|
||||
pub trigger_kind: String,
|
||||
#[serde(default)]
|
||||
pub trigger_device_id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub threshold: Option<f64>,
|
||||
#[serde(default)]
|
||||
pub at_time: Option<String>,
|
||||
pub action_device_id: String,
|
||||
#[serde(default)]
|
||||
pub action: DeviceCommand,
|
||||
#[serde(default = "default_cooldown")]
|
||||
pub cooldown_seconds: u64,
|
||||
#[serde(default)]
|
||||
pub last_fired_at: Option<DateTime<Utc>>,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Reading {
|
||||
pub id: i64,
|
||||
pub device_id: String,
|
||||
pub timestamp: DateTime<Utc>,
|
||||
pub indoor_temperature: Option<f64>,
|
||||
pub outdoor_temperature: Option<f64>,
|
||||
pub target_temperature: f64,
|
||||
pub power: bool,
|
||||
pub source: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct EventLog {
|
||||
pub id: i64,
|
||||
pub timestamp: DateTime<Utc>,
|
||||
pub level: String,
|
||||
pub kind: String,
|
||||
pub message: String,
|
||||
pub metadata: Value,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct HomeAssistantSettings {
|
||||
#[serde(default)]
|
||||
pub url: String,
|
||||
#[serde(default)]
|
||||
pub token: String,
|
||||
#[serde(default)]
|
||||
pub default_entity_id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct RuntimeSettings {
|
||||
pub controller_id: String,
|
||||
pub simulator_enabled: bool,
|
||||
pub poll_interval_seconds: u64,
|
||||
pub zone_interval_seconds: u64,
|
||||
pub discovery_timeout_ms: u64,
|
||||
pub discovery_broadcast: String,
|
||||
pub home_assistant: HomeAssistantSettings,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DiscoveryRequest {
|
||||
#[serde(default)]
|
||||
pub timeout_ms: Option<u64>,
|
||||
#[serde(default)]
|
||||
pub broadcast: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ManualDeviceRequest {
|
||||
pub name: String,
|
||||
pub mac: String,
|
||||
pub ip: String,
|
||||
#[serde(default = "default_port")]
|
||||
pub port: u16,
|
||||
#[serde(default = "default_protocol")]
|
||||
pub protocol_version: u8,
|
||||
#[serde(default)]
|
||||
pub key: Option<String>,
|
||||
#[serde(default)]
|
||||
pub simulated: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ApiTokenInfo {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub token_prefix: String,
|
||||
pub created_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ApiEvent {
|
||||
pub event: String,
|
||||
pub timestamp: DateTime<Utc>,
|
||||
pub data: Value,
|
||||
}
|
||||
Reference in New Issue
Block a user