diff --git a/TeslaSolarCharger.Model/Entities/TeslaSolarCharger/CarValueLog.cs b/TeslaSolarCharger.Model/Entities/TeslaSolarCharger/CarValueLog.cs index 158b3cb94..fa13a7c7b 100644 --- a/TeslaSolarCharger.Model/Entities/TeslaSolarCharger/CarValueLog.cs +++ b/TeslaSolarCharger.Model/Entities/TeslaSolarCharger/CarValueLog.cs @@ -12,6 +12,8 @@ public class CarValueLog public int? IntValue { get; set; } public string? StringValue { get; set; } public string? UnknownValue { get; set; } + public bool? BooleanValue { get; set; } + public bool? InvalidValue { get; set; } public int CarId { get; set; } public Car Car { get; set; } diff --git a/TeslaSolarCharger.Model/Migrations/20241026131635_AddBoolAndInvalidValueToCarValueLog.Designer.cs b/TeslaSolarCharger.Model/Migrations/20241026131635_AddBoolAndInvalidValueToCarValueLog.Designer.cs new file mode 100644 index 000000000..9e2a10789 --- /dev/null +++ b/TeslaSolarCharger.Model/Migrations/20241026131635_AddBoolAndInvalidValueToCarValueLog.Designer.cs @@ -0,0 +1,928 @@ +// +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("20241026131635_AddBoolAndInvalidValueToCarValueLog")] + partial class AddBoolAndInvalidValueToCarValueLog + { + /// + 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.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("ApiRefreshIntervalSeconds") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(500); + + 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("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("UseBleForWakeUp") + .HasColumnType("INTEGER"); + + b.Property("UseFleetTelemetry") + .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("BoolValue") + .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.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") + .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/20241026131635_AddBoolAndInvalidValueToCarValueLog.cs b/TeslaSolarCharger.Model/Migrations/20241026131635_AddBoolAndInvalidValueToCarValueLog.cs new file mode 100644 index 000000000..de9fc7211 --- /dev/null +++ b/TeslaSolarCharger.Model/Migrations/20241026131635_AddBoolAndInvalidValueToCarValueLog.cs @@ -0,0 +1,38 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace TeslaSolarCharger.Model.Migrations +{ + /// + public partial class AddBoolAndInvalidValueToCarValueLog : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "BoolValue", + table: "CarValueLogs", + type: "INTEGER", + nullable: true); + + migrationBuilder.AddColumn( + name: "InvalidValue", + table: "CarValueLogs", + type: "INTEGER", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "BoolValue", + table: "CarValueLogs"); + + migrationBuilder.DropColumn( + name: "InvalidValue", + table: "CarValueLogs"); + } + } +} diff --git a/TeslaSolarCharger.Model/Migrations/20241026133046_RenameBoolValueToBooleanOnCarValueLog.Designer.cs b/TeslaSolarCharger.Model/Migrations/20241026133046_RenameBoolValueToBooleanOnCarValueLog.Designer.cs new file mode 100644 index 000000000..8e80d3bb2 --- /dev/null +++ b/TeslaSolarCharger.Model/Migrations/20241026133046_RenameBoolValueToBooleanOnCarValueLog.Designer.cs @@ -0,0 +1,928 @@ +// +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("20241026133046_RenameBoolValueToBooleanOnCarValueLog")] + partial class RenameBoolValueToBooleanOnCarValueLog + { + /// + 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.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("ApiRefreshIntervalSeconds") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(500); + + 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("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("UseBleForWakeUp") + .HasColumnType("INTEGER"); + + b.Property("UseFleetTelemetry") + .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.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") + .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/20241026133046_RenameBoolValueToBooleanOnCarValueLog.cs b/TeslaSolarCharger.Model/Migrations/20241026133046_RenameBoolValueToBooleanOnCarValueLog.cs new file mode 100644 index 000000000..60b57b59a --- /dev/null +++ b/TeslaSolarCharger.Model/Migrations/20241026133046_RenameBoolValueToBooleanOnCarValueLog.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace TeslaSolarCharger.Model.Migrations +{ + /// + public partial class RenameBoolValueToBooleanOnCarValueLog : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "BoolValue", + table: "CarValueLogs", + newName: "BooleanValue"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "BooleanValue", + table: "CarValueLogs", + newName: "BoolValue"); + } + } +} diff --git a/TeslaSolarCharger.Model/Migrations/TeslaSolarChargerContextModelSnapshot.cs b/TeslaSolarCharger.Model/Migrations/TeslaSolarChargerContextModelSnapshot.cs index 55359cab5..eb627ab22 100644 --- a/TeslaSolarCharger.Model/Migrations/TeslaSolarChargerContextModelSnapshot.cs +++ b/TeslaSolarCharger.Model/Migrations/TeslaSolarChargerContextModelSnapshot.cs @@ -238,6 +238,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); + b.Property("BooleanValue") + .HasColumnType("INTEGER"); + b.Property("CarId") .HasColumnType("INTEGER"); @@ -247,6 +250,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("IntValue") .HasColumnType("INTEGER"); + b.Property("InvalidValue") + .HasColumnType("INTEGER"); + b.Property("Source") .HasColumnType("INTEGER"); diff --git a/TeslaSolarCharger.Tests/Services/Server/FleetTelemetryWebSocketService.cs b/TeslaSolarCharger.Tests/Services/Server/FleetTelemetryWebSocketService.cs new file mode 100644 index 000000000..ffb13e434 --- /dev/null +++ b/TeslaSolarCharger.Tests/Services/Server/FleetTelemetryWebSocketService.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using System; +using TeslaSolarCharger.Shared.Dtos.ChargingCost.CostConfigurations; +using TeslaSolarCharger.Shared.Enums; +using Xunit.Abstractions; +using Xunit; + +namespace TeslaSolarCharger.Tests.Services.Server; + +public class FleetTelemetryWebSocketService : TestBase +{ + public FleetTelemetryWebSocketService(ITestOutputHelper outputHelper) + : base(outputHelper) + { + } + + [Fact] + public void CanDeserializeKnownEnumValues() + { + var message = "{\"Type\":1,\"DoubleValue\":15.0,\"IntValue\":null,\"StringValue\":null,\"UnknownValue\":null,\"TimeStamp\":\"2024-10-26T09:56:24.9895636+00:00\"}"; + var fleetTelemetryWebSocketService = Mock.Create(); + var result = fleetTelemetryWebSocketService.DeserializeFleetTelemetryMessage(message); + Assert.NotNull(result); + Assert.Equal(CarValueType.ModuleTempMax, result.Type); + } + + [Fact] + public void CanDeserializeUnKnownEnumValues() + { + var message = "{\"Type\":364,\"DoubleValue\":15.0,\"IntValue\":null,\"StringValue\":null,\"UnknownValue\":null,\"TimeStamp\":\"2024-10-26T09:56:24.9895636+00:00\"}"; + var fleetTelemetryWebSocketService = Mock.Create(); + var result = fleetTelemetryWebSocketService.DeserializeFleetTelemetryMessage(message); + Assert.NotNull(result); + Assert.Equal(CarValueType.Unknown, result.Type); + } +} diff --git a/TeslaSolarCharger/Server/Dtos/DtoTscFleetTelemetryMessage.cs b/TeslaSolarCharger/Server/Dtos/DtoTscFleetTelemetryMessage.cs index fd26440d0..95cc6d67e 100644 --- a/TeslaSolarCharger/Server/Dtos/DtoTscFleetTelemetryMessage.cs +++ b/TeslaSolarCharger/Server/Dtos/DtoTscFleetTelemetryMessage.cs @@ -9,5 +9,7 @@ public class DtoTscFleetTelemetryMessage public int? IntValue { get; set; } public string? StringValue { get; set; } public string? UnknownValue { get; set; } + public bool? BooleanValue { get; set; } + public bool? InvalidValue { get; set; } public DateTimeOffset TimeStamp { get; set; } } diff --git a/TeslaSolarCharger/Server/Helper/EnumDefaultConverter.cs b/TeslaSolarCharger/Server/Helper/EnumDefaultConverter.cs new file mode 100644 index 000000000..1194ccc2b --- /dev/null +++ b/TeslaSolarCharger/Server/Helper/EnumDefaultConverter.cs @@ -0,0 +1,35 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace TeslaSolarCharger.Server.Helper; + +public class EnumDefaultConverter(T defaultValue) : StringEnumConverter + where T : struct, Enum +{ + public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) + { + if (reader.Value == null) + { + return defaultValue; + } + + var valueString = reader.Value.ToString(); + + // Handle integer-based enums + if (int.TryParse(valueString, out var intValue)) + { + if (Enum.IsDefined(typeof(T), intValue)) + { + return (T)(object)intValue; + } + } + // Handle string-based enums + else if (Enum.TryParse(valueString, ignoreCase: true, out T parsedEnum)) + { + return parsedEnum; + } + + // Return the default value if the input doesn't match any known enum values + return defaultValue; + } +} diff --git a/TeslaSolarCharger/Server/Services/FleetTelemetryWebSocketService.cs b/TeslaSolarCharger/Server/Services/FleetTelemetryWebSocketService.cs index dc0229f1b..c7c542ddb 100644 --- a/TeslaSolarCharger/Server/Services/FleetTelemetryWebSocketService.cs +++ b/TeslaSolarCharger/Server/Services/FleetTelemetryWebSocketService.cs @@ -1,11 +1,13 @@ using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; +using Newtonsoft.Json.Converters; using System.Net.WebSockets; using System.Text; using System.Threading.Tasks.Sources; using TeslaSolarCharger.Model.Entities.TeslaSolarCharger; using TeslaSolarCharger.Model.EntityFramework; using TeslaSolarCharger.Server.Dtos; +using TeslaSolarCharger.Server.Helper; using TeslaSolarCharger.Server.Services.Contracts; using TeslaSolarCharger.Shared.Contracts; using TeslaSolarCharger.Shared.Enums; @@ -17,6 +19,7 @@ public class FleetTelemetryWebSocketService(ILogger Clients { get; set; } = new(); @@ -30,7 +33,6 @@ public async Task ReconnectWebSocketsForEnabledCars() .Select(c => c.Vin) .ToListAsync(); var bytesToSend = Encoding.UTF8.GetBytes("Heartbeat"); - var heartbeatsendTimeout = TimeSpan.FromSeconds(5); foreach (var vin in vins) { if (string.IsNullOrEmpty(vin)) @@ -46,7 +48,7 @@ public async Task ReconnectWebSocketsForEnabledCars() try { await existingClient.WebSocketClient.SendAsync(segment, WebSocketMessageType.Text, true, - new CancellationTokenSource(heartbeatsendTimeout).Token); + new CancellationTokenSource(_heartbeatsendTimeout).Token); } catch (Exception ex) { @@ -85,7 +87,7 @@ private async Task ConnectToFleetTelemetryApi(string vin) using var client = new ClientWebSocket(); try { - await client.ConnectAsync(new Uri(url), CancellationToken.None).ConfigureAwait(false); + await client.ConnectAsync(new Uri(url), new CancellationTokenSource(_heartbeatsendTimeout).Token).ConfigureAwait(false); var cancellation = new CancellationTokenSource(); var dtoClient = new DtoFleetTelemetryWebSocketClients { @@ -109,9 +111,9 @@ private async Task ConnectToFleetTelemetryApi(string vin) finally { Clients.Remove(dtoClient); - if (dtoClient.WebSocketClient.State == WebSocketState.Open) + if (dtoClient.WebSocketClient.State != WebSocketState.Closed && dtoClient.WebSocketClient.State != WebSocketState.Aborted) { - await client.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None).ConfigureAwait(false); + await client.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", new CancellationTokenSource(_heartbeatsendTimeout).Token).ConfigureAwait(false); } } } @@ -134,7 +136,7 @@ private async Task ReceiveMessages(ClientWebSocket webSocket, CancellationToken if (result.MessageType == WebSocketMessageType.Close) { // If the server closed the connection, close the WebSocket - await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", ctx); + await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, result.CloseStatusDescription, ctx); logger.LogInformation("WebSocket connection closed by server."); } else @@ -148,7 +150,7 @@ private async Task ReceiveMessages(ClientWebSocket webSocket, CancellationToken } logger.LogDebug("Received non heartbeat message {string}", jsonMessage); // Deserialize the JSON message into a C# object - var message = JsonConvert.DeserializeObject(jsonMessage); + var message = DeserializeFleetTelemetryMessage(jsonMessage); if (message != null) { logger.LogDebug("Saving fleet telemetry message"); @@ -162,6 +164,8 @@ private async Task ReceiveMessages(ClientWebSocket webSocket, CancellationToken IntValue = message.IntValue, StringValue = message.StringValue, UnknownValue = message.UnknownValue, + BooleanValue = message.BooleanValue, + InvalidValue = message.InvalidValue, Timestamp = message.TimeStamp.UtcDateTime, Source = CarValueSource.FleetTelemetry, }; @@ -176,4 +180,17 @@ private async Task ReceiveMessages(ClientWebSocket webSocket, CancellationToken } } } + + internal DtoTscFleetTelemetryMessage? DeserializeFleetTelemetryMessage(string jsonMessage) + { + var settings = new JsonSerializerSettings + { + Converters = new List + { + new EnumDefaultConverter(CarValueType.Unknown), + }, + }; + var message = JsonConvert.DeserializeObject(jsonMessage, settings); + return message; + } } diff --git a/TeslaSolarCharger/Shared/Enums/CarValueType.cs b/TeslaSolarCharger/Shared/Enums/CarValueType.cs index 611dc374f..74b1bd83c 100644 --- a/TeslaSolarCharger/Shared/Enums/CarValueType.cs +++ b/TeslaSolarCharger/Shared/Enums/CarValueType.cs @@ -9,4 +9,6 @@ public enum CarValueType ChargeAmps, ChargeCurrentRequest, ChargePortLatch, + DetailedChargeState, + Unknown = 9999, }