1.1.7 - Improve configuration environment and file loading

This commit is contained in:
Ryan Wagoner 2019-12-26 22:14:58 -05:00
parent 9a966225b6
commit a5e9fae32e
5 changed files with 126 additions and 67 deletions

View file

@ -28,4 +28,4 @@ EXPOSE 8000/tcp
VOLUME /config VOLUME /config
WORKDIR /app WORKDIR /app
COPY --from=build /app . COPY --from=build /app .
CMD [ "mono", "OmniLinkBridge.exe", "-i", "-c", "/config/OmniLinkBridge.ini", "-s", "/config/WebSubscriptions.json" ] CMD [ "mono", "OmniLinkBridge.exe", "-i", "-c", "/config/OmniLinkBridge.ini", "-e", "-s", "/config/WebSubscriptions.json" ]

View file

@ -12,6 +12,9 @@ namespace OmniLinkBridge.Notifications
public void Notify(string source, string description, NotificationPriority priority) public void Notify(string source, string description, NotificationPriority priority)
{ {
if (string.IsNullOrEmpty(Global.mail_server))
return;
foreach (MailAddress address in Global.mail_to) foreach (MailAddress address in Global.mail_to)
{ {
MailMessage mail = new MailMessage MailMessage mail = new MailMessage

View file

@ -28,6 +28,12 @@ namespace OmniLinkBridge
case "-c": case "-c":
Global.config_file = args[++i]; Global.config_file = args[++i];
break; break;
case "-e":
Settings.UseEnvironment = true;
break;
case "-d":
Settings.ShowDebug = true;
break;
case "-s": case "-s":
Global.webapi_subscriptions_file = args[++i]; Global.webapi_subscriptions_file = args[++i];
break; break;
@ -47,6 +53,9 @@ namespace OmniLinkBridge
log4net.Config.XmlConfigurator.Configure(); log4net.Config.XmlConfigurator.Configure();
if(Environment.UserInteractive || interactive)
Trace.Listeners.Add(new TextWriterTraceListener(Console.Out));
try try
{ {
Settings.LoadSettings(); Settings.LoadSettings();
@ -57,7 +66,6 @@ namespace OmniLinkBridge
Environment.Exit(1); Environment.Exit(1);
} }
if (Environment.UserInteractive || interactive) if (Environment.UserInteractive || interactive)
{ {
if (IsRunningOnMono()) if (IsRunningOnMono())
@ -80,8 +88,6 @@ namespace OmniLinkBridge
Console.TreatControlCAsInput = false; Console.TreatControlCAsInput = false;
Console.CancelKeyPress += new ConsoleCancelEventHandler(myHandler); Console.CancelKeyPress += new ConsoleCancelEventHandler(myHandler);
Trace.Listeners.Add(new TextWriterTraceListener(Console.Out));
server = new CoreServer(); server = new CoreServer();
} }
else else
@ -114,8 +120,11 @@ namespace OmniLinkBridge
static void ShowHelp() static void ShowHelp()
{ {
Console.WriteLine( Console.WriteLine(
AppDomain.CurrentDomain.FriendlyName + " [-c config_file] [-s subscriptions_file] [-i]\n" + AppDomain.CurrentDomain.FriendlyName + " [-c config_file] [-e] [-d] [-s subscriptions_file] [-i]\n" +
"\t[-debug-config] [-ignore-env]\n" +
"\t-c Specifies the configuration file. Default is OmniLinkBridge.ini\n" + "\t-c Specifies the configuration file. Default is OmniLinkBridge.ini\n" +
"\t-e Check environment variables for configuration settings\n" +
"\t-d Show debug output for configuration loading\n" +
"\t-s Specifies the web api subscriptions file. Default is WebSubscriptions.json\n" + "\t-s Specifies the web api subscriptions file. Default is WebSubscriptions.json\n" +
"\t-i Run in interactive mode"); "\t-i Run in interactive mode");
} }

View file

@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.1.6.0")] [assembly: AssemblyVersion("1.1.7.0")]
[assembly: AssemblyFileVersion("1.1.6.0")] [assembly: AssemblyFileVersion("1.1.7.0")]

View file

@ -13,87 +13,110 @@ namespace OmniLinkBridge
public static class Settings public static class Settings
{ {
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public static bool ShowDebug { get; set; }
public static bool UseEnvironment { get; set; }
public static void LoadSettings() public static void LoadSettings()
{ {
NameValueCollection settings = LoadCollection(Global.config_file); NameValueCollection settings = LoadCollection(Global.config_file);
// HAI / Leviton Omni Controller // HAI / Leviton Omni Controller
Global.controller_address = settings.CheckEnv("controller_address"); Global.controller_address = settings.ValidateHasValue("controller_address");
Global.controller_port = ValidatePort(settings, "controller_port"); Global.controller_port = settings.ValidatePort("controller_port");
Global.controller_key1 = settings.CheckEnv("controller_key1"); Global.controller_key1 = settings.ValidateHasValue("controller_key1");
Global.controller_key2 = settings.CheckEnv("controller_key2"); Global.controller_key2 = settings.ValidateHasValue("controller_key2");
Global.controller_name = settings.CheckEnv("controller_name") ?? "OmniLinkBridge"; Global.controller_name = settings.CheckEnv("controller_name") ?? "OmniLinkBridge";
// Controller Time Sync // Controller Time Sync
Global.time_sync = ValidateYesNo(settings, "time_sync"); Global.time_sync = settings.ValidateBool("time_sync");
Global.time_interval = ValidateInt(settings, "time_interval");
Global.time_drift = ValidateInt(settings, "time_drift"); if (Global.time_sync)
{
Global.time_interval = settings.ValidateInt("time_interval");
Global.time_drift = settings.ValidateInt("time_drift");
}
// Verbose Console // Verbose Console
Global.verbose_unhandled = ValidateYesNo(settings, "verbose_unhandled"); Global.verbose_unhandled = settings.ValidateBool("verbose_unhandled");
Global.verbose_event = ValidateYesNo(settings, "verbose_event"); Global.verbose_event = settings.ValidateBool("verbose_event");
Global.verbose_area = ValidateYesNo(settings, "verbose_area"); Global.verbose_area = settings.ValidateBool("verbose_area");
Global.verbose_zone = ValidateYesNo(settings, "verbose_zone"); Global.verbose_zone = settings.ValidateBool("verbose_zone");
Global.verbose_thermostat_timer = ValidateYesNo(settings, "verbose_thermostat_timer"); Global.verbose_thermostat_timer = settings.ValidateBool("verbose_thermostat_timer");
Global.verbose_thermostat = ValidateYesNo(settings, "verbose_thermostat"); Global.verbose_thermostat = settings.ValidateBool("verbose_thermostat");
Global.verbose_unit = ValidateYesNo(settings, "verbose_unit"); Global.verbose_unit = settings.ValidateBool("verbose_unit");
Global.verbose_message = ValidateYesNo(settings, "verbose_message"); Global.verbose_message = settings.ValidateBool("verbose_message");
// mySQL Logging // mySQL Logging
Global.mysql_logging = ValidateYesNo(settings, "mysql_logging"); Global.mysql_logging = settings.ValidateBool("mysql_logging");
Global.mysql_connection = settings.CheckEnv("mysql_connection"); Global.mysql_connection = settings.CheckEnv("mysql_connection");
// Web Service // Web Service
Global.webapi_enabled = ValidateYesNo(settings, "webapi_enabled"); Global.webapi_enabled = settings.ValidateBool("webapi_enabled");
Global.webapi_port = ValidatePort(settings, "webapi_port");
Global.webapi_override_zone = LoadOverrideZone<WebAPI.OverrideZone>(settings, "webapi_override_zone"); if (Global.webapi_enabled)
{
Global.webapi_port = settings.ValidatePort("webapi_port");
Global.webapi_override_zone = settings.LoadOverrideZone<WebAPI.OverrideZone>("webapi_override_zone");
}
// MQTT // MQTT
Global.mqtt_enabled = ValidateYesNo(settings, "mqtt_enabled"); Global.mqtt_enabled = settings.ValidateBool("mqtt_enabled");
Global.mqtt_server = settings.CheckEnv("mqtt_server");
Global.mqtt_port = ValidatePort(settings, "mqtt_port");
Global.mqtt_username = settings.CheckEnv("mqtt_username");
Global.mqtt_password = settings.CheckEnv("mqtt_password");
Global.mqtt_prefix = settings.CheckEnv("mqtt_prefix") ?? "omnilink";
Global.mqtt_discovery_prefix = settings.CheckEnv("mqtt_discovery_prefix") ?? "homeassistant";
Global.mqtt_discovery_name_prefix = settings.CheckEnv("mqtt_discovery_name_prefix") ?? string.Empty;
if (!string.IsNullOrEmpty(Global.mqtt_discovery_name_prefix)) if (Global.mqtt_enabled)
Global.mqtt_discovery_name_prefix += " "; {
Global.mqtt_server = settings.CheckEnv("mqtt_server");
Global.mqtt_port = settings.ValidatePort("mqtt_port");
Global.mqtt_username = settings.CheckEnv("mqtt_username");
Global.mqtt_password = settings.CheckEnv("mqtt_password");
Global.mqtt_prefix = settings.CheckEnv("mqtt_prefix") ?? "omnilink";
Global.mqtt_discovery_prefix = settings.CheckEnv("mqtt_discovery_prefix") ?? "homeassistant";
Global.mqtt_discovery_name_prefix = settings.CheckEnv("mqtt_discovery_name_prefix") ?? string.Empty;
Global.mqtt_discovery_ignore_zones = ValidateRange(settings, "mqtt_discovery_ignore_zones"); if (!string.IsNullOrEmpty(Global.mqtt_discovery_name_prefix))
Global.mqtt_discovery_ignore_units = ValidateRange(settings, "mqtt_discovery_ignore_units"); Global.mqtt_discovery_name_prefix += " ";
Global.mqtt_discovery_override_zone = LoadOverrideZone<MQTT.OverrideZone>(settings, "mqtt_discovery_override_zone");
Global.mqtt_discovery_ignore_zones = settings.ValidateRange("mqtt_discovery_ignore_zones");
Global.mqtt_discovery_ignore_units = settings.ValidateRange("mqtt_discovery_ignore_units");
Global.mqtt_discovery_override_zone = settings.LoadOverrideZone<MQTT.OverrideZone>("mqtt_discovery_override_zone");
}
// Notifications // Notifications
Global.notify_area = ValidateYesNo(settings, "notify_area"); Global.notify_area = settings.ValidateBool("notify_area");
Global.notify_message = ValidateYesNo(settings, "notify_message"); Global.notify_message = settings.ValidateBool("notify_message");
// Email Notifications // Email Notifications
Global.mail_server = settings.CheckEnv("mail_server"); Global.mail_server = settings.CheckEnv("mail_server");
Global.mail_tls = ValidateYesNo(settings, "mail_tls");
Global.mail_port = ValidatePort(settings, "mail_port"); if (!string.IsNullOrEmpty(Global.mail_server))
Global.mail_username = settings.CheckEnv("mail_username"); {
Global.mail_password = settings.CheckEnv("mail_password"); Global.mail_tls = settings.ValidateBool("mail_tls");
Global.mail_from = ValidateMailFrom(settings, "mail_from"); Global.mail_port = settings.ValidatePort("mail_port");
Global.mail_to = ValidateMailTo(settings, "mail_to"); Global.mail_username = settings.CheckEnv("mail_username");
Global.mail_password = settings.CheckEnv("mail_password");
Global.mail_from = settings.ValidateMailFrom("mail_from");
Global.mail_to = settings.ValidateMailTo("mail_to");
}
// Prowl Notifications // Prowl Notifications
Global.prowl_key = ValidateMultipleStrings(settings, "prowl_key"); Global.prowl_key = settings.ValidateMultipleStrings("prowl_key");
// Pushover Notifications // Pushover Notifications
Global.pushover_token = settings.CheckEnv("pushover_token"); Global.pushover_token = settings.CheckEnv("pushover_token");
Global.pushover_user = ValidateMultipleStrings(settings, "pushover_user"); Global.pushover_user = settings.ValidateMultipleStrings("pushover_user");
} }
private static string CheckEnv(this NameValueCollection settings, string name) private static string CheckEnv(this NameValueCollection settings, string name)
{ {
string env = Environment.GetEnvironmentVariable(name.ToUpper()); string env = UseEnvironment ? Environment.GetEnvironmentVariable(name.ToUpper()) : null;
return !string.IsNullOrEmpty(env) ? env : settings[name]; string value = !string.IsNullOrEmpty(env) ? env : settings[name];
if (ShowDebug)
log.Debug((!string.IsNullOrEmpty(env) ? "ENV" : "CONF").PadRight(5) + $"{name}: {value}");
return value;
} }
private static ConcurrentDictionary<int, T> LoadOverrideZone<T>(NameValueCollection settings, string section) where T : new() private static ConcurrentDictionary<int, T> LoadOverrideZone<T>(this NameValueCollection settings, string section) where T : new()
{ {
try try
{ {
@ -115,14 +138,14 @@ namespace OmniLinkBridge
T override_zone = new T(); T override_zone = new T();
if (((object)override_zone) is WebAPI.OverrideZone webapi_zone) if (override_zone is WebAPI.OverrideZone webapi_zone)
{ {
if (!attributes.ContainsKey("device_type") || !Enum.TryParse(attributes["device_type"], out WebAPI.DeviceType attrib_device_type)) if (!attributes.ContainsKey("device_type") || !Enum.TryParse(attributes["device_type"], out WebAPI.DeviceType attrib_device_type))
throw new Exception("Missing or invalid device_type attribute"); throw new Exception("Missing or invalid device_type attribute");
webapi_zone.device_type = attrib_device_type; webapi_zone.device_type = attrib_device_type;
} }
else if (((object)override_zone) is MQTT.OverrideZone mqtt_zone) else if (override_zone is MQTT.OverrideZone mqtt_zone)
{ {
if (!attributes.ContainsKey("device_class") || !Enum.TryParse(attributes["device_class"], out MQTT.BinarySensor.DeviceClass attrib_device_class)) if (!attributes.ContainsKey("device_class") || !Enum.TryParse(attributes["device_class"], out MQTT.BinarySensor.DeviceClass attrib_device_class))
throw new Exception("Missing or invalid device_class attribute"); throw new Exception("Missing or invalid device_class attribute");
@ -142,7 +165,20 @@ namespace OmniLinkBridge
} }
} }
private static int ValidateInt(NameValueCollection settings, string section) private static string ValidateHasValue(this NameValueCollection settings, string section)
{
string value = settings.CheckEnv(section);
if(string.IsNullOrEmpty(value))
{
log.Error("Empty string specified for " + section);
throw new Exception();
}
return value;
}
private static int ValidateInt(this NameValueCollection settings, string section)
{ {
try try
{ {
@ -155,7 +191,7 @@ namespace OmniLinkBridge
} }
} }
private static HashSet<int> ValidateRange(NameValueCollection settings, string section) private static HashSet<int> ValidateRange(this NameValueCollection settings, string section)
{ {
try try
{ {
@ -168,7 +204,7 @@ namespace OmniLinkBridge
} }
} }
private static int ValidatePort(NameValueCollection settings, string section) private static int ValidatePort(this NameValueCollection settings, string section)
{ {
try try
{ {
@ -186,7 +222,7 @@ namespace OmniLinkBridge
} }
} }
private static MailAddress ValidateMailFrom(NameValueCollection settings, string section) private static MailAddress ValidateMailFrom(this NameValueCollection settings, string section)
{ {
try try
{ {
@ -199,14 +235,16 @@ namespace OmniLinkBridge
} }
} }
private static MailAddress[] ValidateMailTo(NameValueCollection settings, string section) private static MailAddress[] ValidateMailTo(this NameValueCollection settings, string section)
{ {
try try
{ {
if(settings.CheckEnv(section) == null) string value = settings.CheckEnv(section);
if (value == null)
return new MailAddress[] {}; return new MailAddress[] {};
string[] emails = settings.CheckEnv(section).Split(','); string[] emails = value.Split(',');
MailAddress[] addresses = new MailAddress[emails.Length]; MailAddress[] addresses = new MailAddress[emails.Length];
for(int i=0; i < emails.Length; i++) for(int i=0; i < emails.Length; i++)
@ -221,7 +259,7 @@ namespace OmniLinkBridge
} }
} }
private static string[] ValidateMultipleStrings(NameValueCollection settings, string section) private static string[] ValidateMultipleStrings(this NameValueCollection settings, string section)
{ {
try try
{ {
@ -237,19 +275,19 @@ namespace OmniLinkBridge
} }
} }
private static bool ValidateYesNo (NameValueCollection settings, string section) private static bool ValidateBool (this NameValueCollection settings, string section)
{ {
string value = settings.CheckEnv(section); string value = settings.CheckEnv(section);
if (value == null) if (value == null)
return false; return false;
if (string.Compare(value, "yes", true) == 0) if (string.Compare(value, "yes", true) == 0 || string.Compare(value, "true", true) == 0)
return true; return true;
else if (string.Compare(value, "no", true) == 0) else if (string.Compare(value, "no", true) == 0 || string.Compare(value, "false", true) == 0)
return false; return false;
else else
{ {
log.Error("Invalid yes/no specified for " + section); log.Error("Invalid yes/no or true/false specified for " + section);
throw new Exception(); throw new Exception();
} }
} }
@ -258,6 +296,15 @@ namespace OmniLinkBridge
{ {
NameValueCollection settings = new NameValueCollection(); NameValueCollection settings = new NameValueCollection();
if (ShowDebug)
log.Debug($"Using settings file {sFile}");
if(!File.Exists(sFile))
{
log.Warn($"Unable to locate settings file {sFile}");
return settings;
}
try try
{ {
FileStream fs = new FileStream(sFile, FileMode.Open, FileAccess.Read); FileStream fs = new FileStream(sFile, FileMode.Open, FileAccess.Read);
@ -289,7 +336,7 @@ namespace OmniLinkBridge
} }
catch (FileNotFoundException ex) catch (FileNotFoundException ex)
{ {
log.Error("Unable to parse settings file " + sFile, ex); log.Error("Error parsing settings file " + sFile, ex);
throw; throw;
} }