Compare commits

..

2 Commits

Author SHA1 Message Date
Neil Dorin
258699fbcd fix: Enhance AppUrl change logging
Updated logging to include the new AppUrl value when it changes. This provides better context in the logs, making it easier to track the specific URL that was set.
2025-09-18 18:23:12 -06:00
Neil Dorin
738504e9fc fix: Add error handling for network parameter retrieval
Introduced a try-catch block to handle exceptions when fetching the Crestron Ethernet adapter's ID, subnet mask, and IP address. Added logging for cases where the processor lacks a CS LAN. Also included a new using directive for Serilog.Events.
2025-09-18 14:48:21 -06:00
4 changed files with 75 additions and 116 deletions

View File

@@ -9,59 +9,40 @@ using Serilog.Events;
namespace PepperDash.Core.Config
{
/// <summary>
/// Reads a Portal formatted config file
/// </summary>
public class PortalConfigReader
{
const string template = "template";
const string system = "system";
const string systemUrl = "system_url";
const string templateUrl = "template_url";
const string info = "info";
const string devices = "devices";
const string rooms = "rooms";
const string sourceLists = "sourceLists";
const string destinationLists = "destinationLists";
const string cameraLists = "cameraLists";
const string audioControlPointLists = "audioControlPointLists";
const string tieLines = "tieLines";
const string joinMaps = "joinMaps";
const string global = "global";
/// <summary>
/// Reads the config file, checks if it needs a merge, merges and saves, then returns the merged Object.
/// </summary>
/// <returns>JObject of config file</returns>
public static void ReadAndMergeFileIfNecessary(string filePath, string savePath)
/// <summary>
/// Reads the config file, checks if it needs a merge, merges and saves, then returns the merged Object.
/// </summary>
/// <returns>JObject of config file</returns>
public static void ReadAndMergeFileIfNecessary(string filePath, string savePath)
{
try
{
if (!File.Exists(filePath))
{
Debug.LogError(
Debug.Console(1, Debug.ErrorLogLevel.Error,
"ERROR: Configuration file not present. Please load file to {0} and reset program", filePath);
}
using (StreamReader fs = new StreamReader(filePath))
{
var jsonObj = JObject.Parse(fs.ReadToEnd());
if(jsonObj[template] != null && jsonObj[system] != null)
if(jsonObj["template"] != null && jsonObj["system"] != null)
{
// it's a double-config, merge it.
var merged = MergeConfigs(jsonObj);
if (jsonObj[systemUrl] != null)
if (jsonObj["system_url"] != null)
{
merged[systemUrl] = jsonObj[systemUrl].Value<string>();
merged["systemUrl"] = jsonObj["system_url"].Value<string>();
}
if (jsonObj[templateUrl] != null)
if (jsonObj["template_url"] != null)
{
merged[templateUrl] = jsonObj[templateUrl].Value<string>();
merged["templateUrl"] = jsonObj["template_url"].Value<string>();
}
jsonObj = merged;
@@ -96,62 +77,62 @@ namespace PepperDash.Core.Config
var merged = new JObject();
// Put together top-level objects
if (system[info] != null)
merged.Add(info, Merge(template[info], system[info], info));
if (system["info"] != null)
merged.Add("info", Merge(template["info"], system["info"], "infO"));
else
merged.Add(info, template[info]);
merged.Add("info", template["info"]);
merged.Add(devices, MergeArraysOnTopLevelProperty(template[devices] as JArray,
system[devices] as JArray, "key", devices));
merged.Add("devices", MergeArraysOnTopLevelProperty(template["devices"] as JArray,
system["devices"] as JArray, "key", "devices"));
if (system[rooms] == null)
merged.Add(rooms, template[rooms]);
if (system["rooms"] == null)
merged.Add("rooms", template["rooms"]);
else
merged.Add(rooms, MergeArraysOnTopLevelProperty(template[rooms] as JArray,
system[rooms] as JArray, "key", rooms));
merged.Add("rooms", MergeArraysOnTopLevelProperty(template["rooms"] as JArray,
system["rooms"] as JArray, "key", "rooms"));
if (system[sourceLists] == null)
merged.Add(sourceLists, template[sourceLists]);
if (system["sourceLists"] == null)
merged.Add("sourceLists", template["sourceLists"]);
else
merged.Add(sourceLists, Merge(template[sourceLists], system[sourceLists], sourceLists));
merged.Add("sourceLists", Merge(template["sourceLists"], system["sourceLists"], "sourceLists"));
if (system[destinationLists] == null)
merged.Add(destinationLists, template[destinationLists]);
if (system["destinationLists"] == null)
merged.Add("destinationLists", template["destinationLists"]);
else
merged.Add(destinationLists,
Merge(template[destinationLists], system[destinationLists], destinationLists));
merged.Add("destinationLists",
Merge(template["destinationLists"], system["destinationLists"], "destinationLists"));
if (system[cameraLists] == null)
merged.Add(cameraLists, template[cameraLists]);
if (system["cameraLists"] == null)
merged.Add("cameraLists", template["cameraLists"]);
else
merged.Add(cameraLists, Merge(template[cameraLists], system[cameraLists], cameraLists));
merged.Add("cameraLists", Merge(template["cameraLists"], system["cameraLists"], "cameraLists"));
if (system[audioControlPointLists] == null)
merged.Add(audioControlPointLists, template[audioControlPointLists]);
if (system["audioControlPointLists"] == null)
merged.Add("audioControlPointLists", template["audioControlPointLists"]);
else
merged.Add(audioControlPointLists,
Merge(template[audioControlPointLists], system[audioControlPointLists], audioControlPointLists));
merged.Add("audioControlPointLists",
Merge(template["audioControlPointLists"], system["audioControlPointLists"], "audioControlPointLists"));
// Template tie lines take precedence. Config tool doesn't do them at system
// level anyway...
if (template[tieLines] != null)
merged.Add(tieLines, template[tieLines]);
else if (system[tieLines] != null)
merged.Add(tieLines, system[tieLines]);
if (template["tieLines"] != null)
merged.Add("tieLines", template["tieLines"]);
else if (system["tieLines"] != null)
merged.Add("tieLines", system["tieLines"]);
else
merged.Add(tieLines, new JArray());
merged.Add("tieLines", new JArray());
if (template[joinMaps] != null)
merged.Add(joinMaps, template[joinMaps]);
if (template["joinMaps"] != null)
merged.Add("joinMaps", template["joinMaps"]);
else
merged.Add(joinMaps, new JObject());
merged.Add("joinMaps", new JObject());
if (system[global] != null)
merged.Add(global, Merge(template[global], system[global], global));
if (system["global"] != null)
merged.Add("global", Merge(template["global"], system["global"], "global"));
else
merged.Add(global, template[global]);
merged.Add("global", template["global"]);
//Debug.Console(2, "MERGED CONFIG RESULT: \x0d\x0a{0}", merged);
return merged;
@@ -247,7 +228,7 @@ namespace PepperDash.Core.Config
}
catch (Exception e)
{
Debug.LogError("Cannot merge items at path {propPath}: \r{e}", propPath, e);
Debug.Console(1, Debug.ErrorLogLevel.Warning, "Cannot merge items at path {0}: \r{1}", propPath, e);
}
}
}

View File

@@ -124,35 +124,22 @@ namespace PepperDash.Essentials.Core.Config
Debug.LogMessage(LogEventLevel.Information, "Successfully Loaded Local Config");
return true;
}
}
else
{
var parsedConfig = JObject.Parse(fs.ReadToEnd());
// Check if it's a v2 config (missing "system" or "template" nodes)
// this means it's already merged by the Portal API
// from the v2 config tool
var isV2Config = parsedConfig["system"] == null || parsedConfig["template"] == null;
if (isV2Config)
{
Debug.LogMessage(LogEventLevel.Information, "Config file is a v2 format, no merge necessary.");
ConfigObject = parsedConfig.ToObject<EssentialsConfig>();
Debug.LogMessage(LogEventLevel.Information, "Successfully Loaded v2 Config");
return true;
}
var doubleObj = JObject.Parse(fs.ReadToEnd());
ConfigObject = PortalConfigReader.MergeConfigs(doubleObj).ToObject<EssentialsConfig>();
// Extract SystemUrl and TemplateUrl into final config output
ConfigObject = PortalConfigReader.MergeConfigs(parsedConfig).ToObject<EssentialsConfig>();
if (parsedConfig["system_url"] != null)
if (doubleObj["system_url"] != null)
{
ConfigObject.SystemUrl = parsedConfig["system_url"].Value<string>();
ConfigObject.SystemUrl = doubleObj["system_url"].Value<string>();
}
if (parsedConfig["template_url"] != null)
if (doubleObj["template_url"] != null)
{
ConfigObject.TemplateUrl = parsedConfig["template_url"].Value<string>();
ConfigObject.TemplateUrl = doubleObj["template_url"].Value<string>();
}
}

View File

@@ -16,21 +16,13 @@ namespace PepperDash.Essentials.Core.Config
/// </summary>
public class EssentialsConfig : BasicConfig
{
/// <summary>
/// Gets or sets the SystemUrl
/// </summary>
[JsonProperty("system_url")]
[JsonProperty("system_url")]
public string SystemUrl { get; set; }
/// <summary>
/// Gets or sets the TemplateUrl
/// </summary>
[JsonProperty("template_url")]
[JsonProperty("template_url")]
public string TemplateUrl { get; set; }
/// <summary>
/// Gets the SystemUuid extracted from the SystemUrl
/// </summary>
[JsonProperty("systemUuid")]
public string SystemUuid
{
@@ -53,9 +45,6 @@ namespace PepperDash.Essentials.Core.Config
}
}
/// <summary>
/// Gets the TemplateUuid extracted from the TemplateUrl
/// </summary>
[JsonProperty("templateUuid")]
public string TemplateUuid
{
@@ -78,16 +67,13 @@ namespace PepperDash.Essentials.Core.Config
}
}
[JsonProperty("rooms")]
/// <summary>
/// Gets or sets the Rooms
/// </summary>
[JsonProperty("rooms")]
public List<DeviceConfig> Rooms { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="EssentialsConfig"/> class.
/// </summary>
public EssentialsConfig()
: base()
{
@@ -100,14 +86,11 @@ namespace PepperDash.Essentials.Core.Config
/// </summary>
public class SystemTemplateConfigs
{
/// <summary>
/// Gets or sets the System
/// </summary>
/// <summary>
/// Gets or sets the System
/// </summary>
public EssentialsConfig System { get; set; }
/// <summary>
/// Gets or sets the Template
/// </summary>
public EssentialsConfig Template { get; set; }
}
}

View File

@@ -16,6 +16,7 @@ using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.DeviceInfo;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
using PepperDash.Essentials.Core.UI;
using Serilog.Events;
using Feedback = PepperDash.Essentials.Core.Feedback;
namespace PepperDash.Essentials.Touchpanel
@@ -190,12 +191,19 @@ namespace PepperDash.Essentials.Touchpanel
RegisterForExtenders();
var csAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetCSAdapter);
var csSubnetMask = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, csAdapterId);
var csIpAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, csAdapterId);
try
{
var csAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetCSAdapter);
var csSubnetMask = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, csAdapterId);
var csIpAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, csAdapterId);
this.csSubnetMask = System.Net.IPAddress.Parse(csSubnetMask);
this.csIpAddress = System.Net.IPAddress.Parse(csIpAddress);
this.csSubnetMask = System.Net.IPAddress.Parse(csSubnetMask);
this.csIpAddress = System.Net.IPAddress.Parse(csIpAddress);
}
catch
{
Debug.LogInformation("This processor does not have a CS LAN", this);
}
}
/// <summary>
@@ -502,7 +510,7 @@ namespace PepperDash.Essentials.Touchpanel
_bridge.UserCodeChanged += UpdateFeedbacks;
_bridge.AppUrlChanged += (s, a) =>
{
this.LogInformation("AppURL changed");
this.LogInformation("AppURL changed: {appURL}", _bridge.AppUrl);
SetAppUrl(_bridge.AppUrl);
UpdateFeedbacks(s, a);
};