Skip to content

Commit

Permalink
V0.2.1 - Bug Fixes, and Better Logging (#35)
Browse files Browse the repository at this point in the history
* Added "Debug" Configuration (#32)

* Added Configuration options to support #31

* ALlow cfg to disable publishing discovery messages, for #31

* #31 - Only print discovery messages when specified by debug config.

* If publshing messages is disabled- also don't spam the console the broker is not connected.

* Correct NullReferenceExceptions (#33)

* Remove uneeded braces.

* This fixes #27, caused because the default value was null.

* throw error, if for unexpected reasons, we do get a null http client.

* Change default topic to "rPDU2MQTT".

* Better Logging (#34)

* Log a message indicating we found the config file.

* Added starting logging configuration, for #25

* Renamed these files to be more concise.

* Use serilog for logging.

* Updating application to use Serilog Static Logging.

Don't see value in using Microsoft.Extensions.Logging. Just- extra dependancies to move around.

* Removed appsettings.json completely.

* Static Logger, used for configuring dependancies, initial setup, etc.

* Global using for Serilog.

* Added serilog packages.

* Removed static global using. "Information" does not have the needed context.

* Log message showing that we did successfully load a configuration file.

* Sorting usings

* Added Configuration for Logging.

* Added extension to configure logging.

* Use serilog

* Remove appsettings from .gitignore.

* Use serilog here.

* Added Path to default/example config.

* Moved file-based options to dedicated class. Added file rollover support, and retention support.

* Set minimum log level during startup to verbose.

* Added FileRollover / FileRetention to Config.yaml
  • Loading branch information
XtremeOwnageDotCom authored Sep 1, 2024
1 parent c22a3de commit 13b324f
Show file tree
Hide file tree
Showing 26 changed files with 303 additions and 136 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -362,5 +362,4 @@ MigrationBackup/
# Fody - auto-generated XML schema
FodyWeavers.xsd

/rPDU2MQTT/appsettings.Development.json
/rPDU2MQTT/config.yaml
15 changes: 6 additions & 9 deletions rPDU2MQTT/Classes/PDU.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Microsoft.Extensions.Logging;
using rPDU2MQTT.Extensions;
using rPDU2MQTT.Extensions;
using rPDU2MQTT.Helpers;
using rPDU2MQTT.Models.PDU;
using rPDU2MQTT.Models.PDU.DummyDevices;
Expand All @@ -13,13 +12,11 @@ public partial class PDU
{
private readonly Config config;
private readonly HttpClient http;
private readonly ILogger<PDU> log;

public PDU(Config config, HttpClient http, ILogger<PDU> log)
public PDU(Config config, [DisallowNull, NotNull] HttpClient http)
{
this.config = config;
this.http = http;
this.log = log;
this.http = http ?? throw new NullReferenceException("HttpClient in constructor was null");
}

/// <summary>
Expand All @@ -29,9 +26,9 @@ public PDU(Config config, HttpClient http, ILogger<PDU> log)
/// <returns></returns>
public async Task<RootData> GetRootData_Public(CancellationToken cancellationToken)
{
log.LogDebug("Querying /api");
Log.Debug("Querying /api");
var model = await http.GetFromJsonAsync<GetResponse<RootData>>("/api", options: Models.PDU.Converter.Settings, cancellationToken);
log.LogDebug($"Query response {model.RetCode}");
Log.Debug($"Query response {model.RetCode}");

//Process device data.
processData(model.Data, cancellationToken);
Expand All @@ -44,7 +41,7 @@ public async void processData(RootData data, CancellationToken cancellationToken
//Set basic details.
data.Record_Parent = null;
data.Record_Key = config.MQTT.ParentTopic;
data.URL = http.BaseAddress.ToString();
data.URL = http.BaseAddress!.ToString();

data.Entity_Identifier = Coalesce(config.Overrides?.PDU?.ID, "rPDU2MQTT")!;
data.Entity_Name = data.Entity_DisplayName = Coalesce(config.Overrides?.PDU?.Name, data.Sys.Label, data.Sys.Name, "rPDU2MQTT")!;
Expand Down
6 changes: 3 additions & 3 deletions rPDU2MQTT/Extensions/EntityWithName_Overrides.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ public static void SetEntityNameAndEnabled<TKey, TEntity>([DisallowNull] this Di
{
// We are adding + 1 to the outlet's key- because the PDU gives data 0-based. However, when the entities are viewed through
// its UI, they are 1-based. This corrects that.
(int k, Outlet o) => overrides.Outlets!.TryGetValue(k + 1, out var outletOverride) ? outletOverride : null,
(string k, Device o) => overrides.Devices!.TryGetValue(k, out var outletOverride) ? outletOverride : null,
(string k, Measurement o) => overrides.Measurements!.TryGetValue(o.Type, out var outletOverride) ? outletOverride : null,
(int k, Outlet o) => overrides.Outlets.TryGetValue(k + 1, out var outletOverride) ? outletOverride : null,
(string k, Device o) => overrides.Devices.TryGetValue(k, out var outletOverride) ? outletOverride : null,
(string k, Measurement o) => overrides.Measurements.TryGetValue(o.Type, out var outletOverride) ? outletOverride : null,
_ => null
};

Expand Down
4 changes: 1 addition & 3 deletions rPDU2MQTT/Helpers/StringHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@ public static class StringHelper
public static string? Coalesce(params string?[] values)
{
foreach (var value in values)
{
if (!string.IsNullOrWhiteSpace(value))
return value;
}
return value;

return null;
}
Expand Down
8 changes: 4 additions & 4 deletions rPDU2MQTT/Helpers/ThrowError.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ public static class ThrowError
[DoesNotReturn]
public static T ConfigurationMissing<T>(string ConfigurationPath)
{
Console.WriteLine("Please validate configuration.yaml");
Log.Fatal("Please validate configuration.yaml");
string msg = $"Missing required configuration of type {typeof(T).Name}. Path: " + ConfigurationPath;
Console.WriteLine(msg);
Log.Fatal(msg);

throw new Exception(msg);
}
Expand All @@ -18,9 +18,9 @@ public static void TestRequiredConfigurationSection([AllowNull, NotNull] object
{
if (section is null)
{
Console.WriteLine("Please validate configuration.yaml");
Log.Fatal("Please validate configuration.yaml");
string msg = $"Missing required configuration. Path: " + ConfigurationPath;
Console.WriteLine(msg);
Log.Fatal(msg);

throw new Exception(msg);
}
Expand Down
6 changes: 6 additions & 0 deletions rPDU2MQTT/Models/Config/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,10 @@ public class Config

[YamlMember(Alias = "Overrides", DefaultValuesHandling = DefaultValuesHandling.OmitDefaults, Description = "Overrides")]
public Overrides Overrides { get; set; } = new Overrides();

[YamlMember(Alias = "Debug", DefaultValuesHandling = DefaultValuesHandling.OmitDefaults, Description = "Settings for debugging and diagnostics.")]
public DebugConfig Debug { get; set; } = new DebugConfig();

[YamlMember(Alias = "Logging")]
public LoggingConfig Logging { get; set; } = new LoggingConfig();
}
28 changes: 28 additions & 0 deletions rPDU2MQTT/Models/Config/DebugConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.ComponentModel;
using YamlDotNet.Serialization;

namespace rPDU2MQTT.Models.Config;

/// <summary>
/// Settings for debugging and diagnostics.
/// </summary>
public class DebugConfig
{
/// <summary>
/// This- determines if messages are actually PUSHED to the MQTT broker.
/// </summary>
/// <remarks>
/// Intended usage, is to allow the entire process to be tested, and debugged, without actually publishing the mwssages.
/// </remarks>
[YamlMember(Alias = "PublishMessages")]
[DefaultValue(true)]
public bool PublishMessages { get; set; } = true;


/// <summary>
/// When enabled, this will print the MQTT discovery messages to the console.
/// </summary>
[YamlMember(Alias = "PrintDiscovery")]
[DefaultValue(false)]
public bool PrintDiscovery { get; set; } = false;
}
29 changes: 29 additions & 0 deletions rPDU2MQTT/Models/Config/LoggingConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using rPDU2MQTT.Models.Config.Schemas;
using Serilog.Events;
using YamlDotNet.Serialization;

namespace rPDU2MQTT.Models.Config;

/// <summary>
/// Configuration for logging.
/// </summary>
public class LoggingConfig
{
public string? LogFilePath { get; set; } = null;

[YamlMember(Alias = "Console")]
public LoggingTargetConfiguration Console { get; set; } = new LoggingTargetConfiguration()
{
Enabled = true,
Severity = LogEventLevel.Information,
};

[YamlMember(Alias = "File")]
public FileLoggingTargetConfiguration File { get; set; } = new FileLoggingTargetConfiguration()
{
Enabled = false,
Severity = LogEventLevel.Debug,
FileRetention = 30,
FileRollover = RollingInterval.Day,
};
}
4 changes: 3 additions & 1 deletion rPDU2MQTT/Models/Config/MQTTConfig.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using rPDU2MQTT.Models.Config.Schemas;
using System.ComponentModel;
using YamlDotNet.Serialization;

namespace rPDU2MQTT.Models.Config;
Expand All @@ -23,7 +24,8 @@ public class MQTTConfig
/// </summary>
[Required(ErrorMessage = "ParentTopic is required.")]
[Display(Description = "The parent topic for MQTT messages.")]
public string ParentTopic { get; set; } = "Rack_PDU";
[DefaultValue("rPDU2MQTT")]
public string ParentTopic { get; set; } = "rPDU2MQTT";

/// <summary>
/// Gets or sets the connection details for MQTT Broker.
Expand Down
11 changes: 7 additions & 4 deletions rPDU2MQTT/Models/Config/Overrides.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@ namespace rPDU2MQTT.Models.Config;
public class Overrides
{
[YamlMember(Alias = "PDU", DefaultValuesHandling = DefaultValuesHandling.OmitNull, Description = "Allows overriding values for the PDU itself.")]
public EntityOverride? PDU { get; set; }
public EntityOverride PDU { get; set; } = new();


[YamlMember(Alias = "Devices", DefaultValuesHandling = DefaultValuesHandling.OmitNull, Description = "Allows overriding configuration for individual devices.")]
public Dictionary<string, EntityOverride?>? Devices { get; set; }
public Dictionary<string, EntityOverride?> Devices { get; set; } = new();


[YamlMember(Alias = "Outlets", DefaultValuesHandling = DefaultValuesHandling.OmitNull, Description = "Allows overriding values for individual outlets.")]
public Dictionary<int, EntityOverride?>? Outlets { get; set; }
public Dictionary<int, EntityOverride?> Outlets { get; set; } = new();


[YamlMember(Alias = "Measurements", DefaultValuesHandling = DefaultValuesHandling.OmitNull, Description = "Allows overriding individual measurements")]
public Dictionary<string, EntityOverride?>? Measurements { get; set; }
public Dictionary<string, EntityOverride?> Measurements { get; set; } = new();
}
19 changes: 19 additions & 0 deletions rPDU2MQTT/Models/Config/Schemas/FileLoggingTargetConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace rPDU2MQTT.Models.Config.Schemas;

public class FileLoggingTargetConfiguration : LoggingTargetConfiguration
{
/// <summary>
/// Path to log file which will be used.
/// </summary>
public string? Path { get; set; } = null;

/// <summary>
/// This determines when files are rolled over.
/// </summary>
public RollingInterval FileRollover { get; set; } = RollingInterval.Day;

/// <summary>
/// This determines how many rolled over files to retain.
/// </summary>
public int FileRetention { get; set; } = 30;
}
13 changes: 13 additions & 0 deletions rPDU2MQTT/Models/Config/Schemas/LoggingTargetConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Serilog.Events;

namespace rPDU2MQTT.Models.Config.Schemas;

public class LoggingTargetConfiguration
{
public LogEventLevel Severity { get; set; } = LogEventLevel.Information;

public string Format { get; set; } = "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}";

public bool Enabled { get; set; } = false;

}
16 changes: 11 additions & 5 deletions rPDU2MQTT/Program.cs
Original file line number Diff line number Diff line change
@@ -1,28 +1,34 @@
using HiveMQtt.Client;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using rPDU2MQTT.Startup;
using System.Runtime.InteropServices;

Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.WriteTo.Console()
.MinimumLevel.Is(Serilog.Events.LogEventLevel.Verbose)
.CreateLogger();

var host = Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(ConfigLoader.Configure)
.ConfigureAppConfiguration(o => { o.AddEnvironmentVariables(); })
.ConfigureServices(ServiceConfiguration.Configure)
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.AddConsole();
logging.AddConsole();
})
.Build();

//Ensure we can actually connect to MQTT.
var client = host.Services.GetRequiredService<IHiveMQClient>();
var logger = host.Services.GetRequiredService<ILogger<IHiveMQClient>>();

logger.LogInformation($"Connecting to MQTT Broker at {client.Options.Host}:{client.Options.Port}");
Log.Information($"Connecting to MQTT Broker at {client.Options.Host}:{client.Options.Port}");

await client.ConnectAsync();

logger.LogInformation("Successfully connected to broker!");
Log.Information("Successfully connected to broker!");

host.Run();
8 changes: 4 additions & 4 deletions rPDU2MQTT/Services/HomeAssistantDiscoveryService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,19 @@ namespace rPDU2MQTT.Services;
/// </summary>
public class HomeAssistantDiscoveryService : baseDiscoveryService
{
public HomeAssistantDiscoveryService(ILogger<HomeAssistantDiscoveryService> log, MQTTServiceDependancies deps) : base(deps, log) { }
public HomeAssistantDiscoveryService(MQTTServiceDependancies deps) : base(deps) { }

protected override async Task Execute(CancellationToken cancellationToken)
{
var data = await pdu.GetRootData_Public(cancellationToken);
var pduDevice = data.GetDiscoveryDevice();

log.LogDebug("Starting discovery job.");
Log.Debug("Starting discovery job.");

// Recursively discover everything.
await recursiveDiscovery(data.Devices, pduDevice, cancellationToken);

log.LogInformation("Discovery information published.");
Log.Information("Discovery information published.");
}


Expand Down Expand Up @@ -81,7 +81,7 @@ protected async Task recursiveDiscovery<TEntity>([AllowNull] TEntity entity, Dis
// Discover measurements
await recursiveDiscovery(pduEntity.Measurements, parent, cancellationToken);
}
else if(entity is Measurement measurement)
else if (entity is Measurement measurement)
{
await DiscoverMeasurementAsync(measurement, parent, cancellationToken);
}
Expand Down
7 changes: 3 additions & 4 deletions rPDU2MQTT/Services/MQTTPublishingService.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Microsoft.Extensions.Logging;
using rPDU2MQTT.Classes;
using rPDU2MQTT.Classes;
using rPDU2MQTT.Services.baseTypes;

namespace rPDU2MQTT.Services;
Expand All @@ -9,15 +8,15 @@ namespace rPDU2MQTT.Services;
/// </summary>
public class MQTTPublishingService : basePublishingService
{
public MQTTPublishingService(ILogger<MQTTPublishingService> log, MQTTServiceDependancies deps) : base(log, deps) { }
public MQTTPublishingService(MQTTServiceDependancies deps) : base(deps) { }

protected override async Task Execute(CancellationToken cancellationToken)
{
var rootData = await pdu.GetRootData_Public(cancellationToken);
foreach (var device in rootData.Devices.Values)
{
await PublishState(device, cancellationToken);

foreach (var entity in device.Entity.Values)
{
await PublishName(entity, cancellationToken);
Expand Down
7 changes: 4 additions & 3 deletions rPDU2MQTT/Services/baseTypes/baseDiscoveryService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace rPDU2MQTT.Services.baseTypes;

public abstract class baseDiscoveryService : baseMQTTTService
{
public baseDiscoveryService(MQTTServiceDependancies deps, ILogger log) : base(deps, log, deps.Cfg.HASS.DiscoveryInterval) { }
public baseDiscoveryService(MQTTServiceDependancies deps) : base(deps, deps.Cfg.HASS.DiscoveryInterval) { }

/// <summary>
/// Publish a discovery message for the specified <paramref name="measurement"/>, for device <paramref name="Parent"/>
Expand Down Expand Up @@ -105,15 +105,16 @@ protected Task PushDiscoveryMessage<T>(T sensor, CancellationToken cancellationT
{
var topic = $"{cfg.HASS.DiscoveryTopic}/{sensor.EntityType.ToJsonString()}/{sensor.ID}/config";

log.LogDebug($"Publishing Discovery of type {sensor.EntityType.ToJsonString()} for {sensor.ID} to {topic}");
Log.Debug($"Publishing Discovery of type {sensor.EntityType.ToJsonString()} for {sensor.ID} to {topic}");

var msg = new MQTT5PublishMessage(topic, QualityOfService.AtLeastOnceDelivery)
{
ContentType = "json",
PayloadAsString = System.Text.Json.JsonSerializer.Serialize<T>(sensor, this.jsonOptions)
};

Console.WriteLine(msg.PayloadAsString);
if (cfg.Debug.PrintDiscovery)
Log.Debug(msg.PayloadAsString);

return this.Publish(msg, cancellationToken);
}
Expand Down
Loading

0 comments on commit 13b324f

Please sign in to comment.