mirror of
https://github.com/Stefan-5422/-T5-Elektrifikatsiya.git
synced 2026-09-04 00:45:58 +02:00
Merge pull request #36 from Stefan-5422/feature-DeviceRegistration
Feature device registration
This commit is contained in:
@@ -34,4 +34,6 @@ public class Device
|
||||
User = user;
|
||||
Room = room;
|
||||
}
|
||||
|
||||
private Device(){}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
<Div >
|
||||
<Row Style="height:50%; width:100%" Padding="Padding.Is3.OnDesktop.Is0">
|
||||
<Row Style="height:90%; width:100%">
|
||||
@@ -16,25 +23,29 @@
|
||||
Add a plug via wifi
|
||||
</BarBrand>
|
||||
</Bar>
|
||||
<ListView Class="w-100"
|
||||
TItem="Device"
|
||||
Data="@plugs"
|
||||
<ListView Class="w-100"
|
||||
TItem="IPAddress"
|
||||
Data="@ipAddresses"
|
||||
TextField="@((_)=>(""))"
|
||||
ValueField="@((_)=>(""))"
|
||||
Mode="ListGroupMode.Static"
|
||||
Style="border-radius: 0px 0px">
|
||||
Mode="ListGroupMode.Static">
|
||||
<ItemTemplate>
|
||||
<ListGroupItem>
|
||||
<Row>
|
||||
<Column ColumnSize="ColumnSize.Is7">
|
||||
<Column ColumnSize="ColumnSize.Is6">
|
||||
<Row>
|
||||
<Column >
|
||||
<Heading Size="HeadingSize.Is6" Margin="Margin.Is1.FromBottom">@context.Item</Heading>
|
||||
</Column>
|
||||
</Row>
|
||||
<Row Width="Width.Is100">
|
||||
<Column>
|
||||
<Small>IP: @context.Item.Address</Small>
|
||||
<Small>IP: @context.Item</Small>
|
||||
</Column>
|
||||
</Row>
|
||||
</Column>
|
||||
<Column ColumnSize="ColumnSize.Is4.Is1.WithOffset">
|
||||
<Button Position="Position.Absolute.Top.Is50.Start.Is50.Translate.Middle" Color="Color.Dark" Outline>
|
||||
<Column ColumnSize="ColumnSize.Is4.Is2.WithOffset">
|
||||
<Button Position="Position.Absolute.Top.Is50.Start.Is50.Translate.Middle" Color="Color.Dark" Clicked="@(async () => await DeviceManagmentService.RegisterDevice(context.Item,(await AuthenticationService.GetUserAsync()).ValueOrDefault))" Outline>
|
||||
<BarIcon IconName="IconName.Add" />
|
||||
</Button>
|
||||
</Column>
|
||||
@@ -80,5 +91,15 @@
|
||||
</Div>
|
||||
|
||||
@code {
|
||||
List<Device> plugs = new List<Device>() { 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<IPAddress> ipAddresses = new List<IPAddress>();
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
ipAddresses.AddRange(MdnsDiscovery.GetChachedDevices());
|
||||
MdnsDiscovery.OnDeviceFound += address =>
|
||||
{
|
||||
ipAddresses.Add(address);
|
||||
InvokeAsync(StateHasChanged);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
@page "/"
|
||||
@using Blazorise.Components;
|
||||
@using Elektrifikatsiya.Models;
|
||||
@using System.Net
|
||||
@inject IVersionProvider VersionProvider
|
||||
|
||||
<Row Padding="Padding.Is3">
|
||||
@@ -90,8 +91,7 @@
|
||||
//TODO: insert new event here if plug produces one
|
||||
List<Event> events = new List<Event>() { 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<Device> plugs = new List<Device>() { 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<Device> plugs = new List<Device>() { 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<double> lineChart;
|
||||
|
||||
|
||||
@@ -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,12 +15,17 @@ WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
|
||||
// Add services to the container.
|
||||
builder.Services.AddRazorPages();
|
||||
builder.Services.AddServerSideBlazor();
|
||||
builder.Services.AddHttpContextAccessor();
|
||||
builder.Services.AddHostedService<UpdateService>();
|
||||
builder.Services.AddSingleton<IDeviceStatusService, DeviceStatusService>();
|
||||
builder.Services.AddTransient<IDeviceManagmentService, DeviceManagmentService>();
|
||||
builder.Services.AddScoped<IAuthenticationService, AuthenticationService>();
|
||||
builder.Services.AddScoped<IAuthorizationService, AuthorizationService>();
|
||||
builder.Services.AddScoped<ICookieService, CookieService>();
|
||||
builder.Services.AddDbContext<UserDatabaseContext>(options => options.UseSqlite("Data Source=./UserDatabase.sqlite"));
|
||||
builder.Services.AddDbContext<DeviceManagmentDatabaseContext>((options) => options.UseSqlite("Data Source=./DeviceManagement.sqlite"));
|
||||
builder.Services.AddBootstrapProviders();
|
||||
builder.Services.AddHttpClient<IDeviceManagmentService, DeviceManagmentService>();
|
||||
builder.Services.AddBlazorise(options =>
|
||||
{
|
||||
options.Immediate = true;
|
||||
@@ -44,12 +50,11 @@ app.UseStaticFiles();
|
||||
app.UseRouting();
|
||||
app.MapBlazorHub();
|
||||
app.MapFallbackToPage("/_Host");
|
||||
app.MapControllers();
|
||||
|
||||
IServiceScope serviceScope = app.Services.GetRequiredService<IServiceScopeFactory>().CreateScope();
|
||||
serviceScope.ServiceProvider.GetRequiredService<UserDatabaseContext>().Database.EnsureCreated();
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
AsyncServiceScope scope = app.Services.CreateAsyncScope();
|
||||
scope.ServiceProvider.GetRequiredService<DeviceManagmentDatabaseContext>().Database.EnsureCreated();
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -8,9 +8,9 @@ namespace Elektrifikatsiya.Services;
|
||||
|
||||
public interface IDeviceManagmentService
|
||||
{
|
||||
public Task<Result<Device>> Register(IPAddress ip, User user, string? name = null, string room = "default");
|
||||
public Task<Result<Device>> RegisterDevice(IPAddress ip, User user, string? name = null, string room = "default");
|
||||
|
||||
public Task<Result> Unregister(string macAdress);
|
||||
public Task<Result> UnregisterDevice(string macAdress);
|
||||
|
||||
public Result<Device> GetDevice(string macAdress);
|
||||
|
||||
@@ -19,4 +19,6 @@ public interface IDeviceManagmentService
|
||||
public Result<List<Device>> GetDevicesInRoom(string room);
|
||||
|
||||
public Result<List<Device>> GetDevicesOfUser(int userId);
|
||||
|
||||
public Task<Result> UpdateDevice(Device device);
|
||||
}
|
||||
+53
-16
@@ -10,14 +10,16 @@ namespace Elektrifikatsiya.Services.Implementations;
|
||||
|
||||
public class DeviceManagmentService : IDeviceManagmentService
|
||||
{
|
||||
private readonly DeviceManagmentDatabaseContext deviceManagmentDatabaseContext;
|
||||
private readonly IServiceScopeFactory serviceScopeFactory;
|
||||
private readonly IDeviceStatusService deviceStatusService;
|
||||
private readonly ILogger<DeviceManagmentService> logger;
|
||||
private readonly HttpClient httpClient;
|
||||
|
||||
public DeviceManagmentService(DeviceManagmentDatabaseContext deviceManagmentDatabaseContext, IDeviceStatusService deviceStatusService, HttpClient httpClient)
|
||||
public DeviceManagmentService(IServiceScopeFactory serviceScopeFactory, IDeviceStatusService deviceStatusService, ILogger<DeviceManagmentService> logger, HttpClient httpClient)
|
||||
{
|
||||
this.deviceManagmentDatabaseContext = deviceManagmentDatabaseContext;
|
||||
this.serviceScopeFactory = serviceScopeFactory;
|
||||
this.deviceStatusService = deviceStatusService;
|
||||
this.logger = logger;
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
@@ -76,34 +78,52 @@ public class DeviceManagmentService : IDeviceManagmentService
|
||||
return getDevicesResult.Value.Where(d => d.User.Id == userId).ToList();
|
||||
}
|
||||
|
||||
public async Task<Result<Device>> Register(IPAddress ip, User user, string? name = null, string room = "default")
|
||||
public async Task<Result<Device>> RegisterDevice(IPAddress ip, User user, string? name = null, string room = "default")
|
||||
{
|
||||
ShellyResponse? shellyResponse = await httpClient.GetFromJsonAsync<ShellyResponse>($"{ip}/shelly");
|
||||
using IServiceScope scope = serviceScopeFactory.CreateScope();
|
||||
DeviceManagmentDatabaseContext deviceManagmentDatabaseContext = scope.ServiceProvider.GetRequiredService<DeviceManagmentDatabaseContext>();
|
||||
|
||||
if(shellyResponse is null || shellyResponse.Type != "SHPLG-S")
|
||||
ShellyResponse? shellyResponse = null;
|
||||
|
||||
try
|
||||
{
|
||||
return Result.Fail("Device is not a \"SHPLG-S\" or not reachable!");
|
||||
shellyResponse = await httpClient.GetFromJsonAsync<ShellyResponse>($"http://{ip}/shelly");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError("HTTP request failed! {message}", ex.Message);
|
||||
}
|
||||
|
||||
if (shellyResponse is null || shellyResponse.Type != "SHPLG-S")
|
||||
{
|
||||
return Result.Fail("Device is not reachable or not a \"SHPLG-S\"!");
|
||||
}
|
||||
|
||||
string mac = shellyResponse.Mac;
|
||||
|
||||
if(PhysicalAddress.TryParse(mac, out _))
|
||||
if (!PhysicalAddress.TryParse(mac, out _))
|
||||
{
|
||||
return Result.Fail("Invalid mac address!");
|
||||
}
|
||||
|
||||
Device device = new Device(mac, name ?? mac, ip, user, room);
|
||||
|
||||
deviceManagmentDatabaseContext.Add(device);
|
||||
Result saveDatabaseChangesResult = await Result.Try(async Task () => await deviceManagmentDatabaseContext.SaveChangesAsync());
|
||||
_ = deviceManagmentDatabaseContext.Add(device);
|
||||
Result saveDatabaseChangesResult = await Result.Try(Task () => deviceManagmentDatabaseContext.SaveChangesAsync());
|
||||
|
||||
Result trackDeviceResult = deviceStatusService.TrackDevice(device);
|
||||
|
||||
return Result.Merge(saveDatabaseChangesResult, trackDeviceResult).ToResult(device);
|
||||
if (saveDatabaseChangesResult.IsFailed)
|
||||
{
|
||||
return saveDatabaseChangesResult;
|
||||
}
|
||||
|
||||
public async Task<Result> Unregister(string macAdress)
|
||||
return deviceStatusService.TrackDevice(device);
|
||||
}
|
||||
|
||||
public async Task<Result> UnregisterDevice(string macAdress)
|
||||
{
|
||||
using IServiceScope scope = serviceScopeFactory.CreateScope();
|
||||
DeviceManagmentDatabaseContext deviceManagmentDatabaseContext = scope.ServiceProvider.GetRequiredService<DeviceManagmentDatabaseContext>();
|
||||
|
||||
Result<Device> getDeviceResult = GetDevice(macAdress);
|
||||
|
||||
if (getDeviceResult.IsFailed)
|
||||
@@ -118,8 +138,25 @@ public class DeviceManagmentService : IDeviceManagmentService
|
||||
return untrackDeviceResult;
|
||||
}
|
||||
|
||||
deviceManagmentDatabaseContext.Remove(getDeviceResult.Value);
|
||||
_ = deviceManagmentDatabaseContext.Remove(getDeviceResult.Value);
|
||||
|
||||
return await Result.Try(async Task () => await deviceManagmentDatabaseContext.SaveChangesAsync());
|
||||
return await Result.Try(Task () => deviceManagmentDatabaseContext.SaveChangesAsync());
|
||||
}
|
||||
|
||||
public async Task<Result> UpdateDevice(Device device)
|
||||
{
|
||||
using IServiceScope scope = serviceScopeFactory.CreateScope();
|
||||
DeviceManagmentDatabaseContext deviceManagmentDatabaseContext = scope.ServiceProvider.GetRequiredService<DeviceManagmentDatabaseContext>();
|
||||
|
||||
Result result = deviceStatusService.UpdateDeviceStatus(device);
|
||||
|
||||
if (result.IsFailed)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
_ = deviceManagmentDatabaseContext.Update(device);
|
||||
|
||||
return await Result.Try(Task () => deviceManagmentDatabaseContext.SaveChangesAsync());
|
||||
}
|
||||
}
|
||||
@@ -6,10 +6,15 @@ namespace Elektrifikatsiya.Services.Implementations;
|
||||
|
||||
public class DeviceStatusService : IDeviceStatusService
|
||||
{
|
||||
private readonly ILogger<DeviceStatusService> logger;
|
||||
public event EventHandler<DeviceStatusChagedEventArgs>? OnDeviceStatusChanged;
|
||||
|
||||
private readonly Dictionary<string, Device> devices = new();
|
||||
|
||||
public DeviceStatusService(ILogger<DeviceStatusService> logger)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
public Result<List<Device>> 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();
|
||||
|
||||
@@ -10,18 +10,21 @@ public class UpdateService : IHostedService, IDisposable
|
||||
{
|
||||
private readonly ILogger<UpdateService> logger;
|
||||
private readonly IDeviceStatusService deviceStatusService;
|
||||
private readonly DeviceManagmentDatabaseContext deviceManagmentDatabaseContext;
|
||||
private readonly IServiceScopeFactory serviceScopeFactory;
|
||||
private Timer? timer = null;
|
||||
|
||||
public UpdateService(ILogger<UpdateService> logger, IDeviceStatusService deviceStatusService, DeviceManagmentDatabaseContext deviceManagmentDatabaseContext)
|
||||
public UpdateService(ILogger<UpdateService> logger, IDeviceStatusService deviceStatusService, IServiceScopeFactory serviceScopeFactory)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.deviceStatusService = deviceStatusService;
|
||||
this.deviceManagmentDatabaseContext = deviceManagmentDatabaseContext;
|
||||
this.serviceScopeFactory = serviceScopeFactory;
|
||||
}
|
||||
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
IServiceScope serviceScope = serviceScopeFactory.CreateScope();
|
||||
DeviceManagmentDatabaseContext deviceManagmentDatabaseContext = serviceScope.ServiceProvider.GetRequiredService<DeviceManagmentDatabaseContext>();
|
||||
|
||||
logger.LogInformation("Starting update service...");
|
||||
|
||||
foreach (Device device in await deviceManagmentDatabaseContext.Devices.AsNoTracking().ToListAsync(cancellationToken))
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
using System.Net;
|
||||
|
||||
using Tmds.MDns;
|
||||
|
||||
namespace Elektrifikatsiya.Utilities;
|
||||
|
||||
public static class MdnsDiscovery
|
||||
{
|
||||
public static event Action<IPAddress> 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<IPAddress> GetChachedDevices()
|
||||
{
|
||||
return serviceBrowser.Services.Select(s => s.Addresses.First());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user