Replace pistache solar-server with .net solar api
This commit is contained in:
2
src/Solar.Api/.gitignore
vendored
Normal file
2
src/Solar.Api/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
bin/
|
||||
obj/
|
||||
6
src/Solar.Api/Constants/Format.cs
Normal file
6
src/Solar.Api/Constants/Format.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Solar.Api.Constants;
|
||||
|
||||
internal static class Format
|
||||
{
|
||||
public const string Date = "yyyy-MM-dd";
|
||||
}
|
||||
125
src/Solar.Api/Controllers/SolarLogController.cs
Normal file
125
src/Solar.Api/Controllers/SolarLogController.cs
Normal file
@@ -0,0 +1,125 @@
|
||||
using System.Net.Mime;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Solar.Api.Models;
|
||||
using Solar.Api.Services;
|
||||
using Swashbuckle.AspNetCore.Annotations;
|
||||
|
||||
namespace Solar.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Consumes(MediaTypeNames.Application.Json)]
|
||||
[Produces(MediaTypeNames.Application.Json)]
|
||||
public class SolarLogController : ControllerBase
|
||||
{
|
||||
private readonly SolarService solarService;
|
||||
private readonly ILogger<SolarLogController> logger;
|
||||
|
||||
public SolarLogController(
|
||||
SolarService solarService,
|
||||
ILogger<SolarLogController> logger)
|
||||
{
|
||||
this.solarService = solarService;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
[HttpGet()]
|
||||
[Route("/day")]
|
||||
public async Task<ActionResult<DayResponse>> GetDayDetails(
|
||||
[SwaggerParameter(Required = true)]
|
||||
[SwaggerSchema(Format = "date")]
|
||||
[FromQuery]
|
||||
string date)
|
||||
{
|
||||
var parsedDate = TryParseDate(date);
|
||||
if (!parsedDate.HasValue || parsedDate.Value.Year < 2000 || parsedDate.Value.Year > 3000)
|
||||
{
|
||||
logger.LogInformation("Invalid date {Date} requested", date);
|
||||
return BadRequest();
|
||||
}
|
||||
|
||||
return await solarService.GetDayDetails(parsedDate.Value);
|
||||
}
|
||||
|
||||
/// Parameter <parameter>to</parameter> is inclusive
|
||||
[HttpGet()]
|
||||
[Route("/days")]
|
||||
public async Task<ActionResult<DaysResponse>> GetDaySummaries(
|
||||
[SwaggerParameter(Required = true)]
|
||||
[SwaggerSchema(Format = "date")]
|
||||
[FromQuery]
|
||||
string start,
|
||||
[SwaggerParameter(Required = true)]
|
||||
[SwaggerSchema(Format = "date")]
|
||||
[FromQuery]
|
||||
string stop)
|
||||
{
|
||||
var parsedStartDate = TryParseDate(start);
|
||||
if (!parsedStartDate.HasValue || parsedStartDate.Value.Year < 2000 || parsedStartDate.Value.Year > 3000)
|
||||
{
|
||||
logger.LogInformation("Invalid start date {Date} requested", start);
|
||||
return BadRequest();
|
||||
}
|
||||
|
||||
var parsedStopDate = TryParseDate(stop);
|
||||
if (!parsedStopDate.HasValue || parsedStopDate.Value.Year < 2000 || parsedStopDate.Value.Year > 3000)
|
||||
{
|
||||
logger.LogInformation("Invalid stop date {Date} requested", stop);
|
||||
return BadRequest();
|
||||
}
|
||||
else if (parsedStopDate < parsedStartDate)
|
||||
{
|
||||
logger.LogInformation("Stop date {StopDate} must come before start date {StartDate} requested", stop, start);
|
||||
return BadRequest();
|
||||
}
|
||||
|
||||
return await solarService.GetDaySummaries(parsedStartDate.Value, parsedStopDate.Value);
|
||||
}
|
||||
|
||||
[HttpGet()]
|
||||
[Route("/months")]
|
||||
public async Task<ActionResult<MonthSummariesResponse>> GetMonthSummaries(
|
||||
[SwaggerParameter(Required = true)]
|
||||
[SwaggerSchema(Format = "yyyy-MM")]
|
||||
[FromQuery]
|
||||
string start,
|
||||
[SwaggerParameter(Required = true)]
|
||||
[SwaggerSchema(Format = "yyyy-MM")]
|
||||
[FromQuery]
|
||||
string stop)
|
||||
{
|
||||
var parsedStartDate = TryParseDate($"{start}-01");
|
||||
if (!parsedStartDate.HasValue || parsedStartDate.Value.Year < 2000 || parsedStartDate.Value.Year > 3000)
|
||||
{
|
||||
logger.LogInformation("Invalid start year month {YearMonth} requested", start);
|
||||
return BadRequest();
|
||||
}
|
||||
|
||||
var parsedStopDate = TryParseDate($"{stop}-01");
|
||||
if (!parsedStopDate.HasValue || parsedStopDate.Value.Year < 2000 || parsedStopDate.Value.Year > 3000)
|
||||
{
|
||||
logger.LogInformation("Invalid stop year month {YearMonth} requested", stop);
|
||||
return BadRequest();
|
||||
}
|
||||
else if (parsedStopDate < parsedStartDate)
|
||||
{
|
||||
logger.LogInformation("Stop year month {StopYearMonth} must come before start year month {StartYearMonth} requested", stop, start);
|
||||
return BadRequest();
|
||||
}
|
||||
|
||||
return await solarService.GetMonthSummaries(
|
||||
parsedStartDate.Value.Year,
|
||||
parsedStartDate.Value.Month,
|
||||
parsedStopDate.Value.Year,
|
||||
parsedStopDate.Value.Month);
|
||||
}
|
||||
|
||||
private static DateOnly? TryParseDate(string value)
|
||||
{
|
||||
if (DateOnly.TryParseExact(value, "yyyy-MM-dd", out var date))
|
||||
{
|
||||
return date;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
24
src/Solar.Api/Converters/DateOnlyConverter.cs
Normal file
24
src/Solar.Api/Converters/DateOnlyConverter.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Solar.Api.Converters;
|
||||
|
||||
public class DateOnlyConverter : JsonConverter<DateOnly>
|
||||
{
|
||||
private const string serializationFormat = "yyyy-MM-dd";
|
||||
|
||||
public override DateOnly Read(
|
||||
ref Utf8JsonReader reader,
|
||||
Type typeToConvert,
|
||||
JsonSerializerOptions options)
|
||||
{
|
||||
var value = reader.GetString();
|
||||
return DateOnly.ParseExact(value!, serializationFormat);
|
||||
}
|
||||
|
||||
public override void Write(
|
||||
Utf8JsonWriter writer,
|
||||
DateOnly value,
|
||||
JsonSerializerOptions options)
|
||||
=> writer.WriteStringValue(value.ToString(serializationFormat));
|
||||
}
|
||||
24
src/Solar.Api/Converters/TimeOnlyConverter.cs
Normal file
24
src/Solar.Api/Converters/TimeOnlyConverter.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Solar.Api.Converters;
|
||||
|
||||
public class TimeOnlyConverter : JsonConverter<TimeOnly>
|
||||
{
|
||||
private const string serializationFormat = "HH:mm";
|
||||
|
||||
public override TimeOnly Read(
|
||||
ref Utf8JsonReader reader,
|
||||
Type typeToConvert,
|
||||
JsonSerializerOptions options)
|
||||
{
|
||||
var value = reader.GetString();
|
||||
return TimeOnly.ParseExact(value!, serializationFormat);
|
||||
}
|
||||
|
||||
public override void Write(
|
||||
Utf8JsonWriter writer,
|
||||
TimeOnly value,
|
||||
JsonSerializerOptions options)
|
||||
=> writer.WriteStringValue(value.ToString(serializationFormat));
|
||||
}
|
||||
63
src/Solar.Api/DatabaseContext.cs
Normal file
63
src/Solar.Api/DatabaseContext.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Solar.Api.Entities;
|
||||
|
||||
namespace Solar.Api
|
||||
{
|
||||
public partial class DatabaseContext : DbContext
|
||||
{
|
||||
public DatabaseContext()
|
||||
{
|
||||
}
|
||||
|
||||
public DatabaseContext(DbContextOptions<DatabaseContext> options)
|
||||
: base(options)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual DbSet<EnvoyLog> EnvoyLogs { get; set; } = null!;
|
||||
public virtual DbSet<ZeverLog> ZeverLogs { get; set; } = null!;
|
||||
public virtual DbSet<ZeverSummary> ZeverSummaries { get; set; } = null!;
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.Entity<EnvoyLog>(entity =>
|
||||
{
|
||||
entity.HasIndex(e => e.Date, "idx_EnvoyLogs_Date");
|
||||
|
||||
entity.HasIndex(e => e.TimeUtc, "idx_EnvoyLogs_TimeUtc");
|
||||
|
||||
entity.HasIndex(e => e.TotalWatts, "idx_EnvoyLogs_TotalWatts");
|
||||
|
||||
entity.Property(e => e.TotalWatts).HasColumnType("BIGINT");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<ZeverLog>(entity =>
|
||||
{
|
||||
entity.HasIndex(e => e.Date, "idx_ZeverLogs_Date");
|
||||
|
||||
entity.HasIndex(e => e.TimeUtc, "idx_ZeverLogs_TimeUtc");
|
||||
|
||||
entity.HasIndex(e => e.TotalWatts, "idx_ZeverLogs_TotalWatts");
|
||||
|
||||
entity.Property(e => e.TotalWatts).HasColumnType("BIGINT");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<ZeverSummary>(entity =>
|
||||
{
|
||||
entity.ToTable("ZeverSummary");
|
||||
|
||||
entity.HasIndex(e => e.Date, "IX_ZeverSummary_Date")
|
||||
.IsUnique();
|
||||
|
||||
entity.HasIndex(e => e.Date, "idx_ZeverSummary_Date")
|
||||
.IsUnique();
|
||||
|
||||
entity.Property(e => e.TotalWatts).HasColumnType("BIGINT");
|
||||
});
|
||||
|
||||
OnModelCreatingPartial(modelBuilder);
|
||||
}
|
||||
|
||||
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
|
||||
}
|
||||
}
|
||||
12
src/Solar.Api/Entities/EnvoyLog.cs
Normal file
12
src/Solar.Api/Entities/EnvoyLog.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace Solar.Api.Entities
|
||||
{
|
||||
public partial class EnvoyLog
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public DateOnly Date { get; set; }
|
||||
public TimeOnly TimeUtc { get; set; }
|
||||
public long CurrentWatts { get; set; }
|
||||
public long TotalWatts { get; set; }
|
||||
public long Inverters { get; set; }
|
||||
}
|
||||
}
|
||||
11
src/Solar.Api/Entities/ZeverLog.cs
Normal file
11
src/Solar.Api/Entities/ZeverLog.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace Solar.Api.Entities
|
||||
{
|
||||
public partial class ZeverLog
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public DateOnly Date { get; set; }
|
||||
public TimeOnly TimeUtc { get; set; }
|
||||
public long CurrentWatts { get; set; }
|
||||
public long TotalWatts { get; set; }
|
||||
}
|
||||
}
|
||||
9
src/Solar.Api/Entities/ZeverSummary.cs
Normal file
9
src/Solar.Api/Entities/ZeverSummary.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Solar.Api.Entities
|
||||
{
|
||||
public partial class ZeverSummary
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public DateOnly Date { get; set; }
|
||||
public long TotalWatts { get; set; }
|
||||
}
|
||||
}
|
||||
4
src/Solar.Api/Models/DayResponse.cs
Normal file
4
src/Solar.Api/Models/DayResponse.cs
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
namespace Solar.Api.Models;
|
||||
|
||||
public record DayResponse(ZeverDayLog[] ZeverLogs, EnvoyDayLog[] EnvoyLogs);
|
||||
3
src/Solar.Api/Models/DaySummaryLog.cs
Normal file
3
src/Solar.Api/Models/DaySummaryLog.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
namespace Solar.Api.Models;
|
||||
|
||||
public record DaySummaryLog(DateOnly Date, int ZeverTotalWatts, int EnvoyTotalWatts);
|
||||
3
src/Solar.Api/Models/DaysResponse.cs
Normal file
3
src/Solar.Api/Models/DaysResponse.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
namespace Solar.Api.Models;
|
||||
|
||||
public record DaysResponse(DaySummaryLog[] DayLogs);
|
||||
3
src/Solar.Api/Models/EnvoyDayLog.cs
Normal file
3
src/Solar.Api/Models/EnvoyDayLog.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
namespace Solar.Api.Models;
|
||||
|
||||
public record EnvoyDayLog(TimeOnly TimeUtc, int CurrentWatts, int TotalWatts);
|
||||
3
src/Solar.Api/Models/MonthLog.cs
Normal file
3
src/Solar.Api/Models/MonthLog.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
namespace Solar.Api.Models;
|
||||
|
||||
public record MonthLog(int Year, int Month, int ZeverTotalWatts, int EnvoyTotalWatts);
|
||||
3
src/Solar.Api/Models/MonthSummariesResponse.cs
Normal file
3
src/Solar.Api/Models/MonthSummariesResponse.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
namespace Solar.Api.Models;
|
||||
|
||||
public record MonthSummariesResponse(MonthLog[] MonthLogs);
|
||||
3
src/Solar.Api/Models/ZeverDayLog.cs
Normal file
3
src/Solar.Api/Models/ZeverDayLog.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
namespace Solar.Api.Models;
|
||||
|
||||
public record ZeverDayLog(TimeOnly TimeUtc, int CurrentWatts, int TotalWatts);
|
||||
82
src/Solar.Api/Program.cs
Normal file
82
src/Solar.Api/Program.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using System.Text.Json;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Solar.Api.Converters;
|
||||
using Solar.Api.Services;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
|
||||
namespace Solar.Api;
|
||||
|
||||
public partial class Program
|
||||
{
|
||||
// TODO add launch parameters
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Services
|
||||
builder.Services.AddScoped<SolarService>();
|
||||
|
||||
// Database
|
||||
builder.Services.AddDbContext<DatabaseContext>(options =>
|
||||
{
|
||||
// TODO replace with launch argument
|
||||
options.UseSqlite("Data Source=/home/tijmen/project/home-data-collection-tools/samples/solarpaneloutput.db");
|
||||
});
|
||||
|
||||
// REST infrastructure
|
||||
builder.Services.AddCors(options =>
|
||||
{
|
||||
options.AddPolicy(
|
||||
name: "default",
|
||||
policy =>
|
||||
{
|
||||
policy.WithOrigins("http://localhost:8080");
|
||||
});
|
||||
});
|
||||
|
||||
builder.Services.AddControllers().AddJsonOptions(config =>
|
||||
{
|
||||
config.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
|
||||
config.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
|
||||
config.JsonSerializerOptions.Converters.Add(new DateOnlyConverter());
|
||||
config.JsonSerializerOptions.Converters.Add(new TimeOnlyConverter());
|
||||
});
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen(config =>
|
||||
{
|
||||
config.MapType<DateOnly>(() => new OpenApiSchema
|
||||
{
|
||||
Type = "string",
|
||||
Format = "date",
|
||||
Example = OpenApiAnyFactory.CreateFromJson("\"2022-12-31\"")
|
||||
});
|
||||
config.MapType<TimeOnly>(() => new OpenApiSchema
|
||||
{
|
||||
Type = "string",
|
||||
Format = "time",
|
||||
Example = OpenApiAnyFactory.CreateFromJson("\"13:45:42.0000000\"")
|
||||
});
|
||||
|
||||
config.SupportNonNullableReferenceTypes();
|
||||
config.EnableAnnotations();
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseHttpsRedirection();
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
app.UseCors("default");
|
||||
}
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
}
|
||||
}
|
||||
31
src/Solar.Api/Properties/launchSettings.json
Normal file
31
src/Solar.Api/Properties/launchSettings.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:16253",
|
||||
"sslPort": 44321
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"Solar.Api": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "https://localhost:7012;http://localhost:5199",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
151
src/Solar.Api/Services/SolarService.cs
Normal file
151
src/Solar.Api/Services/SolarService.cs
Normal file
@@ -0,0 +1,151 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Solar.Api.Entities;
|
||||
using Solar.Api.Models;
|
||||
|
||||
namespace Solar.Api.Services;
|
||||
|
||||
public class SolarService
|
||||
{
|
||||
private readonly DatabaseContext databaseContext;
|
||||
private readonly ILogger<SolarService> logger;
|
||||
|
||||
public SolarService(
|
||||
DatabaseContext databaseContext,
|
||||
ILogger<SolarService> logger)
|
||||
{
|
||||
this.databaseContext = databaseContext;
|
||||
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public async Task<DayResponse> GetDayDetails(DateOnly date)
|
||||
{
|
||||
var zeverRecords = await databaseContext
|
||||
.ZeverLogs
|
||||
.Where(zl => zl.Date == date)
|
||||
.OrderBy(zl => zl.TimeUtc)
|
||||
.ToArrayAsync();
|
||||
var envoyRecords = await databaseContext
|
||||
.EnvoyLogs
|
||||
.Where(er => er.Date == date)
|
||||
.OrderBy(er => er.TimeUtc)
|
||||
.ToArrayAsync();
|
||||
|
||||
NormalizeEnvoyLogs(envoyRecords);
|
||||
|
||||
return new DayResponse(
|
||||
zeverRecords
|
||||
.Select(zr => new ZeverDayLog(
|
||||
zr.TimeUtc,
|
||||
(int)zr.CurrentWatts,
|
||||
(int)zr.TotalWatts))
|
||||
.ToArray(),
|
||||
envoyRecords
|
||||
.Select(er => new EnvoyDayLog(
|
||||
er.TimeUtc,
|
||||
(int)er.CurrentWatts,
|
||||
(int)er.TotalWatts))
|
||||
.ToArray());
|
||||
}
|
||||
|
||||
public async Task<DaysResponse> GetDaySummaries(DateOnly start, DateOnly stop)
|
||||
{
|
||||
var zeverRecords = await databaseContext
|
||||
.ZeverSummaries
|
||||
.Where(zl => zl.Date >= start && zl.Date <= stop)
|
||||
.ToArrayAsync();
|
||||
|
||||
List<DaySummaryLog> logs = new();
|
||||
var current = start;
|
||||
do
|
||||
{
|
||||
var zeverResult = zeverRecords.FirstOrDefault(zr => zr.Date == current)?.TotalWatts ?? 0;
|
||||
var envoyResult = await GetEnvoyDayTotalWatts(current);
|
||||
|
||||
logs.Add(new DaySummaryLog(
|
||||
current,
|
||||
(int)zeverResult,
|
||||
envoyResult));
|
||||
|
||||
current = current.AddDays(1);
|
||||
} while (current <= stop);
|
||||
|
||||
return new DaysResponse(logs.ToArray());
|
||||
}
|
||||
|
||||
public async Task<MonthSummariesResponse> GetMonthSummaries(int fromYear, int fromMonth, int toYear, int toMonth)
|
||||
{
|
||||
var results = new List<MonthLog>();
|
||||
var current = (Year: fromYear, Month: fromMonth);
|
||||
do
|
||||
{
|
||||
var zeverResult = (int)await databaseContext.ZeverSummaries
|
||||
.Where(zs => zs.Date.Year == current.Year && zs.Date.Month == current.Month)
|
||||
.SumAsync(zs => zs.TotalWatts);
|
||||
var envoyYear = await GetEnvoyMonthTotalWatts(current.Year, current.Month);
|
||||
results.Add(new MonthLog(current.Year, current.Month, zeverResult, envoyYear));
|
||||
|
||||
if (current.Month == 12)
|
||||
{
|
||||
current = (current.Year + 1, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
current = (current.Year, current.Month + 1);
|
||||
}
|
||||
} while (current.Year < toYear || current.Month < toMonth);
|
||||
return new MonthSummariesResponse(results.ToArray());
|
||||
}
|
||||
|
||||
private async Task<int> GetEnvoyDayTotalWatts(DateOnly date)
|
||||
{
|
||||
var min = await databaseContext.EnvoyLogs
|
||||
.Where(el => el.Date == date)
|
||||
.OrderBy(el => el.TotalWatts)
|
||||
.FirstOrDefaultAsync();
|
||||
var max = await databaseContext.EnvoyLogs
|
||||
.Where(el => el.Date == date)
|
||||
.OrderByDescending(el => el.TotalWatts)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (min == null || max == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int)(max.TotalWatts - min.TotalWatts);
|
||||
}
|
||||
|
||||
private async Task<int> GetEnvoyMonthTotalWatts(int year, int month)
|
||||
{
|
||||
var min = await databaseContext.EnvoyLogs
|
||||
.Where(el => el.Date.Year == year && el.Date.Month == month)
|
||||
.OrderBy(el => el.TotalWatts)
|
||||
.FirstOrDefaultAsync();
|
||||
var max = await databaseContext.EnvoyLogs
|
||||
.Where(el => el.Date.Year == year && el.Date.Month == month)
|
||||
.OrderByDescending(el => el.TotalWatts)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (min == null || max == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int)(max.TotalWatts - min.TotalWatts);
|
||||
}
|
||||
|
||||
private static void NormalizeEnvoyLogs(EnvoyLog[] entities)
|
||||
{
|
||||
if (entities.Length < 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var baseValue = entities[0].TotalWatts;
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
entity.TotalWatts -= baseValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
19
src/Solar.Api/Solar.Api.csproj
Normal file
19
src/Solar.Api/Solar.Api.csproj
Normal file
@@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.9">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.9" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
8
src/Solar.Api/appsettings.Development.json
Normal file
8
src/Solar.Api/appsettings.Development.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
9
src/Solar.Api/appsettings.json
Normal file
9
src/Solar.Api/appsettings.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
Reference in New Issue
Block a user