From ea7a113b956f78e7a904758533a6149c19679c1a Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Tue, 2 Sep 2025 19:23:30 +0200 Subject: [PATCH] Aggiunto DTO decodifica 3EM gen1 --- EgwProxy.Shelly/DTO/Gen1/ActionsStatsDto.cs | 17 ++ EgwProxy.Shelly/DTO/Gen1/CloudInfoDto.cs | 19 ++ EgwProxy.Shelly/DTO/Gen1/EmeterInfoDto.cs | 34 +++ EgwProxy.Shelly/DTO/Gen1/EmeterNInfoDto.cs | 26 +++ EgwProxy.Shelly/DTO/Gen1/MqttInfoDto.cs | 16 ++ EgwProxy.Shelly/DTO/Gen1/RelayInfoDto.cs | 37 +++ .../DTO/Gen1/Shelly3EMStatusDto.cs | 214 ++++++++++++++++++ EgwProxy.Shelly/DTO/Gen1/UpdateInfoDto.cs | 29 +++ .../DTO/Gen1/WifiStationInfoDto.cs | 26 +++ EgwProxy.Shelly/EgwProxy.Shelly.csproj | 9 + 10 files changed, 427 insertions(+) create mode 100644 EgwProxy.Shelly/DTO/Gen1/ActionsStatsDto.cs create mode 100644 EgwProxy.Shelly/DTO/Gen1/CloudInfoDto.cs create mode 100644 EgwProxy.Shelly/DTO/Gen1/EmeterInfoDto.cs create mode 100644 EgwProxy.Shelly/DTO/Gen1/EmeterNInfoDto.cs create mode 100644 EgwProxy.Shelly/DTO/Gen1/MqttInfoDto.cs create mode 100644 EgwProxy.Shelly/DTO/Gen1/RelayInfoDto.cs create mode 100644 EgwProxy.Shelly/DTO/Gen1/Shelly3EMStatusDto.cs create mode 100644 EgwProxy.Shelly/DTO/Gen1/UpdateInfoDto.cs create mode 100644 EgwProxy.Shelly/DTO/Gen1/WifiStationInfoDto.cs diff --git a/EgwProxy.Shelly/DTO/Gen1/ActionsStatsDto.cs b/EgwProxy.Shelly/DTO/Gen1/ActionsStatsDto.cs new file mode 100644 index 0000000..4702e04 --- /dev/null +++ b/EgwProxy.Shelly/DTO/Gen1/ActionsStatsDto.cs @@ -0,0 +1,17 @@ +using Newtonsoft.Json; + +// +// This is here so CodeMaid doesn't reorganize this document +// +namespace EgwProxy.Shelly.DTO.Gen1 +{ + /// + /// Actions Stats + /// + public class ActionsStatsDto + { + [JsonProperty("skipped")] + public int Skipped { get; set; } + } + +} diff --git a/EgwProxy.Shelly/DTO/Gen1/CloudInfoDto.cs b/EgwProxy.Shelly/DTO/Gen1/CloudInfoDto.cs new file mode 100644 index 0000000..b96e204 --- /dev/null +++ b/EgwProxy.Shelly/DTO/Gen1/CloudInfoDto.cs @@ -0,0 +1,19 @@ +using Newtonsoft.Json; + +// +// This is here so CodeMaid doesn't reorganize this document +// +namespace EgwProxy.Shelly.DTO.Gen1 +{ + /// + /// Cloud Info + /// + public class CloudInfoDto + { + [JsonProperty("enabled")] + public bool Enabled { get; set; } + + [JsonProperty("connected")] + public bool Connected { get; set; } + } +} diff --git a/EgwProxy.Shelly/DTO/Gen1/EmeterInfoDto.cs b/EgwProxy.Shelly/DTO/Gen1/EmeterInfoDto.cs new file mode 100644 index 0000000..813deeb --- /dev/null +++ b/EgwProxy.Shelly/DTO/Gen1/EmeterInfoDto.cs @@ -0,0 +1,34 @@ +using Newtonsoft.Json; + +// +// This is here so CodeMaid doesn't reorganize this document +// +namespace EgwProxy.Shelly.DTO.Gen1 +{ + /// + /// EMeter Info + /// + public class EmeterInfoDto + { + [JsonProperty("power")] + public double PowerWatts { get; set; } + + [JsonProperty("pf")] + public double PowerFactor { get; set; } + + [JsonProperty("current")] + public double CurrentAmps { get; set; } + + [JsonProperty("voltage")] + public double VoltageVolts { get; set; } + + [JsonProperty("is_valid")] + public bool IsValid { get; set; } + + [JsonProperty("total")] + public double TotalKWh { get; set; } + + [JsonProperty("total_returned")] + public double TotalReturnedKWh { get; set; } + } +} diff --git a/EgwProxy.Shelly/DTO/Gen1/EmeterNInfoDto.cs b/EgwProxy.Shelly/DTO/Gen1/EmeterNInfoDto.cs new file mode 100644 index 0000000..6fa6a12 --- /dev/null +++ b/EgwProxy.Shelly/DTO/Gen1/EmeterNInfoDto.cs @@ -0,0 +1,26 @@ +using Newtonsoft.Json; + +// +// This is here so CodeMaid doesn't reorganize this document +// +namespace EgwProxy.Shelly.DTO.Gen1 +{ + + /// + /// EMeter N Info + /// + public class EmeterNInfoDto + { + [JsonProperty("current")] + public double CurrentAmps { get; set; } + + [JsonProperty("ixsum")] + public double Ixsum { get; set; } + + [JsonProperty("mismatch")] + public bool Mismatch { get; set; } + + [JsonProperty("is_valid")] + public bool IsValid { get; set; } + } +} diff --git a/EgwProxy.Shelly/DTO/Gen1/MqttInfoDto.cs b/EgwProxy.Shelly/DTO/Gen1/MqttInfoDto.cs new file mode 100644 index 0000000..f6f60fa --- /dev/null +++ b/EgwProxy.Shelly/DTO/Gen1/MqttInfoDto.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +// +// This is here so CodeMaid doesn't reorganize this document +// +namespace EgwProxy.Shelly.DTO.Gen1 +{ + /// + /// MQTT Info + /// + public class MqttInfoDto + { + [JsonProperty("connected")] + public bool Connected { get; set; } + } +} diff --git a/EgwProxy.Shelly/DTO/Gen1/RelayInfoDto.cs b/EgwProxy.Shelly/DTO/Gen1/RelayInfoDto.cs new file mode 100644 index 0000000..209b2ce --- /dev/null +++ b/EgwProxy.Shelly/DTO/Gen1/RelayInfoDto.cs @@ -0,0 +1,37 @@ +using Newtonsoft.Json; + +// +// This is here so CodeMaid doesn't reorganize this document +// +namespace EgwProxy.Shelly.DTO.Gen1 +{ + /// + /// Relay Info + /// + public class RelayInfoDto + { + [JsonProperty("ison")] + public bool IsOn { get; set; } + + [JsonProperty("has_timer")] + public bool HasTimer { get; set; } + + [JsonProperty("timer_started")] + public int TimerStarted { get; set; } + + [JsonProperty("timer_duration")] + public int TimerDuration { get; set; } + + [JsonProperty("timer_remaining")] + public int TimerRemaining { get; set; } + + [JsonProperty("overpower")] + public bool Overpower { get; set; } + + [JsonProperty("is_valid")] + public bool IsValid { get; set; } + + [JsonProperty("source")] + public string Source { get; set; } = string.Empty; + } +} \ No newline at end of file diff --git a/EgwProxy.Shelly/DTO/Gen1/Shelly3EMStatusDto.cs b/EgwProxy.Shelly/DTO/Gen1/Shelly3EMStatusDto.cs new file mode 100644 index 0000000..5cb5c95 --- /dev/null +++ b/EgwProxy.Shelly/DTO/Gen1/Shelly3EMStatusDto.cs @@ -0,0 +1,214 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; + +// +// This is here so CodeMaid doesn't reorganize this document +// +namespace EgwProxy.Shelly.DTO.Gen1 +{ + /// + /// Represents the status response from a Shelly 3EM device. + /// This class maps the JSON structure returned by the Shelly 3EM REST API. + /// + public class Shelly3EMStatusDto + { + /// + /// Wi-Fi station configuration (connected status, SSID, IP, RSSI) + /// + [JsonProperty("wifi_sta")] + public WifiStationInfoDto WifiStation { get; set; } + + /// + /// Cloud connectivity status (enabled and connected) + /// + [JsonProperty("cloud")] + public CloudInfoDto Cloud { get; set; } + + /// + /// MQTT connectivity status + /// + [JsonProperty("mqtt")] + public MqttInfoDto Mqtt { get; set; } + + /// + /// Current time in HH:MM format (e.g., "15:19") + /// + [JsonProperty("time")] + public string Time { get; set; } = string.Empty; + + /// + /// Unix timestamp (seconds since epoch) + /// + [JsonProperty("unixtime")] + public long UnixTime { get; set; } + + /// + /// Device serial number (unique ID) + /// + [JsonProperty("serial")] + public int Serial { get; set; } + + /// + /// Whether an update is available (true = update available) + /// + [JsonProperty("has_update")] + public bool HasUpdate { get; set; } + + /// + /// MAC address of the device + /// + [JsonProperty("mac")] + public string Mac { get; set; } = string.Empty; + + /// + /// Number of configuration changes since boot + /// + [JsonProperty("cfg_changed_cnt")] + public int CfgChangedCount { get; set; } + + /// + /// Actions statistics (e.g., how many actions were skipped) + /// + [JsonProperty("actions_stats")] + public ActionsStatsDto ActionsStats { get; set; } + + /// + /// Array of relay states (e.g., on/off, timer, overpower) + /// + [JsonProperty("relays")] + public List Relays { get; set; } = new List(); + + /// + /// Array of emeter readings (each emeter has power, current, voltage, total energy) + /// + [JsonProperty("emeters")] + public List Emeters { get; set; } = new List(); + + /// + /// Total power consumption across all emeters (in watts) + /// + [JsonProperty("total_power")] + public double TotalPower { get; set; } + + /// + /// EMeter N data (e.g., current, ixsum, mismatch) + /// + [JsonProperty("emeter_n")] + public EmeterNInfoDto EmeterN { get; set; } + + /// + /// Whether filesystem is mounted (true = mounted) + /// + [JsonProperty("fs_mounted")] + public bool Fsmounted { get; set; } + + /// + /// Version data (v_data = 1 means normal operation) + /// + [JsonProperty("v_data")] + public int VData { get; set; } + + /// + /// Calibration timestamp (0 = not set) + /// + [JsonProperty("ct_calst")] + public int CTCalst { get; set; } + + /// + /// Update information (status, versions) + /// + [JsonProperty("update")] + public UpdateInfoDto Update { get; set; } + + /// + /// RAM total (in KB) + /// + [JsonProperty("ram_total")] + public int RamTotal { get; set; } + + /// + /// RAM free (in KB) + /// + [JsonProperty("ram_free")] + public int RamFree { get; set; } + + /// + /// Filesystem size (in KB) + /// + [JsonProperty("fs_size")] + public int Fssize { get; set; } + + /// + /// Filesystem free space (in KB) + /// + [JsonProperty("fs_free")] + public int FsFree { get; set; } + + /// + /// Uptime in seconds (e.g., 336276 seconds = ~93.4 hours) + /// + [JsonProperty("uptime")] + public int Uptime { get; set; } + + /// + /// Converts Unix timestamp to a DateTime object + /// + /// UTC DateTime + public DateTime GetDateTimeFromUnixTime() + { + return DateTimeOffset.FromUnixTimeSeconds(UnixTime).UtcDateTime; + } + + /// + /// Gets total power consumption in watts (from emeters) + /// + /// Sum of all emeter powers + public double GetTotalPowerFromEmeters() + { + return Emeters.Sum(emeter => emeter.PowerWatts); + } + + /// + /// Gets total energy consumption in kWh (sum of total values) + /// + /// Total kWh across all emeters + public double GetTotalEnergyKWh() + { + return Emeters.Sum(emeter => emeter.TotalKWh); + } + + /// + /// Checks if the device is connected to Wi-Fi and cloud + /// + /// True if both Wi-Fi and cloud are connected + public bool IsConnected() + { + return WifiStation?.Connected == true && + Cloud?.Connected == true && + !string.IsNullOrEmpty(WifiStation?.Ssid); + } + + /// + /// Checks if the device has an available update + /// + /// True if update is available + public bool HasAvailableUpdate() + { + return Update?.HasUpdate == true; + } + + /// + /// Returns the current time as a formatted string (HH:mm) + /// + /// Formatted time string + public string GetFormattedTime() + { + if (string.IsNullOrEmpty(Time)) + return "N/A"; + + return Time; + } + } +} diff --git a/EgwProxy.Shelly/DTO/Gen1/UpdateInfoDto.cs b/EgwProxy.Shelly/DTO/Gen1/UpdateInfoDto.cs new file mode 100644 index 0000000..86c49ff --- /dev/null +++ b/EgwProxy.Shelly/DTO/Gen1/UpdateInfoDto.cs @@ -0,0 +1,29 @@ +using Newtonsoft.Json; + +// +// This is here so CodeMaid doesn't reorganize this document +// +namespace EgwProxy.Shelly.DTO.Gen1 +{ + + /// + /// Update Info + /// + public class UpdateInfoDto + { + [JsonProperty("status")] + public string Status { get; set; } = string.Empty; + + [JsonProperty("has_update")] + public bool HasUpdate { get; set; } + + [JsonProperty("new_version")] + public string NewVersion { get; set; } = string.Empty; + + [JsonProperty("old_version")] + public string OldVersion { get; set; } = string.Empty; + + [JsonProperty("beta_version")] + public string BetaVersion { get; set; } = string.Empty; + } +} diff --git a/EgwProxy.Shelly/DTO/Gen1/WifiStationInfoDto.cs b/EgwProxy.Shelly/DTO/Gen1/WifiStationInfoDto.cs new file mode 100644 index 0000000..05e082f --- /dev/null +++ b/EgwProxy.Shelly/DTO/Gen1/WifiStationInfoDto.cs @@ -0,0 +1,26 @@ +using Newtonsoft.Json; + +// +// This is here so CodeMaid doesn't reorganize this document +// +namespace EgwProxy.Shelly.DTO.Gen1 +{ + + /// + /// Wi-Fi Station Info + /// + public class WifiStationInfoDto + { + [JsonProperty("connected")] + public bool Connected { get; set; } + + [JsonProperty("ssid")] + public string Ssid { get; set; } = string.Empty; + + [JsonProperty("ip")] + public string Ip { get; set; } = string.Empty; + + [JsonProperty("rssi")] + public int Rssi { get; set; } + } +} diff --git a/EgwProxy.Shelly/EgwProxy.Shelly.csproj b/EgwProxy.Shelly/EgwProxy.Shelly.csproj index 22709c5..1700e0b 100644 --- a/EgwProxy.Shelly/EgwProxy.Shelly.csproj +++ b/EgwProxy.Shelly/EgwProxy.Shelly.csproj @@ -92,6 +92,15 @@ + + + + + + + + +