diff --git a/src/GreenHome.Application/Dtos.cs b/src/GreenHome.Application/Dtos.cs
index bb74338..66f4516 100644
--- a/src/GreenHome.Application/Dtos.cs
+++ b/src/GreenHome.Application/Dtos.cs
@@ -26,6 +26,8 @@ public sealed class TelemetryDto
public decimal SoilPercent { get; set; }
public int GasPPM { get; set; }
public decimal? Voltage { get; set; }
+ public decimal? BatteryVoltage { get; set; }
+ public decimal? BatteryPercent { get; set; }
public byte? Power { get; set; }
public byte? OldPower { get; set; }
public decimal Lux { get; set; }
diff --git a/src/GreenHome.Domain/TelemetryRecord.cs b/src/GreenHome.Domain/TelemetryRecord.cs
index 4ac0988..afc50d7 100644
--- a/src/GreenHome.Domain/TelemetryRecord.cs
+++ b/src/GreenHome.Domain/TelemetryRecord.cs
@@ -16,6 +16,8 @@ public sealed class TelemetryRecord
[Column(TypeName = "decimal(18,2)")]
public decimal? Voltage { get; set; }
+ public decimal? BatteryVoltage { get; set; }
+ public decimal? BatteryPercent { get; set; }
public byte? Power { get; set; }
public int PersianYear { get; set; }
public int PersianMonth { get; set; }
diff --git a/src/GreenHome.Infrastructure/GreenHomeDbContext.cs b/src/GreenHome.Infrastructure/GreenHomeDbContext.cs
index 94afa61..3e22b8c 100644
--- a/src/GreenHome.Infrastructure/GreenHomeDbContext.cs
+++ b/src/GreenHome.Infrastructure/GreenHomeDbContext.cs
@@ -55,6 +55,8 @@ public sealed class GreenHomeDbContext : DbContext
b.Property(x => x.Lux).HasColumnType("decimal(18,2)");
b.Property(x => x.PersianDate).HasMaxLength(10);
b.Property(x => x.Voltage).HasColumnType("decimal(18,2)");
+ b.Property(x => x.BatteryVoltage).HasColumnType("decimal(18,2)");
+ b.Property(x => x.BatteryPercent).HasColumnType("decimal(18,2)");
b.HasIndex(x => new { x.DeviceId, x.PersianYear, x.PersianMonth });
b.HasIndex(x => new { x.DeviceId, x.TimestampUtc });
b.HasIndex(x => new { x.DeviceId, x.ServerTimestampUtc });
diff --git a/src/GreenHome.Infrastructure/Migrations/20260113032844_AddBatteryInfoFields.Designer.cs b/src/GreenHome.Infrastructure/Migrations/20260113032844_AddBatteryInfoFields.Designer.cs
new file mode 100644
index 0000000..55a9ccc
--- /dev/null
+++ b/src/GreenHome.Infrastructure/Migrations/20260113032844_AddBatteryInfoFields.Designer.cs
@@ -0,0 +1,1246 @@
+//
+using System;
+using GreenHome.Infrastructure;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace GreenHome.Infrastructure.Migrations
+{
+ [DbContext(typeof(GreenHomeDbContext))]
+ [Migration("20260113032844_AddBatteryInfoFields")]
+ partial class AddBatteryInfoFields
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "9.0.9")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128);
+
+ SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
+
+ modelBuilder.Entity("GreenHome.Domain.AIQuery", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("Answer")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("CompletionTokens")
+ .HasColumnType("int");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("DeviceId")
+ .HasColumnType("int");
+
+ b.Property("Model")
+ .HasMaxLength(100)
+ .HasColumnType("nvarchar(100)");
+
+ b.Property("PromptTokens")
+ .HasColumnType("int");
+
+ b.Property("Question")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("ResponseTimeMs")
+ .HasColumnType("bigint");
+
+ b.Property("Temperature")
+ .HasColumnType("float");
+
+ b.Property("TotalTokens")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CreatedAt");
+
+ b.HasIndex("DeviceId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AIQueries", (string)null);
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.AlertCondition", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("CallCooldownMinutes")
+ .HasColumnType("int");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("DeviceId")
+ .HasColumnType("int");
+
+ b.Property("IsEnabled")
+ .HasColumnType("bit");
+
+ b.Property("NotificationType")
+ .HasColumnType("int");
+
+ b.Property("SmsCooldownMinutes")
+ .HasColumnType("int");
+
+ b.Property("TimeType")
+ .HasColumnType("int");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("datetime2");
+
+ b.HasKey("Id");
+
+ b.HasIndex("DeviceId");
+
+ b.ToTable("AlertConditions", (string)null);
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.AlertLog", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("AlertConditionId")
+ .HasColumnType("int");
+
+ b.Property("AlertType")
+ .HasColumnType("int");
+
+ b.Property("DeviceId")
+ .HasColumnType("int");
+
+ b.Property("ErrorMessage")
+ .HasMaxLength(2000)
+ .HasColumnType("nvarchar(2000)");
+
+ b.Property("Message")
+ .IsRequired()
+ .HasMaxLength(1000)
+ .HasColumnType("nvarchar(1000)");
+
+ b.Property("NotificationType")
+ .HasColumnType("int");
+
+ b.Property("PhoneNumber")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("nvarchar(20)");
+
+ b.Property("ProcessingTimeMs")
+ .HasColumnType("bigint");
+
+ b.Property("SentAt")
+ .HasColumnType("datetime2");
+
+ b.Property("Status")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AlertConditionId");
+
+ b.HasIndex("AlertType");
+
+ b.HasIndex("Status");
+
+ b.HasIndex("DeviceId", "SentAt");
+
+ b.HasIndex("UserId", "SentAt");
+
+ b.ToTable("AlertLogs", (string)null);
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.AlertNotification", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("AlertConditionId")
+ .HasColumnType("int");
+
+ b.Property("DeviceId")
+ .HasColumnType("int");
+
+ b.Property("ErrorMessage")
+ .HasMaxLength(1000)
+ .HasColumnType("nvarchar(1000)");
+
+ b.Property("IsSent")
+ .HasColumnType("bit");
+
+ b.Property("Message")
+ .IsRequired()
+ .HasMaxLength(500)
+ .HasColumnType("nvarchar(500)");
+
+ b.Property("MessageOutboxIds")
+ .HasMaxLength(500)
+ .HasColumnType("nvarchar(500)");
+
+ b.Property("NotificationType")
+ .HasColumnType("int");
+
+ b.Property("SentAt")
+ .HasColumnType("datetime2");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AlertConditionId");
+
+ b.HasIndex("UserId");
+
+ b.HasIndex("DeviceId", "UserId", "AlertConditionId", "SentAt");
+
+ b.ToTable("AlertNotifications", (string)null);
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.AlertRule", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("AlertConditionId")
+ .HasColumnType("int");
+
+ b.Property("ComparisonType")
+ .HasColumnType("int");
+
+ b.Property("Order")
+ .HasColumnType("int");
+
+ b.Property("SensorType")
+ .HasColumnType("int");
+
+ b.Property("Value1")
+ .HasColumnType("decimal(18,2)");
+
+ b.Property("Value2")
+ .HasColumnType("decimal(18,2)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AlertConditionId");
+
+ b.ToTable("AlertRules", (string)null);
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.Checklist", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("CreatedByUserId")
+ .HasColumnType("int");
+
+ b.Property("Description")
+ .HasMaxLength(1000)
+ .HasColumnType("nvarchar(1000)");
+
+ b.Property("DeviceId")
+ .HasColumnType("int");
+
+ b.Property("IsActive")
+ .HasColumnType("bit");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("nvarchar(200)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CreatedByUserId");
+
+ b.HasIndex("DeviceId", "IsActive");
+
+ b.ToTable("Checklists", (string)null);
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.ChecklistCompletion", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("ChecklistId")
+ .HasColumnType("int");
+
+ b.Property("CompletedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("CompletedByUserId")
+ .HasColumnType("int");
+
+ b.Property("Notes")
+ .HasMaxLength(2000)
+ .HasColumnType("nvarchar(2000)");
+
+ b.Property("PersianDate")
+ .IsRequired()
+ .HasMaxLength(10)
+ .HasColumnType("nvarchar(10)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CompletedByUserId");
+
+ b.HasIndex("ChecklistId", "PersianDate");
+
+ b.ToTable("ChecklistCompletions", (string)null);
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.ChecklistItem", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("ChecklistId")
+ .HasColumnType("int");
+
+ b.Property("Description")
+ .HasMaxLength(1000)
+ .HasColumnType("nvarchar(1000)");
+
+ b.Property("IsRequired")
+ .HasColumnType("bit");
+
+ b.Property("Order")
+ .HasColumnType("int");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasMaxLength(300)
+ .HasColumnType("nvarchar(300)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ChecklistId", "Order");
+
+ b.ToTable("ChecklistItems", (string)null);
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.ChecklistItemCompletion", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("ChecklistCompletionId")
+ .HasColumnType("int");
+
+ b.Property("ChecklistItemId")
+ .HasColumnType("int");
+
+ b.Property("IsChecked")
+ .HasColumnType("bit");
+
+ b.Property("Note")
+ .HasMaxLength(500)
+ .HasColumnType("nvarchar(500)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ChecklistCompletionId");
+
+ b.HasIndex("ChecklistItemId");
+
+ b.ToTable("ChecklistItemCompletions", (string)null);
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.DailyReport", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("Analysis")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("CompletionTokens")
+ .HasColumnType("int");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("DeviceId")
+ .HasColumnType("int");
+
+ b.Property("Model")
+ .HasMaxLength(100)
+ .HasColumnType("nvarchar(100)");
+
+ b.Property("PersianDate")
+ .IsRequired()
+ .HasMaxLength(10)
+ .HasColumnType("nvarchar(10)");
+
+ b.Property("PersianDay")
+ .HasColumnType("int");
+
+ b.Property("PersianMonth")
+ .HasColumnType("int");
+
+ b.Property("PersianYear")
+ .HasColumnType("int");
+
+ b.Property("PromptTokens")
+ .HasColumnType("int");
+
+ b.Property("RecordCount")
+ .HasColumnType("int");
+
+ b.Property("ResponseTimeMs")
+ .HasColumnType("bigint");
+
+ b.Property("SampledRecordCount")
+ .HasColumnType("int");
+
+ b.Property("TotalTokens")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CreatedAt");
+
+ b.HasIndex("DeviceId", "PersianDate")
+ .IsUnique();
+
+ b.HasIndex("DeviceId", "PersianYear", "PersianMonth");
+
+ b.ToTable("DailyReports", (string)null);
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.Device", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("DeviceName")
+ .IsRequired()
+ .HasMaxLength(10)
+ .HasColumnType("nvarchar(10)");
+
+ b.Property("Location")
+ .IsRequired()
+ .HasMaxLength(250)
+ .HasColumnType("nvarchar(250)");
+
+ b.Property("NeshanLocation")
+ .IsRequired()
+ .HasMaxLength(80)
+ .HasColumnType("nvarchar(80)");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("Devices", (string)null);
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.DevicePost", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("AuthorUserId")
+ .HasColumnType("int");
+
+ b.Property("Content")
+ .IsRequired()
+ .HasMaxLength(5000)
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("DeviceId")
+ .HasColumnType("int");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("datetime2");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AuthorUserId");
+
+ b.HasIndex("DeviceId", "CreatedAt");
+
+ b.ToTable("DevicePosts", (string)null);
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.DevicePostImage", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("ContentType")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("nvarchar(100)");
+
+ b.Property("DevicePostId")
+ .HasColumnType("int");
+
+ b.Property("FileName")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("nvarchar(255)");
+
+ b.Property("FilePath")
+ .IsRequired()
+ .HasMaxLength(500)
+ .HasColumnType("nvarchar(500)");
+
+ b.Property("FileSize")
+ .HasColumnType("bigint");
+
+ b.Property("UploadedAt")
+ .HasColumnType("datetime2");
+
+ b.HasKey("Id");
+
+ b.HasIndex("DevicePostId");
+
+ b.ToTable("DevicePostImages", (string)null);
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.DeviceSettings", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("AreaSquareMeters")
+ .HasColumnType("decimal(18,2)");
+
+ b.Property("City")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("nvarchar(100)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("DeviceId")
+ .HasColumnType("int");
+
+ b.Property("DeviceId1")
+ .HasColumnType("int");
+
+ b.Property("DevicePhoneNumber")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Latitude")
+ .HasColumnType("decimal(9,6)");
+
+ b.Property("Longitude")
+ .HasColumnType("decimal(9,6)");
+
+ b.Property("MinimumCallIntervalMinutes")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasDefaultValue(60);
+
+ b.Property("MinimumSmsIntervalMinutes")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasDefaultValue(15);
+
+ b.Property("ProductType")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("nvarchar(100)");
+
+ b.Property("Province")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("nvarchar(100)");
+
+ b.Property("SimCardType")
+ .HasColumnType("int");
+
+ b.Property("SmsRecievers")
+ .IsRequired()
+ .HasMaxLength(120)
+ .HasColumnType("nvarchar(120)");
+
+ b.Property("TokenCode")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("TokenExpiresAt")
+ .HasColumnType("datetime2");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("UploadIntervalMin")
+ .HasColumnType("int");
+
+ b.Property("VerificationCode")
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("DeviceId")
+ .IsUnique();
+
+ b.HasIndex("DeviceId1");
+
+ b.ToTable("DeviceSettings", (string)null);
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.DeviceUser", b =>
+ {
+ b.Property("DeviceId")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.Property("ReceiveAlerts")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bit")
+ .HasDefaultValue(true);
+
+ b.HasKey("DeviceId", "UserId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("DeviceUsers", (string)null);
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.ReportImage", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("ContentType")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("nvarchar(100)");
+
+ b.Property("Description")
+ .HasMaxLength(500)
+ .HasColumnType("nvarchar(500)");
+
+ b.Property("FileName")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("nvarchar(255)");
+
+ b.Property("FilePath")
+ .IsRequired()
+ .HasMaxLength(500)
+ .HasColumnType("nvarchar(500)");
+
+ b.Property("FileSize")
+ .HasColumnType("bigint");
+
+ b.Property("UploadedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("UserDailyReportId")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserDailyReportId");
+
+ b.ToTable("ReportImages", (string)null);
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.TelemetryRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("BatteryPercent")
+ .HasColumnType("decimal(18,2)");
+
+ b.Property("BatteryVoltage")
+ .HasColumnType("decimal(18,2)");
+
+ b.Property("DeviceId")
+ .HasColumnType("int");
+
+ b.Property("GasPPM")
+ .HasColumnType("int");
+
+ b.Property("HumidityPercent")
+ .HasColumnType("decimal(18,2)");
+
+ b.Property("Lux")
+ .HasColumnType("decimal(18,2)");
+
+ b.Property("PersianDate")
+ .IsRequired()
+ .HasMaxLength(10)
+ .HasColumnType("nvarchar(10)");
+
+ b.Property("PersianMonth")
+ .HasColumnType("int");
+
+ b.Property("PersianYear")
+ .HasColumnType("int");
+
+ b.Property("Power")
+ .HasColumnType("tinyint");
+
+ b.Property("ServerTimestampUtc")
+ .HasColumnType("datetime2");
+
+ b.Property("SoilPercent")
+ .HasColumnType("decimal(18,2)");
+
+ b.Property("TemperatureC")
+ .HasColumnType("decimal(18,2)");
+
+ b.Property("TimestampUtc")
+ .HasColumnType("datetime2");
+
+ b.Property("Voltage")
+ .HasColumnType("decimal(18,2)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("DeviceId", "ServerTimestampUtc");
+
+ b.HasIndex("DeviceId", "TimestampUtc");
+
+ b.HasIndex("DeviceId", "PersianYear", "PersianMonth");
+
+ b.ToTable("Telemetry", (string)null);
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.User", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("Family")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("nvarchar(100)");
+
+ b.Property("LastLoginAt")
+ .HasColumnType("datetime2");
+
+ b.Property("Mobile")
+ .IsRequired()
+ .HasMaxLength(11)
+ .HasColumnType("nvarchar(11)");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("nvarchar(100)");
+
+ b.Property("Role")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Mobile")
+ .IsUnique();
+
+ b.ToTable("Users", (string)null);
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.UserDailyReport", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("DeviceId")
+ .HasColumnType("int");
+
+ b.Property("Notes")
+ .HasMaxLength(2000)
+ .HasColumnType("nvarchar(2000)");
+
+ b.Property("Observations")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Operations")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("PersianDate")
+ .IsRequired()
+ .HasMaxLength(10)
+ .HasColumnType("nvarchar(10)");
+
+ b.Property("PersianDay")
+ .HasColumnType("int");
+
+ b.Property("PersianMonth")
+ .HasColumnType("int");
+
+ b.Property("PersianYear")
+ .HasColumnType("int");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("nvarchar(200)");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.HasIndex("DeviceId", "PersianDate");
+
+ b.HasIndex("DeviceId", "PersianYear", "PersianMonth");
+
+ b.ToTable("UserDailyReports", (string)null);
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.VerificationCode", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("Code")
+ .IsRequired()
+ .HasMaxLength(4)
+ .HasColumnType("nvarchar(4)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2");
+
+ b.Property("ExpiresAt")
+ .HasColumnType("datetime2");
+
+ b.Property("IsUsed")
+ .HasColumnType("bit");
+
+ b.Property("Mobile")
+ .IsRequired()
+ .HasMaxLength(11)
+ .HasColumnType("nvarchar(11)");
+
+ b.Property("UsedAt")
+ .HasColumnType("datetime2");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Mobile", "Code", "IsUsed");
+
+ b.ToTable("VerificationCodes", (string)null);
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.AIQuery", b =>
+ {
+ b.HasOne("GreenHome.Domain.Device", "Device")
+ .WithMany()
+ .HasForeignKey("DeviceId")
+ .OnDelete(DeleteBehavior.SetNull);
+
+ b.HasOne("GreenHome.Domain.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.SetNull);
+
+ b.Navigation("Device");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.AlertCondition", b =>
+ {
+ b.HasOne("GreenHome.Domain.Device", "Device")
+ .WithMany()
+ .HasForeignKey("DeviceId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Device");
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.AlertLog", b =>
+ {
+ b.HasOne("GreenHome.Domain.AlertCondition", "AlertCondition")
+ .WithMany()
+ .HasForeignKey("AlertConditionId")
+ .OnDelete(DeleteBehavior.SetNull);
+
+ b.HasOne("GreenHome.Domain.Device", "Device")
+ .WithMany()
+ .HasForeignKey("DeviceId")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired();
+
+ b.HasOne("GreenHome.Domain.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired();
+
+ b.Navigation("AlertCondition");
+
+ b.Navigation("Device");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.AlertNotification", b =>
+ {
+ b.HasOne("GreenHome.Domain.AlertCondition", "AlertCondition")
+ .WithMany()
+ .HasForeignKey("AlertConditionId")
+ .OnDelete(DeleteBehavior.Restrict);
+
+ b.HasOne("GreenHome.Domain.Device", "Device")
+ .WithMany()
+ .HasForeignKey("DeviceId")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired();
+
+ b.HasOne("GreenHome.Domain.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired();
+
+ b.Navigation("AlertCondition");
+
+ b.Navigation("Device");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.AlertRule", b =>
+ {
+ b.HasOne("GreenHome.Domain.AlertCondition", "AlertCondition")
+ .WithMany("Rules")
+ .HasForeignKey("AlertConditionId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("AlertCondition");
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.Checklist", b =>
+ {
+ b.HasOne("GreenHome.Domain.User", "CreatedByUser")
+ .WithMany()
+ .HasForeignKey("CreatedByUserId")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired();
+
+ b.HasOne("GreenHome.Domain.Device", "Device")
+ .WithMany()
+ .HasForeignKey("DeviceId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("CreatedByUser");
+
+ b.Navigation("Device");
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.ChecklistCompletion", b =>
+ {
+ b.HasOne("GreenHome.Domain.Checklist", "Checklist")
+ .WithMany("Completions")
+ .HasForeignKey("ChecklistId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("GreenHome.Domain.User", "CompletedByUser")
+ .WithMany()
+ .HasForeignKey("CompletedByUserId")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired();
+
+ b.Navigation("Checklist");
+
+ b.Navigation("CompletedByUser");
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.ChecklistItem", b =>
+ {
+ b.HasOne("GreenHome.Domain.Checklist", "Checklist")
+ .WithMany("Items")
+ .HasForeignKey("ChecklistId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Checklist");
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.ChecklistItemCompletion", b =>
+ {
+ b.HasOne("GreenHome.Domain.ChecklistCompletion", "ChecklistCompletion")
+ .WithMany("ItemCompletions")
+ .HasForeignKey("ChecklistCompletionId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("GreenHome.Domain.ChecklistItem", "ChecklistItem")
+ .WithMany()
+ .HasForeignKey("ChecklistItemId")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired();
+
+ b.Navigation("ChecklistCompletion");
+
+ b.Navigation("ChecklistItem");
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.DailyReport", b =>
+ {
+ b.HasOne("GreenHome.Domain.Device", "Device")
+ .WithMany()
+ .HasForeignKey("DeviceId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Device");
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.Device", b =>
+ {
+ b.HasOne("GreenHome.Domain.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired();
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.DevicePost", b =>
+ {
+ b.HasOne("GreenHome.Domain.User", "AuthorUser")
+ .WithMany()
+ .HasForeignKey("AuthorUserId")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired();
+
+ b.HasOne("GreenHome.Domain.Device", "Device")
+ .WithMany()
+ .HasForeignKey("DeviceId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("AuthorUser");
+
+ b.Navigation("Device");
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.DevicePostImage", b =>
+ {
+ b.HasOne("GreenHome.Domain.DevicePost", "DevicePost")
+ .WithMany("Images")
+ .HasForeignKey("DevicePostId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("DevicePost");
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.DeviceSettings", b =>
+ {
+ b.HasOne("GreenHome.Domain.Device", "Device")
+ .WithMany()
+ .HasForeignKey("DeviceId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("GreenHome.Domain.Device", null)
+ .WithMany("DeviceSettings")
+ .HasForeignKey("DeviceId1");
+
+ b.Navigation("Device");
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.DeviceUser", b =>
+ {
+ b.HasOne("GreenHome.Domain.Device", "Device")
+ .WithMany("DeviceUsers")
+ .HasForeignKey("DeviceId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("GreenHome.Domain.User", "User")
+ .WithMany("DeviceUsers")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Device");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.ReportImage", b =>
+ {
+ b.HasOne("GreenHome.Domain.UserDailyReport", "UserDailyReport")
+ .WithMany("Images")
+ .HasForeignKey("UserDailyReportId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("UserDailyReport");
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.UserDailyReport", b =>
+ {
+ b.HasOne("GreenHome.Domain.Device", "Device")
+ .WithMany()
+ .HasForeignKey("DeviceId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("GreenHome.Domain.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired();
+
+ b.Navigation("Device");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.AlertCondition", b =>
+ {
+ b.Navigation("Rules");
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.Checklist", b =>
+ {
+ b.Navigation("Completions");
+
+ b.Navigation("Items");
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.ChecklistCompletion", b =>
+ {
+ b.Navigation("ItemCompletions");
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.Device", b =>
+ {
+ b.Navigation("DeviceSettings");
+
+ b.Navigation("DeviceUsers");
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.DevicePost", b =>
+ {
+ b.Navigation("Images");
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.User", b =>
+ {
+ b.Navigation("DeviceUsers");
+ });
+
+ modelBuilder.Entity("GreenHome.Domain.UserDailyReport", b =>
+ {
+ b.Navigation("Images");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/GreenHome.Infrastructure/Migrations/20260113032844_AddBatteryInfoFields.cs b/src/GreenHome.Infrastructure/Migrations/20260113032844_AddBatteryInfoFields.cs
new file mode 100644
index 0000000..20bd24a
--- /dev/null
+++ b/src/GreenHome.Infrastructure/Migrations/20260113032844_AddBatteryInfoFields.cs
@@ -0,0 +1,38 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace GreenHome.Infrastructure.Migrations
+{
+ ///
+ public partial class AddBatteryInfoFields : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn(
+ name: "BatteryPercent",
+ table: "Telemetry",
+ type: "decimal(18,2)",
+ nullable: true);
+
+ migrationBuilder.AddColumn(
+ name: "BatteryVoltage",
+ table: "Telemetry",
+ type: "decimal(18,2)",
+ nullable: true);
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "BatteryPercent",
+ table: "Telemetry");
+
+ migrationBuilder.DropColumn(
+ name: "BatteryVoltage",
+ table: "Telemetry");
+ }
+ }
+}
diff --git a/src/GreenHome.Infrastructure/Migrations/GreenHomeDbContextModelSnapshot.cs b/src/GreenHome.Infrastructure/Migrations/GreenHomeDbContextModelSnapshot.cs
index a6ba3f2..49af6f7 100644
--- a/src/GreenHome.Infrastructure/Migrations/GreenHomeDbContextModelSnapshot.cs
+++ b/src/GreenHome.Infrastructure/Migrations/GreenHomeDbContextModelSnapshot.cs
@@ -727,6 +727,12 @@ namespace GreenHome.Infrastructure.Migrations
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+ b.Property("BatteryPercent")
+ .HasColumnType("decimal(18,2)");
+
+ b.Property("BatteryVoltage")
+ .HasColumnType("decimal(18,2)");
+
b.Property("DeviceId")
.HasColumnType("int");