Merge remote-tracking branch 'origin/feature-DeviceRegistration' into feature-DeviceRegistration

This commit is contained in:
Stefan
2023-05-24 11:28:20 +02:00
10 changed files with 240 additions and 185 deletions
@@ -1,10 +1,10 @@
namespace Elektrifikatsiya.Models; namespace Elektrifikatsiya.Models;
public class DeviceStatusChagedEventArgs : EventArgs public class DeviceStatusChangedEventArgs : EventArgs
{ {
public string MacAddress { get; set; } public string MacAddress { get; set; }
public DeviceStatusChagedEventArgs(string macAddress) public DeviceStatusChangedEventArgs(string macAddress)
{ {
MacAddress = macAddress; MacAddress = macAddress;
} }
@@ -11,14 +11,16 @@ namespace Elektrifikatsiya.Models
public string EventName { get; set; } public string EventName { get; set; }
public string Description { get; set; } public string Description { get; set; }
public DateTime Date { get; set; } public DateTime Date { get; set; }
public Device Plug { get; set; }
//if Plug Class implemented -> Property for which plug this event is from //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; EventName = eventName;
Description = description; Description = description;
Date = date; Date = date;
Plug = plug;
} }
} }
} }
@@ -0,0 +1,11 @@
namespace Elektrifikatsiya.Models
{
public class EventServiceEventArgs : EventArgs
{
public Event NewEvent { get; set; } = new Event();
public EventServiceEventArgs(Event newEvent)
{
NewEvent = newEvent;
}
}
}
@@ -7,13 +7,11 @@
@using System.Diagnostics @using System.Diagnostics
@using Elektrifikatsiya.Services.Implementations @using Elektrifikatsiya.Services.Implementations
@inject IVersionProvider VersionProvider @inject IVersionProvider VersionProvider
@inject IDeviceStatusService DeviceStatusService
@inject IEventService EventService
@inject IDeviceStatusService DeviceStatusService; <Row Padding="Padding.Is3">
@inject IDeviceManagmentService DeviceManagmentService; <Div Display="Display.Flex.Row.OnDesktop" Margin="Margin.Is3.FromBottom" Width="Width.Is100">
<Div>
<Row Padding="Padding.Is3">
<Div Display="Display.Flex.Row.OnDesktop" Margin=" Margin.Is3.FromBottom" Width="Width.Is100">
<Column ColumnSize="ColumnSize.Is6.OnDesktop.Is12"> <Column ColumnSize="ColumnSize.Is6.OnDesktop.Is12">
<Bar Breakpoint="Breakpoint.Desktop" <Bar Breakpoint="Breakpoint.Desktop"
Background="Background.White" Background="Background.White"
@@ -31,7 +29,7 @@
Mode="ListGroupMode.Static" Mode="ListGroupMode.Static"
Style="border-radius: 0px 0px"> Style="border-radius: 0px 0px">
<ItemTemplate> <ItemTemplate>
<ListGroupItem> <ListGroupItem Border="Border.OnBottom">
<Row> <Row>
<Column ColumnSize="ColumnSize.Is8"> <Column ColumnSize="ColumnSize.Is8">
<Row> <Row>
@@ -51,8 +49,8 @@
</Row> </Row>
</Column> </Column>
<Column ColumnSize="ColumnSize.Is4"> <Column ColumnSize="ColumnSize.Is4">
<Button Clicked="() => Switch(context.Item)" Position="Position.Absolute.Top.Is50.Start.Is50.Translate.Middle" Color="Color.Primary" Primary Outline> <Button Position="Position.Absolute.Top.Is50.Start.Is50.Translate.Middle" Color="Color.Dark" Outline>
<BarIcon TextColor="(context.Item.Enabled?TextColor.Success:TextColor.Danger)" IconName="IconName.Bolt" /> <BarIcon IconName="IconName.Bolt" />
</Button> </Button>
</Column> </Column>
</Row> </Row>
@@ -76,21 +74,21 @@
ValueField="@((_)=>(""))" ValueField="@((_)=>(""))"
Mode="ListGroupMode.Static" Mode="ListGroupMode.Static"
Style="border-radius: 0px 0px"> Style="border-radius: 0px 0px">
<ItemTemplate> <ItemTemplate>
<Div Flex="Flex.InlineFlex.JustifyContent.Between" Width="Width.Is100"> <Div Flex="Flex.InlineFlex.JustifyContent.Between" Width="Width.Is100">
<Heading Size="HeadingSize.Is6" Margin="Margin.Is2.FromBottom">@context.Item.EventName</Heading> <Heading Size="HeadingSize.Is6" Margin="Margin.Is2.FromBottom">@context.Item.EventName</Heading>
<Small>@context.Item.Date</Small> <Small>@context.Item.Date</Small>
</Div> </Div>
<Paragraph Margin="Margin.Is2.FromBottom">@context.Item.Description</Paragraph> <Paragraph Border="Border.OnBottom" Margin="Margin.Is2.FromBottom">@context.Item.Description</Paragraph>
</ItemTemplate> </ItemTemplate>
</ListView> </ListView>
</Column> </Column>
</Div> </Div>
</Row> </Row>
<Row Padding="Padding.Is3"> <Row Padding="Padding.Is3">
<Column> <Column>
<Button Color="Color.Primary" Style="border-radius: 0px" Clicked="@(async () => await HandleRedraw())">Aktualisieren</Button> <Button Color="Color.Primary" Style="border-radius: 0px" Clicked="@(async () => await HandleRedraw())">Aktualisieren</Button>
<LineChart Height="Height.Is100" Width="Width.Is100" @ref="lineChart" TItem="double" /> <LineChart @ref="lineChart" TItem="double" />
</Column> </Column>
</Row> </Row>
</Div>
@@ -11,18 +11,21 @@ namespace Elektrifikatsiya.Pages;
public partial class Dashboard public partial class Dashboard
{ {
//TODO: insert new event here if plug produces one //TODO: insert new event here if plug produces one
private readonly List<Event> events = new List<Event>() { new Event("Placeholder", "Placeholder", DateTime.Now), new Event("Placeholder", "Placeholder", DateTime.Now), new Event("Placeholder", "Placeholder", DateTime.Now) }; List<Event> events = new List<Event>() { new Event("Text", "Text", DateTime.Today, null ) };
//TODO: insert new Device here if user adds one //TODO: insert new Device here if user adds one
private List<Device> plugs = new List<Device>(); List<Device> plugs = new List<Device>();
//code for graph //code for graph
private LineChart<double> lineChart; LineChart<double> lineChart;
protected override void OnInitialized() protected override void OnInitialized()
{ {
plugs = DeviceStatusService.GetDevices().ValueOrDefault ?? new List<Device>(); plugs = DeviceStatusService.GetDevices().ValueOrDefault ?? new List<Device>();
events = EventService.Events;
EventService.OnEventCalled += (_, e) =>
{
_ = InvokeAsync(StateHasChanged);
};
DeviceStatusService.OnDeviceStatusChanged += (_, e) => DeviceStatusService.OnDeviceStatusChanged += (_, e) =>
{ {
_ = InvokeAsync(StateHasChanged); _ = InvokeAsync(StateHasChanged);
@@ -37,13 +40,7 @@ public partial class Dashboard
} }
} }
private async Task Switch(Device device) async Task HandleRedraw()
{
device.Enabled = !device.Enabled;
_ = await DeviceManagmentService.UpdateDevice(device);
}
private async Task HandleRedraw()
{ {
labels.Clear(); labels.Clear();
await lineChart.Clear(); await lineChart.Clear();
@@ -51,42 +48,40 @@ public partial class Dashboard
} }
//TODO: insert dataset of current and last voltage usages //TODO: insert dataset of current and last voltage usages
private async Task<LineChartDataset<double>> GetLineChartDataset() async Task<LineChartDataset<double>> GetLineChartDataset()
{ {
return new LineChartDataset<double> return new LineChartDataset<double>
{ {
Label = "Wattage", Label = "Wattage",
Data = await DeviceData(), Data = await RandomizeData(),
Fill = true, Fill = true,
PointRadius = 3, PointRadius = 3,
CubicInterpolationMode = "monotone", CubicInterpolationMode = "monotone",
}; };
} }
private readonly List<string> labels = new List<string>(); List<string> labels = new List<string>();
private async Task<List<double>> DeviceData() async Task<List<double>> RandomizeData()
{ {
PrometheusQuery promQueryer = new PrometheusQuery("http://localhost:9090"); if (plugs.Count == 0)
StringBuilder builder = new();
foreach (Device device in plugs)
{
_ = builder.Append($"shellyplug-s-{device.MacAddress}/relay/0|");
}
if (builder.Length <= 1)
{ {
return new(); return new();
} }
PrometheusQuery promQueryer = new PrometheusQuery("http://localhost:9090");
string plugnames = builder.ToString()[..^1]; string plugnames = "";
foreach (Device device in plugs)
{
plugnames += $"shellyplug-s-{device.MacAddress}/relay/0|";
}
plugnames = plugnames[0..^1];
Debug.WriteLine($$"""sum(power{sensor=~"{{plugnames}}"})[1h:1m]"""); Debug.WriteLine($$"""sum(power{sensor=~"{{plugnames}}"})[1h:1m]""");
PrometheusDataWrapper? deviceData = (await promQueryer.Query($$"""sum(power{sensor=~"{{plugnames}}"})[1h:1m]"""))?.Data; PrometheusDataWrapper? deviceData = (await promQueryer.Query($$"""sum(power{sensor=~"{{plugnames}}"})[1h:1m]"""))?.Data;
Random r = new Random(DateTime.Now.Millisecond); var r = new Random(DateTime.Now.Millisecond);
return deviceData?.MatrixTypeToTimestampFloatTuple().ValueOrDefault?.Select(x => return deviceData?.MatrixTypeToTimestampFloatTuple().ValueOrDefault?.Select(x =>
{ {
@@ -90,21 +90,7 @@
Here you can change the name of your plug Here you can change the name of your plug
</Paragraph> </Paragraph>
</FieldLabel> </FieldLabel>
<TextEdit @bind-Text="@DeviceCopy.Name" Placeholder="Enter Name" /> <TextEdit MaxLength="30" @bind-Text="@DeviceCopy.Name" Placeholder="Enter Name" />
</Field>
<br />
<br />
<Field>
<FieldLabel>
<h5>
Change Max Output
</h5>
<Paragraph>
Here you can limit how much power your plug uses
</Paragraph>
</FieldLabel>
<TextEdit Placeholder="Enter Max Output" />
<!--TODO: What is this?-->
</Field> </Field>
<br /> <br />
<br /> <br />
@@ -117,7 +103,7 @@
Here you select or change the room the plug belongs to. Here you select or change the room the plug belongs to.
</Paragraph> </Paragraph>
</FieldLabel> </FieldLabel>
<TextEdit @bind-text="@DeviceCopy.Room" Placeholder="Enter the name of the room here"/> <TextEdit MaxLength="30" @bind-text="@DeviceCopy.Room" Placeholder="Enter the name of the room here" />
</Field> </Field>
</Div> </Div>
} }
@@ -138,7 +124,7 @@
Here you enter your electricity price. This is gonna calculate the overall Price of your System Here you enter your electricity price. This is gonna calculate the overall Price of your System
</Paragraph> </Paragraph>
</FieldLabel> </FieldLabel>
<TextEdit Placeholder="Enter Electricity Price" /> <TextEdit MaxLength="8" Placeholder="Enter Electricity Price" />
</Field> </Field>
</Div> </Div>
<Column ColumnSize="ColumnSize.IsFull" TextAlignment="TextAlignment.End"> <Column ColumnSize="ColumnSize.IsFull" TextAlignment="TextAlignment.End">
@@ -6,7 +6,7 @@ namespace Elektrifikatsiya.Services;
public interface IDeviceStatusService public interface IDeviceStatusService
{ {
public event EventHandler<DeviceStatusChagedEventArgs> OnDeviceStatusChanged; public event EventHandler<DeviceStatusChangedEventArgs> OnDeviceStatusChanged;
public Result<List<Device>> GetDevices(); public Result<List<Device>> GetDevices();
@@ -0,0 +1,10 @@
using Elektrifikatsiya.Models;
namespace Elektrifikatsiya.Services
{
public interface IEventService
{
public List<Event> Events { get; }
public event EventHandler<EventServiceEventArgs> OnEventCalled;
}
}
@@ -1,5 +1,4 @@
using Elektrifikatsiya.Models; using Elektrifikatsiya.Models;
using FluentResults; using FluentResults;
namespace Elektrifikatsiya.Services.Implementations; namespace Elektrifikatsiya.Services.Implementations;
@@ -7,8 +6,7 @@ namespace Elektrifikatsiya.Services.Implementations;
public class DeviceStatusService : IDeviceStatusService public class DeviceStatusService : IDeviceStatusService
{ {
private readonly ILogger<DeviceStatusService> logger; private readonly ILogger<DeviceStatusService> logger;
public event EventHandler<DeviceStatusChangedEventArgs>? OnDeviceStatusChanged;
public event EventHandler<DeviceStatusChagedEventArgs>? OnDeviceStatusChanged;
private readonly Dictionary<string, Device> devices = new(); private readonly Dictionary<string, Device> devices = new();
@@ -36,7 +34,7 @@ public class DeviceStatusService : IDeviceStatusService
modDevice.IpAddress = device.IpAddress; modDevice.IpAddress = device.IpAddress;
modDevice.Name = device.Name; modDevice.Name = device.Name;
OnDeviceStatusChanged?.Invoke(this, new DeviceStatusChagedEventArgs(device.MacAddress)); OnDeviceStatusChanged?.Invoke(this, new DeviceStatusChangedEventArgs(device.MacAddress));
return Result.Ok(); return Result.Ok();
} }
@@ -0,0 +1,55 @@
using Elektrifikatsiya.Models;
using FluentResults;
using System.Reflection;
namespace Elektrifikatsiya.Services.Implementations
{
public class EventService : IEventService
{
private readonly ILogger<EventService> logger;
public event EventHandler<EventServiceEventArgs> OnEventCalled;
public List<Event> Events { get; } = new();
public EventService(ILogger<EventService> logger, IDeviceStatusService deviceStatusService, IDeviceManagmentService deviceManagmentService)
{
this.logger = logger;
List<Device> 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);
}
};
}
}
}