diff --git a/TeslaSolarCharger.Model/Contracts/ITeslaSolarChargerContext.cs b/TeslaSolarCharger.Model/Contracts/ITeslaSolarChargerContext.cs index a4cb94817..2b5847e30 100644 --- a/TeslaSolarCharger.Model/Contracts/ITeslaSolarChargerContext.cs +++ b/TeslaSolarCharger.Model/Contracts/ITeslaSolarChargerContext.cs @@ -15,7 +15,7 @@ public interface ITeslaSolarChargerContext Task SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken()); DatabaseFacade Database { get; } DbSet SpotPrices { get; set; } - DbSet TeslaTokens { get; set; } + DbSet BackendTokens { get; set; } DbSet TscConfigurations { get; set; } DbSet Cars { get; set; } DbSet RestValueConfigurations { get; set; } diff --git a/TeslaSolarCharger.Model/Entities/TeslaSolarCharger/BackendToken.cs b/TeslaSolarCharger.Model/Entities/TeslaSolarCharger/BackendToken.cs new file mode 100644 index 000000000..08d003500 --- /dev/null +++ b/TeslaSolarCharger.Model/Entities/TeslaSolarCharger/BackendToken.cs @@ -0,0 +1,9 @@ +namespace TeslaSolarCharger.Model.Entities.TeslaSolarCharger; + +public class BackendToken(string accessToken, string refreshToken) +{ + public int Id { get; set; } + public string AccessToken { get; set; } = accessToken; + public string RefreshToken { get; set; } = refreshToken; + public DateTimeOffset ExpiresAtUtc { get; set; } +} diff --git a/TeslaSolarCharger.Model/Entities/TeslaSolarCharger/Car.cs b/TeslaSolarCharger.Model/Entities/TeslaSolarCharger/Car.cs index bd5ec6f18..7a3833203 100644 --- a/TeslaSolarCharger.Model/Entities/TeslaSolarCharger/Car.cs +++ b/TeslaSolarCharger.Model/Entities/TeslaSolarCharger/Car.cs @@ -9,6 +9,7 @@ public class Car public string? Name { get; set; } public string? Vin { get; set; } public TeslaCarFleetApiState? TeslaFleetApiState { get; set; } + public bool IsFleetTelemetryHardwareIncompatible { get; set; } public ChargeMode ChargeMode { get; set; } public int MinimumSoc { get; set; } public DateTime LatestTimeToReachSoC { get; set; } @@ -40,24 +41,19 @@ public class Car public CarStateEnum? State { get; set; } public bool VehicleCommandProtocolRequired { get; set; } - public DateTime? VehicleRateLimitedUntil { get; set; } - public DateTime? VehicleDataRateLimitedUntil { get; set; } - public DateTime? CommandsRateLimitedUntil { get; set; } - public DateTime? WakeUpRateLimitedUntil { get; set; } - public DateTime? ChargingCommandsRateLimitedUntil { get; set; } public bool UseBle { get; set; } public string? BleApiBaseUrl { get; set; } public bool UseFleetTelemetry { get; set; } - public bool UseFleetTelemetryForLocationData { get; set; } + public bool IncludeTrackingRelevantFields { get; set; } public bool IsAvailableInTeslaAccount { get; set; } - public string? WakeUpCalls { get; set; } - public string? VehicleDataCalls { get; set; } - public string? VehicleCalls { get; set; } - public string? ChargeStartCalls { get; set; } - public string? ChargeStopCalls { get; set; } - public string? SetChargingAmpsCall { get; set; } - public string? OtherCommandCalls { get; set; } + public List WakeUpCalls { get; set; } = new(); + public List VehicleDataCalls { get; set; } = new(); + public List VehicleCalls { get; set; } = new(); + public List ChargeStartCalls { get; set; } = new(); + public List ChargeStopCalls { get; set; } = new(); + public List SetChargingAmpsCall { get; set; } = new(); + public List OtherCommandCalls { get; set; } = new(); public List ChargingProcesses { get; set; } = new List(); public List CarValueLogs { get; set; } = new List(); diff --git a/TeslaSolarCharger.Model/Entities/TeslaSolarCharger/TeslaToken.cs b/TeslaSolarCharger.Model/Entities/TeslaSolarCharger/TeslaToken.cs deleted file mode 100644 index 4a61b6153..000000000 --- a/TeslaSolarCharger.Model/Entities/TeslaSolarCharger/TeslaToken.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Microsoft.Extensions.Primitives; -using TeslaSolarCharger.Model.Enums; - -namespace TeslaSolarCharger.Model.Entities.TeslaSolarCharger; - -public class TeslaToken -{ - public int Id { get; set; } - public string AccessToken { get; set; } - public string RefreshToken { get; set; } - public string IdToken { get; set; } - public int UnauthorizedCounter { get; set; } - public DateTime ExpiresAtUtc { get; set; } - public TeslaFleetApiRegion Region { get; set; } -} diff --git a/TeslaSolarCharger.Model/EntityFramework/TeslaSolarChargerContext.cs b/TeslaSolarCharger.Model/EntityFramework/TeslaSolarChargerContext.cs index b0333c1bb..08f517fa3 100644 --- a/TeslaSolarCharger.Model/EntityFramework/TeslaSolarChargerContext.cs +++ b/TeslaSolarCharger.Model/EntityFramework/TeslaSolarChargerContext.cs @@ -16,7 +16,7 @@ public class TeslaSolarChargerContext : DbContext, ITeslaSolarChargerContext public DbSet HandledCharges { get; set; } = null!; public DbSet PowerDistributions { get; set; } = null!; public DbSet SpotPrices { get; set; } = null!; - public DbSet TeslaTokens { get; set; } = null!; + public DbSet BackendTokens { get; set; } = null!; public DbSet TscConfigurations { get; set; } = null!; public DbSet Cars { get; set; } = null!; public DbSet RestValueConfigurations { get; set; } = null!; @@ -124,6 +124,41 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) .HasConversion(timeListToString) .Metadata.SetValueComparer(valueComparer); + modelBuilder.Entity() + .Property(e => e.WakeUpCalls) + .HasConversion(timeListToString) + .Metadata.SetValueComparer(valueComparer); + + modelBuilder.Entity() + .Property(e => e.VehicleDataCalls) + .HasConversion(timeListToString) + .Metadata.SetValueComparer(valueComparer); + + modelBuilder.Entity() + .Property(e => e.VehicleCalls) + .HasConversion(timeListToString) + .Metadata.SetValueComparer(valueComparer); + + modelBuilder.Entity() + .Property(e => e.ChargeStartCalls) + .HasConversion(timeListToString) + .Metadata.SetValueComparer(valueComparer); + + modelBuilder.Entity() + .Property(e => e.ChargeStopCalls) + .HasConversion(timeListToString) + .Metadata.SetValueComparer(valueComparer); + + modelBuilder.Entity() + .Property(e => e.SetChargingAmpsCall) + .HasConversion(timeListToString) + .Metadata.SetValueComparer(valueComparer); + + modelBuilder.Entity() + .Property(e => e.OtherCommandCalls) + .HasConversion(timeListToString) + .Metadata.SetValueComparer(valueComparer); + } #pragma warning disable CS8618 diff --git a/TeslaSolarCharger.Model/Migrations/20241227093212_ReplaceTeslaTokensWithBackendTokens.Designer.cs b/TeslaSolarCharger.Model/Migrations/20241227093212_ReplaceTeslaTokensWithBackendTokens.Designer.cs new file mode 100644 index 000000000..91767f9c7 --- /dev/null +++ b/TeslaSolarCharger.Model/Migrations/20241227093212_ReplaceTeslaTokensWithBackendTokens.Designer.cs @@ -0,0 +1,916 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using TeslaSolarCharger.Model.EntityFramework; + +#nullable disable + +namespace TeslaSolarCharger.Model.Migrations +{ + [DbContext(typeof(TeslaSolarChargerContext))] + [Migration("20241227093212_ReplaceTeslaTokensWithBackendTokens")] + partial class ReplaceTeslaTokensWithBackendTokens + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.10"); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.BackendNotification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("BackendIssueId") + .HasColumnType("INTEGER"); + + b.Property("DetailText") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Headline") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("IsConfirmed") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("ValidFromDate") + .HasColumnType("TEXT"); + + b.Property("ValidFromVersion") + .HasColumnType("TEXT"); + + b.Property("ValidToDate") + .HasColumnType("TEXT"); + + b.Property("ValidToVersion") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("BackendNotifications"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.BackendToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ExpiresAtUtc") + .HasColumnType("TEXT"); + + b.Property("RefreshToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("BackendTokens"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.CachedCarState", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CarId") + .HasColumnType("INTEGER"); + + b.Property("CarStateJson") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("LastUpdated") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("CachedCarStates"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.Car", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("BleApiBaseUrl") + .HasColumnType("TEXT"); + + b.Property("ChargeMode") + .HasColumnType("INTEGER"); + + b.Property("ChargeStartCalls") + .HasColumnType("TEXT"); + + b.Property("ChargeStopCalls") + .HasColumnType("TEXT"); + + b.Property("ChargerActualCurrent") + .HasColumnType("INTEGER"); + + b.Property("ChargerPhases") + .HasColumnType("INTEGER"); + + b.Property("ChargerPilotCurrent") + .HasColumnType("INTEGER"); + + b.Property("ChargerRequestedCurrent") + .HasColumnType("INTEGER"); + + b.Property("ChargerVoltage") + .HasColumnType("INTEGER"); + + b.Property("ChargingCommandsRateLimitedUntil") + .HasColumnType("TEXT"); + + b.Property("ChargingPriority") + .HasColumnType("INTEGER"); + + b.Property("ClimateOn") + .HasColumnType("INTEGER"); + + b.Property("CommandsRateLimitedUntil") + .HasColumnType("TEXT"); + + b.Property("IgnoreLatestTimeToReachSocDate") + .HasColumnType("INTEGER"); + + b.Property("IgnoreLatestTimeToReachSocDateOnWeekend") + .HasColumnType("INTEGER"); + + b.Property("IsAvailableInTeslaAccount") + .HasColumnType("INTEGER"); + + b.Property("LatestTimeToReachSoC") + .HasColumnType("TEXT"); + + b.Property("Latitude") + .HasColumnType("REAL"); + + b.Property("Longitude") + .HasColumnType("REAL"); + + b.Property("MaximumAmpere") + .HasColumnType("INTEGER"); + + b.Property("MinimumAmpere") + .HasColumnType("INTEGER"); + + b.Property("MinimumSoc") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("OtherCommandCalls") + .HasColumnType("TEXT"); + + b.Property("PluggedIn") + .HasColumnType("INTEGER"); + + b.Property("SetChargingAmpsCall") + .HasColumnType("TEXT"); + + b.Property("ShouldBeManaged") + .HasColumnType("INTEGER"); + + b.Property("SoC") + .HasColumnType("INTEGER"); + + b.Property("SocLimit") + .HasColumnType("INTEGER"); + + b.Property("State") + .HasColumnType("INTEGER"); + + b.Property("TeslaFleetApiState") + .HasColumnType("INTEGER"); + + b.Property("TeslaMateCarId") + .HasColumnType("INTEGER"); + + b.Property("UsableEnergy") + .HasColumnType("INTEGER"); + + b.Property("UseBle") + .HasColumnType("INTEGER"); + + b.Property("UseFleetTelemetry") + .HasColumnType("INTEGER"); + + b.Property("UseFleetTelemetryForLocationData") + .HasColumnType("INTEGER"); + + b.Property("VehicleCalls") + .HasColumnType("TEXT"); + + b.Property("VehicleCommandProtocolRequired") + .HasColumnType("INTEGER"); + + b.Property("VehicleDataCalls") + .HasColumnType("TEXT"); + + b.Property("VehicleDataRateLimitedUntil") + .HasColumnType("TEXT"); + + b.Property("VehicleRateLimitedUntil") + .HasColumnType("TEXT"); + + b.Property("Vin") + .HasColumnType("TEXT"); + + b.Property("WakeUpCalls") + .HasColumnType("TEXT"); + + b.Property("WakeUpRateLimitedUntil") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("TeslaMateCarId") + .IsUnique(); + + b.HasIndex("Vin") + .IsUnique(); + + b.ToTable("Cars"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.CarValueLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("BooleanValue") + .HasColumnType("INTEGER"); + + b.Property("CarId") + .HasColumnType("INTEGER"); + + b.Property("DoubleValue") + .HasColumnType("REAL"); + + b.Property("IntValue") + .HasColumnType("INTEGER"); + + b.Property("InvalidValue") + .HasColumnType("INTEGER"); + + b.Property("Source") + .HasColumnType("INTEGER"); + + b.Property("StringValue") + .HasColumnType("TEXT"); + + b.Property("Timestamp") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UnknownValue") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CarId"); + + b.ToTable("CarValueLogs"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargePrice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AddSpotPriceToGridPrice") + .HasColumnType("INTEGER"); + + b.Property("EnergyProvider") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(6); + + b.Property("EnergyProviderConfiguration") + .HasColumnType("TEXT"); + + b.Property("GridPrice") + .HasColumnType("TEXT"); + + b.Property("SolarPrice") + .HasColumnType("TEXT"); + + b.Property("SpotPriceCorrectionFactor") + .HasColumnType("TEXT"); + + b.Property("ValidSince") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("ChargePrices"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChargerVoltage") + .HasColumnType("INTEGER"); + + b.Property("ChargingProcessId") + .HasColumnType("INTEGER"); + + b.Property("GridPower") + .HasColumnType("INTEGER"); + + b.Property("HomeBatteryPower") + .HasColumnType("INTEGER"); + + b.Property("SolarPower") + .HasColumnType("INTEGER"); + + b.Property("TimeStamp") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ChargingProcessId"); + + b.ToTable("ChargingDetails"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingProcess", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CarId") + .HasColumnType("INTEGER"); + + b.Property("Cost") + .HasColumnType("TEXT"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("OldHandledChargeId") + .HasColumnType("INTEGER"); + + b.Property("StartDate") + .HasColumnType("TEXT"); + + b.Property("UsedGridEnergyKwh") + .HasColumnType("TEXT"); + + b.Property("UsedHomeBatteryEnergyKwh") + .HasColumnType("TEXT"); + + b.Property("UsedSolarEnergyKwh") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CarId"); + + b.ToTable("ChargingProcesses"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.HandledCharge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AverageSpotPrice") + .HasColumnType("TEXT"); + + b.Property("CalculatedPrice") + .HasColumnType("TEXT"); + + b.Property("CarId") + .HasColumnType("INTEGER"); + + b.Property("ChargingProcessId") + .HasColumnType("INTEGER"); + + b.Property("UsedGridEnergy") + .HasColumnType("TEXT"); + + b.Property("UsedSolarEnergy") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("HandledCharges"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.LoggedError", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DismissedAt") + .HasColumnType("TEXT"); + + b.Property("EndTimeStamp") + .HasColumnType("TEXT"); + + b.Property("FurtherOccurrences") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Headline") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("IssueKey") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Message") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("MethodName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Source") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("StackTrace") + .HasColumnType("TEXT"); + + b.Property("StartTimeStamp") + .HasColumnType("TEXT"); + + b.Property("TelegramNotificationSent") + .HasColumnType("INTEGER"); + + b.Property("TelegramResolvedMessageSent") + .HasColumnType("INTEGER"); + + b.Property("Vin") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("LoggedErrors"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConnectDelayMilliseconds") + .HasColumnType("INTEGER"); + + b.Property("Endianess") + .HasColumnType("INTEGER"); + + b.Property("Host") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Port") + .HasColumnType("INTEGER"); + + b.Property("ReadTimeoutMilliseconds") + .HasColumnType("INTEGER"); + + b.Property("UnitIdentifier") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("ModbusConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusResultConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Address") + .HasColumnType("INTEGER"); + + b.Property("BitStartIndex") + .HasColumnType("INTEGER"); + + b.Property("CorrectionFactor") + .HasColumnType("TEXT"); + + b.Property("InvertedByModbusResultConfigurationId") + .HasColumnType("INTEGER"); + + b.Property("Length") + .HasColumnType("INTEGER"); + + b.Property("ModbusConfigurationId") + .HasColumnType("INTEGER"); + + b.Property("Operator") + .HasColumnType("INTEGER"); + + b.Property("RegisterType") + .HasColumnType("INTEGER"); + + b.Property("UsedFor") + .HasColumnType("INTEGER"); + + b.Property("ValueType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("InvertedByModbusResultConfigurationId"); + + b.HasIndex("ModbusConfigurationId"); + + b.ToTable("ModbusResultConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.MqttConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Host") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Password") + .HasColumnType("TEXT"); + + b.Property("Port") + .HasColumnType("INTEGER"); + + b.Property("Username") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("MqttConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.MqttResultConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CorrectionFactor") + .HasColumnType("TEXT"); + + b.Property("MqttConfigurationId") + .HasColumnType("INTEGER"); + + b.Property("NodePattern") + .HasColumnType("TEXT"); + + b.Property("NodePatternType") + .HasColumnType("INTEGER"); + + b.Property("Operator") + .HasColumnType("INTEGER"); + + b.Property("Topic") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UsedFor") + .HasColumnType("INTEGER"); + + b.Property("XmlAttributeHeaderName") + .HasColumnType("TEXT"); + + b.Property("XmlAttributeHeaderValue") + .HasColumnType("TEXT"); + + b.Property("XmlAttributeValueName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("MqttConfigurationId"); + + b.ToTable("MqttResultConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.PowerDistribution", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChargingPower") + .HasColumnType("INTEGER"); + + b.Property("GridProportion") + .HasColumnType("REAL"); + + b.Property("HandledChargeId") + .HasColumnType("INTEGER"); + + b.Property("PowerFromGrid") + .HasColumnType("INTEGER"); + + b.Property("TimeStamp") + .HasColumnType("TEXT"); + + b.Property("UsedWattHours") + .HasColumnType("REAL"); + + b.HasKey("Id"); + + b.HasIndex("HandledChargeId"); + + b.ToTable("PowerDistributions"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("HttpMethod") + .HasColumnType("INTEGER"); + + b.Property("NodePatternType") + .HasColumnType("INTEGER"); + + b.Property("Url") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("RestValueConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfigurationHeader", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("RestValueConfigurationId") + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RestValueConfigurationId", "Key") + .IsUnique(); + + b.ToTable("RestValueConfigurationHeaders"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueResultConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CorrectionFactor") + .HasColumnType("TEXT"); + + b.Property("NodePattern") + .HasColumnType("TEXT"); + + b.Property("Operator") + .HasColumnType("INTEGER"); + + b.Property("RestValueConfigurationId") + .HasColumnType("INTEGER"); + + b.Property("UsedFor") + .HasColumnType("INTEGER"); + + b.Property("XmlAttributeHeaderName") + .HasColumnType("TEXT"); + + b.Property("XmlAttributeHeaderValue") + .HasColumnType("TEXT"); + + b.Property("XmlAttributeValueName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RestValueConfigurationId"); + + b.ToTable("RestValueResultConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.SpotPrice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("Price") + .HasColumnType("TEXT"); + + b.Property("StartDate") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("SpotPrices"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.TscConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Key") + .IsUnique(); + + b.ToTable("TscConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.CarValueLog", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.Car", "Car") + .WithMany("CarValueLogs") + .HasForeignKey("CarId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Car"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingDetail", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingProcess", "ChargingProcess") + .WithMany("ChargingDetails") + .HasForeignKey("ChargingProcessId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChargingProcess"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingProcess", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.Car", "Car") + .WithMany("ChargingProcesses") + .HasForeignKey("CarId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Car"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusResultConfiguration", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusResultConfiguration", "InvertedByModbusResultConfiguration") + .WithMany() + .HasForeignKey("InvertedByModbusResultConfigurationId"); + + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusConfiguration", "ModbusConfiguration") + .WithMany("ModbusResultConfigurations") + .HasForeignKey("ModbusConfigurationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("InvertedByModbusResultConfiguration"); + + b.Navigation("ModbusConfiguration"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.MqttResultConfiguration", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.MqttConfiguration", "MqttConfiguration") + .WithMany("MqttResultConfigurations") + .HasForeignKey("MqttConfigurationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MqttConfiguration"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.PowerDistribution", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.HandledCharge", "HandledCharge") + .WithMany("PowerDistributions") + .HasForeignKey("HandledChargeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("HandledCharge"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfigurationHeader", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfiguration", "RestValueConfiguration") + .WithMany("Headers") + .HasForeignKey("RestValueConfigurationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("RestValueConfiguration"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueResultConfiguration", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfiguration", "RestValueConfiguration") + .WithMany("RestValueResultConfigurations") + .HasForeignKey("RestValueConfigurationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("RestValueConfiguration"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.Car", b => + { + b.Navigation("CarValueLogs"); + + b.Navigation("ChargingProcesses"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingProcess", b => + { + b.Navigation("ChargingDetails"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.HandledCharge", b => + { + b.Navigation("PowerDistributions"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusConfiguration", b => + { + b.Navigation("ModbusResultConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.MqttConfiguration", b => + { + b.Navigation("MqttResultConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfiguration", b => + { + b.Navigation("Headers"); + + b.Navigation("RestValueResultConfigurations"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/TeslaSolarCharger.Model/Migrations/20241227093212_ReplaceTeslaTokensWithBackendTokens.cs b/TeslaSolarCharger.Model/Migrations/20241227093212_ReplaceTeslaTokensWithBackendTokens.cs new file mode 100644 index 000000000..70a11fe25 --- /dev/null +++ b/TeslaSolarCharger.Model/Migrations/20241227093212_ReplaceTeslaTokensWithBackendTokens.cs @@ -0,0 +1,58 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace TeslaSolarCharger.Model.Migrations +{ + /// + public partial class ReplaceTeslaTokensWithBackendTokens : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "TeslaTokens"); + + migrationBuilder.CreateTable( + name: "BackendTokens", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + AccessToken = table.Column(type: "TEXT", nullable: false), + RefreshToken = table.Column(type: "TEXT", nullable: false), + ExpiresAtUtc = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_BackendTokens", x => x.Id); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "BackendTokens"); + + migrationBuilder.CreateTable( + name: "TeslaTokens", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + AccessToken = table.Column(type: "TEXT", nullable: false), + ExpiresAtUtc = table.Column(type: "TEXT", nullable: false), + IdToken = table.Column(type: "TEXT", nullable: false), + RefreshToken = table.Column(type: "TEXT", nullable: false), + Region = table.Column(type: "INTEGER", nullable: false), + UnauthorizedCounter = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TeslaTokens", x => x.Id); + }); + } + } +} diff --git a/TeslaSolarCharger.Model/Migrations/20241230094540_RemoveCarRateLimits.Designer.cs b/TeslaSolarCharger.Model/Migrations/20241230094540_RemoveCarRateLimits.Designer.cs new file mode 100644 index 000000000..b19e82170 --- /dev/null +++ b/TeslaSolarCharger.Model/Migrations/20241230094540_RemoveCarRateLimits.Designer.cs @@ -0,0 +1,901 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using TeslaSolarCharger.Model.EntityFramework; + +#nullable disable + +namespace TeslaSolarCharger.Model.Migrations +{ + [DbContext(typeof(TeslaSolarChargerContext))] + [Migration("20241230094540_RemoveCarRateLimits")] + partial class RemoveCarRateLimits + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.10"); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.BackendNotification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("BackendIssueId") + .HasColumnType("INTEGER"); + + b.Property("DetailText") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Headline") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("IsConfirmed") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("ValidFromDate") + .HasColumnType("TEXT"); + + b.Property("ValidFromVersion") + .HasColumnType("TEXT"); + + b.Property("ValidToDate") + .HasColumnType("TEXT"); + + b.Property("ValidToVersion") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("BackendNotifications"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.BackendToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ExpiresAtUtc") + .HasColumnType("TEXT"); + + b.Property("RefreshToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("BackendTokens"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.CachedCarState", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CarId") + .HasColumnType("INTEGER"); + + b.Property("CarStateJson") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("LastUpdated") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("CachedCarStates"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.Car", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("BleApiBaseUrl") + .HasColumnType("TEXT"); + + b.Property("ChargeMode") + .HasColumnType("INTEGER"); + + b.Property("ChargeStartCalls") + .HasColumnType("TEXT"); + + b.Property("ChargeStopCalls") + .HasColumnType("TEXT"); + + b.Property("ChargerActualCurrent") + .HasColumnType("INTEGER"); + + b.Property("ChargerPhases") + .HasColumnType("INTEGER"); + + b.Property("ChargerPilotCurrent") + .HasColumnType("INTEGER"); + + b.Property("ChargerRequestedCurrent") + .HasColumnType("INTEGER"); + + b.Property("ChargerVoltage") + .HasColumnType("INTEGER"); + + b.Property("ChargingPriority") + .HasColumnType("INTEGER"); + + b.Property("ClimateOn") + .HasColumnType("INTEGER"); + + b.Property("IgnoreLatestTimeToReachSocDate") + .HasColumnType("INTEGER"); + + b.Property("IgnoreLatestTimeToReachSocDateOnWeekend") + .HasColumnType("INTEGER"); + + b.Property("IsAvailableInTeslaAccount") + .HasColumnType("INTEGER"); + + b.Property("LatestTimeToReachSoC") + .HasColumnType("TEXT"); + + b.Property("Latitude") + .HasColumnType("REAL"); + + b.Property("Longitude") + .HasColumnType("REAL"); + + b.Property("MaximumAmpere") + .HasColumnType("INTEGER"); + + b.Property("MinimumAmpere") + .HasColumnType("INTEGER"); + + b.Property("MinimumSoc") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("OtherCommandCalls") + .HasColumnType("TEXT"); + + b.Property("PluggedIn") + .HasColumnType("INTEGER"); + + b.Property("SetChargingAmpsCall") + .HasColumnType("TEXT"); + + b.Property("ShouldBeManaged") + .HasColumnType("INTEGER"); + + b.Property("SoC") + .HasColumnType("INTEGER"); + + b.Property("SocLimit") + .HasColumnType("INTEGER"); + + b.Property("State") + .HasColumnType("INTEGER"); + + b.Property("TeslaFleetApiState") + .HasColumnType("INTEGER"); + + b.Property("TeslaMateCarId") + .HasColumnType("INTEGER"); + + b.Property("UsableEnergy") + .HasColumnType("INTEGER"); + + b.Property("UseBle") + .HasColumnType("INTEGER"); + + b.Property("UseFleetTelemetry") + .HasColumnType("INTEGER"); + + b.Property("UseFleetTelemetryForLocationData") + .HasColumnType("INTEGER"); + + b.Property("VehicleCalls") + .HasColumnType("TEXT"); + + b.Property("VehicleCommandProtocolRequired") + .HasColumnType("INTEGER"); + + b.Property("VehicleDataCalls") + .HasColumnType("TEXT"); + + b.Property("Vin") + .HasColumnType("TEXT"); + + b.Property("WakeUpCalls") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("TeslaMateCarId") + .IsUnique(); + + b.HasIndex("Vin") + .IsUnique(); + + b.ToTable("Cars"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.CarValueLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("BooleanValue") + .HasColumnType("INTEGER"); + + b.Property("CarId") + .HasColumnType("INTEGER"); + + b.Property("DoubleValue") + .HasColumnType("REAL"); + + b.Property("IntValue") + .HasColumnType("INTEGER"); + + b.Property("InvalidValue") + .HasColumnType("INTEGER"); + + b.Property("Source") + .HasColumnType("INTEGER"); + + b.Property("StringValue") + .HasColumnType("TEXT"); + + b.Property("Timestamp") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UnknownValue") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CarId"); + + b.ToTable("CarValueLogs"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargePrice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AddSpotPriceToGridPrice") + .HasColumnType("INTEGER"); + + b.Property("EnergyProvider") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(6); + + b.Property("EnergyProviderConfiguration") + .HasColumnType("TEXT"); + + b.Property("GridPrice") + .HasColumnType("TEXT"); + + b.Property("SolarPrice") + .HasColumnType("TEXT"); + + b.Property("SpotPriceCorrectionFactor") + .HasColumnType("TEXT"); + + b.Property("ValidSince") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("ChargePrices"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChargerVoltage") + .HasColumnType("INTEGER"); + + b.Property("ChargingProcessId") + .HasColumnType("INTEGER"); + + b.Property("GridPower") + .HasColumnType("INTEGER"); + + b.Property("HomeBatteryPower") + .HasColumnType("INTEGER"); + + b.Property("SolarPower") + .HasColumnType("INTEGER"); + + b.Property("TimeStamp") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ChargingProcessId"); + + b.ToTable("ChargingDetails"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingProcess", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CarId") + .HasColumnType("INTEGER"); + + b.Property("Cost") + .HasColumnType("TEXT"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("OldHandledChargeId") + .HasColumnType("INTEGER"); + + b.Property("StartDate") + .HasColumnType("TEXT"); + + b.Property("UsedGridEnergyKwh") + .HasColumnType("TEXT"); + + b.Property("UsedHomeBatteryEnergyKwh") + .HasColumnType("TEXT"); + + b.Property("UsedSolarEnergyKwh") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CarId"); + + b.ToTable("ChargingProcesses"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.HandledCharge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AverageSpotPrice") + .HasColumnType("TEXT"); + + b.Property("CalculatedPrice") + .HasColumnType("TEXT"); + + b.Property("CarId") + .HasColumnType("INTEGER"); + + b.Property("ChargingProcessId") + .HasColumnType("INTEGER"); + + b.Property("UsedGridEnergy") + .HasColumnType("TEXT"); + + b.Property("UsedSolarEnergy") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("HandledCharges"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.LoggedError", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DismissedAt") + .HasColumnType("TEXT"); + + b.Property("EndTimeStamp") + .HasColumnType("TEXT"); + + b.Property("FurtherOccurrences") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Headline") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("IssueKey") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Message") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("MethodName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Source") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("StackTrace") + .HasColumnType("TEXT"); + + b.Property("StartTimeStamp") + .HasColumnType("TEXT"); + + b.Property("TelegramNotificationSent") + .HasColumnType("INTEGER"); + + b.Property("TelegramResolvedMessageSent") + .HasColumnType("INTEGER"); + + b.Property("Vin") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("LoggedErrors"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConnectDelayMilliseconds") + .HasColumnType("INTEGER"); + + b.Property("Endianess") + .HasColumnType("INTEGER"); + + b.Property("Host") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Port") + .HasColumnType("INTEGER"); + + b.Property("ReadTimeoutMilliseconds") + .HasColumnType("INTEGER"); + + b.Property("UnitIdentifier") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("ModbusConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusResultConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Address") + .HasColumnType("INTEGER"); + + b.Property("BitStartIndex") + .HasColumnType("INTEGER"); + + b.Property("CorrectionFactor") + .HasColumnType("TEXT"); + + b.Property("InvertedByModbusResultConfigurationId") + .HasColumnType("INTEGER"); + + b.Property("Length") + .HasColumnType("INTEGER"); + + b.Property("ModbusConfigurationId") + .HasColumnType("INTEGER"); + + b.Property("Operator") + .HasColumnType("INTEGER"); + + b.Property("RegisterType") + .HasColumnType("INTEGER"); + + b.Property("UsedFor") + .HasColumnType("INTEGER"); + + b.Property("ValueType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("InvertedByModbusResultConfigurationId"); + + b.HasIndex("ModbusConfigurationId"); + + b.ToTable("ModbusResultConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.MqttConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Host") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Password") + .HasColumnType("TEXT"); + + b.Property("Port") + .HasColumnType("INTEGER"); + + b.Property("Username") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("MqttConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.MqttResultConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CorrectionFactor") + .HasColumnType("TEXT"); + + b.Property("MqttConfigurationId") + .HasColumnType("INTEGER"); + + b.Property("NodePattern") + .HasColumnType("TEXT"); + + b.Property("NodePatternType") + .HasColumnType("INTEGER"); + + b.Property("Operator") + .HasColumnType("INTEGER"); + + b.Property("Topic") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UsedFor") + .HasColumnType("INTEGER"); + + b.Property("XmlAttributeHeaderName") + .HasColumnType("TEXT"); + + b.Property("XmlAttributeHeaderValue") + .HasColumnType("TEXT"); + + b.Property("XmlAttributeValueName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("MqttConfigurationId"); + + b.ToTable("MqttResultConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.PowerDistribution", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChargingPower") + .HasColumnType("INTEGER"); + + b.Property("GridProportion") + .HasColumnType("REAL"); + + b.Property("HandledChargeId") + .HasColumnType("INTEGER"); + + b.Property("PowerFromGrid") + .HasColumnType("INTEGER"); + + b.Property("TimeStamp") + .HasColumnType("TEXT"); + + b.Property("UsedWattHours") + .HasColumnType("REAL"); + + b.HasKey("Id"); + + b.HasIndex("HandledChargeId"); + + b.ToTable("PowerDistributions"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("HttpMethod") + .HasColumnType("INTEGER"); + + b.Property("NodePatternType") + .HasColumnType("INTEGER"); + + b.Property("Url") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("RestValueConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfigurationHeader", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("RestValueConfigurationId") + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RestValueConfigurationId", "Key") + .IsUnique(); + + b.ToTable("RestValueConfigurationHeaders"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueResultConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CorrectionFactor") + .HasColumnType("TEXT"); + + b.Property("NodePattern") + .HasColumnType("TEXT"); + + b.Property("Operator") + .HasColumnType("INTEGER"); + + b.Property("RestValueConfigurationId") + .HasColumnType("INTEGER"); + + b.Property("UsedFor") + .HasColumnType("INTEGER"); + + b.Property("XmlAttributeHeaderName") + .HasColumnType("TEXT"); + + b.Property("XmlAttributeHeaderValue") + .HasColumnType("TEXT"); + + b.Property("XmlAttributeValueName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RestValueConfigurationId"); + + b.ToTable("RestValueResultConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.SpotPrice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("Price") + .HasColumnType("TEXT"); + + b.Property("StartDate") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("SpotPrices"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.TscConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Key") + .IsUnique(); + + b.ToTable("TscConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.CarValueLog", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.Car", "Car") + .WithMany("CarValueLogs") + .HasForeignKey("CarId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Car"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingDetail", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingProcess", "ChargingProcess") + .WithMany("ChargingDetails") + .HasForeignKey("ChargingProcessId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChargingProcess"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingProcess", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.Car", "Car") + .WithMany("ChargingProcesses") + .HasForeignKey("CarId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Car"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusResultConfiguration", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusResultConfiguration", "InvertedByModbusResultConfiguration") + .WithMany() + .HasForeignKey("InvertedByModbusResultConfigurationId"); + + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusConfiguration", "ModbusConfiguration") + .WithMany("ModbusResultConfigurations") + .HasForeignKey("ModbusConfigurationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("InvertedByModbusResultConfiguration"); + + b.Navigation("ModbusConfiguration"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.MqttResultConfiguration", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.MqttConfiguration", "MqttConfiguration") + .WithMany("MqttResultConfigurations") + .HasForeignKey("MqttConfigurationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MqttConfiguration"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.PowerDistribution", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.HandledCharge", "HandledCharge") + .WithMany("PowerDistributions") + .HasForeignKey("HandledChargeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("HandledCharge"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfigurationHeader", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfiguration", "RestValueConfiguration") + .WithMany("Headers") + .HasForeignKey("RestValueConfigurationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("RestValueConfiguration"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueResultConfiguration", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfiguration", "RestValueConfiguration") + .WithMany("RestValueResultConfigurations") + .HasForeignKey("RestValueConfigurationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("RestValueConfiguration"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.Car", b => + { + b.Navigation("CarValueLogs"); + + b.Navigation("ChargingProcesses"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingProcess", b => + { + b.Navigation("ChargingDetails"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.HandledCharge", b => + { + b.Navigation("PowerDistributions"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusConfiguration", b => + { + b.Navigation("ModbusResultConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.MqttConfiguration", b => + { + b.Navigation("MqttResultConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfiguration", b => + { + b.Navigation("Headers"); + + b.Navigation("RestValueResultConfigurations"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/TeslaSolarCharger.Model/Migrations/20241230094540_RemoveCarRateLimits.cs b/TeslaSolarCharger.Model/Migrations/20241230094540_RemoveCarRateLimits.cs new file mode 100644 index 000000000..6e0e09b42 --- /dev/null +++ b/TeslaSolarCharger.Model/Migrations/20241230094540_RemoveCarRateLimits.cs @@ -0,0 +1,69 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace TeslaSolarCharger.Model.Migrations +{ + /// + public partial class RemoveCarRateLimits : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "ChargingCommandsRateLimitedUntil", + table: "Cars"); + + migrationBuilder.DropColumn( + name: "CommandsRateLimitedUntil", + table: "Cars"); + + migrationBuilder.DropColumn( + name: "VehicleDataRateLimitedUntil", + table: "Cars"); + + migrationBuilder.DropColumn( + name: "VehicleRateLimitedUntil", + table: "Cars"); + + migrationBuilder.DropColumn( + name: "WakeUpRateLimitedUntil", + table: "Cars"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "ChargingCommandsRateLimitedUntil", + table: "Cars", + type: "TEXT", + nullable: true); + + migrationBuilder.AddColumn( + name: "CommandsRateLimitedUntil", + table: "Cars", + type: "TEXT", + nullable: true); + + migrationBuilder.AddColumn( + name: "VehicleDataRateLimitedUntil", + table: "Cars", + type: "TEXT", + nullable: true); + + migrationBuilder.AddColumn( + name: "VehicleRateLimitedUntil", + table: "Cars", + type: "TEXT", + nullable: true); + + migrationBuilder.AddColumn( + name: "WakeUpRateLimitedUntil", + table: "Cars", + type: "TEXT", + nullable: true); + } + } +} diff --git a/TeslaSolarCharger.Model/Migrations/20250113011813_AddIsFleetTelemetryHardwareIncompatibleToCars.Designer.cs b/TeslaSolarCharger.Model/Migrations/20250113011813_AddIsFleetTelemetryHardwareIncompatibleToCars.Designer.cs new file mode 100644 index 000000000..cb0e0b1b6 --- /dev/null +++ b/TeslaSolarCharger.Model/Migrations/20250113011813_AddIsFleetTelemetryHardwareIncompatibleToCars.Designer.cs @@ -0,0 +1,904 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using TeslaSolarCharger.Model.EntityFramework; + +#nullable disable + +namespace TeslaSolarCharger.Model.Migrations +{ + [DbContext(typeof(TeslaSolarChargerContext))] + [Migration("20250113011813_AddIsFleetTelemetryHardwareIncompatibleToCars")] + partial class AddIsFleetTelemetryHardwareIncompatibleToCars + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.10"); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.BackendNotification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("BackendIssueId") + .HasColumnType("INTEGER"); + + b.Property("DetailText") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Headline") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("IsConfirmed") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("ValidFromDate") + .HasColumnType("TEXT"); + + b.Property("ValidFromVersion") + .HasColumnType("TEXT"); + + b.Property("ValidToDate") + .HasColumnType("TEXT"); + + b.Property("ValidToVersion") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("BackendNotifications"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.BackendToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ExpiresAtUtc") + .HasColumnType("TEXT"); + + b.Property("RefreshToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("BackendTokens"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.CachedCarState", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CarId") + .HasColumnType("INTEGER"); + + b.Property("CarStateJson") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("LastUpdated") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("CachedCarStates"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.Car", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("BleApiBaseUrl") + .HasColumnType("TEXT"); + + b.Property("ChargeMode") + .HasColumnType("INTEGER"); + + b.Property("ChargeStartCalls") + .HasColumnType("TEXT"); + + b.Property("ChargeStopCalls") + .HasColumnType("TEXT"); + + b.Property("ChargerActualCurrent") + .HasColumnType("INTEGER"); + + b.Property("ChargerPhases") + .HasColumnType("INTEGER"); + + b.Property("ChargerPilotCurrent") + .HasColumnType("INTEGER"); + + b.Property("ChargerRequestedCurrent") + .HasColumnType("INTEGER"); + + b.Property("ChargerVoltage") + .HasColumnType("INTEGER"); + + b.Property("ChargingPriority") + .HasColumnType("INTEGER"); + + b.Property("ClimateOn") + .HasColumnType("INTEGER"); + + b.Property("IgnoreLatestTimeToReachSocDate") + .HasColumnType("INTEGER"); + + b.Property("IgnoreLatestTimeToReachSocDateOnWeekend") + .HasColumnType("INTEGER"); + + b.Property("IsAvailableInTeslaAccount") + .HasColumnType("INTEGER"); + + b.Property("IsFleetTelemetryHardwareIncompatible") + .HasColumnType("INTEGER"); + + b.Property("LatestTimeToReachSoC") + .HasColumnType("TEXT"); + + b.Property("Latitude") + .HasColumnType("REAL"); + + b.Property("Longitude") + .HasColumnType("REAL"); + + b.Property("MaximumAmpere") + .HasColumnType("INTEGER"); + + b.Property("MinimumAmpere") + .HasColumnType("INTEGER"); + + b.Property("MinimumSoc") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("OtherCommandCalls") + .HasColumnType("TEXT"); + + b.Property("PluggedIn") + .HasColumnType("INTEGER"); + + b.Property("SetChargingAmpsCall") + .HasColumnType("TEXT"); + + b.Property("ShouldBeManaged") + .HasColumnType("INTEGER"); + + b.Property("SoC") + .HasColumnType("INTEGER"); + + b.Property("SocLimit") + .HasColumnType("INTEGER"); + + b.Property("State") + .HasColumnType("INTEGER"); + + b.Property("TeslaFleetApiState") + .HasColumnType("INTEGER"); + + b.Property("TeslaMateCarId") + .HasColumnType("INTEGER"); + + b.Property("UsableEnergy") + .HasColumnType("INTEGER"); + + b.Property("UseBle") + .HasColumnType("INTEGER"); + + b.Property("UseFleetTelemetry") + .HasColumnType("INTEGER"); + + b.Property("UseFleetTelemetryForLocationData") + .HasColumnType("INTEGER"); + + b.Property("VehicleCalls") + .HasColumnType("TEXT"); + + b.Property("VehicleCommandProtocolRequired") + .HasColumnType("INTEGER"); + + b.Property("VehicleDataCalls") + .HasColumnType("TEXT"); + + b.Property("Vin") + .HasColumnType("TEXT"); + + b.Property("WakeUpCalls") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("TeslaMateCarId") + .IsUnique(); + + b.HasIndex("Vin") + .IsUnique(); + + b.ToTable("Cars"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.CarValueLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("BooleanValue") + .HasColumnType("INTEGER"); + + b.Property("CarId") + .HasColumnType("INTEGER"); + + b.Property("DoubleValue") + .HasColumnType("REAL"); + + b.Property("IntValue") + .HasColumnType("INTEGER"); + + b.Property("InvalidValue") + .HasColumnType("INTEGER"); + + b.Property("Source") + .HasColumnType("INTEGER"); + + b.Property("StringValue") + .HasColumnType("TEXT"); + + b.Property("Timestamp") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UnknownValue") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CarId"); + + b.ToTable("CarValueLogs"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargePrice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AddSpotPriceToGridPrice") + .HasColumnType("INTEGER"); + + b.Property("EnergyProvider") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(6); + + b.Property("EnergyProviderConfiguration") + .HasColumnType("TEXT"); + + b.Property("GridPrice") + .HasColumnType("TEXT"); + + b.Property("SolarPrice") + .HasColumnType("TEXT"); + + b.Property("SpotPriceCorrectionFactor") + .HasColumnType("TEXT"); + + b.Property("ValidSince") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("ChargePrices"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChargerVoltage") + .HasColumnType("INTEGER"); + + b.Property("ChargingProcessId") + .HasColumnType("INTEGER"); + + b.Property("GridPower") + .HasColumnType("INTEGER"); + + b.Property("HomeBatteryPower") + .HasColumnType("INTEGER"); + + b.Property("SolarPower") + .HasColumnType("INTEGER"); + + b.Property("TimeStamp") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ChargingProcessId"); + + b.ToTable("ChargingDetails"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingProcess", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CarId") + .HasColumnType("INTEGER"); + + b.Property("Cost") + .HasColumnType("TEXT"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("OldHandledChargeId") + .HasColumnType("INTEGER"); + + b.Property("StartDate") + .HasColumnType("TEXT"); + + b.Property("UsedGridEnergyKwh") + .HasColumnType("TEXT"); + + b.Property("UsedHomeBatteryEnergyKwh") + .HasColumnType("TEXT"); + + b.Property("UsedSolarEnergyKwh") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CarId"); + + b.ToTable("ChargingProcesses"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.HandledCharge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AverageSpotPrice") + .HasColumnType("TEXT"); + + b.Property("CalculatedPrice") + .HasColumnType("TEXT"); + + b.Property("CarId") + .HasColumnType("INTEGER"); + + b.Property("ChargingProcessId") + .HasColumnType("INTEGER"); + + b.Property("UsedGridEnergy") + .HasColumnType("TEXT"); + + b.Property("UsedSolarEnergy") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("HandledCharges"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.LoggedError", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DismissedAt") + .HasColumnType("TEXT"); + + b.Property("EndTimeStamp") + .HasColumnType("TEXT"); + + b.Property("FurtherOccurrences") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Headline") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("IssueKey") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Message") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("MethodName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Source") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("StackTrace") + .HasColumnType("TEXT"); + + b.Property("StartTimeStamp") + .HasColumnType("TEXT"); + + b.Property("TelegramNotificationSent") + .HasColumnType("INTEGER"); + + b.Property("TelegramResolvedMessageSent") + .HasColumnType("INTEGER"); + + b.Property("Vin") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("LoggedErrors"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConnectDelayMilliseconds") + .HasColumnType("INTEGER"); + + b.Property("Endianess") + .HasColumnType("INTEGER"); + + b.Property("Host") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Port") + .HasColumnType("INTEGER"); + + b.Property("ReadTimeoutMilliseconds") + .HasColumnType("INTEGER"); + + b.Property("UnitIdentifier") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("ModbusConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusResultConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Address") + .HasColumnType("INTEGER"); + + b.Property("BitStartIndex") + .HasColumnType("INTEGER"); + + b.Property("CorrectionFactor") + .HasColumnType("TEXT"); + + b.Property("InvertedByModbusResultConfigurationId") + .HasColumnType("INTEGER"); + + b.Property("Length") + .HasColumnType("INTEGER"); + + b.Property("ModbusConfigurationId") + .HasColumnType("INTEGER"); + + b.Property("Operator") + .HasColumnType("INTEGER"); + + b.Property("RegisterType") + .HasColumnType("INTEGER"); + + b.Property("UsedFor") + .HasColumnType("INTEGER"); + + b.Property("ValueType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("InvertedByModbusResultConfigurationId"); + + b.HasIndex("ModbusConfigurationId"); + + b.ToTable("ModbusResultConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.MqttConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Host") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Password") + .HasColumnType("TEXT"); + + b.Property("Port") + .HasColumnType("INTEGER"); + + b.Property("Username") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("MqttConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.MqttResultConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CorrectionFactor") + .HasColumnType("TEXT"); + + b.Property("MqttConfigurationId") + .HasColumnType("INTEGER"); + + b.Property("NodePattern") + .HasColumnType("TEXT"); + + b.Property("NodePatternType") + .HasColumnType("INTEGER"); + + b.Property("Operator") + .HasColumnType("INTEGER"); + + b.Property("Topic") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UsedFor") + .HasColumnType("INTEGER"); + + b.Property("XmlAttributeHeaderName") + .HasColumnType("TEXT"); + + b.Property("XmlAttributeHeaderValue") + .HasColumnType("TEXT"); + + b.Property("XmlAttributeValueName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("MqttConfigurationId"); + + b.ToTable("MqttResultConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.PowerDistribution", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChargingPower") + .HasColumnType("INTEGER"); + + b.Property("GridProportion") + .HasColumnType("REAL"); + + b.Property("HandledChargeId") + .HasColumnType("INTEGER"); + + b.Property("PowerFromGrid") + .HasColumnType("INTEGER"); + + b.Property("TimeStamp") + .HasColumnType("TEXT"); + + b.Property("UsedWattHours") + .HasColumnType("REAL"); + + b.HasKey("Id"); + + b.HasIndex("HandledChargeId"); + + b.ToTable("PowerDistributions"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("HttpMethod") + .HasColumnType("INTEGER"); + + b.Property("NodePatternType") + .HasColumnType("INTEGER"); + + b.Property("Url") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("RestValueConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfigurationHeader", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("RestValueConfigurationId") + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RestValueConfigurationId", "Key") + .IsUnique(); + + b.ToTable("RestValueConfigurationHeaders"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueResultConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CorrectionFactor") + .HasColumnType("TEXT"); + + b.Property("NodePattern") + .HasColumnType("TEXT"); + + b.Property("Operator") + .HasColumnType("INTEGER"); + + b.Property("RestValueConfigurationId") + .HasColumnType("INTEGER"); + + b.Property("UsedFor") + .HasColumnType("INTEGER"); + + b.Property("XmlAttributeHeaderName") + .HasColumnType("TEXT"); + + b.Property("XmlAttributeHeaderValue") + .HasColumnType("TEXT"); + + b.Property("XmlAttributeValueName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RestValueConfigurationId"); + + b.ToTable("RestValueResultConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.SpotPrice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("Price") + .HasColumnType("TEXT"); + + b.Property("StartDate") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("SpotPrices"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.TscConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Key") + .IsUnique(); + + b.ToTable("TscConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.CarValueLog", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.Car", "Car") + .WithMany("CarValueLogs") + .HasForeignKey("CarId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Car"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingDetail", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingProcess", "ChargingProcess") + .WithMany("ChargingDetails") + .HasForeignKey("ChargingProcessId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChargingProcess"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingProcess", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.Car", "Car") + .WithMany("ChargingProcesses") + .HasForeignKey("CarId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Car"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusResultConfiguration", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusResultConfiguration", "InvertedByModbusResultConfiguration") + .WithMany() + .HasForeignKey("InvertedByModbusResultConfigurationId"); + + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusConfiguration", "ModbusConfiguration") + .WithMany("ModbusResultConfigurations") + .HasForeignKey("ModbusConfigurationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("InvertedByModbusResultConfiguration"); + + b.Navigation("ModbusConfiguration"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.MqttResultConfiguration", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.MqttConfiguration", "MqttConfiguration") + .WithMany("MqttResultConfigurations") + .HasForeignKey("MqttConfigurationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MqttConfiguration"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.PowerDistribution", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.HandledCharge", "HandledCharge") + .WithMany("PowerDistributions") + .HasForeignKey("HandledChargeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("HandledCharge"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfigurationHeader", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfiguration", "RestValueConfiguration") + .WithMany("Headers") + .HasForeignKey("RestValueConfigurationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("RestValueConfiguration"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueResultConfiguration", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfiguration", "RestValueConfiguration") + .WithMany("RestValueResultConfigurations") + .HasForeignKey("RestValueConfigurationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("RestValueConfiguration"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.Car", b => + { + b.Navigation("CarValueLogs"); + + b.Navigation("ChargingProcesses"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingProcess", b => + { + b.Navigation("ChargingDetails"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.HandledCharge", b => + { + b.Navigation("PowerDistributions"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusConfiguration", b => + { + b.Navigation("ModbusResultConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.MqttConfiguration", b => + { + b.Navigation("MqttResultConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfiguration", b => + { + b.Navigation("Headers"); + + b.Navigation("RestValueResultConfigurations"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/TeslaSolarCharger.Model/Migrations/20250113011813_AddIsFleetTelemetryHardwareIncompatibleToCars.cs b/TeslaSolarCharger.Model/Migrations/20250113011813_AddIsFleetTelemetryHardwareIncompatibleToCars.cs new file mode 100644 index 000000000..225f931f5 --- /dev/null +++ b/TeslaSolarCharger.Model/Migrations/20250113011813_AddIsFleetTelemetryHardwareIncompatibleToCars.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace TeslaSolarCharger.Model.Migrations +{ + /// + public partial class AddIsFleetTelemetryHardwareIncompatibleToCars : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "IsFleetTelemetryHardwareIncompatible", + table: "Cars", + type: "INTEGER", + nullable: false, + defaultValue: false); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "IsFleetTelemetryHardwareIncompatible", + table: "Cars"); + } + } +} diff --git a/TeslaSolarCharger.Model/Migrations/20250113013705_RenameIncludeAdditionalFleetTelemtryFields.Designer.cs b/TeslaSolarCharger.Model/Migrations/20250113013705_RenameIncludeAdditionalFleetTelemtryFields.Designer.cs new file mode 100644 index 000000000..ae50a3815 --- /dev/null +++ b/TeslaSolarCharger.Model/Migrations/20250113013705_RenameIncludeAdditionalFleetTelemtryFields.Designer.cs @@ -0,0 +1,904 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using TeslaSolarCharger.Model.EntityFramework; + +#nullable disable + +namespace TeslaSolarCharger.Model.Migrations +{ + [DbContext(typeof(TeslaSolarChargerContext))] + [Migration("20250113013705_RenameIncludeAdditionalFleetTelemtryFields")] + partial class RenameIncludeAdditionalFleetTelemtryFields + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.10"); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.BackendNotification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("BackendIssueId") + .HasColumnType("INTEGER"); + + b.Property("DetailText") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Headline") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("IsConfirmed") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("ValidFromDate") + .HasColumnType("TEXT"); + + b.Property("ValidFromVersion") + .HasColumnType("TEXT"); + + b.Property("ValidToDate") + .HasColumnType("TEXT"); + + b.Property("ValidToVersion") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("BackendNotifications"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.BackendToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ExpiresAtUtc") + .HasColumnType("TEXT"); + + b.Property("RefreshToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("BackendTokens"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.CachedCarState", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CarId") + .HasColumnType("INTEGER"); + + b.Property("CarStateJson") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("LastUpdated") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("CachedCarStates"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.Car", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("BleApiBaseUrl") + .HasColumnType("TEXT"); + + b.Property("ChargeMode") + .HasColumnType("INTEGER"); + + b.Property("ChargeStartCalls") + .HasColumnType("TEXT"); + + b.Property("ChargeStopCalls") + .HasColumnType("TEXT"); + + b.Property("ChargerActualCurrent") + .HasColumnType("INTEGER"); + + b.Property("ChargerPhases") + .HasColumnType("INTEGER"); + + b.Property("ChargerPilotCurrent") + .HasColumnType("INTEGER"); + + b.Property("ChargerRequestedCurrent") + .HasColumnType("INTEGER"); + + b.Property("ChargerVoltage") + .HasColumnType("INTEGER"); + + b.Property("ChargingPriority") + .HasColumnType("INTEGER"); + + b.Property("ClimateOn") + .HasColumnType("INTEGER"); + + b.Property("IgnoreLatestTimeToReachSocDate") + .HasColumnType("INTEGER"); + + b.Property("IgnoreLatestTimeToReachSocDateOnWeekend") + .HasColumnType("INTEGER"); + + b.Property("IncludeTrackingRelevantFields") + .HasColumnType("INTEGER"); + + b.Property("IsAvailableInTeslaAccount") + .HasColumnType("INTEGER"); + + b.Property("IsFleetTelemetryHardwareIncompatible") + .HasColumnType("INTEGER"); + + b.Property("LatestTimeToReachSoC") + .HasColumnType("TEXT"); + + b.Property("Latitude") + .HasColumnType("REAL"); + + b.Property("Longitude") + .HasColumnType("REAL"); + + b.Property("MaximumAmpere") + .HasColumnType("INTEGER"); + + b.Property("MinimumAmpere") + .HasColumnType("INTEGER"); + + b.Property("MinimumSoc") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("OtherCommandCalls") + .HasColumnType("TEXT"); + + b.Property("PluggedIn") + .HasColumnType("INTEGER"); + + b.Property("SetChargingAmpsCall") + .HasColumnType("TEXT"); + + b.Property("ShouldBeManaged") + .HasColumnType("INTEGER"); + + b.Property("SoC") + .HasColumnType("INTEGER"); + + b.Property("SocLimit") + .HasColumnType("INTEGER"); + + b.Property("State") + .HasColumnType("INTEGER"); + + b.Property("TeslaFleetApiState") + .HasColumnType("INTEGER"); + + b.Property("TeslaMateCarId") + .HasColumnType("INTEGER"); + + b.Property("UsableEnergy") + .HasColumnType("INTEGER"); + + b.Property("UseBle") + .HasColumnType("INTEGER"); + + b.Property("UseFleetTelemetry") + .HasColumnType("INTEGER"); + + b.Property("VehicleCalls") + .HasColumnType("TEXT"); + + b.Property("VehicleCommandProtocolRequired") + .HasColumnType("INTEGER"); + + b.Property("VehicleDataCalls") + .HasColumnType("TEXT"); + + b.Property("Vin") + .HasColumnType("TEXT"); + + b.Property("WakeUpCalls") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("TeslaMateCarId") + .IsUnique(); + + b.HasIndex("Vin") + .IsUnique(); + + b.ToTable("Cars"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.CarValueLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("BooleanValue") + .HasColumnType("INTEGER"); + + b.Property("CarId") + .HasColumnType("INTEGER"); + + b.Property("DoubleValue") + .HasColumnType("REAL"); + + b.Property("IntValue") + .HasColumnType("INTEGER"); + + b.Property("InvalidValue") + .HasColumnType("INTEGER"); + + b.Property("Source") + .HasColumnType("INTEGER"); + + b.Property("StringValue") + .HasColumnType("TEXT"); + + b.Property("Timestamp") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UnknownValue") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CarId"); + + b.ToTable("CarValueLogs"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargePrice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AddSpotPriceToGridPrice") + .HasColumnType("INTEGER"); + + b.Property("EnergyProvider") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(6); + + b.Property("EnergyProviderConfiguration") + .HasColumnType("TEXT"); + + b.Property("GridPrice") + .HasColumnType("TEXT"); + + b.Property("SolarPrice") + .HasColumnType("TEXT"); + + b.Property("SpotPriceCorrectionFactor") + .HasColumnType("TEXT"); + + b.Property("ValidSince") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("ChargePrices"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChargerVoltage") + .HasColumnType("INTEGER"); + + b.Property("ChargingProcessId") + .HasColumnType("INTEGER"); + + b.Property("GridPower") + .HasColumnType("INTEGER"); + + b.Property("HomeBatteryPower") + .HasColumnType("INTEGER"); + + b.Property("SolarPower") + .HasColumnType("INTEGER"); + + b.Property("TimeStamp") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ChargingProcessId"); + + b.ToTable("ChargingDetails"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingProcess", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CarId") + .HasColumnType("INTEGER"); + + b.Property("Cost") + .HasColumnType("TEXT"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("OldHandledChargeId") + .HasColumnType("INTEGER"); + + b.Property("StartDate") + .HasColumnType("TEXT"); + + b.Property("UsedGridEnergyKwh") + .HasColumnType("TEXT"); + + b.Property("UsedHomeBatteryEnergyKwh") + .HasColumnType("TEXT"); + + b.Property("UsedSolarEnergyKwh") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CarId"); + + b.ToTable("ChargingProcesses"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.HandledCharge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AverageSpotPrice") + .HasColumnType("TEXT"); + + b.Property("CalculatedPrice") + .HasColumnType("TEXT"); + + b.Property("CarId") + .HasColumnType("INTEGER"); + + b.Property("ChargingProcessId") + .HasColumnType("INTEGER"); + + b.Property("UsedGridEnergy") + .HasColumnType("TEXT"); + + b.Property("UsedSolarEnergy") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("HandledCharges"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.LoggedError", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DismissedAt") + .HasColumnType("TEXT"); + + b.Property("EndTimeStamp") + .HasColumnType("TEXT"); + + b.Property("FurtherOccurrences") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Headline") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("IssueKey") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Message") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("MethodName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Source") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("StackTrace") + .HasColumnType("TEXT"); + + b.Property("StartTimeStamp") + .HasColumnType("TEXT"); + + b.Property("TelegramNotificationSent") + .HasColumnType("INTEGER"); + + b.Property("TelegramResolvedMessageSent") + .HasColumnType("INTEGER"); + + b.Property("Vin") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("LoggedErrors"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConnectDelayMilliseconds") + .HasColumnType("INTEGER"); + + b.Property("Endianess") + .HasColumnType("INTEGER"); + + b.Property("Host") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Port") + .HasColumnType("INTEGER"); + + b.Property("ReadTimeoutMilliseconds") + .HasColumnType("INTEGER"); + + b.Property("UnitIdentifier") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("ModbusConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusResultConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Address") + .HasColumnType("INTEGER"); + + b.Property("BitStartIndex") + .HasColumnType("INTEGER"); + + b.Property("CorrectionFactor") + .HasColumnType("TEXT"); + + b.Property("InvertedByModbusResultConfigurationId") + .HasColumnType("INTEGER"); + + b.Property("Length") + .HasColumnType("INTEGER"); + + b.Property("ModbusConfigurationId") + .HasColumnType("INTEGER"); + + b.Property("Operator") + .HasColumnType("INTEGER"); + + b.Property("RegisterType") + .HasColumnType("INTEGER"); + + b.Property("UsedFor") + .HasColumnType("INTEGER"); + + b.Property("ValueType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("InvertedByModbusResultConfigurationId"); + + b.HasIndex("ModbusConfigurationId"); + + b.ToTable("ModbusResultConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.MqttConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Host") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Password") + .HasColumnType("TEXT"); + + b.Property("Port") + .HasColumnType("INTEGER"); + + b.Property("Username") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("MqttConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.MqttResultConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CorrectionFactor") + .HasColumnType("TEXT"); + + b.Property("MqttConfigurationId") + .HasColumnType("INTEGER"); + + b.Property("NodePattern") + .HasColumnType("TEXT"); + + b.Property("NodePatternType") + .HasColumnType("INTEGER"); + + b.Property("Operator") + .HasColumnType("INTEGER"); + + b.Property("Topic") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UsedFor") + .HasColumnType("INTEGER"); + + b.Property("XmlAttributeHeaderName") + .HasColumnType("TEXT"); + + b.Property("XmlAttributeHeaderValue") + .HasColumnType("TEXT"); + + b.Property("XmlAttributeValueName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("MqttConfigurationId"); + + b.ToTable("MqttResultConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.PowerDistribution", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChargingPower") + .HasColumnType("INTEGER"); + + b.Property("GridProportion") + .HasColumnType("REAL"); + + b.Property("HandledChargeId") + .HasColumnType("INTEGER"); + + b.Property("PowerFromGrid") + .HasColumnType("INTEGER"); + + b.Property("TimeStamp") + .HasColumnType("TEXT"); + + b.Property("UsedWattHours") + .HasColumnType("REAL"); + + b.HasKey("Id"); + + b.HasIndex("HandledChargeId"); + + b.ToTable("PowerDistributions"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("HttpMethod") + .HasColumnType("INTEGER"); + + b.Property("NodePatternType") + .HasColumnType("INTEGER"); + + b.Property("Url") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("RestValueConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfigurationHeader", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("RestValueConfigurationId") + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RestValueConfigurationId", "Key") + .IsUnique(); + + b.ToTable("RestValueConfigurationHeaders"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueResultConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CorrectionFactor") + .HasColumnType("TEXT"); + + b.Property("NodePattern") + .HasColumnType("TEXT"); + + b.Property("Operator") + .HasColumnType("INTEGER"); + + b.Property("RestValueConfigurationId") + .HasColumnType("INTEGER"); + + b.Property("UsedFor") + .HasColumnType("INTEGER"); + + b.Property("XmlAttributeHeaderName") + .HasColumnType("TEXT"); + + b.Property("XmlAttributeHeaderValue") + .HasColumnType("TEXT"); + + b.Property("XmlAttributeValueName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RestValueConfigurationId"); + + b.ToTable("RestValueResultConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.SpotPrice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("Price") + .HasColumnType("TEXT"); + + b.Property("StartDate") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("SpotPrices"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.TscConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Key") + .IsUnique(); + + b.ToTable("TscConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.CarValueLog", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.Car", "Car") + .WithMany("CarValueLogs") + .HasForeignKey("CarId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Car"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingDetail", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingProcess", "ChargingProcess") + .WithMany("ChargingDetails") + .HasForeignKey("ChargingProcessId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChargingProcess"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingProcess", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.Car", "Car") + .WithMany("ChargingProcesses") + .HasForeignKey("CarId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Car"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusResultConfiguration", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusResultConfiguration", "InvertedByModbusResultConfiguration") + .WithMany() + .HasForeignKey("InvertedByModbusResultConfigurationId"); + + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusConfiguration", "ModbusConfiguration") + .WithMany("ModbusResultConfigurations") + .HasForeignKey("ModbusConfigurationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("InvertedByModbusResultConfiguration"); + + b.Navigation("ModbusConfiguration"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.MqttResultConfiguration", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.MqttConfiguration", "MqttConfiguration") + .WithMany("MqttResultConfigurations") + .HasForeignKey("MqttConfigurationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MqttConfiguration"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.PowerDistribution", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.HandledCharge", "HandledCharge") + .WithMany("PowerDistributions") + .HasForeignKey("HandledChargeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("HandledCharge"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfigurationHeader", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfiguration", "RestValueConfiguration") + .WithMany("Headers") + .HasForeignKey("RestValueConfigurationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("RestValueConfiguration"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueResultConfiguration", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfiguration", "RestValueConfiguration") + .WithMany("RestValueResultConfigurations") + .HasForeignKey("RestValueConfigurationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("RestValueConfiguration"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.Car", b => + { + b.Navigation("CarValueLogs"); + + b.Navigation("ChargingProcesses"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingProcess", b => + { + b.Navigation("ChargingDetails"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.HandledCharge", b => + { + b.Navigation("PowerDistributions"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusConfiguration", b => + { + b.Navigation("ModbusResultConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.MqttConfiguration", b => + { + b.Navigation("MqttResultConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfiguration", b => + { + b.Navigation("Headers"); + + b.Navigation("RestValueResultConfigurations"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/TeslaSolarCharger.Model/Migrations/20250113013705_RenameIncludeAdditionalFleetTelemtryFields.cs b/TeslaSolarCharger.Model/Migrations/20250113013705_RenameIncludeAdditionalFleetTelemtryFields.cs new file mode 100644 index 000000000..8c2c46c0e --- /dev/null +++ b/TeslaSolarCharger.Model/Migrations/20250113013705_RenameIncludeAdditionalFleetTelemtryFields.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace TeslaSolarCharger.Model.Migrations +{ + /// + public partial class RenameIncludeAdditionalFleetTelemtryFields : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "UseFleetTelemetryForLocationData", + table: "Cars", + newName: "IncludeTrackingRelevantFields"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "IncludeTrackingRelevantFields", + table: "Cars", + newName: "UseFleetTelemetryForLocationData"); + } + } +} diff --git a/TeslaSolarCharger.Model/Migrations/20250113103656_UseCalueConverterForDateLists.Designer.cs b/TeslaSolarCharger.Model/Migrations/20250113103656_UseCalueConverterForDateLists.Designer.cs new file mode 100644 index 000000000..5e028fa29 --- /dev/null +++ b/TeslaSolarCharger.Model/Migrations/20250113103656_UseCalueConverterForDateLists.Designer.cs @@ -0,0 +1,911 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using TeslaSolarCharger.Model.EntityFramework; + +#nullable disable + +namespace TeslaSolarCharger.Model.Migrations +{ + [DbContext(typeof(TeslaSolarChargerContext))] + [Migration("20250113103656_UseCalueConverterForDateLists")] + partial class UseCalueConverterForDateLists + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.10"); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.BackendNotification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("BackendIssueId") + .HasColumnType("INTEGER"); + + b.Property("DetailText") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Headline") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("IsConfirmed") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("ValidFromDate") + .HasColumnType("TEXT"); + + b.Property("ValidFromVersion") + .HasColumnType("TEXT"); + + b.Property("ValidToDate") + .HasColumnType("TEXT"); + + b.Property("ValidToVersion") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("BackendNotifications"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.BackendToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ExpiresAtUtc") + .HasColumnType("TEXT"); + + b.Property("RefreshToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("BackendTokens"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.CachedCarState", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CarId") + .HasColumnType("INTEGER"); + + b.Property("CarStateJson") + .HasColumnType("TEXT"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("LastUpdated") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("CachedCarStates"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.Car", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("BleApiBaseUrl") + .HasColumnType("TEXT"); + + b.Property("ChargeMode") + .HasColumnType("INTEGER"); + + b.Property("ChargeStartCalls") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ChargeStopCalls") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ChargerActualCurrent") + .HasColumnType("INTEGER"); + + b.Property("ChargerPhases") + .HasColumnType("INTEGER"); + + b.Property("ChargerPilotCurrent") + .HasColumnType("INTEGER"); + + b.Property("ChargerRequestedCurrent") + .HasColumnType("INTEGER"); + + b.Property("ChargerVoltage") + .HasColumnType("INTEGER"); + + b.Property("ChargingPriority") + .HasColumnType("INTEGER"); + + b.Property("ClimateOn") + .HasColumnType("INTEGER"); + + b.Property("IgnoreLatestTimeToReachSocDate") + .HasColumnType("INTEGER"); + + b.Property("IgnoreLatestTimeToReachSocDateOnWeekend") + .HasColumnType("INTEGER"); + + b.Property("IncludeTrackingRelevantFields") + .HasColumnType("INTEGER"); + + b.Property("IsAvailableInTeslaAccount") + .HasColumnType("INTEGER"); + + b.Property("IsFleetTelemetryHardwareIncompatible") + .HasColumnType("INTEGER"); + + b.Property("LatestTimeToReachSoC") + .HasColumnType("TEXT"); + + b.Property("Latitude") + .HasColumnType("REAL"); + + b.Property("Longitude") + .HasColumnType("REAL"); + + b.Property("MaximumAmpere") + .HasColumnType("INTEGER"); + + b.Property("MinimumAmpere") + .HasColumnType("INTEGER"); + + b.Property("MinimumSoc") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("OtherCommandCalls") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PluggedIn") + .HasColumnType("INTEGER"); + + b.Property("SetChargingAmpsCall") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ShouldBeManaged") + .HasColumnType("INTEGER"); + + b.Property("SoC") + .HasColumnType("INTEGER"); + + b.Property("SocLimit") + .HasColumnType("INTEGER"); + + b.Property("State") + .HasColumnType("INTEGER"); + + b.Property("TeslaFleetApiState") + .HasColumnType("INTEGER"); + + b.Property("TeslaMateCarId") + .HasColumnType("INTEGER"); + + b.Property("UsableEnergy") + .HasColumnType("INTEGER"); + + b.Property("UseBle") + .HasColumnType("INTEGER"); + + b.Property("UseFleetTelemetry") + .HasColumnType("INTEGER"); + + b.Property("VehicleCalls") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("VehicleCommandProtocolRequired") + .HasColumnType("INTEGER"); + + b.Property("VehicleDataCalls") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Vin") + .HasColumnType("TEXT"); + + b.Property("WakeUpCalls") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("TeslaMateCarId") + .IsUnique(); + + b.HasIndex("Vin") + .IsUnique(); + + b.ToTable("Cars"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.CarValueLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("BooleanValue") + .HasColumnType("INTEGER"); + + b.Property("CarId") + .HasColumnType("INTEGER"); + + b.Property("DoubleValue") + .HasColumnType("REAL"); + + b.Property("IntValue") + .HasColumnType("INTEGER"); + + b.Property("InvalidValue") + .HasColumnType("INTEGER"); + + b.Property("Source") + .HasColumnType("INTEGER"); + + b.Property("StringValue") + .HasColumnType("TEXT"); + + b.Property("Timestamp") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UnknownValue") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CarId"); + + b.ToTable("CarValueLogs"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargePrice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AddSpotPriceToGridPrice") + .HasColumnType("INTEGER"); + + b.Property("EnergyProvider") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(6); + + b.Property("EnergyProviderConfiguration") + .HasColumnType("TEXT"); + + b.Property("GridPrice") + .HasColumnType("TEXT"); + + b.Property("SolarPrice") + .HasColumnType("TEXT"); + + b.Property("SpotPriceCorrectionFactor") + .HasColumnType("TEXT"); + + b.Property("ValidSince") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("ChargePrices"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChargerVoltage") + .HasColumnType("INTEGER"); + + b.Property("ChargingProcessId") + .HasColumnType("INTEGER"); + + b.Property("GridPower") + .HasColumnType("INTEGER"); + + b.Property("HomeBatteryPower") + .HasColumnType("INTEGER"); + + b.Property("SolarPower") + .HasColumnType("INTEGER"); + + b.Property("TimeStamp") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ChargingProcessId"); + + b.ToTable("ChargingDetails"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingProcess", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CarId") + .HasColumnType("INTEGER"); + + b.Property("Cost") + .HasColumnType("TEXT"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("OldHandledChargeId") + .HasColumnType("INTEGER"); + + b.Property("StartDate") + .HasColumnType("TEXT"); + + b.Property("UsedGridEnergyKwh") + .HasColumnType("TEXT"); + + b.Property("UsedHomeBatteryEnergyKwh") + .HasColumnType("TEXT"); + + b.Property("UsedSolarEnergyKwh") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CarId"); + + b.ToTable("ChargingProcesses"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.HandledCharge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AverageSpotPrice") + .HasColumnType("TEXT"); + + b.Property("CalculatedPrice") + .HasColumnType("TEXT"); + + b.Property("CarId") + .HasColumnType("INTEGER"); + + b.Property("ChargingProcessId") + .HasColumnType("INTEGER"); + + b.Property("UsedGridEnergy") + .HasColumnType("TEXT"); + + b.Property("UsedSolarEnergy") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("HandledCharges"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.LoggedError", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DismissedAt") + .HasColumnType("TEXT"); + + b.Property("EndTimeStamp") + .HasColumnType("TEXT"); + + b.Property("FurtherOccurrences") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Headline") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("IssueKey") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Message") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("MethodName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Source") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("StackTrace") + .HasColumnType("TEXT"); + + b.Property("StartTimeStamp") + .HasColumnType("TEXT"); + + b.Property("TelegramNotificationSent") + .HasColumnType("INTEGER"); + + b.Property("TelegramResolvedMessageSent") + .HasColumnType("INTEGER"); + + b.Property("Vin") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("LoggedErrors"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConnectDelayMilliseconds") + .HasColumnType("INTEGER"); + + b.Property("Endianess") + .HasColumnType("INTEGER"); + + b.Property("Host") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Port") + .HasColumnType("INTEGER"); + + b.Property("ReadTimeoutMilliseconds") + .HasColumnType("INTEGER"); + + b.Property("UnitIdentifier") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("ModbusConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusResultConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Address") + .HasColumnType("INTEGER"); + + b.Property("BitStartIndex") + .HasColumnType("INTEGER"); + + b.Property("CorrectionFactor") + .HasColumnType("TEXT"); + + b.Property("InvertedByModbusResultConfigurationId") + .HasColumnType("INTEGER"); + + b.Property("Length") + .HasColumnType("INTEGER"); + + b.Property("ModbusConfigurationId") + .HasColumnType("INTEGER"); + + b.Property("Operator") + .HasColumnType("INTEGER"); + + b.Property("RegisterType") + .HasColumnType("INTEGER"); + + b.Property("UsedFor") + .HasColumnType("INTEGER"); + + b.Property("ValueType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("InvertedByModbusResultConfigurationId"); + + b.HasIndex("ModbusConfigurationId"); + + b.ToTable("ModbusResultConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.MqttConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Host") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Password") + .HasColumnType("TEXT"); + + b.Property("Port") + .HasColumnType("INTEGER"); + + b.Property("Username") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("MqttConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.MqttResultConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CorrectionFactor") + .HasColumnType("TEXT"); + + b.Property("MqttConfigurationId") + .HasColumnType("INTEGER"); + + b.Property("NodePattern") + .HasColumnType("TEXT"); + + b.Property("NodePatternType") + .HasColumnType("INTEGER"); + + b.Property("Operator") + .HasColumnType("INTEGER"); + + b.Property("Topic") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UsedFor") + .HasColumnType("INTEGER"); + + b.Property("XmlAttributeHeaderName") + .HasColumnType("TEXT"); + + b.Property("XmlAttributeHeaderValue") + .HasColumnType("TEXT"); + + b.Property("XmlAttributeValueName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("MqttConfigurationId"); + + b.ToTable("MqttResultConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.PowerDistribution", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChargingPower") + .HasColumnType("INTEGER"); + + b.Property("GridProportion") + .HasColumnType("REAL"); + + b.Property("HandledChargeId") + .HasColumnType("INTEGER"); + + b.Property("PowerFromGrid") + .HasColumnType("INTEGER"); + + b.Property("TimeStamp") + .HasColumnType("TEXT"); + + b.Property("UsedWattHours") + .HasColumnType("REAL"); + + b.HasKey("Id"); + + b.HasIndex("HandledChargeId"); + + b.ToTable("PowerDistributions"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("HttpMethod") + .HasColumnType("INTEGER"); + + b.Property("NodePatternType") + .HasColumnType("INTEGER"); + + b.Property("Url") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("RestValueConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfigurationHeader", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("RestValueConfigurationId") + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RestValueConfigurationId", "Key") + .IsUnique(); + + b.ToTable("RestValueConfigurationHeaders"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueResultConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CorrectionFactor") + .HasColumnType("TEXT"); + + b.Property("NodePattern") + .HasColumnType("TEXT"); + + b.Property("Operator") + .HasColumnType("INTEGER"); + + b.Property("RestValueConfigurationId") + .HasColumnType("INTEGER"); + + b.Property("UsedFor") + .HasColumnType("INTEGER"); + + b.Property("XmlAttributeHeaderName") + .HasColumnType("TEXT"); + + b.Property("XmlAttributeHeaderValue") + .HasColumnType("TEXT"); + + b.Property("XmlAttributeValueName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RestValueConfigurationId"); + + b.ToTable("RestValueResultConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.SpotPrice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("EndDate") + .HasColumnType("TEXT"); + + b.Property("Price") + .HasColumnType("TEXT"); + + b.Property("StartDate") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("SpotPrices"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.TscConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Key") + .IsUnique(); + + b.ToTable("TscConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.CarValueLog", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.Car", "Car") + .WithMany("CarValueLogs") + .HasForeignKey("CarId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Car"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingDetail", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingProcess", "ChargingProcess") + .WithMany("ChargingDetails") + .HasForeignKey("ChargingProcessId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChargingProcess"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingProcess", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.Car", "Car") + .WithMany("ChargingProcesses") + .HasForeignKey("CarId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Car"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusResultConfiguration", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusResultConfiguration", "InvertedByModbusResultConfiguration") + .WithMany() + .HasForeignKey("InvertedByModbusResultConfigurationId"); + + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusConfiguration", "ModbusConfiguration") + .WithMany("ModbusResultConfigurations") + .HasForeignKey("ModbusConfigurationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("InvertedByModbusResultConfiguration"); + + b.Navigation("ModbusConfiguration"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.MqttResultConfiguration", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.MqttConfiguration", "MqttConfiguration") + .WithMany("MqttResultConfigurations") + .HasForeignKey("MqttConfigurationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MqttConfiguration"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.PowerDistribution", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.HandledCharge", "HandledCharge") + .WithMany("PowerDistributions") + .HasForeignKey("HandledChargeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("HandledCharge"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfigurationHeader", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfiguration", "RestValueConfiguration") + .WithMany("Headers") + .HasForeignKey("RestValueConfigurationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("RestValueConfiguration"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueResultConfiguration", b => + { + b.HasOne("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfiguration", "RestValueConfiguration") + .WithMany("RestValueResultConfigurations") + .HasForeignKey("RestValueConfigurationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("RestValueConfiguration"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.Car", b => + { + b.Navigation("CarValueLogs"); + + b.Navigation("ChargingProcesses"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ChargingProcess", b => + { + b.Navigation("ChargingDetails"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.HandledCharge", b => + { + b.Navigation("PowerDistributions"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.ModbusConfiguration", b => + { + b.Navigation("ModbusResultConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.MqttConfiguration", b => + { + b.Navigation("MqttResultConfigurations"); + }); + + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.RestValueConfiguration", b => + { + b.Navigation("Headers"); + + b.Navigation("RestValueResultConfigurations"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/TeslaSolarCharger.Model/Migrations/20250113103656_UseCalueConverterForDateLists.cs b/TeslaSolarCharger.Model/Migrations/20250113103656_UseCalueConverterForDateLists.cs new file mode 100644 index 000000000..7b287cb89 --- /dev/null +++ b/TeslaSolarCharger.Model/Migrations/20250113103656_UseCalueConverterForDateLists.cs @@ -0,0 +1,144 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace TeslaSolarCharger.Model.Migrations +{ + /// + public partial class UseCalueConverterForDateLists : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "WakeUpCalls", + table: "Cars", + type: "TEXT", + nullable: false, + defaultValue: "[]", + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "VehicleDataCalls", + table: "Cars", + type: "TEXT", + nullable: false, + defaultValue: "[]", + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "VehicleCalls", + table: "Cars", + type: "TEXT", + nullable: false, + defaultValue: "[]", + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "SetChargingAmpsCall", + table: "Cars", + type: "TEXT", + nullable: false, + defaultValue: "[]", + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "OtherCommandCalls", + table: "Cars", + type: "TEXT", + nullable: false, + defaultValue: "[]", + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "ChargeStopCalls", + table: "Cars", + type: "TEXT", + nullable: false, + defaultValue: "[]", + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "ChargeStartCalls", + table: "Cars", + type: "TEXT", + nullable: false, + defaultValue: "[]", + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "WakeUpCalls", + table: "Cars", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + + migrationBuilder.AlterColumn( + name: "VehicleDataCalls", + table: "Cars", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + + migrationBuilder.AlterColumn( + name: "VehicleCalls", + table: "Cars", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + + migrationBuilder.AlterColumn( + name: "SetChargingAmpsCall", + table: "Cars", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + + migrationBuilder.AlterColumn( + name: "OtherCommandCalls", + table: "Cars", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + + migrationBuilder.AlterColumn( + name: "ChargeStopCalls", + table: "Cars", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + + migrationBuilder.AlterColumn( + name: "ChargeStartCalls", + table: "Cars", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + } + } +} diff --git a/TeslaSolarCharger.Model/Migrations/TeslaSolarChargerContextModelSnapshot.cs b/TeslaSolarCharger.Model/Migrations/TeslaSolarChargerContextModelSnapshot.cs index e4f729503..08fee2e39 100644 --- a/TeslaSolarCharger.Model/Migrations/TeslaSolarChargerContextModelSnapshot.cs +++ b/TeslaSolarCharger.Model/Migrations/TeslaSolarChargerContextModelSnapshot.cs @@ -57,6 +57,28 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("BackendNotifications"); }); + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.BackendToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ExpiresAtUtc") + .HasColumnType("TEXT"); + + b.Property("RefreshToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("BackendTokens"); + }); + modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.CachedCarState", b => { b.Property("Id") @@ -94,9 +116,11 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("INTEGER"); b.Property("ChargeStartCalls") + .IsRequired() .HasColumnType("TEXT"); b.Property("ChargeStopCalls") + .IsRequired() .HasColumnType("TEXT"); b.Property("ChargerActualCurrent") @@ -114,27 +138,27 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("ChargerVoltage") .HasColumnType("INTEGER"); - b.Property("ChargingCommandsRateLimitedUntil") - .HasColumnType("TEXT"); - b.Property("ChargingPriority") .HasColumnType("INTEGER"); b.Property("ClimateOn") .HasColumnType("INTEGER"); - b.Property("CommandsRateLimitedUntil") - .HasColumnType("TEXT"); - b.Property("IgnoreLatestTimeToReachSocDate") .HasColumnType("INTEGER"); b.Property("IgnoreLatestTimeToReachSocDateOnWeekend") .HasColumnType("INTEGER"); + b.Property("IncludeTrackingRelevantFields") + .HasColumnType("INTEGER"); + b.Property("IsAvailableInTeslaAccount") .HasColumnType("INTEGER"); + b.Property("IsFleetTelemetryHardwareIncompatible") + .HasColumnType("INTEGER"); + b.Property("LatestTimeToReachSoC") .HasColumnType("TEXT"); @@ -157,12 +181,14 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("TEXT"); b.Property("OtherCommandCalls") + .IsRequired() .HasColumnType("TEXT"); b.Property("PluggedIn") .HasColumnType("INTEGER"); b.Property("SetChargingAmpsCall") + .IsRequired() .HasColumnType("TEXT"); b.Property("ShouldBeManaged") @@ -192,31 +218,22 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("UseFleetTelemetry") .HasColumnType("INTEGER"); - b.Property("UseFleetTelemetryForLocationData") - .HasColumnType("INTEGER"); - b.Property("VehicleCalls") + .IsRequired() .HasColumnType("TEXT"); b.Property("VehicleCommandProtocolRequired") .HasColumnType("INTEGER"); b.Property("VehicleDataCalls") - .HasColumnType("TEXT"); - - b.Property("VehicleDataRateLimitedUntil") - .HasColumnType("TEXT"); - - b.Property("VehicleRateLimitedUntil") + .IsRequired() .HasColumnType("TEXT"); b.Property("Vin") .HasColumnType("TEXT"); b.Property("WakeUpCalls") - .HasColumnType("TEXT"); - - b.Property("WakeUpRateLimitedUntil") + .IsRequired() .HasColumnType("TEXT"); b.HasKey("Id"); @@ -737,38 +754,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("SpotPrices"); }); - modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.TeslaToken", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("AccessToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("ExpiresAtUtc") - .HasColumnType("TEXT"); - - b.Property("IdToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("RefreshToken") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Region") - .HasColumnType("INTEGER"); - - b.Property("UnauthorizedCounter") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.ToTable("TeslaTokens"); - }); - modelBuilder.Entity("TeslaSolarCharger.Model.Entities.TeslaSolarCharger.TscConfiguration", b => { b.Property("Id") diff --git a/TeslaSolarCharger.Services/Services/Modbus/ModbusValueConfigurationService.cs b/TeslaSolarCharger.Services/Services/Modbus/ModbusValueConfigurationService.cs index 85d118496..d5a7b0614 100644 --- a/TeslaSolarCharger.Services/Services/Modbus/ModbusValueConfigurationService.cs +++ b/TeslaSolarCharger.Services/Services/Modbus/ModbusValueConfigurationService.cs @@ -6,27 +6,29 @@ using TeslaSolarCharger.Model.Entities.TeslaSolarCharger; using TeslaSolarCharger.Services.Services.Modbus.Contracts; using TeslaSolarCharger.Shared.Dtos.ModbusConfiguration; -using TeslaSolarCharger.SharedBackend.MappingExtensions; namespace TeslaSolarCharger.Services.Services.Modbus; public class ModbusValueConfigurationService ( ILogger logger, ITeslaSolarChargerContext context, - IMapperConfigurationFactory mapperConfigurationFactory, IModbusClientHandlingService modbusClientHandlingService) : IModbusValueConfigurationService { public async Task> GetModbusConfigurationByPredicate(Expression> predicate) { logger.LogTrace("{method}({predicate})", nameof(GetModbusConfigurationByPredicate), predicate); - var mapper = mapperConfigurationFactory.Create(cfg => - { - cfg.CreateMap() - ; - }); var resultConfigurations = await context.ModbusConfigurations .Where(predicate) - .ProjectTo(mapper) + .Select(c => new DtoModbusConfiguration() + { + Id = c.Id, + UnitIdentifier = c.UnitIdentifier, + Host = c.Host, + Port = c.Port, + Endianess = c.Endianess, + ConnectDelayMilliseconds = c.ConnectDelayMilliseconds, + ReadTimeoutMilliseconds = c.ReadTimeoutMilliseconds + }) .ToListAsync().ConfigureAwait(false); return resultConfigurations; } @@ -42,14 +44,21 @@ public async Task> GetModbusResultConfig Expression> predicate) { logger.LogTrace("{method}({predicate})", nameof(GetModbusResultConfigurationsByPredicate), predicate); - var mapper = mapperConfigurationFactory.Create(cfg => - { - cfg.CreateMap() - ; - }); var resultConfigurations = await context.ModbusResultConfigurations .Where(predicate) - .ProjectTo(mapper) + .Select(e => new DtoModbusValueResultConfiguration() + { + Id = e.Id, + CorrectionFactor = e.CorrectionFactor, + UsedFor = e.UsedFor, + Operator = e.Operator, + RegisterType = e.RegisterType, + ValueType = e.ValueType, + Address = e.Address, + Length = e.Length, + BitStartIndex = e.BitStartIndex, + InvertedByModbusResultConfigurationId = e.InvertedByModbusResultConfigurationId, + }) .ToListAsync().ConfigureAwait(false); return resultConfigurations; } @@ -64,14 +73,20 @@ public async Task> GetResultConfiguratio public async Task SaveModbusResultConfiguration(int parentId, DtoModbusValueResultConfiguration dtoData) { logger.LogTrace("{method}({parentId}, {@dtoData})", nameof(SaveModbusResultConfiguration), parentId, dtoData); - var mapperConfiguration = mapperConfigurationFactory.Create(cfg => + var dbData = new ModbusResultConfiguration() { - cfg.CreateMap() - ; - }); - - var mapper = mapperConfiguration.CreateMapper(); - var dbData = mapper.Map(dtoData); + Id = dtoData.Id, + CorrectionFactor = dtoData.CorrectionFactor, + UsedFor = dtoData.UsedFor, + Operator = dtoData.Operator, + RegisterType = dtoData.RegisterType, + ValueType = dtoData.ValueType, + Address = dtoData.Address, + Length = dtoData.Length, + BitStartIndex = dtoData.BitStartIndex, + ModbusConfigurationId = parentId, + InvertedByModbusResultConfigurationId = dtoData.InvertedByModbusResultConfigurationId, + }; dbData.ModbusConfigurationId = parentId; var trackedData = context.ChangeTracker.Entries() .FirstOrDefault(e => e.Entity.Id == dbData.Id); @@ -116,11 +131,6 @@ public async Task DeleteResultConfiguration(int id) public async Task SaveModbusConfiguration(DtoModbusConfiguration dtoData) { logger.LogTrace("{method}({@dtoData})", nameof(SaveModbusConfiguration), dtoData); - var mapperConfiguration = mapperConfigurationFactory.Create(cfg => - { - cfg.CreateMap() - ; - }); if (dtoData.Id != default) { modbusClientHandlingService.RemoveClient(dtoData.Host, dtoData.Port); @@ -130,8 +140,16 @@ public async Task SaveModbusConfiguration(DtoModbusConfiguration dtoData) modbusClientHandlingService.RemoveClient(hostPortCombination.Host, hostPortCombination.Port); } - var mapper = mapperConfiguration.CreateMapper(); - var dbData = mapper.Map(dtoData); + var dbData = new ModbusConfiguration() + { + Id = dtoData.Id, + UnitIdentifier = dtoData.UnitIdentifier ?? 0, + Host = dtoData.Host, + Port = dtoData.Port, + Endianess = dtoData.Endianess, + ConnectDelayMilliseconds = dtoData.ConnectDelayMilliseconds, + ReadTimeoutMilliseconds = dtoData.ReadTimeoutMilliseconds + }; if (dbData.Id == default) { context.ModbusConfigurations.Add(dbData); diff --git a/TeslaSolarCharger.Services/Services/Mqtt/MqttConfigurationService.cs b/TeslaSolarCharger.Services/Services/Mqtt/MqttConfigurationService.cs index 7a84640bc..fb15d3efe 100644 --- a/TeslaSolarCharger.Services/Services/Mqtt/MqttConfigurationService.cs +++ b/TeslaSolarCharger.Services/Services/Mqtt/MqttConfigurationService.cs @@ -9,26 +9,26 @@ using TeslaSolarCharger.Services.Services.Mqtt.Contracts; using TeslaSolarCharger.Shared.Dtos.ModbusConfiguration; using TeslaSolarCharger.Shared.Dtos.MqttConfiguration; -using TeslaSolarCharger.SharedBackend.MappingExtensions; namespace TeslaSolarCharger.Services.Services.Mqtt; public class MqttConfigurationService(ILogger logger, ITeslaSolarChargerContext context, - IMapperConfigurationFactory mapperConfigurationFactory, IMqttClientHandlingService mqttClientHandlingService) : IMqttConfigurationService { public async Task> GetMqttConfigurationsByPredicate(Expression> predicate) { logger.LogTrace("{method}({predicate})", nameof(GetMqttConfigurationsByPredicate), predicate); - var mapper = mapperConfigurationFactory.Create(cfg => - { - cfg.CreateMap() - ; - }); var resultConfigurations = await context.MqttConfigurations .Where(predicate) - .ProjectTo(mapper) + .Select(e => new DtoMqttConfiguration() + { + Id = e.Id, + Host = e.Host, + Port = e.Port, + Username = e.Username, + Password = e.Password, + }) .ToListAsync().ConfigureAwait(false); return resultConfigurations; } @@ -43,19 +43,20 @@ public async Task GetConfigurationById(int id) public async Task SaveConfiguration(DtoMqttConfiguration dtoData) { logger.LogTrace("{method}({@dtoData})", nameof(SaveConfiguration), dtoData); - var mapperConfiguration = mapperConfigurationFactory.Create(cfg => - { - cfg.CreateMap() - ; - }); if (dtoData.Id != default) { mqttClientHandlingService.RemoveClient(dtoData.Host, dtoData.Port, dtoData.Username); RemoveMqttClientsByConfigurationId(dtoData.Id); } - var mapper = mapperConfiguration.CreateMapper(); - var dbData = mapper.Map(dtoData); + var dbData = new MqttConfiguration() + { + Id = dtoData.Id, + Host = dtoData.Host, + Port = dtoData.Port, + Username = dtoData.Username, + Password = dtoData.Password, + }; if (dbData.Id == default) { context.MqttConfigurations.Add(dbData); @@ -85,14 +86,21 @@ public async Task DeleteConfiguration(int id) public async Task> GetMqttResultConfigurationsByPredicate(Expression> predicate) { logger.LogTrace("{method}({predicate})", nameof(GetMqttResultConfigurationsByPredicate), predicate); - var mapper = mapperConfigurationFactory.Create(cfg => - { - cfg.CreateMap() - ; - }); var resultConfigurations = await context.MqttResultConfigurations .Where(predicate) - .ProjectTo(mapper) + .Select(e => new DtoMqttResultConfiguration() + { + Id = e.Id, + CorrectionFactor = e.CorrectionFactor, + UsedFor = e.UsedFor, + Operator = e.Operator, + NodePattern = e.NodePattern, + XmlAttributeHeaderName = e.XmlAttributeHeaderName, + XmlAttributeHeaderValue = e.XmlAttributeHeaderValue, + XmlAttributeValueName = e.XmlAttributeValueName, + Topic = e.Topic, + NodePatternType = e.NodePatternType, + }) .ToListAsync().ConfigureAwait(false); return resultConfigurations; } @@ -107,14 +115,20 @@ public async Task> GetResultConfigurationsByPar public async Task SaveResultConfiguration(int parentId, DtoMqttResultConfiguration dtoData) { logger.LogTrace("{method}({@dtoData})", nameof(SaveResultConfiguration), dtoData); - var mapperConfiguration = mapperConfigurationFactory.Create(cfg => + var dbData = new MqttResultConfiguration { - cfg.CreateMap() - ; - }); - var mapper = mapperConfiguration.CreateMapper(); - var dbData = mapper.Map(dtoData); - dbData.MqttConfigurationId = parentId; + Id = dtoData.Id, + CorrectionFactor = dtoData.CorrectionFactor, + UsedFor = dtoData.UsedFor, + Operator = dtoData.Operator, + NodePattern = dtoData.NodePattern, + XmlAttributeHeaderName = dtoData.XmlAttributeHeaderName, + XmlAttributeHeaderValue = dtoData.XmlAttributeHeaderValue, + XmlAttributeValueName = dtoData.XmlAttributeValueName, + Topic = dtoData.Topic, + NodePatternType = dtoData.NodePatternType, + MqttConfigurationId = parentId, + }; if (dbData.Id == default) { context.MqttResultConfigurations.Add(dbData); diff --git a/TeslaSolarCharger.Services/Services/Rest/RestValueConfigurationService.cs b/TeslaSolarCharger.Services/Services/Rest/RestValueConfigurationService.cs index bd82b2cf8..487297161 100644 --- a/TeslaSolarCharger.Services/Services/Rest/RestValueConfigurationService.cs +++ b/TeslaSolarCharger.Services/Services/Rest/RestValueConfigurationService.cs @@ -6,26 +6,24 @@ using TeslaSolarCharger.Model.Entities.TeslaSolarCharger; using TeslaSolarCharger.Services.Services.Rest.Contracts; using TeslaSolarCharger.Shared.Dtos.RestValueConfiguration; -using TeslaSolarCharger.SharedBackend.MappingExtensions; namespace TeslaSolarCharger.Services.Services.Rest; public class RestValueConfigurationService( ILogger logger, - ITeslaSolarChargerContext context, - IMapperConfigurationFactory mapperConfigurationFactory) : IRestValueConfigurationService + ITeslaSolarChargerContext context) : IRestValueConfigurationService { public async Task> GetAllRestValueConfigurations() { logger.LogTrace("{method}()", nameof(GetAllRestValueConfigurations)); - var mapper = mapperConfigurationFactory.Create(cfg => - { - cfg.CreateMap() - ; - }); - var result = await context.RestValueConfigurations - .ProjectTo(mapper) + .Select(e => new DtoRestValueConfiguration() + { + Id = e.Id, + Url = e.Url, + NodePatternType = e.NodePatternType, + HttpMethod = e.HttpMethod, + }) .ToListAsync().ConfigureAwait(false); return result; } @@ -34,16 +32,21 @@ public async Task> GetFullRestValueConfigura Expression> predicate) { logger.LogTrace("{method}({predicate})", nameof(GetFullRestValueConfigurationsByPredicate), predicate); - var mapper = mapperConfigurationFactory.Create(cfg => - { - cfg.CreateMap(); - cfg.CreateMap() - .ForMember(d => d.Headers, opt => opt.MapFrom(s => s.Headers)) - ; - }); var restValueConfigurations = await context.RestValueConfigurations .Where(predicate) - .ProjectTo(mapper) + .Select(c => new DtoFullRestValueConfiguration() + { + Id = c.Id, + Url = c.Url, + NodePatternType = c.NodePatternType, + HttpMethod = c.HttpMethod, + Headers = c.Headers.Select(h => new DtoRestValueConfigurationHeader() + { + Id = h.Id, + Key = h.Key, + Value = h.Value, + }).ToList(), + }) .ToListAsync().ConfigureAwait(false); return restValueConfigurations; } @@ -51,15 +54,19 @@ public async Task> GetFullRestValueConfigura public async Task> GetRestResultConfigurationByPredicate( Expression> predicate) { - - var mapper = mapperConfigurationFactory.Create(cfg => - { - cfg.CreateMap() - ; - }); var resultConfigurations = await context.RestValueResultConfigurations .Where(predicate) - .ProjectTo(mapper) + .Select(e => new DtoJsonXmlResultConfiguration() + { + Id = e.Id, + CorrectionFactor = e.CorrectionFactor, + UsedFor = e.UsedFor, + Operator = e.Operator, + NodePattern = e.NodePattern, + XmlAttributeHeaderName = e.XmlAttributeHeaderName, + XmlAttributeHeaderValue = e.XmlAttributeHeaderValue, + XmlAttributeValueName = e.XmlAttributeValueName, + }) .ToListAsync().ConfigureAwait(false); return resultConfigurations; } @@ -67,14 +74,10 @@ public async Task> GetRestResultConfiguratio public async Task SaveRestValueConfiguration(DtoFullRestValueConfiguration dtoData) { logger.LogTrace("{method}({@dtoData})", nameof(SaveRestValueConfiguration), dtoData); - var mapperConfiguration = mapperConfigurationFactory.Create(cfg => + var dbData = new RestValueConfiguration() { - cfg.CreateMap() - ; - }); - - var mapper = mapperConfiguration.CreateMapper(); - var dbData = mapper.Map(dtoData); + Id = dtoData.Id, Url = dtoData.Url, NodePatternType = dtoData.NodePatternType, HttpMethod = dtoData.HttpMethod, + }; if (dbData.Id == default) { context.RestValueConfigurations.Add(dbData); @@ -89,15 +92,9 @@ public async Task SaveRestValueConfiguration(DtoFullRestValueConfiguration context.RestValueConfigurationHeaders.RemoveRange(headersToRemove); context.RestValueConfigurations.Update(dbData); } - var headerMapperConfiguration = mapperConfigurationFactory.Create(cfg => - { - cfg.CreateMap() - ; - }); - var headerMapper = headerMapperConfiguration.CreateMapper(); foreach (var dtoHeader in dtoData.Headers) { - var dbHeader = headerMapper.Map(dtoHeader); + var dbHeader = new RestValueConfigurationHeader() { Id = dtoHeader.Id, Key = dtoHeader.Key, Value = dtoHeader.Value, }; if (dbData.Id == default) { dbData.Headers.Add(dbHeader); @@ -122,29 +119,27 @@ public async Task SaveRestValueConfiguration(DtoFullRestValueConfiguration public async Task> GetHeadersByConfigurationId(int parentId) { logger.LogTrace("{method}({parentId})", nameof(GetHeadersByConfigurationId), parentId); - var mapper = mapperConfigurationFactory.Create(cfg => - { - cfg.CreateMap() - ; - }); return await context.RestValueConfigurationHeaders .Where(x => x.RestValueConfigurationId == parentId) - .ProjectTo(mapper) + .Select(e => new DtoRestValueConfigurationHeader() + { + Id = e.Id, + Key = e.Key, + Value = e.Value, + }) .ToListAsync().ConfigureAwait(false); } public async Task SaveHeader(int parentId, DtoRestValueConfigurationHeader dtoData) { logger.LogTrace("{method}({@dtoData})", nameof(SaveHeader), dtoData); - var mapperConfiguration = mapperConfigurationFactory.Create(cfg => + var dbData = new RestValueConfigurationHeader { - cfg.CreateMap() - ; - }); - - var mapper = mapperConfiguration.CreateMapper(); - var dbData = mapper.Map(dtoData); - dbData.RestValueConfigurationId = parentId; + Id = dtoData.Id, + Key = dtoData.Key, + Value = dtoData.Value, + RestValueConfigurationId = parentId, + }; if (dbData.Id == default) { context.RestValueConfigurationHeaders.Add(dbData); @@ -167,29 +162,37 @@ public async Task DeleteHeader(int id) public async Task> GetResultConfigurationsByConfigurationId(int parentId) { logger.LogTrace("{method}({parentId})", nameof(GetResultConfigurationsByConfigurationId), parentId); - var mapper = mapperConfigurationFactory.Create(cfg => - { - cfg.CreateMap() - ; - }); return await context.RestValueResultConfigurations .Where(x => x.RestValueConfigurationId == parentId) - .ProjectTo(mapper) + .Select(e => new DtoJsonXmlResultConfiguration() + { + Id = e.Id, + CorrectionFactor = e.CorrectionFactor, + UsedFor = e.UsedFor, + Operator = e.Operator, + NodePattern = e.NodePattern, + XmlAttributeHeaderName = e.XmlAttributeHeaderName, + XmlAttributeHeaderValue = e.XmlAttributeHeaderValue, + XmlAttributeValueName = e.XmlAttributeValueName, + }) .ToListAsync().ConfigureAwait(false); } public async Task SaveResultConfiguration(int parentId, DtoJsonXmlResultConfiguration dtoData) { logger.LogTrace("{method}({@dtoData})", nameof(SaveResultConfiguration), dtoData); - var mapperConfiguration = mapperConfigurationFactory.Create(cfg => - { - cfg.CreateMap() - ; - }); - - var mapper = mapperConfiguration.CreateMapper(); - var dbData = mapper.Map(dtoData); - dbData.RestValueConfigurationId = parentId; + var dbData = new RestValueResultConfiguration + { + Id = dtoData.Id, + CorrectionFactor = dtoData.CorrectionFactor, + UsedFor = dtoData.UsedFor, + Operator = dtoData.Operator, + NodePattern = dtoData.NodePattern, + XmlAttributeHeaderName = dtoData.XmlAttributeHeaderName, + XmlAttributeHeaderValue = dtoData.XmlAttributeHeaderValue, + XmlAttributeValueName = dtoData.XmlAttributeValueName, + RestValueConfigurationId = parentId, + }; if (dbData.Id == default) { context.RestValueResultConfigurations.Add(dbData); diff --git a/TeslaSolarCharger.SharedBackend/MappingExtensions/MapperConfigurationFactory.cs b/TeslaSolarCharger.SharedBackend/MappingExtensions/MapperConfigurationFactory.cs deleted file mode 100644 index 61cadb474..000000000 --- a/TeslaSolarCharger.SharedBackend/MappingExtensions/MapperConfigurationFactory.cs +++ /dev/null @@ -1,29 +0,0 @@ -using AutoMapper; -using AutoMapper.Configuration.Annotations; -using System.Reflection; -using IConfigurationProvider = AutoMapper.IConfigurationProvider; - -namespace TeslaSolarCharger.SharedBackend.MappingExtensions; - -public class MapperConfigurationFactory : IMapperConfigurationFactory -{ - public IConfigurationProvider Create(Action configure) - { - return new MapperConfiguration(config => - { - config.ShouldMapProperty = p => p.GetCustomAttribute() == null; - configure(config); - }); - } - - public IConfigurationProvider CreateMap() - { - return new MapperConfiguration(config => config.CreateMap()); - } -} - -public interface IMapperConfigurationFactory -{ - IConfigurationProvider Create(Action configure); - IConfigurationProvider CreateMap(); -} diff --git a/TeslaSolarCharger.Tests/TestBase.cs b/TeslaSolarCharger.Tests/TestBase.cs index 4a5ca3b2e..03cb4d36a 100644 --- a/TeslaSolarCharger.Tests/TestBase.cs +++ b/TeslaSolarCharger.Tests/TestBase.cs @@ -20,7 +20,6 @@ using TeslaSolarCharger.Shared.Contracts; using TeslaSolarCharger.Shared.Resources.Contracts; using TeslaSolarCharger.Shared.TimeProviding; -using TeslaSolarCharger.SharedBackend.MappingExtensions; using TeslaSolarCharger.Tests.Data; using Xunit.Abstractions; using Constants = TeslaSolarCharger.Shared.Resources.Constants; @@ -67,7 +66,6 @@ protected TestBase( var currentFakeTime = new DateTime(2023, 2, 2, 8, 0, 0); _fake = new AutoFake(); - _fake.Provide(); _fake.Provide(); _fake.Provide(); _fake.Provide(); @@ -79,7 +77,6 @@ protected TestBase( b => { b.Register((_, _) => Context); - b.Register((_, _) => _fake.Resolve()); b.Register((_, _) => _fake.Resolve()); b.Register((_, _) => _fake.Resolve()); b.Register((_, _) => _fake.Resolve()); diff --git a/TeslaSolarCharger/Client/Components/BackendInformationDisplayComponent.razor b/TeslaSolarCharger/Client/Components/BackendInformationDisplayComponent.razor index 2b821fdfd..e4ccb8b52 100644 --- a/TeslaSolarCharger/Client/Components/BackendInformationDisplayComponent.razor +++ b/TeslaSolarCharger/Client/Components/BackendInformationDisplayComponent.razor @@ -1,5 +1,4 @@ @using TeslaSolarCharger.Shared.Dtos -@using TeslaSolarCharger.Shared.Dtos @using TeslaSolarCharger.Shared.Enums @inject HttpClient HttpClient diff --git a/TeslaSolarCharger/Client/Components/EditFormComponent.razor b/TeslaSolarCharger/Client/Components/EditFormComponent.razor index 59db6a23f..1d17a299e 100644 --- a/TeslaSolarCharger/Client/Components/EditFormComponent.razor +++ b/TeslaSolarCharger/Client/Components/EditFormComponent.razor @@ -1,21 +1,35 @@ -@using TeslaSolarCharger.Client.Wrapper +@using Blazored.FluentValidation +@using TeslaSolarCharger.Client.Helper.Contracts +@using TeslaSolarCharger.Client.Wrapper + +@inject IHttpClientHelper HttpClientHelper @typeparam T - - @ChildContent - - @if (!HideSubmitButton) - { - - Save - - } - - - - + + @ChildContent + + @if (!HideSubmitButton) + { + + + @if (IsSubmitting) + { + + Processing + } + else + { + Save + } + + + } + @code { @@ -26,16 +40,67 @@ public RenderFragment ChildContent { get; set; } [Parameter] public bool HideSubmitButton { get; set; } + [Parameter] + public string? SubmitUrl { get; set; } [Parameter] public EventCallback OnValidSubmit { get; set; } + [Parameter] + public EventCallback OnAfterSuccessfullSubmit { get; set; } + + public bool IsDirty => WrappedElement.EditContext.IsModified(); + + private bool IsSubmitting; + + - private void HandleValidSubmit(T wrappedItem) + private async Task HandleValidSubmit(T wrappedItem) { - OnValidSubmit.InvokeAsync(wrappedItem); + IsSubmitting = true; + if (SubmitUrl == default) + { + _ = OnValidSubmit.InvokeAsync(wrappedItem); + IsSubmitting = false; + return; + } + var result = await HttpClientHelper.SendPostRequestAsync(SubmitUrl, wrappedItem); + if (!result.HasError) + { + _ = OnAfterSuccessfullSubmit.InvokeAsync(wrappedItem); + IsSubmitting = false; + return; + } + + if (result.ValidationProblemDetails != null && result.ValidationProblemDetails.Errors.Any()) + { + MapErrorsToEditContext(result.ValidationProblemDetails.Errors); + } + else + { + Console.WriteLine("No validationErrors found in ProblemDetails.Extensions."); + } + IsSubmitting = false; + } + + private void MapErrorsToEditContext(IDictionary errors) + { + // Clear old messages + WrappedElement.MessageStore.Clear(); + + // Add new messages + foreach (var fieldWithErrors in errors) + { + var fieldIdentifier = new FieldIdentifier(WrappedElement.Item, fieldWithErrors.Key); + foreach (var errorMessage in fieldWithErrors.Value) + { + WrappedElement.MessageStore.Add(fieldIdentifier, errorMessage); + } + } + + // Force Blazor to re-render messages + WrappedElement.EditContext.NotifyValidationStateChanged(); } - public bool IsDirty => WrappedElement.EditContext.IsModified(); } diff --git a/TeslaSolarCharger/Client/Components/GenericInput.razor b/TeslaSolarCharger/Client/Components/GenericInput.razor index 918a42ac8..fc2acab5b 100644 --- a/TeslaSolarCharger/Client/Components/GenericInput.razor +++ b/TeslaSolarCharger/Client/Components/GenericInput.razor @@ -2,8 +2,8 @@ @using System.Reflection @using System.ComponentModel.DataAnnotations @using System.ComponentModel -@using Lysando.LabStorageV2.UiHelper.Wrapper.Contracts @using MudExtensions +@using TeslaSolarCharger.Client.Helper.Contracts @using TeslaSolarCharger.Shared.Attributes @using TeslaSolarCharger.Shared.Helper.Contracts @using TeslaSolarCharger.Shared.Resources.Contracts @@ -246,7 +246,6 @@ @bind-Value="Value" For="@(For)" Required="@IsRequired" - HelperText="Leave empty if you want to keep the existing password." InputType="InputType.Password" Label="@LabelName" Disabled="IsDisabled" diff --git a/TeslaSolarCharger/Client/Components/LoggedErrorsComponent.razor b/TeslaSolarCharger/Client/Components/LoggedErrorsComponent.razor index 61599e9f2..cd93f3005 100644 --- a/TeslaSolarCharger/Client/Components/LoggedErrorsComponent.razor +++ b/TeslaSolarCharger/Client/Components/LoggedErrorsComponent.razor @@ -19,7 +19,7 @@ else {
- +
diff --git a/TeslaSolarCharger/Client/Dialogs/AddCarDialog.razor b/TeslaSolarCharger/Client/Dialogs/AddCarDialog.razor index 40887c6f0..6429bfed2 100644 --- a/TeslaSolarCharger/Client/Dialogs/AddCarDialog.razor +++ b/TeslaSolarCharger/Client/Dialogs/AddCarDialog.razor @@ -9,7 +9,7 @@ { } -else if (_fleetApiTokenState != FleetApiTokenState.UpToDate) +else if (_fleetApiTokenState != TokenState.UpToDate) { >("api/FleetApi/FleetApiTokenState").ConfigureAwait(false); + var value = await HttpClient.GetFromJsonAsync>("api/FleetApi/FleetApiTokenState").ConfigureAwait(false); if (value != null) { _fleetApiTokenState = value.Value; diff --git a/TeslaSolarCharger/Client/Dtos/Result.cs b/TeslaSolarCharger/Client/Dtos/Result.cs new file mode 100644 index 000000000..58d2c0587 --- /dev/null +++ b/TeslaSolarCharger/Client/Dtos/Result.cs @@ -0,0 +1,9 @@ +using Microsoft.AspNetCore.Mvc; + +namespace TeslaSolarCharger.Client.Dtos; + +public record Result(T? Data, string? ErrorMessage, ValidationProblemDetails? ValidationProblemDetails) +{ + // Convenience property to check if it's an error + public bool HasError => !string.IsNullOrEmpty(ErrorMessage); +} diff --git a/TeslaSolarCharger/Client/Helper/Contracts/IDialogHelper.cs b/TeslaSolarCharger/Client/Helper/Contracts/IDialogHelper.cs index 62ab7f021..f3c1839b9 100644 --- a/TeslaSolarCharger/Client/Helper/Contracts/IDialogHelper.cs +++ b/TeslaSolarCharger/Client/Helper/Contracts/IDialogHelper.cs @@ -1,4 +1,6 @@ -namespace TeslaSolarCharger.Client.Helper.Contracts; +using MudBlazor; + +namespace TeslaSolarCharger.Client.Helper.Contracts; public interface IDialogHelper { diff --git a/TeslaSolarCharger/Client/Helper/Contracts/IHttpClientHelper.cs b/TeslaSolarCharger/Client/Helper/Contracts/IHttpClientHelper.cs index f7a6fb0c2..ffd112e25 100644 --- a/TeslaSolarCharger/Client/Helper/Contracts/IHttpClientHelper.cs +++ b/TeslaSolarCharger/Client/Helper/Contracts/IHttpClientHelper.cs @@ -1,9 +1,16 @@ -namespace TeslaSolarCharger.Client.Helper.Contracts; +using TeslaSolarCharger.Client.Dtos; +using TeslaSolarCharger.Shared.Dtos; + +namespace TeslaSolarCharger.Client.Helper.Contracts; public interface IHttpClientHelper { Task SendGetRequestWithSnackbarAsync(string url); Task SendGetRequestWithSnackbarAsync(string url); - Task SendPostRequestWithSnackbarAsync(string url, object content); - Task SendPostRequestWithSnackbarAsync(string url, object content); + Task SendPostRequestWithSnackbarAsync(string url, object? content); + Task SendPostRequestWithSnackbarAsync(string url, object? content); + Task> SendGetRequestAsync(string url); + Task> SendGetRequestAsync(string url); + Task> SendPostRequestAsync(string url, object? content); + Task> SendPostRequestAsync(string url, object? content); } diff --git a/TeslaSolarCharger/Client/Helper/Contracts/IJavaScriptWrapper.cs b/TeslaSolarCharger/Client/Helper/Contracts/IJavaScriptWrapper.cs index 047b7632c..b704d771e 100644 --- a/TeslaSolarCharger/Client/Helper/Contracts/IJavaScriptWrapper.cs +++ b/TeslaSolarCharger/Client/Helper/Contracts/IJavaScriptWrapper.cs @@ -1,4 +1,4 @@ -namespace Lysando.LabStorageV2.UiHelper.Wrapper.Contracts; +namespace TeslaSolarCharger.Client.Helper.Contracts; public interface IJavaScriptWrapper { @@ -6,4 +6,4 @@ public interface IJavaScriptWrapper Task RemoveFocusFromElementById(string elementId); Task OpenUrlInNewTab(string url); Task IsIosDevice(); -} \ No newline at end of file +} diff --git a/TeslaSolarCharger/Client/Helper/HttpClientHelper.cs b/TeslaSolarCharger/Client/Helper/HttpClientHelper.cs index ad3faa572..53256a80e 100644 --- a/TeslaSolarCharger/Client/Helper/HttpClientHelper.cs +++ b/TeslaSolarCharger/Client/Helper/HttpClientHelper.cs @@ -2,7 +2,9 @@ using MudBlazor; using Newtonsoft.Json; using System.Net.Http.Json; +using TeslaSolarCharger.Client.Dtos; using TeslaSolarCharger.Client.Helper.Contracts; +using TeslaSolarCharger.Shared.Dtos; namespace TeslaSolarCharger.Client.Helper; @@ -18,24 +20,83 @@ public async Task SendGetRequestWithSnackbarAsync(string url) await SendRequestWithSnackbarInternalAsync(HttpMethod.Get, url, null); } - public async Task SendPostRequestWithSnackbarAsync(string url, object content) + public async Task SendPostRequestWithSnackbarAsync(string url, object? content) { return await SendRequestWithSnackbarInternalAsync(HttpMethod.Post, url, content); } - public async Task SendPostRequestWithSnackbarAsync(string url, object content) + public async Task SendPostRequestWithSnackbarAsync(string url, object? content) { await SendRequestWithSnackbarInternalAsync(HttpMethod.Post, url, content); } + public async Task> SendGetRequestAsync(string url) + { + return await SendRequestCoreAsync(HttpMethod.Get, url, null); + } + + public async Task> SendGetRequestAsync(string url) + { + return await SendRequestCoreAsync(HttpMethod.Get, url, null); + } + + public async Task> SendPostRequestAsync(string url, object? content) + { + return await SendRequestCoreAsync(HttpMethod.Post, url, content); + } + + public async Task> SendPostRequestAsync(string url, object? content) + { + return await SendRequestCoreAsync(HttpMethod.Post, url, content); + } + private async Task SendRequestWithSnackbarInternalAsync( HttpMethod method, string url, object? content) + { + try + { + // Call the same core method + var result = await SendRequestCoreAsync(method, url, content); + + if (result.HasError) + { + // Show error in Snackbar + snackbar.Add(result.ErrorMessage ?? "EmptyErrorMessage", Severity.Error); + return default; + } + + // Return the deserialized data + return result.Data; + } + catch (Exception ex) + { + // If you need special catch logic that includes a Snackbar, do it here. + var message = $"{url}: Unexpected error: {ex.Message}"; + snackbar.Add(message, Severity.Error, config => + { + config.Action = "Details"; + config.ActionColor = Color.Primary; + config.Onclick = snackbar1 => dialogHelper.ShowTextDialog( + "Error Details", + $"Unexpected error while calling {url}: {ex.Message}{Environment.NewLine}{ex.StackTrace}" + ); + }); + + return default; + } + } + + private async Task> SendRequestCoreAsync( + HttpMethod method, + string url, + object? content) { try { HttpResponseMessage response; + if (method == HttpMethod.Get) { response = await httpClient.GetAsync(url); @@ -50,57 +111,64 @@ public async Task SendPostRequestWithSnackbarAsync(string url, object content) } else { - throw new ArgumentException("Unsupported HTTP method", nameof(method)); + return new Result( + default, + $"Unsupported HTTP method: {method}", + null + ); } if (response.IsSuccessStatusCode) { var responseContent = await response.Content.ReadAsStringAsync(); + if (typeof(T) != typeof(object)) { var deserializedObject = JsonConvert.DeserializeObject(responseContent); + if (deserializedObject == null) { - snackbar.Add($"{url}: The string could not be deserialized to the object type.", Severity.Error); + return new Result( + default, + $"{url}: Could not deserialize response to {typeof(T).Name}.", + null + ); } - return deserializedObject; - } - if (string.IsNullOrEmpty(responseContent)) + return new Result(deserializedObject, null, null); + } + else { - return default; + // If T=object, we don't do any deserialization + return new Result( + default, + null, + null + ); } - snackbar.Add($"{url}: The specified object type is not supported", Severity.Error); - return default; - } - else if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError) - { - var problemDetails = await response.Content.ReadFromJsonAsync(); - var message = problemDetails != null ? $"Error: {problemDetails.Detail}" : "An error occurred"; - snackbar.Add(message, Severity.Error); } else { - var message = $"{url}: Unexpected error: {response.StatusCode}"; - snackbar.Add(message, Severity.Error); + var resultString = await response.Content.ReadAsStringAsync(); + var problemDetails = JsonConvert.DeserializeObject(resultString); + var message = problemDetails != null + ? $"Error: {problemDetails.Detail}" + : "An error occurred on the server."; + + return new Result(default, message, problemDetails); } } catch (HttpRequestException ex) { + // Network-level error var message = $"{url}: Network error: {ex.Message}"; - snackbar.Add(message, Severity.Error); + return new Result(default, message, null); } catch (Exception ex) { + // Any other unexpected error var message = $"{url}: Unexpected error: {ex.Message}"; - snackbar.Add(message, Severity.Error, config => - { - config.Action = "Details"; - config.ActionColor = Color.Primary; - config.Onclick = snackbar1 => dialogHelper.ShowTextDialog("Error Details", - $"Unexpected error while calling {url}: {ex.Message}{Environment.NewLine}{ex.StackTrace}"); - }); + return new Result(default, message, null); } - return default; } } diff --git a/TeslaSolarCharger/Client/Helper/JavaScriptWrapper.cs b/TeslaSolarCharger/Client/Helper/JavaScriptWrapper.cs index 2cd6a7539..04cd3a251 100644 --- a/TeslaSolarCharger/Client/Helper/JavaScriptWrapper.cs +++ b/TeslaSolarCharger/Client/Helper/JavaScriptWrapper.cs @@ -1,5 +1,5 @@ -using Lysando.LabStorageV2.UiHelper.Wrapper.Contracts; -using Microsoft.JSInterop; +using Microsoft.JSInterop; +using TeslaSolarCharger.Client.Helper.Contracts; namespace Lysando.LabStorageV2.UiHelper.Wrapper; @@ -51,4 +51,4 @@ public async Task IsIosDevice() return false; } } -} \ No newline at end of file +} diff --git a/TeslaSolarCharger/Client/Pages/BaseConfiguration.razor b/TeslaSolarCharger/Client/Pages/BaseConfiguration.razor index 8e19fbd9c..fa4158cce 100644 --- a/TeslaSolarCharger/Client/Pages/BaseConfiguration.razor +++ b/TeslaSolarCharger/Client/Pages/BaseConfiguration.razor @@ -1,14 +1,16 @@ @page "/BaseConfiguration" @using System.Globalization @using TeslaSolarCharger.Client.Helper.Contracts +@using TeslaSolarCharger.Client.Services.Contracts @using TeslaSolarCharger.Shared.Dtos.BaseConfiguration -@using TeslaSolarCharger.Shared @using TeslaSolarCharger.Shared.Enums @using TeslaSolarCharger.Shared.Dtos @inject HttpClient HttpClient @inject NavigationManager NavigationManager @inject ISnackbar Snackbar @inject IHttpClientHelper HttpClientHelper +@inject IBackendApiTokenCheckService BackendApiTokenCheckService +@inject IDialogHelper DialogHelper Base Configuration @@ -24,245 +26,237 @@ else

General:

+ LabelText="Max combined current" + UnitText="A" + HelpText="Set a value if you want to reduce the max combined used current per phase of all cars. E.g. if you have two cars each set to max 16A but your installation can only handle 20A per phase you can set 20A here. So if one car uses 16A per phase the other car can only use 4A per phase. Note: Power is distributed based on the set car priorities.">
- @if (_fleetApiTokenState != FleetApiTokenState.NotNeeded) +

Tesla Fleet API:

+ @switch (_fleetApiTokenState) { -

Tesla Fleet API:

- @switch (_fleetApiTokenState) - { - case FleetApiTokenState.NotRequested: -
- You have to generate a token in order to use the Tesla Fleet API. Important: You have to allow access to all scopes. -
- break; - case FleetApiTokenState.NotReceived: -
- You already have requested a token but did not receive it yet. It can take up to five minutes to receive the token. If the token did not arrive within five minutes please try again: -
- break; - case FleetApiTokenState.TokenRequestExpired: -
- Your token request has expired. Please generate a new token: -
- break; - case FleetApiTokenState.TokenUnauthorized: -
- Your token is unauthorized, Please generate a new token, allow access to all scopes and enable mobile access in your car. -
- break; - case FleetApiTokenState.MissingScopes: -
- Your token has missing scopes. Remove Tesla Solar Charger from your third party apps as you won't get asked again for the scopes. After that generate a new token and allow access to all scopes. -
- break; - case FleetApiTokenState.Expired: -
- Your token has expired. This could happen if you changed your Tesla password or did not use TeslaSolarCharger for too long. Please generate a new token: -
- break; - case FleetApiTokenState.UpToDate: -
- Everything is fine! If you want to generate a new token e.g. to switch to another Tesla Account please click the button below: -
- break; - } -
- -
-
+ case TokenState.MissingPrecondition: +
+ You are not logged in in the Solar4car.com account. When requesting a new Tesla Token there will also be a request to log in to your Solar4car.com account. +
+ break; + case TokenState.NotAvailable: +
+ You did not request a Fleet API Token, yet. Request a new token, allow access to all scopes and enable mobile access in your car. +
+ break; + case TokenState.Unauthorized: +
+ Your token is unauthorized. Request a new token, allow access to all scopes and enable mobile access in your car. +
+ break; + case TokenState.MissingScopes: +
+ Your token has missing scopes. Request a new Token and allow all scopes (only required scopes are requested). +
+ break; + case TokenState.Expired: +
+ Your Fleet API token is expired. Request a new Token and allow all scopes (only required scopes are requested). +
+ break; + case TokenState.UpToDate: +
+ Everything is fine! If you want to generate a new token e.g. to switch to another Tesla Account please click the button below: +
+ break; } +
+ +
+

TeslaMate:

+ For="() => _dtoBaseConfiguration.UseTeslaMateIntegration" + OnValueChanged="_ => InvokeAsync(StateHasChanged)"> @if (_dtoBaseConfiguration.UseTeslaMateIntegration) { + LabelText="TeslaMate Database Host" + UnitText="" + HelpText=""> - + + LabelText="TeslaMate Database Server Port" + UnitText="" + HelpText="You can use the internal port of the TeslaMate database container"> - + + LabelText="TeslaMate Database Username" + UnitText="" + HelpText=""> + LabelText="TeslaMate Database Server Password" + UnitText="" + HelpText=""> + LabelText="Mosquito servername" + UnitText="" + HelpText=""> - + } - - + +

Home Geofence

+ Latitude="_dtoBaseConfiguration.HomeGeofenceLatitude" + Radius="_dtoBaseConfiguration.HomeGeofenceRadius" + LatitudeChanged="@(newLatitude => _dtoBaseConfiguration.HomeGeofenceLatitude = newLatitude)" + LongitudeChanged="@(newLongitude => { _dtoBaseConfiguration.HomeGeofenceLongitude = newLongitude; Snackbar.Add("To update the location, click the save button on the bottom of the page", Severity.Info); })"> Click on the map to select your home geofence. Within that area TSC will regulate the charging power.
+ LabelText="Home Radius" + UnitText="m" + HelpText="Increase or decrease the radius of the home geofence. Note: Values below 50m are note recommended"> + LabelText="Power Buffer" + UnitText="W" + HelpText="Set values higher than 0 to always have some overage (power to grid). Set values lower than 0 to always consume some power from the grid."> - + + LabelText="Home Battery Minimum SoC" + UnitText="%" + HelpText="Set the SoC your home battery should get charged to before cars start to use full power. Leave empty if you do not have a home battery"> + LabelText="Home Battery Goal charging power" + UnitText="W" + HelpText="Set the power your home battery should charge with as long as SoC is below set minimum SoC. Leave empty if you do not have a home battery"> + LabelText="Max Inverter AC Power" + UnitText="W" + HelpText="If you have a hybrid inverter that has more DC than AC power insert the maximum AC Power here. This is a very rare, so in most cases you can leave this field empty."> - + - +

Telegram:

How to set up Telegram
Note: The Telegram bot for now only sends messages if something is not working. E.g. The car does not respond to commands, solar power values can not be refreshed,...
+ For="() => _dtoBaseConfiguration.TelegramBotKey" + OnValueChanged="@(_ => _telegramSettingsChanged = true)"> + For="() => _dtoBaseConfiguration.TelegramChannelId" + OnValueChanged="@(_ => _telegramSettingsChanged = true)"> + IsDisabled="_telegramSettingsChanged" + DisableToolTipText="You need to save the configuration before testing it." + OnButtonClicked="_ => SendTelegramTestMessage()">
- + + LabelText="Car power adjustment interval" + UnitText="s" + HelpText="Note: It is not possible to use values below 25 seconds here, as there is a delay between the car changing its current and the Tesla API getting notified about this change."> - + + LabelText="Solar plant adjustment interval" + UnitText="s" + HelpText=""> - + + LabelText="Time with enough solar power until charging starts" + UnitText="min" + HelpText=""> - + + LabelText="Time without enough solar power until charging stops" + UnitText="min" + HelpText=""> -
+
+ LabelText="Mqqt ClientId" + UnitText="" + HelpText=""> - + -
+
+ LabelText="HomeBatteryPowerInversion Url" + UnitText="" + HelpText="Use this if you have to dynamically invert the home battery power. Note: Only 0 and 1 are allowed as response. As far as I know this is only needed with Sungrow Inverters."> - +
@@ -271,17 +265,17 @@ else
+ IsLoading="_submitLoading" + ButtonType="ButtonType.Submit">
- +
} @code { private DtoBaseConfiguration? _dtoBaseConfiguration; - private FleetApiTokenState? _fleetApiTokenState; + private TokenState? _fleetApiTokenState; private bool _tokenGenerationButtonDisabled; @@ -291,7 +285,7 @@ else protected override async Task OnInitializedAsync() { _dtoBaseConfiguration = await HttpClient.GetFromJsonAsync("/api/BaseConfiguration/GetBaseConfiguration").ConfigureAwait(false); - var value = await HttpClient.GetFromJsonAsync>("api/FleetApi/FleetApiTokenState").ConfigureAwait(false); + var value = await HttpClient.GetFromJsonAsync>("api/FleetApi/FleetApiTokenState").ConfigureAwait(false); if (value != null) { _fleetApiTokenState = value.Value; @@ -320,6 +314,14 @@ else _tokenGenerationButtonDisabled = true; var locale = CultureInfo.CurrentCulture.ToString(); var baseUrl = NavigationManager.BaseUri; + var backendTokenState = await BackendApiTokenCheckService.GetTokenState(false); + if (backendTokenState != TokenState.UpToDate) + { + Snackbar.Add("You need to be logged in to Solar4Car.com to generate a Fleet API Token", Severity.Error); + NavigationManager.NavigateTo("cloudconnection"); + return; + } + var url = await HttpClient.GetFromJsonAsync>($"api/FleetApi/GetOauthUrl?locale={Uri.EscapeDataString(locale)}&baseUrl={Uri.EscapeDataString(baseUrl)}").ConfigureAwait(false); if (url?.Value != null) { diff --git a/TeslaSolarCharger/Client/Pages/CarSettings.razor b/TeslaSolarCharger/Client/Pages/CarSettings.razor index 9228bcfb6..7ff83fe81 100644 --- a/TeslaSolarCharger/Client/Pages/CarSettings.razor +++ b/TeslaSolarCharger/Client/Pages/CarSettings.razor @@ -11,29 +11,20 @@

Car Settings

- @if (_fleetApiTokenState == FleetApiTokenState.NotReceived) - { - -

Waiting for token

- You already requested a token. TSC is currently waiting for receiving it. This might take up to five minutes. Reload this page to get new information if available. -
- } - else if (_fleetApiTokenState != null && _fleetApiTokenState != FleetApiTokenState.UpToDate) + @if (_fleetApiTokenState != null && _fleetApiTokenState != TokenState.UpToDate) { + NoIcon="true" + ContentAlignment="HorizontalAlignment.Left">

Create Token.

Go to Base Configuration, Generate a Tesla Fleet API Token and restart TSC to see cars here.
} - @if (_fleetApiTokenState == FleetApiTokenState.UpToDate) + @if (_fleetApiTokenState == TokenState.UpToDate) { + NoIcon="true" + ContentAlignment="HorizontalAlignment.Left">
Restart TSC to add new cars
If you do not see all cars here that are available in your Tesla account, restart TSC.
@@ -50,90 +41,104 @@ else @foreach (var carBasicConfiguration in _carBasicConfigurations) {
- - - - - - - - - - + + + - @if(carBasicConfiguration.UseFleetTelemetry) + For="() => carBasicConfiguration.Item.ShouldBeManaged" + OnValueChanged="_ => InvokeAsync(() => StateHasChanged())" /> + @if (carBasicConfiguration.Item.ShouldBeManaged) { - + + + + + + @if (carBasicConfiguration.Item.UseBle) + { + + } + + @if (carBasicConfiguration.Item.UseFleetTelemetry) + { + + } } + -
-

BLE Pairing and test

-
- To come around rate limits TSC can use BLE instead of the Fleet API. This requires setting up a BLE API. -
- @if (_pairingResults.TryGetValue(carBasicConfiguration.Vin, out var result)) + + @if (_vinsToShowBleTest.Contains(carBasicConfiguration.Item.Vin)) { +
+

BLE Pairing and test

+
+ To come around rate limits TSC can use BLE instead of the Fleet API. This requires setting up a BLE API. +
+ @if (_pairingResults.TryGetValue(carBasicConfiguration.Item.Vin, out var result)) + { + + - - @if (DateTime.UtcNow < car.RateLimitedUntil) - { - - } @if (_testingFleetApiCarIds.Any(i => i == car.CarId)) {
@@ -105,7 +93,7 @@ else

Note: For the test the car needs to be awake. If the car was not awake, wake it up and .
- If it still does not work, go to your car and under Controls -> Locks you can check if a key named "www.teslasolarcharger.de" is present. If not try adding the key again by clicking . + If it still does not work, go to your car and under Controls -> Locks you can check if a key named "solar4car.com" is present. If not try adding the key again by clicking .

@@ -605,7 +593,7 @@ else private async Task OpenRegisterPublicKeyPage(int carId) { var response = await HttpClient.PostAsync($"api/Index/UpdateCarFleetApiState?carId={carId}&fleetApiState={TeslaCarFleetApiState.OpenedLinkButNotTested}", null).ConfigureAwait(false); - NavigationManager.NavigateTo("https://tesla.com/_ak/www.teslasolarcharger.de"); + NavigationManager.NavigateTo("https://tesla.com/_ak/solar4car.com"); } private async Task TestFleetApiAccess(int carId) diff --git a/TeslaSolarCharger/Client/Program.cs b/TeslaSolarCharger/Client/Program.cs index 6c2f2bbcb..75bc6dac1 100644 --- a/TeslaSolarCharger/Client/Program.cs +++ b/TeslaSolarCharger/Client/Program.cs @@ -1,5 +1,4 @@ using Lysando.LabStorageV2.UiHelper.Wrapper; -using Lysando.LabStorageV2.UiHelper.Wrapper.Contracts; using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; using MudBlazor; @@ -8,6 +7,8 @@ using TeslaSolarCharger.Client; using TeslaSolarCharger.Client.Helper; using TeslaSolarCharger.Client.Helper.Contracts; +using TeslaSolarCharger.Client.Services; +using TeslaSolarCharger.Client.Services.Contracts; using TeslaSolarCharger.Shared; using TeslaSolarCharger.Shared.Contracts; using TeslaSolarCharger.Shared.Helper; @@ -25,6 +26,7 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddSingleton(); builder.Services.AddSharedDependencies(); builder.Services.AddMudServices(config => diff --git a/TeslaSolarCharger/Client/Services/BackendApiTokenCheckService.cs b/TeslaSolarCharger/Client/Services/BackendApiTokenCheckService.cs new file mode 100644 index 000000000..181deaa5c --- /dev/null +++ b/TeslaSolarCharger/Client/Services/BackendApiTokenCheckService.cs @@ -0,0 +1,15 @@ +using TeslaSolarCharger.Client.Helper.Contracts; +using TeslaSolarCharger.Client.Services.Contracts; +using TeslaSolarCharger.Shared.Dtos; +using TeslaSolarCharger.Shared.Enums; + +namespace TeslaSolarCharger.Client.Services; + +public class BackendApiTokenCheckService(ILogger logger, IHttpClientHelper httpClientHelper) : IBackendApiTokenCheckService +{ + public async Task GetTokenState(bool useCache) + { + var response = await httpClientHelper.SendGetRequestWithSnackbarAsync>($"api/BackendApi/GetTokenState?useCache={useCache}"); + return response?.Value ?? TokenState.MissingPrecondition; + } +} diff --git a/TeslaSolarCharger/Client/Services/Contracts/IBackendApiTokenCheckService.cs b/TeslaSolarCharger/Client/Services/Contracts/IBackendApiTokenCheckService.cs new file mode 100644 index 000000000..fa6835615 --- /dev/null +++ b/TeslaSolarCharger/Client/Services/Contracts/IBackendApiTokenCheckService.cs @@ -0,0 +1,8 @@ +using TeslaSolarCharger.Shared.Enums; + +namespace TeslaSolarCharger.Client.Services.Contracts; + +public interface IBackendApiTokenCheckService +{ + Task GetTokenState(bool useCache); +} diff --git a/TeslaSolarCharger/Client/Shared/NavMenu.razor b/TeslaSolarCharger/Client/Shared/NavMenu.razor index 7c9196e15..fc02cbdc9 100644 --- a/TeslaSolarCharger/Client/Shared/NavMenu.razor +++ b/TeslaSolarCharger/Client/Shared/NavMenu.razor @@ -26,6 +26,11 @@ Charge Prices
+