-
Node Events
-
-
-
-
- Uptime percentage: @Model.UptimePercentage%
-
-
+ @Model.NodeName
+
+
+
+
+
+
+ Uptime percentage:
+
@Model.GetUptimePercentage("all", "pastWeek")%
+
@Model.GetUptimePercentage("hydrophoneStream", "pastWeek")%
+
@Model.GetUptimePercentage("dataplicityConnection", "pastWeek")%
+
@Model.GetUptimePercentage("mezmoLogging", "pastWeek")%
+
@Model.GetUptimePercentage("all", "pastMonth")%
+
@Model.GetUptimePercentage("hydrophoneStream", "pastMonth")%
+
@Model.GetUptimePercentage("dataplicityConnection", "pastMonth")%
+
@Model.GetUptimePercentage("mezmoLogging", "pastMonth")%
+
+
+
+
+
+ Filter by Time Range:
+
+
+
+
+
+
+
+ Filter by Type:
+
+
+
+
+
+
+
+
Timestamp (Pacific) |
@@ -70,11 +60,81 @@
}
@foreach (Models.OrcanodeEvent item in Model.RecentEvents)
{
-
+
@item.DateTimeLocal.ToString("g") |
@item.Description |
}
+
+
diff --git a/OrcanodeMonitor/Pages/NodeEvents.cshtml.cs b/OrcanodeMonitor/Pages/NodeEvents.cshtml.cs
index 2ca86af..0e0aa2d 100644
--- a/OrcanodeMonitor/Pages/NodeEvents.cshtml.cs
+++ b/OrcanodeMonitor/Pages/NodeEvents.cshtml.cs
@@ -2,10 +2,10 @@
// SPDX-License-Identifier: MIT
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
-using Microsoft.IdentityModel.Tokens;
using OrcanodeMonitor.Core;
using OrcanodeMonitor.Data;
using OrcanodeMonitor.Models;
+using static OrcanodeMonitor.Core.Fetcher;
namespace OrcanodeMonitor.Pages
{
@@ -13,8 +13,9 @@ public class NodeEventsModel : PageModel
{
private readonly OrcanodeMonitorContext _databaseContext;
private readonly ILogger _logger;
- private string _nodeId;
- public string Id => _nodeId;
+ private Orcanode? _node = null;
+ public string Id => _node?.ID ?? string.Empty;
+ public string NodeName => _node?.DisplayName ?? "Unknown";
[BindProperty]
public string TimePeriod { get; set; } = "week"; // Default to 'week'
@@ -24,57 +25,59 @@ public class NodeEventsModel : PageModel
private DateTime SinceTime => (TimePeriod == "week") ? DateTime.UtcNow.AddDays(-7) : DateTime.UtcNow.AddMonths(-1);
private List _events;
public List RecentEvents => _events;
- public int UptimePercentage => Orcanode.GetUptimePercentage(_nodeId, _events, SinceTime, (EventType == OrcanodeEventTypes.All) ? OrcanodeEventTypes.HydrophoneStream : EventType);
+ public int GetUptimePercentage(string type, string timeRange)
+ {
+ DateTime sinceTime = (timeRange == "pastWeek") ? DateTime.UtcNow.AddDays(-7) : DateTime.UtcNow.AddMonths(-1);
+ string eventType = type switch
+ {
+ "hydrophoneStream" => OrcanodeEventTypes.HydrophoneStream,
+ "dataplicityConnection" => OrcanodeEventTypes.DataplicityConnection,
+ "mezmoLogging" => OrcanodeEventTypes.MezmoLogging,
+ _ => OrcanodeEventTypes.HydrophoneStream
+ };
+ return Orcanode.GetUptimePercentage(Id, _events, sinceTime, eventType);
+ }
public NodeEventsModel(OrcanodeMonitorContext context, ILogger logger)
{
_databaseContext = context;
_logger = logger;
- _nodeId = string.Empty;
_events = new List();
}
private void FetchEvents(ILogger logger)
{
- _events = Fetcher.GetRecentEventsForNode(_databaseContext, _nodeId, SinceTime, logger).Where(e => e.Type == EventType || EventType == OrcanodeEventTypes.All).ToList() ?? new List();
+ _events = Fetcher.GetRecentEventsForNode(_databaseContext, Id, SinceTime, logger)
+ .Where(e => e.Type == EventType || EventType == OrcanodeEventTypes.All)
+ .ToList() ?? new List();
}
- public void OnGet(string id)
+ public async Task OnGetAsync(string id)
{
- _nodeId = id;
+ _node = _databaseContext.Orcanodes.Where(n => n.ID == id).First();
FetchEvents(_logger);
}
- public IActionResult OnPost(string timePeriod, string eventType, string id)
+ public string GetTypeClass(OrcanodeEvent item) => item.Type switch
{
- if (string.IsNullOrEmpty(id))
- {
- _logger.LogError("Node ID cannot be empty");
- return BadRequest("Invalid node ID");
- }
- if (timePeriod.IsNullOrEmpty())
- {
- timePeriod = TimePeriod;
- }
- if (eventType.IsNullOrEmpty())
- {
- eventType = EventType;
- }
- if (timePeriod != "week" && timePeriod != "month")
- {
- _logger.LogWarning($"Invalid time range selected: {timePeriod}");
- return BadRequest("Invalid time range");
- }
- if (eventType != OrcanodeEventTypes.All && eventType != OrcanodeEventTypes.HydrophoneStream && eventType != OrcanodeEventTypes.MezmoLogging && eventType != OrcanodeEventTypes.DataplicityConnection)
- {
- _logger.LogWarning($"Invalid event type selected: {eventType}");
- return BadRequest("Invalid event type");
- }
- TimePeriod = timePeriod;
- EventType = eventType;
- _nodeId = id;
- FetchEvents(_logger);
- return Page();
+ OrcanodeEventTypes.HydrophoneStream => "hydrophoneStream",
+ OrcanodeEventTypes.DataplicityConnection => "dataplicityConnection",
+ OrcanodeEventTypes.MezmoLogging => "mezmoLogging",
+ OrcanodeEventTypes.AgentUpgradeStatus => "agentUpgradeStatus",
+ OrcanodeEventTypes.SDCardSize => "sdCardSize",
+ _ => string.Empty
+ };
+
+ public string GetTimeRangeClass(OrcanodeEvent item)
+ {
+ DateTime OneWeekAgo = DateTime.UtcNow.AddDays(-7);
+ return (item.DateTimeUtc > OneWeekAgo) ? "pastWeek" : string.Empty;
+ }
+
+ public string GetEventClasses(OrcanodeEvent item)
+ {
+ string classes = GetTypeClass(item) + " " + GetTimeRangeClass(item);
+ return classes;
}
}
}
diff --git a/OrcanodeMonitor/Pages/SpectralDensity.cshtml b/OrcanodeMonitor/Pages/SpectralDensity.cshtml
new file mode 100644
index 0000000..7dfcad1
--- /dev/null
+++ b/OrcanodeMonitor/Pages/SpectralDensity.cshtml
@@ -0,0 +1,48 @@
+@page "{id}"
+@model OrcanodeMonitor.Pages.SpectralDensityModel
+@{
+ ViewData["Title"] = "Spectral Density";
+}
+
+
+
Spectral Density
+
+
+
+
+
+
+
+
diff --git a/OrcanodeMonitor/Pages/SpectralDensity.cshtml.cs b/OrcanodeMonitor/Pages/SpectralDensity.cshtml.cs
new file mode 100644
index 0000000..addf522
--- /dev/null
+++ b/OrcanodeMonitor/Pages/SpectralDensity.cshtml.cs
@@ -0,0 +1,91 @@
+// Copyright (c) Orcanode Monitor contributors
+// SPDX-License-Identifier: MIT
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.RazorPages;
+using OrcanodeMonitor.Core;
+using OrcanodeMonitor.Data;
+using OrcanodeMonitor.Models;
+using static OrcanodeMonitor.Core.Fetcher;
+
+namespace OrcanodeMonitor.Pages
+{
+ ///
+ /// Razor Page model for spectral density visualization.
+ /// Handles retrieval and processing of frequency data for display.
+ ///
+ public class SpectralDensityModel : PageModel
+ {
+ private readonly OrcanodeMonitorContext _databaseContext;
+ private readonly ILogger _logger;
+ private string _nodeId;
+ public string Id => _nodeId;
+ private List _labels;
+ private List _data;
+ public List Labels => _labels;
+ public List Data => _data;
+
+ public SpectralDensityModel(OrcanodeMonitorContext context, ILogger logger)
+ {
+ _databaseContext = context;
+ _logger = logger;
+ _nodeId = string.Empty;
+ }
+
+ private async Task UpdateFrequencyDataAsync()
+ {
+ _labels = new List { };
+ _data = new List { };
+ Orcanode? node = _databaseContext.Orcanodes.Where(n => n.ID == _nodeId).FirstOrDefault();
+ if (node == null)
+ {
+ _logger.LogWarning("Node not found with ID: {NodeId}", _nodeId);
+ return;
+ }
+ TimestampResult? result = await GetLatestS3TimestampAsync(node, false, _logger);
+ if (result != null)
+ {
+ FrequencyInfo? frequencyInfo = await Fetcher.GetLatestAudioSampleAsync(node, result.UnixTimestampString, false, _logger);
+ if (frequencyInfo != null)
+ {
+ const int MaxFrequency = 23000;
+ const int PointCount = 1000;
+
+ // Compute the logarithmic base needed to get PointCount points.
+ double b = Math.Pow(MaxFrequency, 1.0 / PointCount);
+ double logb = Math.Log(b);
+
+ double maxAmplitude = frequencyInfo.FrequencyAmplitudes.Values.Max();
+ var sums = new double[PointCount];
+ var count = new int[PointCount];
+
+ foreach (var pair in frequencyInfo.FrequencyAmplitudes)
+ {
+ double frequency = pair.Key;
+ double amplitude = pair.Value;
+ int bucket = (frequency < 1) ? 0 : (int)(Math.Log(frequency) / logb);
+ count[bucket]++;
+ sums[bucket] += amplitude;
+ }
+
+ // Fill in graph points.
+ for (int i = 0; i < PointCount; i++)
+ {
+ if (count[i] > 0)
+ {
+ int frequency = (int)Math.Pow(b, i);
+ int amplitude = (int)(sums[i] / count[i]);
+ _labels.Add(frequency.ToString());
+ _data.Add(amplitude);
+ }
+ }
+ }
+ }
+ }
+
+ public async Task OnGetAsync(string id)
+ {
+ _nodeId = id;
+ await UpdateFrequencyDataAsync();
+ }
+ }
+}
diff --git a/Test/UnintelligibilityTests.cs b/Test/UnintelligibilityTests.cs
index 855c9a0..c4efe67 100644
--- a/Test/UnintelligibilityTests.cs
+++ b/Test/UnintelligibilityTests.cs
@@ -24,7 +24,8 @@ private async Task TestSampleAsync(string filename, OrcanodeOnlineStatus expecte
try
{
OrcanodeOnlineStatus previousStatus = oldStatus ?? expected_status;
- OrcanodeOnlineStatus status = await FfmpegCoreAnalyzer.AnalyzeFileAsync(filePath, previousStatus);
+ FrequencyInfo frequencyInfo = await FfmpegCoreAnalyzer.AnalyzeFileAsync(filePath, previousStatus);
+ OrcanodeOnlineStatus status = frequencyInfo.Status;
Assert.IsTrue(status == expected_status);
}
catch (Exception ex)