diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Models/Device.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Models/Device.cs
index 0bcca1a..4d15c15 100644
--- a/src/Elektrifikatsiya/Elektrifikatsiya/Models/Device.cs
+++ b/src/Elektrifikatsiya/Elektrifikatsiya/Models/Device.cs
@@ -34,4 +34,6 @@ public class Device
User = user;
Room = room;
}
+
+ private Device(){}
}
\ No newline at end of file
diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Pages/AddPlug.razor b/src/Elektrifikatsiya/Elektrifikatsiya/Pages/AddPlug.razor
index fa1bb7a..41cb0fb 100644
--- a/src/Elektrifikatsiya/Elektrifikatsiya/Pages/AddPlug.razor
+++ b/src/Elektrifikatsiya/Elektrifikatsiya/Pages/AddPlug.razor
@@ -1,7 +1,14 @@
@page "/addplug"
@using Blazorise.Components;
@using Elektrifikatsiya.Models;
+@using System.Net
+@using Elektrifikatsiya.Services
+@using Elektrifikatsiya.Services.Implementations
+@using Elektrifikatsiya.Utilities
@inject IVersionProvider VersionProvider
+@inject IDeviceManagmentService DeviceManagmentService
+@inject IAuthenticationService AuthenticationService
+
@@ -16,32 +23,36 @@
Add a plug via wifi
-
-
-
+
+
+
+
+
-
-
-
- IP: @context.Item.Address
-
-
-
-
-
+
+ @context.Item
-
-
-
+
+
+ IP: @context.Item
+
+
+
+
+
+
+
+
+
+
@@ -80,5 +91,15 @@
@code {
- List plugs = new List() { new Device("Placeholder", "Plug", System.Net.IPAddress.Broadcast, 60, "Oldin", "4AHINF"), new Device("Placeholder", "Plug", System.Net.IPAddress.Broadcast, 60, "Oldin", "4AHINF"), new Device("Placeholder", "Plug", System.Net.IPAddress.Broadcast, 60, "Oldin", "4AHINF") };
+ List ipAddresses = new List();
+
+ protected override void OnInitialized()
+ {
+ ipAddresses.AddRange(MdnsDiscovery.GetChachedDevices());
+ MdnsDiscovery.OnDeviceFound += address =>
+ {
+ ipAddresses.Add(address);
+ InvokeAsync(StateHasChanged);
+ };
+ }
}
diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Pages/Dashboard.razor b/src/Elektrifikatsiya/Elektrifikatsiya/Pages/Dashboard.razor
index fa442fe..049c64e 100644
--- a/src/Elektrifikatsiya/Elektrifikatsiya/Pages/Dashboard.razor
+++ b/src/Elektrifikatsiya/Elektrifikatsiya/Pages/Dashboard.razor
@@ -1,6 +1,7 @@
@page "/"
@using Blazorise.Components;
@using Elektrifikatsiya.Models;
+@using System.Net
@inject IVersionProvider VersionProvider
@@ -90,8 +91,7 @@
//TODO: insert new event here if plug produces one
List events = new List() { new Event("Placeholder", "Placeholder", DateTime.Now), new Event("Placeholder", "Placeholder", DateTime.Now), new Event("Placeholder", "Placeholder", DateTime.Now) };
//TODO: insert new Device here if user adds one
- List plugs = new List() { new Device("Placeholder", "Plug", System.Net.IPAddress.Broadcast, 60, "Oldin", "4AHINF"), new Device("Placeholder", "Plug", System.Net.IPAddress.Broadcast, 60, "Oldin", "4AHINF"), new Device("Placeholder", "Plug", System.Net.IPAddress.Broadcast, 60, "Oldin", "4AHINF") };
-
+ List plugs = new List() { new Device("ffff:ffff:ffff:ffff", "Huso", IPAddress.Broadcast, new User("Joe", "qiowruioewjfopa", Role.Admin), "Raum"), new Device("ffff:ffff:ffff:ffff", "Huso", IPAddress.Broadcast, new User("Joe", "qiowruioewjfopa", Role.Admin), "Raum"), new Device("ffff:ffff:ffff:ffff", "Huso", IPAddress.Broadcast, new User("Joe", "qiowruioewjfopa", Role.Admin), "Raum"), };
//code for graph
LineChart lineChart;
diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Program.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Program.cs
index dfa27db..3c21487 100644
--- a/src/Elektrifikatsiya/Elektrifikatsiya/Program.cs
+++ b/src/Elektrifikatsiya/Elektrifikatsiya/Program.cs
@@ -4,6 +4,7 @@ using Blazorise.Icons.Material;
using Blazorise.Material;
using Elektrifikatsiya.Database;
+using Elektrifikatsiya.Models;
using Elektrifikatsiya.Services;
using Elektrifikatsiya.Services.Implementations;
@@ -14,15 +15,20 @@ WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
+builder.Services.AddHttpContextAccessor();
builder.Services.AddHostedService();
builder.Services.AddSingleton();
builder.Services.AddTransient();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
builder.Services.AddDbContext(options => options.UseSqlite("Data Source=./UserDatabase.sqlite"));
builder.Services.AddDbContext((options) => options.UseSqlite("Data Source=./DeviceManagement.sqlite"));
builder.Services.AddBootstrapProviders();
+builder.Services.AddHttpClient();
builder.Services.AddBlazorise(options =>
{
- options.Immediate = true;
+ options.Immediate = true;
});
AddBlazorise(builder.Services);
@@ -32,9 +38,9 @@ WebApplication app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
- _ = app.UseExceptionHandler("/Error");
- // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
- _ = app.UseHsts();
+ _ = app.UseExceptionHandler("/Error");
+ // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
+ _ = app.UseHsts();
}
app.UseHttpsRedirection();
@@ -44,12 +50,11 @@ app.UseStaticFiles();
app.UseRouting();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
+app.MapControllers();
IServiceScope serviceScope = app.Services.GetRequiredService().CreateScope();
serviceScope.ServiceProvider.GetRequiredService().Database.EnsureCreated();
-app.MapControllers();
-
AsyncServiceScope scope = app.Services.CreateAsyncScope();
scope.ServiceProvider.GetRequiredService().Database.EnsureCreated();
@@ -57,7 +62,7 @@ app.Run();
void AddBlazorise(IServiceCollection services)
{
- _ = services.AddBlazorise();
- _ = services.AddMaterialProviders();
- _ = services.AddMaterialIcons();
+ _ = services.AddBlazorise();
+ _ = services.AddMaterialProviders();
+ _ = services.AddMaterialIcons();
}
\ No newline at end of file
diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Properties/launchSettings.json b/src/Elektrifikatsiya/Elektrifikatsiya/Properties/launchSettings.json
index 71c02c5..fe359ad 100644
--- a/src/Elektrifikatsiya/Elektrifikatsiya/Properties/launchSettings.json
+++ b/src/Elektrifikatsiya/Elektrifikatsiya/Properties/launchSettings.json
@@ -7,7 +7,7 @@
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": true,
- "applicationUrl": "https://localhost:7297;http://localhost:5255"
+ "applicationUrl": "https://localhost:56656;http://localhost:5255"
},
"IIS Express": {
"commandName": "IISExpress",
diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Services/IDeviceManagmentService.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Services/IDeviceManagmentService.cs
index bda0e67..764ee22 100644
--- a/src/Elektrifikatsiya/Elektrifikatsiya/Services/IDeviceManagmentService.cs
+++ b/src/Elektrifikatsiya/Elektrifikatsiya/Services/IDeviceManagmentService.cs
@@ -8,9 +8,9 @@ namespace Elektrifikatsiya.Services;
public interface IDeviceManagmentService
{
- public Task> Register(IPAddress ip, User user, string? name = null, string room = "default");
+ public Task> RegisterDevice(IPAddress ip, User user, string? name = null, string room = "default");
- public Task Unregister(string macAdress);
+ public Task UnregisterDevice(string macAdress);
public Result GetDevice(string macAdress);
@@ -19,4 +19,6 @@ public interface IDeviceManagmentService
public Result> GetDevicesInRoom(string room);
public Result> GetDevicesOfUser(int userId);
+
+ public Task UpdateDevice(Device device);
}
\ 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 b659cf1..34916e0 100644
--- a/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/DeviceManagmentService.cs
+++ b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/DeviceManagmentService.cs
@@ -10,116 +10,153 @@ namespace Elektrifikatsiya.Services.Implementations;
public class DeviceManagmentService : IDeviceManagmentService
{
- private readonly DeviceManagmentDatabaseContext deviceManagmentDatabaseContext;
- private readonly IDeviceStatusService deviceStatusService;
- private readonly HttpClient httpClient;
+ private readonly IServiceScopeFactory serviceScopeFactory;
+ private readonly IDeviceStatusService deviceStatusService;
+ private readonly ILogger logger;
+ private readonly HttpClient httpClient;
- public DeviceManagmentService(DeviceManagmentDatabaseContext deviceManagmentDatabaseContext, IDeviceStatusService deviceStatusService, HttpClient httpClient)
- {
- this.deviceManagmentDatabaseContext = deviceManagmentDatabaseContext;
- this.deviceStatusService = deviceStatusService;
- this.httpClient = httpClient;
- }
+ public DeviceManagmentService(IServiceScopeFactory serviceScopeFactory, IDeviceStatusService deviceStatusService, ILogger logger, HttpClient httpClient)
+ {
+ this.serviceScopeFactory = serviceScopeFactory;
+ this.deviceStatusService = deviceStatusService;
+ this.logger = logger;
+ this.httpClient = httpClient;
+ }
- public Result GetDevice(string macAdress)
- {
- Result> getDevicesResult = deviceStatusService.GetDevices();
+ public Result GetDevice(string macAdress)
+ {
+ Result> getDevicesResult = deviceStatusService.GetDevices();
- if (getDevicesResult.IsFailed)
- {
- return getDevicesResult.ToResult();
- }
+ if (getDevicesResult.IsFailed)
+ {
+ return getDevicesResult.ToResult();
+ }
- Device? device = getDevicesResult.Value.FirstOrDefault(d => d.MacAddress == macAdress);
+ Device? device = getDevicesResult.Value.FirstOrDefault(d => d.MacAddress == macAdress);
- if (device is null)
- {
- return Result.Fail("Device does not exist!");
- }
+ if (device is null)
+ {
+ return Result.Fail("Device does not exist!");
+ }
- return device;
- }
+ return device;
+ }
- public Result> GetDevices()
- {
- Result> getDevicesResult = deviceStatusService.GetDevices();
+ public Result> GetDevices()
+ {
+ Result> getDevicesResult = deviceStatusService.GetDevices();
- if (getDevicesResult.IsFailed)
- {
- return getDevicesResult.ToResult();
- }
+ if (getDevicesResult.IsFailed)
+ {
+ return getDevicesResult.ToResult();
+ }
- return getDevicesResult.Value.ToList();
- }
+ return getDevicesResult.Value.ToList();
+ }
- public Result> GetDevicesInRoom(string room)
- {
- Result> getDevicesResult = deviceStatusService.GetDevices();
+ public Result> GetDevicesInRoom(string room)
+ {
+ Result> getDevicesResult = deviceStatusService.GetDevices();
- if (getDevicesResult.IsFailed)
- {
- return getDevicesResult.ToResult();
- }
+ if (getDevicesResult.IsFailed)
+ {
+ return getDevicesResult.ToResult();
+ }
- return getDevicesResult.Value.Where(d => d.Room == room).ToList();
- }
+ return getDevicesResult.Value.Where(d => d.Room == room).ToList();
+ }
- public Result> GetDevicesOfUser(int userId)
- {
- Result> getDevicesResult = deviceStatusService.GetDevices();
+ public Result> GetDevicesOfUser(int userId)
+ {
+ Result> getDevicesResult = deviceStatusService.GetDevices();
- if (getDevicesResult.IsFailed)
- {
- return getDevicesResult.ToResult();
- }
+ if (getDevicesResult.IsFailed)
+ {
+ return getDevicesResult.ToResult();
+ }
- return getDevicesResult.Value.Where(d => d.User.Id == userId).ToList();
- }
+ return getDevicesResult.Value.Where(d => d.User.Id == userId).ToList();
+ }
- public async Task> Register(IPAddress ip, User user, string? name = null, string room = "default")
- {
- ShellyResponse? shellyResponse = await httpClient.GetFromJsonAsync($"{ip}/shelly");
+ public async Task> RegisterDevice(IPAddress ip, User user, string? name = null, string room = "default")
+ {
+ using IServiceScope scope = serviceScopeFactory.CreateScope();
+ DeviceManagmentDatabaseContext deviceManagmentDatabaseContext = scope.ServiceProvider.GetRequiredService();
- if(shellyResponse is null || shellyResponse.Type != "SHPLG-S")
- {
- return Result.Fail("Device is not a \"SHPLG-S\" or not reachable!");
- }
+ ShellyResponse? shellyResponse = null;
- string mac = shellyResponse.Mac;
+ try
+ {
+ shellyResponse = await httpClient.GetFromJsonAsync($"http://{ip}/shelly");
+ }
+ catch (Exception ex)
+ {
+ logger.LogError("HTTP request failed! {message}", ex.Message);
+ }
- if(PhysicalAddress.TryParse(mac, out _))
- {
- return Result.Fail("Invalid mac address!");
- }
+ if (shellyResponse is null || shellyResponse.Type != "SHPLG-S")
+ {
+ return Result.Fail("Device is not reachable or not a \"SHPLG-S\"!");
+ }
- Device device = new Device(mac, name ?? mac, ip, user, room);
+ string mac = shellyResponse.Mac;
- deviceManagmentDatabaseContext.Add(device);
- Result saveDatabaseChangesResult = await Result.Try(async Task () => await deviceManagmentDatabaseContext.SaveChangesAsync());
+ if (!PhysicalAddress.TryParse(mac, out _))
+ {
+ return Result.Fail("Invalid mac address!");
+ }
- Result trackDeviceResult = deviceStatusService.TrackDevice(device);
+ Device device = new Device(mac, name ?? mac, ip, user, room);
- return Result.Merge(saveDatabaseChangesResult, trackDeviceResult).ToResult(device);
- }
+ _ = deviceManagmentDatabaseContext.Add(device);
+ Result saveDatabaseChangesResult = await Result.Try(Task () => deviceManagmentDatabaseContext.SaveChangesAsync());
- public async Task Unregister(string macAdress)
- {
- Result getDeviceResult = GetDevice(macAdress);
+ if (saveDatabaseChangesResult.IsFailed)
+ {
+ return saveDatabaseChangesResult;
+ }
- if (getDeviceResult.IsFailed)
- {
- return getDeviceResult.ToResult();
- }
+ return deviceStatusService.TrackDevice(device);
+ }
- Result untrackDeviceResult = deviceStatusService.UntrackDevice(macAdress);
+ public async Task UnregisterDevice(string macAdress)
+ {
+ using IServiceScope scope = serviceScopeFactory.CreateScope();
+ DeviceManagmentDatabaseContext deviceManagmentDatabaseContext = scope.ServiceProvider.GetRequiredService();
- if (untrackDeviceResult.IsFailed)
- {
- return untrackDeviceResult;
- }
+ Result getDeviceResult = GetDevice(macAdress);
- deviceManagmentDatabaseContext.Remove(getDeviceResult.Value);
+ if (getDeviceResult.IsFailed)
+ {
+ return getDeviceResult.ToResult();
+ }
- return await Result.Try(async Task () => await deviceManagmentDatabaseContext.SaveChangesAsync());
- }
+ Result untrackDeviceResult = deviceStatusService.UntrackDevice(macAdress);
+
+ if (untrackDeviceResult.IsFailed)
+ {
+ return untrackDeviceResult;
+ }
+
+ _ = deviceManagmentDatabaseContext.Remove(getDeviceResult.Value);
+
+ return await Result.Try(Task () => deviceManagmentDatabaseContext.SaveChangesAsync());
+ }
+
+ public async Task UpdateDevice(Device device)
+ {
+ using IServiceScope scope = serviceScopeFactory.CreateScope();
+ DeviceManagmentDatabaseContext deviceManagmentDatabaseContext = scope.ServiceProvider.GetRequiredService();
+
+ Result result = deviceStatusService.UpdateDeviceStatus(device);
+
+ if (result.IsFailed)
+ {
+ return result;
+ }
+
+ _ = deviceManagmentDatabaseContext.Update(device);
+
+ return await Result.Try(Task () => deviceManagmentDatabaseContext.SaveChangesAsync());
+ }
}
\ No newline at end of file
diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/DeviceStatusService.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/DeviceStatusService.cs
index 3574cec..2e6e904 100644
--- a/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/DeviceStatusService.cs
+++ b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/DeviceStatusService.cs
@@ -6,10 +6,15 @@ namespace Elektrifikatsiya.Services.Implementations;
public class DeviceStatusService : IDeviceStatusService
{
- public event EventHandler? OnDeviceStatusChanged;
+ private readonly ILogger logger;
+ public event EventHandler? OnDeviceStatusChanged;
private readonly Dictionary devices = new();
-
+
+ public DeviceStatusService(ILogger logger)
+ {
+ this.logger = logger;
+ }
public Result> GetDevices()
{
return devices.Values.ToList();
@@ -41,6 +46,8 @@ public class DeviceStatusService : IDeviceStatusService
return Result.Fail("Device already tracked!");
}
+ logger.LogInformation("Tracking new Device {device}", device.IpAddress);
+
devices[device.MacAddress] = device;
return Result.Ok();
diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/UpdateService.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/UpdateService.cs
index 980826d..da74f9f 100644
--- a/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/UpdateService.cs
+++ b/src/Elektrifikatsiya/Elektrifikatsiya/Services/Implementations/UpdateService.cs
@@ -10,19 +10,22 @@ public class UpdateService : IHostedService, IDisposable
{
private readonly ILogger logger;
private readonly IDeviceStatusService deviceStatusService;
- private readonly DeviceManagmentDatabaseContext deviceManagmentDatabaseContext;
+ private readonly IServiceScopeFactory serviceScopeFactory;
private Timer? timer = null;
- public UpdateService(ILogger logger, IDeviceStatusService deviceStatusService, DeviceManagmentDatabaseContext deviceManagmentDatabaseContext)
+ public UpdateService(ILogger logger, IDeviceStatusService deviceStatusService, IServiceScopeFactory serviceScopeFactory)
{
this.logger = logger;
this.deviceStatusService = deviceStatusService;
- this.deviceManagmentDatabaseContext = deviceManagmentDatabaseContext;
+ this.serviceScopeFactory = serviceScopeFactory;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
- logger.LogInformation("Starting update service...");
+ IServiceScope serviceScope = serviceScopeFactory.CreateScope();
+ DeviceManagmentDatabaseContext deviceManagmentDatabaseContext = serviceScope.ServiceProvider.GetRequiredService();
+
+ logger.LogInformation("Starting update service...");
foreach (Device device in await deviceManagmentDatabaseContext.Devices.AsNoTracking().ToListAsync(cancellationToken))
{
diff --git a/src/Elektrifikatsiya/Elektrifikatsiya/Utilities/MdnsDiscovery.cs b/src/Elektrifikatsiya/Elektrifikatsiya/Utilities/MdnsDiscovery.cs
new file mode 100644
index 0000000..55a8943
--- /dev/null
+++ b/src/Elektrifikatsiya/Elektrifikatsiya/Utilities/MdnsDiscovery.cs
@@ -0,0 +1,25 @@
+using System.Net;
+
+using Tmds.MDns;
+
+namespace Elektrifikatsiya.Utilities;
+
+public static class MdnsDiscovery
+{
+ public static event Action OnDeviceFound = null!;
+
+ private static readonly ServiceBrowser serviceBrowser = new ServiceBrowser();
+
+ static MdnsDiscovery()
+ {
+ serviceBrowser.StartBrowse("_http._tcp");
+ serviceBrowser.ServiceAdded += (_, eventArgs) => OnDeviceFound?.Invoke(eventArgs.Announcement.Addresses.First());
+ serviceBrowser.ServiceChanged += (_, eventArgs) => OnDeviceFound?.Invoke(eventArgs.Announcement.Addresses.First());
+ serviceBrowser.ServiceRemoved += (_, eventArgs) => OnDeviceFound?.Invoke(eventArgs.Announcement.Addresses.First());
+ }
+
+ public static IEnumerable GetChachedDevices()
+ {
+ return serviceBrowser.Services.Select(s => s.Addresses.First());
+ }
+}
\ No newline at end of file