From 1028cbfb401ab7cf937a333599fae2dcf2c3f7df Mon Sep 17 00:00:00 2001 From: Stefan <32109571+Stefan-5422@users.noreply.github.com> Date: Thu, 1 Jun 2023 15:33:18 +0200 Subject: [PATCH] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit a0adfc850db648720e3a251838cdee89e4884845 Author: Stefan <32109571+Stefan-5422@users.noreply.github.com> Date: Thu Jun 1 15:28:39 2023 +0200 Revert using Prom.Net commit 08a5bd477257dec4281d18b892ac284d7d5f6c19 Merge: a47c252 9d64698 Author: Stefan <32109571+Stefan-5422@users.noreply.github.com> Date: Thu Jun 1 15:27:48 2023 +0200 Merge remote-tracking branch 'origin/feature-DeviceRegistration' into feature-DeviceRegistration commit a47c2525e1635c0f459f8d0dd23151a51b6d6eaf Author: Stefan <32109571+Stefan-5422@users.noreply.github.com> Date: Thu Jun 1 15:27:30 2023 +0200 Revert using Prom.Net commit 9d646988d12626f006db096ee26fc89df630c2a5 Merge: 889fc5e 4ef3958 Author: Friend2868 <90833416+Friend2868@users.noreply.github.com> Date: Thu Jun 1 15:24:56 2023 +0200 Merge branch 'feature-DeviceRegistration' of https://github.com/Stefan-5422/-T5-Elektrifikatsiya into feature-DeviceRegistration commit 889fc5e3ddf4e7d6e9e1c48ed2b97f03e5d0c1ff Author: Friend2868 <90833416+Friend2868@users.noreply.github.com> Date: Thu Jun 1 15:24:21 2023 +0200 Final2 commit 92a7538996797483705c7b9fec50a2a808c5bec7 Merge: d5f5ec2 f04724e Author: Friend2868 <90833416+Friend2868@users.noreply.github.com> Date: Thu Jun 1 15:23:59 2023 +0200 Merge branch 'feature-DeviceRegistration' of https://github.com/Stefan-5422/-T5-Elektrifikatsiya into feature-DeviceRegistration commit 4ef3958da39d96618a4829502f6521325aee8556 Author: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com> Date: Thu Jun 1 15:23:10 2023 +0200 Fix .gitignore commit d5f5ec2d0e2000af9e481ecbf12f6df5d4f7cd88 Author: Friend2868 <90833416+Friend2868@users.noreply.github.com> Date: Thu Jun 1 15:21:37 2023 +0200 Final commit 236c2418c538487e8e64ffeb6220558129a1d4e0 Author: Friend2868 <90833416+Friend2868@users.noreply.github.com> Date: Thu Jun 1 15:18:57 2023 +0200 Update .gitignore commit f04724e258c0fe0d915c8713b7ad7e1317e6b9b5 Merge: 9b2db9c f74cff3 Author: Stefan <32109571+Stefan-5422@users.noreply.github.com> Date: Thu Jun 1 15:15:57 2023 +0200 Merge remote-tracking branch 'origin/feature-DeviceRegistration' into feature-DeviceRegistration commit 9b2db9c97deda1a4f35f90053050c5d37b5e8608 Author: Stefan <32109571+Stefan-5422@users.noreply.github.com> Date: Thu Jun 1 15:15:44 2023 +0200 Changes 🐙 commit f74cff3d39c9777277ab35b3167531deb656d07f Author: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com> Date: Wed May 24 11:48:07 2023 +0200 Update appsettings.Development.json commit 2f79ccb22da1ee850a91a00277d6a4990444c36b Author: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com> Date: Wed May 24 11:45:16 2023 +0200 Update appsettings.Development.json commit 104bd37bcb1b0309f1aca5a735b5d25d6546d611 Author: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com> Date: Wed May 24 11:44:58 2023 +0200 Update appsettings.Development.json commit bdac3581deacac236aaba988d1e36c23396002c4 Author: Stefan <32109571+Stefan-5422@users.noreply.github.com> Date: Wed May 24 11:29:38 2023 +0200 Revert test shid commit 5b583186992fd77795f457bfc1b3ba5eae639e09 Merge: 5b342c1 b054b9c Author: Stefan <32109571+Stefan-5422@users.noreply.github.com> Date: Wed May 24 11:28:20 2023 +0200 Merge remote-tracking branch 'origin/feature-DeviceRegistration' into feature-DeviceRegistration commit 5b342c1a8fe27e525c957fdc0a627c4d5b018b82 Author: Stefan <32109571+Stefan-5422@users.noreply.github.com> Date: Wed May 24 11:28:12 2023 +0200 Add `ScheduledService` and email things ༼ つ ◕_◕ ༽つ commit b054b9cfe33912c9ea48f37e49c5876d75adb84a Author: Friend2868 <90833416+Friend2868@users.noreply.github.com> Date: Wed May 24 11:16:18 2023 +0200 EventService finish commit 9520fa04b825482e3eaec5c30835bb75a47b3bb8 Author: Stefan <32109571+Stefan-5422@users.noreply.github.com> Date: Wed May 10 12:13:31 2023 +0200 Email Inferstructure --- .gitignore | 1 + .../Database/MainDatabaseContext.cs | 14 +- .../Elektrifikatsiya/DeviceManagement.sqlite | Bin 24576 -> 0 bytes .../DeviceManagement.sqlite-shm | Bin 32768 -> 0 bytes .../DeviceManagement.sqlite-wal | 0 .../Elektrifikatsiya/Elektrifikatsiya.csproj | 3 + ...rgs.cs => DeviceStatusChangedEventArgs.cs} | 4 +- .../Models/EnergyPriceChange.cs | 23 ++++ .../Elektrifikatsiya/Models/Event.cs | 7 +- .../Models/EventServiceEventArgs.cs | 11 ++ .../Elektrifikatsiya/Models/User.cs | 39 +++--- .../Elektrifikatsiya/Pages/Dashboard.razor | 3 + .../Elektrifikatsiya/Pages/Dashboard.razor.cs | 122 ++++++++++-------- .../Elektrifikatsiya/Pages/Login.razor | 17 ++- .../Elektrifikatsiya/Pages/Settings.razor | 39 +++--- .../Elektrifikatsiya/Program.cs | 24 +++- .../Services/IDeviceStatusService.cs | 2 +- .../Services/IEmailService.cs | 8 ++ .../Services/IEventService.cs | 10 ++ .../Services/INotifcationService.cs | 8 ++ .../Services/IUpdateService.cs | 8 ++ .../Implementations/DeviceManagmentService.cs | 2 + .../Implementations/DeviceStatusService.cs | 8 +- .../Services/Implementations/EmailService.cs | 43 ++++++ .../Services/Implementations/EventService.cs | 55 ++++++++ .../Implementations/NotifcationService.cs | 24 ++++ .../Implementations/ServiceScheduler.cs | 61 +++++++++ .../Services/Implementations/UpdateService.cs | 43 +----- .../Elektrifikatsiya/UserDatabase.sqlite | Bin 12288 -> 0 bytes .../Utilities/EmailSettings.cs | 23 ++++ .../Utilities/IScheduledService.cs | 9 ++ .../appsettings.Development.json | 9 -- src/Elektrifikatsiya/assets/DailyNotif.html | 26 ++++ src/Elektrifikatsiya/assets/DailyNotif.mjml | 49 +++++++ 34 files changed, 529 insertions(+), 166 deletions(-) delete mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/DeviceManagement.sqlite delete mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/DeviceManagement.sqlite-shm delete mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/DeviceManagement.sqlite-wal rename src/Elektrifikatsiya/Elektrifikatsiya/Models/{DeviceStatusChagedEventArgs.cs => DeviceStatusChangedEventArgs.cs} (53%) create mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/Models/EnergyPriceChange.cs create mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/Models/EventServiceEventArgs.cs create mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/Services/IEmailService.cs create mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/Services/IEventService.cs create mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/Services/INotifcationService.cs create mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/Services/IUpdateService.cs create mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/EmailService.cs create mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/EventService.cs create mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/NotifcationService.cs create mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/ServiceScheduler.cs delete mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/UserDatabase.sqlite create mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/Utilities/EmailSettings.cs create mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/Utilities/IScheduledService.cs delete mode 100644 src/Elektrifikatsiya/Elektrifikatsiya/appsettings.Development.json create mode 100644 src/Elektrifikatsiya/assets/DailyNotif.html create mode 100644 src/Elektrifikatsiya/assets/DailyNotif.mjml diff --git a/.gitignore b/.gitignore index 883ab1e..a2dcdb0 100644 --- a/.gitignore +++ b/.gitignore @@ -351,3 +351,4 @@ MigrationBackup/ # Project specific *.sqlite* +src/Elektrifikatsiya/Elektrifikatsiya/appsettings.Development.json diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Database/MainDatabaseContext.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Database/MainDatabaseContext.cs index 95caf56..63fcd63 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Database/MainDatabaseContext.cs +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Database/MainDatabaseContext.cs @@ -6,11 +6,13 @@ namespace Elektrifikatsiya.Database; public class MainDatabaseContext : DbContext { - public MainDatabaseContext(DbContextOptions dbContextOptions) : base(dbContextOptions) - { - } + public DbSet Devices { get; set; } - public DbSet Users { get; set; } - public DbSet Devices { get; set; } - public DbSet Events { get; set; } + public DbSet Users { get; set; } + + public DbSet EnergyPriceChanges { get; set; } + + public MainDatabaseContext(DbContextOptions dbContextOptions) : base(dbContextOptions) + { + } } \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/DeviceManagement.sqlite b/src/Elektrifikatsiya/Elektrifikatsiya/DeviceManagement.sqlite deleted file mode 100644 index b7a73e251a9af12973c0b46e7f44df53659c3a0b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24576 zcmeI&&u-H&90%|u{WDapWtUNjUM!zhZGaFjKxo|&Elo?BO06_eg~g1BHepQ$T)0ed zDATP`y_Ml7ezMucumqon5$DkoENL>H@R z^X9y;S8p`*9}iRi-IU82@~bGLdgd#eEibQDh$yt{UzkBK=Sf0|$3`A;dZG?(o3wh) zz;jK@@d)josXbHDcdf4Jj>#DtpU5DNKjUl5)sXdRdw4Z24<09Wa{c&NALlud%MyNd%_EWdMHJO7 ztmJ5I@F)_vCt_;z=8?WvKRndGFY=tpWz|?&tH}2_gy77o{FLM ziy|^q&Abn?4-^PM00Izz00bZa0SG_<0uX=z1a?&b@BdxREY1Z12tWV=5P$##AOHaf zKmY;|xD&wp|IPv}2tWV=5P$##AOHafKmY;|fWWQ_RI-EN|Npz1UYrX85P$##AOHaf nKmY;|fB*y_kPG1bkBa~S2tWV=5P$##AOHafKmY;|*nNS2>qP#F diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/DeviceManagement.sqlite-shm b/src/Elektrifikatsiya/Elektrifikatsiya/DeviceManagement.sqlite-shm deleted file mode 100644 index fe9ac2845eca6fe6da8a63cd096d9cf9e24ece10..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32768 zcmeIuAr62r3 + + @@ -50,6 +52,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Models/DeviceStatusChagedEventArgs.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Models/DeviceStatusChangedEventArgs.cs similarity index 53% rename from src/Elektrifikatsiya/Elektrifikatsiya/Models/DeviceStatusChagedEventArgs.cs rename to src/Elektrifikatsiya/Elektrifikatsiya/Models/DeviceStatusChangedEventArgs.cs index 8b85cd5..caad485 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Models/DeviceStatusChagedEventArgs.cs +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Models/DeviceStatusChangedEventArgs.cs @@ -1,10 +1,10 @@ namespace Elektrifikatsiya.Models; -public class DeviceStatusChagedEventArgs : EventArgs +public class DeviceStatusChangedEventArgs : EventArgs { public string MacAddress { get; set; } - public DeviceStatusChagedEventArgs(string macAddress) + public DeviceStatusChangedEventArgs(string macAddress) { MacAddress = macAddress; } diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Models/EnergyPriceChange.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Models/EnergyPriceChange.cs new file mode 100644 index 0000000..82214fb --- /dev/null +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Models/EnergyPriceChange.cs @@ -0,0 +1,23 @@ +using System.ComponentModel.DataAnnotations; + +namespace Elektrifikatsiya.Models; + +public class EnergyPriceChange +{ + [Key] + public DateTime DateTime { get; set; } + public double EnergyPrice { get; set; } + + + public EnergyPriceChange(DateTime dateTime, double energyPrice) + { + DateTime = dateTime; + EnergyPrice = energyPrice; + } + + public EnergyPriceChange(double energyPrice) + { + EnergyPrice = energyPrice; + DateTime = DateTime.Now; + } +} \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Models/Event.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Models/Event.cs index 40c67ac..01a91d3 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Models/Event.cs +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Models/Event.cs @@ -11,14 +11,15 @@ namespace Elektrifikatsiya.Models public string EventName { get; set; } public string Description { get; set; } public DateTime Date { get; set; } + public Device Plug { get; set; } - //if Plug Class implemented -> Property for which plug this event is from - - public Event(string eventName, string description, DateTime date) + public Event() { } + public Event(string eventName, string description, DateTime date, Device plug) { EventName = eventName; Description = description; Date = date; + Plug = plug; } } } diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Models/EventServiceEventArgs.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Models/EventServiceEventArgs.cs new file mode 100644 index 0000000..4065bb5 --- /dev/null +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Models/EventServiceEventArgs.cs @@ -0,0 +1,11 @@ +namespace Elektrifikatsiya.Models +{ + public class EventServiceEventArgs : EventArgs + { + public Event NewEvent { get; set; } = new Event(); + public EventServiceEventArgs(Event newEvent) + { + NewEvent = newEvent; + } + } +} diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Models/User.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Models/User.cs index be6b1d8..72aaeb2 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Models/User.cs +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Models/User.cs @@ -5,29 +5,30 @@ namespace Elektrifikatsiya.Models; public class User { - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - [Key] - public int Id { get; private set; } + [Required] + public List Devices { get; set; } = new(); - [Required] - public string Name { get; private set; } + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + [Key] + public int Id { get; private set; } - [Required] - public string PasswordHash { get; private set; } + public DateTime LastLoginDate { get; set; } - [Required] - public Role Role { get; set; } + [Required] + public string Name { get; private set; } - public string? SessionToken { get; set; } - public DateTime LastLoginDate { get; set; } + [Required] + public string PasswordHash { get; private set; } - [Required] - public List Devices { get; set; } = new(); + [Required] + public Role Role { get; set; } - public User(string name, string passwordHash, Role role) - { - Name = name; - PasswordHash = passwordHash; - Role = role; - } + public string? SessionToken { get; set; } + + public User(string name, string passwordHash, Role role) + { + Name = name; + PasswordHash = passwordHash; + Role = role; + } } \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Pages/Dashboard.razor b/src/Elektrifikatsiya/Elektrifikatsiya/Pages/Dashboard.razor index 45ab648..d63777f 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Pages/Dashboard.razor +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Pages/Dashboard.razor @@ -1,5 +1,6 @@ @page "/" @using Blazorise.Components; +@using Elektrifikatsiya.Database; @using Elektrifikatsiya.Models; @using System.Net @using Elektrifikatsiya.Services @@ -10,6 +11,8 @@ @inject IDeviceStatusService DeviceStatusService; @inject IDeviceManagmentService DeviceManagmentService; +@inject IEventService EventService; +@inject MainDatabaseContext MainDatabaseContext;
diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Pages/Dashboard.razor.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Pages/Dashboard.razor.cs index 3d70f26..6fb0007 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Pages/Dashboard.razor.cs +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Pages/Dashboard.razor.cs @@ -5,29 +5,23 @@ using Elektrifikatsiya.Utilities; using System.Diagnostics; using System.Text; +using Elektrifikatsiya.Services.Implementations; +using Elektrifikatsiya.Database; namespace Elektrifikatsiya.Pages; public partial class Dashboard { //TODO: insert new event here if plug produces one - private readonly List events = new List() { new Event("Placeholder", "Placeholder", DateTime.Now), new Event("Placeholder", "Placeholder", DateTime.Now), new Event("Placeholder", "Placeholder", DateTime.Now) }; + private List events = new List() { new Event("Text", "Text", DateTime.Today, null) }; - //TODO: insert new Device here if user adds one - private List plugs = new List(); + private List labels = new List(); //code for graph private LineChart lineChart; - protected override void OnInitialized() - { - plugs = DeviceStatusService.GetDevices().ValueOrDefault ?? new List(); - - DeviceStatusService.OnDeviceStatusChanged += (_, e) => - { - _ = InvokeAsync(StateHasChanged); - }; - } + //TODO: insert new Device here if user adds one + private List plugs = new List(); protected override async Task OnAfterRenderAsync(bool firstRender) { @@ -37,10 +31,63 @@ public partial class Dashboard } } - private async Task Switch(Device device) + protected override void OnInitialized() { - device.Enabled = !device.Enabled; - _ = await DeviceManagmentService.UpdateDevice(device); + plugs = DeviceStatusService.GetDevices().ValueOrDefault ?? new List(); + events = EventService.Events; + + EventService.OnEventCalled += (_, e) => + { + _ = InvokeAsync(StateHasChanged); + }; + DeviceStatusService.OnDeviceStatusChanged += (_, e) => + { + _ = InvokeAsync(StateHasChanged); + }; + } + + private async Task> GetData() + { + if (plugs.Count == 0) + { + return new(); + } + PrometheusQuery promQueryer = new PrometheusQuery("http://localhost:9090"); + + string plugnames = ""; + foreach (Device device in plugs) + { + plugnames += $"shellyplug-s-{device.MacAddress}/relay/0|"; + } + plugnames = plugnames[0..^1]; + + double energyPrice = MainDatabaseContext.EnergyPriceChanges.OrderByDescending(e =>e.DateTime).FirstOrDefault()?.EnergyPrice ?? 0; + + PrometheusDataWrapper? deviceData = (await promQueryer.Query($$"""sum(power{sensor=~"{{plugnames}}"})[1h:1m]"""))?.Data; + PrometheusDataWrapper? priceData = (await promQueryer.Query($$"""sum(sum_over_time(power{sensor=~"{{plugnames}}"}[1y])*{{energyPrice}})"""))?.Data; + + Console.WriteLine(priceData.VectorTypeToTimestampFloatTuple()); + + var r = new Random(DateTime.Now.Millisecond); + + return deviceData?.MatrixTypeToTimestampFloatTuple().ValueOrDefault?.Select(x => + { + labels.Add(DateTimeOffset.FromUnixTimeSeconds(long.Parse($"1{x.Item1}0")).UtcDateTime.ToLocalTime().ToShortTimeString()); + return x.Item2; + }).ToList() ?? new List(); + } + + //TODO: insert dataset of current and last voltage usages + private async Task> GetLineChartDataset() + { + return new LineChartDataset + { + Label = "Wattage", + Data = await GetData(), + Fill = true, + PointRadius = 3, + CubicInterpolationMode = "monotone", + }; } private async Task HandleRedraw() @@ -50,48 +97,9 @@ public partial class Dashboard await lineChart.AddLabelsDatasetsAndUpdate(labels, await GetLineChartDataset()); } - //TODO: insert dataset of current and last voltage usages - private async Task> GetLineChartDataset() + private async Task Switch(Device device) { - return new LineChartDataset - { - Label = "Wattage", - Data = await DeviceData(), - Fill = true, - PointRadius = 3, - CubicInterpolationMode = "monotone", - }; - } - - private readonly List labels = new List(); - - private async Task> DeviceData() - { - PrometheusQuery promQueryer = new PrometheusQuery("http://localhost:9090"); - - StringBuilder builder = new(); - foreach (Device device in plugs) - { - _ = builder.Append($"shellyplug-s-{device.MacAddress}/relay/0|"); - } - - if (builder.Length <= 1) - { - return new(); - } - - string plugnames = builder.ToString()[..^1]; - - Debug.WriteLine($$"""sum(power{sensor=~"{{plugnames}}"})[1h:1m]"""); - - PrometheusDataWrapper? deviceData = (await promQueryer.Query($$"""sum(power{sensor=~"{{plugnames}}"})[1h:1m]"""))?.Data; - - Random r = new Random(DateTime.Now.Millisecond); - - return deviceData?.MatrixTypeToTimestampFloatTuple().ValueOrDefault?.Select(x => - { - labels.Add(DateTimeOffset.FromUnixTimeSeconds(long.Parse($"1{x.Item1}0")).UtcDateTime.ToLocalTime().ToShortTimeString()); - return x.Item2; - }).ToList() ?? new List(); + device.Enabled = !device.Enabled; + _ = await DeviceManagmentService.UpdateDevice(device); } } \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Pages/Login.razor b/src/Elektrifikatsiya/Elektrifikatsiya/Pages/Login.razor index 5c303a0..f62fe54 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Pages/Login.razor +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Pages/Login.razor @@ -1,4 +1,19 @@ @using System.Diagnostics; @using Elektrifikatsiya.Layouts; +@using Elektrifikatsiya.Services; +@inject IAuthenticationService AuthenticationService; +@inject NavigationManager NavigationManager @page "/login" -@layout LoginLayout; \ No newline at end of file +@layout LoginLayout; + +@code { + protected override async Task OnAfterRenderAsync(bool firstRender) + { + bool isAuthenticated = (await AuthenticationService.IsAuthenticated()).ValueOrDefault; + + if (isAuthenticated) + { + NavigationManager.NavigateTo("/"); + } + } +} \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Pages/Settings.razor b/src/Elektrifikatsiya/Elektrifikatsiya/Pages/Settings.razor index 263b2af..4b68b99 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Pages/Settings.razor +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Pages/Settings.razor @@ -1,5 +1,6 @@ @page "/Settings" @using Blazorise.Components; +@using Elektrifikatsiya.Database; @using Elektrifikatsiya.Models; @using System.Net @using System.Text.Json @@ -9,6 +10,7 @@ @inject IDeviceManagmentService DeviceManagmentService @inject IMessageService MessageService +@inject MainDatabaseContext MainDatabaseContext
@@ -90,21 +92,7 @@ Here you can change the name of your plug - - -
-
- - -
- Change Max Output -
- - Here you can limit how much power your plug uses - -
- - +


@@ -117,7 +105,7 @@ Here you select or change the room the plug belongs to. - +
} @@ -138,7 +126,7 @@ Here you enter your electricity price. This is gonna calculate the overall Price of your System - +
@@ -153,7 +141,9 @@ @code { List plugs = new List(); - private bool hideButtonSettings = true; + bool hideButtonSettings = true; + + double electricityPrice = 0; Device? SelectedDevice = null; Device? DeviceCopy = null; @@ -166,6 +156,8 @@ { plugs = getDevicesResult.Value; } + + electricityPrice = MainDatabaseContext.EnergyPriceChanges.OrderByDescending(e=>e.DateTime).FirstOrDefault()?.EnergyPrice ?? 0; } private void Toggle(Device device) @@ -175,16 +167,19 @@ DeviceCopy = device.CopyDevice(); } - private void OnSave() + private async void OnSave() { - if (hideButtonSettings || DeviceCopy is null || SelectedDevice is null) + if (hideButtonSettings) { + MainDatabaseContext.EnergyPriceChanges.Add(new EnergyPriceChange(electricityPrice)); + await MainDatabaseContext.SaveChangesAsync(); } - else + else if(DeviceCopy is not null && SelectedDevice is not null) { + SelectedDevice.OverwiteDevice(DeviceCopy); - DeviceManagmentService.UpdateDevice(SelectedDevice); + await DeviceManagmentService.UpdateDevice(SelectedDevice); } } diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Program.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Program.cs index 6615bf5..1e0c08d 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Program.cs +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Program.cs @@ -1,3 +1,5 @@ +global using INotificationService = Elektrifikatsiya.Services.INotifcationService; + using Blazorise; using Blazorise.Bootstrap; using Blazorise.Icons.Material; @@ -7,20 +9,31 @@ using Elektrifikatsiya.Database; using Elektrifikatsiya.Models; using Elektrifikatsiya.Services; using Elektrifikatsiya.Services.Implementations; - +using Elektrifikatsiya.Utilities; using HiveMQtt.Client; using HiveMQtt.Client.Options; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Options; WebApplicationBuilder builder = WebApplication.CreateBuilder(args); +// Read configuration +builder.Services.Configure(builder.Configuration.GetRequiredSection("EmailSettings")); + // Add services to the container. builder.Services.AddRazorPages(); builder.Services.AddServerSideBlazor(); +builder.Services.AddOptions(); builder.Services.AddHttpContextAccessor(); -builder.Services.AddHostedService(); +builder.Services.AddHostedService(); +builder.Services.AddSingleton(); builder.Services.AddSingleton(); +builder.Services.AddSingleton(); +builder.Services.AddSingleton(s => s.GetRequiredService()); +builder.Services.AddSingleton(s => s.GetRequiredService()); +builder.Services.AddSingleton(); +builder.Services.AddSingleton(); builder.Services.AddSingleton((provider)=> { HiveMQClientOptions options = new() @@ -30,7 +43,7 @@ builder.Services.AddSingleton((provider)=> UseTLS = false, }; - HiveMQClient client = new(options); + HiveMQClient client = new(options); client.ConnectAsync().ConfigureAwait(false); return client; }); @@ -67,6 +80,9 @@ app.MapBlazorHub(); app.MapFallbackToPage("/_Host"); app.MapControllers(); + +app.Services.GetRequiredService>().Value.CompileTemplates(); + IServiceScope serviceScope = app.Services.GetRequiredService().CreateScope(); MainDatabaseContext mainDatabase = serviceScope.ServiceProvider.GetRequiredService(); @@ -81,7 +97,7 @@ if (!mainDatabase.Users.Any()) app.Run(); -void AddBlazorise(IServiceCollection services) +static void AddBlazorise(IServiceCollection services) { _ = services.AddBlazorise(); _ = services.AddMaterialProviders(); diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Services/IDeviceStatusService.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Services/IDeviceStatusService.cs index 61e1cc1..ef10788 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Services/IDeviceStatusService.cs +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Services/IDeviceStatusService.cs @@ -6,7 +6,7 @@ namespace Elektrifikatsiya.Services; public interface IDeviceStatusService { - public event EventHandler OnDeviceStatusChanged; + public event EventHandler OnDeviceStatusChanged; public Result> GetDevices(); diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Services/IEmailService.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Services/IEmailService.cs new file mode 100644 index 0000000..01caf9d --- /dev/null +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Services/IEmailService.cs @@ -0,0 +1,8 @@ +namespace Elektrifikatsiya.Services; + +public interface IEmailService +{ + Task SendAsync(string to, string subject, string html, string? from = null); + + Task SendWithTemeplateAsync(string to, string subject, string templateKey, string? from = null, Dictionary? templateParameters = null); +} \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Services/IEventService.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Services/IEventService.cs new file mode 100644 index 0000000..9445447 --- /dev/null +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Services/IEventService.cs @@ -0,0 +1,10 @@ +using Elektrifikatsiya.Models; + +namespace Elektrifikatsiya.Services +{ + public interface IEventService + { + public List Events { get; } + public event EventHandler OnEventCalled; + } +} diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Services/INotifcationService.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Services/INotifcationService.cs new file mode 100644 index 0000000..96e1b23 --- /dev/null +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Services/INotifcationService.cs @@ -0,0 +1,8 @@ +using Elektrifikatsiya.Utilities; + +namespace Elektrifikatsiya.Services; + +public interface INotifcationService : IScheduledService +{ + +} \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Services/IUpdateService.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Services/IUpdateService.cs new file mode 100644 index 0000000..acfae54 --- /dev/null +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Services/IUpdateService.cs @@ -0,0 +1,8 @@ +using Elektrifikatsiya.Utilities; + +namespace Elektrifikatsiya.Services; + +public interface IUpdateService : IScheduledService +{ + +} \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/DeviceManagmentService.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/DeviceManagmentService.cs index 12e4bb1..57f2180 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/DeviceManagmentService.cs +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/DeviceManagmentService.cs @@ -173,6 +173,8 @@ public class DeviceManagmentService : IDeviceManagmentService PublishResult res = await hiveMQClient.PublishAsync($"shellies/shellyplug-s-{device.MacAddress}/relay/0/command", device.Enabled ? "on" : "off"); + device.User = mainDatabaseContext.Users.First(u => u.Id == device.User.Id); + _ = mainDatabaseContext.Update(device); return await Result.Try(Task () => mainDatabaseContext.SaveChangesAsync()); diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/DeviceStatusService.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/DeviceStatusService.cs index becc6f4..4c4f35b 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/DeviceStatusService.cs +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/DeviceStatusService.cs @@ -1,5 +1,4 @@ using Elektrifikatsiya.Models; - using FluentResults; namespace Elektrifikatsiya.Services.Implementations; @@ -7,15 +6,14 @@ namespace Elektrifikatsiya.Services.Implementations; public class DeviceStatusService : IDeviceStatusService { private readonly ILogger logger; - - public event EventHandler? OnDeviceStatusChanged; + public event EventHandler? OnDeviceStatusChanged; private readonly Dictionary devices = new(); public DeviceStatusService(ILogger logger) { this.logger = logger; - } + } public Result> GetDevices() { @@ -36,7 +34,7 @@ public class DeviceStatusService : IDeviceStatusService modDevice.IpAddress = device.IpAddress; modDevice.Name = device.Name; - OnDeviceStatusChanged?.Invoke(this, new DeviceStatusChagedEventArgs(device.MacAddress)); + OnDeviceStatusChanged?.Invoke(this, new DeviceStatusChangedEventArgs(device.MacAddress)); return Result.Ok(); } diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/EmailService.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/EmailService.cs new file mode 100644 index 0000000..5ea518a --- /dev/null +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/EmailService.cs @@ -0,0 +1,43 @@ +using Elektrifikatsiya.Utilities; +using HandlebarsDotNet; +using MailKit.Net.Smtp; +using MailKit.Security; +using Microsoft.Extensions.Options; +using MimeKit; +using MimeKit.Text; + +namespace Elektrifikatsiya.Services.Implementations +{ + public class EmailService : IEmailService + { + private readonly EmailSettings emailSettings; + + public EmailService(IOptions emailSettings) + { + this.emailSettings = emailSettings.Value; + } + + public async Task SendAsync(string to, string subject, string html, string? from = null) + { + from ??= emailSettings.DefaultEmail; + + MimeMessage message = new MimeMessage(); + message.From.Add(MailboxAddress.Parse(from)); + message.To.Add(MailboxAddress.Parse(to)); + message.Subject = subject; + message.Body = new TextPart(TextFormat.Html) { Text = html }; + + using SmtpClient smtp = new SmtpClient(); + await smtp.ConnectAsync(emailSettings.SmtpServer, emailSettings.SmtpPort, SecureSocketOptions.StartTls); + await smtp.AuthenticateAsync(emailSettings.User, emailSettings.Key); + await smtp.SendAsync(message); + await smtp.DisconnectAsync(true); + } + + public Task SendWithTemeplateAsync(string to, string subject, string templateKey, string? from = null, Dictionary? templateParameters = null) + { + string content = emailSettings.CompiledTemplates[templateKey](templateParameters ?? new()); + return SendAsync(to, subject, content, from); + } + } +} \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/EventService.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/EventService.cs new file mode 100644 index 0000000..3fa5e9a --- /dev/null +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/EventService.cs @@ -0,0 +1,55 @@ +using Elektrifikatsiya.Models; +using FluentResults; +using System.Reflection; + +namespace Elektrifikatsiya.Services.Implementations +{ + public class EventService : IEventService + { + private readonly ILogger logger; + public event EventHandler OnEventCalled; + public List Events { get; } = new(); + + public EventService(ILogger logger, IDeviceStatusService deviceStatusService, IDeviceManagmentService deviceManagmentService) + { + this.logger = logger; + List deviceList = deviceManagmentService.GetDevices().ValueOrDefault.Select(x=>x.CopyDevice()).ToList(); + + deviceStatusService.OnDeviceStatusChanged += (_, e) => + { + bool newDevice = true; + Device currentDevice = deviceManagmentService.GetDevice(e.MacAddress).ValueOrDefault; + + for (int i = 0; i < deviceList.Count; i++) + { + if (deviceList[i].MacAddress == currentDevice.MacAddress) + { + PropertyInfo[] properties = typeof(Device).GetProperties(); + + foreach(PropertyInfo property in properties) { + var currentvalue = property.GetValue(deviceList[i], null); + var newvalue = property.GetValue(currentDevice, null); + if(newvalue is not null && !newvalue.ToString().Equals(currentvalue.ToString())) + { + string eventName = $"Plug {deviceList[i].Name} changed: {property.Name}"; + string description = $"Changed {property.Name} of plug [{currentvalue}] to [{newvalue}]"; + DateTime dateTime = DateTime.Now; + + Event newEvent = new Event(eventName, description, dateTime, currentDevice); + Events.Insert(0,newEvent); + OnEventCalled?.Invoke(this, new EventServiceEventArgs(newEvent)); + } + + } + deviceList[i].OverwiteDevice(currentDevice); + newDevice = false; break; + } + } + if (newDevice) + { + deviceList.Add(deviceManagmentService.GetDevice(e.MacAddress).ValueOrDefault); + } + }; + } + } +} diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/NotifcationService.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/NotifcationService.cs new file mode 100644 index 0000000..12c6ff0 --- /dev/null +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/NotifcationService.cs @@ -0,0 +1,24 @@ +using Elektrifikatsiya.Utilities; + +namespace Elektrifikatsiya.Services.Implementations; + +public class NotifcationService : INotifcationService +{ + public TimeSpan ExecutionRepeatDelay => TimeSpan.FromDays(1); + public DateTime FirstExecutionTime => DateTime.Now.AddDays(0); + private readonly IEmailService emailService; + private readonly ILogger logger; + + public NotifcationService(ILogger logger, IEmailService emailService) + { + this.logger = logger; + this.emailService = emailService; + } + + public async void Update() + { + //logger.LogInformation("Sending Email"); + //await emailService.SendWithTemeplateAsync("manuel.strubegger@htl-saalfelden.at", "AAAA", "DailyNotification", templateParameters: new() { { "yesterday", "10" }, { "yearly", "100" }, { "link", "localhost:5565/yes" } }); + //logger.LogInformation("Done sending"); + } +} \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/ServiceScheduler.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/ServiceScheduler.cs new file mode 100644 index 0000000..c430ade --- /dev/null +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/ServiceScheduler.cs @@ -0,0 +1,61 @@ +using Elektrifikatsiya.Utilities; + +namespace Elektrifikatsiya.Services.Implementations; + +public class ServiceScheduler : IHostedService +{ + private readonly ILogger logger; + private readonly IEnumerable scheduledServices; + private readonly Dictionary lastExectued; + + private Timer timer = null!; + + public ServiceScheduler(ILogger logger, IServiceProvider serviceProvider) + { + this.logger = logger; + scheduledServices = serviceProvider.GetServices(); + lastExectued = scheduledServices.ToDictionary(x => x, x => x.FirstExecutionTime); + + } + + public async Task StartAsync(CancellationToken cancellationToken) + { + logger.LogInformation("Starting service scheduler..."); + + timer = new Timer(async (_) => await Update(), null, TimeSpan.Zero, Timeout.InfiniteTimeSpan); + + logger.LogInformation("Service scheduler started."); + } + + public Task StopAsync(CancellationToken cancellationToken) + { + logger.LogInformation("Stopping service scheduler."); + + timer.Dispose(); + + logger.LogInformation("Stopped service scheduler."); + + return Task.CompletedTask; + } + + private async Task Update() + { + TimeSpan s = lastExectued.Min(x => (x.Value + x.Key.ExecutionRepeatDelay)) - DateTime.Now; + + if (s < TimeSpan.Zero) + { + s = TimeSpan.FromSeconds(1); + } + + timer.Change(s, Timeout.InfiniteTimeSpan); + + foreach (IScheduledService scheduledService in scheduledServices.Where(s => s.FirstExecutionTime < DateTime.Now)) + { + if (lastExectued[scheduledService] + scheduledService.ExecutionRepeatDelay <= DateTime.Now) + { + lastExectued[scheduledService] = DateTime.Now; + scheduledService.Update(); + } + } + } +} \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/UpdateService.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/UpdateService.cs index 0a3ef4a..94070e1 100644 --- a/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/UpdateService.cs +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/UpdateService.cs @@ -8,38 +8,29 @@ using Microsoft.EntityFrameworkCore; namespace Elektrifikatsiya.Services.Implementations; -public class UpdateService : IHostedService, IDisposable +public class UpdateService : IUpdateService { private readonly ILogger logger; private readonly IDeviceStatusService deviceStatusService; - private readonly IServiceScopeFactory serviceScopeFactory; - private Timer? timer = null; public UpdateService(ILogger logger, IDeviceStatusService deviceStatusService, IServiceScopeFactory serviceScopeFactory) { this.logger = logger; this.deviceStatusService = deviceStatusService; - this.serviceScopeFactory = serviceScopeFactory; - } - public async Task StartAsync(CancellationToken cancellationToken) - { IServiceScope serviceScope = serviceScopeFactory.CreateScope(); MainDatabaseContext mainDatabaseContext = serviceScope.ServiceProvider.GetRequiredService(); - logger.LogInformation("Starting update service..."); - - foreach (Device device in await mainDatabaseContext.Devices.Include(d => d.User).AsNoTracking().ToListAsync(cancellationToken)) + foreach (Device device in mainDatabaseContext.Devices.Include(d => d.User).AsNoTracking().ToList()) { _ = deviceStatusService.TrackDevice(device); } - - timer = new Timer(async (_) => await Update(), null, TimeSpan.Zero, TimeSpan.FromSeconds(15)); - - logger.LogInformation("Update service started."); } - private async Task Update() + public DateTime FirstExecutionTime { get; } = DateTime.Now.AddSeconds(15); + public TimeSpan ExecutionRepeatDelay { get; } = TimeSpan.FromSeconds(15); + + public async void Update() { Result> getDeviceStatusResult = deviceStatusService.GetDevices(); @@ -61,26 +52,4 @@ public class UpdateService : IHostedService, IDisposable } } } - - public Task StopAsync(CancellationToken cancellationToken) - { - logger.LogInformation("Stopping update service."); - - _ = timer?.Change(Timeout.Infinite, 0); - - logger.LogInformation("Stopped update service."); - - return Task.CompletedTask; - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - timer?.Dispose(); - } } \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/UserDatabase.sqlite b/src/Elektrifikatsiya/Elektrifikatsiya/UserDatabase.sqlite deleted file mode 100644 index eeeb96ffa3098bd6e50255479f5d1e5c5a3c0c6a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI#%SyvQ6b9hQ)C&|Wf{TEwLsl&$)9D$$NwY!ljvxECM7XY?sN zttn_x+?W5rOft8VnJ=s9Ux$;z(0#s`r3IaeLm{O&BN9SLE)_28aQJ0s-Qef4{a;9N zGCDrsS+e#nY9Cx7AOHafKmY;|fB*y_009U<00Q3xV!7uwo6fLEZ>Pr2r+i5rSu=k& z+1+Nd(oU4G6>0xGRJ1X-o~1L>;+2ipBWK@rUFU6gm2+Ut!mcX$W4*WP^Qc}W4lfvc z6hvBGs)VARrf3j`)b2%no%q~OUfda#E8-;R`pJ+wYDoS-_kxHMcU7cYU#TMAiAP%9 zaF#MtITEMVzT}JXRcar9pV2qgPV!9WPbOQ>;GLA~!_*dG{xHcd(&CR#B>9v_HcwJ* zEbr!g=|?~S0uX=z1Rwwb2tWV=5P$##Ah5*(xc_hQ&&AOo009U<00Izz00bZa0SG_< H0;Rwwql9r3 diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Utilities/EmailSettings.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Utilities/EmailSettings.cs new file mode 100644 index 0000000..4e53927 --- /dev/null +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Utilities/EmailSettings.cs @@ -0,0 +1,23 @@ +using HandlebarsDotNet; + +namespace Elektrifikatsiya.Utilities; + +public class EmailSettings +{ + public string User { get; set; } + public string DefaultEmail { get; set; } + public string Key { get; set; } + public Dictionary Templates { get; set; } + public string SmtpServer { get; set; } + public int SmtpPort { get; set; } + + public Dictionary> CompiledTemplates = new(); + + public void CompileTemplates() + { + foreach ((string templateName, string templatePath) in Templates) + { + CompiledTemplates.Add(templateName, Handlebars.Compile(File.ReadAllText(templatePath))); + } + } +} \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Utilities/IScheduledService.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Utilities/IScheduledService.cs new file mode 100644 index 0000000..7c4e0f7 --- /dev/null +++ b/src/Elektrifikatsiya/Elektrifikatsiya/Utilities/IScheduledService.cs @@ -0,0 +1,9 @@ +namespace Elektrifikatsiya.Utilities; + +public interface IScheduledService +{ + DateTime FirstExecutionTime { get; } + TimeSpan ExecutionRepeatDelay { get; } + + void Update(); +} \ No newline at end of file diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/appsettings.Development.json b/src/Elektrifikatsiya/Elektrifikatsiya/appsettings.Development.json deleted file mode 100644 index 770d3e9..0000000 --- a/src/Elektrifikatsiya/Elektrifikatsiya/appsettings.Development.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "DetailedErrors": true, - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } - } -} diff --git a/src/Elektrifikatsiya/assets/DailyNotif.html b/src/Elektrifikatsiya/assets/DailyNotif.html new file mode 100644 index 0000000..ab13c0d --- /dev/null +++ b/src/Elektrifikatsiya/assets/DailyNotif.html @@ -0,0 +1,26 @@ +
Daily Notification
Energy Consumption yesterday: {{yesterday}}
Energy Consumption since the start of the year: {{yearly}}
\ No newline at end of file diff --git a/src/Elektrifikatsiya/assets/DailyNotif.mjml b/src/Elektrifikatsiya/assets/DailyNotif.mjml new file mode 100644 index 0000000..a4cfbb6 --- /dev/null +++ b/src/Elektrifikatsiya/assets/DailyNotif.mjml @@ -0,0 +1,49 @@ + + + + + + + @font-face { + font-family: Nunito; + src: url(https://fonts.gstatic.com/s/nunito/v16/XRXV3I6Li01BKofINeaB.woff2) + format('truetype'); + } + + + + + + + + + + Daily Notification + + + + + + + Energy Consumption yesterday: {{yesterday}} + + + + + Energy Consumption since the start of the year: {{yearly}} + + + + + + + + Goto Dashboard + + + + + + + + \ No newline at end of file